package tud.st.bpel.prolog;
import java.util.Vector;
import alice.tuprolog.InvalidTheoryException;
import alice.tuprolog.MalformedGoalException;
import alice.tuprolog.Prolog;
import alice.tuprolog.SolveInfo;
import alice.tuprolog.Struct;
import alice.tuprolog.Term;
import alice.tuprolog.Theory;
/**
* This class is the heart of the BPEL Prolog Engine.
* It contains the Prolog engine and saves as well all policies.
* Should be accessed through the interface.
* @author Philipp Zuehlke
*
*/
public class BPELPrologEngine implements IBPELPrologEngine {
/**a reference to the tuProlog engine*/
private Prolog engine = new Prolog();
/**a vector of all policies*/
private Vector<Policy> policies = new Vector<Policy>();
// Example for defining new clauses:
// private final static String theories =
// "invoke(ProcessID,Token,Timestamp,Params):-invoke(ProcessID,Token,Timestamp,Params,false).\n" +
// "invoke_req(ProcessID,Token,Timestamp,Params):-invoke(ProcessID,Token,Timestamp,Params,true).\n" +
// "hasbeen_invoked(ProcessID,Token,Timestamp):-invoke(ProcessID,Token,Timestamp,_),invoke_req(ProcessID,Token,Timestamp,_).\n"
// ;
/**
* Constructs an instance of this class
* @param addConstistencyPolicies When true, policies concerning the consistency are added to the list of policies
*/
public BPELPrologEngine(boolean addConsistencyPolicies)
{
// Example for defining new clauses:
// try {
// engine.addTheory(new Theory(theories));
// } catch (InvalidTheoryException e) {
// e.printStackTrace();
// }
if(addConsistencyPolicies) //has the flag been set?
addConsistencyPolicies();
}
/**
* This private methods adds policies to this engine to ensure consistency of the database
*/
private void addConsistencyPolicies()
{
//policy violated, when invoke happens _after_ corresponding end_invoke
addPolicy("invoke(ProcessID,Token,T1,_,_)," +
"end_invoke(ProcessID,Token,T2,_,_)," +
"T1>T2."
);
//policy violated, when destroy_process happens before create_process
addPolicy("create_process(_,ProcessID,CreateT,_)," +
"destroy_process(ProcessID,DestroyT,_)," +
"CreateT>DestroyT."
);
//policy violated, when invoke happens before process is created
addPolicy("create_process(_,ProcessID,CreateT,_)," +
"invoke(ProcessID,_,Time,_,_)," +
"CreateT>Time."
);
//policy violated, when invoke happens after process is destroyed
addPolicy("destroy_process(ProcessID,DestroyT,_)," +
"invoke(ProcessID,_,Time,_,_)," +
"Time>DestroyT."
);
//policy violated, when end_invoke happens before process is created
addPolicy("create_process(_,ProcessID,CreateT,_)," +
"end_invoke(ProcessID,_,Time,_,_)," +
"CreateT>Time."
);
//policy violated, when end_invoke happens after process is destroyed
addPolicy("destroy_process(ProcessID,DestroyT,_)," +
"end_invoke(ProcessID,_,Time,_,_)," +
"Time>DestroyT."
);
//policy violated, when get_var happens before process is created
addPolicy("create_process(_,ProcessID,CreateT,_)," +
"get_var(ProcessID,_,Time,_,_)," +
"CreateT>Time."
);
//policy violated, when get_var happens after process is destroyed
addPolicy("destroy_process(ProcessID,DestroyT,_)," +
"get_var(ProcessID,_,Time,_,_)," +
"Time>DestroyT."
);
//policy violated, when set_var happens before process is created
addPolicy("create_process(_,ProcessID,CreateT,_)," +
"set_var(ProcessID,_,Time,_,_,_)," +
"CreateT>Time."
);
//policy violated, when set_var happens after process is destroyed
addPolicy("destroy_process(ProcessID,DestroyT,_)," +
"set_var(ProcessID,_,Time,_,_,_)," +
"Time>DestroyT."
);
//policy violated, when invoke has no corresponding static process information
addPolicy("invoke(ProcessID,Token,_,_,_)," +
"create_process(DefinitionID,ProcessID,_,_)," +
"s_process(DefinitionID,_,Invokes)," +
"\\+member(s_invoke(Token,_,_,_,_,_,_),Invokes)."
);
//policy violated, when end_invoke has no corresponding static process information
addPolicy("end_invoke(ProcessID,Token,_,_,_)," +
"create_process(DefinitionID,ProcessID,_,_)," +
"s_process(DefinitionID,_,Invokes)," +
"\\+member(s_invoke(Token,_,_,_,_,_,_),Invokes)."
);
/* AL: invoke kann sowohl lesender als auch schreibender zurgriff sein
//policy violated, when set_var has no corresponding static process information
addPolicy("set_var(ProcessID,Token,_,_,_,_)," +
"create_process(DefinitionID,ProcessID,_,_)," +
"s_process(DefinitionID,Activities,_)," +
"\\+member(s_act(Token,_),Activities)."
);
//policy violated, when get_var has no corresponding static process information
addPolicy("get_var(ProcessID,Token,_,_,_)," +
"create_process(DefinitionID,ProcessID,_,_)," +
"s_process(DefinitionID,Activities,_)," +
"\\+member(s_act(Token,_),Activities)."
);
*/
//
addPolicy("set_var(ProcessID,Token,_,_,_,_)," +
"create_process(DefinitionID,ProcessID,_,_)," +
"s_process(DefinitionID,Activities,Invokes)," +
"((\\+member(s_act(Token,_),Activities))," +
"(\\+member(s_invoke(Token,_,_,_,_,_,_),Invokes))).");
addPolicy("get_var(ProcessID,Token,_,_,_)," +
"create_process(DefinitionID,ProcessID,_,_)," +
"s_process(DefinitionID,Activities,Invokes)," +
"((\\+member(s_act(Token,_),Activities))," +
"(\\+member(s_invoke(Token,_,_,_,_,_,_),Invokes))).");
}
/**
* This method adds a single fact to the prolog database
* @param fact the fact to add
*/
private void addFact(Term fact)
{
try {
Struct struct = new Struct();
struct.append(fact);
engine.addTheory(new Theory(struct));
} catch (InvalidTheoryException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Adds all static process facts to the BPEL Prolog Engine. It is possible to add several
* StaticProcessFacts as long as their DefinitionID differs
* @param spf the instance which holds the static process facts
*/
// @Override
public void addStaticProcessFacts(IStaticProcessFactGenerator spf) {
addFact(spf.getStaticProcessStruct());
}
/**
* Will be called when a new BPEL process is created
* @param definitionID The unique ID of the corresponding static process facts
* @param processID unique ID of this process. All activities of this process share this id
* @param timestamp The creation time
* @param request True, activity is requested but not yet checked, false, activity will be executed and granted.
*/
// @Override
public void addCreateProcessInstance(String definitionID, String processID, long timestamp, boolean request) {
Term createprocess = new Struct(
"create_process",
new Struct(definitionID),
new Struct(processID),
new alice.tuprolog.Long(timestamp),
new Struct(new Boolean(request).toString())
);
addFact(createprocess);
}
/**
* Will be called when a BPEL process terminates/ends
* @param processID unique ID of this process. All activities of this process share this id
* @param timestamp The destruction time
* @param request True, activity is requested but not yet checked, false, activity will be executed and granted.
*/
// @Override
public void addDestroyProcessInstance(String processID, long timestamp, boolean request) {
Term destroyprocess = new Struct(
"destroy_process",
new Struct(processID),
new alice.tuprolog.Long(timestamp),
new Struct(new Boolean(request).toString())
);
addFact(destroyprocess);
}
/**
* Will be invoked when an Invoke activity response is received.
* @param processID unique ID of the process
* @param token unique id of BPEL activity
* @param timestamp The invocation time
* @param returnVal the returned value
* @param request True, response is requested but not yet checked, false, response is granted.
* */
// @Override
public void addEndInvoke(String processID, String token, long timestamp,
String returnVal, boolean request) {
Term end_invoke = new Struct(
"end_invoke",
new Struct(processID),
new Struct(token),
new alice.tuprolog.Long(timestamp),
new Struct(returnVal),
new Struct(new Boolean(request).toString())
);
addFact(end_invoke);
}
/**
* Will be invoked when an Invoke activity is requested or executed.
* @param processID unique ID of the process
* @param token unique id of BPEL activity
* @param timestamp The invocation time
* @param params Array of string parameters
* @param request True, activity is requested but not yet checked, false, activity will be executed and granted.
* */
// @Override
public void addInvoke(String processID, String token, long timestamp,
String[] params, boolean request) {
Struct list = new Struct();
for( String s : params )
list.append(new Struct(s));
Term invoke = new Struct(
"invoke",
new Struct(processID),
new Struct(token),
new alice.tuprolog.Long(timestamp),
list,
new Struct(new Boolean(request).toString())
);
addFact(invoke);
}
/**
* Will be invoked whenever a variable is read.
* @param processID unique ID of the process
* @param token unique id of BPEL activity
* @param timestamp The invocation time
* @param varName The name of the variable which is read
* @param request True, reading is requested but not yet checked, false, reading of the variable is granted.
*/
// @Override
public void addGetVar(String processID, String token, long timestamp,
String varName, boolean request) {
Term end_invoke = new Struct(
"get_var",
new Struct(processID),
new Struct(token),
new alice.tuprolog.Long(timestamp),
new Struct(varName),
new Struct(new Boolean(request).toString())
);
addFact(end_invoke);
}
/**
* Will be invoked whenever a variable has changed.
* @param processID unique ID of the process
* @param token unique id of BPEL activity
* @param timestamp The invocation time
* @param varName The name of the variable which is set
* @param value the new value of the variable
* @param request True, setting is requested but not yet checked, false, setting of the variable is granted.
*/
// @Override
public void addSetVar(String processID, String token, long timestamp,
String varName, String value, boolean request) {
Term end_invoke = new Struct(
"set_var",
new Struct(processID),
new Struct(token),
new alice.tuprolog.Long(timestamp),
new Struct(varName),
new Struct(value),
new Struct(new Boolean(request).toString())
);
addFact(end_invoke);
}
/**
* Adds a policy to the BPEL prolog engine. This policy is always checked whenever checkAllPolicies gets called()
* @param policy the policy in prolog format
*/
// @Override
public void addPolicy(Policy policy) {
policies.add(policy);
}
private void addPolicy(String policy) {
policies.add(new Policy(null, null, policy));
}
/**
* This method checks if any policy is violated or not
* @return false, if one of the policies is violated, otherwise true
* @throws MalformedPolicyException Exception is thrown, when a policy is invalid
* @throws PolicyViolatedException Exception is thrown, when a policy has been violated
*/
// @Override
public void checkAllPolicies() throws PolicyViolatedException, MalformedPolicyException
{
for( Policy policy : policies )
{
executeCheckAllPolicies(policy, null);
}
}
// AL: checkAllPolicies nur für eine Prozess-Instanz
public void checkAllPolicies(long pid) throws PolicyViolatedException, MalformedPolicyException {
for( Policy policy : policies )
{
executeCheckAllPolicies(policy, pid+"");
}
}
private void executeCheckAllPolicies(Policy policy, String pid) throws PolicyViolatedException, MalformedPolicyException {
String pol = policy.getPolicy();
// Replace ProcessID with pid
if(pid != null) {
pol = pol.replaceAll("ProcessID", "'" + pid + "'");
}
try {
SolveInfo si = engine.solve(pol);
if(si.isSuccess()) { //policy is violated
throw new PolicyViolatedException(policy,si);
}
} catch (MalformedGoalException e) {
//just throw our exception class
throw new MalformedPolicyException(policy);
}
}
/**
* Debug method
* @param str The query to solve
* @return The result of the query
* @throws MalformedGoalException Exception, when the query was invalid
*/
public SolveInfo solve(String str) throws MalformedGoalException {
return engine.solve(str);
}
/**
* DEBUG METHOD
* Prints all facts in the database to the screen
*/
public void printFacts()
{
System.out.println(engine.getTheory());
}
// @Override
public void addRule(String rule) {
try {
engine.addTheory(new Theory(rule));
} catch (InvalidTheoryException e) {
e.printStackTrace();
}
}
// AL: Fakten müssen sich auch entfernen lassen!
public void removeFactsForProcess(Long pid) {
// engine.clearTheory();
try {
System.out.println("Removing process facts for process: " + pid);
engine.solve("retractall(get_var('"+pid+"',_,_,_,_)).");
engine.solve("retractall(set_var('"+pid+"',_,_,_,_,_)).");
engine.solve("retractall(invoke('"+pid+"',_,_,_,_)).");
engine.solve("retractall(end_invoke('"+pid+"',_,_,_,_)).");
engine.solve("retractall(create_process(_,'"+pid+"',_,_)).");
engine.solve("retractall(destroy_process('"+pid+"',_,_)).");
} catch (MalformedGoalException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}