EJB 3.0 JNDI lookup

di il
8 risposte

EJB 3.0 JNDI lookup

Buongiorno a tutti,

sto lavorando su Eclipse ad un progetto JavaEE. Per il momento ho creato un normale progetto "EJB" e, tramite le funzioni di JPA e una connessione ad un database Mysql chiamato "qax" ho creato le entità a partire dalle tabelle.
Dopo di che ho creato dei Session Bean per gestire la logica di business (prelevare dati dal db ed eseguire operazioni CRUD) creando dei metodi ad hoc che implementano un interfaccia remota.

La struttura del progetto è

MioProgetto
--ejbModule
-----package it.bean
----------> MioBean
----- package it.service
----------> TestI
----------> MiaClasse
-----package it.test
----------> Main


E questo è un esempio di codice:

@Remote
interface TestI {
   void hello();
}

@Stateless
public class MiaClasse implements TestI {
     void hello() {
        System.out.println("Hello world");
     }
}
ed una classe GestLookup che dovrebbe gestire il lookup jndi:
 
 public class GestLookup {
        
       private TestI testI;
	
       public GestLookup () throws RuntimeException {
		try {
			testI= (TestI )new InitialContext().lookup("it.service.MiaClasse");
			
			
		}
		catch(NamingException ex) {
			throw new RuntimeException(ex);
		}
	}
}
Mentre questo è il mio persistence.xml:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
	<persistence-unit name="Qax-EJB" transaction-type="JTA">
	<provider>org.hibernate.ejb.HibernatePersistence</provider>
	<jta-data-source>qax</jta-data-source>
	<exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties>
	        <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/qax"/>
	        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
	        <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
	        <property name="hibernate.connection.password" value=""/>
	        <property name="hibernate.connection.username" value="root"/>
	        <property name="hibernate.hbm2ddl.auto" value="update"/>
	        <property name="hibernate.show_sql" value="true"/>
	        <property name="hibernate.format_sql" value="true"/>
    	</properties>
  </persistence-unit>
</persistence>

Ora vorrei testare questa classe per vedere se funziona in un metodo Main ma i problemi sono che:
1) Avviando progetto dal metodo Main, ho questo errore:
 Exception in thread "main" javax.naming.NoInitialContextException: Cannot instantiate class: 
    com.sun.enterprise.naming.impl.SerialInitContextFactory [Root exception is java.lang.ClassNotFoundException: 
    com.sun.enterprise.naming.impl.SerialInitContextFactory]
Come WebServer uso Tomcat preinstallato in Eclipse, ma il mio progetto EJB non è collegato a nessun Server. Può essere questo il problema?
Grazie a tutti per l'aiuto.

