package org.yamcs.web.rest.archive;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.yamcs.ProcessorFactory;
import org.yamcs.YConfiguration;
import org.yamcs.Processor;
import org.yamcs.parameter.ParameterValueWithId;
import org.yamcs.parameter.ParameterWithIdConsumer;
import org.yamcs.parameter.ParameterWithIdRequestHelper;
import org.yamcs.protobuf.Yamcs.ReplayRequest;
import org.yamcs.security.AuthenticationToken;
import org.yamcs.web.HttpException;
import org.yamcs.web.InternalServerErrorException;
import org.yamcs.web.ServiceUnavailableException;
import org.yamcs.web.rest.RestReplayListener;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.Service.Listener;
import com.google.common.util.concurrent.Service.State;
/**
* Abstracts some common logic for creating replays
*/
public class RestReplays {
static AtomicInteger count = new AtomicInteger();
private static int MAX_CONCURRENT_REPLAYS = YConfiguration.getConfiguration("yamcs").getInt("WebConfig", "maxConcurrentReplays", 2*Runtime.getRuntime().availableProcessors());
static AtomicInteger concurrentCount = new AtomicInteger();
/**
* launches a replay will only return when the replay is done (either
* through success or through error)
*
* TODO we should be more helpful here with catching errored state and
* throwing it up as RestException
*/
public static ReplayWrapper replay(String instance, AuthenticationToken token, ReplayRequest replayRequest, RestReplayListener l) throws HttpException {
int n = concurrentCount.incrementAndGet();
if(n>MAX_CONCURRENT_REPLAYS) {
concurrentCount.decrementAndGet();
throw new ServiceUnavailableException("Maximum number of concurrent replays has been reached");
}
try {
Processor yproc = ProcessorFactory.create(instance, "RestReplays"+count.incrementAndGet(), "ArchiveRetrieval", "internal", replayRequest);
ReplayWrapper wrapper = new ReplayWrapper(l, yproc);
ParameterWithIdRequestHelper pidrm = new ParameterWithIdRequestHelper(yproc.getParameterRequestManager(), wrapper);
pidrm.addRequest(replayRequest.getParameterRequest().getNameFilterList(), token);
yproc.startAsync();
yproc.addListener(new Listener() {
public void terminated(State from){concurrentCount.decrementAndGet();}
public void failed(State from, Throwable failure) {concurrentCount.decrementAndGet();}
}, MoreExecutors.directExecutor());
return wrapper;
} catch (Exception e) {
throw new InternalServerErrorException("Exception creating the replay", e);
}
}
private static class ReplayWrapper implements ParameterWithIdConsumer {
RestReplayListener wrappedListener;
Processor yproc;
ReplayWrapper(RestReplayListener l, Processor yproc) {
this.wrappedListener = l;
this.yproc = yproc;
yproc.addListener(l, MoreExecutors.directExecutor());
}
@Override
public void update(int subscriptionId, List<ParameterValueWithId> params) {
if (!wrappedListener.isReplayAbortRequested()) {
wrappedListener.update(subscriptionId, params);
} else {
yproc.quit();
}
}
}
}