Teil 1 Session Beans - Johann Mildner, Basel

Werbung
Johann Mildner, Basel
JEE – Business Component Developer Seminar
JEE
Business
Component
Developer
Seminar
GLASSFISH
01.01.2017
18.05.17 8:44
1
Johann Mildner, Basel
JEE – Business Component Developer Seminar
JEE - Business Component Developer Seminar
Stellen Sie sich folgende Aufgabenstellung vor: Ein Programm benötigt zu einer bekannten
Personalnummer verschiedene Daten wie Name, Adresse, Name der Ehefrau und der Kinder.
Sie wissen, dass diese Daten in den Tabellen MITARBEITER, ADRESSEN, EHEGATTEN und
KINDER zu finden sind.
Kein Problem werden Sie sagen und wahrscheinlich einen SELECT MITARBEITER join
ADRESSEN join EHEGATTEN, sowie einen SELECT KINDER absetzten um diese Daten zu
lesen.
Sie werden diese Daten mittels einer Methode MaDaten.holeMitarbeiterdaten(int ID) holen.
Da MaDaten temporäre Daten sind, werden Sie diese Daten in einer inneren Klasse erzeugen.
War doch gar nicht so schwierig.
Wie es so ist, benötigen Sie diese Daten in einem weiteren Programm. Kein Problem: die
innere Klasse wird zu einer richtigen Klasse und Sie verwenden diese Klasse ein zweites Mal.
Bleibt ja in der Familie.
Es kommt wie’s kommen muss, in einem anderen Projekt werden diese Daten ebenfalls
benötigt. Jetzt wird’s kompliziert. Die Daten befinden sich auf Ihrem Rechner. Es soll aber von
einem entfernten Rechner auf diese Daten zugegriffen werden.
Die zündende Idee: Sie schreiben einen Socket-Server und das andere Projekt schreibt einen
Socket-Client und schon ist die Sache geritzt.
Erste Gespräche ergeben, dass Ihre Kollegen vom anderen Projekt noch nie was von Sockets
gehört haben. Sie sind froh darüber denn diese Idee wäre doch nicht so gut gewesen. Viel zu
aufwändig. RMI wäre da schon eher geeignet aber das kennen die Kollegen vom anderen
Projekt eigentlich auch nicht wirklich.
Java EE bietet für verteilte Anwendungen Enterprise Java Beans (EJB) als Lösung an1.
Dieses Seminar führt Sie nun in die Technik der EJB-Programmierung ein.
So wie Servlets und JSP’s einen Servlet-Container benötigen, benötigen EJB’s einen EJBContainer. Dieser EJB Container befindet sich innerhalb eines Applikationsservers.
Dieses Seminar zeigt Ihnen, wie Sie verteilte Anwendungen realisieren.
Sie werden Session Beans (Stateless und Stateful), Entities (JPA – Java Persistence API),
Message Driven Beans, Message Services, Timer Services sowie Web Services kennenlernen.
Es werden Aufgaben gestellt, die als EJB‘s gelöst werden. Der Aufruf dieser EJBs kann über
Konsolprogramme, SWING Programme und Web Komponenten (Servlet, JSP, JSF) erfolgen.
1
Nach einiger Überlegung würde sich für dieses speziell konstruierte Szenario auch noch ein Web-Service anbieten.
18.05.17 8:44
2
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Übersicht JEE
JEE – Java Enterprise Edition ist ein Standard für die Programmierung verteilter
Anwendungen.
Wann ist eine Anwendung verteilt?
Wenn Client und Server auf verschiedenen Rechnern laufen. Verteilung liegt aber auch
dann vor, wenn Client und Server zwar auf dem gleichen Rechner aber in
verschiedenen VM’s laufen.
Client nutzt einen Dienst der auf einem Server läuft.
Diese serverseitigen Programme sind sogenannte Enterprise Java Beans (EJB’s).
Arten von Beans:
 Session Beans – local und remote (Session = Sitzung)
o Stateless Session Beans
o Stateful Session Beans
 Message Driven Beans
 Entities
 Java Message Service
 Timer Service
 Web Services (Stateless Session Beans mit @Annotations)
Clients:
 Konsolprogramme
 andere EJB’s
 GUI Programme (SWING)
 Web Components (JSF/JSP/Servlet)
18.05.17 8:44
3
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Inhaltsverzeichnis
JEE - Business Component Developer Seminar ..................................................................................2
Übersicht JEE ..................................................................................................................................3
Inhaltsverzeichnis ................................................................................................................................4
Vorbereitung ........................................................................................................................................6
Software installieren ........................................................................................................................6
Projekte vorbereiten .........................................................................................................................7
Teil 1 Session Beans ............................................................................................................................8
Die erste Bean – First .....................................................................................................................8
Konventioen .................................................................................................................................8
Test der Bean aus Web Komponenten.........................................................................................9
Test der Bean aus einem Konsolprogramm ...............................................................................10
Helperklasse ...............................................................................................................................12
Statless Session Beans .................................................................................................................14
Remote Stateless Session Bean – Rechner ................................................................................14
Local Stateless Session Bean – Hallo1 und Motto1 ..................................................................16
Test der Local Stateless Session Bean .......................................................................................18
Stateful Session Beans – Messwerte ...........................................................................................19
Test der Stateful Session Bean ..................................................................................................20
Aufruf einer EJB aus einer anderen EJB des selben EJB Containers ........................................21
Übung zu Session Beans (optional) ...........................................................................................21
Warenkorb .................................................................................................................................21
Teil 2 Entity Beans ............................................................................................................................22
Vorbereitung ................................................................................................................................22
Applikationsserver .....................................................................................................................22
Projekt ........................................................................................................................................24
Entity – Person1 ...........................................................................................................................25
Data Access Object – Person1Dao ...............................................................................................26
Test Person1Dao ..........................................................................................................................28
JPA (Java Persistence API) ...........................................................................................................28
Teil 3 Transaktionen ..........................................................................................................................29
CMT – Container Managed Transaction .....................................................................................29
Übung zu CMT ..........................................................................................................................30
BMT – Bean Managed Transaction .............................................................................................31
Person2Dao ................................................................................................................................32
ReiseDao ....................................................................................................................................35
Teil 4 Java Message Service ..............................................................................................................39
Funktionsweise ............................................................................................................................39
Vorbereitung für GLASSFISH4 ....................................................................................................40
Applikationsserver .....................................................................................................................40
Implementierung ........................................................................................................................41
Message Driven Bean ...................................................................................................................43
Senden........................................................................................................................................43
Empfangen .................................................................................................................................45
Teil 5 Timer Service ..........................................................................................................................46
Übung1 zu Timer Service ............................................................................................................49
Übung2 zu Timer Service (optional) .........................................................................................49
Teil 6 Web Services ...........................................................................................................................50
Service ...........................................................................................................................................50
Client..............................................................................................................................................50
18.05.17 8:44
4
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Teil 7 Life Cycle, Life Cycle Callback ..............................................................................................51
Stateless Session Bean, Message Driven Bean..............................................................................51
Life Cycle ..................................................................................................................................51
Life Cycle Callbacks..................................................................................................................51
Stateful Session Bean ....................................................................................................................52
Life Cycle ..................................................................................................................................52
Life Cycle Callbacks..................................................................................................................52
Entities ...........................................................................................................................................53
Life Cycle und Life Cycle Callbacks .........................................................................................53
Teil 8 Interzeptoren............................................................................................................................54
Teil 9 Was noch nicht behandelt wurde ............................................................................................57
LocalBeans ....................................................................................................................................57
Beans mit asynchronen Methoden .................................................................................................57
18.05.17 8:44
5
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Vorbereitung
Es wird erwartet, dass Sie ein erfahrener Java Entwickler sind und Ihre IDE im Griff haben. Sie
haben schon Java Programme unter Zuhilfenahme einer IDE geschrieben. Sie kennen SQL und
können einigermassen mit Datenbanken umgehen.
In diesem Abschnitt werden wir unsere Vorbereitungsarbeiten erledigen.
Software installieren
1) Java 1.8
Downloaden Sie Java 1.8 JDK aus dem Internet
Installieren Sie Java 1.8 JDK
Setzen der Umgebungsvariablen $JAVA_HOME und $PATH
2) APPLIKATIONSSERVER
Downloaden Sie GLASSFISH Full Platform aus dem Internet
Entzippen Sie GLASSFISH in das Verzeichnis __BCDS/utils
Starten Sie GLASSFISH mittels .../bin/startserv.bat
Stoppen Sie GLASSFISH mittels .../bin/stopserv.bat
Testen Sie in einem Browser
http://localhost:8080, http://localhost:4848
3) DATENBANK
Downloaden Sie die Datenbank H2 aus dem Internet
Kopieren Sie aus .../bin die Jar-Datei h2-1.3.176.jar in das Verzeichnis
Starten Sie H2 indem die h2-1.3.166.jar doppelklicken
Setzen Sie für den User sa das Passwort auf sa
alter user sa set password 'sa'
Stoppen Sie H2
rechtsklick H2 Icon im System Tray - exit
4) ECLIPSE JEE
Downloaden Sie ECLIPSE aus dem Internet
Entzippen Sie ECLIPSE in das Verzeichnis
Starten und Stoppen Sie ECLIPSE
__BCDS/lib
__BCDS/utils
__BCDS/workspace
Fügen Sie dem Eclipse den Glassfish Applikationsserver hinzu:
 die Glassfish Tools
