EJB Factory Class - PullRequest
       37

EJB Factory Class

2 голосов
/ 06 августа 2009

Я пытаюсь создать фабричный класс EJB, который работает следующим образом: у вас есть метод, который принимает в качестве аргумента класс EJB, а затем проверяет, имеет ли EJB удаленный интерфейс (если не выдает исключение) и если он это делает, он возвращает соответствующий EJB.

Код ниже делает именно это. Однако возвращаемый объект относится к типу удаленного интерфейса соответствующего компонента, а не к самому компоненту. Как я могу изменить это? Есть ли способ сообщить Java, что универсальный тип T относится к тому же типу, что и класс, переданный методам.

import java.util.Properties;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.naming.*;


public class EJBFactory
{

    private InitialContext ctx;

    public EJBFactory() throws NamingException {
        ctx = new InitialContext();
    }

    public EJBFactory(String host, String port) throws NamingException {
        Properties props = new Properties();
        props.setProperty("org.omg.CORBA.ORBInitialHost", host);
        props.setProperty("org.omg.CORBA.ORBInitialPort", port);
        ctx = new InitialContext(props);
    }
.
    // To improve: The object returned should be of the type ejbClass
    // instead of the remote interface, which it implements
    public <T> T createEJB(Class ejbClass) throws NamingException
    {
        Class remoteInterface = null;
        for(Class interface_: ejbClass.getInterfaces()) {
            if(interface_.isAnnotationPresent(Remote.class))
                remoteInterface = interface_;
        }

        if(remoteInterface == null)
            throw new  IllegalArgumentException(
                "EJB Requires a remote interface");

        // Get the stateless annotation, then get the jndiName
        Stateless stateless =
            (Stateless)ejbClass.getAnnotation(Stateless.class);
        String jndiName = stateless.mappedName();
        T ejbObj = (T) ctx.lookup(jndiName);
        return ejbObj;
    }

}

Пример модульного теста, в котором используется Фабрика.

import junit.framework.TestCase;


public class SimpleEJBTest extends TestCase
{
    TestRemote testBean;

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        EJBFactory ejbFactory = new EJBFactory();
        testBean = ejbFactory.createEJB(TestBean.class);
    }

    public void testSayHello() {
        assertEquals("Hello", testBean.sayHello());
    }
}

Примечание: пример работает с Glassfish, я не тестировал его с любым другим сервером приложений.

Ответы [ 4 ]

3 голосов
/ 17 августа 2009

Клиенты EJB взаимодействуют с ними через локальный / удаленный интерфейс, который реализуют EJB. Клиентские приложения никогда не имеют прямого доступа к реальному экземпляру класса сессионного компонента. Это сделано для того, чтобы сделать возможным пул экземпляров, когда контейнер может повторно использовать экземпляры EJB для обслуживания разных запросов.

Я не уверен, зачем вам нужен доступ к объекту фактического бина (поскольку, очевидно, я не знаю вашего требования). Но если вам все еще нужно создать экземпляр этого, вы можете сделать это следующим образом, используя отражение Class.forName(className).newInstance(); Опять же, экземпляр, который вы создаете таким образом, не является EJB. Это просто POJO, вот и все.

РЕДАКТИРОВАТЬ - после вашего комментария относительно тестирования junit: когда вы обращаетесь к бизнес-методам из JavaSE следующим образом, вы фактически вызываете методы в EJB - только то, что вы взаимодействуете через интерфейс. Поэтому, если вы хотите проверить какие-либо бизнес-методы, вы все равно можете сделать это из объекта, прошедшего поиск JNDI в тесте Junit.

//MyGreatBean implements MyGreat. MyGreat has @Remote, MyGreatBean has @Stateless
ref = jndiContext.lookup("MyGreatBean/remote");
MyGreat bean = (MyGreat) ref; 
String retValue = bean.businessMethod();
assertEquals("Success", retValue);

Из предыдущего комментария я чувствую, что вы хотите проверить, какие аннотации были добавлены к фактическому классу EJB - если вы хотите выполнять такую ​​проверку без фактического запуска бизнес-методов, вы можете создать экземпляр используя Class.forName ... как я упоминал выше. Когда вы создаете такой экземпляр, вы можете вызывать только те методы, которые не выполняют никаких «Java EE». Например, вы можете вызвать метод в классе EJB следующим образом

public String someMethod(){
       return "I am a POJO but I look like an EJB";
}
1 голос
/ 06 августа 2009

Я не думаю, что вы можете получить объект EJB. Вы можете получить только интерфейс. CreateEJB должен вызываться с интерфейсом, и он возвращает интерфейс.

0 голосов
/ 14 августа 2009

Можете ли вы попробовать это?

Создать интерфейс. Сделайте это с @Remote. Ваш ejb, аннотированный @Stateless, должен реализовывать созданный выше интерфейс. Теперь попробуйте сделать то же самое, что вы делаете, я думаю, что это должно дать вам желаемый результат. Напечатайте это здесь без копирования от ide, так что извините за любые ошибки. Но я думаю, ты должен получить дрейф.

@Remote
public interface Example{
   String some();
}

@stateless
public class ExampleBean implements Example{

}
0 голосов
/ 06 августа 2009

попробуйте заменить

public <T> T createEJB(Class ejbClass) throws NamingException

с

public <T> T createEJB(Class<T> ejbClass) throws NamingException
...