Beispiel: Stateless Session Bean


Inhalt:

Anlegen der Enterprise Application
Anlegen der GeometricModelBean
Anlegen des WebClient
Server einrichten
Anlegen des Application Clients
Ausführen des Application Clients
Export des Workspace
Re-Import
Ohne Annotations

Beispiel für eine Stateless Session Bean, auf die per Webclient und mittels Application Client zugegriffen wird.
Hier gibt es das WebSphere-Projekt zum Download (dies ist ein Projektaustausch-Export, die Importanleitung findet man am Ende dieses Dokuments): Stateless.ear

Aufbau des Beispieles


a) Bean-Klasse mit Local und Remote-Interfaces
b) Webclient: JSP-Seite
c) WebClient: Servlet
d) App-Client


Anlegen der Application

Schritt 1: Über "File" -> "New" -> "Other..." gelangen wir in den Wizard zum Hinzufügen von neuen Komponenten. wir wählen im Zweig "J2EE" ein "Enterprise Application Project".
Erzeugen einer Application (Schritt 1)
Schritt 2: In dem erscheinenden Dialog geben wir dem Projekt einen Namen und wählen den JBoss 4.0.5-Server aus.
Erzeugen einer Application (Schritt 2)
Auf "Next" klicken.
Schritt 3: Hier belassen wir alles auf dem Default. Die gewählte "EAR version" "1.4" ist zwar für unsere Fälle falsch, aber leider unterstützt WTP noch nicht die 5er-Version.
Erzeugen einer Application (Schritt 3)
Schritt 4: Modulprojekte zufügen. Dazu auf den Button "New Module..." klicken. Wir wünschen uns ein EJB-Projekt, einen Application Client und einen Webclient. Connectorprojekte werden wir im Rahmen dieses Praktikums nie anfassen.
Erzeugen einer Application (Schritt 4)
Schritt 4: Zurück im Hauptdialog stellen wir sicher dass diese drei Module ausgewählt sind.
Erzeugen einer Application (Schritt 5)

Man klickt auf "Finish" und hat folgende J2EE-Hierarchie angelegt:
Erzeugte J2EE-Hierarchie

Jetzt müssen wir das ganze auf den JEE5-Standard bringen, denn im Moment sind alle Deployment-Deskriptoren noch auf J2EE-Niveau.
Eigentlich bräuchten wir diese Dateien nicht zwingend, da in EJB3 alles über Annotations gesteuert werden kann. Um die etwas veraltete Projektstruktur der WebTools-Platform nicht zu verwirren behalten wir die Dateien aber bei.
Im EJB-Projekt stellen wir den EJB-Validator ab, da dieser wiederum nur die EJB-2.1-Struktur validiert und deshalb eine gut gefüllt ejb-jar.xml erwartet.
Dazu in die Properties des EJB-Projekts gehen. Im Punkt "Validation" setzen wir den Haken "Override validation preferences" und schalten den "EJB Validator" ab.
EJB validation


Anlegen der GeometricModelBean

Die WebTools-Platform bietet zwar einen Assistenten für das Anlegen von Beans an, diese sind aber nach EJB-2.1-Standard aufgebaut und verwenden außerdem XDoclet zur Generierung der Deployment-Deskriptoren. Deshalb gehen wir hier zur Handarbeit über.
Schritt 1: In der J2EE-Hierarchie den Knoten "EJB Projects" \ "StatelessEJB" wählen. Rechtsklick, im Contextmenü den Punkt "New" -> "Class" wählen.
Stateless Session Bean
Schritt 2: Wir vergeben einen Namespace und einen Bean-Namen. Den Haken "Generate Comments" setzen wir natürlich.
Stateless Session Bean

Schritt 3: Vorbereiten der Business-Methoden:
Die beiden Business-Methoden werfen eine eigene Exception. Diese wird dem Projekt so zugefügt: Das Package "de.fhw.swtvertiefung.knauf.stateless" im Folder "StatelessEJB\ejbModule" im Projekt "StatelessEJB" auswählen. Rechtsklick, "New" -> "Class". Eine Klasse namens "InvalidParameterException" zufügen, die von "java.lang.Exception abgeleitet ist.

