package org.atomnuke.task.atom.impl;
import org.atomnuke.plugin.InstanceContext;
import org.atomnuke.plugin.context.LocalInstanceContext;
import org.atomnuke.plugin.context.NopInstanceContext;
import org.atomnuke.sink.manager.ManagedSink;
import org.atomnuke.sink.driver.AtomSinkDriver;
import org.atomnuke.sink.driver.DriverArgument;
import org.atomnuke.sink.manager.SinkManager;
import org.atomnuke.plugin.operation.ComplexOperation;
import org.atomnuke.plugin.operation.OperationFailureException;
import org.atomnuke.source.AtomSource;
import org.atomnuke.source.AtomSourceException;
import org.atomnuke.source.action.ActionType;
import org.atomnuke.source.action.AtomSourceActionImpl;
import org.atomnuke.source.result.AtomSourceResult;
import org.atomnuke.source.result.AtomSourceResultImpl;
import org.atomnuke.task.TaskHandle;
import org.atomnuke.task.manager.Tasker;
import org.atomnuke.util.lifecycle.runnable.ReclaimableTask;
import org.atomnuke.util.lifecycle.operation.ReclaimOperation;
import org.atomnuke.util.remote.CancellationRemote;
import org.atomnuke.util.result.ResultCatch;
import org.atomnuke.util.result.ResultCatchImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author zinic
*/
public class ManagedAtomTask implements ReclaimableTask {
private static final Logger LOG = LoggerFactory.getLogger(ManagedAtomTask.class);
private static final ComplexOperation<AtomSource, ResultCatch<AtomSourceResult>> POLLING_OPERATION = new ComplexOperation<AtomSource, ResultCatch<AtomSourceResult>>() {
@Override
public void perform(AtomSource instance, ResultCatch<AtomSourceResult> resultCatch) throws OperationFailureException {
try {
final AtomSourceResult pollResult = instance.poll();
if (pollResult != null) {
resultCatch.setResult(pollResult);
} else {
resultCatch.setResult(new AtomSourceResultImpl(new AtomSourceActionImpl(ActionType.HALT)));
}
} catch (AtomSourceException ase) {
throw new OperationFailureException(ase);
}
}
};
private final SourceManagedPollingController pollingController;
private final InstanceContext<AtomSource> atomSourceContext;
private final SinkManager sinkManager;
private final Tasker tasker;
private CancellationRemote enlistedCancellationRemote;
public ManagedAtomTask(SourceManagedPollingController pollingController, InstanceContext<AtomSource> atomSourceContext, SinkManager sinkManager, Tasker tasker) {
this.pollingController = pollingController;
this.atomSourceContext = atomSourceContext;
this.sinkManager = sinkManager;
this.tasker = tasker;
}
@Override
public void enlisted(TaskHandle taskHandle) {
enlistedCancellationRemote = taskHandle.cancellationRemote();
}
@Override
public void run() {
// Only poll if we have Sinks
if (sinkManager.hasRegisteredSinks()) {
final ResultCatch<AtomSourceResult> resultCatch = new ResultCatchImpl<AtomSourceResult>();
try {
atomSourceContext.perform(POLLING_OPERATION, resultCatch);
} catch (OperationFailureException ofe) {
LOG.error("Failed to poll atom source: " + atomSourceContext + " - Reason: " + ofe.getMessage(), ofe);
}
if (resultCatch.hasResult()) {
handlePollingResult(resultCatch);
}
}
}
@Override
public void destroy() {
try {
atomSourceContext.perform(ReclaimOperation.<AtomSource>instance());
} catch (OperationFailureException ofe) {
LOG.error("Failed to destroy atom source: " + atomSourceContext + " - Reason: " + ofe.getMessage(), ofe);
}
}
private void dispatchToSinks(AtomSourceResult pollResult) {
final DriverArgument driverArgument = new DriverArgument(pollResult.feed(), pollResult.entry());
for (ManagedSink sink : sinkManager.sinks()) {
tasker.queueAction(new NopInstanceContext(new AtomSinkDriver(sink, driverArgument)));
}
}
private void handlePollingResult(final ResultCatch<AtomSourceResult> resultCatch) {
switch (resultCatch.result().action().action()) {
case HAS_NEXT:
// If we have more on this source, ignore our schedule to catch up
pollingController.ignoreSchedule();
// Dispatch our payload to the execution pool
dispatchToSinks(resultCatch.result());
break;
case HALT:
// If we need to halt we cancel our task and then tell our pooling controller to honor the schedule
enlistedCancellationRemote.cancel();
case SLEEP:
default:
pollingController.honorSchedule();
}
}
}