Сбой поиска ejb с помощью NamingException

Я добавил следующее в мой web.xml:

<ejb-ref>
        <ejb-ref-name>ejb/userManagerBean</ejb-ref-name>
        <ejb-ref-type>Session</ejb-ref-type>
        <home>gha.ywk.name.entry.ejb.usermanager.UserManagerHome</home>
        <remote>what should go here??</remote>
</ejb-ref>

Следующий код Java дает мне исключение NamingException:

public UserManager getUserManager () throws HUDException {
    String ROLE_JNDI_NAME = "ejb/userManagerBean";
    try {
        Properties props = System.getProperties();
        Context ctx = new InitialContext(props);
        UserManagerHome userHome = (UserManagerHome) ctx.lookup(ROLE_JNDI_NAME);
        UserManager userManager = userHome.create();
        WASSSecurity user = userManager.getUserProfile("user101", null);
        return userManager;
    } catch (NamingException e) {
        log.error("Error Occured while getting EJB UserManager" + e);
        return null;
    } catch (RemoteException ex) {
        log.error("Error Occured while getting EJB UserManager" + ex);
        return null;
    } catch (CreateException ex) {
        log.error("Error Occured while getting EJB UserManager" + ex);
        return null;
    }
}

Код используется внутри контейнера. Под этим я подразумеваю, что.WAR развернут на сервере (Sun Application Server).

StackTrace (после предложения jsight):

>Exception occurred in target VM: com.sun.enterprise.naming.java.javaURLContext.<init>(Ljava/util/Hashtable;Lcom/sun/enterprise/naming/NamingManagerImpl;)V 
java.lang.NoSuchMethodError: com.sun.enterprise.naming.java.javaURLContext.<init>(Ljava/util/Hashtable;Lcom/sun/enterprise/naming/NamingManagerImpl;)V
 at com.sun.enterprise.naming.java.javaURLContextFactory.getObjectInstance(javaURLContextFactory.java:32)
 at javax.naming.spi.NamingManager.getURLObject(NamingManager.java:584)
 at javax.naming.spi.NamingManager.getURLContext(NamingManager.java:533)
 at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:279)
 at javax.naming.InitialContext.lookup(InitialContext.java:351)
 at gov.hud.pih.eiv.web.EjbClient.EjbClient.getUserManager(EjbClient.java:34)

4 ответа

Я думаю, что вы хотите получить доступ к приложению EJB (известному как модуль EJB) из веб-приложения в Sun Application Server, верно?

хорошо пойдем.

Когда вы развертываете EJB на сервере приложений, сервер приложений дает ему адрес - известный как глобальный адрес JNDI - как способ доступа к нему (что-то вроде вашего адреса). Он меняется с сервера приложений на другой.

На сервере приложений JBoss вы можете увидеть глобальный адрес JNDI (после его запуска) по следующему адресу

http://127.0.0.1:8080/jmx-console/HtmlAdaptor

В Sun Application Server, если вы хотите увидеть глобальный адрес JNDI (после его запуска), сделайте следующее

Получите доступ к консоли администратора по следующему адресу

http://127.0.0.1:4848/asadmin

И нажмите JNDI просмотра

Если ваш EJB НЕ зарегистрирован прямо там, значит что-то не так

EJB поставляется в двух вариантах: EJB 2.1 и EJB 3.0. Так в чем же разница?

Так так так...

Начнем с EJB 2.1

  1. Создать домашний интерфейс

Он определяет методы для СОЗДАНИЯ, уничтожения и поиска локальных или удаленных объектов EJB. Он действует как интерфейс жизненного цикла для объектов EJB. Все домашние интерфейсы должны расширять стандартный интерфейс javax.ejb.EJBHome - если вы используете удаленный объект ejb - или javax.ejb.EJBLocalHome - если вы используете локальный объект EJB.

// a remote EJB object - extends javax.ejb.EJBHome
// a local EJB object - extends javax.ejb.EJBLocalHome
public interface MyBeanRemoteHome extends javax.ejb.EJBHome {

    MyBeanRemote create() throws javax.ejb.CreateException, java.rmi.RemoteException;

}

Сервер приложений будет создавать объекты Home как способ получения объекта EJB, и ничего более.

Позаботьтесь о следующем

Удаленный домашний интерфейс сессионного компонента ДОЛЖЕН ОПРЕДЕЛИТЬ ОДИН ИЛИ БОЛЬШЕ создать методы <МЕТОД>. Сессионный компонент без сохранения состояния ДОЛЖЕН ОПРЕДЕЛИТЬ ровно один метод без аргументов.

