Beispiel: Stateless Session Bean (JBoss 4.0)


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

Beispiel für eine Stateless Session Bean, auf die per Webclient und mittels Application Client zugegriffen wird.
Die Deployanleitung bezieht sich auf JBoss 4.0.3.
Hier gibt es das WebSphere-Projekt zum Download (dies ist ein Projektaustausch-Export, die Importanleitung findet man am Ende dieses Dokuments): Stateless.ear
ACHTUNG: Nach dem Import XDoclet-Builder im EJB- und im Web-Projekt aktivieren ! (siehe Importanleitung)

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-Server aus.
Erzeugen einer Application (Schritt 2)
Auf "Next" klicken.
Schritt 3: Facets konfigurieren: hier müssen wir nur sicherstellen dass als "EAR version" "1.4" gewählt ist.
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


Anlegen der StatelessBean

Schritt 1: In der J2EE-Hierarchie den Knoten "EJB Projects" \ "StatelessEJB" \ "StatelessEJB" \ "Session-Beans" wählen. Rechtsklick, im Contextmenü den Punkt "New" -> "Other..." wählen.
Stateless Session Bean, Step 1
Schritt 2: Eine Session-Bean zufügen:
Stateless Session Bean, Step 2
Stateless Session Bean, Step 3
Schritt 3: Wir vergeben einen Namespace und einen Bean-Namen.
Stateless Session Bean, Step 4
Schritt 4: Hier können wir alles auf den Defaults belassen.
Stateless Session Bean, Step 5
Schritt 5: Auch hier die Defaults:
Stateless Session Bean, Step 6
Nach dem Klick auf "Finish" tut erstmal XDoclet seine Arbeit und erzeugt die Bean-Implementationsklassen für uns.
Die J2EE-Hierarchie sieht jetzt so aus:
Stateless Session Bean, Step 7

Schritt 6: EJB-Referenzen vorbereiten:
Da wir auf die Bean vom ApplicationClient und vom WebClient aus zugreifen wollen müssen wir EJB-Referenzen erzeugen. Dazu folgende XDoclet-Tags in den Klassenkommentar einfügen:

 * @ejb.ejb-ref
 *   ejb-name="GeometricModel"
 *   view-type="local"
 *   name="ejb/GeometricModelLocal"
 * @ejb.ejb-ref
 *   ejb-name="GeometricModel"
 *   view-type="remote"
 *   name="ejb/GeometricModel"
Schritt 7: Vorbereiten der Business-Methoden:
Die beiden Business-Methoden werfen eine eigene Exception. Diese wird dem Projekt so zugefügt: Das Package "com.knauf.ejb.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.
InvalidParameterException
Schritt 8: Hinzufügen der Business-Methoden:
Die Bean-Klasse "GeometricModelBean" wird bearbeitet und zwei Methoden "computeCuboidVolume" und "computeCuboidSurface" zugefügt. Der Assistent hat uns bereits eine Methode "foo" deklariert, die wir überarbeiten.
Zu beachten: des XDoclet-Tag "@ejb.interface-method" wird so abgeändert dass der Viewtype auf "both" steht.

	/**
	 * 
	 * Berechen des Volumens eines Quaders.
	 * 
	 * @param a
	 *            Länge der Seite a, > 0
	 * @param b
	 *            Länge der Seite b, > 0
	 * @param c
	 *            Länge der Seite c, > 0
	 * @return Das Volumen des Quaders = a * b * c
	 * @exception InvalidParameterException
	 *                Falls a oder b oder c <= 0 ist.
	 * 
	 * <!-- begin-xdoclet-definition -->
	 * 
	 * @ejb.interface-method view-type="both" <!-- end-xdoclet-definition -->
	 * @generated
	 */
	public double computeCuboidVolume(double a, double b, double c)
			throws InvalidParameterException {
		logger.info("computeCuboidVolume mit a = " + a + ", b = " + b
				+ ", c = " + c);
		if (a <= 0 || b <= 0 || c <= 0)
			throw new InvalidParameterException("Seitenlänge <= 0");

		return a * b * c;
	}


