Deploying OCI Applications Under The Same JVM

In my previous post, I have been talking about deploying an ADF application that uses OCI driver to connect to Oracle database. I have mentioned that there are some additional problems that may arise when deploying more than one application under the same JVM with multiple classloaders — something that you run into when using Tomcat, for example.

So , you have two (or more) applications that use OCI driver. That means that you each of your applications loads a native library when loading a driver. This is all fine, unless you do this in different classloaders under the same JVM – in that case, you will get the following error:

java.lang.UnsatisfiedLinkError: Native Library C:\oraclexe\app\oracle\product\10.2.0\ server\BIN\ocijdbc10.dll already loaded in another classloader

… or something very similar. Tomcat classloaders architecture basically looks like this:

      Bootstrap
          |
       System
          |
       Common
      /      \
 Catalina   Shared
             /   \
        Webapp1  Webapp2 ...

So your web applicatons have their own classloaders (Webapp1, Webapp2, etc.) — meaning that all the JAR files inside your application’s WEB-INF/lib will be loaded in different classloaders, all having a “shared” class loader as a parent. Thus, by having your ojdbc14.jar / ojdbc14_g.jar in WEB-INF/lib directory of each application, the API for OCI driver (stored in OJDBC JARs) will load the native libraries in different classloaders. The cure here is pretty easy, all you have to do is to put ojdbc14.jar / ojdbc14_g.jar to $CATALINA_HOME/shared/lib – in case of an ADF application, all the ADF jar files, together with OJDBC jar files should rather be put into $CATALINA_HOME/common/lib.

Now, if your ADF application anyway produces some strange errors like JBO-30003: The application pool ... failed to checkout an application module, or strange occurrence of NullPointerException, ClassNotFoundException, followed by Too many open files error and eventually causing your Tomcat to freeze / crash, there might be some additional, eventually cyclic, dependencies.

The example could be another JAR file that is connected with ojdbc14.jar and should be put inside the same classloader. You may have bc4jdatum.jar on your application’s classpath — if you are really, really sure you need it – most probably you don’t -, move it to $CATALINA_HOME/common/lib. There are some other sources of weird problems, like mixing both bc4jdomgnrc.jar and bc4jdomorcl.jar in the same classpath. More on these two possible sources of confusion can be found here.

Deploying Oracle ADF Faces Application Using OCI Driver

Lately, I have been working with Oracle ADF Faces for some time. Despite some features missing in JDeveleoper when compared to popular Java IDEs like Eclipse or IntelliJ Idea, the development went quite smoothly. I have jumped into an “almost-done” project to resolve some of its issues. One of the issue was that users were not able to change the password in Oracle database using the application, nor was the application able to detect expired passwords. After I have done some Google investigation, I have found that:

  • it is not possible to do password change using JDBC Thin driver, one has to use OCI driver instead;
  • OCI drivers use native libraries and require Oracle client installed.

Great! I had Oracle XE installed on my laptop and at least I thought I knew what to do and I expected a transition to OCI driver to be as simple as replacing the thin in the connection string by oci8. Well, it wasn’t that easy. There were couple of other things that had to be done each one leading to another JBO error, UnsatisfiedLinkError, SQLException or some other kind of monster. While there are many discussions on the web, especially in Oracle forums, I have not found them complete enough so I decided to make you guys life a little easier by learning from my mistakes ;).

So here is checklist I recommend you to check before you try to pull your hear from head in a total despair:

Assure that you have Oracle client correctly installed on your computer

Check whether you have Oracle client correctly installed and the PATH variable is correctly set to include Oracle folder with DLL files. That is, for Windows machines, you should have ORACLE_HOME\bin in your PATH variable, on Unix / Solaris systems your LD_LIBRARY_PATH should include ORACLE_HOME/lib and also ORACLE_HOME/lib32 in case you are running 32-bit JVM against 64-bit Oracle database. I recommend you to check the system variables using this guide.

Check your application server / JDeveloper embedded server libraries

Well, if you simply use JDeveloper embedded server and you are getting UnsatisfiedLinkErrors like this:

java.lang.UnsatisfiedLinkError: t2cGetCharSet
at oracle.jdbc.driver.T2CConnection.t2cGetCharSet(Native Method)
at oracle.jdbc.driver.T2CConnection.getCharSetIds( T2CConnection.java:2801)
at oracle.jdbc.driver.T2CConnection.logon(T2CConnection.java:300)
at oracle.jdbc.driver.PhysicalConnection.<init>( PhysicalConnection.java:344)
at oracle.jdbc.driver.T2CConnection.<init>(T2CConnection.java:136)
at oracle.jdbc.driver.T2CDriverExtension.getConnection( T2CDriverExtension.java:79)

most probably you do not have the right ojdbc14.jar and ojdbc14_g.jar in jdbc/lib directory inside JDeveloper home directory. These jar files have to match the version of native libraries of your Oracle client. Replace them with jar files contained in your Oracle client’s jdbc/lib directory and you should be fine. It might happen, however, that you won’t get rid of this exception as it happend also to me. Then you have to check the libraries on your classpath. Most probably you have some kind of additional incorrect ojdbc14dms.jar or even ojdbc14.jar / ojdbc14_g.jar set in JDeveloper’s libraries settings – check both Model and ViewController and get rid of them. The point is that you might have some bad jar file on your classpath that overrides correct jars inside jdbc/lib directory.

To deploy the application inside third-party application server or servlet container (such as Tomcat), it should be enough to include the correct ojdbc14.jar / ojdbc14_g.jar files in your WAR archive’s WEB-INF/lib (this won’t work in case you want to deploy multiple applications that use OCI driver, because of Java Virtual Machine’s inability to load the same native libraries in different class loaders – in that case you should put ojdbc14.jar / ojdbc14_g.jar files inside shared/lib folder of Tomcat instead. This might have some additional issues, I will write about that in some of the future posts, hopefully :) ).

Check your connection strings

So you have double-checked all the settings and still getting some kind of error like ORA-12154: TNS:could not resolve the connect identifier specified. It even might happen that on some environments it might work, while keeping returning this error on the others — with almost the same settings in your tnsnames.ora file. Yes, the error could mean that your ORACLE_HOME/network/admin/tnsnames.ora is wrong or could not be found. So anyway, check whether the file is correct and environment paths and permissions are set correctly. You can check it by using sqlplus client to connect to the specified service. However, if sqlplus connects flawlessly, there might be an error in connection string used in your application.

The application I have been working on, used the following connection string:

jdbc:oracle:oci8@//localhost:1521:XE

XE here is name of the service as it can be defined in tnsnames.ora file. While this worked well on my laptop and on development environment that used HP-UX system with Oracle 10.1.0 installed, it didn’t work on another HP-UX system (testing environment) with Oracle 10.1.0 database. After I have checked all the settings multiple times, I have found that the correct OCI8 connection string should look like this:

jdbc:oracle:oci8@SERVICE_NAME

Replace the SERVICE_NAME string with service name you want to use and… voila! In my case it finally worked on all environments.

As I mentioned above, this checklist does not include some other issues you might run into when trying to deploy mutliple applications using OCI driver under the same application server. But it should help you in case you want to simply run a single web application. Good luck!