...

Предложение throws ДОЛЖНО ВКЛЮЧИТЬ javax.ejb.CreateException

...

Если ваш домашний интерфейс расширяет javax.ejb.EJBHome, элементы throws ДОЛЖНЫ ВКЛЮЧАТЬ исключение java.rmi.RemoteException. Если он расширяет javax.ejb.EJBLocalHome, НЕ ДОЛЖЕН ВКЛЮЧАТЬ исключение java.rmi.RemoteException.

...

Каждый метод create сессионного компонента с сохранением состояния ДОЛЖЕН БЫТЬ ИМЕНИ create , и он должен соответствовать одному из методов Init или ejbCreate , определенных в классе сессионного компонента. Соответствующий метод ejbCreate ДОЛЖЕН ИМЕТЬ ТОЛЬКО НОМЕР И ТИПЫ АРГУМЕНТОВ. НЕОБХОДИМО, чтобы метод create для сессионного компонента без сохранения состояния имел подходящий метод ejbCreate.


Теперь создайте бизнес-интерфейс для определения бизнес-логики в нашем объекте EJB

// a remote EJB object - extends javax.ejb.EJBObject
// a local EJB object - extends javax.ejb.EJBLocalObject
public interface MyBeanRemote extends javax.ejb.EJBObject {

    void doSomething() throws java.rmi.RemoteException;

}

Теперь позаботьтесь о следующем

Если вы используете удаленный объект EJB, методы удаленного интерфейса НЕ ДОЛЖНЫ ОБРАТИТЬСЯ к типам локального интерфейса или типам локального домашнего интерфейса.

...

Если ваш домашний интерфейс расширяет javax.ejb.EJBObject, элементы throws ДОЛЖНЫ ВКЛЮЧАТЬ исключение java.rmi.RemoteException. Если он расширяет javax.ejb.EJBLocalObject, НЕ ДОЛЖЕН ВКЛЮЧАТЬ исключение java.rmi.RemoteException.


Теперь наш EJB

public class MyBean implements javax.ejb.SessionBean {

    // why create method ? Take a special look at EJB Home details (above)
    public void create() {
        System.out.println("create");
    }

    public void doSomething() throws java.rmi.RemoteException {
        // some code
    };

}

Теперь позаботьтесь о следующем

Это ДОЛЖНО РЕАЛИЗОВАТЬ javax.ejb.SessionBean. Он определяет четыре метода - не показанные выше: setSessionContext, ejbRemove, ejbPassivate и ejbActivate.

Обратите внимание, что наш bean-компонент НЕ РЕАЛИЗУЕТ наш бизнес-интерфейс, так как спецификация EJB гласит:

Для каждого метода, определенного в интерфейсе, должен быть соответствующий метод в классе сессионного компонента. Соответствующий метод должен иметь:

  • Одно и то же имя
  • Одинаковое количество и типы аргументов, и тот же тип возврата.
  • Все исключения, определенные в предложении throws соответствующего метода класса сессионного компонента, должны быть определены в предложении throws метода локального интерфейса.

И ВЫ ДОЛЖНЫ ОБЪЯВИТЬ файл ejb-jar.xml в соответствии с

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar 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 http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd" version="2.1">
    <enterprise-beans>
        <session>
            <ejb-name>HelloWorldEJB</ejb-name>
            <home>br.com.MyBeanRemoteHome</home>
            <remote>br.com.MyBeanRemote</remote>
            <local-home>br.com.MyBeanLocalHome</local-home>
            <local>br.com.MyBeanLocal</local>
            <ejb-class>br.com.MyBean</ejb-class>
            <session-type>Stateless</session-type>
            <transaction-type>Container</transaction-type>
        </session>
    </enterprise-beans>
</ejb-jar>

Если у вас нет локального объекта EJB, удалите его из описанного выше дескриптора развертывания.

<local-home>br.com.MyBeanLocalHome</local-home>
<local>br.com.MyBeanLocal</local>

Если у вас нет удаленного объекта EJB, удалите его из описанного выше дескриптора развертывания.

<home>br.com.MyBeanRemoteHome</home>
<remote>br.com.MyBeanRemote</remote>

И положить в каталог META-INF

Наш файл JAR будет содержать следующее