Anlegen des Webclients

JSP anlegen
Den Ordner "Dynamic Web Projects" -> "StatelessWeb" -> "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 (die Fehler-Icons im Screenshot liegen nur daran dass keine Internetverbindung bestand und deshalb xml-Dateien nicht validiert wurden.
Neue JSP (2)
In Schritt 2 verwenden wir das vorgeschlagene Template.
Neue JSP (3)
Jetzt noch auf "Finish" klicken und den JSP-Code einbauen (was zu Compilefehlern führt weil die EJB-Klassen vom Compiler nicht gefunden werden). Beim JSP-Code die Unterschiede zu den anderen Beispielen beachten: wir verwenden hier direkt die vom Bean-Assistenten generierte Hilfsklasse "GeometricModelUtil" um an die Home-Interfaces der Beans zu gelangen.

Hinzufügen der Referenz auf das EJB, damit der Compiler arbeiten kann: Auf "Dynamic Web Projects" -> "StatelessWeb" einen Rechtsklick ausführen und in die "Properties" gehen. Im Punkt "Java JAR Dependencies" aktivieren wir die Referenz auf "StatelessEJB.jar".
Neue JSP (4)
ACHTUNG: Das folgende gilt nur wenn kein Servlet definiert wird !
Jetzt müssen wir noch eine Referenz auf die EJB anlegen. Auf dem JBoss könnten wir sie zwar auch direkt über ihren JNDI-Namen ansprechen, aber das wäre unsauber. Wir öffnen die Datei "Dynamic Web Projects" -> "StatelessWeb" -> "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>com.knauf.ejb.stateless.GeometricModelHome</home>
		<remote>com.knauf.ejb.stateless.GeometricModel</remote>
		<ejb-link>GeometricModel</ejb-link>
	</ejb-ref>
	<ejb-local-ref>
		<ejb-ref-name>ejb/GeometricModelLocal</ejb-ref-name>
		<ejb-ref-type>Session</ejb-ref-type>
		<local-home>com.knauf.ejb.stateless.GeometricModelLocalHome</local-home>
		<local>com.knauf.ejb.stateless.GeometricModelLocal</local>
		<ejb-link>GeometricModel</ejb-link>
	</ejb-local-ref>
Würden wir hier anderen Namen vergeben, könnten wir die EJB z.B. auch als "java:comp/env/ejb/EtwasKomplettAnderes" ansprechen.

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)
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.
Neues Servlet (3)
Damit sind wir fertig. Zu beachten sind die XDoclet-Einträge im Header des Servlets. Dies führt zu einem neuen XDoclet-Task "webdoclet", der die Dateien "web.xml" und "jboss-web.xml" befüllt. Das Ergebnis sieht so aus:
Neues Servlet (4)
Dieser "webdoclet"-Task scheint übrigens erst nach dem Hinzufügen des Servlets zugeschlagen zu haben. Nur mit der JSP-Seite hat die Anwendung und der Bean-Zugriff ebenfalls funktioniert, "web.xml" hätten wir aber per Hand editieren müssen.
Damit die EJB-Referenzen funktionieren müssen wir sie hier in den Klassenkopf des Servlets eintragen:

	 * @web.servlet
	 *   name="GeometricModelServlet"
	 *   display-name="GeometricModelServlet" 
	 *
	 * @web.servlet-mapping
	 *   url-pattern="/servlet/GeometricModelServlet "
	 * @web.ejb-ref
	 *   name="ejb/GeometricModel"
	 *   type="Session"
	 *   home="com.knauf.ejb.stateless.GeometricModelHome"
	 *   remote="com.knauf.ejb.stateless.GeometricModel"
	 *   link="GeometricModel"
	 * @web.ejb-local-ref
	 *   name="ejb/GeometricModelLocal"
	 *   type="Session"
	 *   home="com.knauf.ejb.stateless.GeometricModelLocalHome"
	 *   local="com.knauf.ejb.stateless.GeometricModelLocal" 
	 *   link="GeometricModel"
Das Ergebnis dieser Deklaration finden wir in "web.xml" wieder.

