Skip to content

7. Version 3: Portierung der PAM-Anwendung auf einen GlassFish-Anwendungsserver

Wir schlagen vor, die EJBs aus den [Business]- und [DAO]-Schichten der OpenEJB/EclipseLink-Architektur in den Container eines GlassFish-Anwendungsservers zu integrieren.

Die aktuelle Implementierung mit OpenEJB / EclipseLink

Oben nutzt die [ui]-Schicht die Remote-Schnittstelle der [business]-Schicht.

Wir haben zwei Ausführungskontexte getestet: lokal und remote. Im letzteren Modus fungierte die [ui]-Schicht als Client der [business]-Schicht, die durch EJBs implementiert ist. Um im Client/Server-Modus zu arbeiten, bei dem Client und Server in zwei separaten JVMs laufen, werden wir die [business, DAO, JPA]-Schichten auf dem GlassFish Java EE-Server bereitstellen. Dieser Server ist in NetBeans enthalten.

Die mit dem GlassFish-Server zu erstellende Implementierung

  • Die [UI]-Schicht wird in einer Java SE (Standard Edition)-Umgebung ausgeführt
  • Die [Geschäftslogik-, DAO- und JPA-]Schichten werden in einer Java EE-Umgebung (Enterprise Edition) auf einem GlassFish v3-Server ausgeführt
  • Der Client kommuniziert mit dem Server über ein TCP/IP-Netzwerk. Die Netzwerkkommunikation ist für den Entwickler transparent, er muss sich jedoch bewusst sein, dass Client und Server zur Kommunikation serialisierte Objekte austauschen, nicht Objektreferenzen. Das für diese Kommunikation verwendete Netzwerkprotokoll heißt RMI (Remote Method Invocation) und kann nur zwischen zwei Java-Anwendungen verwendet werden.
  • Die auf dem GlassFish-Server verwendete JPA-Implementierung ist EclipseLink.

7.1. Der Server- -Teil der PAM-Client/Server-Anwendung

7.1.1. Die Anwendungsarchitektur

Hier betrachten wir die serverseitige Komponente, die vom EJB3-Container des GlassFish-Servers gehostet wird:

Das Ziel ist es, das, was bereits mit dem OpenEJB-Container entwickelt und getestet wurde, auf den GlassFish-Server zu portieren. Dies ist der Vorteil von OpenEJB und, allgemeiner gesagt, von eingebetteten EJB-Containern: Sie ermöglichen es uns, die Anwendung in einer vereinfachten Laufzeitumgebung zu testen. Sobald die Anwendung getestet wurde, muss sie nur noch auf einen Zielserver portiert werden, in diesem Fall den GlassFish-Server.

7.1.1.1. Das NetBeans-Projekt

Beginnen wir damit, ein neues NetBeans-Projekt zu erstellen:

  • unter [1], neues Projekt
  • Wählen Sie unter [2] die Kategorie „Maven“ und unter [3] den Modultyp „EJB“ aus. Das Ziel ist es, ein Projekt zu erstellen, das von einem EJB-Container, insbesondere dem GlassFish-Server, gehostet und ausgeführt wird.
  • Wählen Sie über die Schaltfläche [4a] den übergeordneten Ordner für den Projektordner aus oder geben Sie dessen Namen direkt in [4b] ein.
  • Geben Sie dem Projekt in [5] einen Namen
  • Wählen Sie in [6] den Anwendungsserver aus, auf dem das Projekt ausgeführt werden soll. Der hier ausgewählte Server ist einer der auf der Registerkarte [Runtime / Servers] angezeigten Server, in diesem Fall GlassFish v3.
  • Wählen Sie in [7] die Java EE-Version aus.
  • Wählen Sie unter [1] das neue Projekt aus. Es unterscheidet sich in einigen Punkten von einem Standard-Java-Projekt:
    • Es wird automatisch ein Zweig [Other Sources] [2] erstellt. Dieser enthält insbesondere die Datei [persistence.xml], die die JPA-Schicht konfiguriert,
    • Wenn Sie das Projekt erstellen (Build), erscheint eine [javaee-api-6.0]-Abhängigkeit [3]. Sie ist vom Typ „provided“, da sie zur Laufzeit vom Glassfish-EJB-Container bereitgestellt wird.