/META-INF/ejb-jar.xml
br.com.MyBean.class
br.com.MyBeanRemote.class
br.com.MyBeanRemoteHome.class

Теперь наш EJB 3.0

// or @Local
// You can not put @Remote and @Local at the same time
@Remote
public interface MyBean {

    void doSomething();

}

@Stateless
public class MyBeanStateless implements MyBean {

    public void doSomething() {

    }

}

Ничего больше,

В JBoss положить файл JAR в

<JBOSS_HOME>/server/default/deploy

В Sun Application Server доступ (после запуска) к консоли администратора

http://127.0.0.1:4848/asadmin

И получить доступ к модулям EJB, чтобы развернуть файл ejb-jar

Поскольку у вас возникают проблемы при развертывании приложения в NetBeans, я предлагаю следующее

  1. Создать простую библиотеку Java PROJECT (простой jar без основного метода)
  2. Добавьте /server/default/lib (содержит файлы jar для получения EJB-файлов) в ваше приложение Java, независимо от того, используете ли вы JBoss (я не знаю, какой каталог в Sun Application Server)
  3. Реализуйте код выше

Теперь создайте еще один проект войны

  1. Добавьте наш проект, созданный чуть выше, и добавьте / client (содержит файлы jar для доступа к нашим EJB). Опять же я не знаю, какой каталог в Sun Application Server. Проверяйте его документацию.
  2. Посмотрите его глобальный адрес сопоставления, как показано в верхней части ответа.

И внедрите следующий код в свой сервлет или что-то еще, используете ли вы JBoss

public static Context getInitialContext() throws javax.naming.NamingException {

    Properties p = new Properties();
    p.put(Context.INITIAL_CONTEXT_FACTORY,        "org.jnp.interfaces.NamingContextFactory");
    p.put(Context.URL_PKG_PREFIXES, " org.jboss.naming:org.jnp.interfaces");
    p.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");

    return new javax.naming.InitialContext(p);
}

Или в следующем случае, если вы используете Sun Application Server - поместите файл appserv-rt.jar (я не знаю, какое прошлое содержало appserv-rt.jar в Sun Application Server) в вашем classpath

public static Context getInitialContext() throws javax.naming.NamingException {

    return new javax.naming.InitialContext();

}

Чтобы получить доступ к вашему EJB в нашем сервлете или что-то еще

MyBeanRemote myBean = (MyBeanRemote) getInitialContext().lookup(<PUT_EJB_GLOBAL_ADDRESS_RIGHT_HERE>);

myBean.doSomething();

С уважением,

Возможно, строка поиска на самом деле должна выглядеть так: "java:comp/env/ejb/userManagerBean"?

Последние два ответа верны в том смысле, что это то, что вам нужно изменить / исправить. Но ошибка NoSuchMethodError, которую вы видите, не из вашего кода и не из вещей, пытающихся найти ваш код (я думаю, это вызвало бы какое-то исключение NoClassDefFoundException, если бы это было так). Это больше похоже на несовместимые версии поставщика JNDI, предоставляемые контейнером, и на то, что хочет реализация JNDI в библиотеке Java. Это довольно расплывчатый ответ, но можно предположить, что его можно решить, возможно, обновив сервер приложений и, гарантируя, что вы не развернете в своем приложении возможно устаревшие копии классов инфраструктуры, связанных с JNDI, которые могут помешать.

Сначала исправьте ваш web.xml и добавьте в него удаленный интерфейс:

<ejb-ref>
  <description>Sample EJB</description>
  <ejb-ref-name>SampleBean</ejb-ref-name>
  <ejb-ref-type>Session</ejb-ref-type>
  <home>com.SampleHome</home>
  <remote>com.Sample</remote> <!-- the remote interface goes here -->
</ejb-ref>

Тогда относительно java.lang.NoSuchMethodError, Шон прав, у вас несоответствие между версией "клиентской библиотеки" сервера приложений, которую вы используете внутри NetBeans, и версией сервера приложений (на стороне сервера). Хотя я не могу точно сказать, какие JAR-файлы вам нужно выровнять, обратитесь к документации Sun Application Server.

PS: Это не прямой ответ на проблему, но я не думаю, что вы в настоящее время передаете какие-либо полезные свойства при создании исходного контекста с результатами вызова System.getProperties()в этих свойствах нет ничего полезного для определения среды контекста (например, исходной фабрики контекста). Обратитесь к InitialContext javadocs для получения дополнительной информации.

Другие вопросы по тегам