/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.engine.calcnode; import java.util.Collection; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opengamma.util.ArgumentChecker; /** * Invokes jobs on one or more local calculation node implementations. */ public class LocalNodeJobInvoker extends SimpleCalculationNodeInvocationContainer implements JobInvoker { private static final Logger s_logger = LoggerFactory.getLogger(LocalNodeJobInvoker.class); private final AtomicReference<JobInvokerRegister> _notifyWhenAvailable = new AtomicReference<JobInvokerRegister>(); private final CapabilitySet _capabilitySet = new CapabilitySet(); private String _invokerId = "local"; public LocalNodeJobInvoker() { } public LocalNodeJobInvoker(final SimpleCalculationNode node) { addNode(node); recalculateCapabilities(); } public LocalNodeJobInvoker(final Collection<SimpleCalculationNode> nodes) { addNodes(nodes); recalculateCapabilities(); } /** * Updates the capabilities. Call this if the set of nodes has changed. */ public void recalculateCapabilities() { setCapability(PlatformCapabilities.NODE_COUNT, getNodes().size()); } public void setCapability(final String identifier, final double parameter) { getCapabilitySet().setParameterCapability(identifier, parameter); } /** * For injecting capabilities from spring. * * @param parameters capabilities */ public void setCapabilities(final Map<String, Double> parameters) { for (Map.Entry<String, Double> parameter : parameters.entrySet()) { setCapability(parameter.getKey(), parameter.getValue()); } } @Override public void onNodeChange() { final JobInvokerRegister notify = _notifyWhenAvailable.getAndSet(null); if (notify != null) { notify.registerJobInvoker(this); } } protected CapabilitySet getCapabilitySet() { return _capabilitySet; } @Override public Collection<Capability> getCapabilities() { return getCapabilitySet().getCapabilities(); } private void addTail(final Collection<CalculationJob> tails, final ExecutionReceiver executionReceiver) { if (tails != null) { for (CalculationJob tail : tails) { addJob(tail, executionReceiver, null); addTail(tail.getTail(), executionReceiver); } } } @Override public boolean invoke(final CalculationJob job, final JobInvocationReceiver receiver) { final SimpleCalculationNode node = getNodes().poll(); if (node == null) { return false; } final ExecutionReceiver executionReceiver = new ExecutionReceiver() { @Override public void executionComplete(CalculationJobResult result) { receiver.jobCompleted(result); } @Override public void executionFailed(SimpleCalculationNode node, Exception exception) { s_logger.warn("Exception thrown by job execution", exception); receiver.jobFailed(LocalNodeJobInvoker.this, node.getNodeId(), exception); } }; addJob(job, executionReceiver, node); addTail(job.getTail(), executionReceiver); return true; } @Override public void cancel(final Collection<CalculationJobSpecification> jobs) { for (CalculationJobSpecification job : jobs) { cancel(job); } } @Override public boolean isAlive(final Collection<CalculationJobSpecification> jobs) { for (CalculationJobSpecification job : jobs) { if (!isAlive(job)) { return false; } } return true; } @Override protected void onJobExecutionComplete() { onNodeChange(); } @Override public boolean notifyWhenAvailable(JobInvokerRegister callback) { _notifyWhenAvailable.set(callback); if (!getNodes().isEmpty()) { callback = _notifyWhenAvailable.getAndSet(null); if (callback != null) { return true; } } return false; } @Override public String toString() { return getInvokerId(); } @Override public String getInvokerId() { return _invokerId; } public void setInvokerId(final String invokerId) { ArgumentChecker.notNull(invokerId, "invokerId"); _invokerId = invokerId; } }