Schritt 4: Jetzt legen wir die Business-Methoden "computeCuboidVolume" und "computeCuboidSurface" in der GeometricModelBean an.
  public double computeCuboidVolume(double a, double b, double c) throws InvalidParameterException
  {
    logger.info("computeCuboidVolume with a = " + a + ", b = " + b + ", c = " + c);
    if (a <= 0 || b <= 0 || c <= 0)
      throw new InvalidParameterException("Side length <= 0");

    return a * b * c;
  }

  public double computeCuboidSurface(double a, double b, double c) throws InvalidParameterException
  {
    logger.info("computeCuboidSurface with a = " + a + ", b = " + b + ", c = " + c);
    if (a <= 0 || b <= 0 || c <= 0)
      throw new InvalidParameterException("Side length <= 0");

    return 2 * (a * b + b * c + c * a);
  } 


Schritt 5: Wir fügen das Local- und Remote-Interface der Bean zu. Dazu können wir uns die Refactoring-Möglichkeiten von Eclipse zu Nutze machen. Im Project Explorer die Bean-Klasse wählen, Rechtsklick, "Refactor", "Extract Interface..." wählen.
Refactor
Zuerst erzeugen wir das Remote Interface namens "GeometricModel". Wir wählen die zwei Methoden aus.
Refactor
Das gleiche wiederholen wir für das Local-Interface "GeometricModelLocal".

Schritt 6: Die Bean-Klasse soll diese beiden Interfaces implementieren und erhält außerdem die Annotation "Stateless".
@Stateless() 
public class GeometricModelBean implements GeometricModel, GeometricModelLocal
{
	... 
Das Remote-Interface bekommt die Annotation "Remote":
@Remote()
public interface GeometricModel
{
	... 
Das Local-Interface bekommt die Annotation "Local":
@Local()
public interface GeometricModelLocal
{
	... 


Anlegen des Webclients

Modul-Abhängigkeiten Zuerst müssen wir eine Referenz auf das EJB-Projekt zufügen, damit wir die Interfaces der Bean verwenden können: Auf "StatelessWeb" einen Rechtsklick ausführen und in die "Properties" gehen. Im Punkt "J2EE Module Dependencies" aktivieren wir die Referenz auf "StatelessEJB.jar".
J2EE Module Dependencies
JSP anlegen
Den Ordner "StatelessWeb" -> "WebContent" auswählen und per Rechtsklick eine JSP zufügen.
Neue JSP (1)
Im ersten Schritt des Assistenten der JSP den Namen "GeometricModelTest.jsp" geben.
Neue JSP (2)
In Schritt 2 verwenden wir das vorgeschlagene Template.
Neue JSP (3)
Jetzt noch auf "Finish" klicken und den JSP-Code einbauen. Der relevante Ausschnitt für den EJB-Zugriff sieht so aus:
  Object objGeometricModel = initialContext.lookup ("java:comp/env/ejb/GeometricModel");
  GeometricModel geometricModel = (GeometricModel) PortableRemoteObject.narrow(objGeometricModel, GeometricModel.class);
  
