Frage zu J2EE

Bumbum564

Mitglied
Hallo zusammen.

Ich habe seit ca. 2 Wochen die Aufgabe mich in J2EE einzuarbeiten.
Habe auch einiges an Büchern da.
Jedoch komme ich irgendwie nicht weiter...
Habe teilweise schon einige Beispiele durchgearbeitet.
Jedoch passen die ganzen Beispiele nicht so auf mein vorhaben.

Ich "denke" ich weiß mitlerweile was was Session- und EntityBeans sind.
Jedoch weiß ich momentan weder wie sie genau mit einander arbeiten, bzw. wie sie genau verknüpft werden usw.

Die Beispiele klappen soweit immer aber ist ja auch nur stupiedes abtippen.
Und der Lernfaktor ist = NULL.
Ich will zum Anfang eigentlich nur, dass ich mir von einem Client aus über ein SessionBean über ein EntityBean Daten in eine Datenbank schreibe.
Und das gleiche natürlich auch anders rum (also Daten auslesen) zb mit SQLs.
Bekomme es aber leider zum verrecken nicht hin.
Ich weiß nicht, ob ich nen Denkfehler habe oder woran es liegt.

Habe hier mal die Bücher aufgelistet die ich da habe.
Welche würdet ihr mir empfeheln, wenn ich mit dem Thema anfangen will.
Vllt aus der Erfahrung heraus.

