Beispiel: Stateful und Singleton Session Bean


Inhalt:

Anlegen der Enterprise Application
Anlegen der GeometricModelBean
Anlegen der GeometricModelStoreBean
Anlegen der SingletonBean
Anlegen des WebClient
Testen des WebClient
Ohne Annotations
"No-interface" view

Beispiel für eine Stateful Session Bean sowie eine Singleton Session Bean, auf die per Webclient zugegriffen wird.
Hier gibt es das Projekt zum Download (dies ist ein EAR-Export, die Importanleitung findet man im Stateless-Beispiel): Stateful.ear

Dieses Beispiel kann übrigens parallel zum Stateless-Beispiel auf den Server deployed werden, da die GeometricModelBean zwar in beiden Beispielen vorkommt, aber mit unterschiedlichen Namen ins JNDI gehängt wird.

Aufbau des Beispieles

a) Stateless Bean-Klasse mit Local Interface.
b) Stateful Bean-Klasse mit Local Interface.
c) Singleton Bean-Klasse mit Local Interface.
d) Webclient: JSP-Seite

Die Stateful Session Bean speichert alle Berechnungen, die der aktuelle Benutzer in seiner Browser-Session durchgeführt hat. Die Singleton Bean existiert nur einmal im Server und ist unabhängig von Benutzersessions. Sie speichert ebenfalls die Berechnungen, allerdings über alle Benutzersessions hinweg (bis zum Server-Neustart oder bis zum Redeploy der Anwendung). Ich denke übrigens nicht, dass dieses Beispiel eine "optimale" Verwendung einer Singleton-Bean ist, aber es funktioniert zumindest ;-).


Anlegen der Application

Ein "Enterprise Application Project" mit dem Namen "Stateful", einem EJB-Projekt und einem Webprojekt erstellen.
Im Project Explorer sollte es so aussehen:
Erzeugtes Projekt


Anlegen der StatelessBean

Die Schritte sind identisch mit denen des letzten Beispiels. Die Bean (im Package de.fhw.komponentenarchitekturen.knauf.stateful) hat allerdings nur ein Local Interface "GeometricModelLocal", das RemoteInterface "GeometricModelRemote" entfällt. Die Geschäftsmethoden und die Exceptionklasse "InvalidParameterException" sind identisch.


Anlegen der StatefulBean

Die Bean hat den Namen "GeometricModelStoreBean" im Package de.fhw.komponentenarchitekturen.knauf.stateful. Wir wählen als "State Type" den Wert "Stateful". Sie hat ein Local-Interface, wobei man hier den von Eclipse vorgeschlagenen Namen "GeometricModelStoreBeanLocal" in "GeometricModelStoreLocal" ändert. Der Haken "No-interface view" wird zurückgesetzt.
Stateful Session Bean
Die Bean erhält automatisch die Annotation "Stateful":
@Stateful()
public class GeometricModelStoreBean implements GeometricModelStoreRemote
{ 
Wir deklarieren drei Membervariablen für die Tripel der Kantenlängen:
  private Vector<Double> vectorA = null;
  private Vector<Double> vectorB = null;
  private Vector<Double> vectorC = null; 
Außerdem gibt es zwei Business-Methoden "addCalculation" (hinzufügen eines neuen Satzes von Kantenlängen) und "getAllCalculations" (alle bisherigen Berechnungen in String-Form zurückliefern, für die Zeilenumbrüche wird ein HTML-Zeilenumbruch in die Rückgabe eingefügt):
  public void addCalculation(double a, double b, double c) throws InvalidParameterException
  {
    if (a <= 0 || b <= 0 || c <= 0)
      throw new InvalidParameterException("Seitenlänge <= 0");

    this.vectorA.add(new Double(a));
    this.vectorB.add(new Double(b));
    this.vectorC.add(new Double(c));
  }

  public String getAllCalculations()
  {
    String strReturn = "";
    for (int intIndex = 0; intIndex < this.vectorA.size(); intIndex++)
    {
      if (intIndex > 0)
        strReturn += "<br>\r\n";
      strReturn += "Anfrage " + intIndex + ": " + this.vectorA.get(intIndex) + "/" + this.vectorB.get(intIndex) + "/"
          + this.vectorC.get(intIndex);
    }

    return strReturn;
  } 
Eine Besonderheit werden wir hier anwenden: unsere Stateful Session Bean wird nicht unbedingt physisch neu erzeugt wenn ein neuer Client sie anfordert, sondern es wird eventuell eine "freie" (keinem anderen Client zugeordnete) Instanz recycled. Deshalb reicht es nicht die Vektoren im Konstruktor zu erzeugen, sondern wir müssen eine Methode implementieren die der Container bei jedem neuen Binden an einen Client aufruft.
Dieses Binden geschieht über die Annotation "@PostConstruct":
  @PostConstruct()
  public void postConstruct()
  {
    this.vectorA = new Vector<Double>();
    this.vectorB = new Vector<Double>();
    this.vectorC = new Vector<Double>();
  } 

Das Local Interface sollte so aussehen:
@Local()
public interface GeometricModelStoreLocal
{
  public abstract void addCalculation(double a, double b, double c) throws InvalidParameterException;

