GlassFish 3.1 (und 2.1)

+ andere TechDocs
+ Java EE
+ EJB2
+ GlassFish
+


Java EE (Java Platform, Enterprise Edition) ist eine durch Schnittstellen definierte Architektur für Unternehmensanwendungen, bestehend aus verschiedenen Komponenten.

Java-EE-Anwendungen werden auf Java EE Application Servern betrieben. Bekannte Java EE Application Server sind zum Beispiel: GlassFish, JBoss, Oracle WebLogic, IBM WebSphere und Apache Geronimo.



Inhalt

  1. Installation des GlassFish 3.1 (oder 2.1) unter Windows
  2. Einrichtung einer Data Source zu einer MySQL-Datenbank
  3. Webanwendung mit Servlet, JSP, JavaBean und DB-Zugriff für GlassFish, WebLogic, JBoss und Geronimo
    Maven-Webapp-Projekt, MeinServlet.java, MeineJavaBean.java, index.jsp, HelloJSP.jsp, HelloJavaBean.jsp, HelloDB.jsp, web.xml, pom.xml, Projektstruktur, Build, Aufruf
  4. Webanwendung mit JSF und JPA für GlassFish 3.1 (oder 2.1) und WebLogic 10.3.4
    Maven-Webapp-Projekt, Kontakt.java, KontaktController.java, MeineValidatoren.java, KontaktEingabe.jsp, EingabeBestaetigung.jsp, EingabeFehler.jsp, MeineMessages_de.properties, web.xml, faces-config.xml, persistence.xml, pom.xml, Projektstruktur, Build, Aufruf, Besonderheiten
  5. Minimale EJB3-Anwendung (ohne Maven)
  6. Java EE mit EJB3 für GlassFish, WebLogic, JBoss und Geronimo
    JEE-Projektaufbau, EJB3-Unterprojekt, Web-Unterprojekt, EAR-Unterprojekt, JEE-Parent-POM, Projektstruktur, Aufruf der EJB3-Anwendung
  7. Rudimentärer InitialContextFactoryMock
  8. Weitere Beispielanwendungen
    JPA mit Servlets, JPA mit EJB 3, Automatisierter Integrationstest mit Cargo für JBoss, WebLogic und Tomcat, JNDI-Einträge anzeigen, EJB2-Anwendung mit ant, Webanwendung mit ant
  9. Links auf weiterführende Informationen


Installation des GlassFish 3.1 (oder 2.1) unter Windows

GlassFish 3.1

  1. Downloaden Sie GlassFish 3.1 von http://glassfish.java.net (z.B. glassfish-3.1-windows.exe).

  2. Führen Sie das downgeloadete Installationsprogramm aus und geben Sie als Zielverzeichnis zum Beispiel das Verzeichnis C:\GlassFish an.

GlassFish 2.1

  1. Downloaden Sie GlassFish 2.1 von http://glassfish.java.net (z.B. glassfish-installer-v2.1-b60e-windows.jar).

  2. Entpacken Sie die downgeloadete .jar-Archivdatei, zum Beispiel in das Verzeichnis C:\GlassFish:

    cd \GlassFish

    java -Xmx500M -jar glassfish-installer-v2.1-b60e-windows

  3. Im Installationsskript setup.xml (bzw. setup-cluster.xml, falls Sie ein Cluster installieren wollen) können Sie eventuell benötigte Änderungen vornehmen.
    Starten Sie die Installation:

    cd \GlassFish\glassfish

    ant -f setup.xml

GlassFish 3.1 oder 2.1

  1. Starten Sie GlassFish:

    cd \GlassFish\glassfish\bin

    asadmin start-domain domain1

    Warten Sie, bis "Successfully started the domain : domain1" oder "Domain domain1 is ready to receive client requests"erscheint.

  2. Überprüfen Sie die Funktion, zum Beispiel über:

    http://localhost:8080

    http://localhost:4848   (usr=admin, pwd=adminadmin)

  3. Stoppen Sie die GlassFish-Domain:

    cd \GlassFish\glassfish\bin

    asadmin stop-domain domain1

  4. Falls Sie weitere GlassFish-Domains einrichten oder bestehende löschen wollen, sehen Sie sich folgende Kommandos an:

    asadmin create-domain --help

    asadmin create-domain --portbase MeinePortBaseNummer MeinDomainName

    asadmin delete-domain MeinDomainName

    Wenn Sie mehrere Domains gleichzeitig betreiben wollen, müssen Sie unterschiedliche Ports konfigurieren. Statt jeden Port einzeln vorzugeben, wird über den Parameter --portbase MeinePortBaseNummer eine andere Port-Basis-Nummer vorgegeben (z.B. 9000).

  5. Die Defaultports der domain1 lauten:

    8080 HTTP
    8181 HTTPS
    4848  Administrationskonsole
    8686 JMX
    7676 JMS
    3700 IIOP
    3820 Secure IIOP
    3920 Mutual Authorization IIOP
  6. Sehen Sie sich die Logfile-Einträge an:

    C:/GlassFish/glassfish/domains/domain1/logs/server.log

  7. Sehen Sie sich die unter Links auf weiterführende Informationen aufgeführten Anleitungen und Hinweise an.



Einrichtung einer Data Source zu einer MySQL-Datenbank

MySQL

  1. Falls Sie noch keine MySQL-Datenbank installiert haben: Installieren Sie MySQL zum Beispiel wie beschrieben unter: mysql.htm#InstallationUnterWindows. Die folgende Beschreibung geht davon aus, dass Sie als Database-Name MeineDb wählen (CREATE DATABASE MeineDb;) (Alternativ können Sie auch die unten genannte Url anpassen).

  2. MySQL verwendet defaultmäßig die MyISAM-Engine, die aber keine Transaktionen unterstützt. Wenn Sie Transaktionsunterstützung wollen, können Sie die InnoDB-Engine verwenden: Öffnen Sie die zu MySQL gehörende my.ini- oder my.cnf-Datei, zum Beispiel in den Verzeichnissen /etc/mysql, C:\, C:\Windows oder C:\Programme\MySQL\MySQL Server 4.1. Stellen Sie sicher dass nicht skip-innodb gesetzt ist und kontrollieren Sie die anderen "InnoDB Specific options".

JDBC-Treiber

  1. Downloaden Sie den zur Datenbank passenden JDBC-Treiber, für MySQL zum Beispiel mysql-connector-java-5.1.16.zip. Entpacken Sie die .zip-Datei und kopieren Sie die darin enthaltene Treiberdatei mysql-connector-java-5.1.16-bin.jar in das zu Ihrem Application Server und Ihrerer Domain gehörende lib-Verzeichnis, zum Beispiel nach: C:\GlassFish\glassfish\domains\domain1\lib.

GlassFish JDBC Connection Pool

  1. Starten Sie GlassFish neu. Öffnen Sie die GlassFish-Administrationskonsole über:
    http://localhost:4848   (usr=admin, pwd=adminadmin).

  2. Öffnen Sie in der linken Spalte: 'Resources' | 'JDBC' | 'Connection Pools'. Klicken Sie im rechten Fenster auf den 'New...'-Button.

  3. Geben Sie ein:

    New JDBC Connection Pool (Step 1 of 2):
    Name:MeinConnectionPoolName
    Resource Type:javax.sql.DataSource
    Database Vendor:MySQL
    New JDBC Connection Pool (Step 2 of 2):
    Datasource Classname:com.mysql.jdbc.jdbc2.optional.MysqlDataSource
    Url:jdbc:mysql://192.168.178.32:3306/MeineDb
    User:root
    Password:mysqlpwd

    Die letzten drei Properties müssen Sie eventuell über 'Add Property' hinzufügen. Außerdem müssen Sie natürlich die eingetragenen Werte an Ihre Datenbank anpassen.

  4. Testen Sie die Verbindung. Öffnen Sie in der linken Spalte: 'Resources' | 'JDBC' | 'Connection Pools'. Klicken Sie im rechten Fenster auf 'MeinConnectionPoolName' und den 'Ping'-Button.

GlassFish JDBC DataSource

  1. Öffnen Sie in der linken Spalte: 'Resources' | 'JDBC' | 'JDBC Resources'. Klicken Sie im rechten Fenster auf den 'New...'-Button.

  2. Geben Sie ein:

    New JDBC Resource:
    JNDI Name:jdbc/MeinDatasourceJndiName
    Pool Name:MeinConnectionPoolName
    Status:Enabled


