/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.camel.component.pubnub;
import java.util.Arrays;
import com.pubnub.api.PubNubException;
import com.pubnub.api.callbacks.PNCallback;
import com.pubnub.api.models.consumer.PNErrorData;
import com.pubnub.api.models.consumer.PNPublishResult;
import com.pubnub.api.models.consumer.PNStatus;
import com.pubnub.api.models.consumer.history.PNHistoryResult;
import com.pubnub.api.models.consumer.presence.PNGetStateResult;
import com.pubnub.api.models.consumer.presence.PNHereNowResult;
import com.pubnub.api.models.consumer.presence.PNSetStateResult;
import com.pubnub.api.models.consumer.presence.PNWhereNowResult;
import org.apache.camel.AsyncCallback;
import org.apache.camel.CamelException;
import org.apache.camel.Exchange;
import org.apache.camel.impl.DefaultAsyncProducer;
import org.apache.camel.util.ObjectHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The PubNub producer.
*/
public class PubNubProducer extends DefaultAsyncProducer {
private static final Logger LOG = LoggerFactory.getLogger(PubNubProducer.class);
private final PubNubEndpoint endpoint;
private final PubNubConfiguration pubnubConfiguration;
public PubNubProducer(PubNubEndpoint endpoint, PubNubConfiguration pubNubConfiguration) {
super(endpoint);
this.endpoint = endpoint;
this.pubnubConfiguration = pubNubConfiguration;
}
@Override
public boolean process(final Exchange exchange, final AsyncCallback callback) {
Operation operation = getOperation(exchange);
LOG.debug("Executing {} operation", operation);
try {
switch (operation) {
case PUBLISH: {
doPublish(exchange, callback);
break;
}
case FIRE: {
doFire(exchange, callback);
break;
}
case GETHISTORY: {
doGetHistory(exchange, callback);
break;
}
case GETSTATE: {
doGetState(exchange, callback);
break;
}
case HERENOW: {
doHereNow(exchange, callback);
break;
}
case SETSTATE: {
doSetState(exchange, callback);
break;
}
case WHERENOW: {
doWhereNow(exchange, callback);
break;
}
default:
throw new UnsupportedOperationException(operation.toString());
}
} catch (Exception e) {
exchange.setException(e);
callback.done(true);
return true;
}
return false;
}
private void doPublish(Exchange exchange, AsyncCallback callback) {
Object body = exchange.getIn().getBody();
if (ObjectHelper.isEmpty(body)) {
throw new RuntimeException("Can not publish empty message");
}
LOG.debug("Sending message [{}] to channel [{}]", body, getChannel(exchange));
endpoint.getPubnub()
.publish()
.message(body)
.channel(getChannel(exchange))
.usePOST(true)
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if (!status.isError()) {
exchange.getIn().setHeader(PubNubConstants.TIMETOKEN, result.getTimetoken());
}
processMessage(exchange, callback, status, null);
}
});
}
private void doFire(Exchange exchange, AsyncCallback callback) {
Object body = exchange.getIn().getBody();
if (ObjectHelper.isEmpty(body)) {
exchange.setException(new CamelException("Can not fire empty message"));
callback.done(true);
}
LOG.debug("Sending message [{}] to channel [{}]", body, getChannel(exchange));
endpoint.getPubnub()
.fire()
.message(body)
.channel(getChannel(exchange))
.async(new PNCallback<PNPublishResult>() {
@Override
public void onResponse(PNPublishResult result, PNStatus status) {
if (!status.isError()) {
exchange.getIn().setHeader(PubNubConstants.TIMETOKEN, result.getTimetoken());
}
processMessage(exchange, callback, status, null);
}
});
}
private void doGetHistory(Exchange exchange, AsyncCallback callback) {
endpoint.getPubnub()
.history()
.channel(getChannel(exchange))
.async(new PNCallback<PNHistoryResult>() {
@Override
public void onResponse(PNHistoryResult result, PNStatus status) {
LOG.debug("Got history message [{}]", result);
processMessage(exchange, callback, status, result.getMessages());
}
});
}
private void doSetState(Exchange exchange, AsyncCallback callback) {
Object body = exchange.getIn().getBody();
if (ObjectHelper.isEmpty(body)) {
exchange.setException(new CamelException("Can not publish empty message"));
callback.done(true);
}
LOG.debug("Sending setState [{}] to channel [{}]", body, getChannel(exchange));
endpoint.getPubnub()
.setPresenceState()
.channels(Arrays.asList(getChannel(exchange)))
.state(body)
.uuid(getUUID(exchange))
.async(new PNCallback<PNSetStateResult>() {
public void onResponse(PNSetStateResult result, PNStatus status) {
LOG.debug("Got setState responsee [{}]", result);
processMessage(exchange, callback, status, result);
};
});
}
private void doGetState(Exchange exchange, AsyncCallback callback) {
endpoint.getPubnub()
.getPresenceState()
.channels(Arrays.asList(getChannel(exchange)))
.uuid(getUUID(exchange))
.async(new PNCallback<PNGetStateResult>() {
@Override
public void onResponse(PNGetStateResult result, PNStatus status) {
LOG.debug("Got state [{}]", result.getStateByUUID());
processMessage(exchange, callback, status, result);
}
});
}
private void doHereNow(Exchange exchange, AsyncCallback callback) {
endpoint.getPubnub()
.hereNow()
.channels(Arrays.asList(getChannel(exchange)))
.includeState(true)
.includeUUIDs(true)
.async(new PNCallback<PNHereNowResult>() {
@Override
public void onResponse(PNHereNowResult result, PNStatus status) {
LOG.debug("Got herNow message [{}]", result);
processMessage(exchange, callback, status, result);
}
});
}
private void doWhereNow(Exchange exchange, AsyncCallback callback) {
endpoint.getPubnub()
.whereNow()
.uuid(getUUID(exchange))
.async(new PNCallback<PNWhereNowResult>() {
@Override
public void onResponse(PNWhereNowResult result, PNStatus status) {
LOG.debug("Got whereNow message [{}]", result.getChannels());
processMessage(exchange, callback, status, result.getChannels());
};
});
}
private void processMessage(Exchange exchange, AsyncCallback callback, PNStatus status, Object body) {
if (status.isError()) {
PNErrorData errorData = status.getErrorData();
exchange.setException(errorData.getThrowable());
if (errorData != null && errorData.getThrowable() instanceof PubNubException) {
PubNubException pubNubException = (PubNubException) errorData.getThrowable();
throw new RuntimeException(pubNubException.getPubnubError().getMessage(), errorData.getThrowable());
}
throw new RuntimeException(status.getErrorData().getThrowable());
}
if (exchange.getPattern().isOutCapable()) {
exchange.getOut().copyFrom(exchange.getIn());
exchange.getOut().setBody(body);
} else {
exchange.getIn().setBody(body);
}
// signal exchange completion
callback.done(false);
}
private Operation getOperation(Exchange exchange) {
String operation = exchange.getIn().getHeader(PubNubConstants.OPERATION, String.class);
if (operation == null) {
operation = pubnubConfiguration.getOperation();
}
return operation != null ? Operation.valueOf(operation.toUpperCase()) : Operation.PUBLISH;
}
private String getChannel(Exchange exchange) {
String channel = exchange.getIn().getHeader(PubNubConstants.CHANNEL, String.class);
return channel != null ? channel : pubnubConfiguration.getChannel();
}
private String getUUID(Exchange exchange) {
String uuid = exchange.getIn().getHeader(PubNubConstants.UUID, String.class);
return uuid != null ? uuid : pubnubConfiguration.getUuid();
}
private enum Operation {
HERENOW, WHERENOW, GETSTATE, SETSTATE, GETHISTORY, PUBLISH, FIRE;
}
}