ProcessExecutionEngineImpl.java revision 30
// The MIT License
//
// Copyright (c) 2004 Evren Sirin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
/*
* Created on Dec 29, 2003
*
*/
package impl.owls.process.execution;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.mindswap.exceptions.ExecutionException;
import org.mindswap.exceptions.MultipleSatisfiedPreconditionException;
import org.mindswap.exceptions.NotImplementedException;
import org.mindswap.exceptions.UnsatisfiedPreconditionException;
import org.mindswap.owl.OWLIndividual;
import org.mindswap.owl.OWLIndividualList;
import org.mindswap.owl.OWLKnowledgeBase;
import org.mindswap.owl.OWLValue;
import org.mindswap.owl.list.RDFList;
import org.mindswap.owls.generic.list.OWLSObjList;
import org.mindswap.owls.grounding.AtomicGrounding;
import org.mindswap.owls.process.AnyOrder;
import org.mindswap.owls.process.AtomicProcess;
import org.mindswap.owls.process.Binding;
import org.mindswap.owls.process.BindingList;
import org.mindswap.owls.process.Choice;
import org.mindswap.owls.process.CompositeProcess;
import org.mindswap.owls.process.Condition;
import org.mindswap.owls.process.ControlConstruct;
import org.mindswap.owls.process.ControlConstructBag;
import org.mindswap.owls.process.ControlConstructList;
import org.mindswap.owls.process.ForEach;
import org.mindswap.owls.process.IfThenElse;
import org.mindswap.owls.process.Output;
import org.mindswap.owls.process.OutputBinding;
import org.mindswap.owls.process.OutputBindingList;
import org.mindswap.owls.process.Parameter;
import org.mindswap.owls.process.ParameterList;
import org.mindswap.owls.process.ParameterValue;
import org.mindswap.owls.process.Perform;
import org.mindswap.owls.process.Process;
import org.mindswap.owls.process.Produce;
import org.mindswap.owls.process.RepeatUntil;
import org.mindswap.owls.process.RepeatWhile;
import org.mindswap.owls.process.Result;
import org.mindswap.owls.process.Sequence;
import org.mindswap.owls.process.SimpleProcess;
import org.mindswap.owls.process.Split;
import org.mindswap.owls.process.SplitJoin;
import org.mindswap.owls.process.ValueData;
import org.mindswap.owls.process.ValueOf;
import org.mindswap.owls.process.execution.ProcessExecutionEngine;
import org.mindswap.owls.process.execution.ProcessExecutionListener;
import org.mindswap.owls.process.execution.ProcessMonitor;
import org.mindswap.owls.vocabulary.OWLS;
import org.mindswap.query.ABoxQuery;
import org.mindswap.query.ValueMap;
import org.mindswap.swrl.AtomList;
import org.mindswap.swrl.Variable;
/**
* @author Evren Sirin
*
*/
public class ProcessExecutionEngineImpl implements ProcessExecutionEngine {
public static boolean DEBUG = false;
protected List executionListeners ;
protected List monitors;
protected OWLKnowledgeBase env;
protected OWLKnowledgeBase kb;
protected boolean checkPreconditions;
protected boolean allowMultipleSatisifedPreconditions;
protected boolean stopOnException;
protected Map performResults;
protected Process process;
public ProcessExecutionEngineImpl() {
executionListeners = new ArrayList();
monitors = new ArrayList();
checkPreconditions = true;
allowMultipleSatisifedPreconditions = true;
stopOnException = true;
}
public void setKB(OWLKnowledgeBase kb) {
this.kb = kb;
}
public OWLKnowledgeBase getKB() {
return kb;
}
public void setPreconditionCheck(boolean checkPreconditions) {
this.checkPreconditions = checkPreconditions;
}
public boolean isPreconditionCheck() {
return checkPreconditions;
}
public boolean isAllowMultipleSatisifedPreconditions() {
return allowMultipleSatisifedPreconditions;
}
public void setAllowMultipleSatisifedPreconditions(boolean allowMultipleSatisifedPreconditions) {
this.allowMultipleSatisifedPreconditions = allowMultipleSatisifedPreconditions;
}
/**
* @deprecated
*/
protected void notifyListeners(String msg) {
Iterator i = executionListeners.iterator();
while(i.hasNext()) {
ProcessExecutionListener l = (ProcessExecutionListener) i.next();
l.printMessage(msg);
}
}
/**
* @deprecated
*/
protected void setCurrentExecuteService(Process p) {
Iterator i = executionListeners.iterator();
while (i.hasNext()) {
ProcessExecutionListener l = (ProcessExecutionListener) i.next();
l.setCurrentExecuteService(p);
}
}
/**
* @deprecated
*/
protected void finishExecution(int retCode) {
Iterator i = executionListeners.iterator();
while (i.hasNext())
{
ProcessExecutionListener l = (ProcessExecutionListener) i.next();
l.finishExecution(retCode);
}
}
/**
* @deprecated
*/
public void addExecutionListener(ProcessExecutionListener listener) {
executionListeners.add(listener);
}
public void addMonitor(ProcessMonitor monitor) {
monitors.add(monitor);
}
protected void executionFailed(String msg) throws ExecutionException {
executionFailed( new ExecutionException( msg ) );
}
protected void executionFailed(Exception e) throws ExecutionException {
executionFailed( new ExecutionException( e ) );
}
protected void executionFailed(ExecutionException e) throws ExecutionException, UnsatisfiedPreconditionException, MultipleSatisfiedPreconditionException {
e.setProcess(process);
for(Iterator i = monitors.iterator(); i.hasNext();) {
ProcessMonitor monitor = (ProcessMonitor) i.next();
monitor.executionFailed(e);
}
throw e;
}
protected boolean passFilter( ProcessMonitor monitor, Process process ) {
int processType = Process.ANY;
if( process instanceof AtomicProcess )
processType = Process.ATOMIC;
else if( process instanceof CompositeProcess )
processType = Process.COMPOSITE;
else
processType = Process.SIMPLE;
return (processType & monitor.getMonitorFilter()) != 0;
}
protected void executionStarted(Process process, ValueMap inputs) {
for(Iterator i = monitors.iterator(); i.hasNext();) {
ProcessMonitor monitor = (ProcessMonitor) i.next();
if( passFilter( monitor, process) )
monitor.executionStarted(process, inputs);
}
}
protected void executionFinished(Process process, ValueMap inputs, ValueMap outputs) {
for(Iterator i = monitors.iterator(); i.hasNext();) {
ProcessMonitor monitor = (ProcessMonitor) i.next();
if( passFilter( monitor, process) )
monitor.executionFinished(process, inputs, outputs);
}
}
protected void executionStarted() {
for(Iterator i = monitors.iterator(); i.hasNext();) {
ProcessMonitor monitor = (ProcessMonitor) i.next();
monitor.executionStarted();
}
}
protected void executionFinished() {
for(Iterator i = monitors.iterator(); i.hasNext();) {
ProcessMonitor monitor = (ProcessMonitor) i.next();
monitor.executionFinished();
}
}
protected void initEnv(OWLKnowledgeBase defaultKB) {
if(kb != null)
env = kb;
else
env = defaultKB;
performResults = new HashMap();
}
public ValueMap execute(Process p) {
ValueMap result = execute(p, new ValueMap());
return result;
}
public ValueMap execute(Process p, ValueMap values) {
initEnv( p.getKB() );
process = p;
executionStarted();
ValueMap result = null;
try {
result = executeProcess( p, values );
} catch( ExecutionException e ) {
// executionFailed( e );
System.out.println("Excecution failed cause of " + e.getMessage());
}
notifyListeners("[DONE]");
finishExecution(ProcessExecutionListener.EXEC_DONE);
executionFinished();
return result;
}
public ValueMap execute(Perform p) {
initEnv( p.getKB() );
process = p.getProcess();
ValueMap result = null;
try {
result = executePerform( p );
} catch( ExecutionException e ) {
// executionFailed( e );
System.out.println("Excecution failed");
}
notifyListeners("[DONE]");
finishExecution(ProcessExecutionListener.EXEC_DONE);
return result;
}
protected ValueMap executeProcess(Process process, ValueMap inputs) {
ValueMap result = null;
executionStarted( process, inputs );
setCurrentExecuteService( process );
if( checkPreconditions ) {
checkPreconditions( process, inputs );
}
if(process instanceof AtomicProcess) {
result = executeAtomicProcess((AtomicProcess) process, inputs);
}
else if(process instanceof CompositeProcess) {
result = executeCompositeProcess((CompositeProcess) process, inputs);
}
else if(process instanceof SimpleProcess) {
executionFailed(
new NotImplementedException("Executing simple processes is not implemented!") );
}
else
executionFailed( "Unknown process type " + process );
// just for safety
if( result == null )
executionFailed( "Null result after executing process " + process + "!" );
else
executionFinished( process, inputs, result );
return result;
}
protected ValueMap executeAtomicProcess(AtomicProcess process, ValueMap values) {
if(DEBUG) System.out.println("Executing AtomicProcess " + process + "\nInputs:\n" + values.debugString());
AtomicGrounding grounding = process.getGrounding();
if( grounding == null ) throw new ExecutionException( "No grounding for " + process );
if(DEBUG) System.out.println("Invoking " + grounding.getDescriptionURL());
ValueMap result = grounding.invoke(values, env);
result.addMap( values );
if(DEBUG) System.out.println("Result:\n" + result.debugString() + "\n");
if( !env.isConsistent() )
throw new ExecutionException("Invalid value returned from the process " + process, process);
return result;
}
protected ValueMap executeCompositeProcess(CompositeProcess process, ValueMap values) {
ValueMap prevParentPerform = (ValueMap) performResults.get(OWLS.Process.TheParentPerform);
// ValueMap prevThisPerform = (ValueMap) performResults.get(OWLS.Process.ThisPerform);
performResults.put(OWLS.Process.TheParentPerform, values);
// performResults.put(OWLS.Process.ThisPerform, new ValueMap());
executeConstruct(process.getComposedOf());
Result result = process.getResult();
if( result != null ) {
OutputBindingList bindings = result.getBindings();
for(int i = 0; i < bindings.size(); i++) {
OutputBinding binding = bindings.outputBindingAt(i);
Output output = binding.getOutput();
OWLValue value = null;
ParameterValue paramValue = binding.getValue();
if(paramValue instanceof ValueOf) {
ValueOf valueOf = (ValueOf) paramValue;
Perform perform = valueOf.getPerform();
Parameter param = valueOf.getParameter();
ValueMap performResult = (ValueMap) performResults.get(perform);
if(performResult == null)
executionFailed( "Perform " + perform + " cannot be found!" );
value = performResult.getValue(param);
}
else
executionFailed(
new NotImplementedException("Only ValueOf construct in Bindings is supported!") );
values.setValue(output, value);
}
}
// values.addMap( (ValueMap) performResults.get( OWLS.Process.ThisPerform ) );
performResults.put(OWLS.Process.TheParentPerform, prevParentPerform);
// performResults.put(OWLS.Process.ThisPerform, prevThisPerform);
return values;
}
protected ValueMap executePerform(Perform p) {
Process process = p.getProcess();
if(process == null)
executionFailed( "Perform " + p + " does not have a process" );
ValueMap values = new ValueMap();
ValueMap selfBinding = new ValueMap();
ValueMap prevThisPerform = (ValueMap) performResults.get(OWLS.Process.ThisPerform);
performResults.put(OWLS.Process.ThisPerform, values);
BindingList bindings = p.getBindings();
for(int i = 0; i < bindings.size(); i++) {
Binding binding = bindings.bindingAt(i);
Parameter param = binding.getParameter();
ParameterValue paramValue = binding.getValue();
if(paramValue instanceof ValueData)
values.setValue(param, ((ValueData) paramValue).getData());
else if(paramValue instanceof ValueOf) {
ValueOf valueOf = (ValueOf) paramValue;
Perform otherPerform = valueOf.getPerform();
Parameter otherParam = valueOf.getParameter();
ValueMap performResult = (ValueMap) performResults.get(otherPerform);
if(performResult == null)
executionFailed( "Perform " + otherPerform + " cannot be found!" );
OWLValue value = performResult.getValue(otherParam);
if(value == null) {
if( otherPerform.equals( Perform.ThisPerform ) )
selfBinding.setValue( param, otherParam );
else
executionFailed( "There is no value for " + param +
" (bound to Perform: " + otherPerform + " Parameter: " + otherParam + ")");
}
else
values.setValue(param, value);
}
}
for( Iterator i = selfBinding.getVariables().iterator(); i.hasNext(); ) {
Parameter param = (Parameter) i.next();
Parameter otherParam = (Parameter) selfBinding.getValue( param );
OWLValue value = values.getValue( otherParam );
if(value == null)
executionFailed( "There is no value for " + param +
" (bound to Perform: ThisPerform Parameter: " + otherParam + ")");
values.setValue( param, value );
}
values = executeProcess(process, values);
performResults.put(p, values);
performResults.put(OWLS.Process.ThisPerform, prevThisPerform);
return values;
}
protected void executeProduce(Produce produce) {
ValueMap values = (ValueMap) performResults.get( OWLS.Process.ThisPerform );
OutputBindingList bindings = produce.getBindings();
for(int i = 0; i < bindings.size(); i++) {
OutputBinding binding = bindings.outputBindingAt(i);
Output output = binding.getOutput();
ParameterValue paramValue = binding.getValue();
if(paramValue instanceof ValueData)
values.setValue(output, ((ValueData) paramValue).getData());
else if(paramValue instanceof ValueOf) {
ValueOf valueOf = (ValueOf) paramValue;
Perform otherPerform = valueOf.getPerform();
Parameter otherParam = valueOf.getParameter();
ValueMap performResult = (ValueMap) performResults.get(otherPerform);
if(performResult == null)
executionFailed( "Perform " + otherPerform + " cannot be found!" );
values.setValue(output, performResult.getValue(otherParam));
}
}
}
protected void executeConstruct(ControlConstruct cc) {
if(cc instanceof Perform)
executePerform((Perform) cc);
else if(cc instanceof Sequence)
executeSequence((Sequence) cc);
else if(cc instanceof AnyOrder)
executeAnyOrder((AnyOrder) cc);
else if(cc instanceof Choice)
executeChoice((Choice) cc);
else if(cc instanceof IfThenElse)
executeIfThenElse((IfThenElse) cc);
else if(cc instanceof RepeatWhile)
executeRepeatWhile((RepeatWhile) cc);
else if(cc instanceof RepeatUntil)
executeRepeatUntil((RepeatUntil) cc);
else if(cc instanceof Split)
executeParallel(((Split)cc).getComponents(), false);
else if(cc instanceof SplitJoin)
executeParallel(((SplitJoin)cc).getComponents(), true);
else if(cc instanceof Produce)
executeProduce((Produce)cc);
else if(cc instanceof ForEach)
executeForEach((ForEach)cc);
else
executionFailed( "Unknown control construct " + cc.getConstructName() + "!" );
}
protected void executeSequence(Sequence cc) {
ControlConstructList ccList = cc.getComponents();
for(int i = 0; i < ccList.size(); i++) {
ControlConstruct component = ccList.constructAt(i);
executeConstruct(component);
}
}
protected void executeAnyOrder(AnyOrder cc) {
ControlConstructBag ccList = cc.getComponents();
// AnyOrder says it doesn't matter in which order subelements
// are executed so let's try the sequential order
// FIXME check preconditions to find a correct ordering
OWLIndividualList list = ccList.getAll();
for(int i = 0; i < list.size(); i++) {
ControlConstruct component = (ControlConstruct) list.individualAt(i);
executeConstruct(component);
}
}
protected void executeChoice(Choice choice) {
ControlConstructBag ccList = choice.getComponents();
// Choose a random component to execute
// FIXME check preconditions to find an executable component
int size = ccList.size();
int index = new Random().nextInt(size);
ControlConstruct component = ccList.constructAt(index);
executeConstruct(component);
}
protected void executeIfThenElse(IfThenElse ifThenElse) {
Condition ifCondition = ifThenElse.getCondition();
ControlConstruct thenCC = ifThenElse.getThen();
ControlConstruct elseCC = ifThenElse.getElse();
if( isTrue( ifCondition ))
executeConstruct(thenCC);
else if(elseCC != null)
executeConstruct(elseCC);
}
protected void executeRepeatWhile(RepeatWhile cc) {
Condition whileCondition = cc.getCondition();
ControlConstruct loopBody = cc.getComponent();
while( isTrue( whileCondition ) )
executeConstruct(loopBody);
}
protected void executeRepeatUntil(RepeatUntil cc) {
Condition repeatCondition = cc.getCondition();
ControlConstruct loopBody = cc.getComponent();
do {
executeConstruct(loopBody);
}
while( !isTrue( repeatCondition ) );
}
protected void executeForEach(ForEach cc) {
ValueMap parentValues = (ValueMap) performResults.get(OWLS.Process.TheParentPerform);
ControlConstruct loopBody = cc.getComponent();
Variable loopVar = cc.getLoopVar();
ValueOf valueOf = cc.getListValue();
Perform otherPerform = valueOf.getPerform();
Parameter otherParam = valueOf.getParameter();
ValueMap performResult = (ValueMap) performResults.get(otherPerform);
if(performResult == null)
executionFailed( "Perform " + otherPerform + " cannot be found!" );
OWLIndividual ind = performResult.getIndividualValue(otherParam);
RDFList list = (RDFList) ind.castTo(OWLSObjList.class);
for( ; !list.isEmpty(); list = list.getRest() ) {
OWLIndividual value = list.getFirst();
parentValues.setValue(loopVar, value);
executeConstruct(loopBody);
}
}
protected void checkPreconditions(Process process, ValueMap values)
throws UnsatisfiedPreconditionException, MultipleSatisfiedPreconditionException {
ParameterList locals = process.getLocals();
for( Iterator i = process.getConditions().iterator(); i.hasNext(); ) {
// Get the precondition
Condition cond = (Condition) i.next();
if(DEBUG) System.out.println("Values="+values);
// Get the conjunction of atoms and apply the current value bindings
AtomList atoms = cond.getBody();
if(DEBUG) System.out.println("Atoms = " + atoms);
// This is empty body so nothing to do here (trivially true)
if( atoms == null )
continue;
atoms = atoms.apply( values );
if(DEBUG) System.out.println("Atoms = " + atoms);
// Turn this into
ABoxQuery query = atoms.toQuery( locals );
if(DEBUG) System.out.println("Query = " + query);
List results = env.query( query );
if(DEBUG) System.out.println("Query Results = " + results);
if( results.isEmpty() )
executionFailed( new UnsatisfiedPreconditionException( process, cond ) );
else if( results.size() > 1 && !allowMultipleSatisifedPreconditions )
executionFailed( new MultipleSatisfiedPreconditionException( process, cond ) );
ValueMap result = (ValueMap) results.get( 0 );
values.addMap( result );
}
}
protected boolean isTrue( Condition condition ) {
ValueMap binding = (ValueMap) performResults.get(OWLS.Process.TheParentPerform);
return condition.isTrue( env, binding );
}
protected boolean isTrue( Condition condition, ValueMap binding ) {
return condition.isTrue( env, binding );
}
class ProcessExecutionThread extends Thread {
ControlConstruct cc;
ProcessExecutionThread(ControlConstruct cc) {
this.cc = cc;
}
public void run() {
executeConstruct(cc);
}
}
protected void executeParallel(ControlConstructBag ccList, boolean join) {
ProcessExecutionThread[] threads = new ProcessExecutionThread[ccList.size()];
for(int i = 0; i < ccList.size(); i++) {
ControlConstruct construct = ccList.constructAt(i);
threads[i] = new ProcessExecutionThread(construct);
if(DEBUG) System.out.println("Starting " + construct + "...");
threads[i].start();
}
if(join) {
for(int i = 0; i < threads.length; i++) {
try {
if(DEBUG) System.out.println("Waiting " + threads[i].cc + " to finish...");
threads[i].join();
if(DEBUG) System.out.println(threads[i].cc + " finished");
} catch (InterruptedException e) {
notifyListeners("[ERROR]\n");
notifyListeners("Execution Stopped\n");
finishExecution(ProcessExecutionListener.EXEC_ERROR); // done
executionFailed( e );
}
}
}
}
}