Beispielprogramm

KrisKul

Grünschnabel
Hallo ich möchte ein Programm auf JavaEE Ebene programmieren. Hab mich mich mit einigen Bücher auseinandergesetzt und komme einfach nicht weiter.

1. Hab ich ein Objekt mit den Annotationen erstellt.
Code:
package de.datenbanktest.bean;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="person")
public class Person {

	private int id;
	private String vorname, nachname;
	
	protected Person(){
		
	}
	
	public Person(String nachname){
		this.nachname = nachname;
	}
	
	public Person(String nachname, String vorname){
		this.nachname = nachname;
		this.vorname = vorname;
	}

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="id")
	public int getId() {
		return id;
	}

	protected void setId(int id) {
		this.id = id;
	}

	@Column(name="vorname", length=50)
	public String getVorname() {
		return vorname;
	}

	public void setVorname(String vorname) {
		this.vorname = vorname;
	}

	@Column(name="nachname", nullable=false, length=50)
	public String getNachname() {
		return nachname;
	}

	public void setNachname(String nachname) {
		this.nachname = nachname;
	}
	
	
}

2. Es wurde ein (Remote) Interface und die dazugehörige Bean erstellt.

Code:
package de.datenbanktest.bean;

import javax.ejb.Remote;

@Remote
public interface PersonDBManager {

	public abstract Person create(String nachname, String vorname);
	public abstract Person getByName(String name);
}

Code:
package de.datenbanktest.bean;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

public class PersonDBManagerBean implements PersonDBManager {

	@PersistenceContext(name="person")
	EntityManager em;
	
	@Override
	public Person create(String nachname, String vorname) {
		Person p = new Person();
		p.setNachname(nachname);
		p.setVorname(vorname);
		System.out.println(p.getNachname());
		System.out.println(p.getVorname());
		em.persist(p);
		return p;
	}

	@Override
	public Person getByName(String name) {
		Person p = null;
		Query q = em.createNamedQuery("Select t from Peron t where nachname=:n");
		q.setParameter("n", name);
		p = (Person) q.getResultList().get(0);
		return p;
	}

}

3. Eine Klasse zum Testen erstellt.

Code:
package de.datenbanktest.bean;

import javax.naming.Binding;
import javax.naming.InitialContext;
import javax.naming.NamingEnumeration;

public class Ausführung {

	public static void main(String[] args) throws Exception{
		
		String jndiName = PersonDBManager.class.getName();
		InitialContext ctx = new InitialContext();
		System.out.println(jndiName);
		NamingEnumeration<Binding> list = ctx.listBindings("");
		while(list.hasMore()){
			Binding binding = list.next();
			System.out.println(binding.getName() + " : " + binding.getObject());
		}
		PersonDBManager remote = (PersonDBManager) ctx.lookup(jndiName);
		remote.create("Name", "Vorname");
	}

}

4. Eine JDBC Resource im Application Server erstellt (Glasfish). Als Pool wird der DerbyPool verwendet. jdbc/PersonDB

5. Es wurde eine persistence.xml im META-INF erstellt.
Code:
<?xml version="1.0" encoding="UTF-8"?>

<persistence 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_1_0.xsd" version="1.0">

	<persistence-unit name="person" transaction-type="JTA">
	
		<jta-data-source>jdbc/PersonDB</jta-data-source>
		
		<properties>
			<!--
			see http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-extensions.html#Java2DBSchemaGen
			-->
			<property name="toplink.ddl-generation" value="drop-and-create-tables"/>
			<!-- <property name="toplink.ddl-generation.output-mode" value="both"/> --> <!-- sql-script -->
		</properties>

	</persistence-unit>

</persistence>

6. Es werden alle Klassen compiliert und mit der persistence.xml in eine jar gepackt. Diese wird dann in eine ear gepackt und in den autodeploy-folder kopiert.

Im Server.log ist keine Fehlermeldung.

