上下文是只读的

时间:2013-01-29 10:05:38

标签: java spring tomcat servlets jndi

Helo大师,我必须动态创建一个JNDI数据源,我试着用一个叫做SetupApplicationListener的监听器来做。这是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>

听众的代码:

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);
    }

.....
}

有错误:

[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)

我可以将Context的只读属性设置为“true”吗?谢谢! :)

Tomcat 6.0
Oracle 11g
jdk1.5

编辑:不需要动态,我必须在内部定义jndi数据源我无法修改服务器文件,因为它是共享服务器。它必须是jndi,因为其他模块以这种方式使用它,谢谢。

7 个答案:

答案 0 :(得分:4)

如果需要动态创建数据源,是否真的需要JNDI查找? JNDI旨在使应用程序外部连接,而在您的场景中,由于合法的要求,它与应用程序紧密耦合。为什么不直接使用JDBC连接?

答案 1 :(得分:2)

之前我没有遇到过这个问题,因为我经常在应用服务器(tomcat,weblogic等)中定义JNDI。就像凯文所说的那样,这正是JNDI的设计目标;将数据源配置与源代码分离,并通过查找和注入检索JNDI资源;

回到你的问题,我认为tomcat在运行时有很多关于修改JNDI的严格规则。换句话说,您无法从Context重新绑定或删除jndi。如果你通过tomcat规范,你可能会看到一些关于jndi查找但没有重新绑定的事情。

答案 2 :(得分:2)

来自EE 6平台规范(JSR 316)的EE.5.3.4节:

  

容器必须确保应用程序组件实例   只有对其命名上下文的读访问权限。容器必须   抛出所有的javax.naming.OperationNotSupportedException   修改的javax.naming.Context接口的方法   环境命名上下文及其子上下文。

请注意,本节中的“命名上下文”是指java:comp

答案 3 :(得分:2)

你需要创建一个ServletContextListener,你可以在那里使InitialContext可写 - 这不是它应该做的方式,但如果你真的需要它,这是你可以做到的一种方式。

这也适用于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();
    }
}

答案 4 :(得分:0)

我发现我正在关闭environmentContext对象时解决了这个问题 例如:

Context context=new InitialContext();
Context environmentContext=(Context) context.lookup("java:comp/env");

我的代码是:

environmentContext.close();

从environmentContext中删除close函数后,问题被解决了;

答案 5 :(得分:0)

我也遇到过这个问题,但对Tomee来说是新手,我不知道有一个简单的解决方案。当我将我的Web应用程序部署到webapps文件夹时,该应用程序工作正常,但当我将其部署到服务文件夹时,我得到了相同的中止。问题是文件夹名称与战争名称(减去.war)不匹配。一旦我解决了这个问题,应用程序运行良好。确保战争名称,文件夹名称和服务名称相同。此问题会产生几个不同的错误,包括Context是只读和Error合并Java EE JNDI条目。

答案 6 :(得分:0)

我通过在context.xml中设置useNaming="false"解决了这个问题。

From the documentation

  

useNaming:设置为true(默认值)以使Catalina对此Web应用程序启用与Java2 Enterprise Edition(J2EE)平台约定兼容的JNDI InitialContext。