package com.intrbiz.bergamot.worker.engine;
import java.io.IOException;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.log4j.Logger;
import com.intrbiz.bergamot.config.EngineCfg;
import com.intrbiz.bergamot.config.ExecutorCfg;
import com.intrbiz.bergamot.model.message.check.ExecuteCheck;
import com.intrbiz.bergamot.model.message.command.CommandRequest;
import com.intrbiz.bergamot.model.message.command.CommandResponse;
import com.intrbiz.bergamot.model.message.reading.ReadingParcelMO;
import com.intrbiz.bergamot.model.message.result.ActiveResultMO;
import com.intrbiz.bergamot.model.message.result.ResultMO;
import com.intrbiz.bergamot.queue.BergamotCommandQueue;
import com.intrbiz.bergamot.queue.WorkerQueue;
import com.intrbiz.bergamot.queue.key.ActiveResultKey;
import com.intrbiz.bergamot.queue.key.AgentBinding;
import com.intrbiz.bergamot.queue.key.ReadingKey;
import com.intrbiz.bergamot.queue.key.ResultKey;
import com.intrbiz.bergamot.queue.key.WorkerKey;
import com.intrbiz.bergamot.worker.Worker;
import com.intrbiz.queue.Consumer;
import com.intrbiz.queue.DeliveryHandler;
import com.intrbiz.queue.QueueException;
import com.intrbiz.queue.RPCClient;
import com.intrbiz.queue.RoutedProducer;
import com.intrbiz.queue.name.RoutingKey;
public class AbstractEngine implements Engine, DeliveryHandler<ExecuteCheck>
{
private Logger logger = Logger.getLogger(AbstractEngine.class);
protected Worker worker;
protected final String name;
protected EngineCfg config;
protected List<Executor<?>> executors = new LinkedList<Executor<?>>();
private WorkerQueue queue;
private List<Consumer<ExecuteCheck, WorkerKey>> consumers = new LinkedList<Consumer<ExecuteCheck, WorkerKey>>();
protected RoutedProducer<ResultMO, ResultKey> resultProducer;
protected RoutedProducer<ReadingParcelMO, ReadingKey> readingProducer;
private BergamotCommandQueue commandQueue;
private RPCClient<CommandRequest, CommandResponse, RoutingKey> commandRPCClient;
public AbstractEngine(final String name)
{
super();
this.name = name;
}
@Override
public void configure(EngineCfg cfg) throws Exception
{
this.config = cfg;
this.configure();
}
@Override
public EngineCfg getConfiguration()
{
return this.config;
}
@Override
public boolean isAgentRouted()
{
return false;
}
protected void configure() throws Exception
{
for (ExecutorCfg executorCfg : this.config.getExecutors())
{
Executor<?> executor = (Executor<?>) executorCfg.create();
this.addExecutor(executor);
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void addExecutor(Executor<?> executor)
{
((Executor) executor).setEngine(this);
this.executors.add(executor);
}
@Override
public Collection<Executor<?>> getExecutors()
{
return this.executors;
}
@Override
public Worker getWorker()
{
return this.worker;
}
@Override
public void setWorker(Worker worker)
{
this.worker = worker;
}
@Override
public String getName()
{
return this.name;
}
@Override
public void publishResult(ResultKey key, ResultMO resultMO)
{
if (logger.isTraceEnabled())
{
logger.trace("Publishing result: " + resultMO.getId() + " " + resultMO.isOk() + " " + resultMO.getStatus() + " " + resultMO.getOutput());
}
this.resultProducer.publish(key, resultMO);
}
@Override
public void publishReading(ReadingKey key, ReadingParcelMO readingParcelMO)
{
if (logger.isTraceEnabled())
{
logger.trace("Publishing reading: " + readingParcelMO.getReadings().size() + " " + readingParcelMO.getMatchOn());
}
this.readingProducer.publish(key, readingParcelMO);
}
@Override
public void execute(ExecuteCheck task)
{
for (Executor<?> executor : this.executors)
{
if (executor.accept(task))
{
executor.execute(task);
return;
}
}
this.publishResult(new ActiveResultKey(task.getSiteId(), task.getProcessingPool()), new ActiveResultMO().fromCheck(task).error("No executor found to execute check"));
}
protected void startEngineServices() throws Exception
{
}
@Override
public void start() throws Exception
{
// open the command queue
this.commandQueue = BergamotCommandQueue.open();
// create an RPC client
this.commandRPCClient = this.commandQueue.createBergamotCommandRPCClient();
// open the queue
this.queue = WorkerQueue.open();
// the result producer
this.resultProducer = this.queue.publishResults();
// the reading producer
this.readingProducer = this.queue.publishReadings();
// start the executors
for (Executor<?> ex : this.getExecutors())
{
ex.start();
}
// start any services needed for this engine
this.startEngineServices();
// start all the consumers
for (int i = 0; i < this.getWorker().getConfiguration().getThreads(); i ++)
{
logger.trace("Creating consumer " + i);
this.consumers.add(this.queue.consumeChecks(this, this.getWorker().getSite(), this.worker.getWorkerPool(), this.getName(), this.isAgentRouted(), this.getWorker().getId()));
}
}
@Override
public void bindAgent(UUID agentId)
{
logger.trace("Binding agent " + agentId + " to worker " + this.getWorker().getId());
try
{
for (Consumer<ExecuteCheck, WorkerKey> consumer : this.consumers)
{
consumer.addBinding(new AgentBinding(agentId));
break; // shared queue so only need to update bindings once
}
}
catch (QueueException e)
{
logger.debug("Error binding agent", e);
}
}
@Override
public void unbindAgent(UUID agentId)
{
logger.trace("Unbinding agent " + agentId + " to worker " + this.getWorker().getId());
try
{
for (Consumer<ExecuteCheck, WorkerKey> consumer : this.consumers)
{
consumer.removeBinding(new AgentBinding(agentId));
break; // shared queue so only need to update bindings once
}
}
catch (QueueException e)
{
logger.debug("Error binding agent", e);
}
}
@Override
public void handleDevliery(Map<String, Object> headers, ExecuteCheck event) throws IOException
{
if (logger.isTraceEnabled())
logger.trace("Got task: " + event);
this.execute(event);
}
public RPCClient<CommandRequest, CommandResponse, RoutingKey> getCommandRPCClient()
{
return this.commandRPCClient;
}
}