package wrapper;
import java.util.*;
final class Invocation implements Runnable, CPAMWrapperCallbacks{
/**The invocation specific settings of all the parameters, contains client specific
or default settings if no invocation specific settings exist.*/
private ParamValueTable invParams;
/**The status of the invocation specific parameter settings. The keys are
the names of parameters, values are Integers:
* 2: holds client specific setting (set by SETPARAM or taken from default
when invocation was created),not ready for extraction by EXTRACT
* 3: holds invocation specific setting (set by INVOKE)
not ready for extraction by EXTRACT
* 4: value has been updated by computational (legacy) code, yet does not
contain yet final value, ready for progressive extraction
* 5: value has been finally set by computation (legacy) code,
computation for that parameter is complete */
private Map invParamsStatus;
/**Contains the accuracy for all parameters. Is initialised to 0 when
invocation is created. Is it right not to distinguish between
inputs and outputs?*/
private Map invParamsAccuracy;
/**Progress of the invocation. 0 signifies both that progress is
still 0 or that no invocation progress is available at all for this method.*/
private float invocationProgress = 0;
/**Status of the invocation. The following states are possible:
* 0: results need to be computed, legacy code has not started yet
* 1: results need to be computed, legacy code is computing
* 2: some results are ready to some accuracy, legacy code is computing
* 3: legacy code has aborted with error before all results done
* 4: results are all done, client can extract them, legacy code no more active
* 5: client has terminated invocation, legacy code is still working
* 6: client has terminated invocation, legacy code no more active */
private int invocationStatus = 0;
private String methodname;
protected Connection parent;
private final Integer invocationId;
Invocation(ParamValueTable clientParams, String methodname,
Connection connection, Integer invocationId) {
String key;
parent = connection;
invParams = new ParamValueTable(parent.parent.paramType);
invParams.putAll(clientParams);
invParamsStatus = Collections.synchronizedMap(new HashMap());
invParamsAccuracy = Collections.synchronizedMap(new HashMap());
Set keys = invParams.keySet(); Iterator i = keys.iterator();
while (i.hasNext()) {
key = (String)i.next();
invParamsStatus.put(key, new Integer(2));
invParamsAccuracy.put(key, new Float(0));
}
this.methodname = methodname;
//ADD: check validity of methodname against repository
this.invocationId = invocationId;
}
public Integer getInvocationId() {return invocationId;}
void terminate() {
if (invocationStatus == 1 | invocationStatus == 2) {
invocationStatus = 5;
//notify the computational code that it could abort this invocation
//as Java does GC we do not take any special action in either case, the
// connection object will be around as long as the computational code
// has a reference to it and the callbacks will work, though the client
// cannot get the resulsts anymore because officially this invocation
// will be gone
if (parent.parent.abortExecution(this, methodname)) invocationStatus = 6;
}
else if (invocationStatus == 0 | invocationStatus == 3 |
invocationStatus == 4) invocationStatus = 6;
else if (invocationStatus == 5 | invocationStatus == 6) throw
new InvalidInvocationIdException("This invocation has been terminated and does not exist anymore.");
else throw new InvalidInvocationIdException("Invalid status, program bug. Please contact....");
parent.invocationTerminated(invocationId);
}
InvocationStatus status() {
InvocationStatus invstat = new InvocationStatus(invocationId);
parent.parent.updateExecutionStatus(this, methodname);
if (invocationStatus <= 1) invstat.status = "NOT_DONE";
else if (invocationStatus == 2) invstat.status = "PARTIAL";
else if (invocationStatus == 3) invstat.status = "ERROR";
else if (invocationStatus == 4) invstat.status = "DONE";
else if (invocationStatus == 5 | invocationStatus == 6) throw
new InvalidInvocationIdException("This invocation has been terminated and does not exist anymore.");
else throw new InvalidInvocationIdException("Invalid status, program bug. Please contact....");
invstat.progress= invocationProgress;
return invstat;
}
void initParam(String name, Object value){
invParams.set (name, value);
invParamsStatus.put(name, new Integer(3));
}
public void updateParam(String name, Object value, boolean resultIsFinal,
float accuracy){
invParams.set (name, value);
if (resultIsFinal) {
invParamsStatus.put (name, new Integer(5));
invParamsAccuracy.put(name, new Float(accuracy));
}
else {
invParamsStatus.put (name, new Integer(4));
invParamsAccuracy.put(name, new Float(accuracy));
invocationStatus = 2;
}
}
public Object getParam(String name) { //can raise a ParameterNameException
return invParams.get(name);
}
ResultStatus getParamStatus(String name) {
//can raise a MethodNameException
int intstatus;
parent.parent.updateResult(name, this, methodname);
ResultStatus rstatus = new ResultStatus(name, invocationId);
intstatus = ((Integer)invParamsStatus.get(name)).intValue();
if (intstatus == 5) rstatus.status = new String("DONE");
else if (intstatus == 4) rstatus.status = new String ("PARTIAL");
else rstatus.status = new String ("NOT_DONE");
rstatus.accuracy = ((Float) invParamsAccuracy.get(name)).floatValue();
return rstatus;
}
public boolean containsParam(String name) {
//ADD: also check with repository
return invParams.containsName(name);
}
public void updateInvocationProgress(float progress) {
invocationProgress = progress;
}
void startExecution() {
//has to be started asynchronously
new Thread(this).start();
}
public void run() {
//call legacy code
invocationStatus = 1;
boolean success = parent.parent.dispatchInvocation(this, methodname);
if (invocationStatus == 5) invocationStatus = 6;
else if (success) {
//ADD: test if all results of the invocation according to repository
// have status final
invocationStatus = 4;
invocationProgress = 100;
}
else invocationStatus = 3;
}
}