7.1.1.2. Konfigurieren der Persistenzschicht

Unter „Konfiguration der Persistenzschicht“ verstehen wir das Erstellen der Datei [persistence.xml], die Folgendes definiert:

  • die zu verwendende JPA-Implementierung
  • die Definition der von der JPA-Schicht verwendeten Datenquelle. Dabei handelt es sich um eine vom GlassFish-Server verwaltete JDBC-Quelle.

Wir können wie folgt vorgehen. Zunächst erstellen wir auf der Registerkarte [Runtime / Databases] [1] eine Verbindung zur Datenbank MySQL5 / dbpam_eclipselink:

Sobald dies erledigt ist, können wir mit der Erstellung der JDBC-Ressource fortfahren, die vom EJB-Modul verwendet wird:

  • Erstellen Sie in [1] eine neue Datei – stellen Sie sicher, dass das EJB-Projekt ausgewählt ist, bevor Sie diesen Vorgang ausführen
  • Wählen Sie in [2] das EJB-Projekt aus
  • Wählen Sie in [3] die Kategorie [Glassfish] aus
  • Wählen Sie unter [4] „JDBC-Ressource erstellen“ aus
  • Geben Sie in [5] an, dass die JDBC-Ressource einen neuen Verbindungspool verwenden soll. Beachten Sie, dass ein Verbindungspool ein Pool offener Verbindungen ist, der dazu dient, die Interaktionen der Anwendung mit der Datenbank zu beschleunigen.
  • Geben Sie in [6] einen JNDI-Namen für die erstellte JDBC-Ressource an. Dieser Name kann beliebig sein, hat jedoch häufig die Form jdbc/name. Dieser JNDI-Name wird in der Datei [persistence.xml] verwendet, um die Datenquelle zu bezeichnen, die die JPA-Implementierung verwenden muss.
  • Geben Sie in [7] einen beliebigen Namen für den zu erstellenden Verbindungspool ein
  • Wählen Sie in der Dropdown-Liste [8] die zuvor für die MySQL-Datenbank / dbpam_eclipselink erstellte JDBC-Verbindung aus.
  • In [9] finden Sie eine Zusammenfassung der Eigenschaften des Verbindungspools – lassen Sie alles unverändert
  • In [10] können Sie verschiedene Eigenschaften des Verbindungspools festlegen – belassen Sie die Standardwerte
  • In [11] wurde nach Abschluss des Assistenten zum Erstellen einer JDBC-Ressource für das EJB-Modul eine Datei [glassfish-resources.xml] im Zweig [Other Sources] erstellt. Der Inhalt dieser Datei lautet wie folgt:
// it's okay - you can ask for the payslip in the [metier] layer
    IMetierRemote metier = null;
    FeuilleSalaire feuilleSalaire = null;
    try {
       // configure the embedded Open EJB container
...
       // remote business layer instantiation
      metier = (IMetierRemote) initialContext.lookup("MetierRemote");
       // wage sheet calculation
      feuilleSalaire = metier.calculerFeuilleSalaire(args[0], nbHeuresTravaillées, nbJoursTravaillés);
    } catch (PamException ex) {
...
    } catch (Exception ex) {
...
    }

Die Datei [glassfish-resources.xml] ist eine XML-Datei, die alle vom Assistenten erfassten Daten enthält. Sie wird von NetBeans verwendet, um die Erstellung der von diesem Modul benötigten JDBC-Ressource anzufordern, wenn das EJB-Modul auf dem GlassFish-Server bereitgestellt wird.

