package si.ijs.acs.objectexplorer.engine; /** * Data structure that describes the operation declared * by a given introspectable. Note that objects of this * type do not describe a specific remote call (an instance * of the call), but rather syntax of an operation. In that * way they are analogous to Java <code>java.lang.reflect.Method</code> * instances. * A note about the convention on how parameters to the operation * are described: each parameter is described by a name, a type * and a mask field. These data are stored in arrays of equal length, * corresponding indexes describing the same parameter. Only * parameters with mask set to true should be processed by the GUI, * others are used by the engine to hold "context" parameters, such * as callbacks, parameters passed by reference (pointers) to the remote * objects, parameters declared as OUT in CORBA etc. GUI implementations * must not modify any parameter values that declare <code>false</code> * in the mask. */ public abstract class Operation { private String name = null; private SimpleIntrospectable introspectable = null; private String[] parameterNames = null; private DataType[] parameterTypes = null; private boolean[] mask = null; private boolean special = false; private boolean invocation = false; private DataType returnType=null; /** * Constructs a new instance of an operation. * * @param name the name of the operation to be displayed in GUI * @param introspectable the remote object that declares this operation * @param parameterNames an array of string names of all parameters * that the operation declares * @param parameterTypes an array of <code>DataType</code> objects identifying * the parameter types in the same sequence as in the names * array * @param mask an array of booleans that indicates which parameters should * be requested by the GUI to be supplied by the user, when the * method is invoked. The GUI should only ask for parameters that * have <code>true</code> flag set in this array. The sequence is * the same as in types and names arrays. * @param invocation <code>true</code> iff this method is an asynchronous * method. If so, it must be invoked with <code>invokeAsync()</code> method * and will, as a response return an invocation object. * @param special <code>true</code> iff the operation should be treated as * special in the GUI (ie. displayable only if certain checkbox is checked) */ public Operation(String name, SimpleIntrospectable introspectable, DataType returnType, String[] parameterNames, DataType[] parameterTypes, boolean[] mask, boolean invocation, boolean special) { super(); if (name == null) throw new NullPointerException("name"); if (introspectable == null) throw new NullPointerException("introspectable"); if (parameterNames == null) throw new NullPointerException("parameterNames"); if (parameterTypes == null) throw new NullPointerException("parameterTypes"); if (mask == null) throw new NullPointerException("mask"); if (mask.length != parameterNames.length) throw new IllegalArgumentException("parameterNames.length != mask.length"); if (mask.length != parameterTypes.length) throw new IllegalArgumentException("mask.length != parameterTypes.length"); this.name = name; this.mask = mask; this.introspectable = introspectable; this.parameterNames = parameterNames; this.parameterTypes = parameterTypes; this.special = special; this.invocation = invocation; this.returnType=returnType; } /** * Returns the introspectable instance that declares this method. * Returns the same value as was passed to the constructor. * * @return introspectable instance */ public SimpleIntrospectable getIntrospectable() { return introspectable; } /** * Returns the mask value for each argument / parameter to this * method. GUIs should only process (query the user for values) * only those parameters that declare <code>true</code>. Other * parameters should be left unmodified. * * @return a mask array */ public boolean[] getMask() { return mask; } /** * Returns the name of this operation, as it should be displayed * to the user. * * @return operation name */ public String getName() { return name; } /** * Returns the parameter names array. This is the same * value as was passed to the constructor. * * @return parameter names */ public String[] getParameterNames() { return parameterNames; } /** * Returns the array of parameter types for each parameter * to this operation. Note that if parameters are of complex * types and it is desired for the GUI to be able to query * users for their values and construct instances described * by this classes, the classes must declare a public constructor * that takes all parameters that have to be supplied to * instantiate a type. * * @return an array of parameter types */ public DataType[] getParameterTypes() { return parameterTypes; } /** * Returns the array of parameter types for each parameter * to this operation. Note that if parameters are of complex * types and it is desired for the GUI to be able to query * users for their values and construct instances described * by this classes, the classes must declare a public constructor * that takes all parameters that have to be supplied to * instantiate a type. * * @return a return value DataType */ public DataType getReturnType() { return returnType; } /** * Returns short name of the given DataType object * Creation date: (13.5.2001 12:09:49) * @return java.lang.String * @param param java.lang.Class */ private String getShortParamName(DataType param) { return param.getName().substring(param.getName().lastIndexOf(".")+1); } /** * Returns the parameter types of this operation as they should be displayed * by the GUI. * * @return parameter names */ private String getStringParamTypes() { StringBuffer result=new StringBuffer(" "); for (int i=0;i<parameterTypes.length;i++) { if (i>0) result.append(", "); if (!mask[i]) result.append("<"); if (parameterTypes[i].isArray()) { result.append(getShortParamName(parameterTypes[i].getComponentType())); for (int j=0;j<=(parameterTypes[i].getName().lastIndexOf("[")-parameterTypes[i].getName().indexOf("[")); j++ ) { result.append("[ ]"); } } else result.append(getShortParamName(parameterTypes[i])); if (!mask[i]) result.append(">"); } result.append(" "); return result.toString(); } /** * Invokes this operation. The method returns a remote call * data struture that will pack the input parameters, return * values and possible exceptions of the call. * <b>Note: this method should only be used to invoke * synchronous operations, ie. operations that do not * create <code>Invocations</code> as a side-effect.</b>. * The method must block for the duration of the call, * although it can terminate with a timeout, if this * condition can be detected. * * @param data parameters to be passed to the remote call. It is * the responsibility of the GUI to initialize this array * in accordance to the guidelines set forth in the documentation * of this class * * @return remote call data structure that packs the results * of the remote operation call */ public abstract RemoteCall invoke(Object[] data); /** * Invokes an asynchronous operation on the introspectable instane. * The method produces an invocation instance as a side-effect. Note * that because invocations are asynchronous, a callback parameter is * required to receive the asynchronous responses. Use this model for * monitors, alarms, event notifications and similar designs. * * @return invocation instance that represents the started process on * the remote machine; this instance contains also the familiar * remote call data structure that describes the call that * generated the invocation * @param data parameters to be passed to the remote call. It is * the responsibility of the GUI to initialize this array * in accordance to the guidelines set forth in the documentation * of this class * @param cb the callback that will receive the async notifications. Must * not be <code>null</code>. */ public abstract Invocation invokeAsync(Object[] data, RemoteResponseCallback cb); /** * Returns <code>true</code> if this object represents an * operation, that is asynchronous. If so, an invocation of * such operation will produce an invocation object as a side * effect. Asynchronous operations <b>must</b> be invoked with * <code>invokeAsync()</code> method. Therefore the GUI should * always check first the return value of this call and decide * which mode of invocation (sync or async) to use. * * @return <code>true</code> if the method should be invoked through the <code>invokeAsync()</code> method. */ public boolean isInvocation() { return invocation; } /** * Returns <code>true</code> if this operation is "special". GUI * decides how to handle special operations. The preferred way * is not to display them until the user has checked a special * checkbox allowing the GUI to display "advanced" or "dangerous" * features. * * @return <code>true</code> if this operation is special */ public boolean isSpecial() { return special; } /** * Returns the display name of this operation with its * parameter types in brackets. * * @return name of <code>this</code>. */ public String toString() { return (name+" ("+getStringParamTypes()+")"); } }