package wrapper; import java.util.*; public abstract class CPAMMegamodule { /** Number of possible invocation per connection*/ final static int noInv = 10; //replace 10 by a larger number, e.g. 10000 /** Number of possible connections per megamodule.

The following condition must be fulfilled:
noInv * noCon + noCon < MAX int */ final static int noCon = 10; //replace 10 by a larger number, e.g. 10000 /**Table of all the parameters in the megamodule and their default values.*/ private ParamValueTable defaultParams; /**Kind of parameters this megamodule accepts (String or Gentype or ....)*/ final String paramType; /**Maps connection ids to connection objects.*/ private Map connections; private Random random = new Random(); public CPAMMegamodule(String paramType){ this.paramType = paramType; defaultParams = new ParamValueTable(paramType); //ParamValueTable is already synchronized for all dangerous methods createParameters(); connections = Collections.synchronizedMap(new HashMap()); } /**Sets up the table with the parameter names and default values for this megamodule. This method should be overwritten when applying the wrapper template by subclassing.

Use addParam(String name, Object value) to create the name value pairs. The names and the types of the values have to correspond to the names and types specified in the repository. In case of duplicate names or invalid types the method addParam throws ParameterNameException and ParameterTypeException. */ protected void createParameters() {} /**Adds a name value pair to the list of known paramaters of a megamodule. This list should be consistent with the CHAIMS repository. Only use this method within createParameters. The values are default settings that are used by GETPARAM and INVOKE when no client specific or invocation specific settings exist. @throws ParameterNameException the parameter already exists or the parameter is not in the repository @throws ParameterTypeException the type of the parameter is not okay*/ public final void addParam(String paramname, Object paramvalue) { defaultParams.add(paramname, paramvalue); } /**Make estimates. This method should be overwritten when applying the wrapper template to a megamodule that knows how to make estimates.

Return true (for estimates being available). The datastructure 'estimates' contains the fields timeRequired, feeRequired, datavolumeRequired, timeProvided , feeProvided, datavolumeProvided, timeValue, feeValue, datavolumeValue, timeAccuracy, feeAccuracy, datavolumeAccuracy. The ParamValueTable 'clientsettings' contains the client-specific parameter settings. The values can be read with clientsettings.get("parametername"). In case of an unknown methodname, throw an exception of type MethodNameException.*/ protected boolean makeEstimate(Estimates estimates, String methodname, ParamValueTableReader clientsettings) throws MethodNameException { return false; } /**Executes an invocation. Makes synchronous invocation of (legacy) computational code. This method must be overwritten when using the wrapper template.

Methodname is the name of the method invoked according to the CHAIMS repository. In case of an unknown methodname, throw an exception of type MethodNameException. InvocationObject gives the reference to the object holding invocation specific parameter settings, results, progress information and status information for the invocation.

The method must return true upon successful completion of the computation, or false in case of errors that result in being unable to complete all results or in case of an abort. Before returning with true all the final results have to be stored in the invocationObject.

Methods to use (@see also interface CPAMWrapperCallbacks): Method for getting invocation parameters: getParam Method for storing final results: updateParam Methods for storing progressive results and progress information: updateParam, updateInvocationProgress Other useful methods and fields: containsParam, getInvocationId, getInvocationParams Alternative for using getParam: getInvocationParams.get Alternative for storing progressive results and progress information within this method: overwrite the methods getInvocationProgress, getResultProgress, getResultValue ????*/ protected abstract boolean dispatchInvocation(CPAMWrapperCallbacks invocationObject, String methodname); /**Abort the invocation. This method may be overwritten if the computational code can be aborted. The executing invocation given by invocationObject should be aborted. If an immediate abort is possible return true (the invocation referenced by invocationObject will no longer be available and its references should not be used anymore). Otherwise return false (in this case results and status can still be written back in the usual way). If a deferred abort is possible, return false for this method, and return false to dispatchInvocation once the computation has aborted and no longer needs to reference invocationObject. Methodname gives the name of the method invoked by this invocation. It is optional to overwrite this method.*/ protected boolean abortExecution(Invocation invocationObject, String methodname) {return false;} /**If new results for the parameter with the name paramname exist that have not yet been reported back to the wrapper, do it now. For reporting results use invocationObject.updateParam(...). It is optional to overwrite this method. */ protected void updateResult(String paramname, CPAMWrapperCallbacks invocationObject, String methodname) {} /**If new progress information exists for the invocation given by invocationObject or if new result values exist that influence the status of this invocation, report them now. For reporting results use invocationObject.updateParam(...). For reporting invocation progress use invocationObject.updateInvocationProgress(...). */ protected void updateExecutionStatus(CPAMWrapperCallbacks invocationObject, String methodname) {} final Invocation getInvocation(Integer invocationId) { Integer connectionId = new Integer(invocationId.intValue() - ((invocationId.intValue() / noCon) * noCon)); return getConnection(connectionId).getInvocation(invocationId); } final Connection getConnection(Integer connectionId) { if (! connections.containsKey(connectionId)) throw new InvalidConnectionIdException("Connection id " + connectionId.toString() + " unknown"); return (Connection) connections.get(connectionId); } final void connectionTerminated(Integer connectionId) { //This connection has been terminated, so delete it from the table of // connections connections.remove(connectionId); } /**Creates a new connection object and its connection id. The connection id is used to reference this connection and can also be transmitted to a client beyond the barrier of autonomy. Puts the connection object with its connection id into the table 'connections' and returns the connection id. */ final Integer createConnection () { //Connectionids have values from 0 to noCon if (connections.size() >= CPAMMegamodule.noCon) throw new OutOfResourcesException("Maximum number of connections for this megamodule reached."); Integer newConnectionId; int connectionId = Math.abs(random.nextInt() % noCon); while (connections.containsKey(new Integer(connectionId))) connectionId = (++connectionId) % noCon; newConnectionId = new Integer(connectionId); Connection c = new Connection(defaultParams, this, newConnectionId); connections.put (newConnectionId, c); return newConnectionId; } }