Server
new/Server/Oracle/GlassFish Tools next accept finish restart
 den Glassfish Applikationsserver
Server
new/Server/GlassFish/GlassFish4
next
Location: .../utils/glassfish4/glassfish
next next finish
 Starten und Stoppen sie den Glassfish Server aus Eclipse
Server
GlassFish 4 at localhost [domain1] rechtsklick
Start/Restart/Stop
18.05.17 8:44
6
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Projekte vorbereiten
Wir benötigen in Eclipse folgende Projekte
1) bcdsEJB
das Projekt für die Enterprise Java Beans
New / Other / EJB / EJB Project
Project Name: bcdsEJB
Next / Next
Set Generate ejb-jar.xml deployment descriptor
Finish
2) bcdsWEB
das Projekt für den WebTest der EJB’s
New / Other / Web / Dynamic Web Project
Project Name: bcdsWEB
Next / Next
Set Generate web.xml deployment descriptor
Finish
3) bcdsEAR
das Enterprise Archiv für EJB und WEB
New / Other / Java EE / Enterprise Application Project
Project Name: bcdsEAR
Next
Java EE module dependencies
Set bcdsEJB
Set bcdsWEB
Set Generate application.xml deployment descriptor
Finish
4) bcdsXTest
das Projekt für die Remote Tests der EJB’s
New / Other / Java / Java Project
Project Name: bcdsXTest
Finish
18.05.17 8:44
7
JEE – Business Component Developer Seminar
Johann Mildner, Basel
Teil 1 Session Beans
Die erste Bean – First
Die erste Enterprise Java Bean dient uns dem Kennenlernen der Konventionen.
Ein Dienst besteht aus einem Interface und seiner Implementierung.
Unser erster Dienst soll First heissen und eine Methoden anbieten, die einen String
übernimmt und diesen als Echo wieder ausgibt.
Konventioen
Name des Dienstes:
Interface:
Implementierung:
Methode(n):
First
FirstBeanRemote.java
FirstBean.java
String echo(String s)
interfaces/FirstBeanRemote.java
package ch.bcds1.interfaces;
@Remote
public interface FirstBeanRemote
{
String echo(String s) ;
}
beans/FirstBean.java
package ch.bcds1.beans;
@Stateless
public class FirstBean implements FirstBeanRemote
{
@Override
public String echo(String s)
{
return s + "/" + s ;
}
}
18.05.17 8:44
8
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Test der Bean aus Web Komponenten
Die können die Beans sowohl aus einem Servlet als auch aus einem JSP aufrufen.
Schreiben Sie Ihre Web Komponenten in ein eigenes Web Projekt (bcdsWEB).
Damit der Compile fehlerfrei laufen kann müssen die Glassfish.libs und die Interfaces und
Entities im CLASSPATH verfügbar sein
Projects
Add
bcdsEJB
Beispiel für Servlet
FirstServlet.java
package ch.bcds1.servlet;
@WebServlet("/FirstServlet")
public class FirstServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
@EJB
private FirstBeanRemote bean;
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException
{
response.setHeader("Content-Type", "text/html");
PrintWriter pw = response.getWriter();
pw.println("<h1>FirstServlet</h1>");
pw. println (bean.echo("hallo aus einem Servlet"));
}
}
Beispiel für JSP
firstJsp.jsp
<%@ page import="javax.naming.*,ch.bcds1.interfaces.*,ch.bcds.tools.*"%>
<h1>FirstJSP</h1>
<%
InitialContext ctx = new InitialContext();
String LOOKUP_NAME =
"java:global/bcdsEAR/bcdsEJB/FirstBean!ch.bcds1.interfaces.FirstBeanRemote";
FirstBeanRemote bean = (FirstBeanRemote) ctx.lookup(LOOKUP_NAME);
out.println(bean.echo("hallo aus jsp"));
%>
18.05.17 8:44
9
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Test der Bean aus einem Konsolprogramm
Schreiben Sie Ihre Tests in ein eigenes Testprojekt (bcdsXTest).
FirstTest.java
package ch.bcds1.test;
public class FirstTest
{
public static void main(String[] args) throws NamingException
{
/**
* 1.
*
* <code>
*
damit die Imports funktionieren ist folgendes erforderlich
*
*
Properties / Java Build Path
*
*
Libraries / Add External JARs
*
$GLASSFISH/lib/gf-client.jar
*
*
Projects
*
Add
*
bcdsEJB
* </code>
*/
/* 2. Context erstellen */
InitialContext ctx = new InitialContext();
/* 3. Lookup und Bean fuellen */
final String LOOKUP_NAME =
"java:global/bcdsEAR/bcdsEJB/FirstBean!ch.bcds1.interfaces.FirstBeanRemote";
FirstBeanRemote bean = (FirstBeanRemote) ctx.lookup(LOOKUP_NAME);
/* 4. Aufruf der EJB Methode(n) */
System.out.println(bean.echo("hallo"));
}
}
18.05.17 8:44
10
Johann Mildner, Basel
JEE – Business Component Developer Seminar
1) Damit der Compile fehlerfrei laufen kann müssen die Glassfish.libs und die Interfaces
und Entities im CLASSPATH verfügbar sein
a. gf-client.jar aus $GLASSFISH/lib
(Libraries/Add External JARs
b. die Interfaces und Entities aus bcdsEJB (Projects Add)
2) Damit die Referenz auf den Context des Applikationsservers ermittelt werden kann, ist
die Datei jndi.properties nötig. Diese Datei mus im CLASSPATH gefunden werden. Es
bietet sich an, ein Source Verzeichnis resources zu erstellen.
Eventuell nicht mehr nötig. (19.12.2016)
resources/jndi.properties
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
3) Der Aufbau des LOOKUP_NAME ist für alle Applikationsserver unterschiedlich.
Glassfish hat den folgenden Aufbau:
java:global/appName/modulName/BeanName!path.InterfaceName oder
java:global/modulName/BeanName!path.InterfaceName
java:global/bcdsEAR/bcdsEJB/FirstBean!ch.bcds.interfaces.FirstBeanRemote
kann und soll in einer Helper Klasse erfolgen
18.05.17 8:44
11
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Helperklasse
Schreiben Sie für Ihre Tests zur Ermittlung der Bean Referenz in das bcdsWEB Projekt eine
Helperklasse. Die Helperklasse kann auch in bcdsXTest genutzt werden.
Helper.java
package ch.bcds.tools;
public final class Helper
{
public final static String makeLookupName(final String BEAN_NAME,
final String INTERFACE_NAME)
{
/**
* Beispiel des Lookup Namens fuer den Service "First"
* <code>
*
java:global
*
/bcdsEAR
Appliation Name
*
/bcdsEJB
Modul Name
*
/FirstBean
Bean Name
*
!ch.bcds.interfaces.FirstBeanRemote
Interface Name
* </code>
*
* Da Application Name und Modul Name fuer das gesamte Project
* gleich sind, werden sie fest "verdrahtet"
*/
final String APP_NAME = "/bcdsEAR";
final String MOD_NAME = "/bcdsEJB";
return "java:global" + APP_NAME + MOD_NAME
+ "/" + BEAN_NAME + "!" + INTERFACE_NAME;
}
public static Object lookup(final String BEAN_NAME, final String INTERFACE_NAME)
{
try
{
return new InitialContext()
.lookup(makeLookupName(BEAN_NAME, INTERFACE_NAME));
}
catch (NamingException e)
{
e.printStackTrace();
return null;
}
}
}
18.05.17 8:44
12
Johann Mildner, Basel
JEE – Business Component Developer Seminar
In den folgenden Testprogrammen soll das Füllen der EJB Referenz auf folgende Art gemacht
werden.
...
FirstBeanRemote bean = (FirstBeanRemote) Helper.lookup("FirstBean",
"ch.bcds1.interfaces.FirstBeanRemote");
...
18.05.17 8:44
13
JEE – Business Component Developer Seminar
Johann Mildner, Basel
Statless Session Beans
Remote Stateless Session Bean – Rechner
Das nächste EJB wird ein Dienst sein, der die vier Grundrechnungsarten anbietet.
Name des Dienstes:
Interface:
Implementierung:
Methode(n):
Rechner
RechnerBeanRemote
RechnerBean
double add(double a, double b)
double sub(double a, double b)
double mult(double a, double b)
double dib(double a, double b)
interfaces/RechnerBeanRemote.java
package ch.bcds1.interfaces;
@Remote
public interface RechnerBeanRemote
{
double add(double a, double b);
double sub(double a, double b);
double mult(double a, double b);
double div(double a, double b);
}
beans/RechnerBean.java
package ch.bcds1.beans;
@Stateless
public class RechnerBean implements RechnerBeanRemote
{
@Override
public double add(double a, double b)
{
return a + b;
}
@Override
public double sub(double a, double b)
{
return a - b;
}
…
}
18.05.17 8:44
14
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Interface:
@Remote
public interface RechnerBeanRemote
Die Annotation @Remote bewirkt dass der Dienst zu einem Dienst wird, der von einem
entfernten Client aufgerufen werden kann.
@Local bedeutet dass der Dienst nur aus einem Programm, das im selben AS läuft, aufgerufen
werden kann (z.B. aus einer anderen EJB).
Implementierung
@Stateless
public class RechnerBean implements RechnerBeanRemote
Die Annotation @Stateless bewirkt, dass der Dienst keinen Status speichert. Das heisst, dass
keine Attribute erlaubt sind die über mehrere Methodenaufrufe benötigt werden.
@Stateful bedeutet, das die Bean Daten über mehrere Methodenaufrufe behält.
Der Klient hat immer die selbe Referenz der Bean.
Schreiben Sie Tests (Konsolprogramm, JSP, Servlet)
18.05.17 8:44
15
JEE – Business Component Developer Seminar
Johann Mildner, Basel
Local Stateless Session Bean – Hallo1 und Motto1
Als zweites EJB werden wir einen Dienst erstellen, der eine Hallo Meldung zurückgibt. Dieser
Dienst soll wie der vorherige, Remote sein.
Die Hallo Bean soll aber einen weiteren Dienst nutzen. Und zwar soll zu jedem Hallo ein
Motto des Tages mitgegeben werden. Dieses Motto soll von einem lokalen Dienst ermittelt
werden (Zufallsprinzip).
Es sollen zwei Dienste erstellt werden.
Name des Dienstes:
Interface:
Implementierung:
Methode(n):
Motto1
Motto1BeanLocal
Motto1Bean
String getMotto()
(Local, Stateless)
Motto1BeanLocal.java
package ch.bcds1.interfaces;
@Local
public interface Motto1BeanLocal
{
String getMotto();
}
Motto1Bean.java
package ch.bcds1.beans;
@Stateless
public class Motto1Bean implements Motto1BeanLocal
{
private String[] motto = {"luegen haben kurze beine", "eile mit weile", "…") ;
@Override
public String getMotto()
{
return motto[(int) (Math.random() * motto.length)];
}
}
18.05.17 8:44
16
JEE – Business Component Developer Seminar
Johann Mildner, Basel
Name des Dienstes:
Interface:
Implementierung:
Methode(n):
Hallo1
(Remote, Stateless)
Hallo1BeanRemote
Hallo1Bean
String sagHallo()
String sagByeBye()
Hallo1BeanRemote.java
package ch.bcds1.interfaces;
@Remote
public interface Hallo1BeanRemote
{
String sagHallo();
}
Hallo1Bean.java
package ch.bcds1.beans;
@Stateless
public class Hallo1Bean implements Hallo1BeanRemote
{
@EJB
private Motto1BeanLocal motto;
}
@Override
public String sagHallo()
{
return "Hallo Welt: " + motto.getMotto();
}
18.05.17 8:44
17
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Test der Local Stateless Session Bean
Eine Bean mit der Annotaion @Local kann nur von einem Client, der innerhalb des
Applikationsservers läuft, aufgerufen werden. Es sind dies andere Beans, Java Server Faces,
Servlets, Backing Beans aus JSP oder JSF Projects ...
In unserem Fall von der EJB Hallo1Bean.
Es ist dazu eine Deklaration mit Annotation nötig.
@EJB
private Motto1BeanLocal motto;
Dies bewirkt dass motto durch Dependency Injection zum Zeitpunkt des Erzeugens des
Hallo1Beans gefüllt wird
Motto1BeanLocal muss nicht jedes mal neu erzeugt werden. Versehen Sie diese Bean mit
@Singleton.
Fügen Sie der Hallo1Bean eine fortlaufende ID und einen Zähler hinzu.
Füllen Sie die ID in einer Methode mit der Annotation @PostConstruct
indem Sie static int anzahl um 1 hochzählen.
Geben Sie bei jedem Aufruf von getHallo() die ID und den um 1 erhöhten Zähler mit der
Meldung aus.
Testen Sie in einer Schleife – was stellen Sie fest?
Testen Sie parallel (mehrere Threads) – was stellen Sie jetzt fest?
Ändern Sie @Stateless des Hallo1Beans auf @Stateful.
Testen Sie nochmals. Besser?
18.05.17 8:44
18
JEE – Business Component Developer Seminar
Johann Mildner, Basel
Stateful Session Beans – Messwerte
Was wenn ein Dienst benötigt wird, der sich Zustände über mehrere Methodenaufrufe
hinweg merken soll. Sammeln von Messwerten zum Beispiel.
Dann verwendet man Stateful Session Beans.
Name des Dienstes:
Interface:
Implementierung:
Methode(n):
Messwerte
(Remote, Stateful)
MesserteBeanRemote
MesswerteBean
void einfuegen(int key, int value)
Map<Integer, Integer> getMesswerte()
Die Methode einfuegen() dient dem Sammeln der Messwerte und soll beliebig oft aufgerufen
werden können.
Die Methode getMesswerte() dient dem Holen aller bisher gesammelten Messwerte. Diese
Methode soll die Bean beenden (@Remove).
Nach dem Aufruf dieser Methode ist die Bean nicht mehr verfügbar sein.
MesswerteBeanRemote.java
package ch.bcds1.interfaces;
@Remote
public interface MesswerteBeanRemote
{
void einfuegen(int key, int value);
Map<Integer, Integer> getMesswerte();
}
MesswerteBean.java
package ch.bcds1.beans;
@Stateful
public class MesswerteBean implements MesswerteBeanRemote
{
private Map<Integer, Object > messwerte = new TreeMap<Integer, Integer >();
@Override
public void einfuegen(int key, int value)
{
messwerte.put(key, value);
}
}
@Override
@Remove
public Map<Integer, Integer > getMesswerte()
{
return messwerte;
}
18.05.17 8:44
19
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Test der Stateful Session Bean
MesswerteTest.java
package ch.bcds1.test;
public class MesswerteTest
{
static final Logger LOG = Logger.getLogger(MesswerteTest.class);
public static void main(String[] args) throws Exception
{
LOG.info("Programmstart");
MesswerteBeanRemote messwerte = (MesswerteBeanRemote) getBean();
for (int i = 11; i <= 20; i++)
messwerte.einfuegen(i, (int) (Math.random() * 1000000));
MyTools.pause();
Map<Integer, Integer> messwerteMap = messwerte.getMesswerte();
for (Map.Entry<Integer, Integer> me : messwerteMap.entrySet())
{
LOG.info(me.getKey() + " / " + me.getValue());
}
}
}
LOG.info("Programmende");
private static Object getBean()
{
return Helper.lookup("MesswerteBean",
"ch.bcds1.interfaces.MesswerteBeanRemote");
}
18.05.17 8:44
20
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Aufruf einer EJB aus einer anderen EJB des selben EJB Containers