  public abstract String getAllCalculations();
} 


Anlegen der SingletonBean

Die Bean hat den Namen "GeometricModelStoreSingleton" im Package de.fhw.komponentenarchitekturen.knauf.stateful. Wir wählen als "State Type" den Wert "Singleton". Sie hat ein Local-Interface namens "GeometricModelStoreSingletonLocal". Der Haken "No-interface view" wird zurückgesetzt.
Singleton Session Bean
Die Bean erhält automatisch die Annotation "Singleton":
@Singleton
public class GeometricModelStoreSingleton implements GeometricModelStoreSingletonLocal
{ 
Der restliche Code (Methoden "addCalculation" und "getAllCalculations") ist identisch zum vorherigen Beispiel und wird deshalb hier nicht nochmal gedoppelt.
Auch der Code für "postConstruct" bleibt erhalten. Die drei Vektoren hätten wir hier allerdings auch direkt beim Deklarieren der Variablen schon erzeugen können.

Anschließend wird das Local Interface "GeometricModelStoreSingletonLocal" mit Leben gefüllt (identisch zum Stateful Beispiel):
@Local()
public interface GeometricModelStoreSingletonLocal
{
  public abstract void addCalculation(double a, double b, double c) throws InvalidParameterException;

  public abstract String getAllCalculations();
} 


Anlegen des Webclients

Vorbereitung:
Damit die JSP-Seite die EJB referenzieren kann, muss eine Referenz auf die JAR-Datei zugefügt werden.
Dazu einen Rechtsklick auf den Project-Explorer-Knoten "StatefulWeb" ausführen und "Properties" wählen. Unter dem Punkt "Deployment Assembly" -> "Manifest Entries" fügt man eine Referenz auf das EJB-Jar-Projekt zu.
Webclient, EJB-Referenz

Außerdem müssen wir uns die Datei "web.xml" generieren lassen (Screenshot aus dem Stateless-Beispiel): Generate Deployment Descriptor Stub

Im Web-Projekt wird eine JSP-Seite "GeometricModelTest.jsp" zugefügt.
Der Quelltext sieht so aus:
<%@ page import="javax.naming.InitialContext, de.fhw.komponentenarchitekturen.knauf.stateful.*" %>
<HTML>
<HEAD>
<TITLE>
GeometricModelTest
</TITLE>
</HEAD>
<BODY>
<H1>GeometricModel mit Stateful Bean</H1>
<%
InitialContext initialContext = new InitialContext();

//Parameter parsen, falls vorhanden.
GeometricModelStoreLocal geometricModelStore = null;
if (request.getParameter("submit") == null)
{
  //Erster Aufruf: Wir erzeugen den Store.

  //Stateful Session Bean holen !
  geometricModelStore = (GeometricModelStoreLocal) initialContext.lookup ("java:comp/env/ejb/GeometricModelStore");

  //In Session-Context schreiben:
  session.setAttribute("GeometricModelStore", geometricModelStore);
}
else
{
  // Zweiter bis n-ter Aufruf: Berechnen.

  //Den Store aus Session holen:
  geometricModelStore = (GeometricModelStoreLocal) session.getAttribute("GeometricModelStore");

  double dblA = Double.parseDouble(request.getParameter("a") );
  double dblB = Double.parseDouble(request.getParameter("b") );
  double dblC = Double.parseDouble(request.getParameter("c") );

  //Zum Store zufügen:
  geometricModelStore.addCalculation( dblA, dblB, dblC);

  //Singleton für Speicherung aller Berechnungen holen:
  GeometricModelStoreSingletonLocal geometricModelStoreSingleton = (GeometricModelStoreSingletonLocal) initialContext.lookup ("java:comp/env/ejb/GeometricModelStoreSingleton");
  geometricModelStoreSingleton.addCalculation( dblA, dblB, dblC);

  ///////////////////////////////////////////////////////////////
  // Berechnung über Remote-Interface.

  GeometricModelLocal geometricModel = (GeometricModelLocal) initialContext.lookup ("java:comp/env/ejb/GeometricModel");

  double dblVolume = geometricModel.computeCuboidVolume( dblA, dblB, dblC);
  double dblSurface = geometricModel.computeCuboidSurface( dblA, dblB, dblC);

  %>

  Volumen = <%=dblVolume%>, Oberfläche = <%=dblSurface%>
  <br><br><br>

  Ihre letzten Berechnungen: <br>
  <%=geometricModelStore.getAllCalculations() %>
  <br/>
  <br/>
  Alle bisherigen Berechnungen:<br/>
  <%=geometricModelStoreSingleton.getAllCalculations() %>
<%
}
%>
<form action="GeometricModelTest.jsp" method="post">
  a = <input type="text" name="a" /> <br>
  b = <input type="text" name="b" /> <br>
  c = <input type="text" name="c" /> <br>

