JMS (Java Message Service)

+ andere TechDocs
+ EJB
+ Sun JMS
+


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

JMS (Java Message Service) stellt einen wichtigen Bestandteil von Java EE dar, um asynchrone Kommunikation (über einen Message Broker) zu ermöglichen, was auch unter dem Begriff MOM (Message Oriented Middleware) bekannt ist.

Die Vorteile von asynchroner Kommunikation per JMS sind:
+ Zeitliche Entkopplung zwischen Beauftragung und Bearbeitung
+ Lose Kopplung erleichtert Austausch einzelner Systeme
+ Flexibel konfigurierbare Kommunikation und Diensteverteilung
+ Plattform- und programmiersprachenunabhängige Kommunikation
+ Anbindung an Fremdsysteme, z.B. Hosts
+ Batchbetrieb ist möglich
+ Verteilte Anwendungen
+ Verteilte Transaktionen
+ Standardisierung, Wartungsfreundlichkeit
+ Definierte Sicherheitsmechanismen
+ Hohe Ausfallsicherheit erreichbar
+ Hohe Skalierbarkeit



Inhalt

  1. Wichtige Klassen und Methoden
  2. Vorbereitungen für die Beispiele
  3. Namen im JNDI-Context
  4. Queue (Point-to-Point)
  5. Topic (Publish-and-Subscribe)
  6. QueueRequestor
  7. MDB (Message Driven Bean)
  8. Links auf weiterführende Informationen


Wichtige Klassen und Methoden

Überblick
  Queue
(Point-to-Point, "PTP")
Topic
(Publish-and-Subscribe, "pub-sub")
InitialContext InitialContext InitialContext
ConnectionFactory QueueConnectionFactory TopicConnectionFactory
Connection QueueConnection TopicConnection
Session QueueSession TopicSession
Destination Queue Topic
MessageConsumer QueueReceiver TopicSubscriber
MessageProducer QueueSender TopicPublisher
Requestor QueueRequestor TopicRequestor
Message Message Message
Nachrichtenkanäle
Queue (Point-to-Point, PTP)
Queues (Warteschlangen) sind Nachrichtenkanäle, die normalerweise zwischen genau einem Sender und einem Empfänger aufgebaut werden (Punkt-zu-Punkt-Verbindung, ähnlich wie eine E-Mail). Wenn ein Empfänger eine Nachricht erhält, wird sie normalerweise aus dem Nachrichtenkanal entfernt.
Topic (Point-to-Multipoint, Publish-and-Subscribe, pub/sub, Publizieren/Abonnieren)
Topics (Themen) sind themenorientierte Nachrichtenkanäle und haben normalerweise viele Konsumenten. Sender publizieren Nachrichten ('Publish') und Empfänger abbonieren sie ('Subscribe'). Wenn ein Empfänger eine Nachricht erhält, bleibt sie normalerweise trotzdem weiter im Nachrichtenkanal, damit auch weitere Konsumenten die Nachricht empfangen können. Es kann ein Verfallsdatum für die Nachrichten geben oder sie werden durch neuere ersetzt.
Transaktionskontrolle und Bestätigungsmodus
Beim Erzeugen der Session über QueueConnection.createQueueSession() beziehungsweise TopicConnection.createTopicSession() werden die beiden Parameter 'transacted' und 'acknowledgeMode' gesetzt:
transacted
Über den 'transacted'-Parameter wird gesteuert, ob es sich um eine transaktionsorientierte Sitzung handelt. Dann werden die in dieser Session erzeugten Nachrichten zwischengespeichert und erst beim abschließenden Commit gemeinsam abgesendet.
acknowledgeMode
Über den 'acknowledgeMode'-Parameter wird der Bestätigungsmodus gesetzt: 'AUTO_ACKNOWLEDGE', 'CLIENT_ACKNOWLEDGE' oder 'DUPS_OK_ACKNOWLEDGE'.
Nachrichtenempfänger
MessageConsumer . receive()
Anders als ein Listener wartet 'receive()' synchron auf Messages.
MessageConsumer . setMessageListener( MessageListener )
MessageListener . onMessage( Message )
Anders als bei 'receive()' braucht ein Listener nicht auf Messages zu warten, sondern empfängt sie asynchron, indem er sich über 'setMessageListener()' registriert, wodurch Messages an die 'onMessage(Message)'-Callback-Methode geschickt werden.
Nachrichtensender
QueueSender . send( Message )
TopicPublisher . publish( Message )
'send()' und 'publish()' versenden Nachrichten ohne eine Antwortnachricht zu erwarten.
QueueRequestor . request( Message )
TopicRequestor . request( Message )
Ein Requestor verschickt eine Nachricht, öffnet einen temporären Rückkanal, macht diesen über das JMSReplyTo-Feld zugänglich, registriert sich als Empfänger und wartet auf eine Antwortnachricht.
Messages
Message-Aufbau
Header Enthält vom JMS gesetzte allgemeine Nachrichteninformationen wie: JMSCorrelationID, JMSDeliveryMode, JMSDestination, JMSExpiration, JMSMessageID, JMSPriority, JMSRedelivered, JMSReplyTo, JMSTimestamp, JMSType.
Properties Enthält von den Anwendungen gesetzte Nachrichtenzusatzinformationen als Attribute in Form von Key/Value-Paaren, deren Values von verschiedenen Java-Typen sein können. Die Attribute werden gesetzt und gelesen über 'get<Type>Property()' und 'set<Type>Property()'. Ein möglicher Verwendungszweck dieser Attribute ist eine mögliche Filterung der Nachrichten bei den Empfängern.
Body Enthält die eigentliche Nachricht, die einem der folgenden fünf Message-Typen entspricht.
Message-Typen
TextMessage Übermittelt einzelnen Text-String.
MapMessage Übermittelt (mehrere) Attribute als Key/Value-Paare.
Dabei können die Values nicht nur Strings sein,
sondern auch viele andere Java-Typen.
ObjectMessage Übermittelt ein Java-Object (welches 'Serializable' implementieren muss).
StreamMessage Übermittelt Streams ähnlich wie 'DataOutputStream'.
Anders als '
BytesMessage' übergibt 'StreamMessage' auch Datentypen.
BytesMessage Übermittelt Streams ähnlich wie 'DataOutputStream'.
Anders als '
StreamMessage' übergibt 'BytesMessage' nicht interpretierte Rohdaten.


