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".
Schritt 2: In dem erscheinenden Dialog geben wir dem Projekt einen Namen und wählen den JBoss 4.0.5-Server aus.
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.
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.
Schritt 4: Zurück im Hauptdialog stellen wir sicher dass diese drei Module ausgewählt sind.
Man klickt auf "Finish" und hat folgende J2EE-Hierarchie angelegt:
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.
- application.xml
Den Deployment-Deskriptor der Enterprise Application öffnen. Er liegt im Pfad "Stateless\Earcontent\META-INF\application.xml".
Die Datei sieht so aus:
<?xml version="1.0" encoding="UTF-8"?>
<application id="Application_ID" version="1.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd">
...
</application>
Wir ändern die Datei so ab (fett sind die Änderungen):
<?xml version="1.0" encoding="UTF-8"?>
<application id="Application_ID" version="5"
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/application_5.xsd">
...
</application>
- ejb-jar.xml
Den Deployment-Deskriptor des EJB-Projekts öffnen. Er liegt im Pfad "StatelessEJB\ejbModule\META-INF\ejb-jar.xml".
Die Datei sieht so aus:
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar id="ejb-jar_ID" version="2.1"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd">
...
</ejb-jar>
Wir ändern die Datei so ab:
<?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">
...
</ejb-jar>
- application-client.xml
Den Deployment-Deskriptor des Application-Client-Projekts öffnen. Er liegt im Pfad "StatelessClient\appClientModule\META-INF\application-client.xml".
Die Datei sieht so aus:
<?xml version="1.0" encoding="UTF-8"?>
<application-client id="Application-client_ID" version="1.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application-client_1_4.xsd">
...
</application-client>
Wir ändern die Datei so ab:
<?xml version="1.0" encoding="UTF-8"?>
<application-client id="Application-client_ID" version="5"
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/application-client_5.xsd">
...
</application-client>
- web.xml
Den Deployment-Deskriptor des Web-Projekts öffnen. Er liegt im Pfad "StatelessWeb\WebContent\WEB-INF\web.xml".
Die Datei sieht so aus:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
...
</web-app>
Wir ändern die Datei so ab:
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.5"
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/web-app_2_5.xsd">
....
</web-app>
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.
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.
Schritt 2: Wir vergeben einen Namespace und einen Bean-Namen. Den Haken "Generate Comments" setzen wir natürlich.
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.
Zuerst erzeugen wir das Remote Interface namens "GeometricModel". Wir wählen die zwei Methoden aus.
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".
JSP anlegen
Den Ordner "StatelessWeb" -> "WebContent" auswählen und per Rechtsklick eine
JSP zufügen.
Im ersten Schritt des Assistenten der JSP den Namen "GeometricModelTest.jsp" geben.
In Schritt 2 verwenden wir das vorgeschlagene Template.
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:
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.
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:
Server einrichten
Das Webprojekt auswählen, Rechtsklick -> "Run As..." -> "Run on Server" wählen.
Im Assistenten wählen wir den JBoss-Server.
In Schritt 2 belassen wir die Defaults. In Schritt 3 sollte unsere Anwendung bereits ausgewählt sein.
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.
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.
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.
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.
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.
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):
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".
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 !
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".
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.
Unsere Anwendung verfügt über keine Hilfsprojekte, wir können den nächsten Schritt also ignorieren.
Im letzten Schritt wählen wir die gewünschten Module aus.
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:
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.