/*
* 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.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.internal.trace.Trace;
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;
public class CommsSender implements Runnable {
/**
* Receives MQTT packets from the server.
*/
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 Trace trace;
public CommsSender(Trace trace, ClientComms clientComms, ClientState clientState, CommsTokenStore tokenStore, OutputStream out) {
this.trace = trace;
this.out = new MqttOutputStream(out);
this.clientComms = clientComms;
this.clientState = clientState;
this.tokenStore = tokenStore;
}
/**
* Starts up the Sender thread.
*/
public void start() {
if (running == false) {
running = true;
new Thread(this, "MQTT Client Comms Sender").start();
}
}
/**
* Stops the Sender's thread. This call will block.
*/
public void stop() throws IOException {
synchronized (lifecycle) {
//@TRACE 800=stopping sender
trace.trace(Trace.FINE,800);
if (running) {
running = false;
try {
//@TRACE 801=stop: wait on lifecycle
trace.trace(Trace.FINE,801);
// Wait for the thread to finish.
lifecycle.wait();
}
catch (InterruptedException ex) {
}
}
}
}
public void run() {
MqttWireMessage message = null;
while (running && (out != null)) {
try {
//@TRACE 802=run: get message
trace.trace(Trace.FINE,802);
message = clientState.get();
if (message != null) {
if (message instanceof MqttAck) {
out.write(message);
out.flush();
}
else {
MqttDeliveryToken token = tokenStore.getToken(message);
synchronized (token) {
out.write(message);
out.flush();
clientState.notifySent(message);
}
}
if (message instanceof MqttDisconnect) {
synchronized (lifecycle) {
//@TRACE 803=run: sent disconnect
trace.trace(Trace.FINE,803);
running = false;
}
}
} else {
synchronized (lifecycle) {
running = false;
}
}
} catch (MqttException me) {
synchronized (lifecycle) {
running = false;
}
//System.out.println("[MB]SHUTDOWN: 6");
clientComms.shutdownConnection(me);
} catch (Exception ioe) {
//@TRACE 804=run: exception
trace.trace(Trace.FINE,804,null,ioe);
if (message != null && message instanceof MqttDisconnect) {
// An IO exception whilst sending the disconnect will
// cause the application thread to stay blocked
// on the token if we don't pretend it has successfully
// been sent.
clientState.notifySent(message);
}
running = false;
//System.out.println("[MB]SHUTDOWN: 7");
clientComms.shutdownConnection(new MqttException(MqttException.REASON_CODE_CONNECTION_LOST, ioe));
}
}
synchronized (lifecycle) {
//@TRACE 805=run: notify lifecycle
trace.trace(Trace.FINE,805);
lifecycle.notifyAll();
}
}
public boolean isRunning() {
return running;
}
}