问题
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.
回答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?
回答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();
}
}
回答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.
回答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
.
回答5:
I solved this problem when found that I was closing environmentContext object For example:
Context context=new InitialContext();
Context environmentContext=(Context) context.lookup("java:comp/env");
And my code was:
environmentContext.close();
After removing close function from environmentContext problem was solded for me;
回答6:
I also had this problem, but being new to Tomee, I didn't know that there is a simple solution. When I deployed my web app to the webapps folder, the app worked fine, but when I deployed it to a service folder, I got the same abort. The problem was that the folder name did not match the war name (minus the .war). Once I fixed that, the app worked fine. Make sure the war name, folder name and service name are identical. This problem produces several different errors, including Context is read only and Error merging Java EE JNDI entries.
回答7:
I solved this issue by setting useNaming="false"
in my context.xml.
From the documentation:
useNaming : Set to true (the default) to have Catalina enable a JNDI InitialContext for this web application that is compatible with Java2 Enterprise Edition (J2EE) platform conventions.
来源:https://stackoverflow.com/questions/14580286/context-is-read-only