/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE file at the root of the source
* tree and available online at
*
* https://github.com/keeps/roda
*/
package org.roda.core.plugins.orchestrate.akka;
import java.util.Optional;
import org.roda.core.data.exceptions.GenericException;
import org.roda.core.data.exceptions.RequestNotValidException;
import org.roda.core.data.v2.IsRODAObject;
import org.roda.core.data.v2.index.IsIndexed;
import org.roda.core.data.v2.index.select.SelectedItemsAll;
import org.roda.core.data.v2.index.select.SelectedItemsFilter;
import org.roda.core.data.v2.index.select.SelectedItemsList;
import org.roda.core.data.v2.index.select.SelectedItemsNone;
import org.roda.core.data.v2.jobs.Job;
import org.roda.core.data.v2.jobs.Job.JOB_STATE;
import org.roda.core.model.utils.ModelUtils;
import org.roda.core.plugins.Plugin;
import org.roda.core.plugins.orchestrate.JobsHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import akka.actor.ActorRef;
import akka.actor.OneForOneStrategy;
import akka.actor.Props;
import akka.actor.SupervisorStrategy;
import akka.japi.pf.DeciderBuilder;
public class AkkaJobActor extends AkkaBaseActor {
private static final Logger LOGGER = LoggerFactory.getLogger(AkkaJobActor.class);
private ActorRef jobsManager;
private SupervisorStrategy strategy = new OneForOneStrategy(false, DeciderBuilder.matchAny(e -> {
LOGGER.error("A child actor of {} has thrown an exception", AkkaJobActor.class.getSimpleName(), e);
for (ActorRef actorRef : getContext().getChildren()) {
actorRef.tell(new Messages.JobStateUpdated(null, JOB_STATE.FAILED_TO_COMPLETE, e), ActorRef.noSender());
}
return SupervisorStrategy.resume();
}).build());
/** Public constructor */
public AkkaJobActor(ActorRef jobsManager) {
super();
this.jobsManager = jobsManager;
}
@Override
public void onReceive(Object msg) throws Exception {
super.setup(msg);
if (msg instanceof Job) {
Job job = (Job) msg;
Plugin<? extends IsRODAObject> plugin = super.getPluginManager().getPlugin(job.getPlugin());
if (plugin == null) {
JobsHelper.updateJobState(job, super.getModel(), JOB_STATE.FAILED_TO_COMPLETE, Optional.of("Plugin is NULL"));
// 20160818 hsilva: the following instruction is needed for the "sync"
// execution of a job (i.e. for testing purposes)
getSender().tell("Failed to complete", getSelf());
return;
}
JobsHelper.setPluginParameters(plugin, job);
String jobId = job.getId();
ActorRef jobStateInfoActor = getContext().actorOf(Props.create(AkkaJobStateInfoActor.class, plugin, getSender(),
jobsManager, jobId, JobsHelper.getNumberOfJobsWorkers()), jobId);
super.getPluginOrchestrator().setJobContextInformation(jobId, jobStateInfoActor);
jobStateInfoActor.tell(new Messages.JobStateUpdated(plugin, JOB_STATE.STARTED), getSelf());
try {
if (job.getSourceObjects() instanceof SelectedItemsAll<?>) {
runOnAll(job, plugin);
} else if (job.getSourceObjects() instanceof SelectedItemsNone<?>) {
super.getPluginOrchestrator().runPlugin(getSelf(), plugin);
} else if (job.getSourceObjects() instanceof SelectedItemsList<?>) {
runFromList(job, plugin);
} else if (job.getSourceObjects() instanceof SelectedItemsFilter<?>) {
runFromFilter(job, plugin);
}
} catch (Exception e) {
LOGGER.error("Error while invoking orchestration method", e);
jobStateInfoActor.tell(new Messages.JobStateUpdated(plugin, JOB_STATE.FAILED_TO_COMPLETE, e), getSelf());
getSender().tell("Failed to complete", getSelf());
}
} else {
LOGGER.error("Received a message that don't know how to process ({})...", msg.getClass().getName());
unhandled(msg);
}
}
private <T extends IsRODAObject> void runOnAll(Job job, Plugin<T> plugin) throws GenericException {
// get class
Class<IsRODAObject> sourceObjectsClass = JobsHelper
.getSelectedClassFromString(job.getSourceObjects().getSelectedClass());
getPluginOrchestrator().runPluginOnAllObjects(getSelf(), plugin, (Class<T>) sourceObjectsClass);
}
private <T extends IsRODAObject> void runFromList(Job job, Plugin<T> plugin) throws GenericException {
// get class
Class<IsRODAObject> sourceObjectsClass = JobsHelper
.getSelectedClassFromString(job.getSourceObjects().getSelectedClass());
getPluginOrchestrator().runPluginOnObjects(getSelf(), plugin,
(Class<T>) ModelUtils.giveRespectiveModelClass(sourceObjectsClass),
((SelectedItemsList<IsRODAObject>) job.getSourceObjects()).getIds());
}
private void runFromFilter(Job job, Plugin<?> plugin) throws GenericException, RequestNotValidException {
// cast
SelectedItemsFilter<?> selectedItems = (SelectedItemsFilter<?>) job.getSourceObjects();
// get class
Class<IsIndexed> sourceObjectsClass = JobsHelper
.getIsIndexedSelectedClassFromString(selectedItems.getSelectedClass());
// count objects & update job stats
Long objectsCount = super.getIndex().count(sourceObjectsClass, selectedItems.getFilter());
JobsHelper.updateJobObjectsCount(plugin, super.getModel(), objectsCount);
// execute
getPluginOrchestrator().runPluginFromIndex(getSelf(), sourceObjectsClass, selectedItems.getFilter(), plugin);
}
@Override
public SupervisorStrategy supervisorStrategy() {
return strategy;
}
}