Advanced   Java   Services Stateful Session Beans 3.0 Back Next Up Home


Einführung


Eine stateful Session Bean ist eine Bean die clientspezifischen Daten speichert und so eine 1 zu 1 Beziehung zwischen Client und Bean herstellt, bzw. herstellen muß. Zusätzlich zur stateless Sessionbean hat sie noch den Zustand "Passive". Die Zustände werden vom Beancontainer gesteuert.

Eine Hello World EJB 3.0 stateful Sessionbean


Auch diesmal verwenden wir keine Entwicklungsumgebung. Des weiteren verzichten wir der Einfachheit halber wieder auf packages. Als Übung sollten Sie das Beispiel so abändern, daß Sie packages einsetzen und verweisen nochmal darauf daß in der Praxis die Klassen immer in packages gelegt werden.

Unser Beispiel besteht aus drei Dateien, dem Remoteinterface, der eigentlichen Beanklasse und dem Client der den Dienst dieser EJB über das Protokoll "iiop" (Internet Inter-ORB Protocol) in Anspruch nehmen will. Zu diesem Protokoll gibt es eine kurze Information auf Wikipedia.

Das Remoteinterface


import javax.ejb.Remote;

@Remote
public interface SayHello
{
    public String sayHello();
    public java.util.Date getCreationDate();
}


Das Business-Interface ist wieder ein ganz normales Interface. Eine Ableitung vom Interface javax.ejb.EJBObject ist nicht mehr notwendig. Wir markieren das Interface mit einer Annotation als remote interface. Zu jeder Annotation gibt es ein entsprechendes Import. Die neue Methode soll uns das Geburtsdatum der Bean liefern. Wir werden damit feststellen können, daß jeder Client seine eigene Bean zugewiesen bekommt. Wie im vorigen Beispiel: Zum Kompilieren braucht man das Archiv javaee.jar .

Die Beanklasse


/*
   die beanklasse

   stateful session bean  (man beachte die importe)
   implementiert das interface SayHello2
*/

import java.util.Date;
import javax.ejb.Remote;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.ejb.PrePassivate;
import javax.ejb.PostActivate;

@Stateful(name="SayHello2", mappedName="ejb/SayHelloStateful")
@Remote(SayHello2.class)

public class SayHelloBean2 implements SayHello2
{
   private String message = "Hello EJB 3.0 Stateful";
   private java.util.Date creationDate;

   public SayHelloBean2()
   {
      creationDate = new Date();
      System.out.println("constructor SayHelloBean2() called");
   }

   @Override
   public String sayHello2()
   {
      return message;
   }

   @Override
   public java.util.Date getCreationDate()
   {
      return creationDate;
   }

   // für stateful session beans um auf eine zustandsänderung reagieren zu können
   @PrePassivate
   public void ejbPassivate()    // name der methode ist ab 3.0 beliebig
   {
   }

   @PostActivate
   public void ejbActivate()     // name der methode ist ab 3.0 beliebig
   {
   }

   // optional
   @Remove
   public void ejbRemove()       // name der methode ist ab 3.0 beliebig
   {
      System.out.println("ejbRemove called");
   }
}


Wir haben ein Datumsobjekt im privaten Datenteil, das über den Konstruktor initialisiert wird. Damit enthält creationDate das Geburtsdatum des Objekts, das über die öffentliche Methode getCreationDate() erfragt werden kann. Die Methoden ejbPassivate() und ejbActivate() ermöglichen die Reaktion auf eine Zustandsänderung der Bean und sind hier (noch) leer.

Erstellen des Bean-Archivs und der Deployvorgang


Das Remotinterface und die Beanklasse müssen zusammen mit einem META-INF Verzeichnis zu einer jar-Datei (oder auch ear-Datei) gepackt werden. Das META-INF Verzeichnis enthält eine Manifestdatei MANIFEST.MF und optional einen Deploymentdescriptor im XML-Format namens ejb-jar.xml. Diesmal verwenden wir als Packer das Java-Utility jar.exe aus dem vin-verzeichnis des JDK. der einfachste Aufruf ist

jar cvf <name-der-ear-datei> .

jar.exe legt automatisch ein META-INF Verzeichnis mit einer Manifestdatei an. Der Hauptname des ear-Archivs ist übrigens völlig beliebig. Bei der Verwendung von Eclipse oder Netbeans können wir das Erstellen des Archivs zur Gänze delegieren. Das fertige Archiv bringen wir nun zum Server und legen es ins Autodeployverzeichnis von Glassfish.

<SUNHOME>/SDK/domains/domain1/autodeploy

Glassfish kontrolliert periodisch den Inhalt dieses Verzeichnis und versucht neu hinzugekommene ear-Dateien (oder jar-Dateien oder war-dateien) zu starten. Gelingt dies wird eine leere Datei mit dem Namen "SayHellobean.ear_deployed" angelegt. Gelingt es nicht, so heißt die entsprechende Datei "SayHellobean.ear_deployFailed"

Sieht man die Meldung "SayHellobean.ear_deployed" auftauchen, kann man zum Client zurückgehen und die Clientdatei starten.

Der iiop-Client


import java.util.*;
import javax.naming.*;

public class SayHelloClient
{
    public static void main(String[] args)
    {
        System.out.println("about to create initialcontext");
        String url = "iiop://<server-ip-adress>" ;
        String jndiName = "ejb/SayHelloStateful";

        Properties env = new Properties();
        env.put("org.omg.CORBA.ORBInitialHost","<server-ip-adress>");  // default ist localhost !!
        //env.put("org.omg.CORBA.ORBInitialPort","3700");  // ist default
        env.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
        //env.put("java.naming.factory.url.pkgs","com.sun.enterprise.naming");  // hier noch nicht notwendig
        //env.put("java.naming.provider.url","com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl");  // hier noch nicht notwendig
        //env.put("java.naming.factory.state",url);  // hier noch nicht notwendig

        try
        {
            Context ctx = new InitialContext(env);   // NamingException
            System.out.println("initial context received");

            SayHello2 remote = (SayHello)ctx.lookup(jndiName);    // NamingException
            if( remote != null)
                System.out.println("remote class = " + remote.getClass().getName() );
            else
                throw new NullPointerException("lookup failed");

            // der wrapper hat den typ _SayHello_Wrapper und hat das remote interface implementiert,
            // man kann also ohne cast einfach die businessmethoden rufen
            System.out.println(remote2.sayHello());
            System.out.println(remote.getCreationDate());
        }
        catch(NamingException ex)
        {
            System.out.println("NamingException " + ex);
        }
        catch(Exception ex)
        {
            System.out.println("Exception " + ex);
        }
        // ende try - catch

    }  // end main
}


Die Konsolausgaben der Clients


  

Wenn Sie mehrere Instanzen dieses Clients starten, so werden Sie feststellen, daß jedes mal ein anderes Datum ausgegeben wird. Daraus können wir schließen, daß jeder Client eine eigene Beaninstanz erhält.

Als Übung sollten Sie dieses Beispiel so abändern, daß Sie Packages verwenden.

top Back Next Up Home