Webanwendung mit Servlet, JSP, JavaBean und DB-Zugriff für GlassFish, WebLogic, JBoss und Geronimo

  1. Um den Buildprozess möglichst einfach durchzuführen, wird im folgenden Programmierbeispiel Maven eingesetzt. Bitte installieren Sie Maven 3 wie beschrieben in: maven.htm#Installation.

  2. Sie können wahlweise die Sourcedateien als Zip-Archiv MeineJee5Apps.zip downloaden, oder, wie im Folgenden beschrieben, die Dateien selbst erstellen.

  3. Legen Sie ein Workspace-Verzeichnis an (z.B. D:\MeinWorkspace) und erzeugen Sie darin mit folgenden Kommandos ein Maven-Webapp-Projekt (falls Ihr Webbrowser einen Zeilenumbruch durchgeführt hat: auch das mvn-Kommando in einer einzigen Zeile):

    md \MeinWorkspace

    cd \MeinWorkspace

    mvn archetype:generate -DinteractiveMode=false -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=meineappgruppe -DartifactId=MeineJspApp

    cd MeineJspApp

    tree /F

  4. Ihr Projektverzeichnis sieht jetzt folgendermaßen aus:

    [\MeinWorkspace]
     `- [MeineJspApp]
         |- [src]
         |   `- [main]
         |       |- [resources]
         |       `- [webapp]
         |           |- [WEB-INF]
         |           |   `- web.xml
         |           `- index.jsp
         `- pom.xml
    
  5. Erweitern Sie Ihr Projektverzeichnis folgendermaßen um die Unterverzeichnisse java, meinjavabeanpkg und meinservletpkg:

    [\MeinWorkspace]
     `- [MeineJspApp]
         |- [src]
         |   `- [main]
         |       |- [java]
         |       |   |- [meinjavabeanpkg]
         |       |   `- [meinservletpkg]
         |       |- [resources]
         |       `- [webapp]
         |           |- [WEB-INF]
         |           |   `- web.xml
         |           `- index.jsp
         `- pom.xml
    
  6. Speichern Sie im Verzeichnis src\main\java\meinservletpkg die folgende Servlet-Datei MeinServlet.java:

    package meinservletpkg;
    
    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class MeinServlet extends HttpServlet
    {
      public void doGet( HttpServletRequest requ, HttpServletResponse resp )
      throws ServletException, IOException
      {
        resp.setContentType( "text/html" );
        PrintWriter out = resp.getWriter();
        out.println( "<html>" );
        out.println( "Hallo, mein erstes Servlet meldet sich." );
        out.println( "</html>" );
        out.close();
      }
    }
    
  7. Speichern Sie im Verzeichnis src\main\java\meinjavabeanpkg die folgende JavaBean-Datei MeineJavaBean.java:

    package meinjavabeanpkg;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class MeineJavaBean
    {
      public String getDateString()
      {
        return (new SimpleDateFormat("yyyy-MM-dd, HH:mm:ss")).format(new Date()) + " h";
      }
    }
    
  8. Ersetzen Sie im Verzeichnis src\main\webapp die Start-Index-Datei index.jsp durch folgenden Inhalt:

    <html>
    <head><title>Meine Start-Seite</title></head>
    <body>
    <h1>Meine Start-Seite (index.jsp)</h1>
    <p><a href="helloservlet">helloservlet</a></p>
    <p><a href="HelloJSP.jsp">HelloJSP.jsp</a></p>
    <p><a href="HelloJavaBean.jsp">HelloJavaBean.jsp</a></p>
    <p><a href="HelloDB.jsp">HelloDB.jsp</a></p>
    </body>
    </html>
    
  9. Speichern Sie im Verzeichnis src\main\webapp die folgende JSP-Datei HelloJSP.jsp:

    <%@ page import="java.text.SimpleDateFormat" %>
    <%@ page import="java.util.Date" %>
    
    <html>
    <head><title>Hello JSP</title></head>
    <body>
    <h2>Hallo, meine erste JSP-Seite meldet sich.</h2>
    <%= request.getRemoteHost() %>,
    <%= (new SimpleDateFormat("yyyy-MM-dd, HH:mm:ss")).format(new Date()) + " h" %>
    </body>
    </html>
    
  10. Speichern Sie im Verzeichnis src\main\webapp die folgende JSP-Datei HelloJavaBean.jsp:

    <%@ page import="meinjavabeanpkg.MeineJavaBean" %>
    
    <html>
    <head><title>Hello JavaBean</title></head>
    <body>
    <h2>Hallo, meine JSP-Seite mit JavaBean meldet sich.</h2>
    <%= request.getRemoteHost() %><br>
    <%
      MeineJavaBean jb = new MeineJavaBean();
      out.println( jb.getDateString() );
    %>
    </body>
    </html>
    

    Die hier gezeigte Variante der Einbindung der JavaBean ist nur der Einfachkeit halber gewählt.
    Alternativ werden JavaBeans mit "<jsp:useBean ...>" eingebunden, also z.B.:

    <jsp:useBean id="MeineBean" class="meinjavabeanpkg.MeineJavaBean" />

    Dann kann mit "<jsp:getProperty ...>" und "<jsp:setProperty ...>" auf die Bean-Getter und -Setter zugegriffen werden und es ergeben sich weitere Möglichkeiten zur Nutzung, z.B. die einfache Parameterübergabe aus HTML-Formularen in JavaBeans.

  11. Voraussetzung für die folgende JSP-Seite ist die Einrichtung einer DataSource im Java EE Application Server, zum Beispiel so wie beschrieben für GlassFish und Oracle WebLogic (ansonsten können Sie auf diese JSP-Seite auch verzichten).

    Speichern Sie im Verzeichnis src\main\webapp die folgende JSP-Datei HelloDB.jsp:

    <%@ page import="java.sql.*" %>
    <%@ page import="java.util.*" %>
    <%@ page import="javax.naming.*" %>
    <%@ page import="javax.sql.DataSource" %>
    <%@ page import="javax.transaction.*" %>
    
    <html>
    <head><title>Hello DB</title></head>
    <body>
    <h2>Hallo, meine JSP-Seite mit Datenbank-Zugriff meldet sich.</h2>
    <%
      Context    ctx = new InitialContext();
      DataSource ds  = (DataSource) ctx.lookup( "jdbc/MeinDatasourceJndiName" );
      Connection cn  = null;
      Statement  st  = null;
      ResultSet  rs  = null;
      try {
        cn = ds.getConnection();
        st = cn.createStatement();
        rs = st.executeQuery( "Select * from MeineTestTabelle" );
        if( rs.next() ) out.println( "Ergebnis: " + rs.getString( 1 ) + "<br>" );
        out.println( cn.getMetaData().getDatabaseProductName() + ", " );
        out.println( cn.getMetaData().getDatabaseProductVersion() + "<br>" );
      } finally {
        try { if( null != rs ) rs.close(); } catch( Exception ex ) {/*ok*/}
        try { if( null != st ) st.close(); } catch( Exception ex ) {/*ok*/}
        try { if( null != cn ) cn.close(); } catch( Exception ex ) {/*ok*/}
      }
    %>
    </body>
    </html>
    

    Passen Sie MeinDatasourceJndiName und MeineTestTabelle an Ihre DataSource an.

    Bitte beachten Sie, dass dieses Beispiel lediglich fundamentale Funktionen demonstrieren soll (z.B. den Lookup auf die DataSource). Normalerweise ist es keine gute Idee, in einer JSP direkt auf eine Datenbank zuzugreifen. Dies sollte nicht im Presentation Layer, sondern in einem tiefer liegenden Layer erfolgen. Außerdem empfiehlt es sich in der Regel, die Datenbank nicht direkt per JDBC, sondern über JPA anzusprechen.

  12. Ersetzen Sie im Verzeichnis src\main\webapp\WEB-INF die Webanwendungs-Konfigurations-Datei web.xml durch folgenden Inhalt:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC
      '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN'
      'http://java.sun.com/dtd/web-app_2_3.dtd'>
    <web-app>
      <display-name>Meine WebApp</display-name>
      <servlet>
        <servlet-name>MeinServletName</servlet-name>
        <servlet-class>meinservletpkg.MeinServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>MeinServletName</servlet-name>
        <url-pattern>/helloservlet</url-pattern>
      </servlet-mapping>
      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
    </web-app>
    
  13. Ersetzen Sie im <Projektverzeichnis> die Maven-Konfigurations-Datei pom.xml durch folgenden Inhalt:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>meineappgruppe</groupId>
      <artifactId>MeineJspApp</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
      <name>Meine JSP-App</name>
      <url>http://www.torsten-horn.de/techdocs</url>
      <build>
        <finalName>${project.artifactId}</finalName>
      </build>
      <dependencies>
        <dependency>
          <groupId>javaee</groupId>
          <artifactId>javaee-api</artifactId>
          <version>5</version>
          <scope>provided</scope>
        </dependency>
      </dependencies>
      <repositories>
        <repository>
          <id>maven2-repository.dev.java.net</id>
          <name>Java.net Maven 2 Repository</name>
          <url>http://download.java.net/maven/2</url>
        </repository>
      </repositories>
    </project>
    
  14. Ihr Projektverzeichnis muss jetzt so aussehen (überprüfen Sie es mit tree /F) (das target-Verzeichnis entsteht erst später):

    [\MeinWorkspace]
     `- [MeineJspApp]
         |- [src]
         |   `- [main]
         |       |- [java]
         |       |   |- [meinjavabeanpkg]
         |       |   |   `- MeineJavaBean.java
         |       |   `- [meinservletpkg]
         |       |       `- MeinServlet.java
         |       |- [resources]
         |       `- [webapp]
         |           |- [WEB-INF]
         |           |   `- web.xml
         |           |- HelloDB.jsp
         |           |- HelloJavaBean.jsp
         |           |- HelloJSP.jsp
         |           `- index.jsp
         |- [target]
         |   |- [classes]
         |   |   `- ...
         |   |- [MeineJspApp]
         |   |   `- ...
         |   |- [war]
         |   |   `- ...
         |   `- MeineJspApp.war
         `- pom.xml
    
  15. Erzeugen Sie mit "mvn package" die WAR-Datei und kopieren Sie diese in das zu Ihrem Java EE Application Server passende Autodeploy-Verzeichnis (oder deployen Sie auf anderem Wege, z.B. über die Webkonsole):

    cd \MeinWorkspace\MeineJspApp
    mvn package
    copy target\MeineJspApp.war C:\GlassFish\glassfish\domains\domain1\autodeploy [GlassFish]
    copy target\MeineJspApp.war C:\WebLogic\user_projects\domains\MeineDomain\autodeploy [Oracle WebLogic]
    copy target\MeineJspApp.war C:\JBoss\server\default\deploy [JBoss]
    copy target\MeineJspApp.war C:\Geronimo\deploy [Geronimo]

    (Alternativ können Sie statt des copy-Kommandos mit Hilfe des cargo-Plug-ins über "mvn cargo:deployer-deploy" deployen.)

  16. Testen Sie Ihre Webanwendung: Klicken Sie für die einzelnen Tests nacheinander auf die Links der Startseite:

    GlassFish 3.1 (oder 2.1): http://localhost:8080/MeineJspApp
    Oracle WebLogic 10.3.4: http://localhost:7001/MeineJspApp
    JBoss 5.1: http://localhost:8080/MeineJspApp
    Geronimo 2.1: http://localhost:8080/MeineJspApp
    Andere Java EE Application Server: Eventuell andere Portnummer einsetzen
  17. Falls Sie Fehler oder Probleme haben, schauen Sie sich zuerst die Logfile-Einträge an. Beispielsweise:

    GlassFish: C:\GlassFish\glassfish\domains\domain1\logs\server.log
    Oracle WebLogic: C:\WebLogic\user_projects\domains\MeineDomain\servers\AdminServer\logs\AdminServer.log
    JBoss: C:\JBoss\server\default\log\server.log
    Geronimo: C:\Geronimo\var\log\geronimo.log


