/* * Copyright (c) 2009, 2012 IBM Corp. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Dave Locke - initial API and implementation and/or initial documentation */ package org.eclipse.paho.client.mqttv3.internal; import java.io.IOException; import java.io.OutputStream; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttToken; import org.eclipse.paho.client.mqttv3.internal.wire.MqttAck; import org.eclipse.paho.client.mqttv3.internal.wire.MqttDisconnect; import org.eclipse.paho.client.mqttv3.internal.wire.MqttOutputStream; import org.eclipse.paho.client.mqttv3.internal.wire.MqttWireMessage; import org.eclipse.paho.client.mqttv3.logging.Logger; import org.eclipse.paho.client.mqttv3.logging.LoggerFactory; public class CommsSender implements Runnable { /** * Sends MQTT packets to the server on its own thread */ private boolean running = false; private Object lifecycle = new Object(); private ClientState clientState = null; private MqttOutputStream out; private ClientComms clientComms = null; private CommsTokenStore tokenStore = null; private Thread sendThread = null; private final static String className = CommsSender.class.getName(); private Logger log = LoggerFactory.getLogger(LoggerFactory.MQTT_CLIENT_MSG_CAT, className); public CommsSender(ClientComms clientComms, ClientState clientState, CommsTokenStore tokenStore, OutputStream out) { this.out = new MqttOutputStream(out); this.clientComms = clientComms; this.clientState = clientState; this.tokenStore = tokenStore; log.setResourceName(clientComms.getClient().getClientId()); } /** * Starts up the Sender thread. */ public void start(String threadName) { synchronized (lifecycle) { if (running == false) { running = true; sendThread = new Thread(this, threadName); sendThread.start(); } } } /** * Stops the Sender's thread. This call will block. */ public void stop() { final String methodName = "stop"; synchronized (lifecycle) { //@TRACE 800=stopping sender log.fine(className,methodName,"800"); if (running) { running = false; if (!Thread.currentThread().equals(sendThread)) { try { // first notify get routine to finish clientState.notifyQueueLock(); // Wait for the thread to finish. sendThread.join(); } catch (InterruptedException ex) { } } } sendThread=null; //@TRACE 801=stopped log.fine(className,methodName,"801"); } } public void run() { final String methodName = "run"; MqttWireMessage message = null; while (running && (out != null)) { try { message = clientState.get(); if (message != null) { //@TRACE 802=network send key={0} msg={1} log.fine(className,methodName,"802", new Object[] {message.getKey(),message}); if (message instanceof MqttAck) { out.write(message); out.flush(); } else { MqttToken token = tokenStore.getToken(message); // While quiescing the tokenstore can be cleared so need // to check for null for the case where clear occurs // while trying to send a message. if (token != null) { synchronized (token) { out.write(message); try { out.flush(); } catch (IOException ex) { // The flush has been seen to fail on disconnect of a SSL socket // as disconnect is in progress this should not be treated as an error if (!(message instanceof MqttDisconnect)) throw ex; } clientState.notifySent(message); } } } } else { // null message //@TRACE 803=get message returned null, stopping} log.fine(className,methodName,"803"); running = false; } } catch (MqttException me) { handleRunException(message, me); } catch (Exception ex) { handleRunException(message, ex); } } // end while //@TRACE 805=< log.fine(className, methodName,"805"); } private void handleRunException(MqttWireMessage message, Exception ex) { final String methodName = "handleRunException"; //@TRACE 804=exception log.fine(className,methodName,"804",null, ex); MqttException mex; if ( !(ex instanceof MqttException)) { mex = new MqttException(MqttException.REASON_CODE_CONNECTION_LOST, ex); } else { mex = (MqttException)ex; } running = false; clientComms.shutdownConnection(null, mex); } }