  double dblVolume = geometricModel.computeCuboidVolume( dblA, dblB, dblC);
  double dblSurface = geometricModel.computeCuboidSurface( dblA, dblB, dblC); 

EJB-Referenzen anlegen Obiger Codeausschnitt verwendet eine EJB-Referenz die im JNDI-Environment-Naming-Context (ENC) der Webanwendung abgelegt ist und auf die GeometricModelBean zeigt. Auf dem JBoss könnten wir die Bean zwar auch direkt über ihren JNDI-Namen ansprechen, aber das wäre unsauber.
Wir öffnen die Datei "StatelessWeb\WebContent\WEB-INF\web.xml" und fügen folgendes Stück nach dem Element "welcome-file-list" ein:
	<ejb-ref>
		<ejb-ref-name>ejb/GeometricModel</ejb-ref-name>
		<ejb-ref-type>Session</ejb-ref-type>
		<home>java.lang.Object</home>
		<remote>de.fhw.swtvertiefung.knauf.stateless.GeometricModel</remote>
	</ejb-ref>
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelLocal</ejb-ref-name>
		<ejb-ref-type>Session</ejb-ref-type>
		<local-home>java.lang.Object</local-home>
		<local>de.fhw.swtvertiefung.knauf.stateless.GeometricModelLocal</local>
	</ejb-local-ref> 
Wichtig ist dass wir ein "home"-Tag angeben, auch wenn Beans nach EJB3-Standard keine Home-Interfaces mehr kennen ! Der Grund ist dass JBoss ansonsten eine Fehlermeldung ausspuckt: "org.jboss.deployment.DeploymentException: Failed to parse WEB-INF/web.xml; - nested throwable: (org.jboss.deployment.DeploymentException: expected one local-home tag)". Das liegt wahrscheinlich daran dass der Web-Container noch auf J2EE-1.4-Stand ist.
Würden wir hier anderen Namen vergeben, könnten wir die EJB z.B. auch als "java:comp/env/ejb/EtwasKomplettAnderes" ansprechen.

Jetzt müssen wir noch den JBoss-spezifischen Teil der EJB-Referenz erzeugen (nämlich eine Verbindung zur tatsächlichen Bean im Container-JNDI). Dazu legen wir in "StatelessWeb\WEB-INF\" eine Datei "jboss-web.xml" an mit diesem Inhalt:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-web PUBLIC "-//JBoss//DTD Web Application 2.4//EN" "http://www.jboss.org/j2ee/dtd/jboss-web_4_0.dtd">
<jboss-web>
	<context-root>StatelessWeb</context-root>
	<ejb-ref>
		<ejb-ref-name>ejb/GeometricModel</ejb-ref-name>
		<jndi-name>Stateless/GeometricModelBean/remote</jndi-name>
	</ejb-ref>
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelLocal</ejb-ref-name>
		<local-jndi-name>Stateless/GeometricModelBean/local</local-jndi-name>
	</ejb-local-ref>
</jboss-web> 
Der Eintrag "context-root" legt fest unter welcher URL wir die Anwendung später auf dem Server erreichen. Im obigen Beispiel also "http://www.meinserver.de/StatelessWeb/meineWebseite.html".
Hier wird der Name der EJB-Referenz mit einem EJB-Namen des Containers verbunden. Woher "Stateless/GeometricModelBean/remote" kommt werden wir weiter unten sehen.

Anmerkung: Gemäß JavaEE5-Spezifikation sollte es möglich sein eine EJB-Referenz per Injection zu erhalten (durch diese Variablendeklaration: @EJB GeometricModel geometricModel;). Dies funktioniert beim JBoss allerdings nicht weil es einen Servlet-Spezifikation-2.5-kompatiblen Container benötigt, und dies ist unterstützt der zugrundeliegende Tomcat 5.5 nicht.


Servlet anlegen:
Wir gehen auf "Dynamic Web Projects" -> "StatelessWeb" und erstellen mit Rechtsklick -> "New" -> "Servlet" ein neues Servlet. Package und Name sollten so aussehen:
Neues Servlet (1)
In den restlichen Schritten belassen wir alles auf den Defaults.
Im nächsten Schritt wird eine URL angegeben unter der das Servlet später angesprochen werden soll. Ich habe den Default "/GeometricModelServlet" entfernt und durch "/servlet/GeometricModelServlet" ersetzt. Diese Angabe finden wir in "web.xml" wieder.
Neues Servlet (2)
In Schritt 3 belassen wir alles auf den Defaults.

Es wird dieser Eintrag in "web.xml" erzeugt:
	<servlet>
		<description>
		</description>
		<display-name>GeometricModelServlet</display-name>
		<servlet-name>GeometricModelServlet</servlet-name>
		<servlet-class>de.fhw.swtvertiefung.knauf.stateless.GeometricModelServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>GeometricModelServlet</servlet-name>
		<url-pattern>/servlet/GeometricModelServlet</url-pattern>
	</servlet-mapping> 
Im "Project Explorer" sieht das so aus:
Neues Servlet (4)


Server einrichten

Das Webprojekt auswählen, Rechtsklick -> "Run As..." -> "Run on Server" wählen. Im Assistenten wählen wir den JBoss-Server.
Server anlegen (1)
In Schritt 2 belassen wir die Defaults. In Schritt 3 sollte unsere Anwendung bereits ausgewählt sein.
Server anlegen (2)

Wir klicken auf "Finish". Die Enterprise Application wird auf den JBoss deployed und der Server wird gestartet.
Falls das ohne Fehlermeldungen klappt erscheint ein integriertes Browserfenster mit einem Verzeichnislisting der URL
http://localhost:8080/StatelessWeb/.
Warum hier die WAR-Datei auftaucht kann ich nicht erklären, es scheint sich um einen WebTools-Platform-Bug zu handeln.
Webclient testen
Wir wählen hier unsere Seite "GeometricModelTest.jsp" aus und können Berechnungen ausführen.
Den neu angelegten Server erreichen wir über die Karteikarte "Servers" im unteren Bereich der Anwendung. Nachdem wir die Anwendung jetzt zum ersten Mal deployed haben können wir sie in Zukunft nach einer Änderung aktualisieren indem wir den Server auswählen und im Contextmenü "Publish" wählen. Kurz nach einem Publish sollte auf der Karteikarte "Console", auf der die JBoss-Ausgabe landet, eine Ausgabe über ein Neu-Laden der Anwendung auftauchen.
Publish
Eine Anleitung wie das Logging für den JBoss zu konfigurieren ist findet sich hier.

Anlegen des Application Clients

Zuallererst einmal löschen wir die Klasse "Main.java" im Default-Package !

In der J2EE-Hierarchie "StatelessClient" auswählen. Rechtsklick, und dann "New" -> "Class" wählen.
Application Client, Schritt 1
Wie im Webclient muss hier eine Abhängigkeit zum EJB-Projekt definiert werden (Rechtsklick auf "StatelessClient", "Properties" wählen). Man wählt unter "J2EE Module Dependencies" das Bean-JAR aus.
Application Client, Schritt 2
Jetzt den Code einfügen. Da wir uns im Gegensatz zur Webanwendung hier selbst um die Initialisierung der Clients-Umgebung (und damit des JNDI) kümmern müssen, müssen wir die Verbindungsinfos zum JNDI (für das Bean-Lookup) selbst anlegen. Dazu verwenden wir folgendes Codestück:
      Properties props = new Properties();
      props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
      props.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming.client");
      props.setProperty(Context.PROVIDER_URL, "jnp://localhost:1099");
      props.setProperty("j2ee.clientName", "StatelessClient"); 

