Search code examples
javatomcattomcat8

Tomcat throwing error "java.lang.ClassNotFoundException: org.apache.naming.java.javaURLContextFactory"


I am trying to open database connection from my code using datasource. The webapp is deployed in Tomcat. But when opening connection Tomcat throws below error:

javax.naming.NoInitialContextException: Cannot instantiate class: org.apache.naming.java.javaURLContextFactory
at javax.naming.spi.NamingManager.getInitialContext(Unknown Source) ~[?:1.8.0_161]
at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source) ~[?:1.8.0_161]
at javax.naming.InitialContext.init(Unknown Source) ~[?:1.8.0_161]
at javax.naming.InitialContext.<init>(Unknown Source) ~[?:1.8.0_161]
at com.profinch.fincluez.jdbc.JDBCConnection$ConnectionHandler.<init>(JDBCConnection.java:244) [classes/:?]
at com.profinch.fincluez.jdbc.JDBCConnection$ConnectionHandler.<init>(JDBCConnection.java:214) [classes/:?]
at com.profinch.fincluez.jdbc.JDBCConnection.getConnection(JDBCConnection.java:86) [classes/:?]
at com.profinch.fincluez.jdbc.RDBMSQueryEngine.loadData(RDBMSQueryEngine.java:190) [classes/:?]
at com.profinch.fincluez.jdbc.QueryEngineWrapper.loadData(QueryEngineWrapper.java:62) [classes/:?]
at com.profinch.fincluez.infra.loaders.ConfigLoaderQueryMode.loadData(ConfigLoaderQueryMode.java:64) [classes/:?]
at com.profinch.fincluez.infra.loaders.ConfigLoaderQueryMode.compute(ConfigLoaderQueryMode.java:82) [classes/:?]
at com.profinch.fincluez.infra.loaders.ConfigLoaderQueryMode.compute(ConfigLoaderQueryMode.java:1) [classes/:?]
at java.util.concurrent.RecursiveTask.exec(Unknown Source) [?:1.8.0_161]
at java.util.concurrent.ForkJoinTask.doExec(Unknown Source) [?:1.8.0_161]
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(Unknown Source) [?:1.8.0_161]
at java.util.concurrent.ForkJoinPool.runWorker(Unknown Source) [?:1.8.0_161]
at java.util.concurrent.ForkJoinWorkerThread.run(Unknown Source) [?:1.8.0_161]

Caused by: java.lang.ClassNotFoundException: org.apache.naming.java.javaURLContextFactory
at java.net.URLClassLoader.findClass(Unknown Source) ~[?:1.8.0_161]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.8.0_161]
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) ~[?:1.8.0_161]
at java.lang.ClassLoader.loadClass(Unknown Source) ~[?:1.8.0_161]
at java.lang.Class.forName0(Native Method) ~[?:1.8.0_161]
at java.lang.Class.forName(Unknown Source) ~[?:1.8.0_161]
at com.sun.naming.internal.VersionHelper12.loadClass(Unknown Source) ~[?:1.8.0_161]
at com.sun.naming.internal.VersionHelper12.loadClass(Unknown Source) ~[?:1.8.0_161]
... 17 more

Thing is I am able to see my web-app is able to open 3 connections then load properties and partial configuration from database and then close those properly. This I know because I have a centralized API through which all connections are being opened and closed. So there I am keeping count of number of connections getting opened and closed. But from 4th connection onwards I get this error. I am running several threads and each thread is opening and closing connection and each of them fails with this same error.

Code to open Connection:

InitialContext initialContext = new InitialContext();//throwing exception here
DataSource dataSource = (DataSource) initialContext.lookup("java:/comp/env/jdbc/OracleDS");
Connection l_conn = dataSource.getConnection ();

Datasource details in Tomcat:

<Resource name="jdbc/OracleDS" auth="Container" type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver" username="test" password="test" url="jdbc:oracle:thin:@localhost:1521/sid" initialSize="5" maxTotal="15" defaultAutoCommit="false" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"/>

This issue is in Tomcat only and when I deploy my code in Wildfly11/Glassfish and connect to its Datasource I face no issues and code runs smoothly.

I have gone through some posts and some suggested to do the below thing but still getting same error:

Properties l_props = new Properties();
l_props.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.naming.java.javaURLContextFactory");
l_props.put(Context.URL_PKG_PREFIXES, "org.apache.naming");
InitialContext initialContext = new InitialContext(l_props);//Still throws Exception

Environment Details

  • Java 1.8.0_161
  • Tomcat 8.5 (same error on Tomcat 9.0.6)
  • OS: Windows 10 Pro 64 bit

Note: I am runing the web-app from Tomcat server and not from any IDE and not using JUnit.

[Update: 15-March-2018]: I have some how managed to narrow down the problem. I am running several tasks in parallel using Fork Join Framework and each task opens a dedicated connection and closes it. Tasks are not using any shared connection. So this error appears when all task runs in parallel. If I change the code to run these task sequentially by giving the ForkJoinPool size as 1 then this error does not appear. Currently I have 5 tasks running in parallel and my data source connection pool size is configured with maxTotal=20. Not sure what is happening.

[Update 16-Match-2018]: If anybody is interested to simulate this issue, I have uploaded test code on Git. URL: Git Hub Repository


Solution

  • I was able to find the answer after posting the same to Tomcat's mailing list. From the discussions there it seems this is happening due to memory leak fix provided in Tomcat. Refer to the following link Tomcat Bug 60620

    and the various threads linked from there.

    I wrote the following code just before creating the initial context and JNDI lookup to resolve this issue:

    //Fix Start
    Thread l_thread = Thread.currentThread();
    l_thread.setContextClassLoader(this.getClass().getClassLoader());
    //Fix End
    initialContext  = new InitialContext();