Vorbereitungen für die Beispiele

Für die folgenden Beispiel wird ein Java EE Application Server für die JNDI- und JMS-Dienste benötigt. Es wird im Folgenden davon ausgegangen, dass JBoss installiert wird. Mit kleinen Modifikationen sind die Beispiele auch mit anderen Java EE Application Servern lauffähig.

  1. Installieren Sie JBoss wie beschrieben unter 'jee-ejb2.htm#InstallationJBoss'.

    Wenn Sie nicht JBoss verwenden wollen, müssen Sie einen anderen Java EE Application Server für die JNDI- und JMS-Dienste installieren.

  2. Legen Sie ein Projektverzeichnis an, z.B. 'D:\MeinWorkspace\MeinJmsProjekt' (im Folgenden '<MeinJmsProjekt>' genannt).

  3. Legen Sie im Projektverzeichnis '<MeinJmsProjekt>' das Unterverzeichnis '<MeinJmsProjekt>\lib' an und kopieren Sie dort hinein die vom Client benötigten Libs. Für JBosss ist dies die Datei 'jbossall-client.jar' aus dem JBoss-Verzeichnis 'C:\JBoss\client'.

  4. Legen Sie im Projektverzeichnis '<MeinJmsProjekt>' das Unterverzeichnis '<MeinJmsProjekt>\conf' und darin die folgende Datei 'jndi.properties' an (wird von 'InitialContext()' benötigt):

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

    Wenn Sie nicht JBoss verwenden oder wenn JBoss auf einem anderen Rechner installiert ist, müssen Sie die Datei anpassen, wie zum Beispiel beschrieben unter: jee-jndi.htm#jndi.properties.

  5. JMS-Queues und -Topics müssen beim Java EE Application Server bzw. JMS-Provider angemeldet werden. Für JBoss muss hierfür eine '*-service.xml'-Datei in das JBoss-Deploy-Verzeichnis kopiert werden.

    Legen Sie im Unterverzeichnis '<MeinJmsProjekt>\conf' die folgende Datei 'wetter-service.xml' an:

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Destination without a configured SecurityManager or without a SecurityConf
         will default to role guest with read=true, write=true, create=false. -->
    <server>
      <mbean code="org.jboss.mq.server.jmx.Topic"
             name="jboss.mq.destination:service=Topic,name=WetterTopic">
        <depends optional-attribute-name="DestinationManager">
          jboss.mq:service=DestinationManager
        </depends>
        <depends optional-attribute-name="SecurityManager">
          jboss.mq:service=SecurityManager
        </depends>
      </mbean>
    </server>
    

    Kopieren Sie diese Datei in das JBoss-Deploy-Verzeichnis:

    copy D:\MeinWorkspace\MeinJmsProjekt\conf\wetter-service.xml C:\JBoss\server\default\deploy

    Bei anderen Java EE Application Servern müssen entweder ähnliche Dateien erstellt werden oder JMS wird über die Server-Konfiguration (z.B. Web-Konsole) eingerichtet.