Dependency Injection (die zu bevorzugende Art)
@EJB
BeanInterfaceName bn;

Normaler Lookup
Context ctx = new InitialContext();
BeanInterfaceName bn= (BeanInterfaceName)context.lookup(LOOKUP_NAME);
Übung zu Session Beans (optional)
Warenkorb
Zu erstellende Artefakte:
1. Warenkorb.java
(Interface und Bean)
a. einfuegenArtikel(id,bez,preis,stueck)
die Artikel werden in eine TreeMap eingefügt
b. bestellungAbschliessen
es wird eine Lieferschein geschrieben (in Datenbank) – ab dann ist die
EJB nicht mehr verfügbar
2. testWarenkorb.jsp
Es werden solange Artikel eingefügt, bis die Bestellung abgeschlossen wird.
3. TestWarenkorb.java
Ähnlich jsp aber als Massentest von der Konsole aufgerufen.
18.05.17 8:44
21
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Teil 2 Entity Beans
Wir wollen Java Objekte dauerhaft in einer relationalen Datenbank speichern,
Datenbanksätze sollen gelesen und in Java Objekten gespeichert werden.
Relational nach Objektorientiert und vice versa.
JEE bietet diese Möglichkeit über das JPA (Java Persistence API).
Vorbereitung
Applikationsserver
Im Verzeichnis $GLASSFISH_HOME/domains/domain1/lib benötigt es die JAR Datei für die
Datenbank.
 h2-1.3.176.jar
 postgresql-9.4-1208.jar
 oracle.jar
 mysql.jar