[#|2008-06-21T19:17:51.342+0200|INFO|sun-appserver9.1|javax.enterprise.system.tools.deployment|_ThreadID=17;_ThreadName=Timer-9;|[AutoDeploy] Selecting file C:\Sun\SDK\domains\domain1\autodeploy\person.ear for autodeployment.|#]

[#|2008-06-21T19:17:51.343+0200|INFO|sun-appserver9.1|javax.enterprise.system.tools.deployment|_ThreadID=17;_ThreadName=Timer-9;|Autoundeploying application :person|#]

[#|2008-06-21T19:17:51.428+0200|INFO|sun-appserver9.1|javax.enterprise.system.tools.deployment|_ThreadID=17;_ThreadName=Timer-9;|[AutoDeploy] Successfully autoundeployed : C:\Sun\SDK\domains\domain1\autodeploy\person.ear.|#]

[#|2008-06-21T19:17:51.525+0200|INFO|sun-appserver9.1|javax.enterprise.system.tools.deployment|_ThreadID=17;_ThreadName=Timer-9;|deployed with moduleid = person|#]

[#|2008-06-21T19:17:51.568+0200|INFO|sun-appserver9.1|javax.enterprise.system.tools.deployment|_ThreadID=17;_ThreadName=Timer-9;|[AutoDeploy] Successfully autodeployed : C:\Sun\SDK\domains\domain1\autodeploy\person.ear.|#]

Beim Ausführen der main-Methoden kommt eine NamingException.

de.datenbanktest.bean.PersonDBManager
__SYSTEM : com.sun.enterprise.naming.TransientContext@2f1e75
jdbc : com.sun.enterprise.naming.TransientContext@4eeaaf
UserTransaction : com.sun.enterprise.distributedtx.UserTransactionImpl@19a37a
ejb : com.sun.enterprise.naming.TransientContext@135daf
--Bis hierhin ist die normale Ausgabe.---

Exception in thread "main" javax.naming.NameNotFoundException: de.datenbanktest.bean.PersonDBManager not found
at com.sun.enterprise.naming.TransientContext.doLookup(TransientContext.java:216)
at com.sun.enterprise.naming.TransientContext.lookup(TransientContext.java:188)
at com.sun.enterprise.naming.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:74)
at com.sun.enterprise.naming.RemoteSerialContextProviderImpl.lookup(RemoteSerialContextProviderImpl.java:129)
at sun.reflect.GeneratedMethodAccessor829.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:154)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:687)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:227)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1846)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1706)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:1088)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:223)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:806)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:563)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2567)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)

Ich weiss einfach nicht warum. Bin echt am verzweifeln. Kann da einer helfen?
 
Also zum einen musst du deinen InitialContext noch ein paar properties mitgeben, sonst weiß der ja nicht, dass er auf deinem Server suchen soll. as genau da rein muss, ist AS spezifisch. D.h. Glassfish Doku wälzen.

Zum anderen musst du AFAIK remote beans per BeanName+"/remote" referenzieren. Kannst du nicht über die Adminkonsole des Glasfish nachschauen, unter welchen Namen die EJB registriert ist?

Bei der Entity kannst du dir einige überflüssige Annotationen sparen (@Column(name="id") brauchst du nicht, wenn die property id heißt), zum anderen lesen die sich IMHO leichter wenn sie an den properties stehen. Das Query Interface bietet ein getSingleResult() - dann sparst du dir den blöden cast.

Ansonsten sieht das recht ordentlich aus ;).

Gruß
Ollie
 
Danke schon mal für die Antwort.

Zum anderen musst du AFAIK remote beans per BeanName+"/remote" referenzieren. Kannst du nicht über die Adminkonsole des Glasfish nachschauen, unter welchen Namen die EJB registriert ist?

Was heißt AFAIK? Eigentlich kapier ich die denn Satz nicht wirklich.;-)

In der Konsole unter Applications ist die bean mit person bezeichnet. Wie die .ear datei halt heißt. Wenn du das meinst.

