/* * (C) Copyright IBM Corp. 2008 * * LICENSE: Eclipse Public License v1.0 * http://www.eclipse.org/legal/epl-v10.html */ package com.ibm.gaiandb.tools.replay; import java.util.ArrayList; import java.util.Iterator; import com.ibm.mqtt.IMqttClient; import com.ibm.mqtt.MqttClient; import com.ibm.mqtt.MqttException; import com.ibm.mqtt.MqttNotConnectedException; import com.ibm.mqtt.MqttPersistenceException; import com.ibm.mqtt.MqttSimpleCallback; /** * @author hbowyer / DavidVyvyan * * A BrokerConnector connects to a broker and subscribes to given topics. * It also allows messages to be published to the broker. * * To process incoming messages differently (other than printing them out), override method publishArrived(). * To publish messages, use method publishMessage(). */ public class BrokerConnector implements MqttSimpleCallback { // Use PROPRIETARY notice if class contains a main() method, otherwise use COPYRIGHT notice. public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2008"; private String clientID = null ; // The client ID // must be unique // for every client // connecting to the // broker. private String brokerHost = null; private int brokerPort = -1; private String subscriptionTopic = null; // /battlefield2/# private boolean cleanStart = true; // Clean start is used to clear up any // subscription that the client may have // had from a previous connection. private short connectRetryInterval = 5000; // ms private short keepAliveInterval = 30; // The heartbeat interval for the // client in seconds. private int qualityOfService = 0; // Quality of Service (Qos) can be 0,1 // or 2 depending on how reliably the // message is to be delivered. private IMqttClient wmqttClient = null; // ClientMQIsdp from the WMQTT // library is the underlying object // used for publish/subscribe // communication. private ArrayList<IMqttClient> forwardingLinks = new ArrayList<IMqttClient>(); // List of brokers that // messages should be forwarded to. // see setForwardingLinkToBroker() // /** // * Create an instance of the subscriber and configure it. Stay subscribed // * and connected till the user presses a key. // */ // public static void main(String[] args) { // // try { // MQTTMessageStorer subscriber = new MQTTMessageStorer(); // subscriber.connect(); // subscriber.subscribe(); // waitForUserInput(); // subscriber.unsubscribe(); // subscriber.disconnect(); // } catch (Exception e) { // e.printStackTrace(); // } finally { // System.exit(0); // } // } protected void finalize() throws Throwable { try { logInfo("finalize(): Closing derby connection, Unsubscribing to MQTT topics and Disconnecting from Microbroker..."); unsubscribe(); terminate(); } catch (Exception e) { e.printStackTrace(); } finally { super.finalize(); } } /** * Constructor for the WMQTTSubscriber. Creates a WMQTT client object with * the broker details. NOTE: Registers the object as a simple WMQTT callback * handler to receive the connectionLost() and publishArrived() calls. * * * @throws SQLException * @throws SQLException * */ public BrokerConnector( String mqttClientName, String brokerAddress, int brokerPortNumber, String topic ) throws MqttException { this.clientID = mqttClientName; // Now the db is ready, setup mqtt client and subscribe to the message topic if ( null != brokerAddress && 0 < brokerPortNumber && null != topic ) { // If one of these isn't set we have nothing to store msgs from yet logInfo("Constructor starting BrokerConnector with these values: brokerAddress: " + brokerAddress + ", brokerPortNumber: " + brokerPortNumber + ", topic: " + topic); refreshBrokerClient( brokerAddress, brokerPortNumber, topic ); } } /** * * @param brokerAddress * @param brokerPortNumber * @param topic * @throws MqttException */ public void refreshBrokerClient( String brokerAddress, int brokerPortNumber, String topic ) throws MqttException { this.subscriptionTopic = topic; this.brokerHost = brokerAddress; this.brokerPort = brokerPortNumber; if ( null != wmqttClient ) terminate(); wmqttClient = MqttClient.createMqttClient(MqttClient.TCP_ID + brokerHost + "@" + brokerPort, null); wmqttClient.registerSimpleHandler(this); wmqttClient.connect(clientID, cleanStart, keepAliveInterval); if ( !wmqttClient.isConnected() ) throw new MqttException( "MQTT client not connected" ); if ( null != subscriptionTopic ) subscribe(); } public void setForwardingLinkToBroker( String brokerAddress, int brokerPortNumber ) throws MqttException { IMqttClient mc = MqttClient.createMqttClient(MqttClient.TCP_ID + brokerAddress + "@" + brokerPortNumber, null); // wmqttClient.registerSimpleHandler(this); // no subscriptions here.. we just publish on to this broker mc.connect(clientID, cleanStart, keepAliveInterval); if ( !mc.isConnected() ) throw new MqttException( "MQTT client not connected" ); synchronized ( forwardingLinks ) { forwardingLinks.add( mc ); } // if ( null != subscriptionTopic ) // subscribe(); } /** * Try connecting to be broker. Retry every 5 seconds till you are * connected. */ private void connect() { logInfo("Attempting to connect to the microbroker (re-try every " + connectRetryInterval + " ms)"); while (!wmqttClient.isConnected()) { try { wmqttClient.connect(clientID, cleanStart, keepAliveInterval); logInfo("Connected as " + clientID ); } catch (Exception e) { System.out.print('.'); try { Thread.sleep( connectRetryInterval ); } catch (InterruptedException ie) { ie.printStackTrace(); } } } } /** * This method is implemented as part of the MQIsdpSimpleCallback interface. * It is automatically called when the WMQTT client looses it connection to * the broker. Simply call the connect method. */ public void connectionLost() throws Exception { logInfo("Lost the connection to the broker...."); connect(); subscribe(); } /** * Subscribe to the subscription topic on the specified quality of service. * Subscription information is specified in a String array allowing multiple * subscriptions to be registered at one time. The quality of service for * each subscription in specified as an int value (0-2) in an array. */ private void subscribe() throws MqttException, MqttNotConnectedException { String[] subscriptionArray = { subscriptionTopic }; int[] qosArray = { qualityOfService }; wmqttClient.subscribe(subscriptionArray, qosArray); logInfo("Subscribed to the " + subscriptionTopic + " topic."); } /** * Unsubscribe from the subscription topic. One again a String array is used * so that multiple subscription string can be specified together. */ private void unsubscribe() throws MqttException, MqttNotConnectedException { String[] subscriptionArray = { subscriptionTopic }; wmqttClient.unsubscribe(subscriptionArray); logInfo("Unsubscribed from the " + subscriptionTopic + " topic."); } /** * Disconnect the WMQTT client from the broker. */ public void terminate() { try { wmqttClient.disconnect(); } catch (MqttException e) { System.out.println("BrokerConnector unable to disconnect from broker (terminating anyway), cause: " + e); } wmqttClient.terminate(); logInfo(clientID + " terminated client connection to the broker..."); synchronized( forwardingLinks ) { Iterator<IMqttClient> i = forwardingLinks.iterator(); while ( i.hasNext() ) { IMqttClient mc = i.next(); try { mc.disconnect(); } catch (MqttException e) { System.out.println("BrokerConnector unable to disconnect from forwarding link to other broker, cause: " + e); } mc.terminate(); } } logInfo(clientID + " disconnected forwarding links..."); } public void publish( String topic, String msg ) throws MqttNotConnectedException, MqttPersistenceException, IllegalArgumentException, MqttException { int qos = 2; // Delivery qos: 0 = no guarantees, 1 = at least once, 2 = once and only once boolean retain = false; wmqttClient.publish( topic, msg.getBytes(), qos, retain ); } /** * publishArrived() is implemented as part of the MQIsdpSimpleCallback * interface. It is a callback method used by subscribers to automatically * receive publications that are forwarded to them by a broker. * * Here it is used to forward messages on to other brokers that we have set up links to using method setForwardingLinkToBroker() */ public void publishArrived(String topic, byte[] messageData, int qos, boolean retain) { synchronized( forwardingLinks ) { Iterator<IMqttClient> i = forwardingLinks.iterator(); while ( i.hasNext() ) { IMqttClient mc = i.next(); try { mc.publish(topic, messageData, qos, retain); } catch (MqttException e) { System.out.println("BrokerConnector unable to forward message to broker, cause: " + e); } } } // String message = new String(messageData); // logInfo("Message: '" + message + "' received on topic '" + topic // + "'. Quality of service is " + qos // + ", retain flag is set to " + retain); } private static void logInfo( String s ) { System.out.println( s ); } // /** // * Wait for the user to press a key. // */ // private static void waitForUserInput() { // logInfo("Press any key to exit...."); // BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // try { // br.readLine(); // } catch (IOException ex) { // ex.printStackTrace(); // } // } }