Westfälische Wilhelms-Universität Münster Ausarbeitung Message Oriented Middleware: Technische Aspekte der Umsetzung von EAI im Rahmen des Seminars Enterprise Architecture Management Benjamin Oberste-Berghaus Themensteller: Prof. Dr. Herbert Kuchen Betreuer: Dipl.- Wirt.Inform. Christoph Lembeck Institut für Wirtschaftsinformatik Praktische Informatik in der Wirtschaft Inhaltsverzeichnis 1 Middleware und Enterprise Application Intergration................................................ 3 2 Message Oriented Middleware .................................................................................. 4 3 2.1 Middleware ....................................................................................................... 4 2.2 Remote Procedure Call ..................................................................................... 5 2.3 Object Oriented Middleware ............................................................................ 5 2.4 Message Oriented Middleware ......................................................................... 6 2.5 MOM und Enterprise Application Integration.................................................. 7 Java Message Service ................................................................................................ 9 3.1 Grundlagen........................................................................................................ 9 3.2 Kommunikationsmodelle................................................................................ 10 3.2.1 3.2.2 3.3 Nachrichten..................................................................................................... 12 3.4 Interfaces......................................................................................................... 13 3.5 Erweiterte Konzepte ....................................................................................... 16 3.5.1 3.5.2 3.5.3 4 Point-to-Point.............................................................................................. 10 Publish/Subscribe........................................................................................ 11 Zuverlässigkeit............................................................................................ 16 Transaktionen.............................................................................................. 18 Request Reply ............................................................................................. 20 Message Driven Beans ............................................................................................ 21 4.1 Grundlagen...................................................................................................... 21 4.2 Lebenszyklus .................................................................................................. 22 4.3 Beurteilung...................................................................................................... 23 5 Zusammenfassung ................................................................................................... 25 A WM-Ticket-Beispiel ................................................................................................ 26 Literaturverzeichnis ........................................................................................................ 34 II Kapitel 1: Middleware und Enterprise Application Intergration 1 Middleware und Enterprise Application Intergration In Unternehmen gibt es häufig eine Vielzahl von unterschiedlichen Applikationen, Plattformen und Datenbanken, die historisch nebeneinander gewachsen sind. Neben diesen Altsystemen ist die Nutzung von neueren Technologien, wie Intranet und Internet, für eine effiziente und effektive Wettbewerbsstrategie erforderlich. Middleware ermöglicht diesen unterschiedlichen Softwarekomponenten miteinander zu kommunizieren. Ziel der Enterprise Application Integration ist es die intra- und interorganisatorischen Geschäftsprozesse zu optimieren. Dafür ist die Kommunikation zwischen den Softwaresystemen, und deswegen Middleware notwendig. Innerhalb dieser Ausarbeitung wird zunächst begründet, weshalb sich gerade Message Oriented Middleware auf dem Gebiet der Enterprise Application Integration durchsetzt (Kapitel 2). Anschließend wird der Java Message Service, als eine mögliche Spezifikation für Message Oriented Middleware, näher erläutert (Kapitel 3). Abschließend werden Message Driven Beans vorgestellt, welche die asynchrone Kommunikation auf Ebene der Enterprise Java Beans unterstützen (Kapitel 4). 3 Kapitel 2: Message Oriented Middleware 2 Message Oriented Middleware Dieses Kapitel führt zunächst in den Begriff „Middleware“ ein (Abschnitt 2.1) und stellt in den Abschnitten 2.2 - 2.4 drei Typen von Middleware vor. Abschließend soll in Abschnitt 2.5.herausgearbeitet werden, warum sich gerade Message Oriented Middleware für die Enterprise Application Integration eignet. 2.1 Middleware Der Begriff „Middleware“ ist, wie viele andere in wissenschaftlichen Diskussionen, nicht einheitlich definiert. Eine weit gefasste Definition von Linthicum dient als Grundlage dieser Ausarbeitung: „Middleware is basically any type of software that facilitates communication between two or more software systems“ [Li99, S. 100]. Anhand dieser Definition lassen sich die wichtigsten Merkmale von Middleware identifizieren. Zunächst ist Middleware ein softwarebasiertes Konzept. Ein weiterer Bestandteil der Definition ist, dass Middleware eingesetzt wird, um Kommunikation zu ermöglichen. Auf Softwaresysteme bezogen, bedeutet Kommunikation den Austausch von Daten bzw. Informationen. Diese kann hierbei sowohl zwischen zwei, als auch zwischen mehreren Softwaresystemen stattfinden. Die Softwaresysteme zwischen denen die Kommunikation ermöglicht werden soll, weisen i.d.R. einen hohen Grad an Heterogenität auf. Die Heterogenität der Softwaresysteme kann sich auf viele Bereiche der Softwaresysteme, wie die Programmiersprache, Plattformen und Inhalt, beziehen. Das Verbergen der Heterogenität der zu Grunde liegenden Netzwerke, Hardware, Betriebssysteme und Programmiersprachen ist nach Coulouris das zentrale Ziel der Middleware [CDK01, S. 35]. Der Name „Middleware“ resultiert aus der Tatsache, dass die von Middleware angebotenen Dienste zwischen der Betriebssystemschicht und der Applikationsschicht ausgeführt werden [JBLN01, S. 27]. Middleware wird je nach Zweck unterschiedlich klassifiziert. Eine gängige Klassifizierung unterteilt Middleware anhand der beteiligten Softwaresysteme bzw. der ausgetauschten Informationen in Remote Procedure Calls, Object Oriented Middleware, Database Oriented Middleware und Message Oriented Middleware [Li99, JBLN01, Ke02]. Da Message Oriented Middleware im Mittelpunkt dieser Ausarbeitung steht, wird eine grobe, aber für das Ziel der Ausarbeitung zweckmäßige Klassifizierung in synchrone 4 Kapitel 2: Message Oriented Middleware und asynchrone Middleware vorgenommen. Dadurch ist es möglich die Unterschiede zwischen den Kommunikationsparadigmen deutlich herauszustellen. Wie noch gezeigt wird, arbeiten Remote Procedure Calls und Objekt Oriented Middleware mit synchroner Kommunikationsmechanismen und Message Oriented Middleware mit einem asynchronen Mechanismus. Diese drei Typen von Middleware sollen im Folgenden näher beschrieben werden. 2.2 Remote Procedure Call Der Remote Procedure Call (RPC) ermöglicht die Kommunikation zwischen Applikationen, die auf heterogenen Plattformen laufen. RPC basiert auf prozeduralen Konzepten und unterstützt entfernte Funktionsaufrufe. RPC blendet die Details der Kommunikation, die Low-Level Netzwerkkommunikation, vor der Applikation und dem Programmierer aus. Dieser braucht sich um die Details nicht zu kümmern. Zentrales Anliegen des RPC ist es, einem lokalen Programm eine entfernte Funktion nutzbar zu machen. Für das lokale Programm ist der entfernte Funktionsaufruf genauso wie ein lokaler Aufruf [CDK01, S. 215]. Ein RPC ist für das lokale Programm also transparent. Diese Art der Transparenz erfordert, dass die aufrufende Applikation, wie bei einem lokalen Aufruf, auf die Antwort wartet und nicht weiterarbeitet; sie blockiert. Dieser Kommunikationsmechanismus, bei der ein Prozess blockiert während seine Anfrage bearbeitet wird, heißt synchrone Kommunikation. Ausführlichere Informationen über RPC können beispielsweise in [CDK01] nachgelesen werden. 2.3 Object Oriented Middleware Object Oriented Middelware (OOM) unterstützt die Kommunikation zwischen verteilten Objekten und Komponenten [JBLN01, S. 31f.]. Realisiert wird OOM meistens mit Hilfe von Object Request Broker (ORB). Sie ermöglichen lokalen Objekten oder Komponenten die Methoden entfernter Objekte oder Komponenten mittels Schnittstellen zu benutzen. Im Prinzip ist OOM eine weitere Schicht über RPC. Deswegen arbeitet auch OOM mit dem synchronen Kommunikationsmechanismus und blendet Details der Kommunikation aus. Um hinsichtlich der Programmiersprachen und der Plattformen Transparenz zu ermöglichen, sind Standards für die Schnittstellen erforderlich, an welche sich die Hersteller von ORB halten können. 5 Kapitel 2: Message Oriented Middleware Die drei wichtigsten Standards für ORB sind CORBA von OMG, JAVA RMI und RMIIIOP von SUN sowie COM/DCOM/COM+ von Microsoft. Viele ORB Produkte sind mit den CORBA ORB Spezifikationen und den verschiedenen RMI und RMI-IIOP Implementierungen kompatibel. Insbesondere die Unterstützung von RMI-IIOP ist wichtig, da es das gleiche Kommunikationsprotokoll wie CORBA benutzt, IIOP (Internet Inter-ORB-Protocol), und dadurch RMI und CORBA zusammenarbeiten können. Verteilte Objekte sind die Grundlage von Enterprise Java Beans (EJB) und dementsprechend ist die mittels RMI bzw. RMI-IIOP durchgeführte Kommunikation zentraler Bestandteil der gesamten J2EE Plattform. Der Microsoft Standard, welcher des Öfteren den Namen gewechselt hat, unterscheidet sich in einigen Punkten deutlich von RMI und CORBA. Trotzdem ist eine Verbindung zwischen diesen Technologien möglich. Da eine detaillierte Auseinandersetzung mit den genannten ORB Standards nicht Gegenstand dieser Ausarbeitung ist, sei auf die weiterführende Literatur verwiesen: zum Thema CORBA [CDK01, Kap.17] und zum Thema RMI und RMI-IIOP siehe [MAY03, Kap.4]. 2.4 Message Oriented Middleware Wie in den Abschnitten 2.2 und 2.3 gezeigt, sind RPC und OOM klassische Vertreter auf synchroner Kommunikation basierender Middleware. Message Oriented Middleware (MOM) ermöglicht asynchrone Kommunikation mittels Nachrichten. Diese werden nicht direkt von einer Sender-Applikation zur Empfänger-Applikation gesendet, sondern gelangen über einen Vermittler an ihr Ziel. Dieser Mittler ist die MOM und deren technische Realisierung wird als Message-Server oder auch Message Broker bezeichnet [Mo02, S. 10]. Durch die Verwendung von Nachrichten und einen Vermittler ist ein hohes Maß an Interoperabilität zwischen sehr heterogenen Softwaresystemen möglich, da diese keine Details übereinander kennen müssen [JBLN01, S.28]. Außerdem sind die kommunizierenden Applikationen, wie in Abbildung 1 [JBLN01, S. 28] dargestellt, entkoppelt. Die Sender-Applikation sendet die Nachricht an den Vermittler und arbeitet sofort weiter, ohne dass sie, wie bei Verwendung von RPC oder OOM, blockiert. Der Vermittler ist für die Weiterleitung der Nachricht an die Empfänger-Applikation verantwortlich. Ist diese temporär nicht verfügbar, dann verwahrt der Message-Server die Nachricht solange, bis die Applikation empfangsbereit ist [JBLN01, S. 28]. 6 Kapitel 2: Message Oriented Middleware Abbildung 1: Prinzip von MOM Auch in einer anderen Hinsicht sind die Applikationen entkoppelt. Da die Kommunikation über Nachrichten stattfindet, benötigen die Applikationen keine Informationen darüber, wer die Nachrichten wann und wie bearbeitet. Genauso wie bei RPC und OOM reduziert MOM die Komplexität, da Details der Kommunikation, bezüglich des Transports und des Netzwerks, versteckt werden. Die Funktionalität von MOM wird über ein Application Programming Interface (API) zugänglich. 2.5 MOM und Enterprise Application Integration Um verschiedene Softwaresysteme eines Unternehmens miteinander zu verbinden, ist Middleware, als „Motor von Enterprise Application Integration (EAI)“, notwendig [Li99, S. 99]. Gerade MOM ist ein wichtiger Bestandteil von EAI, da sie einige wichtige Eigenschaften besitzt [Li99, S. 110]. Diese Eigenschaften resultieren zum einen aus der Verwendung eines zentralen Vermittlers, dem Message-Server, und zum anderen aus der Verwendung des asynchronen Kommunikationsmechanismus mittels Nachrichten. Die Verwendung eines Message-Servers und die damit verbundene zentrale Architektur ermöglicht eine einfache Umsetzung nicht nur der Point-to-Point, sondern auch der Many-to-Many Kommunikation. Letztere Art der Kommunikation ist im Rahmen der EAI notwendig, da es innerhalb eines Unternehmens häufig erforderlich ist, dass viele Applikationen miteinander kommunizieren [Li99, S.113f.]. Die Applikationen treten jeweils nur direkt mit dem Message-Server in Kontakt. Dadurch ist die gesamte Architek7 Kapitel 2: Message Oriented Middleware tur flexibel, denn Änderungen sind leicht durchzuführen. Außerdem brauchen Applikationen deswegen die Details der anderen Applikationen und Plattformen nicht zu kennen [JBLN01, S.28]. Zudem stellt ein Message-Server neben der reinen Nachrichtenübermittlung i.d.R noch weitere Dienste, wie Lastverteilung und Transaktionen, bereit. Besonders die gesicherte Kommunikation mittels Transaktionen ist vor dem Hintergrund der EAI relevant [Li99, S.118f.]. Die Verwendung eines zentralen Servers kann allerdings auch einen großen Nachteil haben, weil dann die gesamte Architektur von diesem abhängig ist. Können die Applikationen nur mit dem Server eines Anbieters kommunizieren, ist die Architektur sogar von dem Server eines bestimmten Anbieters abhängig. Um diese Abhängigkeit zu vermeiden, hat die Firma SUN eine allgemeine Schnittstelle bereitgestellt, mittels der die Message-Server aller Anbieter kontaktiert werden können, den Java Message Service (JMS). Dieser wird in Kapitel 3 näher beschrieben. Durch den JMS entfällt zwar die Abhängigkeit von einem speziellen Anbieter, allerdings müssen die Applikationen in Java geschrieben sein. Durch die Verwendung von Nachrichten ist die asynchrone Kommunikation zwischen Applikationen möglich. Da die Applikationen dabei nicht blockieren, ist MOM grundsätzlich performanter als RPC oder OOM. Wie in diesem Kapitel deutlich wurde, hat MOM viele Vorteile gegenüber der „klassischen“ Middleware RPC und OOM. MOM ist aber vor allem eine Ergänzung von RPC und OOM, insbesondere im Rahmen der EAI, und kein vollständiger Ersatz. In vielen Situationen findet die Kommunikation weiterhin über die „klassische“ Middleware statt. 8 Kapitel 3: Java Message Service 3 Java Message Service Innerhalb dieses Kapitels wird der Java Message Service der Firma SUN vorgestellt. Zunächst wird im ersten Abschnitt erklärt was der Java Message Service ist. Die Abschnitte 3.2 bis 3.4 beschreiben die grundsätzliche Funktionsweise, sowie die notwendigen Bestandteile. Das letzte Kapitel erläutert weiterführende Konzepte, die insbesondere im Rahmen von EAI interessant sind. 3.1 Grundlagen Java Message Service (JMS) ist ein Messaging Standard. Eine vollständige Darstellung des Java Message Service ist in [JMS1.1] nachzulesen. JMS stellt eine Spezifikationen dar, welche Schnittstellen und Semantik definiert. Diese ermöglichen es Java Applikationen Dienste von allen JMS kompatiblen Message-Servern zu nutzen. JMS besteht aus zwei Teilen; einem Application Programming Interface (API), um Nachrichten zu schreiben und zu verschicken, und ein Service Provider Interface (SPI), welches die Seite des Servers spezifiziert [RAJ02, S.203]. Die Java Applikation kann mit einem beliebigen Message-Server kommunizieren, wenn dieser JMS kompatibel ist, also das JMS SPI umsetzt. Im Kontext von JMS werden diese Message-Server auch als JMS Provider bezeichnet. Es ist wichtig zu beachten, dass SUN derzeit keine Kompatibilitätstests durchführt. Deswegen gibt es keinen Standard, um die auf Seiten der Anbieter erklärte JMS Kompatibilität zu überprüfen [MC01, S.133]. Eine Applikation, welche die JMS Spezifikation umsetzt, ist nicht mehr an den Message-Server eines bestimmten Herstellers gekoppelt. Dieser Zusammenhand ist in Abbildung 2 verdeutlicht. Abbildung 2: Java Message Service 9 Kapitel 3: Java Message Service Fünf große JMS Provider sind WebSphere MQ von IBM, SonicMQ von Progress, FioranoMQ von Fiorano, Java Message Queue von Sun Microsystems und WebLogic Server von BEA. Diese sind in [MC01, Kap.9] näher beschrieben. Das Message Produkt Message Queue der Firma Microsoft unterstützt JMS nicht. JMS wurde entwickelt, um die Vorteile von asynchroner Kommunikation auch für Java Applikationen zu nutzen. An der Entwicklung von JMS waren außer SUN weitere große Unternehmen beteiligt. Das ist ein Grund, weshalb die JMS Spezifikation von vielen Server Anbietern unterstützt wird. Ein weiterer Grund für die weit verbreitete Unterstützung ist, dass JMS nur die direkt mit der Kommunikation zusammenhängenden Aspekte festlegt. Beispielsweise werden keine Vorgaben bezüglich der Lastverteilung oder von Sicherheitsaspekten gemacht [JMS1.1, S.16f.] Die Spezifikation ist dadurch leichtgewichtig und die Anbieter von JMS Providern können sich anhand zusätzlicher Merkmale untereinander differenzieren. Um JMS benutzen zu können, werden Nachrichten, administrative Objekte und JMS Clients benötigt. Bevor diese näher Erläutert werden, sollen die beiden in JMS spezifizierten Kommunikationsmodelle erklärt werden. 3.2 Kommunikationsmodelle JMS unterstützt zwei Kommunikationsmodelle, Point-to-Point und Publish/Subscribe. Die an der Kommunikation beteiligten Komponenten werden allgemein als Produzent, Konsument und Destination bezeichnet. Der Produzent ist der Erzeuger der Nachricht, der Konsument ist der Abnehmer. Eine Destination agiert als Vermittler der Nachrichten. Diese Komponenten werden in Abhängigkeit von dem zugrunde liegenden Kommunikationsmodell entweder als Sender, Receiver und Queue oder als Publisher, Abonnent und Topic bezeichnet. 3.2.1 Point-to-Point Das Point-to-Point (P-t-P) Modell realisiert Kommunikation zwischen einem Sender und einem Receiver mittels einer Queue (s. Abbildung 3). Abbildung 3: Das Point-to-Point Kommunikationsmodell 10 Kapitel 3: Java Message Service Dabei hat jede Nachricht genau einen Receiver. Der Kommunikationsaustausch findet zwischen genau zwei Komponenten statt. Ein oder mehrere Sender schicken eine Nachricht an die Queue. Eine Queue kann mehrere Receiver haben an die sie Nachrichten weiterleitet. Die Queue stellt sicher, dass jede Nachricht genau einmal versendet wird. JMS unterstützt für die Weiterleitung von Nachrichten durch die Queue den Pull- und den Push- Mechanismus. Beim Pull-Mechanismus ruft der Receiver Nachrichten aktiv ab, indem er bei der Queue anfragt, ob Nachrichten für ihn vorhanden sind. Leitet die Queue Nachrichten automatisch an den Receiver weiterleitet, ist der Push-Mechanismus umgesetzt. Weitere Einstellungen hinsichtlich der Bearbeitung von Nachrichten durch die Queue, beispielsweise die Lastverteilung, werden Herstellerspezifisch umgesetzt. 3.2.2 Publish/Subscribe Das Publish/Subscribe (Pub/Sub) Kommunikationsmodell ermöglicht die Kommunikation zwischen einem Publisher und einem oder mehreren Abonnenten mittels eines Topics. Dieses Modell ist die Umsetzung der Many-to-Many Kommunikation. Der Nachrichtenaustausch ist nicht auf zwei beteiligte Komponenten beschränkt. Unter einem Topic können ein oder mehrere Publisher Nachrichten veröffentlichten, also Nachrichten an das Topic senden. Diese Nachrichten eines Topics erhalten alle Abonnenten, die bei dem Topic registriert sind. Deswegen kann eine Nachricht viele Konsumenten haben. Dieser Zusammenhang ist in Abbildung 4 dargestellt. Abbildung 4: Das Publish/Subscribe Kommunikationsmodell Publisher und Abonnenten können dynamisch während der Laufzeit hinzugefügt werden, dadurch lassen sich Systeme einfach verändern und vergrößern. Das Pub/Sub Kommunikationsmodell in JMS unterstützt nur den Push-Mechanismus, also die automatische Weitergabe der Nachrichten durch das Topic an die Abonnenten. 11 Kapitel 3: Java Message Service 3.3 Nachrichten Der Inhalt der Kommunikation zwischen Produzent und Konsument wird mittels Nachrichten weitergegeben. Nachrichten sind zentraler Bestandteil von jeder MOM. Ihre Struktur wird im Folgenden erklärt. Wie in Abbildung 5 zu erkennen, besteht eine Nachricht aus drei Teilen: Header, Property und Body. Abbildung 5: Struktur einer Nachricht Im Header sind Metadaten enthalten, welche die Nachricht beschreiben, bspw. das Ziel der Nachricht und der Zeitpunkt, wann sie erhalten wurde. Mit dem Inhalt des Headers lassen sich die Nachrichten vom JMS Provider an das gewünschte Ziel weiterleiten. Die Properties ermöglichen es dem Entwickler neben den Standardinformationen des Headers optional weitere zusätzliche Informationen, wie applikationsspezifische und serverspezifische Eigenschaften, hinzuzufügen. Der Body enthält die eigentlichen Daten, die transportiert werden sollen. Die Art des Inhalts ist unterschiedlich und hängt vom Typ der Nachrichten ab. Die Typen von JMS werden durch das javax.jms.Message Interface festgelegt und sind in Tabelle 1 aufgelistet. Tabelle 1: JMS Nachrichten Typen 12 Kapitel 3: Java Message Service 3.4 Interfaces Neben dem Message Interface stellt JMS noch weitere Interfaces bereit, die in jeder JMS Applikation genutzt werden. Im Einzelnen sind dies die administrativen Objekte Destination, ConnectionFactory, Connection und Session, sowie MessageProducer und MessageConsumer. Der in Abbildung 6 [JMS1.1, S. 24] dargestellte Zusammenhang zwischen den Interfaces ist für die beiden Kommunikationsmodelle P-t-P und Pub/Sub grundsätzlich gleich. Für jedes Modell gibt es jeweils eigene Subinterfaces. Connection Factory erzeugt Connection erzeugt erzeugt Message Producer sendet an erzeugt Session erzeugt Destination Message Consumer erhält von Destination Message Abbildung 6: Zusammenhang zwischen den Interfaces Ohne auf Details der einzelnen Interfaces einzugehen, lassen sich anhand dieser Abbildung bereits die notwendigen Schritte beschreiben, die zur Nutzung des JMS durchzuführen sind. Die Interfaces werden weiter unten ausführlicher beschrieben. Voraussetzung zur Durchführung der Schritte sind eine bereits vorhandene ConnectionFactory und eine Destination. Diese Komponenten werden im JMS Provider konfiguriert und sind nicht Bestandteil der Applikation. Um sie nutzen zu können, ist ein JNDI lookup notwendig. Zur Funktionsweise des JNDI siehe [MAY03, Kap.11]. Die ConnectionFactory erzeugt ein Connection Objekt. Mit dem Connection Objekt lässt sich eine Session erstellen. Das Session Objekt erzeugt einen Mes13 Kapitel 3: Java Message Service sageProducer, wenn eine Nachricht versendet werden soll, bzw. einen MessageConsumer, wenn eine Nachricht empfangen werden soll. Im ersten Fall wird auch Objekt vom Typ Message von der Session erstellt. Diese wird dann durch den MessageProducer versendet. Im Anhang ist ein kompletter Beispielcode aufgeführt, an dem die Zusammenhänge verdeutlicht werden. Eine Destination ist das Ziel einer Nachricht. Spezielle Destinations sind im Kontext von JMS die Queue oder das Topic, je nach dem zugrunde liegenden Kommunikationsmodell. Normalerweise werden diese im JMS Provider konfiguriert und können nicht direkt in der Applikation instanziiert werden. Eine Ausnahme bilden temporaryQueue und temporaryTopic, die in Abschnitt 3.5.3 beschrieben werden. Das Interface ist javax.jms.Destination. Die Subinterfaces sind Queue für die P-t-P Kommunikation und Topic für das Pub/Sub Modell. Objekte vom Typ Connection werden in JMS ausschließlich mittels ConnectionFactories erzeugt. ConnectionFactories sind nur für die Erstellung von Connections zuständig. Auch die ConnectionFactory muss, wie die Destination, über einen JNDI lookup aufgerufen werden. Das Interface ist javax.jms.ConnectionFactory. Für die Kommunikationsmodelle P-t-P bzw. Pub/Sub sind die Subinterfaces QueueConnectionFactory und TopicConnectionFactory vorhanden. Ab der JMS Version 1.1 ist allerdings eine Unterscheidung nicht mehr notwendig [MAY03, S. 237]; es kann für beide Modelle das Interface ConnectionFactory benutzt werden. Nur aus Gründen der Abwärtskompatibilität mit älteren Versionen, sind die Subinterfaces noch vorhanden. JMS Connections repräsentieren eine Verbindung zwischen einem Client und einem JMS Provider, über welche Nachrichten gesendet werden [MC01, S. 142]. Connections steuern die Low-Level Kommunikation über das Netzwerk. Das Connection Interface ist javax.jms.Connection. Entsprechend der ConnectionFactory hat auch Connection Subinterfaces, QueueConnection und TopicConnection, welche ebenfalls lediglich wegen der Abwärtskompatibilität vorhanden sind. Ein Objekt vom Typ Session arbeitet wie eine Fabrik für Objekte des Typs Message, MessageProducer und MessageConsumer [MC01, S. 27]. Nachrichten werden nicht direkt über Connections versendet, sondern durch ein Session Objekt erzeugt. Um ein Objekt vom Typ Session zu erstellen ist ein Connection Objekt 14 Kapitel 3: Java Message Service notwendig. Da ein Session Objekt eine Connection nutzt, stellt sie die Verbindung zwischen einem Client und dem JMS Provider her. Für die Kommunikation zwischen zwei Clients sind folglich mindestens zwei Sessions, vom MessageProducer zur Destination und von der Destination zum MessageConsumer, erforderlich. Das Interface ist javax.jms.Session. Die Subinterfaces QueueSession und TopicSession werden auch nur für ältere Versionen benötigt. Nachdem die notwendigen administrativen Objekte (Destination, ConnectionFactory, Connection und Session) erzeugt sind, können Nachrichten versendet und empfangen werden. Außer Nachrichten, deren Struktur in Abschnitt 3.3 beschrieben ist, erzeugt eine Session auch MessageProducer und MessageConsumer. Um Nachrichten versenden zu können, ist ein Objekt vom Typ MessageProducer notwendig. Das Interface für diesen ist javax.jms.Message-Producer und hat zwei Subinterfaces: QueueSender und TopicPublisher. Zur Erzeugung eines MessageProducers ist ein Session Objekt erforderlich. Mit dem Interface javax.jms.Message-Consumer lässt sich ein Objekt vom Typ MessageConsumer erzeugen. Auch dieses stellt zwei Subinterfaces bereit, QueueReceiver und TopicReceiver. Wie in Abschnitt 3.2.1 erwähnt, unterstützt JMS zur Weiterleitung von Nachrichten durch den JMS Provider den Pull und den PushMechanismus. Diese Mechanismen werden durch den MessageConsumer entweder mit der Methode receive() oder dem Interface MessageListener() umgesetzt [Mo02, S.36]. Wird der Pull-Mechanismus realisiert, holt sich der Konsument die Nachrichten vom JMS Provider ab. Dafür wendet der Client die receive() Methode an. Durch den Aufruf der Methode liefert der Server die nächste Nachricht. Ist momentan keine Nachricht vorhanden, blockiert der Konsument so lange, bis eine neue kommt. Um diese Blockade zu begrenzen, kann als Argument ein Zeitintervall in Millisekunden angegeben werden. Die Methode hat dann die Form receive(long timeout). Der Konsument blockiert nur in dem vorgegebenen Intervall. Durch Anwendung der Methode receiveNoWait() wird die Blockierung des Konsumenten verhindert. Alternativ kann der Push-Mechanismus realisiert werden. Der Konsument lässt sich Nachrichten zustellen, sobald sie verfügbar sind. Dazu muss ein Objekt erzeugt werden, welches das MessageListener()Interface implementiert. Dieses Interface enthält 15 Kapitel 3: Java Message Service nur die Methode onMessage(). Die Methode definiert was gemacht werden soll, wenn eine Nachricht eintrifft. Sie enthält ein Argument vom Typ Message. Ein MessageListener Objekt verhält sich wie ein asynchroner event handler für Nachrichten. Durch den Aufruf der Methode setMessageListener()wird ein MessageListener bei einem spezifischen QueueReceiver oder TopicSubscriber registriert. Wird eine Nachricht überbracht, ruft der Client automatisch die onMessage() Methode auf. Wie in Kapitel 4 noch gezeigt wird, sind Message Driven Beans eine spezielle Form des Typs MessageListener. 3.5 Erweiterte Konzepte Nachdem die bisherigen Abschnitte die Grundlagen zur Nutzung des JMS gelegt haben, soll nun auf einige erweiterte Konzepte eingegangen werden. Hierbei wurden Konzepte ausgewählt, die Sicherheitsaspekte adressieren und dementsprechend insbesondere im Rahmen der EAI relevant sind. Dazu zählen Aspekte der Zuverlässigkeit, Transaktionen und der Request/Reply Mechanismus. 3.5.1 Zuverlässigkeit Die Zuverlässigkeit der Nachrichtenübertragung kann auf den drei Ebenen Nachrichtenproduzent, JMS Provider und Nachrichtenkonsument beeinflusst werden. Auf Ebene des Produzenten kann der Übertragungsmodus, auf Ebene des JMS Providers das Quittierungsverhalten und auf Ebene des Konsumenten der Subskriptionstyp festgelegt werden. Diese drei Möglichkeiten zur Beeinflussung der Zuverlässigkeit sind Gegenstand dieses Abschnitts. Bei der Wahl des gewünschten Zuverlässigkeitsgrads ist zu berücksichtigen, dass höhere Zuverlässigkeit immer schlechtere Performanz nach sich zieht. Auf Ebene des Nachrichtenproduzenten kann Übertragungsmodus festgelegt werden, der sich auf die Art der Nachrichtenspeicherung durch den Server bezieht [MC01, S.85]. In Abhängigkeit, ob eher Zuverlässigkeit oder Performanz gewünscht ist, unterstützt JMS die Übertragungsmodi „nicht-persistent“ oder „persistent“. Wenn die Performanz wichtiger und der Verlust einer Nachricht als nicht kritisch zu bewerten ist, kann der Modus „nicht-persistent“ gewählt werden. Da die Nachricht vom Server nicht auf einen stabilen Speicher abgelegt werden muss, entsteht weniger Overhead. Allerdings kann die Nachricht bei einem Serverabsturz verloren gehen. Ist die zuverlässige Nachrichtenübermittlung unerlässlich, muss der Modus „persistent“ gewählt werden. 16 Kapitel 3: Java Message Service Die Nachricht wird von dem JMS Provider so abgespeichert, dass sie auch bei einem Serverabsturz nicht verloren geht. „Persistent“ ist der default Wert. Das von JMS bereitgestellte DeliveryMode Interface sieht folgendermaßen aus: public interface DeliveryMode { static final int NON_PERSISTENT = 1; static final int PERSISTENT = 2; } Informationen über die Art des Übertragungsmodus sind im Header der Nachricht hinterlegt. Ist eine Nachricht bei dem JMS Provider angekommen, dann obliegt es seiner Verantwortung die Nachricht an den oder die Konsumenten weiterzuleiten. Erst wenn die Nachricht nachweislich das gewünschte Ziel erreicht hat, löscht der Server die Nachricht. Der Nachweis erfolgt in Form einer Rückmeldung bzw. Quittierung vom Konsument. Solange eine Nachricht nicht quittiert wurde, versucht der Server sie erneut zu versenden, bis er die Rückmeldung erhält. Dieses Verhalten des Servers ist bei der Wahl des Modus zu beachten. Im JMS sind die drei in Tabelle 2 beschriebenen Rückmeldungsmodi möglich. Modus Beschreibung Session.AUTO_ACKNOWLEDGE Session.CLIENT_ACKNOWLEDGE Session.DUPS_OK_ACKNOWLEDGE Sobald die Session des Konsumenten eine Nachricht erhält, quittiert sie den Empfang automatisch. Dieser Modus garantiert das eine Nachricht once-and-only-once ein Ziel erreicht und wird normalerweise angewendet. Nicht die Session, sondern der Client quittiert den Empfang einer Nachricht. Er braucht nicht sofort jede einzeln zu quittieren, sondern kann dies für mehrere auf einmal machen. Bei diesem Modus erfolgt die Quittierung mittels der Session nicht automatisch., sondern es bleibt der Session überlassen, wann sie dies macht. Tabelle 2: Die drei Rückmeldungsmodi Der Modus wird bei der Erstellung einer Session als zweites Argument angegeben und ist vom Typ int. Das Mapping zwischen den int Werten und den Modi ist Serverspezifisch. Im Beispiel sieht das folgendermaßen aus: 17 Kapitel 3: Java Message Service session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Bei der Wahl des Rückmeldungsmodus ist zu beachten, dass jede Nachricht, die ein JMS Provider an einen Konsument versendet, quittiert werden muss. Ist der Empfang einer Nachricht noch nicht quittiert, verschickt der JMS Provider sie erneut. Die Modi Session.CLIENT_ACKNOWLEDGE und Session.DUPS_OK_ACKNOWLEDGE ermöglichen eine bessere Performanz, da mehrer Nachrichten zusammen quittiert werden können. Allerdings müssen die Konsumenten bei diesen Modi den wiederholten Empfang der gleichen Nachricht verarbeiten können [Mo02, S.34]. Das JMS Publish/Subscribe Kommunikationsmodell unterstützt zwei mögliche Subskriptionstypen, nicht-dauerhaft und dauerhaft. Nicht-dauerhaft bedeutet, dass ein Client eine Nachricht nur erhält, wenn der Abonnent zum Zeitpunkt der Veröffentlichung aktiv ist. Ist er nicht aktiv, erhält der Client die Nachricht nicht. Abonnenten dieser Art werden mit der Methode Session.createSubsriber() erzeugt. Durch die Methode Session.createDurableSubsriber()lässt sich ein dauerhafter Abonnent erzeugen, der alle unter einem Topic veröffentlichten Nachrichten bekommt, auch wenn er nicht immer aktiv ist. Der JMS Provider stellt die Nachricht an den Abonnenten zu, sobald dieser wieder welche empfangen kann. Dieser Mechanismus ist auch unter dem Namen „store-and-forward“ bekannt [MAY03, S.236]. Da sichergestellt ist, dass der Abonnent alle Nachrichten erhält, ist das Pub/Sub Modell durch diesen Mechanismus genauso zuverlässig, wie das P-t-P Modell. Zwischen den Ebenen bestehen Zusammenhänge, die bei der Implementierung berücksichtigt werden müssen. Wenn beispielsweise eine Nachricht an einen dauerhaften Abonnenten geschickt und der Modus „nicht-persistent“ benutzt wird, kann die Nachricht verloren gehen. Das ist möglich, wenn der Abonnent nicht aktiv ist und der Server abstürzt. Deswegen sollte für Nachrichten die an dauerhafte Abonnenten gesendet werden immer der Modus „persistent“ gewählt werden. 3.5.2 Transaktionen Durch Verwendung von Transaktionen kann sichergestellt werden, dass zusammenhängende Nachrichten entweder alle zusammen oder gar nicht versendet werden [MC01, 18 Kapitel 3: Java Message Service S.95ff.]. Das Transaktionskonzept bietet erweiterte, auf mehrere Nachrichten bezogene Zuverlässigkeit. Das Transaktionsverhalten wird bei der Erzeugung einer Session festgelegt. Es ist vom Typ boolean. Sollen mehrere Nachrichten atomar versendet bzw. empfangen werden, ist der Wert true als Argument einzutragen. Sind Transaktionen nicht erwünscht, wird false als Argument angegeben. Eine Transaktion wird innerhalb einer Session ausgeführt. Da Produzent und Konsument unterschiedliche Sessions benutzen, bezieht sich eine Transaktion entweder auf das Versenden oder den Empfang von Nachrichten. Es ist möglich eine Nachricht, die über eine transaktionale Session versendet wurde, innerhalb einer nicht-transaktionalen Session zu empfangen et vice versa [DP02, S.265]. Ein Produzent benutzt eine Transaktion, um zuverlässig mehrere Nachrichten zusammen zu versenden. Die Transaktion startet automatisch, wenn eine Session mit Transaktionsverhalten erstellt wird. Nachrichten, die der Produzent innerhalb einer Transaktion erzeugt, werden erst als ein Paket an die Queue oder das Topic gesendet, wenn der Produzent session.commit()aufruft. Danach startet innerhalb der Session automatisch die nächste Transaktion. Da es keine Methode zum manuellen Aufruf einer Transaktion gibt, sind deswegen verschachtelte Transaktionen nicht möglich. Der Aufruf von session.rollback() bewirkt, dass alle Nachrichten nach dem letzten Aufruf von commit()verworfen werden. Die Nutzung von Transaktionen durch den Produzent wird an einem Beispiel dargestellt: session = connection.createSession(true, Session.Auto_ACKNOWLEDGE); MessageProducer producer = session.createProducer(); /** Sende einige Nachrichten durch den Produzenten */ if(erfolgreich) session.commit(); else session.rollback(); Auf Seite des Konsumenten läuft die Transaktion ähnlich ab. Durch den session.commit()Aufruf quittiert der Konsument die empfangenen Nachrichten. Erst nach Aufruf dieser Methode löscht der JMS Provider die Nachricht. Wenn sessi19 Kapitel 3: Java Message Service on.rollback() vom Konsument aufgerufen wird, versendet der JMS Provider alle Nachrichten seit dem letzten session.commit() erneut. Da bei einer Transaktion der Empfang der Nachrichten erst durch den Aufruf der commit() Methode quittiert werden kann, sind die anderen Rückmeldungsmodi, die in Abschnitt 3.5.2 beschrieben wurden, für Transaktionen nicht relevant. 3.5.3 Request Reply Grundsätzlich entspringt die Idee der asynchronen Kommunikation aus der Entkopplung von dem Produzent und dem Konsumenten einer Nachricht. Nachdem der Produzent die Nachricht an den JMS Provider versendet hat, arbeitet er weiter, ohne auf ein Ergebnis bzw. eine Antwort zu warten. Er hat auch keine Informationen darüber, wer seine Nachricht wann bearbeitet. Der Konsument bekommt die Nachricht vom JMS Provider und hat seinerseits keine Informationen über den Produzenten. Für manche Prozesse benötigt der Produzent aber eine Antwort auf eine spezielle Nachricht, um weiterarbeiten zu können. Der von JMS spezifizierte Request/Reply Mechanismus gewährleistet dieses Verhalten [DP02, S. 269ff.;Mo02, Kap.6]. Dieser Mechanismus ermöglicht synchrone Kommunikation. Von zentraler Bedeutung für die Umsetzung, ist die Erzeugung einer temporären Destination, an die der Konsument die Antwort senden kann. Temporärere Destinations gibt es in der Form TemporaryQueue und TemporarayTopic. Durch die on.createTemporaryQueue beiden Methoden und QueueSessiTopicSessi- on.createTemporaryTopic werden sie dynamisch erstellt. Sie existieren nur solange, wie die Connection besteht, innerhalb der sie erzeugt wurden. Nur die Konsumenten, die von der gleichen Connection wie die temporäre Destination erzeugt wurden, können die Antworten verarbeiten. Wenn eine temporäre Destination erzeugt wurde und im Header Feld JMSReplyTo der Nachricht an den Konsumenten übergeben wird, kann dieser eine Antwort an die angegebene Destination zurücksenden. 20 Kapitel 4: Message Driven Beans 4 Message Driven Beans Inhalt dieses Kapitels sind die Message Driven Beans, welche zunächst in Abschnitt 4.1 allgemein eingeordnet werden. Anschließend werden die wichtigsten Bestandteile anhand ihres Lebenszyklus beschrieben (4.2). Im letzten Abschnitt werden noch kurz Vorund Nachteile, die durch die Verwendung von Message Driven Beans entstehen, diskutiert. 4.1 Grundlagen Ab der Version Enterprise Java Beans (EJB) 2.0 gibt es neben den Entity und Session Beans noch zusätzlich Message Driven Beans (MDB). Diese wurden eingeführt, um EJB Komponenten asynchrone Kommunikation zu ermöglichen. Entity und Session Beans können zwar problemlos JMS Nachrichten erstellen und senden. Allerdings ist es für sie laut EJB Spezifikation 2.1 nicht möglich ein MessageListener zu sein und Nachrichten asynchron zu empfangen [EJB2.1, S.337]. Im JMS Kontext fungiert der Container als Konsument von Nachrichten aus Topics oder Queues und kann alle zulässigen JMS Nachrichten verarbeiten. Aus Sicht des Clients sind die MDBs, wie in Abbildung 7 [EJB2.1, S. 335] zu sehen, hinter der Destination versteckt. Container MDB Pool Client Destination MDB Instanzen Abbildung 7: MDB Prinzip 21 Kapitel 4: Message Driven Beans Der Container ist für das Management der MDB verantwortlich. Durch den Container werden einzelne MDB erzeugt und gelöscht. Ein großer Vorteil von MDB ist, dass sie eingehende Nachrichten parallel verarbeiten können [MC01, S. 129]. Denn innerhalb eines Pools werden mehrere MDB Objekte verwaltet. Je nach der Menge eintreffender Nachrichten, kann der Container dynamisch MDB Objekte zusätzlich erzeugen oder überflüssige löschen. Im Gegensatz zu den Entity und Session Beans können Clients MDB nicht direkt, sondern nur indirekt via Nachrichten ansprechen. Deswegen benötigen MDBs auch weder ein remote noch ein home Interface. Da MDB nur innerhalb eines Containers existieren, werden sie auch als abhängige Konsumenten bezeichnet. Im Gegensatz zu unabhängigen JMS Nachrichten Konsumenten, die nicht von einem Container gesteuert werden. 4.2 Lebenszyklus Ein MDB besteht aus einer Bean Klasse und einem XML Deployment Descriptor. Da die Aufgabe der MDB nur im Empfangen von asynchronen Nachrichten besteht, sind sie sehr leichtgewichtig. MDB besitzen nur zwei Zustände und die Bean Klasse hat nur vier Methoden. In Abbildung 8 [EJB2.1, S. 343] ist der Lebenszyklus sowie die Methoden dargestellt. Die Methoden stellen jeweils einen Aufruf vom Container an das MDB Objekt dar. Existiert nicht 1: newInstance() 2:setMessageDrivenContext() ejbRemove() 3:ejbCreate() Existent onMessage() Abbildung 8: Lebenszyklus einer MDB 22 Kapitel 4: Message Driven Beans Eine MDB-Klasse implementiert die beiden Interfaces ja- vax.jms.MessageListener und javax.ejb.MessageDrivenBean mit den Methoden onMessage() bzw. ejbRemove() und setMessageDrivenContext(MessageDrivenContext). Zusätzlich muss jede MDB-Klasse die argumentlose ejbCreate() Methode bereitstellen. Die onMessage() Methode ist notwendig, um den Push-Mechanismus zu realisieren und Nachrichten asynchron zu empfangen. Da ein MDB das gleiche MessageListener Interface implementiert wie ein unabhängiger JMS Konsument, ist auch die Funktionsweise identisch. Diese ist in Abschnitt 3.4 beschrieben. Um ein Bean Objekt zu erstellen ruft der Container die ejbCreate() Methode auf. Gelöscht wird ein Bean Objekt durch den Aufruf der Methode ejbRemove(). Über die Methode setMessageDrivenContext(MessageDrivenContext) erhält das Bean Informationen über die Umgebung, in der es ausgeführt wird. Weitere Einstellungen werden im Deployment Descriptor konfiguriert. In diesem werden die Connection und die Session Objekte festgelegt, sowie der Name der Destination eingetragen. Auch die mit diesen Objekten assoziierte Einstellungen, wie Transaktionsverhalten, Rückmeldungsmodus und Subskriptionstyp, sind im Deployment Descriptor vorzunehmen. Details hierzu können in [RAJ02, S. 219ff. ; MAY03, S.570ff.] nachgelesen werden. Im Anhang ist ein Beispiel zum Deployment Descriptor aufgeführt. 4.3 Beurteilung Die Vorteile bei der Nutzung von MDB gegenüber unabhängigen JMS Konsument resultieren aus der Verwendung des Containers. Erstens stellt dieser Transaktionsdienste bereit, welche die Abwicklung von Transaktionen entweder auf Ebene der Beans (beanmanaged-transactions) oder vom Container (container-managed-transactions) ermöglicht. Zweitens kann die Anzahl der Bean Objekte einfach über die Größe des Pools angepasst werden. Dadurch wird die Effizienz gesteigert und eine optimale Lösung der Lastverteilung gewährleistet [RAJ02, S.224]. Drittens können im Container neben MDB noch Entity und Session Beans vorhanden sein. Deswegen ist keine Netzwerkkommunikation zwischen Nachrichtenempfänger und dem Bean, welches die Geschäftslogik bereitstellt, erforderlich. Außer den drei aufgeführten Vorteilen ist es 23 Kapitel 4: Message Driven Beans grundsätzlich einfacher MDB zu erstellen, da administrative Objekte, wie Connection und Session, vom Container bereitgestellt werden. Auch Nachteile können aus der Verwendung eines Containers entstehen [MAY03, S.575]. In der Regel stellt ein Container mehrere MDB Objekte zugleich bereit und ermöglicht dadurch die parallele Verarbeitung von eingehenden Nachrichten. Wenn die Nachrichten in einer bestimmten Reihenfolge bearbeitet werden sollen, kann das zu Problemen führen. Das die richtige Reihenfolge sichergestellt wird, ist bei der Implementierung gegebenenfalls zu beachteten. 24 Kapitel 5: Zusammenfassung 5 Zusammenfassung Message Oriented Middleware stellt eine umfassende Möglichkeit dar, den Datenaustausch zwischen verschiedenen Softwaresystemen zu gewährleisten. Sie ist flexibel, gegenüber anderen Middlewaretypen performanter und erlaubt auf elegante Weise die Interoperabilität heterogener Systeme. Trotzdem kann auf RPC und OOM nicht gänzlich verzichtet werden. Der Java Message Service stellt eine wohldefinierte Spezifikation bereit, die von fast allen namhaften Anbietern von Message-Servern umgesetzt wird. Allerdings müssen die Applikationen, die JMS Dienste nutzen sollen in Java geschrieben sein. In Zusammenhang mit den unternehmensweiten Lösungen rund um die J2EE Plattform von SUN, unterstützen Message Driven Beans die Umsetzung asynchroner Kommunikation. In Zukunft ist es vielleicht möglich den asynchronen Kommunikationsmechanismus auf RPC bzw. OOM auszuweiten, um diese performanter zu gestalten. 25 Anhang A: Titel von Anhang 1 A WM-Ticket-Beispiel Als Beispiel wird eine P-t-P Kommunikation umgesetzt. Inhaltlicher Hintergrund soll der Ticketverkauf für die Weltmeisterschaft 2006 in Deutschland sein. Dazu wird die Klasse TicketService mit der Methode request() erstellt, welche einen speziellen Ticket Typ nachfragt. Ein Objekt der Klasse TicketService ist ein MessageProducer. Als Typen stehen normale Tickets zum normalen Preis, exklusive VIPTickets und günstige Studenten-Tickets zur Verfügung (Die Typen entsprechen nicht den originalen Klassen 1-4 der FIFA). Die Methode benutzt eine QueueConnection, die während der Initialisierung erstellt wird, um eine MapMessage an die FIFA zu senden. Inhalt der Nachricht ist der Typ des Tickets, die Nummer des Spiels (1 = Eröffnungsspiel; 64 = Endspiel) und das Datum. Die Auslosung der Tickets ist nicht Bestandteil des Beispiels. Der TicketService ist ein Singleton, dass ist aber nicht notwendig. Dadurch wird aber verhindert, dass mehr als ein Connection Objekt erstellt werden kann. Die dfb.TicketOrderQueue wird genauso wie die ConnectionFactory vorausgesetzt. Da die Initialisierung des InitialContext serverspezifisch ist, soll sie nicht näher erläutert werden. Für Details zum JMS Provider SwiftMQ4.5.1 von IIT Software siehe [www.swiftmq.com]. Das Beispiel orientiert sich an [MAY03, Kap. 9 und 17]. TicketService TicketService.java import java.util.*; import java.text.DateFormat; import javax.jms.*; import javax.naming.*; public class TicketService { public static final String NORMAL = "normal"; public static final String VIP = "vip"; public static final String STUDENT = "student"; 26 Anhang A: Titel von Anhang 1 private static TicketService singleton = null; private Connection connection; private Queue ticketOrderQ; private TicketService() { try { /**Zuständige JMS Objekte initialisieren und den JNDI InitialContext erhalten */ Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.swiftmq.jndi.InitialContextFactoryImpl"); env.put(Context.PROVIDER_URL, "smqp://localhost:4001/timeout=10000"); Context ctx = new InitialContext(env); /**ConnectionFactory erhalten und eine Connection erzeugen */ ConnectionFactory cf = (ConnectionFactory)ctx.lookup( "QueueConnectionFactory"); connection = cf.createConnection(); /**Die Destination Queue erhalten */ ticketOrderQ = (Queue)ctx.lookup("dfb.TicketOrderQueue"); } catch(NamingException ne) { ne.printStackTrace(); } catch(JMSException je) { je.printStackTrace(); } } public static TicketService getTicketService(){ if(singleton == null) singleton = new TicketService(); return singleton; } 27 Anhang A: Titel von Anhang 1 public void request(int spiel, Date date) { request(NORMAL, spiel, date); } public void request(String type, int spiel, Date date) { MessageProducer qSender; Session session; try { /** Eine Session erzeugen */ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); /** Einen MessageProducer erzeugen */ qSender = session.createProducer(ticketOrderQ); /** Die MapMessage erzeugen */ MapMessage msg = session.createMapMessage(); msg.setString("ticketType", type); msg.setInt("spiel", spiel); msg.setString("date", DateFormat.getDateInstance().format(date)); /** DeliveryMode setzen */ msg.setJMSDeliveryMode(DeliveryMode.Persistent); /** Versenden der Nachricht */ qSender.send(msg); qSender.close(); session.close(); } catch(JMSException e) { e.printStackTrace(); } } 28 Anhang A: Titel von Anhang 1 public void close() { try { connection.close(); singleton = null; } catch(JMSException e) { e.printStackTrace(); } } public static void main(String args[]) { TicketService service = TicketService.getTicketService(); service.request(64, new Date()); service.close(); System.exit(0); } } Fifa mittels eines unabhängigen MessageConsumer Empfänger der Ticket Anfragen und damit der Nachrichten aus der dfb.TicketOrderQueue ist die Fédération Internationale de Football Association (FIFA). Durch die Klasse Fifa lassen sich entsprechende MessageConsumer erzeugen. Dieser realisiert den Push-Mechansimus und lässt sich deswegen als MessageListener registrieren. Fifa.java import javax.naming.*; import javax.jms.*; import java.util.*; public class Fifa implements MessageListener { private Fifa() { try { /** Die Initialisierung sowie das Erzeugen der Connection 29 Anhang A: Titel von Anhang 1 und der Session erfolgt genauso wie bei der Klasse TicketService */ Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.swiftmq.jndi.InitialContextFactoryImpl"); env.put(Context.PROVIDER_URL, "smqp://localhost:4001/timeout=10000"); Context ctx = new InitialContext(env); ConnectionFactory cf = (ConnectionFactory)ctx.lookup( "QueueConnectionFactory"); Connection connection = cf.createConnection(); Queue ticketOrderQ = (Queue)ctx.lookup( "dfb.TicketOrderQueue"); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); /** Statt eines MessageProducers wird ein MessageConsumer erzeugt */ MessageConsumer mc = session.createConsumer( ticketOrderQ); /** Registrieren des MessageConsumer als MessageListener */ mc.setMessageListener(this); /** Um Nachrichten empfangen zu können muss die Methode start() ausgeführt werden */ connection.start(); } catch(Exception e) { e.printStackTrace(); } } public void onMessage(Message msg) { try { /** Umsetzung einer simplen onMessage Methode, die 30 Anhang A: Titel von Anhang 1 den Inhalt der Nachricht ausdruckt */ MapMessage mmsg = (MapMessage)msg; System.out.println("Ticket Anfrage für Spiel Nr. "+ mmsg.getString("spiel")+" am" +mmsg.getString("date")); } catch(Exception e) { e.printStackTrace(); } } public static void main(String args[]) { Fifa f = new Fifa(); } } Fifa mittels MDB Alternativ zum unabhängigen Empfänger von JMS Nachrichten, wie er in der obigen Klasse realisiert ist, lässt sich auch ein MDB erzeugen. An diesem Beispiel ist gut zu erkennen, dass das MDB weniger Code benötigt, da die Initialisierung dem Container obliegt und im Deployment Descriptor festgelegt ist. Message Driven Bean Fifa import javax.jms.*; import javax.ejb.*; /** MDB implementieren immer die beiden Interfaces */ public class Fifa implements MessageDrivenBean, MessageListener { MessageDrivenContetxt ctx; /** Konstruktor */ public Fifa(){} 31 Anhang A: Titel von Anhang 1 /** Dieselbe Methode wie bei der unabhängigen Umsetzung */ public void onMessage(Message message) { try { MapMessage mmsg = (MapMessage)msg; System.out.println("Ticket Anfrage für Spiel Nr. "+ mmsg.getString("spiel")+" am" +mmsg.getString("date")); } catch(Exception e) { e.printStackTrace(); } } public void ejbRemove()throws javax.ejb.EJBException {} public void setMessageDrivenContext( MessageDrivenContext ctx)throws javax.ejb.EJBException { this.ctx = ctx; } public void ejbCreate() {} } Fifa Deployment Descriptor Im Deployment Descriptor sind die Einstellungen hervorgehoben, die bei der unabhängigen Fifa Klasse im Code vorgenommen werden. <ejb-jar> <enterprise-beans> <message-driven> <ejb-name>Fifa</ejb-name> <ejb-class>Fifa</ejb-class> <transaction-type>Container</transaction-type> 32 Anhang A: Titel von Anhang 1 <transaction-scope>Local</transaction-scope> <jms-acknowledge-mode> auto-acknowledge </jms-acknowledge-mode> <message-driven-destination> <jms-destination-type> javax.jms.Topic </jms-destination-type> <jms-subscription-durability> nondurable </jms-subscription-durability> </message-driven-destination> </message-driven> </enterprise-beans> <assembly-descriptor> <container-transaction> <method> <ejb-name>Fifa</ejb-name> <method-name>onMessage</method-name> <method-params> <method-param> javax.jms.Message </method-param> </method-params> </method> <trans-attribute>NotSupported</trans-attribute> </container-transaction> </assembly-descriptor> <ejb-jar> 33 Literaturverzeichnis [CDK01] George Coulouris, Jean Dollimore, Tim Kindberg: Verteilte Systeme, Pearson, 2001. [DP02] Stefan Denninger, Ingo Peters: Enterprise Java Beans 2.0, 2.Aufl., AddisonWesley, 2002. [EJB2.1] SUN Microsystems: Enterprise JavaBeans Specification 2.1, 2003, http://java.sun.com/products/ejb/docs.html [JBLN01] Matjaz B. Juric, S. Jeelani Basha, Rick Leander, Ramesh Nagappan: Professional J2EE EAI, Wrox, 2001. [JMS1.1] SUN Microsystems: Java Message Service Specification 1.1, 2002, http://java.sun.com/products/jms/docs.html [Ke02] Wolfgang Keller, Enterprise Application Integration, Dpunkt, 2002. [Li99] David S. Linthicum: Enterprise Application Integration, Addison-Wesley, 1999. [MAY03] James McGovern, Rahim Adatia, Fain Yakov, et al.: Java 2 enterprise Edition 1.4 Bible, Wiley, 2003. [MC01] Richard Monson-Haefel, David A. Chappell: Java Message Service, O’Reilly, 2001. [Mo02] Tarak Modi: Practical Java Message Service, Manning, 2002. [RAJ02] Ed Roman, Scott Ambler, Tyler Jewell: Mastering Enterprise JavaBeans, 2nd.ed., Wiley, 2002.