Namen im JNDI-Context anzeigen

JNDI (Java Naming and Directory Interface) bietet einen Namens- und Verzeichnisdienst, über den Objekte und Dienste gefunden und verfügbar gemacht werden.

Besonders zu Beginn kann es sehr hilfreich sein, die genauen Namen aller JNDI-Einträge anzeigen zu lassen, da sie bei den verschiedenen Java EE Application Servern unterschiedlich vergeben werden können.

Führen Sie hierfür das Testprogramm unter jee-jndi.htm#Auslesen-Namen-im-JNDI aus.



Queue (Point-to-Point)

  1. QueueSender

    Vergegenwärtigen Sie sich den Unterschied zwischen 'Queue' und 'Topic'.

    Der folgende QueueSender sendet zehn Nachrichten an ein Queue.

    Speichern Sie im Verzeichnis '<MeinJmsProjekt>\src\meinjmspackage' die folgende Datei 'MyQueueSender.java':

    package meinjmspackage;
    
    import javax.jms.*;
    import javax.naming.*;
    
    public class MyQueueSender
    {
      public static void main( String[] args ) throws NamingException, JMSException
      {
        final String MEINE_QUEUE = "queue/testQueue";
        Context         ctx      = null;
        QueueConnection connect  = null;
        QueueSession    session  = null;
        Queue           queue    = null;
        QueueSender     sender   = null;
        try {
          ctx = new InitialContext();
          QueueConnectionFactory fact = (QueueConnectionFactory)
                                        ctx.lookup( "ConnectionFactory" );
          connect = fact.createQueueConnection();
          session = connect.createQueueSession( false, Session.AUTO_ACKNOWLEDGE );
          try {
            queue = (Queue) ctx.lookup( MEINE_QUEUE );
          } catch( NameNotFoundException ex ) {
            queue = session.createQueue( MEINE_QUEUE );
            ctx.bind( MEINE_QUEUE, queue );
          }
          sender = session.createSender( queue );
          connect.start();
          for( int i=0; i<10; i++ ) {
            TextMessage msg = session.createTextMessage();
            msg.setText( "Die " + (i+1) + ". Meldung des MyQueueSenders." );
            sender.send( msg );
            System.out.println( "Sending " + msg.getText() );
            // System.out.println( "Sending " + msg.toString() );
          }
        } finally {
          try { if( null != sender  ) sender.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != session ) session.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != connect ) connect.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != ctx     ) ctx.close();     } catch( Exception ex ) {/*ok*/}
        }
      }
    }
    
  2. Queue-receive

    Der folgende QueueReceiver empfängt maximal 20 Sekunden lang bis zu 20 Nachrichten von einer Queue.

    Anders als ein Listener wartet 'QueueReceiver.receive(1000)' synchron auf Messages (mit vorgegebenem Timeout).

    Speichern Sie im Verzeichnis '<MeinJmsProjekt>\src\meinjmspackage' die folgende Datei 'MyQueueReceive.java':

    package meinjmspackage;
    
    import javax.jms.*;
    import javax.naming.*;
    
    public class MyQueueReceive
    {
      public static void main( String[] args ) throws Exception
      {
        final String MEINE_QUEUE = "queue/testQueue";
        Context         ctx      = null;
        QueueConnection connect  = null;
        QueueSession    session  = null;
        Queue           queue    = null;
        QueueReceiver   receiver = null;
        try {
          ctx = new InitialContext();
          QueueConnectionFactory fact = (QueueConnectionFactory)
                                        ctx.lookup( "ConnectionFactory" );
          connect = fact.createQueueConnection();
          session = connect.createQueueSession( false, Session.AUTO_ACKNOWLEDGE );
          try {
            queue = (Queue) ctx.lookup( MEINE_QUEUE );
          } catch( NameNotFoundException ex ) {
            queue = session.createQueue( MEINE_QUEUE );
            ctx.bind( MEINE_QUEUE, queue );
          }
          receiver = session.createReceiver( queue );
          connect.start();
          for( int i=0; i<20; i++ ) {
            TextMessage msg = (TextMessage) receiver.receive( 1000 );
            if( null != msg ) {
              System.out.println( msg.getText() );
              msg.acknowledge();
            }
          }
        } finally {
          try { if( null != receiver ) receiver.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != session  ) session.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != connect  ) connect.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != ctx      ) ctx.close();      } catch( Exception ex ) {/*ok*/}
        }
      }
    }
    
  3. Queue-Listener

    Der folgende Queue-Listener empfängt 20 Sekunden lang Nachrichten von einer Queue.

    Anders als bei 'receive()' braucht er als Listener nicht auf Messages zu warten, sondern empfängt sie asynchron, indem er sich über 'QueueReceiver.setMessageListener(new MyQueueListener())' registriert, wodurch Messages an die 'onMessage(Message message)'-Callback-Methode geschickt werden.

    Speichern Sie im Verzeichnis '<MeinJmsProjekt>\src\meinjmspackage' die folgende Datei 'MyQueueListener.java':

    package meinjmspackage;
    
    import javax.jms.*;
    import javax.naming.*;
    
    public class MyQueueListener implements MessageListener
    {
      public static void main( String[] args ) throws Exception
      {
        final String MEINE_QUEUE = "queue/testQueue";
        Context         ctx      = null;
        QueueConnection connect  = null;
        QueueSession    session  = null;
        Queue           queue    = null;
        QueueReceiver   receiver = null;
        try {
          ctx = new InitialContext();
          QueueConnectionFactory fact = (QueueConnectionFactory)
                                        ctx.lookup( "ConnectionFactory" );
          connect = fact.createQueueConnection();
          session = connect.createQueueSession( false, Session.AUTO_ACKNOWLEDGE );
          try {
            queue = (Queue) ctx.lookup( MEINE_QUEUE );
          } catch( NameNotFoundException ex ) {
            queue = session.createQueue( MEINE_QUEUE );
            ctx.bind( MEINE_QUEUE, queue );
          }
          receiver = session.createReceiver( queue );
          receiver.setMessageListener( new MyQueueListener() );
          connect.start();
          Thread.sleep( 20000 );
        } finally {
          try { if( null != receiver ) receiver.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != session  ) session.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != connect  ) connect.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != ctx      ) ctx.close();      } catch( Exception ex ) {/*ok*/}
        }
      }
    
      public void onMessage( Message message )
      {
        try {
          TextMessage msg = (TextMessage) message;
          System.out.println( msg.getText() );
          message.acknowledge();
        } catch( JMSException ex ) {
          System.out.println( ex.getMessage() );
        }
      }
    }
    
  4. Achten Sie darauf, dass die 'Vorbereitungen' durchgeführt sind.

    Prüfen Sie mit der 'JNDI-Context-Testroutine', ob unter 'queue' der Eintrag 'queue/testQueue' aufgelistet ist.

    Starten Sie JBoss und öffnen Sie drei Kommandozeilenfenster.

    Geben Sie im ersten Kommandozeilenfenster ein:

    cd \MeinWorkspace\MeinJmsProjekt

    set CLASSPATH=.;bin;conf;lib/jbossall-client.jar

    javac -d bin src/meinjmspackage/*.java

    java meinjmspackage.MyQueueListener

    Geben Sie im zweiten Kommandozeilenfenster ein:

    cd \MeinWorkspace\MeinJmsProjekt

    set CLASSPATH=.;bin;conf;lib/jbossall-client.jar

    java meinjmspackage.MyQueueReceive

    Geben Sie im dritten Kommandozeilenfenster ein:

    cd \MeinWorkspace\MeinJmsProjekt

    set CLASSPATH=.;bin;conf;lib/jbossall-client.jar

    java meinjmspackage.MyQueueSender

    Starten Sie dabei das jeweils letzte 'java ...'-Kommando in der Reihenfolge der Kommandozeilenfenster, also 'MyQueueSender' zuletzt. Starten Sie diese drei Kommandos möglichst kurz hintereinander.

    In allen drei Kommandozeilenfenstern sollen Nachrichten erscheinen. Im 'MyQueueSender'-Kommandozeilenfenster erscheinen alle zehn Nachrichten. Die beiden anderen Kommandozeilenfenster teilen sich die Nachrichten, jede Nachricht erscheint also in genau einem Empfänger-Kommandozeilenfenster.



Topic (Publish-and-Subscribe)

  1. TopicPublisher

    Vergegenwärtigen Sie sich den Unterschied zwischen 'Queue' und 'Topic'.

    Der folgende TopicPublisher sendet zehn Wetternachrichten an ein Topic.

    Dabei gibt es eine Besonderheit: Während 'Wetterlage', 'Windrichtung' und 'Temperatur' normal über eine 'MapMessage' im Body der 'Message' übermittelt werden, wird die 'Stadt'-Information getrennt davon als 'Message'-Property gesetzt. Dies werden wir weiter unten im 'Topic-Listener'-Beispiel für einen Nachrichtenfilter ausnutzen.

    Speichern Sie im Verzeichnis '<MeinJmsProjekt>\src\meinjmspackage' die folgende Datei 'MyTopicPublisher.java':

    package meinjmspackage;
    
    import javax.jms.*;
    import javax.naming.*;
    
    public class MyTopicPublisher
    {
      public static void main( String[] args ) throws NamingException, JMSException
      {
        final String    WETTER_TOPIC   = "topic/WetterTopic";
        final String[]  STAEDTE        = { "Aachen", "Berlin" };
        final String[]  WETTERLAGEN    = { "Sonnig", "Wolkig", "Regen " };
        final String[]  WINDRICHTUNGEN = { "Nord", "West", "Sued", "Ost " };
        Context         ctx     = null;
        TopicConnection connect = null;
        TopicSession    session = null;
        Topic           topic   = null;
        TopicPublisher  sender  = null;
        try {
          ctx = new InitialContext();
          TopicConnectionFactory fact = (TopicConnectionFactory)
                                        ctx.lookup( "ConnectionFactory" );
          connect = fact.createTopicConnection();
          session = connect.createTopicSession( false, Session.AUTO_ACKNOWLEDGE );
          try {
            topic = (Topic) ctx.lookup( WETTER_TOPIC );
          } catch( NameNotFoundException ex ) {
            topic = session.createTopic( WETTER_TOPIC );
            ctx.bind( WETTER_TOPIC, topic );
          }
          sender = session.createPublisher( topic );
          connect.start();
          for( int i=0; i<10; i++ ) {
            int rndm = (int) (Math.random() * 300);
            String stadt        = STAEDTE[rndm % STAEDTE.length];
            String wetterlage   = WETTERLAGEN[rndm % WETTERLAGEN.length];
            String windrichtung = WINDRICHTUNGEN[rndm % WINDRICHTUNGEN.length];
            double temperatur   = (double) (rndm - 50) / 10;
            MapMessage msg = session.createMapMessage();
            msg.setStringProperty( "Stadt", stadt );
            msg.setString( "Wetterlage",   wetterlage );
            msg.setString( "Windrichtung", windrichtung );
            msg.setDouble( "Temperatur",   temperatur );
            sender.publish( msg );
            System.out.println( "Sending Stadt=" + stadt
                                     + " Wl=" + wetterlage
                                     + " Wr=" + windrichtung
                                     + " T="  + temperatur + "C" );
            // System.out.println( "Sending " + msg.toString() );
          }
        } finally {
          try { if( null != sender  ) sender.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != session ) session.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != connect ) connect.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != ctx     ) ctx.close();     } catch( Exception ex ) {/*ok*/}
        }
      }
    }
    
  2. Topic-receive

    Der folgende Topic-Empfänger empfängt maximal 20 Sekunden lang bis zu 20 Wetternachrichten von einem Topic.

    Anders als ein Listener wartet 'TopicSubscriber.receive(1000)' synchron auf Messages (mit vorgegebenem Timeout).

    Speichern Sie im Verzeichnis '<MeinJmsProjekt>\src\meinjmspackage' die folgende Datei 'MyTopicReceive.java':

    package meinjmspackage;
    
    import javax.jms.*;
    import javax.naming.*;
    
    public class MyTopicReceive
    {
      public static void main( String[] args ) throws Exception
      {
        final String WETTER_TOPIC = "topic/WetterTopic";
        Context         ctx       = null;
        TopicConnection connect   = null;
        TopicSession    session   = null;
        Topic           topic     = null;
        TopicSubscriber subscrib  = null;
        try {
          ctx = new InitialContext();
          TopicConnectionFactory fact = (TopicConnectionFactory)
                                        ctx.lookup( "ConnectionFactory" );
          connect = fact.createTopicConnection();
          session = connect.createTopicSession( false, Session.AUTO_ACKNOWLEDGE );
          try {
            topic = (Topic) ctx.lookup( WETTER_TOPIC );
          } catch( NameNotFoundException ex ) {
            topic = session.createTopic( WETTER_TOPIC );
            ctx.bind( WETTER_TOPIC, topic );
          }
          subscrib = session.createSubscriber( topic );
          connect.start();
          for( int i=0; i<20; i++ ) {
            MapMessage msg = (MapMessage)subscrib.receive( 1000 );
            if( null != msg ) {
              System.out.println( "Receiving: Stadt=" + msg.getStringProperty( "Stadt" )
                                          + " Wl=" + msg.getString( "Wetterlage" )
                                          + " Wr=" + msg.getString( "Windrichtung" )
                                          + " T="  + msg.getDouble( "Temperatur" ) + "C" );
              msg.acknowledge();
            }
          }
        } finally {
          try { if( null != subscrib ) subscrib.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != session  ) session.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != connect  ) connect.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != ctx      ) ctx.close();      } catch( Exception ex ) {/*ok*/}
        }
      }
    }
    
  3. Topic-Listener (mit Filter)

    Der folgende Topic-Listener empfängt 20 Sekunden lang Wetternachrichten von einem Topic.

    Anders als bei 'receive()' braucht er als Listener nicht auf Messages zu warten, sondern empfängt sie asynchron, indem er sich über 'TopicSubscriber.setMessageListener(new MyTopicListener())' registriert, wodurch Messages an die 'onMessage(Message message)'-Callback-Methode geschickt werden.

    Dabei gibt es eine Besonderheit: Oben im 'TopicPublisher'-Beispiel wurden 'Wetterlage', 'Windrichtung' und 'Temperatur' normal über eine 'MapMessage' im Body der 'Message' übermittelt, während die 'Stadt'-Information getrennt davon als 'Message'-Property gesetzt wurde. Dies wird jetzt für einen Nachrichtenfilter ausgenutzt. Wird ein Stadtname als Kommandozeilen-Argument übergeben, wird 'createSubscriber()' nicht mit
    subscrib = session.createSubscriber( topic ); sondern stattdessen mit
    subscrib = session.createSubscriber( topic, "Stadt='"+ args[0] + "'", true ); aufgerufen, und es werden nur Nachrichten für die gewählte Stadt ausfiltert und übermittelt.

    Speichern Sie im Verzeichnis '<MeinJmsProjekt>\src\meinjmspackage' die folgende Datei 'MyTopicListener.java':

    package meinjmspackage;
    
    import javax.jms.*;
    import javax.naming.*;
    
    public class MyTopicListener implements MessageListener
    {
      public static void main( String[] args ) throws Exception
      {
        final String WETTER_TOPIC = "topic/WetterTopic";
        Context         ctx       = null;
        TopicConnection connect   = null;
        TopicSession    session   = null;
        Topic           topic     = null;
        TopicSubscriber subscrib  = null;
        try {
          ctx = new InitialContext();
          TopicConnectionFactory fact = (TopicConnectionFactory)
                                        ctx.lookup( "ConnectionFactory" );
          connect = fact.createTopicConnection();
          session = connect.createTopicSession( false, Session.AUTO_ACKNOWLEDGE );
          try {
            topic = (Topic) ctx.lookup( WETTER_TOPIC );
          } catch( NameNotFoundException ex ) {
            topic = session.createTopic( WETTER_TOPIC );
            ctx.bind( WETTER_TOPIC, topic );
          }
          if( null != args && 0 < args.length )
            subscrib = session.createSubscriber( topic, "Stadt='"+ args[0] + "'", true );
          else
            subscrib = session.createSubscriber( topic );
          subscrib.setMessageListener( new MyTopicListener() );
          connect.start();
          Thread.sleep( 20000 );
        } finally {
          try { if( null != subscrib ) subscrib.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != session  ) session.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != connect  ) connect.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != ctx      ) ctx.close();      } catch( Exception ex ) {/*ok*/}
        }
      }
    
      public void onMessage( Message message )
      {
        try {
          MapMessage msg = (MapMessage)message;
          System.out.println( "Receiving: Stadt=" + msg.getStringProperty( "Stadt" )
                                      + " Wl=" + msg.getString( "Wetterlage" )
                                      + " Wr=" + msg.getString( "Windrichtung" )
                                      + " T="  + msg.getDouble( "Temperatur" ) + "C" );
          message.acknowledge();
        } catch( JMSException ex ) {
          System.out.println( ex.getMessage() );
        }
      }
    }
    
  4. Achten Sie darauf, dass die 'Vorbereitungen' durchgeführt sind.

    Prüfen Sie mit der 'JNDI-Context-Testroutine', ob unter 'topic' der Eintrag 'topic/WetterTopic' aufgelistet ist.

    Starten Sie JBoss und öffnen Sie drei Kommandozeilenfenster.

    Geben Sie im ersten Kommandozeilenfenster ein:

    cd \MeinWorkspace\MeinJmsProjekt

    set CLASSPATH=.;bin;conf;lib/jbossall-client.jar

    javac -d bin src/meinjmspackage/*.java

    java meinjmspackage.MyTopicListener

    Geben Sie im zweiten Kommandozeilenfenster ein:

    cd \MeinWorkspace\MeinJmsProjekt

    set CLASSPATH=.;bin;conf;lib/jbossall-client.jar

    java meinjmspackage.MyTopicReceive

    Geben Sie im dritten Kommandozeilenfenster ein:

    cd \MeinWorkspace\MeinJmsProjekt

    set CLASSPATH=.;bin;conf;lib/jbossall-client.jar

    java meinjmspackage.MyTopicPublisher

    Starten Sie dabei das jeweils letzte 'java ...'-Kommando in der Reihenfolge der Kommandozeilenfenster, also 'MyTopicPublisher' zuletzt. Starten Sie diese drei Kommandos möglichst kurz hintereinander.

    In allen drei Kommandozeilenfenstern erscheinen die gleichen Wetternachrichten (allerdings nicht immer in der gleichen Reihenfolge).

    Geben Sie anschließend in einem Kommandozeilenfenster ein:

    java meinjmspackage.MyTopicListener Aachen

    Geben Sie sofort danach in einem anderen Kommandozeilenfenster ein:

    java meinjmspackage.MyTopicPublisher

    Jetzt werden nur noch Wetternachrichten für Aachen empfangen.



QueueRequestor

  1. QueueRequestor

    Der folgende QueueRequestor sendet zehn Nachrichten an ein Queue. Anders als die bisherigen Sender/Publisher erwartet er eine Antwortnachricht. Für jede Nachricht öffnet er einen temporären Rückkanal, macht diesen über das JMSReplyTo-Feld zugänglich, registriert sich als Empfänger und wartet auf eine Antwort.

    Speichern Sie im Verzeichnis '<MeinJmsProjekt>\src\meinjmspackage' die folgende Datei 'MyQueueRequestor.java':

    package meinjmspackage;
    
    import javax.jms.*;
    import javax.naming.*;
    
    public class MyQueueRequestor
    {
      public static void main( String[] args ) throws NamingException, JMSException
      {
        final String MEINE_QUEUE = "queue/testQueue";
        Context         ctx      = null;
        QueueConnection connect  = null;
        QueueSession    session  = null;
        Queue           queue    = null;
        QueueRequestor  sender   = null;
        try {
          ctx = new InitialContext();
          QueueConnectionFactory fact = (QueueConnectionFactory)
                                        ctx.lookup( "ConnectionFactory" );
          connect = fact.createQueueConnection();
          session = connect.createQueueSession( false, Session.AUTO_ACKNOWLEDGE );
          try {
            queue = (Queue) ctx.lookup( MEINE_QUEUE );
          } catch( NameNotFoundException ex ) {
            queue = session.createQueue( MEINE_QUEUE );
            ctx.bind( MEINE_QUEUE, queue );
          }
          sender = new QueueRequestor( session, queue );
          connect.start();
          for( int i=0; i<10; i++ ) {
            TextMessage msg = session.createTextMessage();
            msg.setText( "Die " + (i+1) + ". Anfrage des MyQueueRequestors." );
            System.out.println( "Sending:  " + msg.getText() );
            TextMessage answer = (TextMessage) sender.request( msg );
            System.out.println( "Reveived: " + answer.getText() );
          }
        } finally {
          try { if( null != sender  ) sender.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != session ) session.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != connect ) connect.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != ctx     ) ctx.close();     } catch( Exception ex ) {/*ok*/}
        }
      }
    }
    
  2. QueueRequestor-reply

    Der folgende Nachrichtenbeantworter empfängt 20 Sekunden lang Nachrichten von einer Queue und beantwortet sie.

    Speichern Sie im Verzeichnis '<MeinJmsProjekt>\src\meinjmspackage' die folgende Datei 'MyQueueRequestorAnswer.java':

    package meinjmspackage;
    
    import javax.jms.*;
    import javax.naming.*;
    
    public class MyQueueRequestorAnswer implements MessageListener
    {
      final String MEINE_QUEUE = "queue/testQueue";
      Context         ctx      = null;
      QueueConnection connect  = null;
      QueueSession    session  = null;
      Queue           queue    = null;
      QueueReceiver   receiver = null;
      QueueSender     replySnd = null;
    
      public static void main( String[] args ) throws Exception
      {
        new MyQueueRequestorAnswer();
      }
    
      public MyQueueRequestorAnswer() throws Exception
      {
        try {
          ctx = new InitialContext();
          QueueConnectionFactory fact = (QueueConnectionFactory)
                                        ctx.lookup( "ConnectionFactory" );
          connect = fact.createQueueConnection();
          session = connect.createQueueSession( false, Session.AUTO_ACKNOWLEDGE );
          try {
            queue = (Queue) ctx.lookup( MEINE_QUEUE );
          } catch( NameNotFoundException ex ) {
            queue = session.createQueue( MEINE_QUEUE );
            ctx.bind( MEINE_QUEUE, queue );
          }
          receiver = session.createReceiver( queue );
          receiver.setMessageListener( this );
          connect.start();
          Thread.sleep( 20000 );
        } finally {
          try { if( null != replySnd ) replySnd.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != receiver ) receiver.close(); } catch( Exception ex ) {/*ok*/}
          try { if( null != session  ) session.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != connect  ) connect.close();  } catch( Exception ex ) {/*ok*/}
          try { if( null != ctx      ) ctx.close();      } catch( Exception ex ) {/*ok*/}
        }
      }
    
      public void onMessage( Message message )
      {
        try {
          TextMessage msg = (TextMessage) message;
          System.out.println( "Reveived:  " + msg.getText() );
          TextMessage answer = session.createTextMessage();
          answer.setText( "Echo '" + msg.getText() + "'." );
          System.out.println( "Answering: " + answer.getText() );
          Queue reply = (Queue)msg.getJMSReplyTo();
          replySnd = session.createSender( reply );
          replySnd.send( answer );
          replySnd.close();
          replySnd = null;
          message.acknowledge();
        } catch( JMSException ex ) {
          System.out.println( ex.getMessage() );
        }
      }
    }
    
  3. Achten Sie darauf, dass die 'Vorbereitungen' durchgeführt sind.

    Prüfen Sie mit der 'JNDI-Context-Testroutine', ob unter 'queue' der Eintrag 'queue/testQueue' aufgelistet ist.

    Starten Sie JBoss und öffnen Sie zwei Kommandozeilenfenster.

    Geben Sie im ersten Kommandozeilenfenster ein:

    cd \MeinWorkspace\MeinJmsProjekt

    set CLASSPATH=.;bin;conf;lib/jbossall-client.jar

    javac -d bin src/meinjmspackage/*.java

    java meinjmspackage.MyQueueRequestorAnswer

    Geben Sie im zweiten Kommandozeilenfenster ein:

    cd \MeinWorkspace\MeinJmsProjekt

    set CLASSPATH=.;bin;conf;lib/jbossall-client.jar

    java meinjmspackage.MyQueueRequestor

    Starten Sie dabei das jeweils letzte 'java ...'-Kommando in der Reihenfolge der Kommandozeilenfenster, also 'MyQueueRequestor' zuletzt. Starten Sie diese zwei Kommandos möglichst kurz hintereinander.

    In den beiden Kommandozeilenfenstern können Sie das Anfrage-/Antwort-Spiel beobachten.



MDB (Message Driven Bean)

Erläuterungen und ein Programmierbeispiel zu MDB (Message Driven Bean) finden Sie in jee-ejb2.htm#Beispiel-MDB.



Links auf weiterführende Informationen





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