      InitialContext initialContext = new InitialContext(props);
      Object objRemote = initialContext.lookup("java:comp/env/ejb/GeometricModel");
      GeometricModel geometricModel = (GeometricModel) PortableRemoteObject.narrow(objRemote, GeometricModel.class); 
Wichtig ist hier dass wir die Property j2ee.clientName (scheint JBoss-spezifisch zu sein) auf den Namen des Projekts (bzw. auf den Wert des Elements display-name in "application-client.xml") setzen !

Die EJB-Referenzen müssen im Deployment-Deskriptor des Clients deklariert werden. Leider kann uns XDoclet hier nicht mehr helfen, wir müssen also selbst Hand anlegen. Dazu die Datei "application-client.xml" öffnen und folgendes einfügen:
	<ejb-ref>
		<ejb-ref-name>ejb/GeometricModel</ejb-ref-name>
		<ejb-ref-type>Session</ejb-ref-type>
		<home>java.lang.Object</home>
		<remote>de.fhw.swtvertiefung.knauf.stateless.GeometricModel</remote>
	</ejb-ref> 
Auch hier ist wieder wie im Webclient das sinnlose Item "home" nötig :-(.

Wie im Web-Projekt ist ein JBoss-spezifischer Deployment-Deskriptor nötig um die EJB-Referenz mit der Bean im Server-JNDI zu verbinden. Die Datei dazu heißt "jboss-client.xml" und sieht so aus:
	<?xml version="1.0" encoding="UTF-8"?>
	<!DOCTYPE jboss-client PUBLIC "-//JBoss//DTD Application Client 4.0//EN" "http://www.jboss.org/j2ee/dtd/jboss-client_4_0.dtd" >
	<jboss-client>
		<jndi-name>StatelessClient</jndi-name>
		<!-- Connect the declared EJB reference to the JNDI-Name of the EJB: -->
		<ejb-ref>
			<ejb-ref-name>ejb/GeometricModel</ejb-ref-name>
			<jndi-name>Stateless/GeometricModelBean/remote</jndi-name>
		</ejb-ref>
	</jboss-client> 

Jetzt noch die Klasse mit der "main"-Methode in "StatelessClient\appClientModule\META-INF\MANIFEST.MF" eintragen und nicht mal der J2EE-Verifier hat etwas zu meckern:
Manifest-Version: 1.0
Class-Path: StatelessEJB.jar
Main-Class: de.fhw.swtvertiefung.knauf.stateless.GeometricModel.Geometr
 icModelApplicationClient
Der Zeilenumbruch in der Zeile "Main-Class" gehört so, denn in einer Manifest-Datei darf eine Zeile maximal 72 Zeichen lang sein !

Ausführen des Application Clients

Manueller Start:
Sobald die komplette Enterprise Application auf den Server deployed wurde können wir die JAR-Datei des Application-Clients mit einem simplen Packprogramm klauen. Alternativ dazu finden wir sie im Verzeichnis ".metadata\.plugins\org.eclipse.wst.server.core\tmp0\Stateless" unseres Workspaces. Für die Interfaces unserer Bean benötigen wir außerdem die EJB-JAR-Datei "StatelessEJB.jar".

So sieht die Kommandozeile zum Start aus:
java -cp c:\...\jboss-4.0.4.GA\client\jbossall-client.jar;c:\...\jboss-4.0.4.GA\client\jboss-ejb3-client.jar; c:\...\jboss-4.0.4.GA\client\jboss-aop-jdk50-client.jar;c:\...\jboss-4.0.4.GA\client\jboss-aspect-jdk50-client.jar; StatelessEJB.jar;StatelessClient.jar de.fhw.swtvertiefung.knauf.stateless.GeometricModelApplicationClient

Wir benötigen hier insgesamt 4 weitere JBoss-Dateien.


Ausführen aus Eclipse heraus:
Wir wählen das Application-Client-Projekt aus und gehen im Menü "Run" auf "Run As...". Der Dialog für die diversen Launch-Konfigurationen öffnet sich. Wir wählen links den Punkt "Java Application" und fügen durch Klick auf "New" (der unscheinbare Button links in der Toolbarleiste oben). eine neue Konfiguration zu. Die Konfiguration bekommt den Namen "StatelessClient", als MainClass wird natürlich "com.knauf.ejb.stateless.GeometricModelApplicationClient" gewählt. Auf der Registerkarte "Classpath" finden wir auch die benötigten JBoss-Libraries wieder.
Application Client starten
Nach dem Klick auf "Run" läuft unsere Anwendung los, und wir sollten auf der JBoss-Konsole ein paar Ausgaben über die Bean-Methoden-Aufrufe sehen. Damit wir die Ausgabe unseres Clients sehen müssen wir die entsprechende Konsole auswählen (siehe Screenshot):
Application Client-Ausgabe


Export des Workspace

Um den kompletten Workspace so zu exportieren, dass er auf einem anderen Rechner wieder importiert werden kann, im Menü "File" den Punkt "Export..." wählen. Als "export destination" wählen wir "EAR file".
Export, Schritt 1
Im nächsten Schritt die zu exportierende EAR-Anwendung "Stateless" auswählen und eine Zieldatei für den Export angeben. Ich würde empfehlen diese Datei genauso zu benennen wie die EAR-Anwendung da der Dateiname beim Import als Vorschlag für die neu zu erstellen EAR-Anwendung verwendet wird.
Wichtig: den Haken bei "Export source files" setzen !
Export, Schritt 2
Fertig !


Re-Import:

Falls wir das zu importierende Projekt bereits im Workspace haben dann sollten wir es vorher löschen.
Im Menü "File" ruft man "Import..." auf. Man wählt wiederum die Quelle "EAR file".
Import, Schritt 1
Im nächsten Schritt wählt man die Quelldatei (unsere eben exportierte Zip-Datei), den Namen der Ziel-EAR-Anwendung ("Stateless"), und den eben angelegten Target-Server.
Import, Schritt 2
Unsere Anwendung verfügt über keine Hilfsprojekte, wir können den nächsten Schritt also ignorieren.
Import, Schritt 3
Im letzten Schritt wählen wir die gewünschten Module aus.
Import, Schritt 4


Außerdem müssen wir den EJB-Validator des EJB-Projekts wieder abschalten.


Ohne Annotations

Alle Annotations des JavaEE5-Standards lassen sich komplett durch Deployment-Deskriptoren ersetzen.
Die Datei "ejb-jar.xml" im EJB-Projekt muss so geändert werden:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar id="ejb-jar_ID" version="3.0"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd">
	<display-name>StatelessEJB</display-name>
	<enterprise-beans>
		<session>
			<description><![CDATA[This is the Stateless SessionBean "GeometricModel",
				which might be used for simple geometric calculations.]]>
			</description>
			<display-name>GeometricModelBean</display-name>
			<ejb-name>GeometricModelBean</ejb-name>
			<remote>de.fhw.swtvertiefung.knauf.stateless.GeometricModel</remote>
			<local>de.fhw.swtvertiefung.knauf.stateless.GeometricModelLocal</local>
			<ejb-class>de.fhw.swtvertiefung.knauf.stateless.GeometricModelBean</ejb-class>
			<session-type>Stateless</session-type>
		</session>
	</enterprise-beans>
</ejb-jar> 
Pflichtangaben gibt es eigentlich keine mehr, da alles durch Annotations gesteuert werden kann. Wird ein Element "session" eingefügt dann muss allerdings zumindest ein "ejb-name" angegeben werden.

Schieben wir das Projekt auf den JBoss scheint der intern die Annotations an die Klassen zu basteln (aus der Konsolenausgabe abzulesen):
19:22:43,718 WARN  [MainDeployer] Found non-jar deployer for StatelessEJB.jar: MBeanProxyExt[jboss.ejb3:service=EJB3Deployer]
19:22:43,828 INFO  [Ejb3DescriptorHandler] adding class annotation javax.ejb.Stateless to de.fhw.swtvertiefung.knauf.stateless.GeometricModelBean org.jboss.ejb.StatelessImpl@d38c3d
19:22:43,843 INFO  [Ejb3DescriptorHandler] adding class annotation javax.ejb.Remote to de.fhw.swtvertiefung.knauf.stateless.GeometricModelBean org.jboss.ejb.RemoteImpl@9c1f2c
19:22:43,843 INFO  [Ejb3DescriptorHandler] adding class annotation javax.ejb.Local to de.fhw.swtvertiefung.knauf.stateless.GeometricModelBean org.jboss.ejb.LocalImpl@1c28517 

Durch Angabe des "ejb-name" können wir steuern unter welchem Namen JBoss die Bean im Default ins JNDI hängt ("Stateless/GeometricModelBean/local" und "Stateless/GeometricModelBean/remote", fett markiert ist der "ejb-name"). Der Name der Bean-Klasse, also "GeometricModelBean", ist gleichzeitig der Default wenn kein EJB-Name angegeben ist.

Wollen wir mehr Kontrolle über den globalen JNDI-Namen dann können wir eine Datei "jboss.xml" ins EJB-Projekt hängen.
Beispiel:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss PUBLIC "-//JBoss//DTD JBOSS 4.0//EN" "http://www.jboss.org/j2ee/dtd/jboss_4_0.dtd">
<jboss>
	<enterprise-beans>
		<session>
			<ejb-name>GeometricModelBean</ejb-name>
			<jndi-name>Keks</jndi-name>
			<local-jndi-name>KeksLocal</local-jndi-name>
		</session>
	</enterprise-beans>
</jboss> 
Das führt zu dieser Ausgabe auf der JBoss-Konsole:
19:36:59,984 WARN  [MainDeployer] Found non-jar deployer for StatelessEJB.jar: MBeanProxyExt[jboss.ejb3:service=EJB3Deployer]
19:37:00,125 INFO  [Ejb3DescriptorHandler] adding class annotation javax.ejb.Stateless to de.fhw.swtvertiefung.knauf.stateless.GeometricModelBean org.jboss.ejb.StatelessImpl@c71c00
19:37:00,125 INFO  [Ejb3DescriptorHandler] adding class annotation javax.ejb.Remote to de.fhw.swtvertiefung.knauf.stateless.GeometricModelBean org.jboss.ejb.RemoteImpl@1ff8506
19:37:00,125 INFO  [Ejb3DescriptorHandler] adding class annotation javax.ejb.Local to de.fhw.swtvertiefung.knauf.stateless.GeometricModelBean org.jboss.ejb.LocalImpl@766ec3
19:37:00,125 INFO  [Ejb3DescriptorHandler] adding class annotation org.jboss.annotation.ejb.RemoteBinding to de.fhw.swtvertiefung.knauf.stateless.GeometricModelBean org.jboss.annotation.ejb.RemoteBindingImpl@161fcdd
19:37:00,125 INFO  [Ejb3DescriptorHandler] adding class annotation org.jboss.annotation.ejb.RemoteBinding to de.fhw.swtvertiefung.knauf.stateless.GeometricModelBean org.jboss.annotation.ejb.RemoteBindingImpl@161fcdd
19:37:00,125 INFO  [Ejb3DescriptorHandler] adding class annotation org.jboss.annotation.ejb.LocalBinding to de.fhw.swtvertiefung.knauf.stateless.GeometricModelBean org.jboss.annotation.ejb.LocalBindingImpl@20224a 
Es werden also noch zusätzliche Annotations angelegt. Der Meldung kann man übrigens entnehmen dass diese JNDI-Bindungen (die über keine Standard-JavaEE-Annotation realisierbar sind) durch eine JBoss-spezifische Annotation "org.jboss.annotation.ejb.RemoteBinding" realisierbar wären ! Damit würde unsere Bean allerdings endgültig die Containerunabhängigkeit verlassen, da der Code selbst ohne eine Chance auf Änderung an den JBoss getackert wäre.

Wichtig ist dass wir jetzt die EJB-Referenzen im Web- und ApplicationClient-Projekt anpassen, denn die Bean gibt es unter dem dort deklarierten Namen nicht mehr.
Beispiel für "jboss-client.xml" aus dem Application-Client-Projekt:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-client PUBLIC "-//JBoss//DTD Application Client 4.0//EN" "http://www.jboss.org/j2ee/dtd/jboss-client_4_0.dtd" >
<jboss-client>
	<jndi-name>StatelessClient</jndi-name>
	<ejb-ref>
		<ejb-ref-name>ejb/GeometricModel</ejb-ref-name>
		<jndi-name>Keks</jndi-name>
	</ejb-ref>
</jboss-client> 

Die JNDI-View liefert diese Ausgabe:
JNDI-View


Die modifizierte Version des Projekts (einschließlich des geänderten JNDI-Namens "Keks") gibt es hier:
StatelessNoAnnotation.ear.
ACHTUNG: Dieses Projekt kann nicht neben dem obigen Stateless-Beispiel existieren !
Auf Bean-Ebene wäre dies zwar problemlos möglich da die gleiche Bean-Klasse an unterschiedliche JNDI-Namen gebunden wird. Allerdings wird zweimal der gleiche Environment Naming Context für die Application Clients erzeugt, und das gibt beim Deploy eine Fehlermeldung.



Stand 18.10.2006
Historie:
03.09.2006: Erstellt
04.09.2006: Abschnitt "Ohne Annotations" zugefügt
07.09.2006: Anmerkung "Keine Resource Injection in Webanwendung".
13.09.2006: Verweis auf Eclipse-Bugs beim Re-Import entfernt
18.10.2006: Falsches "<ejb-link>"-Tag in "application-client.xml" des AppClients entfernt. Screenshot "Erzeugen einer Application (2)" angepaßt an aktuellen JBoss-Plugin.