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
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
$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
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
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
bc4jdomorcl.jar in the same classpath. More on these two possible sources of confusion can be found here.
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:
at oracle.jdbc.driver.T2CConnection.t2cGetCharSet(Native Method)
at oracle.jdbc.driver.T2CConnection.getCharSetIds( T2CConnection.java:2801)
at oracle.jdbc.driver.PhysicalConnection.<init>( PhysicalConnection.java:344)
at oracle.jdbc.driver.T2CDriverExtension.getConnection( T2CDriverExtension.java:79)
most probably you do not have the right
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_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
To deploy the application inside third-party application server or servlet container (such as Tomcat), it should be enough to include the correct
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_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:
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:
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!
If you are into photography and Nikon, I am sure you know Nikonians.org website (if you don’t, then you have to know that you are really missing out on something, don’t waste your time and check them out :) ). The site has its own search engine called NikoScope ® and it is available at http://www.nikoscope.com/.
I have participated in the creation of this website and I enjoyed it A LOT. Whole site is written in Java with the help of Lucene indexer using modern technologies like JSF, JBoss SEAM, Google Guice and EJB3. Last week, we have released a new version which brings many new features like ability to add a Nikonian into your buddies or to see other fellow Nikonians on a map. You can even see Nikonians that are not further than e.g. 100 miles – all you have to do is to use the inRadius operator like this.
Of course, you have to be a member of Nikonians.org to use these features. There is also official Nikonians blog post about this release. Enjoy!