org.fusesource.mqtt.client.FutureConnection Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mqtt-client Show documentation
Show all versions of mqtt-client Show documentation
mqtt-client provides an ASL 2.0 licensed API to MQTT. It takes care of
automatically reconnecting to your MQTT server and restoring your client
session if any network failures occur. Applications can use a blocking
API style, a futures based API, or a callback/continuations passing API
style.
The newest version!
/**
* Copyright (C) 2010-2012, FuseSource Corp. All rights reserved.
*
* http://fusesource.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.fusesource.mqtt.client;
import org.fusesource.hawtbuf.Buffer;
import org.fusesource.hawtbuf.UTF8Buffer;
import org.fusesource.hawtdispatch.DispatchQueue;
import org.fusesource.hawtdispatch.Task;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
import static org.fusesource.hawtbuf.Buffer.utf8;
/**
*
* A Future based optionally-blocking Connection interface to MQTT.
*
*
* @author Hiram Chirino
*/
public class FutureConnection {
private final CallbackConnection next;
private final LinkedList> receiveFutures = new LinkedList>();
private final LinkedList receivedFrames = new LinkedList();
private volatile boolean connected;
private long receiveBuffer = 1024*1024;
private long receiveBufferRemaining = receiveBuffer;
private boolean receiveBufferFull = false;
public FutureConnection(CallbackConnection next) {
this.next = next;
this.next.listener(new ExtendedListener() {
public void onConnected() {
connected = true;
}
public void onDisconnected() {
connected = false;
}
public void onPublish(UTF8Buffer topic, final Buffer payload, final Callback> onComplete) {
getDispatchQueue().assertExecuting();
receiveBufferRemaining -= payload.length();
if( !receiveBufferFull && receiveBufferRemaining <=0 ) {
receiveBufferFull = true;
suspend();
}
deliverMessage(new Message(getDispatchQueue(), topic, payload, new Callback>() {
public void onSuccess(Callback value) {
processed();
onComplete.onSuccess(value);
}
public void onFailure(Throwable value) {
processed();
onComplete.onFailure(value);
}
private void processed() {
getDispatchQueue().assertExecuting();
receiveBufferRemaining += payload.length();
if( receiveBufferFull && receiveBufferRemaining >0 ) {
receiveBufferFull = false;
resume();
}
}
}));
}
public void onPublish(UTF8Buffer topic, Buffer payload, final Runnable onComplete) {
onPublish(topic, payload, new Callback>() {
public void onSuccess(Callback value) {
onComplete.run();
}
public void onFailure(Throwable value) {
}
});
}
public void onFailure(Throwable value) {
getDispatchQueue().assertExecuting();
ArrayList> tmp = new ArrayList>(receiveFutures);
receiveFutures.clear();
for (Promise> future : tmp) {
future.onFailure(value);
}
connected = false;
}
});
}
void deliverMessage(Message msg) {
if( receiveFutures.isEmpty() ) {
receivedFrames.add(msg);
} else {
receiveFutures.removeFirst().onSuccess(msg);
}
}
void putBackMessage(Message msg) {
if( receiveFutures.isEmpty() ) {
receivedFrames.addFirst(msg);
} else {
receiveFutures.removeFirst().onSuccess(msg);
}
}
public boolean isConnected() {
return connected;
}
public DispatchQueue getDispatchQueue() {
return this.next.getDispatchQueue();
}
public Future connect() {
final Promise future = new Promise();
next.getDispatchQueue().execute(new Task() {
public void run() {
next.connect(future);
}
});
return future;
}
public Future disconnect() {
final Promise future = new Promise();
next.getDispatchQueue().execute(new Task() {
public void run() {
next.disconnect(future);
}
});
return future;
}
public Future kill() {
final Promise future = new Promise();
next.getDispatchQueue().execute(new Task() {
public void run() {
next.kill(future);
}
});
return future;
}
public Future subscribe(final Topic[] topics) {
final Promise future = new Promise();
next.getDispatchQueue().execute(new Task() {
public void run() {
next.subscribe(topics, future);
}
});
return future;
}
public Future unsubscribe(final String[] topics) {
UTF8Buffer[] buffers = new UTF8Buffer[topics.length];
for (int i = 0; i < buffers.length; i++) {
buffers[i] = new UTF8Buffer(topics[i]);
}
return unsubscribe(buffers);
}
public Future unsubscribe(final UTF8Buffer[] topics) {
final Promise future = new Promise();
next.getDispatchQueue().execute(new Task() {
public void run() {
next.unsubscribe(topics, future);
}
});
return future;
}
public Future publish(final String topic, final byte[] payload, final QoS qos, final boolean retain) {
return publish(utf8(topic), new Buffer(payload), qos, retain);
}
public Future publish(final UTF8Buffer topic, final Buffer payload, final QoS qos, final boolean retain) {
final Promise future = new Promise();
next.getDispatchQueue().execute(new Task() {
public void run() {
next.publish(topic, payload, qos, retain, future);
}
});
return future;
}
public Future receive() {
final Promise future = new Promise();
getDispatchQueue().execute(new Task(){
public void run() {
if( next.failure()!=null ) {
future.onFailure(next.failure());
} else {
if( receivedFrames.isEmpty() ) {
receiveFutures.add(future);
} else {
future.onSuccess(receivedFrames.removeFirst());
}
}
}
});
return future;
}
public long getReceiveBuffer() {
getDispatchQueue().assertExecuting();
return receiveBuffer;
}
public void setReceiveBuffer(long receiveBuffer) {
getDispatchQueue().assertExecuting();
long prev = this.receiveBuffer;
this.receiveBuffer = receiveBuffer;
long diff = prev-receiveBuffer;
receiveBufferRemaining -= diff;
if( !receiveBufferFull && receiveBufferRemaining <=0 ) {
receiveBufferFull = true;
suspend();
} else if( receiveBufferFull && receiveBufferRemaining >0 ) {
receiveBufferFull = false;
resume();
}
}
public void resume() {
next.resume();
}
public void suspend() {
next.suspend();
}
}