Un client JMS remoto

Continuo a seguire il blog di Masoud Kalali e costruisco ora un client remoto per la coda JMS che abbiamo costruito in questo post.

Lo scopo di questo client sarà quello di mandare dei messaggi alla coda che verranno gestiti dal Message-Driven Bean che abbiamo scritto.

Un controllo preventivo

Conviene controllare che il servizio JMS sia configurato correttamente nel nostro application server.
Verifichiamo quindi che GlassFish sia in esecuzione, lanciamo l'Admin Console, selezioniamo il nodo Configuration, Java Message Service, e facciamo un ping del servizio.
Dovremmo ottenere un messaggio di successo. Nel mio caso avevo un errore, dovuto al fatto che, lavorando su un laptop, il mio indirizzo di rete era cambiato da quando avevo configurato GlassFish a quando mi sono messo a lavorare su questo esercizio.

Per superare questo problema (nel caso capiti anche al lettore) basta intervenire sulla lista di JMS Host, creando un nuovo host o modificando l'esistente, e aggiornando, se é il caso, il "Default JMS Host" per il JMS Service.

Il contesto e le librerie

Il punto nell'accesso remoto a JMS sta nel fatto che non abbiamo modo di accedere al contesto iniziale già inizializzato correttamente con i parametri opportuni per l'Application Server e dobbiamo usare alcune librerie per permettere la connessione.

Dobbiamo aggiungere perciò al nostro progetto una decina di jar che ci andiamo a prendere nelle librerie di glassfish, qui di fianco un immagine che riporta la libreria che mi sono creato per l'occorrenza e che include questi file:
  • appserv-rt.jar,
  • javaee.jar,
  • appserv-admin.jar,
  • appserv-launch.jar
  • appserv-ext.jar
  • appserv-deployment-client.jar
  • imqjmsra.jar,
  • jms.jar,
  • imq.jar,
  • imqbroker.jar.
I parametri per il contesto dobbiamo reperirli noi da qualche parte e poi passarli al contesto.

Insomma non possiamo fare come nel nostro client locale:

Context ctx = new InitialContext();

ma dobbiamo piuttosto passargli un paio di parametri.

Creiamo dunque un semplice progetto JavaSE, una sola classe Main dove il contesto come é membro statico che viene inizializzato staticamente:

...
private static final String AS_URL = "iiop://127.0.0.1:3700";
private static final String AS_CLASS = "com.sun.appserv.naming.S1ASCtxFactory";

private static Context ctx;
static {
Hashtable properties = new Hashtable(2);
properties.put(Context.PROVIDER_URL, AS_URL);
properties.put(Context.INITIAL_CONTEXT_FACTORY, AS_CLASS);
try {
ctx = new InitialContext(properties);
}
catch (NamingException ex) {
ex.printStackTrace();
}
}

Al nostro InitialContext abbiamo passato l'indirizzo del provider e il nome della classe specializzata per fare da Context Factory iniziale per il nostro provider. Nel mio caso ho specificato l'indirizzo locale, in un caso reale va messo l'indirizzo della macchina a cui ci vogliamo connettere.

Fatto questo, poco cambia rispetto all'uso in locale, ecco infatti la funzione main:

private static final String CONNECTION = "jms/tConnectionFactory";
private static final String QUEUE = "jms/tQueue";
...

public static void main(String[] args) {
try {
ConnectionFactory f = (ConnectionFactory)ctx.lookup(CONNECTION);
Connection c = f.createConnection();
Session session = c.createSession(false, Session.AUTO_ACKNOWLEDGE);

Queue q = (Queue)ctx.lookup(QUEUE);
MessageProducer messageProducer = session.createProducer(q);

for(int i=0; i<5; i++) {
TextMessage message = session.createTextMessage("A message /" + i);
System.out.println("JmsClient message: " + message.getText());
messageProducer.send(message);
}
}
catch(Exception ex){
ex.printStackTrace();
}

System.exit(0);
}

Come al solito, abbiamo bisogno di una sessione, che viene creata a partire da una connessione, che arriva dalla ConnectionFactory che é reperita mediante lookup dal contesto.
Il MessageProducer viene creato a partire dalla sessione facendo riferimento alla coda che viene reperita tramite lookup dal contesto.

Creiamo un messaggio di testo per mezzo della sessione e lo spediamo alla coda per mezzo dell'oggetto MessageProducer.

Rivediamo il codice completo:

package jmsclient;

import java.util.Hashtable;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

public class Main {
private static final String AS_URL = "iiop://127.0.0.1:3700";
private static final String AS_CLASS = "com.sun.appserv.naming.S1ASCtxFactory";
private static final String CONNECTION = "jms/tConnectionFactory";
private static final String QUEUE = "jms/tQueue";

private static Context ctx;
static {
System.out.println("static ctor");

Hashtable properties = new Hashtable(2);
properties.put(Context.PROVIDER_URL, AS_URL);
properties.put(Context.INITIAL_CONTEXT_FACTORY, AS_CLASS);
try {
ctx = new InitialContext(properties);
}
catch (NamingException ex) {
ex.printStackTrace();
}
}

public static void main(String[] args) {
try {
ConnectionFactory f = (ConnectionFactory)ctx.lookup(CONNECTION);
Connection c = f.createConnection();
Session session = c.createSession(false, Session.AUTO_ACKNOWLEDGE);

Queue q = (Queue)ctx.lookup(QUEUE);
MessageProducer messageProducer = session.createProducer(q);

for(int i=0; i<5; i++) {
TextMessage message = session.createTextMessage("A message /" + i);
System.out.println("JmsClient message: " + message.getText());
messageProducer.send(message);
}
}
catch(Exception ex){
ex.printStackTrace();
}

System.exit(0);
}
}

Nessun commento:

Posta un commento