All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.client.StompConnection Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 35.0.0.Beta1
Show newest version
package org.jgroups.client;

import org.jgroups.annotations.Experimental;
import org.jgroups.annotations.Unsupported;
import org.jgroups.logging.Log;
import org.jgroups.logging.LogFactory;
import org.jgroups.protocols.STOMP;
import org.jgroups.util.Util;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.*;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.SSLContext;
import java.util.*;

/**
 * STOMP client to access the STOMP [1] protocol. Note that the full STOMP protocol is not implemented, e.g. transactions
 * are currently not supported.
 * 

* The interactive client can be started with -h HOST -p PORT, which are the hostname and port of a JGroups server, running * with STOMP in its stack configuration. The interactive client supports automatic failover to a different server if * the currently connected-to server crashes, and a simple syntax for sending STOMP messages: *

 * subscribe DEST // example: subscribe /topics/a
 * send DEST message // example: send /topics/a Hello world
 * 
*

* [1] http://stomp.codehaus.org/Protocol * @author Bela Ban */ @Experimental public class StompConnection implements Runnable { protected SocketFactory socket_factory; protected Socket sock; protected DataInputStream in; protected DataOutputStream out; // collection of server addresses, we can pick any one to connect to protected final Set server_destinations=new HashSet<>(); protected final Set listeners=new HashSet<>(); protected final Set subscriptions=new HashSet<>(); protected final Set callbacks =new HashSet<>(); protected Thread runner; protected volatile boolean running=false; protected String session_id; protected String userid; protected String password; protected boolean reconnect; protected final Log log=LogFactory.getLog(getClass()); /** * @param dest IP address + ':' + port, e.g. "192.168.1.5:8787" */ public StompConnection(String dest) { this(dest, null, null, false, false); } public StompConnection(String dest, boolean reconnect, boolean ssl) { this(dest, null, null, reconnect, ssl); } public StompConnection(String dest, boolean reconnect, SSLContext ssl) { this(dest, null, null, reconnect, ssl); } public StompConnection(String dest, String userid, String password, boolean reconnect, boolean ssl) {; server_destinations.add(dest); this.userid = userid; this.password = password; this.reconnect = reconnect; if (ssl) socket_factory = SSLSocketFactory.getDefault(); else socket_factory = SocketFactory.getDefault(); } public StompConnection(String dest, String userid, String password, boolean reconnect, SSLContext sslcontext) {; server_destinations.add(dest); this.userid = userid; this.password = password; this.reconnect = reconnect; socket_factory = sslcontext.getSocketFactory(); } public String getSessionId() {return session_id;} public void addListener(Listener listener) { if(listener != null) listeners.add(listener); } public void addCallback(ConnectionCallback cb) { if(cb != null) callbacks.add(cb); } public void removeListener(Listener listener) { if(listener != null) listeners.remove(listener); } public void removeCallback(ConnectionCallback cb) { if(cb != null) callbacks.remove(cb); } protected synchronized void startRunner() { if(runner == null || !runner.isAlive()) { running = true; runner=new Thread(this, "StompConnection receiver"); runner.start(); } } protected void sendConnect() { StringBuilder sb=new StringBuilder(); sb.append(STOMP.ClientVerb.CONNECT.name()).append("\n"); if(userid != null) sb.append("login: ").append(userid).append("\n"); if(password != null) sb.append("passcode: ").append(password).append("\n"); sb.append("\n"); try { synchronized(this) { out.write(sb.toString().getBytes()); out.write(STOMP.NULL_BYTE); out.flush(); } } catch(IOException ex) { log.error("failed to send connect message:", ex); } } public void subscribe(String destination) { if(destination == null) return; subscriptions.add(destination); if(isConnected()) { sendSubscribe(destination); } } protected void sendSubscribe(String destination) { StringBuilder sb=new StringBuilder(); sb.append(STOMP.ClientVerb.SUBSCRIBE.name()).append("\n"); sb.append("destination: ").append(destination).append("\n"); sb.append("\n"); try { synchronized(this) { out.write(sb.toString().getBytes()); out.write(STOMP.NULL_BYTE); out.flush(); } } catch(IOException ex) { log.error("failed subscribing to " + destination + ": ", ex); } } public void unsubscribe(String destination) { if(destination == null) return; subscriptions.remove(destination); if(isConnected()) { sendUnsubscribe(destination); } } protected void sendUnsubscribe(String destination) { StringBuilder sb=new StringBuilder(); sb.append(STOMP.ClientVerb.UNSUBSCRIBE.name()).append("\n"); sb.append("destination: ").append(destination).append("\n"); sb.append("\n"); try { synchronized(this) { out.write(sb.toString().getBytes()); out.write(STOMP.NULL_BYTE); out.flush(); } } catch(IOException ex) { log.error("failed unsubscribing from " + destination + ": ", ex); } } public void send(String destination, byte[] buf, int offset, int length, String ... headers) { StringBuilder sb=new StringBuilder(); sb.append(STOMP.ClientVerb.SEND.name()).append("\n"); if(destination != null) sb.append("destination: ").append(destination).append("\n"); if(buf != null) sb.append("content-length: ").append(length).append("\n"); if(headers != null && (headers.length & 1) == 0) { // must be even for(int i=0; i < headers.length; i++) sb.append(headers[i]).append(": ").append(headers[++i]).append("\n"); } sb.append("\n"); try { synchronized(this) { out.write(sb.toString().getBytes()); if(buf != null) out.write(buf, offset, length); out.write(STOMP.NULL_BYTE); out.flush(); } } catch (IOException e) { log.error("failed sending message to " + destination + ": ", e); } } /** * Sends an INFO without body */ public void send(String destination, String ... headers) { send(destination, null, 0, 0, headers); } public void send(String destination, byte[] buf, int offset, int length) { send(destination, buf, offset, length, (String[])null); } public void send(String destination, byte[] buf) { send(destination, buf, 0, buf.length); } public void run() { int timeout = 0; while(running) { try { if (!isConnected() && reconnect) { log.info("Reconnecting in "+timeout+"s."); try { Thread.sleep(timeout * 1000); } catch (InterruptedException e1) { // pass } timeout = timeout*2 > 60 ? 60 : (timeout+1)*2; try { connect(); } catch (IOException e) { // continue and attempt reconnect continue; } for (ConnectionCallback cb : callbacks) { cb.onConnect(); } } STOMP.Frame frame=STOMP.readFrame(in); if(frame != null) { STOMP.ServerVerb verb=STOMP.ServerVerb.valueOf(frame.getVerb()); if(log.isTraceEnabled()) log.trace("frame: " + frame); switch(verb) { case MESSAGE: byte[] buf=frame.getBody(); notifyListeners(frame.getHeaders(), buf, 0, buf != null? buf.length : 0); break; case CONNECTED: String sess_id=frame.getHeaders().get("session-id"); if(sess_id != null) { this.session_id=sess_id; } break; case ERROR: break; case INFO: notifyListeners(frame.getHeaders()); String endpoints=frame.getHeaders().get("endpoints"); if(endpoints != null) { List list=Util.parseCommaDelimitedStrings(endpoints); if(list != null) { boolean changed=server_destinations.addAll(list); if(changed && log.isDebugEnabled()) log.debug("INFO: new server target list: " + server_destinations); } } break; case RECEIPT: break; default: throw new IllegalArgumentException("verb " + verb + " is not known"); } } // reset the connection backoff when we successfully connect. timeout = 0; } catch(IOException e) { log.error("Connection closed unexpectedly:", e); if (reconnect) { closeConnections(); } else { disconnect(); } } catch(Throwable t) { log.error("failure reading frame", t); } } } protected void notifyListeners(Map headers, byte[] buf, int offset, int length) { for(Listener listener: listeners) { try { listener.onMessage(headers, buf, offset, length); } catch(Throwable t) { log.error("failed calling listener", t); } } } protected void notifyListeners(Map info) { for(Listener listener: listeners) { try { listener.onInfo(info); } catch(Throwable t) { log.error("failed calling listener", t); } } } public void connect() throws IOException{ for (String dest : server_destinations) { try { synchronized(this) { connectToDestination(dest); sendConnect(); } for(String subscription: subscriptions) { sendSubscribe(subscription); } log.info("Connected to " + dest); break; } catch(IOException ex) { if(log.isErrorEnabled()) log.error("failed connecting to " + dest + ":" + ex); closeConnections(); } } if(!isConnected()) throw new IOException("no target server available"); startRunner(); } public void startReconnectingClient() { startRunner(); } protected void connectToDestination(String dest) throws IOException { // parse destination int index=dest.lastIndexOf(":"); String host=dest.substring(0, index); int port=Integer.parseInt(dest.substring(index+1)); sock=socket_factory.createSocket(host, port); in=new DataInputStream(sock.getInputStream()); out=new DataOutputStream(sock.getOutputStream()); } public void disconnect() { running = false; closeConnections(); } protected void closeConnections() { Util.close(in); Util.close(out); Util.close(sock); } public boolean isConnected() { return sock != null && sock.isConnected() && !sock.isClosed(); } public static interface Listener { void onMessage(Map headers, byte[] buf, int offset, int length); void onInfo(Map information); } public static interface ConnectionCallback { void onConnect(); } public static void main(String[] args) throws IOException { String host="localhost"; String port="8787"; for(int i=0; i < args.length; i++) { if(args[i].equals("-h")) { host=args[++i]; continue; } if(args[i].equals("-p")) { port=args[++i]; continue; } System.out.println("StompConnection [-h host] [-p port]"); return; } StompConnection conn=new StompConnection(host+ ":" + port, true, false); conn.addListener(new Listener() { public void onMessage(Map headers, byte[] buf, int offset, int length) { System.out.println("<< " + new String(buf, offset, length) + ", headers: " + headers); } public void onInfo(Map information) { System.out.println("<< INFO: " + information); } }); conn.connect(); while(conn.isConnected()) { try { String line=Util.readStringFromStdin(": "); if(line.startsWith("subscribe")) { String dest=line.substring("subscribe".length()).trim(); conn.subscribe(dest); } else if(line.startsWith("unsubscribe")) { String dest=line.substring("unsubscribe".length()).trim(); conn.unsubscribe(dest); } else if(line.startsWith("send")) { String rest=line.substring("send".length()).trim(); int index=rest.indexOf(' '); if(index != -1) { String dest=rest.substring(0, index); String body=rest.substring(index+1); byte[] buf=body.getBytes(); conn.send(dest, buf, 0, buf.length); } } else if(line.startsWith("disconnect")) { conn.disconnect(); } } catch(Exception e) { e.printStackTrace(); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy