2009-08-06 5 views
2

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

Код ниже выполняет именно это. Однако возвращаемый им объект относится к типу удаленного интерфейса для компонента, а не самого компонента. Как я могу это изменить? Есть ли способ сказать 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, я не тестировал его ни с каким другим сервером приложений.

+0

Каким будет использование объекта самого реального компонента? - вы всегда будете взаимодействовать через интерфейс правильно? в основном как InterfaceType ref = (InterfaceType) jndiLookup; После этого вы вызываете методы на ref. Попытка понять необходимость этого. – OpenSource

ответ

3

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

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

EDIT - после вашего комментария относительно тестирования юнита: при доступе к бизнес-методам из 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"; 
} 
+0

> Я не уверен, почему вам нужно получить доступ к объекту реального боба (так как> очевидно, я не знаю вашего требования). Например, чтобы проверить его. Как только вы получите объект EJB в приложение JavaSE, вы можете использовать junit. – Nils

+0

Хорошо. Добавлено больше информации. – OpenSource

0

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

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

с

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

я уже пробовал, но есть исключение произнесения: TestCase: testSayHello (SimpleEJBTest): вызвала ошибку _TestRemote_Wrapper не может быть приведен к TestBean java.lang.ClassCastException: _TestRemote_Wrapper не может быть приведен к TestBean на SimpleEJBTest.setUp (SimpleEJBTest.java : 16) – Nils

+0

может быть декларация по тесту testBean ошибочна. Должен ли он быть типом TestBean, а не TestRemote? – fgui

+0

да, конечно, я тоже изменил это. Затем я получил исключение. Sry забыл упомянуть выше. – Nils

1

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

+0

ok, но если аннотация находится в фактическом классе боба, а не в interace, как вы его получите? – Nils

+0

Я использовал следующую аннотацию в классе bean: @Stateless (name = "TestBean", mappedName = "ejb/TestBean") – Nils

0

Вы можете попробовать это?

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

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

@stateless 
public class ExampleBean implements Example{ 

} 
+0

Неужели я прочитал мой вопрос ?? Я уже сделал это .. – Nils

+0

Ahh .. по какой-то причине я думал, что когда вы ищете пульт, он не был там. Подумайте об этом больше. – OpenSource

+0

ОК, создавая новый ответ. Посмотрим, работает ли он. – OpenSource