Was bedeutet IMHO?

Wie setze ich die Propertys? Ich hab nämlich keine Ahnung wo ich da anfangen soll zu suchen.
 
Was heißt AFAIK? Eigentlich kapier ich die denn Satz nicht wirklich.;-)
Sorry, zu viel Internetzismen ;) As Far As I Know - soweit ich weiß. Du referenzierst die Bean (den PersonDBManager) per "PersonDBManager" im JNDI. Soweit ich weiß geht das aber nur bei Referenzen auf das Localinterface. Für das Remoteinterface müsste es in diesem Fall "PersonDBManager/remote" heißen.

In der Konsole unter Applications ist die bean mit person bezeichnet. Wie die .ear datei halt heißt. Wenn du das meinst.
Das verwirrt mich ein wenig. Relevant ist ja in deinem Fall nicht die Entity sondern die SessionBean. Dabei fällt mir grad noch auf, dass deine PersonDBManagerBean natürlich noch die Annotation @Stateless benötigt. Wahrscheinlich wird sie deswegen nicht im JNDI registriert.

Was bedeutet IMHO?
In My Humble Opinion - meiner bescheidenen Meinung nach

Wie setze ich die Propertys? Ich hab nämlich keine Ahnung wo ich da anfangen soll zu suchen.
Du kannst den InitialContext mit einer HashMap als Parameter instantiieren. Damit legst du fest, welche Contextimplmentierung benutzt werden soll, zu welchem Server die Verbindung aufgebaut werden soll usw.

Beispiel gibts hier http://www.laliluna.de/ejb-3-tutorial-jboss.html, allerdings für den JBoss. Aber da sollte sich was für den Glassfish bei Google finden lassen.

Allerdings ist das fehlende @Stateless meiner Meinung nach der Hauptgrund für den Fehler.

Gruß
Ollie
 
Soweit ich weiß geht das aber nur bei Referenzen auf das Localinterface. Für das Remoteinterface müsste es in diesem Fall "PersonDBManager/remote" heißen.
:confused:
Verstehe ich leider nicht ganz. Die Bean ist ja PersonDBManagerBean. Aber das /remote verstehe ich nicht.

Code:
@Stateless
public class PersonDBManagerBean implements PersonDBManager {

wurde korregiert aber der selbe fehler besteht weiterhin.
 
Woher soll der der JNDI wissen welches Interface du zurück haben willst? Das lokale oder das Remoteinterface? Schau dir doch bitte mal das verlinkte Tutorial und darin den Abschnitt Stateless Session Bean an. Dort siehst du wie im JNDI nach dem Deployment 2(!) Instanzen der Bean liegen eine heißt "${BeanName}/local", die andere "${BeanName}/remote". Wenn du jetzt nur "${BeanName}" im JNDI suchst wird vermutlich standardmäßig die Instanz mit dem Localinterface zurückgegeben.

Soweit ich weiß, MUSST du ein Localinterface definieren. Hast du das hier nur der Einfachnheit halber weggelassen oder ist das wirklich nicht da? Dann solltest du das noch hinzufügen.

Versuch doch mal das Tutorial und schau ob das tut. Wenns passt kannst ja nochmal mit deinem Projekt vergleichen.

Gruß
Ollie
 
Ich hab jetzt eine jndi.properties im src Verzeichnis erstellt.

Code:
java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
java.naming.provider.url=localhost:1099

aber was müßte jetzte für den glasfish darin stehen?

Habe es mit

Code:
java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
java.naming.provider.url=iiop://localhost:1050
java.naming.factory.url.pkgs=com.sun.enterprise.naming:com.sun.enterprise.naming

ausprobiert aber funktioniert auch nicht.

Die Fehlermeldung ist jedoch anders.
ejb : com.sun.enterprise.naming.TransientContext@174aa60
javax.naming.NameNotFoundException
at com.sun.enterprise.naming.TransientContext.resolveContext(TransientContext.java:268)
at com.sun.enterprise.naming.TransientContext.lookup(TransientContext.java:191)
at com.sun.enterprise.naming.SerialContextProviderImpl.lookup(SerialContextProviderImpl.java:74)
at com.sun.enterprise.naming.RemoteSerialContextProviderImpl.lookup(RemoteSerialContextProviderImpl.java:129)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.sun.corba.ee.impl.presentation.rmi.ReflectiveTie._invoke(ReflectiveTie.java:154)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatchToServant(CorbaServerRequestDispatcherImpl.java:687)
at com.sun.corba.ee.impl.protocol.CorbaServerRequestDispatcherImpl.dispatch(CorbaServerRequestDispatcherImpl.java:227)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequestRequest(CorbaMessageMediatorImpl.java:1846)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:1706)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleInput(CorbaMessageMediatorImpl.java:1088)
at com.sun.corba.ee.impl.protocol.giopmsgheaders.RequestMessage_1_2.callback(RequestMessage_1_2.java:223)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.handleRequest(CorbaMessageMediatorImpl.java:806)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.dispatch(CorbaMessageMediatorImpl.java:563)
at com.sun.corba.ee.impl.protocol.CorbaMessageMediatorImpl.doWork(CorbaMessageMediatorImpl.java:2567)
at com.sun.corba.ee.impl.orbutil.threadpool.ThreadPoolImpl$WorkerThread.run(ThreadPoolImpl.java:555)


