/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.rest;
import java.util.concurrent.ExecutorService;
import javax.jms.JMSException;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
import org.fudgemsg.FudgeMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Instant;
import com.opengamma.transport.jaxrs.FudgeRest;
import com.opengamma.util.rest.AbstractDataResource;
/**
* Base class for a RESTful resource which uses a REST+JMS pattern to publish streaming results.
* <p>
* Provides heartbeat listening and control of the JMS stream.
*/
public abstract class AbstractRestfulJmsResultPublisher extends AbstractDataResource {
private static final Logger s_logger = LoggerFactory.getLogger(AbstractRestfulJmsResultPublisher.class);
//CSOFF: just constants
public static final String PATH_HEARTBEAT = "heartbeat";
public static final String PATH_START_JMS_RESULT_STREAM = "startJmsResultStream";
public static final String PATH_STOP_JMS_RESULT_STREAM = "stopJmsResultStream";
public static final String DESTINATION_FIELD = "destination";
//CSON: just constants
private final AbstractJmsResultPublisher _resultPublisher;
private final ExecutorService _executor;
private volatile Instant _lastAccessed = Instant.now();
protected AbstractRestfulJmsResultPublisher(AbstractJmsResultPublisher resultPublisher, ExecutorService executor) {
_resultPublisher = resultPublisher;
_executor = executor;
}
//-------------------------------------------------------------------------
/**
* Tests whether the underlying resource has been terminated.
*
* @return true if the underlying resource has been terminated, false otherwise
*/
protected abstract boolean isTerminated();
/**
* Called to indicate that the publisher's consumer has failed to provide heartbeats, and the resource is no longer
* required. Releases the underlying resource, stopping publication of results.
*/
protected abstract void expire();
//-------------------------------------------------------------------------
protected void startPublishingResults(String destination) throws Exception {
getResultPublisher().startPublishingResults(destination);
}
protected void stopPublishingResults() throws JMSException {
getResultPublisher().stopPublishingResults();
}
//-------------------------------------------------------------------------
@POST
@Path(PATH_HEARTBEAT)
public Response heartbeat() {
updateLastAccessed();
return responseOk();
}
public Instant getLastAccessed() {
return _lastAccessed;
}
protected void updateLastAccessed() {
_lastAccessed = Instant.now();
}
//-------------------------------------------------------------------------
@POST
@Path(PATH_START_JMS_RESULT_STREAM)
@Consumes(FudgeRest.MEDIA)
public Response startResultStream(final FudgeMsg msg) {
updateLastAccessed();
if (getResultPublisher() == null) {
throw new UnsupportedOperationException("JMS not configured on server");
}
final String destination = msg.getString(DESTINATION_FIELD);
_executor.execute(new Runnable() {
@Override
public void run() {
try {
startPublishingResults(destination);
} catch (Exception e) {
s_logger.error("Error starting result publisher", e);
}
}
});
return responseOk(destination);
}
@POST
@Path(PATH_STOP_JMS_RESULT_STREAM)
public Response stopResultStream() {
updateLastAccessed();
if (getResultPublisher() == null) {
throw new UnsupportedOperationException("JMS not configured on server");
}
_executor.execute(new Runnable() {
@Override
public void run() {
try {
stopPublishingResults();
} catch (Exception e) {
s_logger.error("Error stopping result publisher", e);
}
}
});
return responseOk();
}
//-------------------------------------------------------------------------
private AbstractJmsResultPublisher getResultPublisher() {
return _resultPublisher;
}
}