/*
* 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.InputStream;
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.MqttConnack;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream;
import org.eclipse.paho.client.mqttv3.internal.wire.MqttWireMessage;
import android.os.PowerManager.WakeLock;
import android.util.Log;
/**
* Receives MQTT packets from the server.
*/
public class CommsReceiver implements Runnable {
private boolean running = false;
private Object lifecycle = new Object();
private ClientState clientState = null;
private ClientComms clientComms = null;
private MqttInputStream in;
private CommsTokenStore tokenStore = null;
private boolean disconnecting = false;
private Trace trace;
private WakeLock wakeLock;
public CommsReceiver(Trace trace, ClientComms clientComms, ClientState clientState, CommsTokenStore tokenStore, InputStream in,WakeLock wl) {
this.in = new MqttInputStream(in);
this.clientComms = clientComms;
this.clientState = clientState;
this.tokenStore = tokenStore;
this.trace = trace;
this.wakeLock = wl;
}
/**
* Starts up the Receiver's thread.
*/
public void start() {
if (running == false) {
running = true;
new Thread(this, "MQTT Client Comms Receiver").start();
}
}
/**
* Stops the Receiver's thread. This call will block.
*/
public void stop() throws IOException {
synchronized (lifecycle) {
this.wakeLock.release();
//@TRACE 850=stopping receiver
trace.trace(Trace.FINE,850);
if (running) {
running = false;
try {
//@TRACE 851=stop: wait on lifecycle
trace.trace(Trace.FINE,851);
// Wait for the thread to finish.
lifecycle.wait();
}
catch (InterruptedException ex) {
}
}
}
}
/**
* Run loop to receive messages from the server.
*/
public void run() {
this.wakeLock.acquire();
while (running && (in != null)) {
try {
//@TRACE 852=run: read message
trace.trace(Trace.FINE,852);
MqttWireMessage message = in.readMqttWireMessage();
if (message instanceof MqttAck) {
MqttDeliveryToken token = tokenStore.getToken(message);
if (token!=null) {
synchronized (token) {
clientState.notifyReceived(message);
if (message instanceof MqttConnack && ((MqttConnack)message).getReturnCode() != 0) {
synchronized (lifecycle) {
running = false;
}
}
}
} else {
clientState.notifyReceived(message);
}
}
else {
clientState.notifyReceived(message);
}
}
catch (MqttException ex) {
running = false;
clientComms.shutdownConnection(ex);
}
catch (IOException ioe) {
//@TRACE 853=run: IOException
trace.trace(Trace.FINE,853,null,ioe);
running = false;
// An EOFException could be raised if the broker processes the
// DISCONNECT before we receive the ACK for it. As such,
// only shutdown the connection if we're not already shutting down.
if (!disconnecting) {
clientComms.shutdownConnection(new MqttException(MqttException.REASON_CODE_CONNECTION_LOST, ioe));
} else {
clientComms.shutdownConnection(null);
}
}
}
try {
if (this.wakeLock.isHeld()){
this.wakeLock.release();
}
} catch (Exception ex){
Log.w("CommsReciever", "Error releaseing wakelock in CommsReceiver!");
}
synchronized (lifecycle) {
//@TRACE 854=run: notify lifecycle
trace.trace(Trace.FINE,854);
lifecycle.notifyAll();
}
}
public boolean isRunning() {
return running;
}
public void setDisconnecting(boolean disconnecting) {
//@TRACE 855=setDisconnecting disconnecting={0}
trace.trace(Trace.FINE,855, new Object[]{new Boolean(disconnecting)});
this.disconnecting = disconnecting;
}
}