2009-08-06 7 views
2

J'essaie de créer une classe d'usine EJB, qui fonctionne comme ceci: Vous avez une méthode qui prend comme argument une classe d'EJB, puis elle vérifie si l'EJB a une interface distante (sinon lancer une exception) et si c'est le cas, il renvoie l'EJB concerné.EJB Factory Class

Le code ci-dessous fait exactement cela. Cependant l'objet qu'il renvoie est du type de l'interface distante du bean concerné et non du haricot lui-même. Comment puis-je changer cela? Est-il possible de dire à Java que le type générique T est du même type que la classe transmise aux méthodes.

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

}

Exemple d'un test unitaire qui utilise l'usine.

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

Remarque: L'exemple fonctionne avec Glassfish, je ne l'ai pas testé avec un autre serveur d'applications.

+0

Quelle sera l'utilité d'avoir l'objet du haricot lui-même? - vous serez toujours en interaction à travers l'interface droite? fondamentalement comme InterfaceType ref = (InterfaceType) jndiLookup; Ensuite, vous appelez les méthodes sur la réf. Essayer de comprendre le besoin de ceci. – OpenSource

Répondre

3

Les clients des EJB interagissent avec eux via l'interface locale/distante implémentée par les EJB. Les applications clientes n'ont jamais accès directement à une instance de classe de bean session réelle. Ceci est fait pour rendre possible la mise en pool d'instances, où le conteneur peut réutiliser des instances EJB pour traiter différentes requêtes. Je ne sais pas pourquoi vous devez accéder à l'objet du bean réel (puisque évidemment je ne sais pas votre condition). Mais si vous avez encore besoin de créer une instance de ce que vous pouvez faire comme suit en utilisant la réflexion Class.forName(className).newInstance(); Encore une fois l'instance que vous créez comme ceci n'est pas un EJB. C'est juste un POJO c'est tout. Après votre commentaire concernant junit testing: Lorsque vous accédez aux méthodes métier à partir d'un JavaSE comme suit, vous appelez les méthodes dans l'EJB - juste que vous interagissez via l'interface. Donc, si vous voulez tester des méthodes d'affaires, vous pouvez toujours le faire à partir d'un objet obtenu grâce à une recherche JNDI dans un test 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); 

D'un commentaire précédent, je reçois un sentiment que vous voulez vérifier quel type d'annotations ont été ajoutées à la classe EJB réelle - si vous voulez faire ce genre de contrôle sans exécuter réellement les méthodes d'affaires, vous peut créer une instance en utilisant Class.forName ... comme je l'ai mentionné ci-dessus. Lorsque vous créez une instance comme celle-ci, vous ne pouvez appeler que des méthodes qui ne font pas de "Java EE".Par exemple, vous pouvez appeler une méthode dans la classe EJB qui est la suivante

public String someMethod(){ 
     return "I am a POJO but I look like an EJB"; 
} 
+0

> Je ne sais pas pourquoi vous devez accéder à l'objet du bean réel (puisque> évidemment je ne connais pas votre exigence). Par exemple pour le tester. Une fois que vous obtenez l'objet EJB dans une application JavaSE, vous pouvez utiliser junit. – Nils

+0

Ok. Ajouté plus d'info. – OpenSource

0

essayez de remplacer

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

avec

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

je l'ai déjà essayé, mais nous avons eu une exception casting: Testcase: testSayHello (SimpleEJBTest): provoqué une _TestRemote_Wrapper ERREUR ne peut pas être jeté à TestBean java.lang.ClassCastException: _TestRemote_Wrapper ne peut pas être jeté à TestBean à SimpleEJBTest.setUp (SimpleEJBTest.java : 16) – Nils

+0

peut être la déclaration sur le test de testBean est faux. Faut-il taper TestBean et non TestRemote? – fgui

+0

oui bien sûr, j'ai aussi changé cela. Ensuite, j'ai une exception de cast. Sry a oublié de mentionner ci-dessus. – Nils

1

Je ne pense pas que vous pouvez obtenir l'objet EJB. Vous ne pouvez obtenir l'interface. Le createEJB devrait être appelé avec l'interface et il retourne l'interface.

+0

ok, mais si l'annotation est dans la classe réelle du haricot et non dans l'interace, comment l'obtenez-vous alors? – Nils

+0

J'ai utilisé l'annotation suivante sur la classe bean: @Stateless (name = "TestBean", mappedName = "ejb/TestBean") – Nils

0

Pouvez-vous essayer ça?

Créer une interface. Faites-le avoir @Remote. Votre ejb annoté avec @Stateless doit implémenter l'interface créée ci-dessus. Maintenant, essayez de faire la même chose que vous faites, je pense que cela devrait vous donner le résultat souhaité. Taper ici sans copier d'un ide excuse donc les erreurs. Mais vous devriez avoir la dérive je suppose.

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

@stateless 
public class ExampleBean implements Example{ 

} 
+0

Avez-vous lu ma question ?? Je l'ai déjà fait .. – Nils

+0

Ahh .. pour une raison que je pensais quand vous cherchez la télécommande, il n'était pas là. Réfléchira plus à propos de celui-ci. – OpenSource

+0

ok créer une nouvelle réponse. Voyons voir si cela fonctionne. – OpenSource