aus $GLASSFISH_HOME/bin sind folgenede Funktionen aufzurufen
(Glassfish muss gestartet sein)
H2
./asadmin
create-jdbc-connection-pool
--datasourceclassname org.h2.jdbcx.JdbcDataSource h2Pool
./asadmin
create-jdbc-resource
--connectionpoolid h2Pool jdbc/h2
ORACLE
./asadmin
create-jdbc-connection-pool
--datasourceclassname oracle.jdbc.pool.OracleDataSource oraclePool
./asadmin
create-jdbc-resource
--connectionpoolid oraclePool jdbc/oracle
POSTGRES
./asadmin
create-jdbc-connection-pool
--datasourceclassname org.postgresql.ds.PGSimpleDataSource postgresPool
./asadmin
create-jdbc-resource
--connectionpoolid postgresPool jdbc/postgres
18.05.17 8:44
22
Johann Mildner, Basel
JEE – Business Component Developer Seminar
in der Server Administration Console http://localhost:4848 ist folgendes durchzuführen
H2
Passwort muss gesetzt werden :
alter user sa set password 'sa'
Resources
JDBC
JDBC Connection Pools
h2Pool
Additional Properties
url
jdbc:h2:tcp://localhost/~/test
password
sa
user
sa
POSTGRES
Resources
JDBC
JDBC Connection Pools
postgresPool
Additional Properties
url
jdbc :postgresql://localhost :5432/jees
password
jees
user
jees
ORACLE
Resources
JDBC
JDBC Connection Pools
oraclePool
Additional Properties
url
jdbc:oracle:thin:@localhost:1521:xe
password
jees
user
jees
PING muss OK sein !!!
18.05.17 8:44
23
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Projekt
Im Verzeichnis META-INF benötigt es eine Datei
 persistence.xml
Am besten macht man dies über ECLIPSE – Configure/Convert to JPA Project
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<!-- eclipselink.ddl-generation = none | create-tables | drop-and-create-tables -->
<!-- eclipselink.logging.level = all/off/severe/warning/info/config/fine/finer/finest -->
<!-- eclipselink.ddl-generation.output-mode = sql-script|database|both -->
<persistence-unit name="bcds" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/h2</jta-data-source>
<properties>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.logging.level" value="WARNING" />
<property name="eclipselink.drop-ddl-jdbc-file-name"
value="drop.sql" />
<property name="eclipselink.create-ddl-jdbc-file-name"
value="create.sql" />
<property name="eclipselink.ddl-generation.output-mode" value="both" />
</properties>
</persistence-unit>
<!-<jta-data-source>jdbc/h2</jta-data-source>
<jta-data-source>jdbc/postgres</jta-data-source>
<jta-data-source>jdbc/mysql</jta-data-source>
<jta-data-source>jdbc/oracle</jta-data-source>
-->
</persistence>
18.05.17 8:44
24
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Entity – Person1
In unserem ersten Beispiel werden wir die Entität Person1 erzeugen.
Person1.java
package ch.bcds.entities;
@Entity
public class Person1 implements Serializable
{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue
Long id;
@Column(length = 50)
private String name;
public Person1()
{
}
public Person1(String name)
{
this.name = name;
}
// getter, setter, toString()
}
Bis auf die Annotationen ist die Klasse Person ein POJO und kann auch als ganz normales Java
Objekt benutzt werden.
Für den Zugriff auf die Datenbank ist ein Data Access Object (DAO) erforderlich, das unter
Zuhilfenahme des EntityManagers das O/R Mapping macht.
Das DAO ist eine Stateless Session Bean.
18.05.17 8:44
25
JEE – Business Component Developer Seminar
Johann Mildner, Basel
Data Access Object – Person1Dao
Name des Dienstes:
Interface:
Implementierung:
Methode(n):
Person1Dao
(Remote, Stateless)
Person1DaoBeanRemote
Person1DaoBean
Long
create(String name)
Person1
find(Long id)
List<?>
findAll();
int
deleteAll();
Person1DaoBeanRemote.java
package ch.bcds2.interfaces;
@Remote
public interface Person1DaoBeanRemote
{
Long create(String name);
Person1 find(Long id);
List<?> findAll();
int deleteAll();
}
18.05.17 8:44
26
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Person1DaoBean.java
package ch.bcds2.beans;
@Stateless
public class Person1DaoBean
implements Person1DaoBeanRemote, Serializable
{
private static final long serialVersionUID = 1L;
@PersistenceContext // (unitName = "bcds")
private EntityManager em;
@Override
public int deleteAll()
{
return em.createQuery("delete from Person1 p").executeUpdate();
}
public Long create(String name)
{
Person1 p = new Person1(name);
em.persist(p);
return p.getId();
}
public Person1 find(Long id)
{
return em.find(Person1.class, id);
}
public List<?> findAll()
{
Query query = em.createQuery("select p from Person1 p");
return query.getResultList();
}
}
18.05.17 8:44
27
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Test Person1Dao
Person1DaoTest.java
package ch.bcds2.test;
public class Person1DaoTest
{
static final Logger LOG = Logger.getLogger(Person1DaoTest.class);
public static void main(String[] args) throws NamingException
{
LOG.info("Programmstart");
Person1DaoBeanRemote bean = (Person1DaoBeanRemote) getBean();
// EJB Methoden aufrufen
for (int i = 1; i <= 2; i++)
{
Long id = bean.create(Helper.getName());
Person1 p = bean.find(id);
LOG.info(p);
}
List<?> personen = bean.findAll();
for (Object o : personen)
{
Person1 person = (Person1) o;
LOG.info(person);
}
LOG.info("Programmende");
}
}
JPA (Java Persistence API)
Siehe separater Lehrgang.
18.05.17 8:44
28
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Teil 3 Transaktionen
CMT – Container Managed Transaction
Ohne dass es sichtbar geworden wäre, haben wir bereits im vorigen DB Beispiel
Transaktionen verwendet. Sie wurden automatisch vom EJB-Container initiiert und
geschlossen
Jede Methode einer Bean läuft standardmässig als Transaktion.
Über die Annotation @TransactionManager kann man steuern, ob der Container oder die
Bean die Transaktion steuert.
Standardmässig ist Typ Container eingestellt und der Entwickler muss keine Vorkehrungen
treffen.
Der Transaktionsschutz bezieht sich nur auf die Datenbank und nicht auf den Zustand der
Java Klassen im Hauptspeicher (Heap).
Wenn eine Methode einer SessionBean vom Client aufgerufen wird, startet eine Transaktion
die alles was der EntityManager macht aufzeichnet.
Am Ende der Methode wird ein Commit abgesetzt. Im Fehlerfall ein Rollback.
Standardannahme: Jede Methode die von einem Client aufgerufen wird benötigt
Transaktionsschutz.
Dieses Standardverhalten kann geändert werden
Man versieht die Klasse oder ausgewählte Methoden mit einer Annotation.
@TransactionAttribute(TransactionAttributeType.TYPE)
Mögliche Typen
 REQUIRED Standardannahme
