package com.brightcove.opensource.workflowengine;
import java.util.ArrayList;
import java.util.List;
import com.brightcove.opensource.workflowengine.record.Property;
import com.brightcove.opensource.workflowengine.record.Record;
/**
* <p>
* With Workflow, forms the basis for a simple workflow engine. An actor
* is a generic processor that can be chained together with other actors
* to form a workflow in order to process data.
* <p>
*
* <p>
* Each actor is both a Provider (provides data to upstream actors) and a
* Consumer (receives data from downstream actors).
* </p>
*
* <p>
* As a provider, the actor can call its downstream providers to obtain
* data and/or generate its own data (e.g. from reading a file), and then
* passes this data on to its consumers as Record objects.
* </p>
*
* <p>
* As a consumer, the actor receives data from its downstream providers
* and can do something with that data (e.g. save to a file) and/or pass
* the data on to its consumers as Record objects.
* </p>
*
* <p>
* The intention is that this class will be extended to perform specific
* tasks (e.g. reading a CSV file)
* </p>
*
* @author <a href="https://github.com/three4clavin">Sander Gates</a>
*
*/
public class Actor implements Provider, Consumer {
private List<Provider> providers;
private List<Consumer> consumers;
private Boolean started;
private List<Property<String>> properties;
private Workflow workflow;
/**
*
* <p>
* Default constructor.
* </p>
*
* @param workflow Workflow this actor is part of
*
*/
public Actor(Workflow workflow){
providers = new ArrayList<Provider>();
consumers = new ArrayList<Consumer>();
properties = new ArrayList<Property<String>>();
started = false;
this.workflow = workflow;
}
/* (non-Javadoc)
* @see com.brightcove.opensource.workflowengine.Provider#run()
*/
public void run(){
if(! started){
started = true;
for(Provider provider : providers){
provider.run();
}
}
}
public void finalize(){
}
/* (non-Javadoc)
* @see com.brightcove.opensource.workflowengine.Consumer#handleRecord(com.brightcove.opensource.workflowengine.Record)
*/
public void handleRecord(Record record){
// ToDo - what to do when records come in before we've "started" - is that possible?
for(Consumer consumer : consumers){
consumer.handleRecord(record);
}
}
/**
* <p>
* Returns true if this actor has any consumers registered with it.
* Actors with no consumers are considered "terminal" - meaning they
* can be started from the workflow rather than from another actor.
* </p>
*
* @return True if this actor has any consumers registered with it
*/
public Boolean hasConsumers(){
return (! consumers.isEmpty());
}
/**
* <p>
* Registers a provider for this actor to pull data from
* </p>
*
* @param provider Provider to register
*/
public void addProvider(Provider provider){
this.providers.add(provider);
}
/**
* <p>
* Registers a consumer to provide data to
* </p>
*
* @param consumer Consumer to register
*/
public void addConsumer(Consumer consumer){
this.consumers.add(consumer);
}
/**
* <p>
* Adds a configuration parameter
* </p>
*
* @param property Configuration key=value pair
*/
public void addProperty(Property<String> property){
this.properties.add(property);
}
/**
* <p>
* Gets the first config property with the name specified
* </p>
*
* @param name Name of property to get
* @return First property found, or null if none is found
*/
public Property<String> getFirstProperty(String name){
for(Property<String> property : properties){
if((property != null) && (property.getName() != null) && property.getName().equals(name)){
return property;
}
}
return null;
}
/**
* <p>
* Gets the first config value of the first property found with the
* name specified.
* </p>
*
* @param name Name of property to search for
* @return Value of property if found, otherwise null
*/
public String getFirstPropertyValue(String name){
Property<String> prop = getFirstProperty(name);
if(prop == null){
return null;
}
if(prop.getValue() == null){
return null;
}
return prop.getValue();
}
/**
* <p>
* Returns true if this actor has been started - i.e. run() has been
* called from either the workflow or another actor.
* </p>
*
* @return True if actor has been started
*/
public Boolean hasStarted(){
return started;
}
/**
* <p>
* Records a message via the workflow's logging mechanisms
* </p>
*
* @param message Message to log
*/
public void log(String message){
workflow.log(message);
}
/**
* <p>
* Records an error message viw the workflow's logging mechanism
* </p>
*
* @param message Error message to log
*/
public void logError(String message){
workflow.logError(message);
}
/**
* <p>
* Uses the workflow to log a message and then exit the virtual machine
* with a non-zero exit code.
* </p>
*
* @param message Message to log
*/
public void die(String message){
workflow.die(message);
}
}