  <input type="submit" name="submit" value="submit" />
</form>

</BODY>
</HTML>
Besonderheit ist die Behandlung der Stateful Session Bean: damit die in ihr gespeicherten Werte zwischen den Aufrufen erhalten bleiben, wird sie nur beim ersten Erzeugen aus dem JNDI geholt und danach in den SessionContext gespeichert. Bei allen weiteren Aufrufen wird die Instanz aus dem SessionContext wiederverwendet.

Anmerkung: Würde man in der JSP die Stateful Session Bean jedesmal neu aus dem JNDI holen, würde man auch jedesmal eine neue Instanz erhalten und hätte deshalb keinen Session State. Deshalb wird die Instanz beim ersten Aufruf der Seite aus dem JNDI geholt und danach im Session Context gespeichert.
  GeometricModelStoreLocal geometricModelStore = null;
  ...
  geometricModelStore = (GeometricModelStoreLocal) initialContext.lookup ("java:comp/env/ejb/GeometricModelStore");
  session.setAttribute("GeometricModelStore", geometricModelStore);
Bei jedem weiteren Aufruf der Seite schickt der Browser ein Cookie mit, das dem Server ermöglicht, die bestehende Session dem aktuellen Aufruf zuzuordnen. Im Falle des zweiten Aufrufs der Seite ("submit"-Button wurde geklickt und ist als Request-Parameter enthalten) können wir die Stateful Bean aus dem Session Context holen. Dadurch behält sie ihren Zustand.
  GeometricModelStoreLocal geometricModelStore = null;
  ...
  geometricModelStore = (GeometricModelStoreLocal) session.getAttribute("GeometricModelStore");
Geschickter wäre es vermutlich, den JNDI-Lookup nicht vom Submit-Button-Klick abhängig zu machen (wenn man die URL der Seite direkt aufruft, ist der Button ja ebenfalls nicht geklickt worden), sondern zu prüfen, ob man im Session Context bereits etwas findet. Wenn nicht, dann könnte man den JNDI-Lookup durchführen.


Deklaration der EJB-Referenzen in "web.xml":
"StatefulWeb" -> "WebContent" -> "WEB-INF" -> "web.xml" öffnen, im Element "web-app" wird folgendes eingefügt:
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModel</ejb-ref-name>
		<ejb-ref-type>Session</ejb-ref-type>
		<local>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelLocal</local>
	</ejb-local-ref>
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelStore</ejb-ref-name>
		<ejb-ref-type>Session</ejb-ref-type>
		<local>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreLocal</local>
	</ejb-local-ref>
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelStoreSingleton</ejb-ref-name>
		<ejb-ref-type>Session</ejb-ref-type>
		<local>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreSingletonLocal</local>
	</ejb-local-ref>

Die JSP-Seite "GeometricModelTest.jsp" soll als Startseite möglich sein. Auch das stellen wir über "web.xml" ein (die bereits vorhandenen Dateinamen können gelöscht werden, da wir keine davon verwenden):
	<welcome-file-list>
		<welcome-file>GeometricModelTest.jsp</welcome-file> 
	</welcome-file-list> 

Für die EJB-Referenzen müssen wir außerdem in "StatefulWeb\WebContent\WEB-INF" die Datei "jboss-web.xml" mit diesem Inhalt anlegen:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-web_7_0.xsd"
           version="7.0">

<jboss-web>
	<context-root>StatelessWeb</context-root>
	<!-- Referenz auf "GeometricModelBean" -->
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModel</ejb-ref-name>
		<jndi-name>java:global/Stateful/StatefulEJB/GeometricModelBean!de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelLocal</jndi-name>
	</ejb-local-ref>
	<!-- Referenz auf "GeometricModelStoreBean" -->
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelStore</ejb-ref-name>
		<jndi-name>java:global/Stateful/StatefulEJB/GeometricModelStoreBean!de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreLocal</jndi-name>
	</ejb-local-ref>
	<!-- Referenz auf "GeometricModelStoreSingleton" -->
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelStoreSingleton</ejb-ref-name>
		<jndi-name>java:global/Stateful/StatefulEJB/GeometricModelStoreSingleton!de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreSingletonLocal</jndi-name>
	</ejb-local-ref>
</jboss-web> 


Testen des Webclients

Der Test erfolgt über diese URL: http://localhost:8080/StatefulWeb
Achtung: Die Stateful Session Bean ist im Session Context der Webanwendung abgelegt. Der Session Context bleibt uns so lange zugeordnet wie wir den Browser offen haben (Erkennung erfolgt über ein Cookie), das heißt wenn wir eine neue Session und damit eine frische Stateful Session Bean haben wollen müssen wir alle gerade offenen Instanzen des Browsers schließen.


Ohne Annotations

Jetzt der Weg ohne Annotations, nur mit Deployment-Deskriptoren:
Im Enterprise-Application-Projekt "Stateful" sieht der Deskriptor "application.xml" so aus:
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:application="http://java.sun.com/xml/ns/javaee/application_6.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd"
	id="Application_ID" version="6">
	<display-name>Stateful</display-name>
	<module>
		<web>
			<web-uri>StatefulWeb.war</web-uri>
			<context-root>StatefulWeb</context-root>
		</web>
	</module>
	<module>
		<ejb>StatefulEJB.jar</ejb>
	</module>
</application>


Die Datei "ejb-jar.xml" im EJB-Projekt muss so aussehen:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns="http://java.sun.com/xml/ns/javaee"
  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_1.xsd" 
  version="3.1">
  <display-name>StatefulEJB</display-name>
  <enterprise-beans>
		<session>
			<description>
				<![CDATA[Stateless Session Bean für einfache geometrische Berechnungen.]]>
			</description>
			<display-name>GeometricModelBean</display-name>
			<ejb-name>GeometricModelBean</ejb-name>
			<business-local>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelLocal</business-local>
			<ejb-class>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelBean</ejb-class>
			<session-type>Stateless</session-type>
		</session>
		<session>
			<description>
				<![CDATA[Stateful Session Bean für die Speicherung der Berechnungs-Historie.]]>
			</description>
			<display-name>GeometricModelStoreBean</display-name>
			<ejb-name>GeometricModelStoreBean</ejb-name>
			<business-local>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreLocal</business-local>
			<ejb-class>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreBean</ejb-class>
			<session-type>Stateful</session-type>
			<post-construct>
				<lifecycle-callback-class>
					de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreBean
				</lifecycle-callback-class>
				<lifecycle-callback-method>postConstruct</lifecycle-callback-method>
			</post-construct>
		</session>
		<session>
			<description>
				<![CDATA[Singleton Session Bean für die Speicherung aller Berechnungen über 
				die GeometricModelBean, die seit dem Deploy der Anwendung erfolgten.]]>
			</description>
			<display-name>GeometricModelStoreSingleton</display-name>
			<ejb-name>GeometricModelStoreSingleton</ejb-name>
			<business-local>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreSingletonLocal</business-local>
			<ejb-class>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreSingleton</ejb-class>
			<session-type>Singleton</session-type>
			<post-construct>
				<lifecycle-callback-class>
					de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreSingleton
				</lifecycle-callback-class>
				<lifecycle-callback-method>postConstruct</lifecycle-callback-method>
			</post-construct>
		</session>
	</enterprise-beans>
  
</ejb-jar> 
Es gibt zwei Besonderheiten im Vergleich zum Stateless-Beispiel (fett markiert): die Deklaration der GeometricModelStoreBean als "Stateful" und das Mapping des Lifecycle-Callbacks "PostConstruct" auf die Methode der Bean und analog für die Singleton-Bean. Der Rest des Projekts ist absolut identisch mit dem Annotation-igen Beispiel.


Die modifizierte Version des Projekts gibt es hier:
StatefulNoAnnotation.ear.
ACHTUNG: Dieses Projekt kann nicht neben dem obigen Stateful-Beispiel existieren !


"No-interface" view

Ein neues Feature in JavaEE6 ist die "No-interface view": das bedeutet, dass man auf eine Session Bean auch zugreifen kann, ohne dass man Local- oder Remote Interface deklarieren muss. Das geht allerdings nur, wenn der Client in der selben Java Virtual Machine läuft wie die EJB, also z.B. eine Webanwendung, die auf eine EJB auf dem gleichen JBoss-Server zugreift. Alle public Methoden der EJB sind für den Client verfügbar. Dadurch kann man sich einiges an Code sparen.

In diesem Fall baut man nur Bean-Klassen, ohne Interfaces. Der Client führt seinen Lookup direkt auf die EJB durch. Er muss sich die EJB-Instanz allerdings weiterhin holen - er darf sie auf keinen Fall per Konstruktor erzeugen!

Hier die relevanten Klassen im EJB-Projekt:
@Stateless() 
public class GeometricModelBean
{
  ...
}

@Stateful()
public class GeometricModelStoreBean
{
  ...
}

@Singleton
public class GeometricModelStoreSingleton
{
  ...
}
In "GeometricModelTest.jsp" führen wir wie bisher den Lookup auf einen Eintrag im Environment Naming Context durch, allerdings kommt als Ergebnis eine Instanz der Bean-Klasse zurück statt eines Interfaces:
  GeometricModelBean geometricModel = (GeometricModelBean) initialContext.lookup ("java:comp/env/ejb/GeometricModel");

Die Deklaration der ENC-Einträge in "web.xml" bzw. "jboss-web.xml" habe ich durch try&error ausprobiert. Es klappt, wenn man die No-interface view wie ein Local Interface behandelt (aber wie gesagt: ich weiß nicht, ob das korrekt ist ;-)):
Der relevante Teil in "web.xml" sieht so aus (analog zu den bisherigen Fällen, nur dass ich den Bean-Namen ins "local"-Element gehängt habe):
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModel</ejb-ref-name>
		<ejb-ref-type>Session</ejb-ref-type>
		<local>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelBean</local>
	</ejb-local-ref>
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelStore</ejb-ref-name>
		<ejb-ref-type>Session</ejb-ref-type>
		<local>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreBean</local>
	</ejb-local-ref>
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelStoreSingleton</ejb-ref-name>
		<ejb-ref-type>Session</ejb-ref-type>
		<local>de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreSingleton</local>
	</ejb-local-ref>
"jboss-web.xml" sieht so aus:
	<!-- Referenz auf "GeometricModelBean" -->
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModel</ejb-ref-name>
		<jndi-name>java:global/Stateful/StatefulEJB/GeometricModelBean!de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelBean</jndi-name>
	</ejb-local-ref>
	<!-- Referenz auf "GeometricModelStoreBean" -->
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelStore</ejb-ref-name>
		<jndi-name>java:global/Stateful/StatefulEJB/GeometricModelStoreBean!de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreBean</jndi-name>
	</ejb-local-ref>
	<!-- Referenz auf "GeometricModelStoreSingleton" -->
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelStoreSingleton</ejb-ref-name>
		<jndi-name>java:global/Stateful/StatefulEJB/GeometricModelStoreSingleton!de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelStoreSingleton</jndi-name>
	</ejb-local-ref>
Hier ist die Spezialität der JNDI-Name: wie man schon in der Konsolenausgabe gesehen hat, ist die Bean unter ihrem Klassennamen ins JNDI gebunden, statt wie bei den Interfaces mit dem Namen des Local/Remote-Interface nach dem Ausrufezeichen:
20:47:55,407 INFO  [org.jboss.as.ejb3.deployment.processors.EjbJndiBindingsDeploymentUnitProcessor] (MSC service thread 1-4) JNDI bindings 
for session bean named GeometricModelBean in deployment unit subdeployment "StatefulEJB.jar" of deployment "Stateful.ear" are as follows:

	java:global/Stateful/StatefulEJB/GeometricModelBean!de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelBean
	java:app/StatefulEJB/GeometricModelBean!de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelBean
	java:module/GeometricModelBean!de.fhw.komponentenarchitekturen.knauf.stateful.GeometricModelBean
	java:global/Stateful/StatefulEJB/GeometricModelBean
	java:app/StatefulEJB/GeometricModelBean
	java:module/GeometricModelBean

Die modifizierte Version des Projekts gibt es hier:
StatefulNoInterfaceView.ear.
ACHTUNG: Dieses Projekt kann nicht neben dem obigen Stateful-Beispiel existieren !

Stand 05.05.2013
Historie:
01.04.2013: Erstellt aus 2008-Beispiel, angepaßt an JBoss 7 und Eclipse 4.2. Erweiterungen für JavaEE6 (Singleton, "no-interface view")
05.05.2013: Deployment-Deskriptoren korrigiert (unnötige "xmlns"-Deklaration entfernt).