Контекст доступен только для чтения

Здравствуйте, мастера, мне нужно динамически создать источник данных 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

EDIT: не нужно быть динамическим, мне нужно определить источник данных jndi внутри. Я не могу изменять файлы сервера, потому что это общий сервер. Это должно быть jndi, потому что другие модули используют его таким образом, спасибо.


person rubenGL    schedule 29.01.2013    source источник
comment
решена благодаря OscarRyz /а>   -  person rubenGL    schedule 30.01.2013


Ответы (7)


Если вам нужно создать источник данных динамически, есть ли необходимость в поиске JNDI? JNDI предназначен для того, чтобы сделать соединение внешним по отношению к приложению, в то время как в вашем сценарии оно тесно связано с приложением из-за законного требования. Почему бы просто не использовать соединение JDBC?

person Kevin Bowersox    schedule 29.01.2013
comment
потому что есть некоторые модули, которые ссылаются на соединение с jndi. Из-за проблем с безопасностью они не хотят размещать значения подключения (пользователь, пароль, ...) на сервере, потому что это общий сервер. - person rubenGL; 29.01.2013
comment
Мне нужно определить источник данных jndi в приложении, знаете ли вы другой способ сделать это без слушателя? - person rubenGL; 29.01.2013
comment
Не нужно быть динамичным - person rubenGL; 29.01.2013
comment
@rubenGL, но не могли бы они просто проверить файл context.xml, чтобы получить эти значения? - person Kevin Bowersox; 29.01.2013
comment
context.xml — это серверный файл, в котором они не хотят размещать значения соединения на сервере. - person rubenGL; 29.01.2013
comment
@rubenGL Если строка подключения находится в исходном коде, даже тогда кто-то (при условии, что у него есть доступ к tomcat) может извлечь файл .class и декомпилировать его для проверки строки подключения, если только класс не был скрыт с нулевой терпимостью к получению исходного кода. - person Anugoonj; 29.01.2013

Вам нужно создать 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();
    }
}
person Halko Karr-Sajtarevic    schedule 22.03.2016

Раньше у меня не было этой проблемы, так как я обычно определял JNDI на сервере приложений (tomcat, weblogic и т. д.). Как и сказал Кевин, это именно то, для чего был разработан JNDI; отделение конфигурации источника данных от исходного кода и получение ресурсов JNDI посредством поиска и внедрения;

Возвращаясь к вашему вопросу, я думаю, что у tomcat есть все строгие правила по изменению JNDI во время выполнения. Другими словами, вы не можете повторно привязать или удалить jndi из контекста. Если вы просмотрите спецификацию tomcat, вы, вероятно, увидите что-то о поиске jndi, но не о повторном связывании.

person spiritwalker    schedule 29.01.2013
comment
Есть несколько модулей, которые ссылаются на соединение с jndi. Из-за проблем с безопасностью они не хотят размещать значения подключения (пользователь, пароль, ...) на сервере, потому что это общий сервер. Мне нужно определить источник данных jndi в приложении, знаете ли вы другой способ сделать это без слушателя? - person rubenGL; 29.01.2013
comment
Не нужно быть динамичным - person rubenGL; 29.01.2013
comment
+1 user2021142 , JNDI предназначен для отделения исходного кода от конфигурации подключения. Конфигурации JNDI на сервере могут быть ограничены только пользователями-администраторами, если это служит целям безопасности. Кроме того, для подключения к базе данных может быть включен SSL, чтобы избежать злонамеренных поисков. - person Anugoonj; 29.01.2013

Из раздела EE.5.3.4 спецификации платформы EE 6 (JSR 316):

Контейнер должен гарантировать, что экземпляры компонентов приложения имеют доступ только для чтения к своему контексту именования. Контейнер должен генерировать исключение javax.naming.OperationNotSupportedException из всех методов интерфейса javax.naming.Context, которые изменяют контекст именования среды и его подконтексты.

Обратите внимание, что «их контекст именования» в этом разделе относится к java:comp.

person Brett Kail    schedule 29.01.2013
comment
Я помню, как читал, что в EE6 они добавили java:global, который доступен не только для чтения. Любая идея об этом? Я не использовал его раньше. - person John; 22.02.2014

Я решил эту проблему, когда обнаружил, что закрываю объект environmentContext. Например:

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

И мой код был:

environmentContext.close();

После удаления функции close из environmentContext проблема для меня была решена;

person Kaxa    schedule 21.11.2015

У меня тоже была эта проблема, но, будучи новичком в Tomee, я не знал, что есть простое решение. Когда я развернул свое веб-приложение в папке веб-приложений, приложение работало нормально, но когда я развернул его в папке службы, я получил такое же прерывание. Проблема заключалась в том, что имя папки не соответствовало имени войны (минус .war). Как только я это исправил, приложение заработало нормально. Убедитесь, что имя войны, имя папки и имя службы совпадают. Эта проблема вызывает несколько различных ошибок, в том числе Контекст только для чтения и Ошибка слияния записей Java EE JNDI.

person Jim Reitz    schedule 08.12.2017

Я решил эту проблему, установив useNaming="false" в свой context.xml.

Из документации:

useNaming : установите значение true (по умолчанию), чтобы Catalina включила JNDI InitialContext для этого веб-приложения, совместимого с соглашениями платформы Java2 Enterprise Edition (J2EE).

person alarive    schedule 25.07.2018