Context is read only
Solution 1
If you need to create a datasource dynamically is there really any need for a JNDI lookup? JNDI is designed to make the connection external to the application, while in your scenario its tightly coupled to the application due to a legitimate requirement. Why not just use a JDBC connection?
Solution 2
You need to create a ServletContextListener and there you can make the InitialContext writable - it's not the way it should be done, but if you really need it, this is one way you can do it.
This also works with Java Melody!
protected void makeJNDIContextWritable(ServletContextEvent sce) {
try {
Class<?> contextAccessControllerClass = sce.getClass().getClassLoader().loadClass("org.apache.naming.ContextAccessController");
Field readOnlyContextsField = contextAccessControllerClass.getDeclaredField("readOnlyContexts");
readOnlyContextsField.setAccessible(true);
Hashtable readOnlyContexts = (Hashtable) readOnlyContextsField.get(null);
String context = null;
for (Object key : readOnlyContexts.keySet()) {
String keyString = key + "";
if (keyString.endsWith(sce.getServletContext().getContextPath())) {
context = keyString;
}
}
readOnlyContexts.remove(context);
} catch (Exception ex) {
ex.printStackTrace();
}
}
Solution 3
I haven't got this problem before since I usually defined JNDI in application server(tomcat, weblogic and etc). Just like what Kevin said, this is exactly what JNDI was designed for; separating datasource config from your source code and retrieving JNDI resources through lookup and inject;
Back to your question, I think tomcat has every strict rules on modifying JNDI at runtime. In another word, you cannot re-bind or remove jndi from Context. If you go through the tomcat specification you will probably see some thing about jndi lookup but no re-bind.
Solution 4
From section EE.5.3.4 of the EE 6 platform specification (JSR 316):
The container must ensure that the application component instances have only read access to their naming context. The container must throw the javax.naming.OperationNotSupportedException from all the methods of the javax.naming.Context interface that modify the environment naming context and its subcontexts.
Note that "their naming context" in this section is referring to java:comp
.
rubenGL
Updated on August 15, 2022Comments
-
rubenGL over 1 year
Helo masters, I have to create a JNDI Datasource dynamically, I tried to do it with a listener called SetupApplicationListener. Here is the beginning of
WEB-LIB/web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee"> <display-name>pri-web</display-name> <!-- Listeners --> <listener> <listener-class>org.apache.myfaces.webapp.StartupServletContextListener</listener-class> </listener> <listener> <listener-class>myapp.SetupApplicationListener</listener-class> </listener>
The code of the listener:
public class SetupApplicationListener implements ServletContextListener { public static Log LOG = null; public void contextInitialized(ServletContextEvent ctx){ try { createOracleDataSource(); ..... } } private void createOracleDataSource() throws SQLException, NamingException { OracleDataSource ds = new OracleDataSource(); ds.setDriverType(...); ds.setServerName(...); ds.setPortNumber(...); ds.setDatabaseName(...); ds.setUser(...); ds.setPassword(...); new InitialContext().bind("java:comp/env/jdbc/myDS", ds); } ..... }
And there is the error:
[ERROR] 29/01/2013 09:44:50,517 (SetupApplicationListener.java:86) -> Error javax.naming.NamingException: Context is read only at org.apache.naming.NamingContext.checkWritable(NamingContext.java:903) at org.apache.naming.NamingContext.bind(NamingContext.java:831) at org.apache.naming.NamingContext.bind(NamingContext.java:171) at org.apache.naming.NamingContext.bind(NamingContext.java:187) at org.apache.naming.SelectorContext.bind(SelectorContext.java:186) at javax.naming.InitialContext.bind(InitialContext.java:359) at myapp.SetupApplicationListener.createOracleDataSource(SetupApplicationListener.java:102)
Can I set the read-only properties of the Context to "true"? Thanks! :)
Tomcat 6.0 Oracle 11g jdk1.5
EDIT: Don't need to be dynamically, i have to define a jndi datasource internally I can't modify the server files because it is a shared server. It must be jndi because other modules use it in that way, thanks.
-
rubenGL over 11 yearsbecause there are some modules that ref the connetion with jndi. Due to security issues they dont want to place the conection values (user, pass, ...) in the server because it is a shared server.
-
rubenGL over 11 yearsI need to define a jndi datasource in the app, internally, do u know another way to do it without a listener?
-
rubenGL over 11 yearsThere are some modules that ref the connetion with jndi. Due to security issues they dont want to place the conection values (user, pass, ...) in the server because it is a shared server. I need to define a jndi datasource in the app, internally, do u know another way to do it without a listener?
-
rubenGL over 11 yearsDont need to be dinamically
-
Kevin Bowersox over 11 years@rubenGL but couldn't they just check the context.xml file to get these values?
-
rubenGL over 11 yearsDont need to be dinamically
-
rubenGL over 11 yearscontext.xml is a server file they dont want to put the connection values in the server
-
Anugoonj over 11 years+1 user2021142 , JNDI is meant to decouple the source code from the connectivity config. The JNDI configurations on the server can be restricted to only Admin users if that is what serves the purpose of security. Also, the database connection can be SSL enabled to avoid any malicious lookups.
-
Anugoonj over 11 years@rubenGL If the connection string is in the soruce code even then somone(assuming has access to tomcat) can extract the .class file and decompile to check the connection string, unless the class have been obfiscated with zero tolerance of getting the source code.
-
John Eipe about 10 yearsI remember reading that in EE6, they brought java:global which is not-read-only. Any idea about this? I haven't used it before.