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; } }