Sie können nun die Datei [persistence.xml] erstellen, mit der die JPA-Schicht des EJB-Moduls konfiguriert wird:

  • Erstellen Sie in [1] eine neue Datei – stellen Sie sicher, dass das EJB-Projekt ausgewählt ist, bevor Sie diesen Vorgang ausführen
  • Wählen Sie in [2] das EJB-Projekt aus
  • Wählen Sie unter [3] die Kategorie [Persistence] aus
  • Erstellen Sie in [4] eine Persistenz-Einheit
  • Geben Sie in [5] der Persistence-Einheit einen Namen
  • In [6] werden mehrere JPA-Implementierungen angeboten. Wählen Sie hier [EclipseLink] aus. Andere Implementierungen können verwendet werden, sofern Sie die Bibliotheken, die diese implementieren, zusammen mit denen des GlassFish-Servers einbinden.
  • Wählen Sie in der Dropdown-Liste [7] die soeben erstellte JDBC-Datenquelle [jdbc/dbpam_eclipselink] aus.
  • Geben Sie in [8] an, dass Transaktionen vom EJB-Container verwaltet werden
  • Geben Sie in [9] an, dass beim Deployen des EJB-Moduls auf den Server keine Operationen an der Datenquelle durchgeführt werden sollen. Der Grund dafür ist, dass das EJB-Modul eine bereits erstellte [dbpam_eclipselink]-Datenbank verwendet.
  • Am Ende des Assistenten wurde eine [persistence.xml]-Datei erstellt [10]. Ihr Inhalt lautet wie folgt:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE resources PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Resource Definitions//EN" "http://glassfish.org/dtds/glassfish-resources_1_5.dtd">
<resources>
  <jdbc-resource enabled="true" jndi-name="jdbc/dbpam_eclipselink" object-type="user" pool-name="dbpamEclipselinkConnectionPool">
    <description/>
  </jdbc-resource>
  <jdbc-connection-pool allow-non-component-callers="false" associate-with-thread="false" connection-creation-retry-attempts="0" connection-creation-retry-interval-in-seconds="10" connection-leak-reclaim="false" connection-leak-timeout-in-seconds="0" connection-validation-method="auto-commit" datasource-classname="com.mysql.jdbc.jdbc2.optional.MysqlDataSource" fail-all-connections="false" idle-timeout-in-seconds="300" is-connection-validation-required="false" is-isolation-level-guaranteed="true" lazy-connection-association="false" lazy-connection-enlistment="false" match-connections="false" max-connection-usage-count="0" max-pool-size="32" max-wait-time-in-millis="60000" name="dbpamEclipselinkConnectionPool" non-transactional-connections="false" pool-resize-quantity="2" res-type="javax.sql.DataSource" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
    <property name="URL" value="jdbc:mysql://localhost:3306/dbpam_eclipselink"/>
    <property name="User" value="root"/>
    <property name="Password" value=""/>
  </jdbc-connection-pool>
</resources>
  • Zeile 3: der Name der Persistenz-Einheit [mv-pam-ejb-metier-dao-eclipselinkPU] und der Transaktionstyp (JTA für einen EJB-Container)
  • Zeile 5: Der JNDI-Name der von der Persistenzschicht verwendeten Datenquelle: jdbc/dbpam_eclipselink
  • Zeile 6: JPA-Entitäten sind nicht angegeben. Sie werden im Klassenpfad des EJB-Moduls gesucht.
  • Der Name der verwendeten JPA-Implementierung (Hibernate, EclipseLink usw.) ist nicht angegeben. In diesem Fall verwendet GlassFish v3 standardmäßig EclipseLink.

7.1.1.3. Einfügen der [JPA-, DAO-, Business-] Schichten

Nachdem die Datei [persistence.xml] nun definiert wurde, können wir damit fortfahren, die [Business-, DAO- und JPA-]Schichten der Unternehmensanwendung [pam] in das Projekt einzufügen:

Diese drei Schichten sind identisch mit denen aus OpenEJB. Wir können sie einfach zwischen den beiden Projekten kopieren und einfügen. Genau das tun wir jetzt:

  • in [1] das Ergebnis des Kopierens der Pakete [jpa, dao, business, exception] aus dem Projekt [mv-pam-openejb-eclipselink] in das EJB-Modul [mv-pam-ejb-business-dao-jpa-eclipselink]

7.1.1.4. Konfiguration des GlassFish-Servers

Wir müssen den GlassFish-Server noch in zwei Bereichen konfigurieren:

  • Die JPA-Schicht wird von EclipseLink implementiert. Wir müssen sicherstellen, dass der GlassFish-Server über die Bibliotheken für diese JPA-Implementierung verfügt.
  • Die Datenquelle ist eine MySQL-Datenbank. Wir müssen sicherstellen, dass der GlassFish-Server über den JDBC-Treiber für dieses Datenbankmanagementsystem verfügt.

Möglicherweise stellen Sie beim Deployen des EJB-Moduls fest, dass diese Bibliotheken fehlen. Hier ist eine von mehreren Möglichkeiten, fehlende Bibliotheken zum GlassFish-Server hinzuzufügen:

  • Rufen Sie in [1] die Eigenschaften des GlassFish-Servers auf
  • Notieren Sie sich in [2] den Ordner „domains“ des Servers. Wir bezeichnen ihn als <domains>
  • Legen Sie die fehlenden Bibliotheken im Ordner <domains>\domain1\lib ab. Im Beispiel wurden die Hibernate-Bibliotheken (lib/hibernate-tools) und der MySQL-JDBC-Treiber (lib/misc) hinzugefügt. Standardmäßig enthält der GlassFish-Server die EclipseLink-Bibliotheken. Wir fügen daher nur den MySQL-JDBC-Treiber hinzu.
  • In [1] starten wir auf der Registerkarte [Services] den GlassFish v3-Server
  • In [2] ist er aktiv

7.1.1.5. Bereitstellung des EJB-Moduls

Wir werden nun das EJB-Modul auf dem GlassFish-Server bereitstellen:

  • In [1] wird das EJB-Modul bereitgestellt
  • In [2] wird der GlassFish-Serverbaum aktualisiert
  • In [3] erscheint das EJB-Modul nach der Bereitstellung im Zweig [Applications] des GlassFish-Servers
  • in [4] wurde die JDBC-Ressource [jdbc / dbpam_eclipselink] auf dem GlassFish-Server erstellt. Erinnern Sie sich daran, dass wir sie in Abschnitt 7.1.1.2 definiert haben.

Während der Bereitstellung protokolliert der GlassFish-Server die folgenden Informationen in der Konsole:


<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
  <persistence-unit name="mv-pam-ejb-metier-dao-eclipselinkPU" transaction-type="JTA">
    <jta-data-source>jdbc/dbpam_eclipselink</jta-data-source>
    <exclude-unlisted-classes>false</exclude-unlisted-classes>
    <properties/>
  </persistence-unit>
</persistence>

Beachten Sie, dass die Zeilen

  • 3, 6, 8 und 11: die portablen JNDI-Namen der bereitgestellten EJBs. Java EE 6 führte das Konzept der portablen JNDI-Namen ein. Dies bezeichnet einen JNDI-Namen, der von allen Java EE 6-Servern erkannt wird. Bei Java EE 5 sind JNDI-Namen spezifisch für den verwendeten Server.
  • 4, 7, 9, 12: die JNDI-Namen der bereitgestellten EJBs in einem für GlassFish v3 spezifischen Format.

Diese Namen sind für die Konsolenanwendung nützlich, die wir schreiben werden, um das bereitgestellte EJB-Modul zu nutzen.

7.2. Konsolen-Client – Version 1

Nachdem wir nun die serverseitige Komponente unserer Client/Server-Anwendung bereitgestellt haben, werden wir uns die clientseitige Komponente ansehen [1]:

7.2.1. Das Client-Projekt

Wir erstellen ein neues Maven-Projekt vom Typ [Java-Anwendung] mit dem Namen [mv-pam-client-ejb-metier-dao-eclipselink]:

  • in [1], das Client-Projekt

In der Datei [pom.xml] fügen wir die folgenden Abhängigkeiten hinzu:

INFO: Realm admin-realm of classtype com.sun.enterprise.security.auth.realm.file.FileRealm successfully created.
....
INFO: Portable JNDI names for EJB IndemniteDao : [java:global/pam-serveur-metier-dao-jpa-eclipselink/IndemniteDao!DAO.IIndemniteDaoLocal, java:global/pam-serveur-metier-dao-jpa-eclipselink/IndemniteDao!DAO.IIndemniteDaoRemote]
INFO: Glassfish-specific (Non-portable) JNDI names for EJB IndemniteDao : [DAO.IIndemniteDaoRemote#DAO.IIndemniteDaoRemote, DAO.IIndemniteDaoRemote]
...
INFO: Portable JNDI names for EJB CotisationDao : [java:global/pam-serveur-metier-dao-jpa-eclipselink/CotisationDao!DAO.ICotisationDaoLocal, java:global/pam-serveur-metier-dao-jpa-eclipselink/CotisationDao!DAO.ICotisationDaoRemote]
INFO: Glassfish-specific (Non-portable) JNDI names for EJB CotisationDao : [DAO.ICotisationDaoRemote, DAO.ICotisationDaoRemote#DAO.ICotisationDaoRemote]
INFO: Portable JNDI names for EJB Metier : [java:global/pam-serveur-metier-dao-jpa-eclipselink/Metier!metier.IMetierRemote, java:global/pam-serveur-metier-dao-jpa-eclipselink/Metier!metier.IMetierLocal]
INFO: Glassfish-specific (Non-portable) JNDI names for EJB Metier : [metier.IMetierRemote#metier.IMetierRemote, metier.IMetierRemote]
...
INFO: Portable JNDI names for EJB EmployeDao : [java:global/pam-serveur-metier-dao-jpa-eclipselink/EmployeDao!DAO.IEmployeDaoLocal, java:global/pam-serveur-metier-dao-jpa-eclipselink/EmployeDao!DAO.IEmployeDaoRemote]
INFO: Glassfish-specific (Non-portable) JNDI names for EJB EmployeDao : [DAO.IEmployeDaoRemote#DAO.IEmployeDaoRemote, DAO.IEmployeDaoRemote]
INFO: pam-serveur-metier-dao-jpa-eclipselink was successfully deployed in 12 891 milliseconds.
  • Zeilen 31–35: die Abhängigkeit von der Bibliothek [gf-client], die es einem Glassfish-Client ermöglicht, mit einem Remote-Server zu kommunizieren,
  • Zeilen 36–41: die Abhängigkeit vom Maven-Projekt des EJB-Moduls. Hier möchten wir die Definitionen der JPA-Entitäten und der verschiedenen Schnittstellen sowie die der Ausnahmeklasse [PamException] abrufen,

Aus dem Projekt [mv-pam-openejb-eclipselink] kopieren wir die Klasse [MainRemote]:

Die Klasse [MainRemote] muss eine Referenz auf das EJB in der [business]-Schicht abrufen. Der Code für die Klasse [MainRemote] ändert sich wie folgt:


<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
  <groupId>istia.st</groupId>
  <artifactId>mv-pam-client-ejb-metier-dao-eclipselink</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>mv-pam-client-ejb-metier-dao-eclipselink</name>
  <url>http://maven.apache.org</url>
  <repositories>
    <repository>
      <url>http://download.eclipse.org/rt/eclipselink/maven.repo/</url>
      <id>eclipselink</id>
      <layout>default</layout>
      <name>Repository for library Library[eclipselink]</name>
    </repository>    
    <repository>
      <url>http://repo1.maven.org/maven2/</url>
      <id>swing-layout</id>
      <layout>default</layout>
      <name>Repository for library Library[swing-layout]</name>
    </repository>
  </repositories>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
 
  <dependencies>
    <dependency>
      <groupId>org.glassfish.appclient</groupId>
      <artifactId>gf-client</artifactId>
      <version>3.1.1</version>
    </dependency>    
    <dependency>
      <groupId>${project.groupId}</groupId>
      <artifactId>mv-pam-ejb-metier-dao-eclipselink</artifactId>
      <version>${project.version}</version>
      <type>ejb</type>
    </dependency>
    <dependency>
      <groupId>org.swinglabs</groupId>
      <artifactId>swing-layout</artifactId>
      <version>1.0.3</version>
    </dependency>
  </dependencies>
</project>
  • Zeile 6: Initialisierung des JNDI-Kontexts des GlassFish-Servers.
  • Zeile 8: Dieser JNDI-Kontext wird nach einer Referenz auf die Remote-Schnittstelle der [Business]-Schicht abgefragt. Aus den GlassFish-Protokollen wissen wir, dass die Remote-Schnittstelle der [Business]-Schicht zwei mögliche Namen hat:

// it's OK - we can ask for the payslip
    FeuilleSalaire feuilleSalaire = null;
    IMetierRemote metier = null;
    try {
      // context JNDI of Glassfish server
      InitialContext initialContext = new InitialContext();
      // business layer instantiation
      metier = (IMetierRemote) initialContext.lookup("java:global/istia.st_mv-pam-ejb-metier-dao-eclipselink_ejb_1.0-SNAPSHOT/Metier!metier.IMetierRemote");
      // wage sheet calculation
      feuilleSalaire = metier.calculerFeuilleSalaire(args[0], nbHeuresTravaillées, nbJoursTravaillés);
    } catch (PamException ex) {
      System.err.println("L'erreur suivante s'est produite : "
              + ex.getMessage());
      return;
    } catch (Exception ex) {
      System.err.println("L'erreur suivante s'est produite : "
              + ex.toString());
      return;
    }

Zeile 1: der JNDI-Name, der mit jedem Java EE 6-Anwendungsserver verwendet werden kann. Zeile 2: der GlassFish-spezifische JNDI-Name. Im Code verwenden wir in Zeile 9 den portablen JNDI-Namen.

  • Der Rest des Codes bleibt unverändert

In [1] konfigurieren wir das Projekt so, dass die Klasse [MainRemote] mit Argumenten ausgeführt wird. Wenn alles gut geht, liefert die Ausführung des Projekts das folgende Ergebnis:

Infos: EJB5181:Portable JNDI names for EJB Metier: [java:global/istia.st_mv-pam-ejb-metier-dao-eclipselink_ejb_1.0-SNAPSHOT/Metier!metier.IMetierLocal, java:global/istia.st_mv-pam-ejb-metier-dao-eclipselink_ejb_1.0-SNAPSHOT/Metier!metier.IMetierRemote]
Infos: EJB5182:Glassfish-specific (Non-portable) JNDI names for EJB Metier: [metier.IMetierRemote#metier.IMetierRemote, metier.IMetierRemote]

Wenn in den Eigenschaften eine falsche Sozialversicherungsnummer eingegeben wird, ergibt sich folgendes Ergebnis:

run:
Valeurs saisies :
N° de sécurité sociale de l'employé : 254104940426058
Nombre d'heures travaillées : 150
Nombre de jours travaillés : 20

Informations Employé : 
Nom : Jouveinal
Prénom : Marie
Adresse : 5 rue des oiseaux
Ville : St Corentin
Code Postal : 49203
Indice : 2

Informations Cotisations : 
CSGRDS : 3.49 %
CSGD : 6.15 %
Retraite : 7.88 %
Sécurité sociale : 9.39 %

Informations Indemnités : 
Salaire horaire : 2.1 euro
Entretien/jour : 2.1 euro
Repas/jour : 3.1 euro
Congés Payés : 15.0 %

Informations Salaire : 
Salaire de base : 362.25 euro
Cotisations sociales : 97.48 euro
Indemnités d'entretien : 42.0 euro
Indemnités de repas : 62.0 euro
Salaire net : 368.77 euro

BUILD SUCCESSFUL (total time: 2 seconds)

7.3. Client-Konsole – Version 2

In früheren Versionen wurde die JNDI-Umgebung des Glassfish-Servers mithilfe einer [jndi.properties]-Datei konfiguriert, die sich irgendwo in den Projektarchiven befand. Ihr Standardinhalt lautet wie folgt:

1
2
3
run:
L'erreur suivante s'est produite : L'employé de n°[254104940426058x] est introuvable
BUILD SUCCESSFUL (total time: 2 seconds)

Die Zeilen 7 und 8 geben den JNDI-Dienstrechner und dessen Listening-Port an. Mit dieser Datei können Sie keinen anderen JNDI-Server als localhost oder einen Server abfragen, der auf einem anderen Port als Port 3700 läuft. Wenn Sie diese beiden Einstellungen ändern möchten, können Sie eine eigene [jndi.properties]-Datei erstellen oder eine Spring-Konfiguration verwenden. Wir werden die letztere Technik demonstrieren.

Wir beginnen mit der Erstellung eines neuen Projekts auf Basis des ursprünglichen [pam-client-metier-dao-jpa-eclipselink]-Projekts.

  • In [1] wird das neue Projekt
  • in [2] die Spring-Konfigurationsdatei [spring-config-client.xml]. Ihr Inhalt lautet wie folgt:

Die Spring-Konfigurationsdatei lautet wie folgt:


# accès JNDI à Sun Application Server
java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
java.naming.factory.url.pkgs=com.sun.enterprise.naming
# Required to add a javax.naming.spi.StateFactory for CosNaming that
# supports dynamic RMI-IIOP.
java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl
org.omg.CORBA.ORBInitialHost=localhost
org.omg.CORBA.ORBInitialPort=3700

Hier verwenden wir ein <jee>-Tag (Zeile 14), das in Spring 2.0 eingeführt wurde. Die Verwendung dieses Tags erfordert die Definition des Schemas, zu dem es gehört (Zeilen 4, 10 und 11).

  • Zeile 14: Das <jee:jndi-lookup>-Tag wird verwendet, um eine Objektreferenz von einem JNDI-Dienst abzurufen. Hier verknüpfen wir die Bean namens „metier“ mit der JNDI-Ressource, die dem [Metier]-EJB zugeordnet ist. Der hier verwendete JNDI-Name ist der portable Name (Java EE 6) des EJB.
  • Der Inhalt der Datei [jndi.properties] wird zum Inhalt des <jee:environment>-Tags (Zeile 15), das zur Definition der Verbindungsparameter für den JNDI-Dienst verwendet wird.

Die Hauptklasse [MainRemote] ändert sich wie folgt:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
       http://www.springframework.org/schema/jee
       http://www.springframework.org/schema/jee/spring-jee-2.0.xsd">
 
  <!-- business -->
  <jee:jndi-lookup id="metier" jndi-name="java:global/istia.st_mv-pam-ejb-metier-dao-eclipselink_ejb_1.0-SNAPSHOT/Metier!metier.IMetierRemote">
    <jee:environment>
      java.naming.factory.initial=com.sun.enterprise.naming.SerialInitContextFactory
      java.naming.factory.url.pkgs=com.sun.enterprise.naming
      java.naming.factory.state=com.sun.corba.ee.impl.presentation.rmi.JNDIStateFactoryImpl
      org.omg.CORBA.ORBInitialHost=localhost
      org.omg.CORBA.ORBInitialPort=3700
    </jee:environment>
  </jee:jndi-lookup>
</beans>

Zeilen 7–8: Spring wird nach der Typreferenz [IMetierRemote] in der [business]-Schicht gefragt. Diese Lösung verleiht unserer Architektur Flexibilität. Wenn das EJB in der [business]-Schicht lokal würde – d. h. in derselben JVM wie unser [MainRemote]-Client ausgeführt würde –, bliebe der Code des Clients unverändert. Nur der Inhalt der Datei [spring-config-client.xml] würde sich ändern. Wir hätten dann eine Konfiguration, die der in Abschnitt 5.11 besprochenen Spring/JPA-Architektur ähnelt.

Leser sind eingeladen, diese neue Version zu testen.

7.4. Der Swing-Client

Wir werden nun den Swing-Client für unsere EJB-Client/Server-Anwendung erstellen.

Die Datei [pom.xml] muss die für Swing-Anwendungen erforderlichen Abhängigkeiten enthalten:

...
     // it's okay - we can ask for the payslip
    FeuilleSalaire feuilleSalaire = null;
    IMetierRemote metier=null;
    try {
       // instantiation layer [metier]
      ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config-client.xml");
      metier = (IMetierRemote) ctx.getBean("metier");
       // wage sheet calculation
      feuilleSalaire = metier.calculerFeuilleSalaire(args[0], nbHeuresTravaillées, nbJoursTravaillés);
    } catch (PamException ex) {
      System.err.println("L'erreur suivante s'est produite : "
              + ex.getMessage());
      return;
    } catch (Exception ex) {
      System.err.println("L'erreur suivante s'est produite : "
              + ex.toString());
      return;
    }
    ...

Oben wurde die Klasse [PamJFrame] ursprünglich für die Ausführung in einer Spring/JPA-Umgebung geschrieben:

Nun muss diese Klasse zum Remote-Client eines auf dem Glassfish-Server bereitgestellten EJB werden.


Praktische Übung: Nehmen Sie sich den Konsolen-Client [ui.console.MainRemote] im Projekt zum Vorbild und ändern Sie die Art und Weise, wie die Methode [doMyInit] (siehe Abschnitt 5.12.4) in der Klasse [PamJFrame] verwendet wird, um eine Referenz auf die [business]-Schicht zu erhalten, die nun remote ist.