Server einrichten

Das Webprojekt auswählen ("Dynamic Web Projects" -> "StatelessWeb"), 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)
Dass links das Application Client Project auftaucht ist ein Bug (siehe hier:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=119584), es ist sowieso nicht wählbar.

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/. 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

In der J2EE-Hierarchie "Application Client Projects" \ "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" \ "J2EE Modules" das Bean-JAR aus.
Application Client, Schritt 2
Jetzt den Code einfügen. Da wir uns im Gegensatz zum SunAppServer und WebSphere hier selbst um die Initialisierung des Clients 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 homeref = initialContext.lookup(GeometricModelHome.COMP_NAME);
      GeometricModelHome geometricModelHome = (GeometricModelHome) PortableRemoteObject.narrow(homeref, GeometricModelHome.class);
      
      GeometricModel geometricModel = geometricModelHome.create();
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 Lookup-Methoden in der vom WTP-Plugin erzeugten Hilfsklasse "GeometricModelUtil" können wir leider nicht verwenden, da diese immer direkt den JNDI-Namen der Bean verwenden, statt über EJB-Referenzen zu gehen. Nur die Konstante GeometricModelHome.COMP_NAME können wir benutzen, diese hat nämlich den Wert java:comp/env/ejb/GeometricModel.

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>com.knauf.ejb.stateless.GeometricModelHome</home>
		<remote>com.knauf.ejb.stateless.GeometricModel</remote>
		<ejb-link>GeometricModel</ejb-link>
	</ejb-ref> 

Jetzt noch die Main class in "Application Client Projects" -> "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: com.knauf.ejb.stateless.GeometricModelApplicationClient


Ausführen des Application Clients

Manueller Start:
Zum Start benötigen wir folgenden Aufruf:
	java -cp C:\...\jboss-4.0.2\client\jbossall-client.jar;StatelessClient.jar com.knauf.ejb.stateless.GeometricModelApplicationClient
Zu beachten ist dass wir die Datei "jbossall-client.jar" aus dem Client-Verzeichnis der JBoss-Installation in den Classpath aufnehmen.


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" 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:

Man öffnet Eclipse und wählt beim Start am sichersten ein leeres Verzeichnis als Arbeitsbereich. Alternativ könnte man die bestehenden Projekte auch löschen und erspart sich damit die Konfiguration des Arbeitsbereichs (Anlegen des Servers).
Zuallererst einmal legen wir den Server wieder an (da der Arbeitsbereich ja uninitialisiert ist). Die Anleitung gibt es
hier.
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

Nachbearbeitung: Leider geht die Einstellung darüber verloren dass der XDoclet-Builder aktiviert war. Im Gegensatz zu WTP 0.7 müssen wir jetzt aber nichts mehr an der ".project"-Datei schrauben, sondern können dies über schöne bunte Dialoge erledigen.
Wir gehen in die Properties des EJB-Projekts und wählen "Project Facets" aus.
Project Facets (1)
Auf "Add/Remove Project Facets..." klicken. Wir setzen den Haken vor "EJBDoclet (XDoclet)":
Project Facets (2)
Dass der Builder jetzt aktiviert ist können wir in den Properties des Projekts nachprüfen (vorher muss der Properties-Dialog einmal mit OK geschlossen werden !):
XDoclet-Builder

Das gleiche müssen wir für das Web-Projekt wiederholen: hier muss eine "Project Facet" "WebDoclet (XDoclet)" zugefügt werden:
XDoclet-Builder



Version 1.1.0.0, Stand 29.12.2005
Historie:
1.0.0.0 (08.09.2005): Erstellt
1.0.1.0 (27.10.2005): Screenshot für JAR-Dependency an WPT 1.0M8 angepaßt. Import: Dokumentation der zu aktivierenden XDoclet-Builder.
1.0.1.1 (24.11.2005): Anleitung für Projekt-Erstellen war noch WTP 0.7.
1.0.2.0 (27.11.2005): Der Application Client verwendet EJB-Referenzen und jboss-client.xml
1.1.0.0 (29.12.2005): Angepaßt an WTP 1.0