Background
I am embedding an OSGi runtime based on Apache Felix in the bridged mode in a Tomcat6 container. There are a bunch of JDBC connections specified in the conf/server.xml file in Tomcat6.
<Resource name="foo/bar" ... />
Question
The standard JNDI lookup doesn't seem to work from bundles deployed to the OSGi container.
ctx.lookup("java:comp/env/foo/bar");
Is there anything special that needs to be done for the OSGi runtime to be able to lookup resources registered in the parent Tomcat6 container?
#Martin's comment got me thinking about multiple threads part. I got this to work by:
Ensuring that ctx.lookup(...) is invoked in the BundleActivator. This is because, in the bridged mode, the ClassLoader of the thread running the Activator code can look up all Classes and Resources that are defined in the parent WAR file.
Ensuring that the parent WAR's META-INF/context.xml exposes the JNDI resource via <ResourceLink global="foo/bar" name="foo/bar" type="javax.sql.DataSource"/>
Related
There's a web application and a number of environments in which it works. In each environment it has different settings like DB connection and SOAP ends-points that in their turn are defined in properties-files and accessed in the following way:
config.load(AppProp.class.getClassLoader().getResourceAsStream(
PROPERTIES_FILE_PATH + PROPERTIES_FILE_NAME));
Thus the WAR-files are different for every environment.
What we need is to build a unified WAR-file that doesn't contain any configuration and works in any environment (for now, Tomcat instance) getting its configuration from outside its WAR-file.
The answer Java Web Application Configuration Patterns, to my mind, gives the full set of common approaches but with just few examples. The most attractive way is configuring JNDI lookup mechanism. As I can guess it allows to separately configure web-applications by their context paths. But couldn't find a simple (step-by-step) instructions in both the Internet and the Tomcat's docs. Unfortunately cannot spend much time on studying this complicated stuff in order to just meet so seemingly simple and natural demand :(
Would appreciate your links at the relevant descriptions or any alternative suggestion on the problem.
If its a case of simply deploying your WAR on different environment (executed by different OS user), then you can put all your config files in the user's home folder and load them as:
config.load(new FileInputStream(System.getProperty("user.home") + PROPERTIES_FILE_NAME));
This gives you the isolation and security and makes your WAR completely portable. Ideally though, you should still provide built-in default configuration if that makes sense in your case.
The approach we've taken is based on our existing deployment method, namely to put the WAR files in the filesystem next to the Tomcat, and deploy a context.xml pointing to the WAR file to Tomcat.
The context descriptor allows for providing init parameters which is easily accessible in a servlet. We've also done some work on making this work with CDI (for Glassfish and TomEE dependency injection).
If you only have a single WAR file deployed to this Tomcat instance, you can also add init parameters to the default global context XML. These will be global and you can then deploy the WAR file directly. This is very useful during development.
I am using a shared Tomcat instance for many of my apps. I have configured some of the apps to use the JNDI data-source as described here, but others still are not. Because of this, they have kept the ojdbc jar in the web-inf/lib dir.
Unfortunately, this gives me an error :
Caused by: java.lang.IllegalArgumentException: interface oracle.jdbc.internal.ClientDataSupport is not visible from class loader
which is described here.
Do I have to have "all or nothing" in order to make this succeed?
Everything must be JNDI, or nothing must be JNDI?
Is there a way to find out the java classes loaded in the server stack and replace the same with the latest version of the same without restarting the web or application server?
On Tomcat, there is an attribute called reloadable which support automatic reloading of changed classes/libraries. From Tomcat site:
reloadable
"Set to true if you want Catalina to monitor classes in /WEB-INF/classes/ and /WEB-INF/lib for changes, and automatically reload the web application if a change is detected. This feature is very useful during application development, but it requires significant runtime overhead and is not recommended for use on deployed production applications. That's why the default setting for this attribute is false. You can use the Manager web application, however, to trigger reloads of deployed applications on demand."
Sample usages is (Add following line in server.xml file):
<Context path="/webdev" docBase="/webdev" reloadable="true"></Context>
for more info, please refer http://tomcat.apache.org/tomcat-6.0-doc/config/context.html
I have a couple of modules which now have the need of JNDI.
One of these modules runs via Apache Tomcat while the rest run standalone as J2SE application.
I was able to configure the module which uses tomcat without a problem and I've googled a bit and gathered that JBoss JNP can be a good standalone JNDI server to use.
What I fail to understand is how I can reuse the resources definitions which I have already configured (for my module which runs via tomcat in the context.xml file).
Let's say I have the following resource defined in the XML file:
<Resource name="jdbc/dataSource" auth="Container" type="javax.sql.DataSource"
driverClassName="com.mchange.v2.c3p0.ComboPooledDataSource"
url="jdbc:sqlserver://******
username="**" password="**"/>
And the relevant code which starts the JNP is:
System.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
System.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming:org.jnp.interfaces");
NamingBeanImpl jnpServer = new NamingBeanImpl();
jnpServer.start();
How can I have an InitialContext instance identify the jdbc/dataSource binding?
I don't think you can.
You probably can define your jdbs resource in jboss naming context and look it up in your tomcat web app.
More info here: http://www.amitysolutions.com.au/documents/JBossTomcatJNDI-technote.pdf
When I try the following lookup in my code:
Context initCtx = new InitialContext();
Context envCtx = (Context) initCtx.lookup("java:comp/env");
return (DataSource) envCtx.lookup("jdbc/mydb");
I get the following exception:
java.sql.SQLException: QueryResults: Unable to initialize naming context:
Name java:comp is not bound in this Context at
com.onsitemanager.database.ThreadLocalConnection.getConnection
(ThreadLocalConnection.java:130) at
...
I installed embedded JBoss following the JBoss wiki instructions. And I configured Tomcat using the "Scanning every WAR by default" deployment as specified in the configuration wiki page.
Quoting the config page:
JNDI
Embedded JBoss components like connection pooling, EJB, JPA, and transactions make
extensive use of JNDI to publish services. Embedded JBoss overrides Tomcat's JNDI
implementation by layering itself on top of Tomcat's JNDI instantiation. There are a few > reasons for this:
To avoid having to declare each and every one of these services within server.xml
To allow seemeless integration of the java:comp namespace between web apps and
EJBs.
Tomcat's JNDI implementation has a few critical bugs in it that hamper some JBoss
components ability to work
We want to provide the option for you of remoting EJBs and other services that can > be remotely looked up
Anyone have any thoughts on how I can configure the JBoss naming service which according to the above quote is overriding Tomcat's JNDI implementation so that I can do a lookup on java:comp/env?
FYI - My environment Tomcat 5.5.9, Seam 2.0.2sp, Embedded JBoss (Beta 3),
Note: I do have a -ds.xml file for my database connection properly setup and accessible on the class path per the instructions.
Also note: I have posted this question in embedded Jboss forum and seam user forum.
Thanks for the response toolkit.... yes, I can access my datasource by going directly to java:jdbc/mydb, but I'm using an existing code base that connects via the ENC. Here's some interesting info that I've found out ....
The above code works with JBoss 4.2.2.GA and here's the JNDI ctx parameters being used:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces:
org.jboss.naming:org.jnp.interfaces
The above code works with Tomcat 5.5.x and here's the JNDI ctx parameters being used:
java.naming.factory.initial=org.apache.naming.java.javaURLContextFactory
java.naming.factory.url.pkgs=org.apache.naming
The above code fails with Embedded JBoss (Beta 3) in Tomcat 5.5.x with the above error message.
java.naming.factory.initial=org.apache.naming.java.javaURLContextFactory
java.naming.factory.url.pkgs=org.apache.namingThe above code fails with the above error using JBoss Embedded in tomcat 5.5.x
Anyone have any thoughts I what I need to do with configuring embedded JBoss JNDI configuration?
java:comp/env is known as the Enterprise Naming Context (ENC) and is not globally visible. See here for more information. You will need to locate the global JNDI name which your datasource is regsitered at.
The easiest way to do this is to navigate to JBoss' web-based JMX console and look for a 'JNDIView' (not exactly sure of the name - currently at home) mbean. This mbean should have a list method which you can invoke, which will display the context path for all of the JNDI-bound objects.
I had some similar issue with Jboss Embedded and i finally fix playing in the file:
test-Datasource-ds.xml
adding
<mbean code="org.jboss.naming.NamingAlias" name="jboss.jmx:alias=testDatasource">
<attribute name="FromName">jdbc/Example DataSource</attribute>
<attribute name="ToName">java:/testDatasource</attribute>
</mbean>
The problem was jboss add the prefix java:/ for all data source declared. So finally i had a datasource named testDatasource, overrided with that directive to jdbc/Example DataSource
Hope it works