- J2EE mit Eclipse 3 und JBoss (von Hanser ISBN: 3-446-22739-3)
- Enterprise JavaBeans 3. Auflage (O'Reilly ISBN: 3-89721-297-8)
- Java Enterprise in a Nutshell 2. Auflage (O'Reilly ISBN: 3-89721-334-6)
- Enterprise JavaBeans 2.0 (Addison-Wesley ISBN: 3-8273-1765-7)
- Das J2EE Codebook (Addison-Wesley ISBN: 3-8273-2176-X)

Wenn jmd noch ne andere Idee hat wie man sich in das Thema einarbeiten kann.
Bzw. noch irgendwelche Anregungen hat. Bitte melden.

Vielen Dank schonmal im vorraus.
 
Hi,
warum zeigst du nicht direkt den Code, den du bisher erstellt hast.
Daran können wir sehen warum es nicht funktioniert und können dir dabei helfen!

Ich dadurch wird der Lerneffekt gesteigert, da du ja siehst was falsch ist und entsprechend später darauf achten kannst!

Gruß
BlackMagician
 
Sorry war nen paar Tage krank und kommte daher nicht direkt antworten.

Also hier mal das was ich so bisher gemacht habe:

Mein Session-Bean:
Code:
/*
 * Created on 23.08.2007
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package myhelloworld;

import java.rmi.RemoteException;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;

import javax.ejb.*;
import javax.naming.*;

/**
 *
 * <!-- begin-user-doc --> A generated session bean <!-- end-user-doc --> *
 <!-- lomboz.beginDefinition -->
 <?xml version="1.0" encoding="UTF-8"?>
 <lomboz:EJB xmlns:j2ee="http://java.sun.com/xml/ns/j2ee" xmlns:lomboz="http://lomboz.objectlearn.com/xml/lomboz">
 <lomboz:session>
 <lomboz:sessionEjb>
 <j2ee:display-name>HelloWorld</j2ee:display-name>
 <j2ee:ejb-name>HelloWorld</j2ee:ejb-name>
 <j2ee:ejb-class>myhelloworld.HelloWorldBean</j2ee:ejb-class>
 <j2ee:session-type>Stateful</j2ee:session-type>
 <j2ee:transaction-type>Container</j2ee:transaction-type>
 </lomboz:sessionEjb>
 </lomboz:session>
 </lomboz:EJB>
 <!-- lomboz.endDefinition -->
 *
 * <!-- begin-xdoclet-definition --> 
 * @ejb.bean name="HelloWorld"	
 *           jndi-name="HelloWorld"
 *           type="Stateful" 
 *           transaction-type="Container"
 * 
 *--
 * This is needed for JOnAS.
 * If you are not using JOnAS you can safely remove the tags below.
 * @jonas.bean ejb-name="HelloWorld" 
 *             jndi-name="HelloWorld"
 * 
 *--
 * <!-- end-xdoclet-definition --> 
 * @generated
 */
public abstract class HelloWorldBean implements SessionBean {
	
	private int id = 0;
	private String name = "";
		
	/**
	 * @ejb.interface-method
	 *	view-type="remote" 
	**/
	public int getId()
	{ 
	 return id; 
	}
	/**
	 * @ejb.interface-method
	 *	view-type="remote" 
	**/
	public String getName()
	{ 
	 return name; 
	}
	/**
	 * @ejb.interface-method
	 *	view-type="remote" 
	**/
	public void setId(int id)
	{ 
		this.id = id;
	}
	/**
	 * @ejb.interface-method
	 *	view-type="remote" 
	**/
	public void setName(String name)
	{ 
		this.name = name;
	}
	
	private HelloWorldHome getHome() throws NamingException {
		return (HelloWorldHome) getContext().lookup(HelloWorldHome.JNDI_NAME);
	}

	private InitialContext getContext() throws NamingException {
		Hashtable props = new Hashtable();

		props.put(InitialContext.INITIAL_CONTEXT_FACTORY,
				"org.jnp.interfaces.NamingContextFactory");
		props.put(InitialContext.PROVIDER_URL, "jnp://127.0.0.1:1099");

		// This establishes the security for authorization/authentication
		// props.put(InitialContext.SECURITY_PRINCIPAL,"username");
		// props.put(InitialContext.SECURITY_CREDENTIALS,"password");

		InitialContext initialContext = new InitialContext(props);
		return initialContext;
	}
		
	public void ejbCreate() throws CreateException
	{
		
	}
}

Mein Entity-Bean:
Code:
/*
 * Created on 23.08.2007
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package myhelloworld;

import javax.ejb.EntityBean;

/**
 *
 * <!-- begin-user-doc --> You can insert your documentation for '<em><b>PersonenBean</b></em>'. <!-- end-user-doc --> *
 <!--  begin-lomboz-definition -->
 <?xml version="1.0" encoding="UTF-8"?>
 <lomboz:EJB xmlns:j2ee="http://java.sun.com/xml/ns/j2ee" xmlns:lomboz="http://lomboz.objectlearn.com/xml/lomboz">
 <lomboz:entity>
 <lomboz:entityEjb>
 <j2ee:display-name>Personen</j2ee:display-name>
 <j2ee:ejb-name>Personen</j2ee:ejb-name>
 <j2ee:ejb-class>myhelloworld.PersonenBean</j2ee:ejb-class>
 <j2ee:persistence-type>Container</j2ee:persistence-type>
 <j2ee:prim-key-class>java.lang.Integer</j2ee:prim-key-class>
 <j2ee:cmp-version>2.x</j2ee:cmp-version>
 <j2ee:abstract-schema-name>TabPerson</j2ee:abstract-schema-name>
 <j2ee:primkey-field>id</j2ee:primkey-field>
 </lomboz:entityEjb>
 <lomboz:fieldMappings>
 <lomboz:fieldName>id</lomboz:fieldName>
 <lomboz:fieldType>java.lang.Integer</lomboz:fieldType>
 <lomboz:columnName>id</lomboz:columnName>
 <lomboz:jdbcType>VARCHAR</lomboz:jdbcType>
 <lomboz:sqlType>INTEGER</lomboz:sqlType>
 <lomboz:readOnly>false</lomboz:readOnly>
 <lomboz:primaryKey>true</lomboz:primaryKey>
 </lomboz:fieldMappings>
 <lomboz:fieldMappings>
 <lomboz:fieldName>name</lomboz:fieldName>
 <lomboz:fieldType>java.lang.String</lomboz:fieldType>
 <lomboz:columnName>name</lomboz:columnName>
 <lomboz:jdbcType>VARCHAR</lomboz:jdbcType>
 <lomboz:sqlType>VARCHAR</lomboz:sqlType>
 <lomboz:readOnly>false</lomboz:readOnly>
 <lomboz:primaryKey>false</lomboz:primaryKey>
 </lomboz:fieldMappings>
 <lomboz:tableName>TabPerson</lomboz:tableName>
 <lomboz:dataSourceName></lomboz:dataSourceName>
 </lomboz:entity>
 </lomboz:EJB>
 <!--  end-lomboz-definition -->
 *
 * <!-- begin-xdoclet-definition -->
 * @ejb.bean name="Personen"
 *	jndi-name="Personen"
 *	type="CMP"
 *  primkey-field="id" 
 *  schema="TabPerson" 
 *  cmp-version="2.x"
 *  data-source=""
 *--
 * This is needed for JOnAS.
 * If you are not using JOnAS you can safely remove the tags below.
 * @jonas.bean ejb-name="Personen"
 *   jndi-name="Personen"
 * @jonas.jdbc-mapping  jndi-name="" jdbc-table-name="TabPerson" 
 * --
 * 
 *  @ejb.persistence 
 *   table-name="TabPerson" 
 * 
 * @ejb.finder 
 *    query="SELECT OBJECT(a) FROM TabPerson as a"  
 *    signature="java.util.Collection findAll()"  
 * 
 *  * @ejb.finder 
 *    query="SELECT OBJECT(a) FROM TabPerson as a WHERE a.name = ?1"  
 *    signature="java.util.Collection findPersonByName(java.lang.String name)"  
 *
 * @ejb.pk class="java.lang.Integer"
 *--
 * This is needed for JOnAS.
 * If you are not using JOnAS you can safely remove the tags below.
 * @jonas.finder-method-jdbc-mapping  method-name="findAll"
 *	jdbc-where-clause=""
 * @jonas.jdbc-mapping  jndi-name=""
 *	jdbc-table-name="TabPerson"
 * 
 *--
 * <!-- end-xdoclet-definition -->
 * @generated
 **/
public abstract class PersonenBean implements javax.ejb.EntityBean {

  /**
   *
   * <!-- begin-user-doc -->
   * The  ejbCreate method.
   * <!-- end-user-doc -->
   *
   * <!-- begin-xdoclet-definition --> 
   * @ejb.create-method 
   * <!-- end-xdoclet-definition --> 
   * @generated
   */
  public java.lang.Integer ejbCreate(Integer id, String name) throws javax.ejb.CreateException {
    // EJB 2.0 spec says return null for CMP ejbCreate methods.
    // TODO: YOU MUST INITIALIZE THE FIELDS FOR THE BEAN HERE. 
    // setMyField("Something"); 
    // begin-user-code
  	setId(id);
  	setName(name);
    return null;
    // end-user-code
  }

  /**
   * <!-- begin-user-doc -->
   * The container invokes this method immediately after it calls ejbCreate.
   * <!-- end-user-doc -->
   * 
   * @generated
   */
  public void ejbPostCreate(Integer id, String name) throws javax.ejb.CreateException {
    // begin-user-code
    // end-user-code
  }

  /**
   *
   *
   * <!-- begin-user-doc -->
   * CMP Field id
   *
   * Returns the id
   * @return the id
   * 
   * <!-- end-user-doc -->
   *
   * <!-- begin-xdoclet-definition --> 
   *
   * @ejb.persistent-field 
   * @ejb.persistence
   *    column-name="id"
   *     jdbc-type="VARCHAR"
   *     sql-type="INTEGER"
   *     read-only="false"
   * @ejb.pk-field 
   *
   * @ejb.interface-method
   * 
   * --
   * This is needed for JOnAS.
   * If you are not using JOnAS you can safely remove the tags below.
   * @jonas.cmp-field-jdbc-mapping  field-name="id"
   *	jdbc-field-name="id"
   * 
   * --
   * <!-- end-xdoclet-definition --> 
   * @generated
   */
  public abstract java.lang.Integer getId();

  /**
   * <!-- begin-user-doc -->
   * Sets the id
   * 
   * @param java.lang.Integer the new id value
   * <!-- end-user-doc -->
   * 
   * <!-- begin-xdoclet-definition --> 
   * @ejb.interface-method
   * <!-- end-xdoclet-definition -->
   * @generated 
   */
  public abstract void setId(java.lang.Integer id);

  /**
   *
   *
   * <!-- begin-user-doc -->
   * CMP Field name
   *
   * Returns the name
   * @return the name
   * 
   * <!-- end-user-doc -->
   *
   * <!-- begin-xdoclet-definition --> 
   *
   * @ejb.persistent-field 
   * @ejb.persistence
   *    column-name="name"
   *     jdbc-type="VARCHAR"
   *     sql-type="VARCHAR"
   *     read-only="false"
   *  
   *
   * @ejb.interface-method
   * 
   * --
   * This is needed for JOnAS.
   * If you are not using JOnAS you can safely remove the tags below.
   * @jonas.cmp-field-jdbc-mapping  field-name="name"
   *	jdbc-field-name="name"
   * 
   * --
   * <!-- end-xdoclet-definition --> 
   * @generated
   */
  public abstract java.lang.String getName();

  /**
   * <!-- begin-user-doc -->
   * Sets the name
   * 
   * @param java.lang.String the new name value
   * <!-- end-user-doc -->
   * 
   * <!-- begin-xdoclet-definition --> 
   * @ejb.interface-method
   * <!-- end-xdoclet-definition -->
   * @generated 
   */
  public abstract void setName(java.lang.String name);
}

Hier mein Test-Client:
Code:
/*
 * Created on 24.08.2007
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package myhelloworld.test;

import java.rmi.RemoteException;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;

import javax.ejb.CreateException;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import myhelloworld.Personen;

/**
 * @author Administrator
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class PersonTestClient_Add {

	private myhelloworld.PersonenHome getHome() throws NamingException {
		return (myhelloworld.PersonenHome) getContext().lookup(
				myhelloworld.PersonenHome.JNDI_NAME);
	}

	private InitialContext getContext() throws NamingException {
		Hashtable props = new Hashtable();

		props.put(InitialContext.INITIAL_CONTEXT_FACTORY,
				"org.jnp.interfaces.NamingContextFactory");
		props.put(InitialContext.PROVIDER_URL, "jnp://127.0.0.1:1099");

		// This establishes the security for authorization/authentication
		// props.put(InitialContext.SECURITY_PRINCIPAL,"username");
		// props.put(InitialContext.SECURITY_CREDENTIALS,"password");

		InitialContext initialContext = new InitialContext(props);
		return initialContext;
	}

	private void insertPerson(Integer id, String name)
	{
		try{
			getHome().create(id, name);
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void AddBean() 
	{
		try {

			Collection all = getHome().findAll();
			Iterator it = all.iterator();
			
			while(it.hasNext())
			{
				Personen element = (Personen)it.next();
				//element.remove();
			}
			
			insertPerson(new Integer(10), new String("wert"));
			
			all = getHome().findAll();
			it = all.iterator();
			
			while(it.hasNext())
			{
				Personen element = (Personen) it.next();
				System.out.println("Id: " + element.getId() + " Name: " + element.getName());
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
			
	}

	public static void main(String[] args) {
		PersonTestClient_Add test = new PersonTestClient_Add();
		test.AddBean();

	}
}

Also eigentlich will ich, dass ich wie man zB bei dem Client sieht nur das " insertPerson(new Integer(10), new String("wert"));" aufrufen müssen um was zu speichern in der DB. Wenn ich das so alles richtig verstanden habe, muss ich das ja in dem Session-Bean machen. Weil das Entity-Bean ist ja (wenn richtig verstanden) dafür da um die Daten aus der DB bereitzustellen.

Daher nun meine Frage wie mache ich das genau?
Bzw. wie sieht das aus mit zB einem lösch aufruf nach "Name" oder so.
Also ungefähr wie "deleteByName" oder so.
Oder einen "findByName".

Wie baue ich sowas ein.
Sorry wenn ich soviele Sachen auf einmal will aber ich schaffe es irgendwie nicht alleine.
Ich denke mir wenn ich einmal vllt sehe wie es genau geht das es dann bei mir klack macht und ich die ganze Schose verstehe.

Vielen Dank für die Hilfe.

Habe auch alles nochmal exportiert und angehängt fals du noch die anderen Dateien brauchst...
 

Anhänge

  • Java.zip
    54,7 KB · Aufrufe: 15
Hallo BumBum,
willst du das ganze mit EJB3 oder EJB2 machen?
Da sich da schon ein paar Änderungen zwischen EJB3 und EJB2 eingeschlichen haben.

Bei EJB2 verwendet man noch XDoclet, um die Interfaces zu generieren. Bei EJB3 hingegen schreibst du die Interfaces zwar selbst, brauchst aber keine Deskriptoren wie ejb-jar.xml mehr zu erstellen.

Je nach dem welche Technik du verwenden möchtest. Würde an deiner Stelle das Projekt mit EJB3 erstellen. Werde mir den Code heute nachmittag mal anschauen, da ich im Moment nicht so viel Zeit habe!

Gruß
BlackMagician
 
Danke erstmal für die schnelle Antwort...

Ich habe es bisher immer mit einer Eclipse-Version gemacht, die bei dem Buch "J2EE mit Eclipse 3 und JBoss (von Hanser ISBN: 3-446-22739-3)" dabei war.
Bei dieser Version wird XDoclet verwendet um wie du schon sagst die Interfaces zu generieren.
Ich hatte mich dafür entschieden, da bei dieser Eclipse-Version nach dem Installieren schon alles vorhanden/vorbereitet ist... (JBoss, Eclipse Plugins usw...)
Habe gedacht, dass es vllt leichter ist mit dieser Version einzuarbeiten, da die Interfaces ja automatisch generiert werden. Und man somit schon eine weitere Fehlerquelle auschließen könnte. Aber ich habe auch schon gemerkt, dass das nicht so 100%ig das gelbe vom Ei ist.
Da man doch irgendwie recht eingeschränkt ist.

Habe zb. mal was in der Home oder HomeLocal erstellt und das kloppt er Dir alles wieder raus, sobald du auf generieren gehst.
Daher habe ich auch schonmal überlegt alles ohne dieses selbststämdige generieren zu machen (EJB3).
Jedoch bin ich mir nicht sicher, ob das vllt zu schwer am Anfang ist.
Weil ich versuche ja gerade erst in das Thema einzusteigen...

Habe auch schonmal überlegt eine andere Version von Eclipse zu installieren.
Jedoch weiß ich ehrlich gesagt nich was ich alles an Plugins benötige.
Den JBoss habe ich schon im Internet gefunden.
Denke mal es sollte ja auch nicht so schwer sein diesen zu Installieren/Konfigurieren oder?!

Ich habe zwar hier in der Firma die möglichkeit auf Server zuzugreifen wo JBoss und eine ASA-Datenbank installiert und konfiguriert sind.
Jedoch denke ich ist es Sinnvoller erst alles einmal local laufen zu lassen.
Will ja nicht direkt alles zerschießen durch mögliche Fehler.
 
Also mitlerweile finde ich persönlich EJB3 einfacher, da man nicht auf solche Dinge wie XDoclet achten muss.

Habe zb. mal was in der Home oder HomeLocal erstellt und das kloppt er Dir alles wieder raus, sobald du auf generieren gehst.

Das kommt daher:
Du kannst nur Änderungen in der Bean machen, da die Interfaces nur zur Kommunikation zwischen Client und Server dienen!
Die Beans werden auf dem Server (JBoss) abgelegt und die Interfaces werden beim Client und auf dem Server abgelegt, da der Client nicht direkt mit dem Bean kommunizieren darf.
Daher ist auch die komplette Business-Logik in den Beans abzulegen, um die Trennung von Server und Client zu gewährleisten.

Ablauf der Kommunikation:
1. Die Beans werden im Server deployed und die Objekte werden im JNDI des Servers als Proxys abgelegt.
2. Der Client erfragt jetzt im JNDI ein Objekt und erhält dieses Proxy-Objekt. Damit hat er die Möglichkeit die Bean im Server anzusprechen.
3. Bean bekommt über das Proxy-Objekte die Aktionen mit und reagiert entsprechend darauf

Wenn du mit EJB3 arbeiten möchtest, könnte ich dir ein kurzes Beispiel zeigen.

Gruß
BlackMagician
 
Hallo,

meiner Meinung nach ist EJB3 wesentlich einfacher.

Was du an Plugins bei eclipse 3 brauchst kann ich dir nicht genau sagen. Wenn du JBoss verwendest gibt es dazu ein Plugin für eclipse.
Was ich persönlich aber am leichtesten fand war Netbeans mit den entsprechenden Plugins. Damit hatte ich eine kleine Beispielanwendung in ca 5 Minuten "online". Aber ich glaube das ist geschmackssache was einem besser gefällt. Eigentlich arbeite ich auch lieber mit eclipse.
Außer halt nen Application-Server und einer Entwicklungsumgebung brauchst du eigenlich nichts. Man braucht auch nicht zwingend Plugins oder sowas, es macht alles aber wesentlich leichter. :)

MFG

zEriX
 
Ja ich denke auch das alles auf EJB3 hinaus laufen wird.
Wenn ihr alle sagt das das einfacher ist ^^

Habe mir gerade erstmal "Eclipse IDE for Java EE Developers" von der Eclipse.org Seite gezogen. Und noch seperat neben dem anderem Eclipse laufen.

Ich möchte schon gerne mit dem JBoss arbeiten, da dieser auch später tatsächlich benutzt wird. Bzw. sogar schon auf dem Server installiert ist.
 
Also dann will ich mal loslegen:

Vorbereitung
Zuerst einmal solltest du dir den neuesten JBoss Application Server (Version 4.2.1GA) herunterladen.

Ich verwende immer ein Standard-Eclipse bzw. ein Eclipse, dass zwar gewisse Plugins mit sich bringt, von denen ich aber selten welche nutze. Zumindest nutze ich die Plugins nicht zur Generierung von Beans.

Ich nutze im Eclipse immer eine bestimmte Verzeichnis-Struktur:
- als source-folder benutze ich "src/main"
- als output folder für eclipse benutze ich "output/classes-eclipse"
- als library-folder benutze ich "lib"

Zudem wende ich die folgende Package-Struktur an, um Server und Client logisch von einander zu kapseln:
- client: Hier kommen alle Klassen rein, die nur vom Client verwendet werden
- server: Hier kommen nur die Klassen rein, die vom Server verwendet werden, also die Beans sowie die LocalInterfaces, da die nur server-seitig anzusprechen sind
- commons: Hier kommen die Klassen rein, die vom Client und vom Server instantiiert werden können. Zum Beispiel das RemoteInterface oder auch das ValueObjekt (sehen wir später noch genauer)


Nun zu dem wesentlichen Part:

Session-Bean
Ich nutze immer ein Interface, in dem die Methoden definiert sind, die später in der SessionBean implementiert werden:

Verwaltung.java
Java:
package tutorials.ejb3.common;

import java.util.List;


public interface Verwaltung
{
    public void insertPerson(String name);

    public void removePerson(int id);

    public Person findPersonById(int id);

    public List<Person> findPersonByName(String name);

    public List<Person> findAll();
}

Von dieser SessionBean erben die beiden Interfaces VerwaltungLocal und VerwaltungRemote

VerwaltungRemote.java
Java:
package tutorials.ejb3.common;


public interface VerwaltungRemote extends Verwaltung
{
    public static final String JNDI_NAME = "VerwaltungBean/remote";
}

VerwaltungLocal.java
Java:
package tutorials.ejb3.server;

import tutorials.ejb3.common.Verwaltung;

public interface VerwaltungLocal extends Verwaltung
{
}

Das mache ich aus dem Grund, um den Code für die zu implementierenden Klassen nur einmal zu schreiben. Zu dem ist der Unterschied zwischen Local und Remote nur der, dass das Remote-Interface den JNDI-Namen preis gibt unter dem ich die Bean laden kann.

VerwaltungBean.java
Java:
package tutorials.ejb3.server;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import tutorials.ejb3.common.Person;
import tutorials.ejb3.common.Verwaltung;
import tutorials.ejb3.common.VerwaltungRemote;

/*
 * @Stateless gibt an, dass es sich um eine Stateless Session Bean handelt
 * @Remote gibt das Remote-Interface an, auf das der Client zugreift
 * @Local gibt das Local-Interface an, den der Server intern verwendet
 */
@Stateless
@Remote(VerwaltungRemote.class)
@Local(VerwaltungLocal.class)
public class VerwaltungBean implements Verwaltung
{
    @PersistenceContext(unitName = "PPC")
    private EntityManager manager;

    public void insertPerson(String name)
    {
        PersonBean person = new PersonBean();
        person.setName(name);
    }

    public void removePerson(int id)
    {
        PersonBean person = manager.find(PersonBean.class, id);
        manager.remove(person);
    }

    public Person findPersonById(int id)
    {
        PersonBean bean = this.manager.find(PersonBean.class, id);

        Person person = new Person();
        person.setId(bean.getId());
        person.setName(bean.getName());

        return person;
    }

    public List<Person> findPersonByName(String name)
    {
        Query query = manager.createNamedQuery("findAllPersonsByName");
        query.setParameter("name", name);

        @SuppressWarnings("unchecked")
        List<PersonBean> beans = query.getResultList();

        List<Person> personen = new ArrayList<Person>();
        for (PersonBean pb : beans)
        {
            Person person = new Person();
            person.setId(pb.getId());
            person.setName(pb.getName());

            personen.add(person);
        }

        return personen;
    }

    public List<Person> findAll()
    {
        Query query = manager.createNamedQuery("findAllPersons");

        @SuppressWarnings("unchecked")
        List<PersonBean> beans = query.getResultList();

        List<Person> personen = new ArrayList<Person>();
        for (PersonBean pb : beans)
        {
            Person person = new Person();
            person.setId(pb.getId());
            person.setName(pb.getName());

            personen.add(person);
        }

        return personen;
    }
}

Die Annotation @Stateless gibt an, dass es sich bei der Bean um eine StatelessSessionBean handelt. Die beiden Annotations @Remote und @Local zeigen auf die Interfaces für den Remote- und den lokalen Zugriff. Diese Bean ist nun von einem Client per JNDI-lookup ansprechbar.

Java:
@PersistenceContext(unitName = "PPC")
Der PersistenceContext wird über die persistence.xml festgelegt, in der die DataSource angegeben wird, auf die ich im JBoss zugreifen möchte.
Code:
<?xml version="1.0" encoding="UTF-8"?>
<persistence>
  <persistence-unit name="PPC">
    <jta-data-source>java:/DefaultDS</jta-data-source>
    <properties>
      <property name="hibernate.hbm2ddl.auto" value="update"/>
      <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
    </properties>
  </persistence-unit>
</persistence>

Der EntityManager verwaltet die Entitäten und hat nützliche Methoden um Entitys zu laden.
Java:
EntityManager.find(Class<PersonBean> arg0, Object arg1);
EntityManager.createNamedQuery(String arg0);
find() erfordert zwei Parameter:
- die Entität die geladen werden soll. hier: PersonBean.class
- und den PrimaryKey in unserem Fall die "id"

createNamedQuery() ruft eine NamedQuery auf, die wir per Annotation festlegen. Beispiel dazu folgt unter dem Punkt "Entity-Bean".

Entity-Bean
Die Entity-Bean kann ebenfalls mit Annotations stark vereinfacht werden:

PersonBean.java
Java:
package tutorials.ejb3.server;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name = "Person")
@NamedQueries( { @NamedQuery(name = "findAllPersons", query = "from PersonBean"),
        @NamedQuery(name = "findAllPersonsByName", query = "from PersonBean where name = ?") })
public class PersonBean
{
    private int id;
    private String name;

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

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

    public String getName()
    {
        return this.name;
    }

    public void setName(String newName)
    {
        this.name = newName;
    }
}

Die Annotation @Entity gibt an das diese Bean eine Entity-Bean ist. Die Annotation @Table gibt an welche Tabelle in der Datenbank genutzt werden soll. Der Name der Bean wird somit auf die Tabelle gemapped. Gibt man die Annotation nicht an, wird der Name der Bean genommen.
Mit der Annotation @NamedQueries können verschiedene @NamedQuery-Annotations vereint werden.
Eine @NamedQuery hat den einen Namen und die Abfrage (query) die sie auf DB-Level ausführt.

Java:
@NamedQuery(name = "findAllPersons", query = "from PersonBean")

Diese Query fragt in der Tabelle die auf die PersonBean gemapped ist alle Daten ab. Also wie

Java:
Select * from Person

Java:
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Diese beiden Annotations legen zum einen das ID-Feld (PrimaryKey) und den Typ der Generierung in der Datenbank fest. Also in dise mFall eine automatische Generierung der ID in der DB.

ValueObject
Ich habe zu dem auch ein Value-Objekt benutzt, da die Trennung zwischen Client und Server erhalten bleiben muss und ich nicht die Entität an den Client schicke sondern ein Objekt, dass die Daten der Entität zwischenspeichert und an den Client gesendet wird.
Die Klasse Person speichert wie die Entity-Bean die id und den Namen und kann vom Client verarbeitet werden, da die Entität im Server liegt und nichts auf der Client-Seite zu suchen hat.

Person.java
Java:
package tutorials.ejb3.common;

import java.io.Serializable;

public class Person implements Serializable
{
    private int id;
    private String name;

    public void setName(String newName)
    {
        name = newName;
    }

    public String getName()
    {
        return name;
    }

    public int getId()
    {
        return id;
    }

    public void setId(int newId)
    {
        id = newId;
    }
}

Client
Der Client macht den lookUp im JNDI des JBoss-Servers und holt sich das VerwaltungBean. Dadurch kann er nun Perosnen laden und löschen.

Java:
package tutorials.ejb3.client;

import java.util.List;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.InitialContext;

import tutorials.ejb3.common.Person;
import tutorials.ejb3.common.Verwaltung;

public class Client
{
    public static void main(String[] args)
    {
        Properties props = new Properties();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
        props.put(Context.PROVIDER_URL, "jnp://localhost:1099");
        props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");

        try
        {
            InitialContext ctx = new InitialContext(props);
            Verwaltung verwaltung = (Verwaltung) ctx.lookup("VerwaltungBean/remote");

			verwaltung.insertPerson("Hans");
			verwaltung.insertPerson("Franz");
			verwaltung.insertPerson("Klaus");
			
            List<Person> list = verwaltung.findAll();
            for (Person person : list)
            {
                System.out.println(person.getName());
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

Auf der Konsole sollte dann die angelegten Personen ausgegeben werden.

Kontrolle
Neben den Ausgaben des Clients kann man auch noch mal den DatabaseManager starten.
Dazu suche in der jmx-console nach dem Eintrag
"database=localDB,service=Hypersonic" und invoke "startDatabaseManager" drücken.
Darauf öffent sich der Hypersonic-DBManager worin man normale SQL-Statements absetzen kann.

Gruß
BlackMagician
 
Zurück