o Die Methode benötigt Transaktionsschutz – ist beim Aufruf schon eine
Transaktion aktiv, wird diese genutzt, sonst wird eine neue Transaktion
gestartet
 REQUIRED_NEW
o Die Methode benötigt eine neue Transaktion – ist beim Aufruf schon eine
Transaktion aktiv, wird diese suspendiert und eine neue Transaktion gestartet.
Nach Ende der neuen Transaktion wird die suspendierte Transaktion
weitergenutzt.
 SUPPORTS
o Unterstützt Transaktionen, benötigt aber keine. Läuft unter einer ev.
bestehenden Transaktion – startet aber keine neue.
 NOT_SUPPORTED
o Eine ev. bestehende Transaktion wird suspendiert und wieder gestartet..
 MANDATORY
o Transaktionsschutz muss schon beim Aufruf bestehen.
 NEVER
o Es darf kein Transaktionsschutz bestehen.
Benötigt man in einer Methode keinen Transaktionsschutz weil man keine Datenbankzugriffe
macht oder weil in der Datenbank nur gelesen wird, sollte man NOT_SUPPORTED verwenden.
In jedem Fall startet und beendet der Container die Transaktionen.
18.05.17 8:44
29
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Übung zu CMT
Erstellen Sie Hallo2 mit Motto2
Spielen Sie mit sagHallo() und getMotto() herum.
Folgende Kombinationen müssen einen Fehler bringen
sagHallo() – NEVER
getMotto() – MANDATORY
sagHallo() – REQUIRED
getMotto() – NEVER.
18.05.17 8:44
30
JEE – Business Component Developer Seminar
Johann Mildner, Basel
BMT – Bean Managed Transaction
Man kann die Steuerung von Transaktionen auch der Bean überlassen.
Man versieht die Bean Klasse mit einer Annotation.
@TransactionManagement(TransactionManagementType.BEAN)
Mögliche Typen:
 CONTAINER
 BEAN