8 Risposte

  • Re: EJB 3.0 JNDI lookup

    Può essere che hai il problema nel casting?

    testI= (TestI )new InitialContext().lookup("it.service.MiaClasse");

    stai castando una interfaccia e forse lui si aspetta una classe?
  • Re: EJB 3.0 JNDI lookup

    Ciao, come dici tu è giusto, ma ora provando a fare
    testI= (TestI )new InitialContext().lookup("it.service.TestI");
    ottengo quest'altro errore:
    
    Exception in thread "main" java.lang.RuntimeException: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
    	at it.capone.service.CGestioneDomande.<init>(CGestioneDomande.java:37)
    	at it.capone.test.MainGestioneDomande.main(MainGestioneDomande.java:10)
    Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
    	at javax.naming.spi.NamingManager.getInitialContext(Unknown Source)
    	at javax.naming.InitialContext.getDefaultInitCtx(Unknown Source)
    	at javax.naming.InitialContext.getURLOrDefaultInitCtx(Unknown Source)
    	at javax.naming.InitialContext.lookup(Unknown Source)
    	at it.capone.service.CGestioneDomande.<init>(CGestioneDomande.java:32)
    	... 1 more
    
    Dopo aver cercato su google, ho modificato il mio persistence.xml in questo modo:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistenc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instanc" xsi:schemaLocation="http://java.sun.com/xml/ns/persistenc http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="QaxEJB" transaction-type="JTA">
    <jta-data-source>java:openejb/Resource/qaxDB</jta-data-source>
    <class>it.bean.MioBean</class>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties/>
    </persistence-unit>
    </persistence>

    Ma mi da sempre l'errore di javax.naming.NoInitialContextException. A questo punto vorrei capire, il progetto di tipo EJB va deployato su un
    Server in locale per farlo funzionare?
  • Re: EJB 3.0 JNDI lookup

    Non ci siamo.

    Hai MiaClasse che implementa l'interfaccia e quindi (non sarebbe corretto dire così) eredità metodi e proprietà, quindi perchè stai cercando di creare un oggetto di tipo interfaccia???

    Hai inizializzato un oggetto e se gli vuoi passare il reference dell'istanza attuale devi passargli un oggetto uguale o derivato da quella classe.

    Per interderci io scriverei qualcosa di simile:
    
    
    private MiaClasse testI;
       
           public GestLookup () throws RuntimeException {
          try {
             testI= new InitialContext().lookup("it.service.MiaClasse");
             .
             .
             .
             
    
    
    Non conosco bene quello che stai facendo ma potresti usare istanceof per verificare se " InitialContext().lookup("it.service.MiaClasse");" è di tipo MiaClasse per davvero, se non lo è blocca tutto che se no esplode . XD

    Fammi sapere.
    Aggiungo "Avvisami via email quando si risponde in questo argomento" così mi accorgo prima
  • Re: EJB 3.0 JNDI lookup

    Grazie per la risposta.
    Il codice che ho scritto fa match con le specifiche degli EJB 3.0.
    Dalla tua risposta forse non hai capito che sto usando tale tecnologia, perchè nel fare il jndi lookup di un EJB 3 si usa istanziare un oggetto di tipo Interface e non la classe.

    Lo stesso codice usando come IDE Netbeans + Glassfish 4.0 funziona, mentre usando Eclipse Neon + Glassfish 3.1 va in errore.

    A tal proposito su ho letto questa risposta interessante(leggi l'ultima risposta):
    https://stackoverflow.com/questions/7767967/connection-problems-with-ejb-jpa-and-eclipse
    soprattutto questa frase della risposta "I think JTA is only supported in a container such as GlassFish and not from Eclipse."

    Da ciò mi fa pensare che sia proprio un problema di Eclipse e Glassfish 3.1.
    Ripeto, lo stesso codice usando come IDE Netbeans + Glassfish 4.0 funziona.

    Magari proverò ad usare Glassfish 4 ed istanziare la classe invece dell' Interface, e vediamo se cambia qualcosa.

    Ti tengo aggiornato.
  • Re: EJB 3.0 JNDI lookup

    Allora un momento. Io ho detto una cavolata.
    Ripensando bene, è possibile fare qualcosa tipo [Interfaccia] interf = oggetto. Anzi direi che è corretto perchè è una delle proprietà del polimorfismo, in quanto l'oggetto estende l'interfaccia, quindi in questo passaggio stai passando il reference dell'oggetto ad una varibile locale Interfaccia astratta.

    Quindi è giusto il primo codice che avevi scritto. Non penso che sia necessario castare, ma controllare che sia dello stesso tipo o cmq un derivato ereditato o esteso come in questo caso.

    Ho visto che stai usando una versione meno recente di Glassfish, non puoi provare con la stessa versione? Gli ide è difficile che possa dare problemi se la versione Java è la stessa. Difficile non impossibile cmq.
  • Re: EJB 3.0 JNDI lookup

    Ciao, ho deployato un altro progetto su GlassFish 4 utilizzando sempre come Ide Eclipse. Il progetto è sempre dello stesso tipo, ovvero un EJBProject che usa gli EJB 3.0. C'è da dire che il progetto, dopo averlo creato, lo converto come "JPA Project", quindi uso la funzionalità per crearmi le entità del database.
    Su Eclise ottengo sempre questo errore quando tenta di fare il lookup JNDI:
    
    Exception in thread "main" java.lang.RuntimeException: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
    	at it.capone.service.CGestioneDomande.<init>(CGestioneDomande.java:44)
    	at it.capone.test.MainGestioneDomande.main(MainGestioneDomande.java:13)
    Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial
    	at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)
    	at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
    	at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:325)
    	at javax.naming.InitialContext.lookup(InitialContext.java:392)
    	at it.capone.service.CGestioneDomande.<init>(CGestioneDomande.java:35)
    	... 1 more
    
    Questo è il persistence.xml. Il dataSource lo chiamo "qaxjndi" e l'ho configurato su GlassFish, si connette verso un database, e facendo il Ping proprio verso quel database esso va a buon fine:
    
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    	<persistence-unit name="QaxEJB-PU" transaction-type="JTA">
    		<jta-data-source>qaxjndi</jta-data-source>
        	        <class>it.capone.entity.Domanda</class>
        	       <exclude-unlisted-classes>false</exclude-unlisted-classes>
        	      <properties/>
    	</persistence-unit>
    </persistence>
    
    Entità Domanda creata automaticamente dall'IDE:
    
    @Entity
    @NamedQuery(name="Domanda.findAll", query="SELECT d FROM Domanda d")
    public class Domanda implements Serializable {
    	private static final long serialVersionUID = 1L;
    
    	@Id
    	@GeneratedValue(strategy=GenerationType.IDENTITY)
    	private int iddomanda;
            
            //Altri campi e metodi get/set dell'entità
            ........   
            ........
    }
    
    Interfaccia Locale:
    
    @Local
    public interface DomandaDAOLocal {
    	
    	List<Domanda> getDomande();
    }
    
    Interfaccia Remota:
    
    @Remote
    public interface DomandaDAORemote {
    	
    	List<Domanda> getDomande();
    }
    
    Classe Stateless:
    
    @Stateless
    public class DomandaDAOImpl implements DomandaDAORemote, DomandaDAOLocal {
    	
    	@PersistenceContext(unitName="QaxEJB-PU")
    	protected EntityManager em;	
    	
    	@Override
    	public List<Domanda> getDomande() {
    		List<Domanda> domande = em.createNamedQuery("Domanda.findAll").setMaxResults(10).getResultList();
    		return domande;
    	}
    }
    
    Classe che uso per il JNDI lookup. Come puoi vedere la stringa che uso per il lookup è quella che il server mi suggerisce in fase di deploy:
    
    Portable JNDI names for EJB DomandaDAOImpl: [java:global/QaxEJB/DomandaDAOImpl!it.capone.businessDAO.DomandaDAORemote, java:global/QaxEJB/DomandaDAOImpl!it.capone.businessDAO.DomandaDAOLocal]
    
    
    public class CGestioneDomande {
    	
    	private DomandaDAORemote domandaService;
    	
    	
    	public CGestioneDomande() throws RuntimeException {
    		try {
    			if(new InitialContext().lookup("java:global/QaxEJB/DomandaDAOImpl!it.capone.businessDAO.DomandaDAORemote") instanceof DomandaDAORemote)
    				domandaService = (DomandaDAORemote) new InitialContext().lookup("java:global/QaxEJB/DomandaDAOImpl!it.capone.businessDAO.DomandaDAORemote");
    			
    			else {
    				System.out.println("Instanceof non ha funzionato");
    			}
    			
    		}
    		catch(NamingException ex) {
    			throw new RuntimeException(ex);
    		}
    	}
    	 
    
    	public List<Domanda> getDomande() {
    		List<Domanda> domande = domandaService.getDomande();
    		return domande;
    	}
    
    E questo è il Main in cui testo l'applicazione:
    
    public class MainGestioneDomande {
    
    	public static void main(String[] args) {
    		CGestioneDomande cgd = new CGestioneDomande();
    		
    		List<Domanda> lista = cgd.getDomande();
    		for(Domanda d : lista) {
    			System.out.println("Titolo domanda: " +d.getTitolo());
    		}
    	}
    
    Debuggando ho che nel momento in cui l'applicazione arriva a leggere la stringa di lookup, si ha l'errore e schiatta tutto, quindi il problema deve essere li in qualche modo, anche se la stringa di jndi lookup è quella che il server mi dice di usare, e lo stesso progetto su Netbeans funziona bene.
  • Re: EJB 3.0 JNDI lookup

    Il package è giusto? il porting ti ha modificato il nome di qualche classe? è tutto corretto sulle directory di progetto?

    è giusto questo? <class>it.capone.entity.Domanda</class>

    Credo di essere arrivato al confine con le mie conoscenze. Sembra uno di quei problemi stupidi, tipo magari una impostazione. Il tipo di errore è abbastanza chiaro, RunTimeException, è sicuramente un errore che non è di codice, o per lo meno non visibile all'IDE, ma che compare all'avvio dell'applicazione. Potrebbe anche essere una cazzata nel porting... ma vattela a pesca.

    Ti sono vicino
  • Re: EJB 3.0 JNDI lookup

    Beh innanzitutto ti ringrazio per le risposte, almeno tu sei l'unico che ha cercato di darmi una mano

    Il package <class>it.capone.entity.Domanda</class> è effettivamente questo, e come dici te non è un errore di codice poichè stesso progetto ma IDE diverso (Glassgish) va OK.

    Per il porting non saprei, come potrei verificare ?
    Non vorrei che il problema è proprio creare un "EJBProject", mi spiego meglio: in NetBeans ho creato un "EnterpriseProject", e li mi chiedeva se creare anche un EjbProject ed un War-Project associati. Ovviamente io spuntavo le caselle per dire si, ed a questo punto ecco i 3 progetti creati: Un War-Project, un Enterprise-Project ed un EjbProject, tutti e tre con lo stesso nome. Poi scrivevo tutto il codice e lavoravo con l' EjbProject, senza mai più toccare gli altri due. Provando a fare lo stesso con Eclipse e avviando per vedere se funziona, ho altre eccezioni che al momento non ricordo, mentre creando direttamente un EjbProject ho l'errore che conosci già.
Devi accedere o registrarti per scrivere nel forum
8 risposte