Webanwendung mit JSF und JPA für GlassFish 3.1 (oder 2.1) und WebLogic 10.3.4

  1. Um den Buildprozess möglichst einfach durchzuführen, wird auch im folgenden Programmierbeispiel wieder Maven eingesetzt. Bitte installieren Sie Maven wie beschrieben in: maven.htm#Installation.

  2. Dieses Beispiel setzt eine installierte Datenbank und eine hierfür im Java EE Application Server unter dem JNDI-Namen "jdbc/MeinDatasourceJndiName" eingerichtete Datasource voraus (z.B. so wie für GlassFish und Oracle WebLogic beschrieben).

    Wenn Sie so wie weiter unten beschrieben in der persistence.xml die automatische Generierung der benötigten Tabellen aktivieren, brauchen Sie keine Tabelle manuell anzulegen. Andernfalls müssten Sie die Tabelle KONTAKTE und die Sequenztabelle für die Primary-Key-Generierung selbst anlegen.

  3. Sie können wahlweise die Sourcedateien als Zip-Archiv MeineJee5Apps.zip downloaden, oder, wie im Folgenden beschrieben, die Dateien selbst erstellen.

  4. Legen Sie ein Workspace-Verzeichnis an und erzeugen Sie darin mit folgenden Kommandos ein Maven-Webapp-Projekt (falls Ihr Webbrowser einen Zeilenumbruch durchgeführt hat: auch das mvn-Kommando in einer einzigen Zeile):

    md \MeinWorkspace

    cd \MeinWorkspace

    mvn archetype:generate -DinteractiveMode=false -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=meineappgruppe -DartifactId=MeineJsfJpaApp

    cd MeineJsfJpaApp

    tree /F

  5. Ihr Projektverzeichnis sieht jetzt folgendermaßen aus:

    [\MeinWorkspace]
     `- [MeineJsfJpaApp]
         |- [src]
         |   `- [main]
         |       |- [resources]
         |       `- [webapp]
         |           |- [WEB-INF]
         |           |   `- web.xml
         |           `- index.jsp
         `- pom.xml
    
  6. Erweitern Sie Ihr Projektverzeichnis folgendermaßen um die Unterverzeichnisse java, controller, entities, validators und META-INF:

    [\MeinWorkspace]
     `- [MeineJsfJpaApp]
         |- [src]
         |   `- [main]
         |       |- [java]
         |       |   |- [controller]
         |       |   |- [entities]
         |       |   `- [validators]
         |       |- [resources]
         |       |   `- [META-INF]
         |       `- [webapp]
         |           |- [WEB-INF]
         |           |   `- web.xml
         |           `- index.jsp
         `- pom.xml
    
  7. Speichern Sie im Verzeichnis src\main\java\entities die folgende Entity-Klasse Kontakt.java:

    package entities;
    
    import java.io.Serializable;
    import javax.persistence.*;
    
    @Entity
    @Table( name = "KONTAKTE" )
    public class Kontakt implements Serializable
    {
      private static final long serialVersionUID = 1L;
    
      @Id
      @GeneratedValue( strategy=GenerationType.AUTO )
      @Column( name = "KONTAKT_ID" )
      private Long kontaktId;
    
      private String vorname;
      private String nachname;
      private String email;
    
      public Long   getKontaktId() { return kontaktId; }
      public String getVorname()   { return vorname;   }
      public String getNachname()  { return nachname;  }
      public String getEmail()     { return email;     }
    
      public void setKontaktId( Long   kontaktId ) { this.kontaktId = kontaktId; }
      public void setVorname(   String vorname   ) { this.vorname   = vorname;   }
      public void setNachname(  String nachname  ) { this.nachname  = nachname;  }
      public void setEmail(     String email     ) { this.email     = email;     }
    }
    
  8. Speichern Sie im Verzeichnis src\main\java\controller die folgende Controller-Klasse KontaktController.java:

    package controller;
    
    import javax.annotation.Resource;
    import javax.persistence.*;
    import javax.transaction.UserTransaction;
    import entities.Kontakt;
    
    public class KontaktController
    {
      @PersistenceUnit( unitName = "kontaktPersistenceUnit" )
      private EntityManagerFactory entityManagerFactory;
    
      @Resource
      private UserTransaction userTransaction;
    
      private Kontakt kontakt;
    
      public String speichereKontakt()
      {
        EntityManager entityManager = entityManagerFactory.createEntityManager();
        try {
          userTransaction.begin();
          entityManager.persist( kontakt );
          userTransaction.commit();
          return "success";
        } catch( Exception ex ) {
          ex.printStackTrace();
          return "failure";
        }
      }
    
      public Kontakt getKontakt()
      {
        return kontakt;
      }
    
      public void setKontakt( Kontakt kontakt )
      {
        this.kontakt = kontakt;
      }
    }
    
  9. Speichern Sie im Verzeichnis src\main\java\validators die folgende Validatoren-Klasse MeineValidatoren.java:

    package validators;
    
    import javax.faces.application.FacesMessage;
    import javax.faces.component.UIComponent;
    import javax.faces.component.html.HtmlInputText;
    import javax.faces.context.FacesContext;
    import javax.faces.validator.ValidatorException;
    import org.apache.commons.lang.StringUtils;
    import org.apache.commons.validator.EmailValidator;
    
    public class MeineValidatoren
    {
      public void validiereAlpha(
          FacesContext facesContext, UIComponent uiComponent, Object value )
          throws ValidatorException
      {
        if( !StringUtils.isAlphaSpace( "" + value ) )
        {
          HtmlInputText htmlInputText = (HtmlInputText) uiComponent;
          FacesMessage  facesMessage = new FacesMessage(
              htmlInputText.getLabel() + ": Es sind nur alphabetische Zeichen erlaubt." );
          throw new ValidatorException( facesMessage );
        }
      }
    
      public void validiereEmail(
          FacesContext facesContext, UIComponent uiComponent, Object value )
          throws ValidatorException
      {
        if( !(EmailValidator.getInstance()).isValid( "" + value ) )
        {
          HtmlInputText htmlInputText = (HtmlInputText) uiComponent;
          FacesMessage  facesMessage = new FacesMessage(
              htmlInputText.getLabel() + ": Das E-Mail-Format ist ungueltig." );
          throw new ValidatorException( facesMessage );
        }
      }
    }
    
  10. Speichern Sie im Verzeichnis src\main\webapp die folgende JSF-Datei KontaktEingabe.jsp:

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
                          "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <style type="text/css">
      .linkeSpalte  { text-align: right; }
      .rechteSpalte { text-align: left;  }
    </style>
    <title>Speichere Kontakt</title>
    </head>
    <body>
    
    <h2>Speichere Kontakt:</h2>
    <f:view>
      <h:form>
        <h:messages style="color: red;"></h:messages>
        <h:panelGrid columns="2" columnClasses="linkeSpalte,rechteSpalte">
          <h:outputText value="Vorname:"></h:outputText>
          <h:inputText  label="Vorname" value="#{Kontakt.vorname}"
            required="true" validator="#{MeineValidatoren.validiereAlpha}">
            <f:validateLength minimum="2" maximum="25"></f:validateLength>
          </h:inputText>
          <h:outputText value="Nachname:"></h:outputText>
          <h:inputText  label="Nachname" value="#{Kontakt.nachname}"
            required="true" validator="#{MeineValidatoren.validiereAlpha}">
            <f:validateLength minimum="2" maximum="25"></f:validateLength>
          </h:inputText>
          <h:outputText value="Email:"></h:outputText>
          <h:inputText  label="Email" value="#{Kontakt.email}"
            validator="#{MeineValidatoren.validiereEmail}">
          </h:inputText>
          <h:panelGroup></h:panelGroup>
          <h:commandButton action="#{KontaktController.speichereKontakt}" value="Save"></h:commandButton>
        </h:panelGrid>
      </h:form>
    </f:view>
    
    </body>
    </html>
    
  11. Speichern Sie im Verzeichnis src\main\webapp die folgende JSF-Datei EingabeBestaetigung.jsp:

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
                          "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <style type="text/css">
      .linkeSpalte  { text-align: left; }
      .rechteSpalte { color: blue;  }
    </style>
    <title>Kontakt erfolgreich gespeichert</title>
    </head>
    <body>
    
    <h2>Die folgenden Kontaktdaten wurden erfolgreich in der Datenbank gespeichert:</h2>
    <f:view>
      <h:panelGrid columns="2" columnClasses="linkeSpalte,rechteSpalte">
        <h:outputText value="Kontakt-ID:"></h:outputText>
        <h:outputText value="#{Kontakt.kontaktId}"></h:outputText>
        <h:outputText value="Vorname:"></h:outputText>
        <h:outputText value="#{Kontakt.vorname}"></h:outputText>
        <h:outputText value="Nachname:"></h:outputText>
        <h:outputText value="#{Kontakt.nachname}"></h:outputText>
        <h:outputText value="Email:"></h:outputText>
        <h:outputText value="#{Kontakt.email}"></h:outputText>
      </h:panelGrid>
    </f:view>
    
    </body>
    </html>
    
  12. Speichern Sie im Verzeichnis src\main\webapp die folgende JSP-Datei EingabeFehler.jsp:

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
                          "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Fehler</title>
    </head>
    <body>
    
    <p>Beim Speicherversuch trat ein Fehler auf.</p>
    
    </body>
    </html>
    
  13. Speichern Sie im Verzeichnis src\main\resources die folgende Messages-Ressourcendatei MeineMessages_de.properties:

    javax.faces.validator.LengthValidator.MINIMUM={1}: Minimal erlaubte Länge ist ''{0}''
    javax.faces.validator.LengthValidator.MAXIMUM={1}: Maximal erlaubte Länge ist ''{0}''
    

    Auf diese Art können Sie einzelne oder alle Default-Fehlermeldungen durch eigene ersetzen und/oder lokalisieren.

  14. Ersetzen Sie im Verzeichnis src\main\webapp\WEB-INF die Webanwendungs-Konfigurations-Datei web.xml durch folgenden Inhalt:

    <web-app 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">
    
      <display-name>Meine JSF/JPA-Webanwendung</display-name>
    
      <context-param>
        <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
        <param-value>client</param-value>
      </context-param>
    
      <servlet>
        <display-name>FacesServlet</display-name>
        <servlet-name>FacesServlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
      </servlet>
    
      <servlet-mapping>
        <servlet-name>FacesServlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
      </servlet-mapping>
      <servlet-mapping>
        <servlet-name>FacesServlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
      </servlet-mapping>
    
    </web-app>
    
  15. Speichern Sie im Verzeichnis src\main\webapp\WEB-INF die folgende JSF-XML-Datei faces-config.xml:

    <faces-config 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-facesconfig_1_2.xsd"
      version="1.2">
    
      <application>
        <message-bundle>MeineMessages</message-bundle>
      </application>
    
      <managed-bean>
        <managed-bean-name>KontaktController</managed-bean-name>
        <managed-bean-class>controller.KontaktController</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
        <managed-property>
          <property-name>kontakt</property-name>
          <property-class>entities.Kontakt</property-class>
          <value>#{Kontakt}</value>
        </managed-property>
      </managed-bean>
      <managed-bean>
        <managed-bean-name>Kontakt</managed-bean-name>
        <managed-bean-class>entities.Kontakt</managed-bean-class>
        <managed-bean-scope>request</managed-bean-scope>
      </managed-bean>
      <managed-bean>
        <managed-bean-name>MeineValidatoren</managed-bean-name>
        <managed-bean-class>validators.MeineValidatoren</managed-bean-class>
        <managed-bean-scope>application</managed-bean-scope>
      </managed-bean>
    
      <navigation-rule>
        <from-view-id>/KontaktEingabe.jsp</from-view-id>
        <navigation-case>
          <from-outcome>success</from-outcome>
          <to-view-id>/EingabeBestaetigung.jsp</to-view-id>
        </navigation-case>
        <navigation-case>
          <from-outcome>failure</from-outcome>
          <to-view-id>/EingabeFehler.jsp</to-view-id>
        </navigation-case>
      </navigation-rule>
    
    </faces-config>
    
  16. Speichern Sie im Verzeichnis src\main\resources\META-INF die folgende JPA-XML-Datei persistence.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="1.0"
        xmlns="http://java.sun.com/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
                            http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
      <persistence-unit name="kontaktPersistenceUnit" transaction-type="JTA">
        <jta-data-source>jdbc/MeinDatasourceJndiName</jta-data-source>
        <properties>
          <property name="toplink.ddl-generation" value="create-tables"/>
          <property name="hibernate.hbm2ddl.auto" value="create"/>
          <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
        </properties>
      </persistence-unit>
    </persistence>
    

    Die drei <property.../>-Zeilen können Sie weglassen, wenn Sie keine automatische Anlage der benötigten Datenbanktabelle wünschen. Wenn Sie eine automatische Tabellengenerierung wünschen, benötigen Sie nur eine dieser <property.../>-Zeilen, nämlich die zu Ihrem JPA-Manager passende. Im Beispiel sind für TopLink Essentials, JBoss Hibernate und OpenJPA / OpenEJB geeignete gezeigt.

  17. Ersetzen Sie im Verzeichnis <Projektverzeichnis> die Maven-Projektbeschreibungsdatei pom.xml durch folgenden Inhalt:

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>meineappgruppe</groupId>
      <artifactId>MeineJsfJpaApp</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
      <name>Meine JSF/JPA-App</name>
      <url>http://www.torsten-horn.de/techdocs</url>
      <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </plugin>
        </plugins>
      </build>
      <dependencies>
        <dependency>
          <groupId>javaee</groupId>
          <artifactId>javaee-api</artifactId>
          <version>5</version>
          <scope>provided</scope>
        </dependency>
        <dependency>
          <groupId>commons-lang</groupId>
          <artifactId>commons-lang</artifactId>
          <version>[2.0,)</version>
        </dependency>
        <dependency>
          <groupId>commons-validator</groupId>
          <artifactId>commons-validator</artifactId>
          <version>[1.3.0,)</version>
        </dependency>
      </dependencies>
      <repositories>
        <repository>
          <id>maven2-repository.dev.java.net</id>
          <name>Java.net Maven 2 Repository</name>
          <url>http://download.java.net/maven/2</url>
        </repository>
      </repositories>
    </project>
    
  18. Falls Sie WebLogic 10.3.4 einsetzen:
    Entpacken Sie die jsf-1.2.war aus dem C:\WebLogic\wlserver_10.3\common\deployable-libraries-Verzeichnis in ein temporäres Verzeichnis.
    Erzeugen Sie im src\main\webapp\WEB-INF-Verzeichnis das Unterverzeichnis lib und kopieren Sie dorthinein die vier .jar-Libs glassfish.jsf_1.0.0.0_1-2-15.jar, glassfish.jstl_1.2.0.1.jar, javax.jsf_1.1.0.0_1-2.jar (oder javax.jsf_1.2.0.1.jar) und wls.jsf.di.jar aus dem WEB-INF\lib-Verzeichnis der entpackten jsf-1.2.war.

  19. Ihr Projektverzeichnis muss jetzt so aussehen (überprüfen Sie es mit tree /F) (das target-Verzeichnis entsteht erst später):

    [\MeinWorkspace]
     `- [MeineJsfJpaApp]
         |- [src]
         |   `- [main]
         |       |- [java]
         |       |   |- [controller]
         |       |   |   `- KontaktController.java
         |       |   |- [entities]
         |       |   |   `- Kontakt.java
         |       |   `- [validators]
         |       |       `- MeineValidatoren.java
         |       |- [resources]
         |       |   |- [META-INF]
         |       |   |   `- persistence.xml
         |       |   `- MeineMessages_de.properties
         |       `- [webapp]
         |           |- [WEB-INF]
         |           |   |- [lib]
         |           |   |   |- glassfish.jsf_1.0.0.0_1-2-15.jar  [falls WebLogic]
         |           |   |   |- glassfish.jstl_1.2.0.1.jar        [falls WebLogic]
         |           |   |   |- javax.jsf_1.1.0.0_1-2.jar         [falls WebLogic]
         |           |   |   `- wls.jsf.di.jar                    [falls WebLogic]
         |           |   |- faces-config.xml
         |           |   `- web.xml
         |           |- EingabeBestaetigung.jsp
         |           |- EingabeFehler.jsp
         |           `- KontaktEingabe.jsp
         |- [target]
         |   |- [classes]
         |   |   `- ...
         |   |- [MeineJsfJpaApp]
         |   |   `- ...
         |   |- [war]
         |   |   `- ...
         |   `- MeineJsfJpaApp.war
         `- pom.xml
    
  20. Erzeugen Sie mit "mvn package" die WAR-Datei und kopieren Sie diese in das zu Ihrem Java EE Application Server passende Autodeploy-Verzeichnis (oder deployen Sie auf anderem Wege, z.B. über die Webkonsole):

    cd \MeinWorkspace\MeineJsfJpaApp
    mvn clean package
    copy target\MeineJsfJpaApp.war C:\GlassFish\glassfish\domains\domain1\autodeploy [GlassFish]
    copy target\MeineJsfJpaApp.war C:\WebLogic\user_projects\domains\MeineDomain\autodeploy [Oracle WebLogic]
  21. Falls Sie GlassFish verwenden:
    Beobachten Sie, dass GlassFish nach einigen Sekunden nach erfolgreichem Deployment als Bestätigung die Datei MeineJsfJpaApp.war_deployed anlegt:

    dir C:\GlassFish\glassfish\domains\domain1\autodeploy

  22. Starten Sie die Webanwendung:

    GlassFish: http://localhost:8080/MeineJsfJpaApp/KontaktEingabe.jsf
    Oracle WebLogic: http://localhost:7001/MeineJsfJpaApp/KontaktEingabe.jsf
  23. Testen Sie die Fehlermeldungen bei ungültigen Eingaben:
    - Fehlender Vor- oder Nachname
    - Vor- oder Nachname zu kurz oder zu lang
    - Vor- oder Nachname mit anderen als alphabetischen Zeichen (leider ist das Demobeispiel etwas fehlerhaft: Deutsche Umlaute werden nicht akzeptiert)
    - Ungültige Email-Adresse
    - Schalten Sie während des Betriebs die Datenbank ab, um die EingabeFehler.jsp-Seite zu sehen.

  24. Beachten Sie folgende Besonderheiten:

    Obwohl in der faces-config.xml als message-bundle-Name "MeineMessages" eingetragen ist, wird die lokalisierte Datei MeineMessages_de.properties gefunden und verwendet.
    Im Beispiel enthält diese Datei nicht alle Meldungen, sondern überschreibt nur einige.
    Wenn Sie weitere Dateien in anderen Sprachen und anderen _..-Länderkürzeln anlegen, können Sie im Webbrowser die Sprache umschalten.

    Die Zeile "@GeneratedValue(strategy=GenerationType.AUTO)" in der Kontakt.java-Entity-Klasse sorgt dafür, dass beim Speichern automatisch eine Primary-Key-ID generiert wird. Das entityManager.persist()-Kommando füllt das Attribut kontaktId im kontakt-Java-Objekt mit der generierten ID.

    Obwohl Sie keine Datei mit der Endung .jsf angelegt haben (sondern nur .jsp-Dateien), müssen Sie in der Webbrowser-URL .jsf als Endung eingeben.

  25. Falls Sie Probleme haben oder auf Fehler stoßen, schauen Sie sich zuerst die Logfile-Einträge an. Zum Beispiel für GlassFish und WebLogic unter:

    C:/GlassFish/glassfish/domains/domain1/logs

    C:/WebLogic/user_projects/domains/MeineDomain/servers/AdminServer/logs

  26. Falls Sie Fehlermeldungen ähnlich zu "There was a failure when processing annotations" oder "java.lang.ClassNotFoundException: javax.faces.webapp.FacesServlet" erhalten: Dann fehlen .jar-Libs im src\main\webapp\WEB-INF\lib-Verzeichnis. GlassFish 3.1 (oder 2.1) benötigt keine zusätzlchen .jar-Libs, aber zum Beispiel WebLogic 10.3.4 benötigt die oben genannten.

  27. Falls Sie eine Fehlermeldung ähnlich zu "java.lang.RuntimeException: Cannot find FacesContext" erhalten, müssen Sie die im Webbrowser aufgerufene URL so ändern, dass Sie einem der in der src\main\webapp\WEB-INF\web.xml unter <servlet-mapping> für <servlet-name>FacesServlet</servlet-name> eingetragenen <url-pattern> entspricht (üblich sind z.B. "*.jsf" oder "/faces/*").

  28. Falls Sie die Fehlermeldung "javax.faces.application.ViewExpiredException: viewId:/KontaktEingabe.jsf - View /KontaktEingabe.jsf could not be restored." erhalten: Versuchen Sie verschiedene Einstellungen beim javax.faces.STATE_SAVING_METHOD-Parameter im <context-param>-Block in der src\main\webapp\WEB-INF\web.xml.

  29. Falls Sie andere Java EE Application Server einsetzen wollen, müssen Sie eventuell weitere Maßnahmen ergreifen, um JSF und JPA zu aktivieren. Eventuell sind zusätzliche oder andere Konfigurationen, .xml-Dateien und .jar-Libraries notwendig.



Minimale EJB3-Anwendung (ohne Maven)

Das folgende Beispiel zeigt zu Lern- und Demonstrationszwecken, wie Sie ohne Maven eine minimale EJB3-Anwendung inklusive Servlet- und externem Stand-alone-Client erzeugen können (im Beispiel für GlassFish, aber auch an anderer App-Server anpassbar). Allerdings ist für ernsthafte Projekte unbedingt ein Build-Tool wie Maven zu bevorzugen, wie es das MeineEjb3App-Beispiel zeigt.

  1. Installieren Sie GlassFish wie oben beschrieben.

  2. Legen Sie folgende Verzeichnisstruktur an:

    [\MeinWorkspace\MeineEjb3OhneMaven]
     |- [src]
     |   '- [meinpkg]
     '- [web]
         '- [WEB-INF]
    
  3. Erzeugen Sie im src\meinpkg-Verzeichnis folgende Java-Klassen:

    EjbIntf.java

    package meinpkg;
    
    @javax.ejb.Remote
    public interface EjbIntf
    {
       public String echo( String s );
    }
    

    EjbImpl.java

    package meinpkg;
    
    @javax.ejb.Stateless
    public class EjbImpl implements EjbIntf
    {
       public String echo( String s ) {
          return s;
       }
    }
    

    MeinClient.java

    package meinpkg;
    
    import javax.naming.InitialContext;
    
    public class MeinClient
    {
       public static void main( String[] args ) throws Exception {
          EjbIntf meineEJB = (EjbIntf) (new InitialContext()).lookup( EjbIntf.class.getName() );
          System.out.println( meineEJB.echo( "Hallo " + ((args.length > 0) ? args[0] : "Welt") ) );
       }
    }
    

    MeinEjbServlet.java

    package meinpkg;
    
    import java.io.*;
    import javax.servlet.ServletException;
    import javax.servlet.http.*;
    
    public class MeinEjbServlet extends HttpServlet
    {
       @javax.ejb.EJB
       private EjbIntf meineEJB;
    
       @Override
       public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
          response.setContentType( "text/html; charset=ISO-8859-1" );
          PrintWriter out = response.getWriter();
          String      name = request.getParameter( "name" );
          String      result = meineEJB.echo( "Hallo " + ((name != null) ? name : "Welt") );
          out.println( "<html>\n" +
                       "<head><title>MeinEjbServlet</title></head>\n" +
                       "<body><h2>" + result + "</h2></body>\n" +
                       "</html>\n" );
       }
    }
    
  4. Erzeugen Sie im web\WEB-INF-Verzeichnis folgende web.xml-Datei:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app 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">
      <servlet>
        <servlet-name>MeinEjbServlet</servlet-name>
        <servlet-class>meinpkg.MeinEjbServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>MeinEjbServlet</servlet-name>
        <url-pattern>/MeinEjbServlet</url-pattern>
      </servlet-mapping>
    </web-app>
    
  5. Erzeugen Sie im Projekt-Root-Verzeichnis folgende run.bat-Batchdatei (passen Sie die Pfade an):

    set APPSRV_HOME=C:\GlassFish\glassfish
    set APPSRV_AUTODEPLOY=%APPSRV_HOME%\domains\domain1\autodeploy
    set APPSRV_RT_JAR=%APPSRV_HOME%\lib\appserv-rt.jar
    set JAVAEE_JAR=%APPSRV_HOME%\lib\javaee.jar
    
    rd bin /S /Q
    md bin
    javac -cp bin;%JAVAEE_JAR% -d bin src\meinpkg\*.java
    cd bin
    jar cvf %APPSRV_AUTODEPLOY%\simple-ejb.jar meinpkg\EjbImpl.class meinpkg\EjbIntf.class
    cd ..
    
    rd web\WEB-INF\classes /S /Q
    xcopy bin\meinpkg\*Intf.*    web\WEB-INF\classes\meinpkg\ /Y
    xcopy bin\meinpkg\*Servlet.* web\WEB-INF\classes\meinpkg\ /Y
    cd web
    jar cvf %APPSRV_AUTODEPLOY%\simple-web.war *.*
    cd ..
    
    tree /F
    dir %APPSRV_AUTODEPLOY%
    pause ... Einen Moment warten, bis Deployment fertig ist ...
    dir %APPSRV_AUTODEPLOY%
    @echo.
    java -cp bin;%JAVAEE_JAR%;%APPSRV_RT_JAR% meinpkg.MeinClient _Mein_Name_
    @echo.
    start http://localhost:8080/simple-web/MeinEjbServlet?name=_Mein_Name_
    
  6. Ihre Verzeichnisstruktur sieht jetzt so aus:

    [\MeinWorkspace\MeineEjb3OhneMaven]
     |- [src]
     |   '- [meinpkg]
     |       |- EjbImpl.java
     |       |- EjbIntf.java
     |       |- MeinClient.java
     |       '- MeinEjbServlet.java
     |- [web]
     |   '- [WEB-INF]
     |       '- web.xml
     '- run.bat
    
  7. Starten Sie den Server, führen Sie die Build-Batchdatei aus und tragen Sie statt _Mein_Name_ Ihren Namen ein:

    GlassFish: 

    call C:\GlassFish\glassfish\bin\asadmin start-domain domain1

    Build + Run: 

    cd \MeinWorkspace\MeineEjb3OhneMaven

    run.bat

    Ext. Client: 

    java -cp bin;%JAVAEE_JAR%;%APPSRV_RT_JAR% meinpkg.MeinClient _Mein_Name_

    Web-Client: 

    start http://localhost:8080/simple-web/MeinEjbServlet?name=_Mein_Name_

  8. Falls Sie auf Probleme stoßen, sehen Sie sich die GlassFish-Logdatei C:\GlassFish\glassfish\domains\domain1\logs\server.log an.

  9. Unter java-jpa.htm#JpaEjb finden Sie ein Programmierbeispiel, welches das hier gezeigte um Persistenz mit JPA erweitert.



Java EE mit EJB3 für GlassFish, WebLogic, JBoss und Geronimo

JEE-Projektaufbau

Java-Enterprise-Edition-Projekte bestehen meistens aus Projekten verschiedener Typen, typischerweise:

Das folgende Beispiel geht von einem installierten Java EE 5 Application Server aus (Installationsbeschreibungen siehe z.B. GlassFish, JBoss, WebLogic, Geronimo).

Um den Buildprozess möglichst einfach durchzuführen, wird auch im folgenden Programmierbeispiel wieder Maven eingesetzt. Bitte installieren Sie Maven wie beschrieben in: maven.htm#Installation.

Sie können wahlweise die Sourcedateien als Zip-Archiv MeineJee5Apps.zip downloaden, oder, wie im Folgenden beschrieben, die Dateien selbst erstellen.

JEE-Parent-Projektverzeichnis

  1. Erstellen Sie in Ihrem Projekte-Verzeichnis (z.B. D:\MeinWorkspace) für das neue Multimodulprojekt das neue Parent-Verzeichnis MeineEjb3App:

    cd \MeinWorkspace

    md MeineEjb3App

    cd MeineEjb3App

    Legen Sie vorläufig in diesem Verzeichnis noch keine pom.xml an, damit die folgenden "mvn archetype:generate ..."-Kommandos nicht durcheinander geraten.

EJB3-Unterprojekt

  1. Erzeugen Sie im neuen MeineEjb3App-Verzeichnis ein neues Maven-Unterprojekt:

    cd \MeinWorkspace\MeineEjb3App

    mvn archetype:generate -DinteractiveMode=false -DgroupId=de.meinefirma.meinprojekt -DartifactId=EjbProj

    cd \MeinWorkspace\MeineEjb3App\EjbProj

    tree /F

  2. Ersetzen Sie im MeineEjb3App\EjbProj-Verzeichnis den Inhalt der pom.xml durch:

    <project>
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <groupId>de.meinefirma.meinprojekt</groupId>
        <artifactId>MeineEjb3App</artifactId>
        <version>1.0-SNAPSHOT</version>
      </parent>
      <!-- EjbProj ohne <groupId> und <version>: Wird von <parent> uebernommen: -->
      <artifactId>EjbProj</artifactId>
      <packaging>ejb</packaging>
      <name>EjbProj</name>
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-ejb-plugin</artifactId>
            <version>2.3</version>
            <configuration>
              <archive>
                <manifest>
                  <addClasspath>true</addClasspath>
                </manifest>
              </archive>
              <ejbVersion>3.0</ejbVersion>
              <generateClient>true</generateClient>
            </configuration>
          </plugin>
        </plugins>
      </build>
      <dependencies>  
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.8.2</version>
          <scope>test</scope>
        </dependency>
      </dependencies>
    </project>
    
  3. Löschen Sie im MeineEjb3App\EjbProj\src\main\java\de\meinefirma\meinprojekt-Verzeichnis die App.java und legen Sie stattdessen folgende drei Klassen an:

    MyEjbIntf.java:

    package de.meinefirma.meinprojekt;
    
    @javax.ejb.Remote
    public interface MyEjbIntf
    {
       public String berechne( String d1, String d2 );
    }
    

    MyEjbImpl.java:

    package de.meinefirma.meinprojekt;
    
    @javax.ejb.Stateless( mappedName = "MyEjb" )
    public class MyEjbImpl implements MyEjbIntf
    {
       public String berechne( String d1, String d2 )
       {
          try {
             return "" + (Double.parseDouble( d1 ) + Double.parseDouble( d2 ));
          } catch( Exception ex ) {
             return "";
          }
       }
    }
    

    MyEjbClient.java:

    package de.meinefirma.meinprojekt;
    
    import javax.naming.*;
    
    public class MyEjbClient
    {
       public static void main( String[] args ) throws Exception
       {
          System.out.println( "\n" + execute( args ) );
       }
    
       public static String execute( String[] args ) throws Exception
       {
          if( args.length < 2 )
             return "Bitte zwei Zahlen uebergeben (eventuell zusaetzlich den Context.lookup()-String).";
          // Context.lookup()-String fuer EJB ist leider App-Server-spezifisch:
          String    ejbJndiName = ( args.length > 2 ) ? args[2] : ("MyEjb#" + MyEjbIntf.class.getName());
          Context   ctx = new InitialContext();
          MyEjbIntf meineEJB = (MyEjbIntf) ctx.lookup( ejbJndiName );
          return "MyEjbIntf.berechne( " + args[0] + ", " + args[1] + " ) = " +
                   meineEJB.berechne( args[0], args[1] );
       }
    }
    

    Bitte beachten Sie, dass der Client natürlich normalerweise in einem eigenen Projekt beheimatet sein müsste und hier nur der Einfachheit halber im EJB-Projekt liegt.

  4. Löschen Sie im MeineEjb3App\EjbProj\src\test\java\de\meinefirma\meinprojekt-Verzeichnis die AppTest.java und legen Sie stattdessen folgende MyEjbTest.java an:

    package de.meinefirma.meinprojekt;
    
    import static org.junit.Assert.assertEquals;
    import org.junit.Test;
    import javax.naming.InitialContext;
    
    public class MyEjbTest
    {
       @Test public void testMyEjbImpl()
       {
          MyEjbIntf meineEJB = new MyEjbImpl();
          assertEquals( "3.0", meineEJB.berechne( "1", "2" ) );
       }
    
       /* Diesen Test nur bei vorhandenem InitialContextFactoryMock aktivieren:
       @Test public void testMyEjbClient() throws Exception
       {
          System.setProperty( "java.naming.factory.initial", InitialContextFactoryMock.class.getName() );
          (new InitialContext()).bind( "MyEjb#" + MyEjbIntf.class.getName(), new MyEjbImpl() );
          String s = MyEjbClient.execute( new String[] { "1", "2" } );
          assertEquals( " 3.0", s.substring( s.length() - 4 ) );
       }
       */
    }
    

    Weiter unten finden Sie ein Beispiel für einen InitialContextFactoryMock.

Web-Unterprojekt

  1. Erzeugen Sie im Parent-Projektverzeichnis MeineEjb3App ein neues Webapp-Unterprojekt:

    cd \MeinWorkspace\MeineEjb3App

    mvn archetype:generate -DinteractiveMode=false -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=de.meinefirma.meinprojekt -DartifactId=WebProj

    cd \MeinWorkspace\MeineEjb3App\WebProj

    tree /F

  2. Löschen Sie im MeineEjb3App\WebProj\src\main\webapp-Verzeichnis die index.jsp und legen Sie stattdessen folgende zwei JSP-Dateien an:

    index.jsp:

    <html>
    <head><title>Startseite</title></head>
    <body>
    <h2>Startseite</h2>
    <p><a href="BerechnungsFormularServlet">Berechnungsformular-Servlet</a></p>
    <p><a href="BerechnungsFormular.jsp">Berechnungsformular-JSP</a> (nicht auf allen App-Servern)</p>
    </body>
    </html>
    

    BerechnungsFormular.jsp:

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" %>
    <%@ page import="javax.ejb.*, javax.naming.*, de.meinefirma.meinprojekt.MyEjbIntf" %>
    <%! // Falls JBoss:
        @javax.ejb.EJB
        private static MyEjbIntf meineEJB;
        private void ejbLookup() {
          try {
            // Falls GlassFish oder WebLogic (fuer andere App-Server eventuell anpassen):
            Context ctx = new InitialContext();
            meineEJB = (MyEjbIntf) ctx.lookup( "MyEjb#" + MyEjbIntf.class.getName() );
          } catch( Exception ex ) {
            throw new RuntimeException( ex );
          }
        } %>
    <%  if( meineEJB == null ) ejbLookup();
        String wert1 = request.getParameter( "wert1" );
        String wert2 = request.getParameter( "wert2" );
        if( wert1 == null ) wert1 = "";
        if( wert2 == null ) wert2 = "";
        String ergebnis = meineEJB.berechne( wert1, wert2 ); %>
    <html>
    <head><title>JSP mit Berechnungsformular</title></head>
    <body>
    <h2>JSP mit Berechnungsformular</h2>
    <form name="meinFormular" method="get"><pre>
    Wert1 <input type="text" name="wert1" value='<%= wert1 %>' size=10 maxlength=10><br>
    Wert2 <input type="text" name="wert2" value='<%= wert2 %>' size=10 maxlength=10><br>
          <input type="submit" value="berechne"> <input type="text" value='<%= ergebnis %>' size=10 readonly><br>
    </pre></form>
    </body>
    </html>
    
  3. Erzeugen Sie unter MeineEjb3App\WebProj\src\main die Unterverzeichnisse java\de\meinefirma\meinprojekt und darin das Servlet BerechnungsFormularServlet.java:

    package de.meinefirma.meinprojekt;
    
    import java.io.*;
    import javax.servlet.*;
    import javax.servlet.http.*;
    
    public class BerechnungsFormularServlet extends HttpServlet
    {
       @javax.ejb.EJB
       de.meinefirma.meinprojekt.MyEjbIntf meineEJB;
    
       @Override
       public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
       {
          doGetOrPost( request, response );
       }
    
       @Override
       public void doPost( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException
       {
          doGetOrPost( request, response );
       }
    
       private void doGetOrPost( HttpServletRequest request, HttpServletResponse response ) throws IOException
       {
          // Request:
          String wert1 = request.getParameter( "wert1" );
          String wert2 = request.getParameter( "wert2" );
          if( wert1 == null ) wert1 = "";
          if( wert2 == null ) wert2 = "";
          // EJB-Aufruf:
          String ergebnis = meineEJB.berechne( wert1, wert2 );
          // Response:
          response.setContentType( "text/html; charset=ISO-8859-1" );
          PrintWriter out = response.getWriter();
          out.printf(
             "<html>\n" +
             "<head><title>Servlet mit Berechnungsformular</title></head>\n" +
             "<body>\n" +
             "<h2>Servlet mit Berechnungsformular</h2>\n" +
             "<form name='meinFormular' method='get'><pre>\n" +
             "Wert1 <input type='text' name='wert1' value='%1$s' size=10 maxlength=10><br>\n" +
             "Wert2 <input type='text' name='wert2' value='%2$s' size=10 maxlength=10><br>\n" +
             "      <input type='submit' value='berechne'> <input type='text' value='%3$s' size=10 readonly><br>\n" +
             "</pre></form>\n" +
             "</body>\n" +
             "</html>\n",
             wert1, wert2, ergebnis );
       }
    }
    
  4. Ersetzen Sie im MeineEjb3App\WebProj\src\main\webapp\WEB-INF-Verzeichnis den Inhalt der web.xml durch:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app 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">
      <servlet>
        <servlet-name>BerechnungsFormularServlet</servlet-name>
        <servlet-class>de.meinefirma.meinprojekt.BerechnungsFormularServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>BerechnungsFormularServlet</servlet-name>
        <url-pattern>/BerechnungsFormularServlet</url-pattern>
      </servlet-mapping>
      <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
    </web-app>
    
  5. Ersetzen Sie im MeineEjb3App\WebProj-Verzeichnis den Inhalt der pom.xml durch:

    <project>
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <groupId>de.meinefirma.meinprojekt</groupId>
        <artifactId>MeineEjb3App</artifactId>
        <version>1.0-SNAPSHOT</version>
      </parent>
      <!-- WebProj ohne <groupId> und <version>: Wird von <parent> uebernommen: -->
      <artifactId>WebProj</artifactId>
      <packaging>war</packaging>
      <name>WebProj</name>
      <build>
        <finalName>${project.artifactId}</finalName>
      </build>
      <dependencies>
        <dependency>
          <groupId>${project.groupId}</groupId>
          <artifactId>EjbProj</artifactId>
          <version>${project.version}</version>
          <classifier>client</classifier>
          <scope>provided</scope>
        </dependency>
      </dependencies>
    </project>
    

    Bitte beachten Sie die ${project.groupId}- und ${project.version}-Ausdrücke, mit denen schwer wartbare Mehrfacheinträge vermieden werden.

EAR-Unterprojekt

  1. Erzeugen Sie im Parent-Projektverzeichnis MeineEjb3App ein neues Verzeichnis für das EAR-Unterprojekt:

    cd \MeinWorkspace\MeineEjb3App

    md EarProj

    cd EarProj

  2. Legen Sie im neuen MeineEjb3App\EarProj-Verzeichnis folgende pom.xml an:

    <project>
      <modelVersion>4.0.0</modelVersion>
      <parent>
        <groupId>de.meinefirma.meinprojekt</groupId>
        <artifactId>MeineEjb3App</artifactId>
        <version>1.0-SNAPSHOT</version>
      </parent>
      <!-- EarProj ohne <groupId> und <version>: Wird von <parent> uebernommen: -->
      <artifactId>EarProj</artifactId>
      <packaging>ear</packaging>
      <name>EarProj</name>
      <build>
        <plugins>
          <plugin>
            <artifactId>maven-ear-plugin</artifactId>
            <version>2.5</version>
            <configuration>
              <defaultLibBundleDir>lib</defaultLibBundleDir>
              <archive>
                <manifest>
                  <addClasspath>true</addClasspath>
                </manifest>
              </archive>
              <modules>
                <ejbModule>
                  <groupId>${project.groupId}</groupId>
                  <artifactId>EjbProj</artifactId>
                  <bundleFileName>EjbProj.jar</bundleFileName>
                </ejbModule>
                <webModule>
                  <groupId>${project.groupId}</groupId>
                  <artifactId>WebProj</artifactId>
                  <bundleFileName>WebProj.war</bundleFileName>
                  <contextRoot>/WebProj</contextRoot>
                </webModule>
              </modules>
            </configuration>
          </plugin>
          <!--
          <plugin>
            <groupId>org.glassfish.maven.plugin</groupId>
            <artifactId>maven-glassfish-plugin</artifactId>
            <version>2.1</version>
            <configuration>
              <domain>
                <name>domain1</name>
                <adminPort>4848</adminPort>
              </domain>
              <glassfishDirectory>${env.GLASSFISH_HOME}</glassfishDirectory>
              <user>admin</user>
              <adminPassword>adminadmin</adminPassword>
              <echo>true</echo>
            </configuration>
          </plugin>
          -->
          <!--
          <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>jboss-maven-plugin</artifactId>
            <configuration>
              <jbossHome>${env.JBOSS_HOME}</jbossHome>
              <port>8080</port>
            </configuration>
          </plugin>
          -->
        </plugins>
      </build>
      <dependencies>
        <dependency>
          <groupId>${project.groupId}</groupId>
          <artifactId>EjbProj</artifactId>
          <version>${project.version}</version>
          <type>ejb</type>
        </dependency>
        <dependency>
          <groupId>${project.groupId}</groupId>
          <artifactId>WebProj</artifactId>
          <version>${project.version}</version>
          <type>war</type>
        </dependency>
      </dependencies>
    </project>
    

JEE-Parent-POM

  1. Erzeugen Sie im Parent-Verzeichnis MeineEjb3App folgende pom.xml:

    <project>
      <modelVersion>4.0.0</modelVersion>
      <groupId>de.meinefirma.meinprojekt</groupId>
      <artifactId>MeineEjb3App</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>pom</packaging>
      <name>MeineEjb3App</name>
      <modules>
        <module>EjbProj</module>
        <module>WebProj</module>
        <module>EarProj</module>
      </modules>
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
              <source>1.6</source>
              <target>1.6</target>
            </configuration>
          </plugin>
        </plugins>
      </build>
      <dependencies>
        <dependency>
          <groupId>javaee</groupId>
          <artifactId>javaee-api</artifactId>
          <version>5</version>
          <scope>provided</scope>
        </dependency>
      </dependencies>
      <repositories>
        <repository>
          <id>maven2-repository.dev.java.net</id>
          <name>Java.net Maven 2 Repository</name>
          <url>http://download.java.net/maven/2</url>
        </repository>
      </repositories>
    </project>
    

Projektstruktur

  1. Ihre Projektstruktur sieht jetzt so aus:

    [\MeinWorkspace\MeineEjb3App]
     |- [EarProj]
     |   '- pom.xml
     |- [EjbProj]
     |   |- [src]
     |   |   |- [main]
     |   |   |   '- [java]
     |   |   |       '- [de]
     |   |   |           '- [meinefirma]
     |   |   |               '- [meinprojekt]
     |   |   |                   |- MyEjbClient.java
     |   |   |                   |- MyEjbImpl.java
     |   |   |                   '- MyEjbIntf.java
     |   |   '- [test]
     |   |       '- [java]
     |   |           '- [de]
     |   |               '- [meinefirma]
     |   |                   '- [meinprojekt]
     |   |                       '- MyEjbTest.java
     |   '- pom.xml
     |- [WebProj]
     |   |- [src]
     |   |   '- [main]
     |   |       |- [java]
     |   |       |   '- [de]
     |   |       |       '- [meinefirma]
     |   |       |           '- [meinprojekt]
     |   |       |               '- BerechnungsFormularServlet.java
     |   |       |- [resources]
     |   |       '- [webapp]
     |   |           |- [WEB-INF]
     |   |           |   '- web.xml
     |   |           |- BerechnungsFormular.jsp
     |   |           '- index.jsp
     |   '- pom.xml
     '- pom.xml
    

Aufruf der EJB3-Anwendung

  1. Webanwendung mit Servlet und JSP:

    Wechseln Sie in das Parent-Verzeichnis MeineEjb3App, bauen Sie alle Projekte, kopieren Sie das EAR-Ergebnisartefakt in das Autodeploy-Verzeichnis Ihres Java EE Application Servers und testen Sie die EJB3-Webanwendung bei laufendem Java EE Application Server. Beispielsweise so (von den copy-Kommandos ist natürlich nur das eine für Ihren App-Server passende relevant):

    cd \MeinWorkspace\MeineEjb3App

    mvn clean install

    copy EarProj\target\EarProj-1.0-SNAPSHOT.ear C:\GlassFish\glassfish\domains\domain1\autodeploy

    copy EarProj\target\EarProj-1.0-SNAPSHOT.ear C:\WebLogic\user_projects\domains\MeineDomain\autodeploy

    copy EarProj\target\EarProj-1.0-SNAPSHOT.ear C:\JBoss\server\default\deploy

    copy EarProj\target\EarProj-1.0-SNAPSHOT.ear C:\Geronimo\deploy

    start http://localhost:8080/WebProj   [falls GlassFish, JBoss oder Geronimo]

    start http://localhost:7001/WebProj   [falls WebLogic]

    Das Servlet BerechnungsFormularServlet funktioniert auf allen Java-EE-5- und EJB-3-konformen Application Servern, aber beachten Sie bitte, dass im JSP BerechnungsFormular.jsp der Context.lookup() leider eventuell Application-Server-spezifisch angepasst werden muss. Die gezeigte Variante funktioniert mit GlassFish 3.1 (und 2.1), WebLogic 10.3.4 und JBoss 5.1, aber nicht mit Geronimo 2.1.4.

  2. Stand-alone-Client für GlassFish 3.1 (und 2.1):

    Das Ausführen von EJBs von einem externen Stand-alone-Client aus ist leider sehr Application-Server-spezifisch.
    Rufen Sie im MeineEjb3App-Projektverzeichnis auf (ersetzen Sie die beiden Zahlen 13 und 42 durch beliebige andere):

    java -cp C:\GlassFish\glassfish\lib\appserv-rt.jar;C:\GlassFish\glassfish\lib\javaee.jar;EjbProj\target\EjbProj-1.0-SNAPSHOT.jar de.meinefirma.meinprojekt.MyEjbClient 13 42

    Für GlassFish wird keine zusätzliche jndi.properties benötigt, weil diese Datei bereits in appserv-rt.jar enthalten ist. Beachten Sie auch die Hinweise unter: How do I access a Remote EJB from a stand-alone java client?

  3. Stand-alone-Client für WebLogic 10.3.4:

    Erzeugen Sie im MeineEjb3App-Projektverzeichnis das neue Unterverzeichnis WebLogic-JNDI und speichern Sie darin die folgende jndi.properties:

    java.naming.provider.url=t3://localhost:7001
    java.naming.factory.initial=weblogic.jndi.WLInitialContextFactory
    

    Rufen Sie im MeineEjb3App-Projektverzeichnis auf (ersetzen Sie die beiden Zahlen durch beliebige andere):

    java -cp WebLogic-JNDI;C:\WebLogic\wlserver_10.3\server\lib\wlclient.jar;EjbProj\target\EjbProj-1.0-SNAPSHOT.jar de.meinefirma.meinprojekt.MyEjbClient 13 42

  4. Stand-alone-Client für JBoss 5.1:

    Erzeugen Sie im MeineEjb3App-Projektverzeichnis das neue Unterverzeichnis JBoss-JNDI und speichern Sie darin die folgende jndi.properties:

    java.naming.provider.url=jnp://localhost:1099
    java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
    java.naming.factory.url.pkgs=org.jboss.naming:org.jnp.interfaces
    jnp.socket.Factory=org.jnp.interfaces.TimedSocketFactory
    

    Rufen Sie im MeineEjb3App-Projektverzeichnis auf (ersetzen Sie die beiden Zahlen durch beliebige andere):

    java -cp JBoss-JNDI;C:\JBoss\client\jbossall-client.jar;EjbProj\target\EjbProj-1.0-SNAPSHOT.jar de.meinefirma.meinprojekt.MyEjbClient 13 42 MyEjb

    Bitte beachten Sie, dass JBoss 5.1 den Context.lookup()-String "MyEjb" benötigt.

  5. Stand-alone-Client für Geronimo 2.1.4:

    Erzeugen Sie im MeineEjb3App-Projektverzeichnis das neue Unterverzeichnis Geronimo-JNDI und speichern Sie darin die folgende jndi.properties:

    java.naming.provider.url=127.0.0.1:4201
    java.naming.factory.initial=org.openejb.client.RemoteInitialContextFactory
    

    Rufen Sie im MeineEjb3App-Projektverzeichnis auf (ersetzen Sie die beiden Zahlen durch beliebige andere):

    java -cp Geronimo-JNDI;C:\Geronimo\repository\org\apache\openejb\openejb-client\3.0.1\openejb-client-3.0.1.jar;C:\Geronimo\repository\org\apache\geronimo\specs\geronimo-ejb_3.0_spec\1.0.1\geronimo-ejb_3.0_spec-1.0.1.jar;EjbProj\target\EjbProj-1.0-SNAPSHOT.jar de.meinefirma.meinprojekt.MyEjbClient 13 42 MyEjbImplRemote

    Bitte beachten Sie, dass Geronimo 2.1.4 den Context.lookup()-String "MyEjbImplRemote" benötigt.

  6. Für andere Java EE Application Server müssen andere .jar-Libs im Classpath eingetragen werden, muss eine zum App-Server passende jndi.properties im Classpath sein und eventuell muss der MyEjbClient-Klasse als dritter Parameter ein zum App-Server passende Context.lookup()-String übergeben werden (falls der Default nicht funktioniert).

  7. Eclipse:

    Falls Sie das Projekt in Eclipse bearbeiten wollen:

    Verwenden Sie den wtpversion-Parameter, um die Eclipse-Projektkonfigurationsdateien anzulegen:

    mvn eclipse:eclipse -Dwtpversion=2.0

    Oder verwenden Sie das M2Eclipse-Plugin.



Rudimentärer InitialContextFactoryMock

Wenn Sie nicht nur die EJB-Komponenten mit JUnit-Komponententests testen wollen (so wie es in obiger Testklasse MyEjbTest.java die erste Testmethode testMyEjbImpl() zeigt), sondern auch einen externen Stand-alone-Client per JUnit-Test ohne Java EE Application Server testen wollen (wie es in obiger Testklasse MyEjbTest.java die zweite Testmethode testMyEjbClient() zeigt), benötigen Sie eine JNDI-Implementierung oder zumindest eine InitialContextFactory-Implementierung (beides beinhaltet normalerweise der Java EE Application Server).

Eine sehr einfache primitive Variante zeigt folgender InitialContextFactoryMock. Bitte beachten Sie, dass dieser Mock nur für sehr einfache Testfälle geeignet ist (es sind nur die beiden Methoden bind() und lookup() implementiert). Wenn Sie eine vollständigere Implementierung benötigen, sehen Sie sich Simple-JNDI an (oder googeln beispielsweise nach SimpleContextFactory oder SimpleInitialContextFactory).

Im Folgenden wird die Einbettung in obiges MeineEjb3App-Projekt gezeigt.

  1. Legen Sie im MeineEjb3App\EjbProj\src\test\java\de\meinefirma\meinprojekt-Verzeichnis folgende InitialContextFactoryMock.java an:

    package de.meinefirma.meinprojekt;
    
    import java.util.Hashtable;
    import javax.naming.*;
    import javax.naming.spi.InitialContextFactory;
    
    public class InitialContextFactoryMock implements InitialContextFactory
    {
       private static final InitialContextMock ctx = new InitialContextMock();
    
       @Override
       public Context getInitialContext( Hashtable<?,?> hashtable ) throws NamingException
       {
          return ctx;
       }
    }
    
    class InitialContextMock implements Context
    {
       private Hashtable<String,Object> hashtable = new Hashtable<String,Object>();
    
       @Override public void bind( String key, Object value ) throws NamingException
       {
          hashtable.put( key, value );
       }
    
       @Override public Object lookup( String key ) throws NamingException
       {
          return hashtable.get( key );
       }
    
       @Override public Object addToEnvironment( String arg0, Object arg1 ) throws NamingException { return null; }
       @Override public void bind( Name key, Object value ) throws NamingException {}
       @Override public void close() throws NamingException {}
       @Override public Name composeName( Name arg0, Name arg1 ) throws NamingException { return null; }
       @Override public String composeName( String arg0, String arg1 ) throws NamingException { return null; }
       @Override public Context createSubcontext( Name arg0 ) throws NamingException { return null; }
       @Override public Context createSubcontext( String arg0 ) throws NamingException { return null; }
       @Override public void destroySubcontext( Name arg0 ) throws NamingException {}
       @Override public void destroySubcontext( String arg0 ) throws NamingException {}
       @Override public Hashtable<?,?> getEnvironment() throws NamingException { return null; }
       @Override public String getNameInNamespace() throws NamingException { return null; }
       @Override public NameParser getNameParser( Name arg0 ) throws NamingException { return null; }
       @Override public NameParser getNameParser( String arg0 ) throws NamingException { return null; }
       @Override public NamingEnumeration<NameClassPair> list( Name arg0 ) throws NamingException { return null; }
       @Override public NamingEnumeration<NameClassPair> list( String arg0 ) throws NamingException { return null; }
       @Override public NamingEnumeration<Binding> listBindings( Name arg0 ) throws NamingException { return null; }
       @Override public NamingEnumeration<Binding> listBindings( String arg0 ) throws NamingException { return null; }
       @Override public Object lookup( Name arg0 ) throws NamingException { return null; }
       @Override public Object lookupLink( Name arg0 ) throws NamingException { return null; }
       @Override public Object lookupLink( String arg0 ) throws NamingException { return null; }
       @Override public void rebind( Name arg0, Object arg1 ) throws NamingException {}
       @Override public void rebind( String arg0, Object arg1 ) throws NamingException {}
       @Override public Object removeFromEnvironment( String arg0 ) throws NamingException { return null; }
       @Override public void rename( Name arg0, Name arg1 ) throws NamingException {}
       @Override public void rename( String arg0, String arg1 ) throws NamingException {}
       @Override public void unbind( Name arg0 ) throws NamingException {}
       @Override public void unbind( String arg0 ) throws NamingException {}
    }
    
  2. Entfernen Sie in obiger Testklasse MyEjbTest.java die Auskommentierung um die Testmethode testMyEjbClient() und führen Sie "mvn clean test" aus.



Weitere Beispielanwendungen



Links auf weiterführende Informationen





Weitere Themen: andere TechDocs | JSP | Java EE | EJB | SQL
© 1998-2011 Torsten Horn, Aachen