Standardannahme
Die Klasse muss Stateful sein und muss in den Besitz einer Instanz der Klasse
UserTransaction kommen.
Möglichkeiten
1. @Resource
UserTransaction ut;
// zu bevorzugen!
2. @Resource
SessionContext ctx;
3. UserTransaction ut = ctx.getUserTransaction();
InitialContext ctx = new InitialContext();
UserTransaction ut = (UserTransaction)
ctx.lookup("java:comp/env/UserTransaction");
Mit dieser Referenz kann man nun die Transaktion selbst steuern
@PersistenceContext
EntityManager em;
@Resource
SessionContext ctx;
ut.begin();
…
em.xxx()
…
if(fehler)
ut.rollback();
else
ut.commit();
18.05.17 8:44
31
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Person2Dao
Ein Programm macht dialoggesteuert einen Insert und anschliessend einen Update.
Danach wird entschieden ob ein Commit oder ein Rollback durchgeführt werden soll.
Person2.java
package ch.bcds3.entities;
@Entity
public class Person2 implements Serializable
{
@Id @GeneratedValue
Long id;
@Column(length = 50)
private String name;
public Person2()
{
}
public Person2(String name)
{
this.name = name;
}
}
// getter, setter, toString()
Person2DaoBeanRemote.java
package ch.bcds3.interfaces;
@Remote
public interface Person2DaoBeanRemote
{
Person2 insert(String name);
Person2 update(Person2 person);
Person2 find(Long id);
void start() throws Exception;
void stoppCommit() throws Exception;
void stoppRollback() throws Exception;
void beanDiscard() throws Exception;
}
18.05.17 8:44
32
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Person2DaoBean.java
package ch.bcds3.beans;
@Stateful
@TransactionManagement(TransactionManagementType.BEAN)
public class Person2DaoBean implements Person2DaoBeanRemote, Serializable
{
@PersistenceContext
EntityManager em;
@Resource
UserTransaction ut;
@Override
public Person2 insert(String name) {
Person2 p = new Person2(name);
em.persist(p);
return p;
}
@Override
public Person2 find(Long id) {
return em.find(Person2.class, id);
}
@Override
public Person2 update(Person2 p) {
p = em.merge(p);
return p;
}
@Override
public void start() throws Exception {
ut.begin();
}
@Override
public void stoppCommit() throws Exception {
ut.commit();
}
@Override
public void stoppRollback() throws Exception {
ut.rollback();
}
@Override
@Remove
public void beanDiscard() throws Exception {
System.out.println(this.getClass() + " @Remove beanDiscard aufgerufen ...");
}
}
18.05.17 8:44
33
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Person2DaoTest.java
package ch.bcds3.test;
public class Person2DaoTest1
{
static final Logger LOG = Logger.getLogger(Person2DaoTest1.class);
public static void main(String args[]) throws Exception
{
Person2DaoBeanRemote bean = (Person2DaoBeanRemote) getBean();
String name = MyTools.getString("name > ");
bean.start();
Person2 p1 = bean.insert(name + "-1");
Person2 p2 = bean.insert(name + "-2");
LOG.info(p1);
LOG.info(p2);
MyTools.pause();
bean.stoppCommit();
bean.start();
p1.setName(p1.getName() + "-neu1");
bean.update(p1);
p2.setName(p2.getName() + "-neu2");
bean.update(p2);
LOG.info(p1);
LOG.info(p2);
MyTools.pause();
String ok = MyTools.getString("ok j/n > ");
if (ok.equals("j"))
{
bean.stoppCommit();
}
else
{
bean.stoppRollback();
}
MyTools.pause();
p1 = bean.find(p1.getId());
p2 = bean.find(p2.getId());
LOG.info(p1);
LOG.info(p2);
}
bean.beanDiscard();
}
18.05.17 8:44
34
Johann Mildner, Basel
JEE – Business Component Developer Seminar
ReiseDao
In diesem Programm soll optimistisches Locking gezeigt werden.
1. Es sind 10 Reisen oder Flüge oder Cabinen verfügbar.
2. Es sollen mehrere Threads dialoggesteuert die gleiche Reise auswählen.
3. Der erste Update ist OK.
4. Der zweite Update muss den Client über den konkurrierenden Zugriff benachrichtigen.
Reise.java
package ch.bcds3.entities;
@Entity
public class Reise implements Serializable
{
@Id @GeneratedValue
@Column(unique = true, length = 50)
@Column(unique = false, length = 50)
@Version
public Reise()
public Reise(String destination)
}
Long id;
private String destination;
private String teilnehmer;
private int version;
{}
{this.destination = destination;}
// getter, setter, toString()
ReiseDaoBeanRemote.java
package ch.bcds3.interfaces;
@Remote
public interface ReiseDaoBeanRemote
{
List<?> findAll();
List<?> findVerfuegbareReisen();
Reise find(Long id);
Reise persist(Reise r);
Reise update(Reise r);
void init();
void delete();
}
18.05.17 8:44
35
Johann Mildner, Basel
JEE – Business Component Developer Seminar
ReiseDaoBean.java
package ch.bcds3.beans;
@Stateless
public class ReiseDaoBean implements ReiseDaoBeanRemote
{
@PersistenceContext // (unitName = "jeesPostgres")
private EntityManager em;
@Override
public List<?> findAll()
{
Query query = em.createQuery(
"select r from Reise r order by r.id");
return query.getResultList();
}
@Override
public List<?> findVerfuegbareReisen()
{
Query query = em.createQuery(
"select r from Reise r where r.teilnehmer is null order by r.id");
return query.getResultList();
}
@Override
public Reise update(Reise reise)
{
reise = em.merge(reise);
return reise;
}
@Override
public Reise persist(Reise reise)
{
em.persist(reise);
return reise;
}
@Override
public void delete()
{
Query q = em.createQuery("delete from Reise r");
int anzahl = q.executeUpdate();
System.out.println("geloescht " + anzahl);
}
18.05.17 8:44
36
Johann Mildner, Basel
JEE – Business Component Developer Seminar
@Override
public void init()
{
Query q = em.createQuery(
"select count(r.id) from Reise r where r.teilnehmer is null");
Long anzahl = (Long) q.getSingleResult();
if (anzahl > 0)
return;
delete();
System.out.println("init aufgerufen !!!");
em.persist(new Reise("London"));
em.persist(new Reise("Paris"));
em.persist(new Reise("Vaduz"));
em.persist(new Reise("Wien"));
em.persist(new Reise("Muenchen"));
em.persist(new Reise("Budapest"));
em.persist(new Reise("Athen"));
em.persist(new Reise("Barcelona"));
em.persist(new Reise("Lissabon"));
em.persist(new Reise("Prag"));
}
@Override
public Reise find(Long id)
{
Reise reise = em.find(Reise.class, id);
return reise;
}
18.05.17 8:44
37
Johann Mildner, Basel
JEE – Business Component Developer Seminar
ReiseDaoTest.java
package ch.bcds3.test;
public class ReiseDaoTest
{
static final Logger LOG = Logger.getLogger(ReiseDaoTest.class);
public static void main(String args[]) throws Exception
{
ReiseDaoBeanRemote bean = (ReiseDaoBeanRemote) getBean();
bean.init();
while (true)
{
List<?> reisen = bean.findVerfuegbareReisen();
for (Object r : reisen)
{
LOG.info(r);
}
long id = MyTools.getInteger("waehlen Sie eine Reise aus obiger Liste aus > ");
Reise reise = bean.find(id);
if (reise == null || reise.getTeilnehmer() != null)
{
StringBuilder fehlermeldung = new StringBuilder();
fehlermeldung.append("Reise kann nicht gebucht werden: ");
fehlermeldung.append(reise == null ? "reise==null" : reise);
LOG.info(fehlermeldung.toString());
System.out.println();
}
else
{
String name = MyTools.getString("name > ");
reise.setTeilnehmer(name);
try
{
reise = bean.update(reise);
LOG.info("Reise gebucht: " + reise);
break;
}
catch (Exception e)
{
LOG.info("Sie waren zu langsam");
}
}
}
}
}
18.05.17 8:44
38
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Teil 4 Java Message Service
Java Message Service (JMS) ist eine Programmierschnittstelle (API) für die Ansteuerung
einer Message Oriented Middleware (MOM) zum Senden und Empfangen von Nachrichten
aus einem Client heraus, der in der Programmiersprache Java geschrieben ist.
JMS hat das Ziel, lose gekoppelte, verlässliche und asynchrone Kommunikation zwischen den
Komponenten einer verteilten Anwendung zu ermöglichen.
JMS ist Teil der Java Platform, Enterprise Edition.
Für die Anwendung braucht man einen Provider, der die API umsetzt und somit den Dienst
bereitstellt.
Funktionsweise
Messaging ist eine Möglichkeit der lose gekoppelten und verteilten Kommunikation in Form
von zwischen Softwarekomponenten verschickten Nachrichten.
Messaging versucht, die sonst enge Kopplung anderer Kommunikationsmöglichkeiten
wie TCP Kommunikation über Sockets, CORBA oder RMI durch die Einführung einer zwischen
den Clients gelegenen Komponente aufzubrechen.
Damit wird sichergestellt, dass die Clients kein näheres Wissen über die Gegenstelle(n) ihrer
Kommunikation haben müssen, was sowohl den Einsatzbereich als auch die Wartung und
Wiederverwendung der Komponenten erhöht.
JMS und der durch diese angesteuerte Dienst unterstützen zwei unterschiedliche Ansätze
zum Versenden von Nachrichten. Zum einen die Nachrichtenwarteschlange (Queue) für
sogenannte point-to-point Verbindungen und zum anderen ein Anmelde-Versendesystem
(Topic) für Publish-Subscribe-Kommunikation:

Queue: Bei der Warteschlange sendet der Sender an eine Queue, an der ein Empfänger
hängt. Ist dieser nicht verfügbar, wird die Nachricht gespeichert und der Empfänger kann
sie jederzeit später abholen. Man kann dies am besten mit einem Paketdienst vergleichen.
Jede Sendung hat genau einen Empfänger. Ist dieser nicht zu Hause, kann er sich die
Sendung zu einem beliebigen Zeitpunkt später abholen. Es sind mehrere Empfänger
möglich aber nur einer bekommt das „Paket“.

Topic: Bei dem Anmelde-Versendesystem werden die Nachrichten an ein Topic geschickt,
auf das eine beliebige Anzahl von Empfängern hört. Wird die Nachricht nicht konsumiert,
weil kein Empfänger sich an das Topic angemeldet hat, dann ist dies unerheblich. Man
kann dies am besten mit einem Radiosender vergleichen (Broadcasting). Entweder man
schaltet den Radio ein und hört die Nachricht oder man lässt den Radio ausgeschaltet und
hört die Nachricht nicht.
18.05.17 8:44
39
JEE – Business Component Developer Seminar
Johann Mildner, Basel
Vorbereitung für GLASSFISH4
Applikationsserver
Glassfish muss gestartet sein!
aus $GLASSFISH_HOME/bin sind folgenede Funktionen aufzurufen
CONNECTION_FACTORY
./asadmin
create-jms-resource --restype javax.jms.ConnectionFactory jms/jeesConnectionFactory
QUEUE und TOPIC
./asadmin
create-jms-resource
./asadmin
create-jms-resource
--restype
javax.jms.Queue
jms/jeesQueue
--restype
javax.jms.Topic
jms/jeesTopic
für MDB’s dürfen die jms-resourcen keine Schrägstriche beinhalten
./asadmin
create-jms-resource
./asadmin
create-jms-resource
--restype
javax.jms.Queue
jeesQueue
--restype
javax.jms.Topic
jeesTopic
Überpruefung
 localhost:4848
o JMS Resources
 Connection Factories
 Destination Resources
18.05.17 8:44
40
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Implementierung
Für die ersten Implementierungen MessageSenden und Message Empfangen sind keine EJB’s
erforderlich.
Wir senden und empfangen die ersten Messages über Standalone Programme, benötigen aber
Glassfish als Messages Service Provider.
MessagesConstants.java
package ch.bcds4.test;
public interface MessagesConstants
{
final String CF_LOOKUP_NAME = "jeesConnectionFactory";
final String DEST_LOOKUP_NAME = "jeesQueue"; // oder jeesTopic
}
MessageSenden.java
package ch.bcds4.test;
public class MessagesSenden implements MessagesConstants
{
public static void main(String args[]) throws Exception
{
Context ctx = new InitialContext();
ConnectionFactory cf = (ConnectionFactory) ctx.lookup(CF_LOOKUP_NAME);
Connection connection = cf.createConnection();
Destination dest = (Destination) ctx.lookup(DEST_LOOKUP_NAME);
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = session.createProducer(dest);
TextMessage textMessage = session.createTextMessage();
for (int i = 1; i <= 9; i++)
{
textMessage.setText(i + ". text aus einem Standalone Program");
producer.send(textMessage);
}
}
}
producer.close();
18.05.17 8:44
41
Johann Mildner, Basel
JEE – Business Component Developer Seminar
MessageEmpfangen.java
package ch.bcds4.test;
public class MessagesEmpfangen implements MessagesConstants
{
public static void main(String args[]) throws Exception
{
LOG.info("Programmstart");
Context ctx = new InitialContext();
ConnectionFactory cf = (ConnectionFactory) ctx.lookup(CF_LOOKUP_NAME);
Connection connection = cf.createConnection();
Destination dest = (Destination) ctx.lookup(DEST_LOOKUP_NAME);
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer consumer = session.createConsumer(dest);
consumer.setMessageListener(new MessageListener()
{
@Override
public void onMessage(Message message)
{
TextMessage textMessage = (TextMessage) message;
try
{
}
LOG.info(textMessage.getText());
}
catch (JMSException e)
{
e.printStackTrace();
}
});
connection.start();
System.out.println("......... Listener mit ENTER beenden ......... ");
System.in.read();
}
}
consumer.close();
session.close();
connection.close();
18.05.17 8:44
42
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Message Driven Bean
Nachdem nun alle technischen Begriffe und Vorgehensweisen im Zusammenhang mit der
Benutzung des JMS betrachtet wurden, ist es an der Zeit, die Frage zu klären, wie diese
Mechanismen in EJB’s genutzt werden können.
Senden
Senden kann man sowohl aus Main Programmen (siehe MessageSenden) als auch aus Beans.
SendMessageBeanRemote.java
package ch.bcds4.interfaces;
@Remote
public interface SendMessageBeanRemote
{
void sendQueueMessage(String text) throws Exception;
void sendTopicMessage(String text) throws Exception;
}
18.05.17 8:44
43
Johann Mildner, Basel
JEE – Business Component Developer Seminar
SendMessageBean.java
package ch.bcds4.beans;
@Stateless
public class SendMessageBean
implements SendMessageBeanRemote, Serializable
{
private static final long serialVersionUID = 1L;
@Override
public void sendTopicMessage(String text) throws Exception
{
sendMessage(text, "jeesQueue");
}
@Override
public void sendQueueMessage(String text) throws Exception
{
sendMessage(text, "jeesTopic");
}
private void sendMessage(String text, String destType)
throws NamingException, JMSException
{
Context ctx = new InitialContext();
Destination destination = (Destination) ctx.lookup(destType);
ConnectionFactory cf = (ConnectionFactory) ctx
.lookup("jms/jeesConnectionFactory");
Connection connection = cf.createConnection();
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session
.createProducer(destination);
TextMessage message = session.createTextMessage();
message.setText(text);
messageProducer.send(message);
connection.close();
}
}
18.05.17 8:44
44
JEE – Business Component Developer Seminar
Johann Mildner, Basel
Empfangen
Will man Messages in Beans empfangen, geht das nur in MessageDrivenBeans (MDB).
Eine MDB kann kurz als zustandsloser, asynchroner Nachrichtenempfänger charakterisiert
werden.
Bei genauer Betrachtung stellen wir fest, dass hier eine Stateless Session Bean vorliegt, die
nur über den Versand von Nachrichten erreichbar ist.
MDB’s sind relativ simpel aufgebaut. Sie haben genau eine Business-Methode mit dem Namen
onMessage().
Da die Bean simple ist, sind die nötigen Annotationen deutlich umfangreicher als bei anderen
Beans.
MessageDrivenBean.java
(MessageDrivenQueueBean.java, MessageDrivenTopicBean.java)
@MessageDriven
(
activationConfig=
{
@ActivationConfigProperty(
propertyName="destinationType",
propertyValue="javax.jms.Queue"),
// od. javax.jms.Topic
@ActivationConfigProperty(
propertyName="destination",
propertyValue="jeesQueue"),
// od. jeesTopic
@ActivationConfigProperty(
propertyName="acknowledgeMode",
propertyValue="Auto-acknowledge")
}
)
public class MessageDrivenXxxxxBean implements MessageListener
{
@Override
public void onMessage(Message message)
{
TextMessage m=(TextMessage) message;
try
{
}
System.out.println(m.getText());
}
catch (JMSException e)
{
e.printStackTrace();
}
}
18.05.17 8:44
45
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Teil 5 Timer Service
Kommt immer dann zum Einsatz wenn eine zeitgesteuerte Verarbeitung gewünscht wird.
Dabei kann die Anforderung etwas zu tun sein:
an einem bestimmten Zeitpunkt
oder periodisch alle x Sekunden.
Wenn die Methode aufgerufen wird, gibt es keine Verbindung zu einem Client. Es ist lediglich
ein Mal ein Anstoss von einem Client nötig. Dann ist es der AS selbst, der den Aufruf steuert.
Um einen Timer Service zu implementieren, verwendet man entweder eine
Stateless Session Bean
oder eine
Message Driven Bean
Beide ermöglichen es dem AS, sich eine beliebige Beaninstanz aus dem Method-Ready Pool zu
entnehmen, um die Timer-Methode aufzurufen.
Wir wollen alle 10 Sekunden wissen, wie viel Hauptspeicher dem AS zur Verfügung steht.
Dienstname:
Interface
Bean
Methode(n):
HauptspeicherUeberwachung
HauptspeicherUeberwachungBeanRemote.java
HauptspeicherUeberwachungBean.java
void startMonitor()
void stoppMonitor()
long getHauptspeicher()
HauptspeicherUeberwachungBeanRemote.java
package ch.bcds5.interfaces;
@Remote
public interface HauptspeicherUeberwachungBeanRemote
{
void startMonitor();
void stoppMonitor();
long getHauptspeicher() ;
}
18.05.17 8:44
46
Johann Mildner, Basel
JEE – Business Component Developer Seminar
HauptspeicherUeberwachungBean.java
package ch.bcds5.beans;
@Stateless
public class HauptspeicherUeberwachungBean
implements HauptspeicherUeberwachungBeanRemote, Serializable
{
private static final long serialVersionUID = 1L;
@Resource
private TimerService timerService;
String timerName = "HAUPTSPEICHERUEBERWACHUNG";
@Override
public void startMonitor()
{
timerService.createTimer(1 * 1000, 1 * 1000, timerName);
}
@Override
public void stoppMonitor()
{
for (Object obj : timerService.getTimers())
{
Timer timer = (Timer) obj;
String tn = (String) timer.getInfo();
}
}
if (tn.equals(timerName))
{
timer.cancel();
System.out.println(tn + ": cancelled");
break;
}
@Timeout
private void timeout(Timer time)
{
String msg = timerName + ": " + getHauptspeicher();
System.out.println(msg);
}
}
@Override
public long getHauptspeicher()
{
return Runtime.getRuntime().freeMemory();
}
18.05.17 8:44
47
Johann Mildner, Basel
JEE – Business Component Developer Seminar
HauptspeicherUeberwachungTest.java
package ch.bcds5.test;
public class HauptspeicherUeberwachungTest
{
static final Logger LOG = Logger.getLogger(HauptspeicherUeberwachungTest.class);
public static void main(String args[]) throws Exception
{
LOG.info("Programmstart");
HauptspeicherUeberwachungBeanRemote ejb =
(HauptspeicherUeberwachungBeanRemote) getBean();
LOG.info("HAUPTSPEICHER: " + String.format("%,d", ejb.getHauptspeicher()));
ejb.startMonitor();
Thread.sleep(10000);
ejb.stoppMonitor();
LOG.info("HAUPTSPEICHER: " + String.format("%,d", ejb.getHauptspeicher()));
LOG.info("Programmende");
}
}
private static Object getBean()
{
return Helper.lookup("HauptspeicherUeberwachungBean",
"ch.bcds5.interfaces.HauptspeicherUeberwachungBeanRemote");
}
18.05.17 8:44
48
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Übung1 zu Timer Service
Senden Sie die Information über den freien Speicher an das Topic jeesTopic.
Passen Sie MessagesEmpfangen an. Es sollten 10 Messages eintreffen.
Übung2 zu Timer Service (optional)
Stellen Sie sich vor, Sie haben einen Web Shop. Die Clients können Artikel in den Warenkorb
stellen. Nach der Auswahl – zur Kassa, wird die Bestellung abgeschlossen. Die
abgeschlossenen Bestellungen sollen frühestens nach einer Wartezeit von einem Halben Tag
in einem weiteren Prozess abgearbeitet werden.
Eine Möglichkeit wäre, dass der Prozess „eine Bestellung abarbeiten“ manuell gestartet
wird. Der Typ im Lager nimmt sich jeden Morgen alle noch nicht abgearbeiteten Bestellungen
vor und macht sie versandfertig.
Eine andere Möglichkeit wäre, immer nach Abschluss einer Bestellung eine Stateless Bean
aufzurufen, die einen Timer startet der nach einem Halben Tag (1000*60*60*6) die
Abarbeitung der Bestellung startet.
18.05.17 8:44
49
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Teil 6 Web Services
JEE bietet eine einfache Möglichketi Web Services zu erstellen. Dazu ist lediglich eine Remote
Stateless Session Bean mit Annotationen (@WebService, @WebMethod …) zu versehen.
Service
Echo.java
package ch.bcds6.webservices;
@Stateless
@WebService
public class Echo
{
@WebMethod
public String echo(@WebParam(name = "name") String name)
{
return "hallo " + name;
}
}
Client
Web Services können Sprachunabhängig genutzt werden.
.NETwäre möglich – haben wir aber nicht. Wir verwenden Eclipse.
Erstellen Sie ein JavaProjekt bcdsXTestEcho und erstellen Sie folgende Files:
1. generieren Sie in Ihrem Echo Testprojekt die benötigten Files
new / other / WebServices / WebServiceClient
Server definition : browse
http://localhost:8080/EchoService/Echo?wsdl
OK
FINISH
2. src/ch.bcds.test/TestEchoClient.java
EchoServiceClient.java
package ch.bcds6.test;
public class EchoClient
{
public static void main(String[] args) throws Throwable
{
EchoService service = new EchoServiceLocator();
Echo echo = (Echo) service.getEchoPort();
System.out.println(echo.echo("fritz"));
}
}
18.05.17 8:44
50
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Teil 7 Life Cycle, Life Cycle Callback
Stateless Session Bean, Message Driven Bean
Life Cycle
NICHT EXISTENT
neue Anfrage
AKTIVIERT
sehr lange inaktiv
ZERSTÖRT
Life Cycle Callbacks
 @PostConstruct
o Nach der Initialisierung der Bean
 @PreDestroy
o Kurz vor der Zerstörung der Bean
Dienstname:
Interface:
Bean:
Methoden:
18.05.17 8:44
LifeCycleSL
LifeCycleSLBeanRemote
LifeCycleSLBean
echo()
51
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Stateful Session Bean
Life Cycle
NICHT EXISTENT
neue Anfrage
AKTIVIERT
länger inaktiv oder der Server benötigt Ressourcen
PASSIVIERT (auf Festplatte ausgelagert)
erneute Anfrage oder sehr lange inaktiv (Timeout)
AKTIVIERT
sehr lange inaktiv (Timeout) oder @Remove
ZERSTÖRT
Life Cycle Callbacks
Wenn man Ressourcen wie JDBC, Messaging usw. verwendet, dann muss man ggf. zu
verschiedenen Zeitpunkten Ressourcen initialisieren oder freigeben.
Hierzu verwendet man die Life Cycle Callback Methoden, die automatisch aufgerufen werden,
wenn ein bestimmter Zustand erreicht wird.
 @PostConstruct
o Nach der Initialisierung der Bean
o (z.B. Datenbank öffnen)
 @PreDestroy
o Kurz vor der Zerstörung der Bean
o (z.B. Datenbank schließen)
 @PrePassivate:
o Vor der Passivierung der Bean
o (z.B. Datenbank schliessen)
 @PostActivate:
o Nach der Aktivierung der Bean
o (z.B. Datenbank öffnen)
Dienstname:
Interface:
Bean:
Methoden:
18.05.17 8:44
LifeCycleSF
LifeCycleSFBeanRemote
LifeCycleSFBean
echo()
discardBean()
mit @Remove
52
JEE – Business Component Developer Seminar
Johann Mildner, Basel
Entities
Life Cycle und Life Cycle Callbacks
Am Beispiel Person
DOES NOT EXIST
Person p = new Person();
NEW
em.persist(p)
@PrePersist, @PostPersist
MANAGED
p=em.find()
@PostLoad
MANAGED
Wenn die Entität serialisiert und über das Netz übertragen wird
oder wenn em.detach(p) aufgerufen wird
DETACHED
em.remove(p)
@PreRemove, @PostRemove
REMOVED
em.merge(p)
@PreUpdate, @PostUpdate
MANAGED
Entity:
Person3
mit allen 7 Life Cycle Callbacks
Dienstname:
Interface:
Bean:
Methoden:
18.05.17 8:44
Person3DaoBean
Person3DaoBeanRemote
Person3DaoBean
nach Bedarf
53
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Teil 8 Interzeptoren
Wenn wir den Aufruf von Methoden protokollieren und eventuell mit einer Zeitmessung versehen
wollen, so müssen wir eine Interceptor Klasse schreiben.
SimpleInterceptorLogging.java
package ch.bcds8.interceptors;
public class SimpleInterceptorLogging
{
@AroundInvoke
public Object intercept(InvocationContext context) throws Exception
{
System.out.println("Logging BEFORE calling method : " + context.getMethod().getName());
Object result = context.proceed();
System.out.println("Logging AFTER calling method : " + context.getMethod().getName());
return result;
}
}
SimpleInterceptorTime.java
package ch.bcds8. interceptors;
public class SimpleInterceptorTime
{
@AroundInvoke
public Object intercept(InvocationContext context) throws Exception
{
long startZeit = new Date().getTime();
Object result = context.proceed();
long stoppZeit = new Date().getTime();
long dauer = stoppZeit - startZeit;
System.out.println("Duration : " + dauer + " Millisekunden "
+ context.getMethod().getName());
}
return result;
}
18.05.17 8:44
54
Johann Mildner, Basel
JEE – Business Component Developer Seminar
Die Klasse deren Methoden protokolliert werden soll, bekommt die Annotation @Interceptors.
Mehr ist nicht zu tun. Die Methoden in dieser Klasse wissen nichts von einer Protokollierung.
SimpleInterceptorBeanRemote.java
package ch.bcds8.interfaces;
@Remote
public interface SimpleInterceptorBeanRemote
{
String printMessage(String m);
}
SimpleInterceptorBean.java
package ch.bcds8.beans;
@Stateless
@Interceptors ({ SimpleInterceptorLogging.class, SimpleInterceptorTime.class })
public class SimpleInterceptorBean extends SimpleInterceptorBeanRemote
{
public String printMessage(String m)
{
System.out.println("Executing method: printMessage " + m);
return "Message is " + m;
}
}
18.05.17 8:44
55
Johann Mildner, Basel
JEE – Business Component Developer Seminar
SimpleInterceptorTest.java
package ch.bcds8.test;
public class SimpleInterceptorTest
{
static final Logger LOG = Logger.getLogger(SimpleInterceptorTest.class);
public static void main(String args[]) throws Exception
{
LOG.info("Programmstart");
SimpleInterceptorBeanRemote ejb = (SimpleInterceptorBeanRemote) getBean();
System.out.println(ejb.printMessage("message aus siTest"));
}
}
LOG.info("Programmende");
private static Object getBean()
{
return Helper.lookup("SimpleInterceptorBean",
"ch.bcds8.interfaces.SimpleInterceptorBeanRemote");
}
18.05.17 8:44
56
JEE – Business Component Developer Seminar
Johann Mildner, Basel
Teil 9 Was noch nicht behandelt wurde
LocalBeans
Wenn eine Bean kein Interface hat – no interface Bean so ist sie eine LocalBean.
Die Bean hat entweder keine Annotation bezüglich Local oder die Annotation @LocalBean.
Eine lokale Bean kann nicht remote aufgerufen werden. (Servlet oder JSP).
@EJB BeanName bean;
Uebung:
NoInterfaceBean mit der Methode String echo(String s)
NoInterfaceServlet
Beans mit asynchronen Methoden
müssen void sein oder ein Future Object zurückliefern.
Future liefern geht nur wenn der Client im gleichen AS läuft
z.B. in einem Servlet oder einem BackingBean
die Bean mit den AsyncMethoden muss Stateless sein.
Wenn nicht, muss der Client zwar nicht warten aber ... die Methoden laufen nicht parallel sondern
wartet bis keine andere Methode mehr läuft (Synchronisation ?)
Uebung:
Name des Dienstes:
Interface:
Implementierung:
Methode(n):
AsynchroneMethoden
(Stateless)
AsynchroneMethodenBeanRemote.java
AsynchroneMethodenBeanjava
void syncEcho
(String s)
gibt s und eine Zufallszahl aus
void asyncEcho1 (String s)
gibt s und eine Zufallszahl aus
Future asyncEcho2 (String s)
liefert s mit einer Zufallszahl
Damit man die Asynchronität beim Test auch sieht, soll in den Methoden sleep(10000) aufgerufen
werden und Anfang und Ende der Methoden protokolliert werden.
18.05.17 8:44
57
Herunterladen