Habe in PersonDBManagerBean noch

Code:
public static final String RemoteJNDIName =  PersonDBManager.class.getSimpleName() + "/remote";

hinzugefügt und in Ausführung

Code:
PersonDBManager remote = (PersonDBManager) ctx.lookup(PersonDBManagerBean.RemoteJNDIName);

verändert.
 
Hallo,

um eine RemoteBean im Glassfish zu finden musst du vor den JNDI-Namen der Bean noch "java:comp/env/ejb/" setzen.

In Deinem Beispielclient also:

Code:
PersonDBManager remote = (PersonDBManager) ctx.lookup("java:comp/env/ejb/" + jndiName);

Als InitialContextFactory würde ich mal com.sun.jndi.cosnaming.CNCtxFactory versuchen.

Ich hoffe das hilft etwas.
Viele Grüße
scratX
 
Hallo nochmal,

vergiss das mit dem "java:comp/env/ejb/". Dein Client hat keinen Zugriff auf die Komponentenumgebung.

Vielleicht hilft folgendes:
In deiner Bean musst du einen globalen JNDI-Namen angeben. Bei Glassfish wird das über den mappedName gemacht.

Code:
@Stateless(mappedName="HelloBean")
public class DemoBeanBean implements DemoBeanRemote {

   public void hello() {
      System.out.println("Hello World");
   }
}

Als Context-Factory funktioniert auch die SerialInitContextFactory. In dem Classpath des Clients muss die javaee.jar und das appserv-rt.jar enthalten sein (im lib/-Verzeichnis des Glassfish). Der Standard-IIOP-Port ist im Glassfish 3700.

Hier mal ein Beispielclient:

Code:
   public static void main(String[] args) {
      try {
         Hashtable<String, String> env = new Hashtable<String, String>();

         env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.enterprise.naming.SerialInitContextFactory");
         env.put(Context.URL_PKG_PREFIXES, "com.sun.enterprise.naming");
         env.put(Context.STATE_FACTORIES, "com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");
         env.put(Context.PROVIDER_URL, "iiop://localhost:3700");

         InitialContext ic = new InitialContext(env);
         System.out.println(DemoBeanRemote.class.getName());
         DemoBeanRemote remoteObject = (DemoBeanRemote) ic.lookup("HelloBean");

         remoteObject.hello();
      } catch (NamingException e) {
         e.printStackTrace();
      }
   }

Viele Grüße
 

Neue Beiträge

Zurück