/*
* This file is part of Alida, a Java library for
* Advanced Library for Integrated Development of Data Analysis Applications.
*
* Copyright (C) 2010 - @YEAR@
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Fore more information on Alida, visit
*
* http://www.informatik.uni-halle.de/alida/
*
*/
//TODO: do we need unset..... if we wompletely switch to annotations??
package de.unihalle.informatik.Alida.operator;
import de.unihalle.informatik.Alida.operator.events.ALDOperatorExecutionProgressEvent;
import de.unihalle.informatik.Alida.operator.events.ALDOperatorExecutionProgressEventListener;
import de.unihalle.informatik.Alida.version.ALDVersionProvider;
import de.unihalle.informatik.Alida.version.ALDVersionProviderFactory;
import de.unihalle.informatik.Alida.annotations.Parameter;
import de.unihalle.informatik.Alida.annotations.Parameter.ExpertMode;
import de.unihalle.informatik.Alida.datatypes.ALDConfigurationValidator;
import de.unihalle.informatik.Alida.exceptions.*;
import de.unihalle.informatik.Alida.exceptions.ALDOperatorException.OperatorExceptionType;
import java.io.*;
import java.util.*;
import java.lang.reflect.Field;
import javax.swing.event.EventListenerList;
/**
* This is the abstract super class for all Alida operators. Alida opertators
* facilitate automatic logging of the processing historys and automatic
* generation of user interfaces.
* <p>
* The interface consisting of all parameters needs to be define by annotating
* the corresponding fields (i.e. member variables) using the {@link Parameter}
* annotation. The direction of a parameter may be input (IN), output (OUT), or
* both input and output (INOUT). A Parameter may be declared to be
* supplemental. Supplemental parameters, e.g., control output of debugging
* information or return intermediate results. The outputs of the operator are
* expected to be independent of the value of these supplemental values which
* are not stored in the processing history. A parameter with direction IN or
* INOUT which is not supplemental may be declared to be required. For OUT
* parameter and supplemental parameters the required field is ignored. If a
* parameter of an operator is expected to be documented in the data flow of the
* processing history, it may be of any Java class where the instances are by
* references. This excludes only primitive data types, interned strings, and
* cached numerical objects. If the parameter is not be part of the data flow
* all classes are acceptable.
* <p>
* Parameter may be added or removed.
* <p>
* Values of parameters and inputs have to be set prior to invoking the operator
* via <code>runOp()</code> and the resulting outputs may be retrieved from the
* operator after return from <code>runOp()</code>.
* <p>
* A default constructor without arguments has to be implemented for all
* features of code generation and generic execution to be available. For
* generic execution the operator has to be annotated with
* {@link de.unihalle.informatik.Alida.annotations.ALDAOperator} with
* <code>allowGenericExecution</code> set to true.
* <p>
* The method <code>operate()</code> implements the processing of this operator
* and has to be overridden when implementing non-abstract operators. All
* information passed into and back from the operator are passed via the member
* variables of the operator which are properly annotated. This method should by
* no means be used to invoke processing of the operator directly, rather
* <code>runOp()</code> is to be used.
* <p>
* The method <code>runOp()</code> is called by the user of an operator to
* invoke processing. <code>runOp()</code> first checks if all required
* parameters and inputs are set to non-null values and subsequently check the
* validity of parameters and inputs as defined by the method
* <code>validateCustom</code> which has to be overridden when implementing an
* operator.
* <p>
* Refer to the Alida manual for more details and examples.
*
* @author posch
*/
public abstract class ALDOperator
implements ALDConfigurationValidator, ALDOperatorExecutionProgressEventListener {
/**
* Determines the visibility of an operator invocation via <code>runOp()</code> in
* the processing history.
*/
public enum HidingMode {
/** visible in the history
*/
VISIBLE,
/** hide this invocation, i.e. the corresponding opnode, form the
* history as well as all children, i.e. nested calls of further operators
*/
HIDDEN,
/** the invocation is visible, but all children, i.e. nested invocations
* of further operators, are hidden
*/
HIDE_CHILDREN
}
// ====================================================
// MEMBER VARIABLES
/**
* Name of the operator
*/
public String name;
/**
* Genuine object representing the operation. This may be used in operators,
* wrapping another class implementing the actual operation. Reflections
* need to be used to set this member in extending classes.
*/
Object genuineInstance;
/**
* The <code>opNode</code> of this operator during execution of <code>runOp</code>.
*/
private ALDOpNode opNode = null;
/**
* Verbose flag to be inherited by all operators.
*/
@Parameter(label = "Verbose", supplemental = true,
direction = Parameter.Direction.IN, description = "Verbose flag",
mode = ExpertMode.ADVANCED)
protected Boolean verbose = new Boolean(false);
/**
* Does this operator prefer a complete DAG or a data dependency DAG. This
* field may be changed when implementing an operator.
*/
protected boolean completeDAG = true;
/**
* Access to the central port hash.
*/
protected static ALDPortHashAccess portHashAccess = new ALDPortHashAccess();
/**
* A weak hashmap which contains for each thread a stack of opNodes
* reflecting the current state of the method stack. Whenever
* <code>runOp()</code> is called, an opNode is created which is associated
* with this call. It is pushed onto the stack and popped at the end of
* <code>runOp()</code>. As the first element a opNode for the dummy
* operator ALDToplevelOperator is created which represents outer or top
* most level of operator calls.
*/
static WeakHashMap<Thread, Stack<ALDOpNode>> opNodeStackHash = new WeakHashMap<Thread, Stack<ALDOpNode>>();
/**
* Hash contains parameter descriptors
* for all currently active parameters.
*/
private Hashtable<String, ALDOpParameterDescriptor> parameterDescriptorsAll;
/**
* Hash contains parameter descriptors which has previous be active but currently inactive, i.e. removed,
* for potential later re-use.
*/
private Hashtable<String, ALDOpParameterDescriptor> parameterDescriptorsInactive;
/**
* Hash contains parameter descriptors which are annotated.
*/
private Hashtable<String, ALDOpParameterDescriptor> parameterDescriptorsAnnotated;
/**
* Instance of a class providing version information.
*/
protected ALDVersionProvider versionProvider = ALDVersionProviderFactory
.getProviderInstance();
// really only debugging
private boolean debug = false;
/**
* List of control event listeners attached to this class listening to
* {@link ALDOperatorExecutionProgressEvent}.
*/
protected transient volatile EventListenerList operatorExecutionEventlistenerList =
new EventListenerList();
// ----------------------------------------------------
// This is currently experimental for debugging purposes
/**
* Mode of implicit construction of the processing graph. Still experimental
* at this point!!
*/
public enum ConstructioMode {
/** obey hiding mode, i.e. construct no history for hidden nodes
*/
CONSIDER_HIDINGMODE,
/** prevent implicit construction completely
*/
NO_HISTORY,
/** complete construction of the history, does not take hiding mode into account
*/
COMPLETE_HISTORY
}
/**
* Mode of implicit construction of the processing graph.
* <dl>
* <li> 0 = complete construction of the history, does not take hiding mode into account (= COMPLETE_HISTORY) </li>
* <li> 1 = do not create opNodes for hidden operator invocations (= CONSIDER_HIDINGMODE) </li>
* <li> 2 = prevent implicit construction completely (= NO_HISTORY) </li>
* </dl>
*/
private static ConstructioMode constructionMode = ConstructioMode.CONSIDER_HIDINGMODE;
// END of This is currently experimental for debugging purposes
// ----------------------------------------------------
// ====================================================
// METHODS
/**
* @param constructionMode the constructionMode to set
*/
public static void setConstructionMode(ConstructioMode constructionMode) {
ALDOperator.constructionMode = constructionMode;
}
/**
* @param constructionMode the constructionMode to set
*/
public static ConstructioMode setConstructionMode() {
return ALDOperator.constructionMode;
}
/**
* Return the current mode of implicit construction {@link #constructionMode}.
*
* @return the constructionMode
* @throws ALDOperatorException
*/
public static int getConstructionMode() {
switch ( ALDOperator.constructionMode) {
case CONSIDER_HIDINGMODE:
return 1;
case NO_HISTORY:
return 2;
case COMPLETE_HISTORY:
return 0;
default:
return 0;
// throw new ALDOperatorException(
// ALDOperatorException.OperatorExceptionType.UNSPECIFIED_ERROR,
// "unhandled construction mode in getConstructionMode" );
}
}
/**
* Set the mode of implicit construction of the processing graph. Still experimental
* at this point!!
* <dl>
* <li> 0 = regular construction </li>
* <li> 1 = do not create opNodes for hidden operator invocations </li>
* <li> 2 = prevent implicit construction completely </li>
* </dl>
*
* @param cMode the constructionMode to set
*/
public static void setConstructionMode(int cMode) {
switch ( cMode) {
case 1:
ALDOperator.constructionMode = ConstructioMode.CONSIDER_HIDINGMODE;
break;
case 2:
ALDOperator.constructionMode = ConstructioMode.NO_HISTORY;
break;
case 0:
ALDOperator.constructionMode = ConstructioMode.COMPLETE_HISTORY;
break;
// default:
// throw new ALDOperatorException(
// ALDOperatorException.OperatorExceptionType.UNSPECIFIED_ERROR,
// "unhandled construction mode in setConstructionMode" );
//
}
}
/**
* This constructor initializes an operator. The name is retrieved from the
* classname and the parameter hash is initialized.
*/
public ALDOperator() throws ALDOperatorException {
this.name = this.getClass().getSimpleName();
this.genuineInstance = this;
this.parameterDescriptorsAll = new Hashtable<String, ALDOpParameterDescriptor>();
this.parameterDescriptorsInactive = new Hashtable<String, ALDOpParameterDescriptor>();
this.parameterDescriptorsAnnotated = new Hashtable<String, ALDOpParameterDescriptor>();
// loop for this class and all super classes over all declared fields to
// find Annotations
Class<?> myclass = this.getClass();
do {
for (Field field : myclass.getDeclaredFields()) {
String name = field.getName();
// if we already found a parameter with this name keep the former one
// as it is lower in the class hierarchy
if ( this.parameterDescriptorsAll.containsKey(name)) {
//System.out.println("discard " + name + " in " + myclass.getName());
break;
}
Parameter pAnnotation = field.getAnnotation(Parameter.class);
// if field is annotated as parameter create and add appropriate
// descriptor
// and not already declared in a class downstream of the
// inheritance hierarchy
// (as we add the first field for each name we find when walking
// up the inheritance hierarchy
if (pAnnotation != null && !fieldContained(name)) {
// Object defaultValue = null;
String explanation;
explanation = pAnnotation.description();
String label = pAnnotation.label();
if (pAnnotation.direction() != Parameter.Direction.UNKNOWN) {
// this is the current version of parameter annotation
ALDOpParameterDescriptor parameterDescriptor = new ALDOpParameterDescriptor(
name, pAnnotation.direction(),
pAnnotation.supplemental(), field.getType(),
explanation, label, pAnnotation.required(),
field, pAnnotation.dataIOOrder(),
pAnnotation.mode(), true,
pAnnotation.callback(),
pAnnotation.paramModificationMode(),
pAnnotation.info());
if (this.debug) {
System.out
.println(" ALDOperator():: adding output parameter <"
+ name + ">");
}
this.addParameterUnconditioned(parameterDescriptor);
this.parameterDescriptorsAnnotated.put( name, parameterDescriptor);
} else {
// this is the previous version of parameter annotation
// still
// handled for compatibility
Parameter.Type myType = pAnnotation.type();
if (myType == Parameter.Type.OUTPUT) {
// output
ALDOpParameterDescriptor parameterDescriptor = new ALDOpParameterDescriptor(
name, Parameter.Direction.OUT, false,
field.getType(), explanation, label,
pAnnotation.required(),
field, pAnnotation.dataIOOrder(),
pAnnotation.mode(), true,
pAnnotation.callback(),
pAnnotation.paramModificationMode(),
pAnnotation.info());
if (!allowedClassForIO(field.getType())) {
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.INVALID_CLASS,
"<" + field.getName() + "> of class <"
+ field.getType().getName()
+ ">" + " in operator "
+ this.name);
}
if (this.debug) {
System.out
.println(" ALDOperator():: adding output parameter <"
+ name + ">");
}
this.addParameterUnconditioned(parameterDescriptor);
this.parameterDescriptorsAnnotated.put( name, parameterDescriptor);
} else if (myType == Parameter.Type.INPUT) {
// input
ALDOpParameterDescriptor parameterDescriptor = new ALDOpParameterDescriptor(
name, Parameter.Direction.IN, false,
field.getType(), explanation, label,
pAnnotation.required(),
field, pAnnotation.dataIOOrder(),
pAnnotation.mode(), true,
pAnnotation.callback(),
pAnnotation.paramModificationMode(),
pAnnotation.info());
if (!allowedClassForIO(field.getType())) {
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.INVALID_CLASS,
"<" + field.getName() + "> of class <"
+ field.getType().getName()
+ ">" + " in operator "
+ this.name);
}
if (this.debug) {
System.out
.println(" ALDOperator():: adding input parameter <"
+ name
+ ">"
+ " of type <"
+ field.getType() + ">");
}
this.addParameterUnconditioned(parameterDescriptor);
this.parameterDescriptorsAnnotated.put( name, parameterDescriptor);
} else if (myType == Parameter.Type.PARAMETER) {
// parameter
ALDOpParameterDescriptor parameterDescriptor = new ALDOpParameterDescriptor(
name, Parameter.Direction.IN, false,
field.getType(), explanation, label,
pAnnotation.required(),
field, pAnnotation.dataIOOrder(),
pAnnotation.mode(), true,
pAnnotation.callback(),
pAnnotation.paramModificationMode(),
pAnnotation.info());
if (this.debug) {
System.out
.println(" ALDOperator():: adding parameter parameter <"
+ name + ">");
}
this.addParameterUnconditioned(parameterDescriptor);
this.parameterDescriptorsAnnotated.put( name, parameterDescriptor);
} else if (myType == Parameter.Type.SUPPLEMENTAL) {
// supplemental
ALDOpParameterDescriptor parameterDescriptor = new ALDOpParameterDescriptor(
name, Parameter.Direction.IN, true,
field.getType(), explanation, label, false,
field,
pAnnotation.dataIOOrder(),
pAnnotation.mode(), true,
pAnnotation.callback(),
pAnnotation.paramModificationMode(),
pAnnotation.info());
if (this.debug) {
System.out
.println(" ALDOperator():: adding supplemental parameter <"
+ name + ">");
}
this.addParameterUnconditioned(parameterDescriptor);
this.parameterDescriptorsAnnotated.put( name, parameterDescriptor);
}
}
}
}
myclass = myclass.getSuperclass();
} while (myclass != null);
}
/**
* This method does the actual work and needs to be implemented by every
* subclass.
*/
protected abstract void operate() throws ALDOperatorException,
ALDProcessingDAGException;
/**
* Get the name of this operator
*
* @return name of the operator
*/
public final String getName() {
return this.name;
}
/**
* Set the name of this operator
*
* @return name of the operator
*/
protected void setName( String name) {
this.name = name;
}
/** Return the <code>hidingMode</code> of this operator during execution
* via <code>runOp</code>.
*
* @return current hiding mode if operator is being executed
*/
public HidingMode getHidingMode() {
if ( this.opNode != null ) {
return this.opNode.getHidingMode();
} else {
return null;
}
}
/**
* Set the hiding mode of this operator during execution via <code>runOp</code>.
* <p>
* NOTE: A subsequent call of <code>runOp</code> will reset the <code>hdingMode</code>
* according to the argments of this method call.
*
* @param hidingMode
*/
public void setHidingMode( HidingMode hidingMode) {
if ( this.opNode != null) {
this.opNode.setHidden(hidingMode);
}
}
/**
* Get the version of this operator
*
* @return version of the operator
*/
public final String getVersion() {
if (this.versionProvider != null) {
return this.versionProvider.getVersion();
}
return "unknown";
}
/**
* Get a reference to the port hash access object.
*
* @return reference to the port hash access object
*/
public static ALDPortHashAccess getALDPortHashAccessKey() {
return portHashAccess;
}
// -------------------------------------------------------
// functions to parameters, their descriptors, and generic getter and setter
// methods
/**
* Add a parameter with the given descriptor to the operator.
*
* @param descr
* @throws ALDOperatorException of type <code>INVALID_PARAMETERNAME</code>if parameter already exists
*/
protected void addParameter( ALDOpParameterDescriptor descr) throws ALDOperatorException {
if ( hasParameter( descr.name) ) {
// operator has already a parameter with this name
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.INVALID_PARAMETERNAME,
name + " already defined");
}
if ( parameterDescriptorsAnnotated.containsKey(descr.name)) {
// operator has an annotated parameter with this name
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.INVALID_PARAMETERNAME,
name + " was an annotated parameter");
}
this.addParameterUnconditioned( descr);
}
/**
* Add a parameter with the given <code>name</code> to the operator.
* A parameter with this name needs to have been active previously and
* the descriptor of the last instance of a parameter with this name is (re)used.
*
* @param descr
* @throws ALDOperatorException of type <code>INVALID_PARAMETERNAME</code>if parameter already exists
* or was not known/active previously.
*/
protected void addParameter( String name) throws ALDOperatorException {
if ( hasParameter(name) ) {
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.INVALID_PARAMETERNAME,
name + " already defined");
}
if ( ! parameterDescriptorsInactive.containsKey(name)) {
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.INVALID_PARAMETERNAME,
name + " has no known descriptor");
}
this.addParameterUnconditioned( this.parameterDescriptorsInactive.get(name));
this.parameterDescriptorsInactive.remove(name);
}
/**
* Add a parameter descriptor to the operator without checks or updating of
* parameter hashes besides active parameters.
*
* @param descr
*/
protected void addParameterUnconditioned( ALDOpParameterDescriptor descr) {
this.parameterDescriptorsAll.put(descr.getName(), descr);
}
/**
* Remove the descriptor associated with <code>name</code>.
*
* @param name
* @throws ALDOperatorException
*/
protected void removeParameter( String name) throws ALDOperatorException {
if ( ! hasParameter(name) ) {
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.INVALID_PARAMETERNAME,
name + " is currently not defined");
}
ALDOpParameterDescriptor descr = this.getParameterDescriptor( name);
parameterDescriptorsInactive.put(name, descr);
parameterDescriptorsAll.remove(name);
}
/**
* Get the number of parameters
*
* @return number of parameters
*/
public final int getNumParameters() {
return this.parameterDescriptorsAll.size();
}
/**
* Get the names of in or inout parameters.
*
* @return names of in or inout parameters
*/
public final Collection<String> getInInoutNames() {
return getInInoutNames(null);
}
/**
* Get the names of in or inout parameters.
*
* @param useRequired
* If true return only required in or inout parameters, if false
* return only not required in or inout parameters. If
* <code>null</code> then return all in or inout parameters.
* @return names of in or inout parameters
*/
public final Collection<String> getInInoutNames(Boolean useRequired) {
LinkedList<String> names = new LinkedList<String>();
for (ALDOpParameterDescriptor descr : parameterDescriptorsAll.values()) {
if ((useRequired == null || useRequired == descr.required)
&& (!descr.supplemental)
&& (descr.direction == Parameter.Direction.IN || descr.direction == Parameter.Direction.INOUT)) {
names.add(descr.name);
}
}
return names;
}
/**
* Get the names of out or inout parameters
*
* @return names of out or inout parameters
*/
public final Collection<String> getOutInoutNames() {
LinkedList<String> names = new LinkedList<String>();
for (ALDOpParameterDescriptor descr : parameterDescriptorsAll.values()) {
if ((descr.direction == Parameter.Direction.OUT || descr.direction == Parameter.Direction.INOUT)) {
names.add(descr.name);
}
}
return names;
}
// ................
/**
* Get the names of in parameters.
*
* @param useRequired
* If true return only required in parameters, if false return
* only not required in parameters. If <code>null</code> then
* return all in parameters.
* @return names of in parameters
*/
public final Collection<String> getInNames(Boolean useRequired) {
LinkedList<String> names = new LinkedList<String>();
for (ALDOpParameterDescriptor descr : parameterDescriptorsAll.values()) {
if ((useRequired == null || useRequired == descr.required)
&& (descr.direction == Parameter.Direction.IN)) {
names.add(descr.name);
}
}
// Collections.sort(names, new Comparator<String>() {
// public int compare(String one, String two) {
// ALDOpParameterDescriptor descr1 = parameterDescriptorsAll
// .get(one);
// ALDOpParameterDescriptor descr2 = parameterDescriptorsAll
// .get(two);
//
// if (descr1.required && descr2.required)
// return one.compareTo(two);
// if (!descr1.required && !descr1.supplemental
// && !descr2.required && !descr2.supplemental)
// return one.compareTo(two);
// if (!descr1.required && descr1.supplemental && !descr2.required
// && descr2.supplemental)
// return one.compareTo(two);
// if (descr1.required && !descr2.required && !descr2.supplemental)
// return -1;
// if (!descr1.required && !descr1.supplemental
// && !descr2.required && descr2.supplemental)
// return -1;
// if (descr1.required && !descr2.required && descr2.supplemental)
// return -1;
// return 1;
// }
// });
return names;
}
/**
* Get the names of out parameters
*
* @return names of out parameters
*/
public final Collection<String> getOutNames() {
LinkedList<String> names = new LinkedList<String>();
for (ALDOpParameterDescriptor descr : parameterDescriptorsAll.values()) {
if ((descr.direction == Parameter.Direction.OUT)) {
names.add(descr.name);
}
}
Collections.sort(names);
return names;
}
/**
* Get the names of inout parameters.
*
* @param useRequired
* If true return only required inout parameters, if false return
* only not required inout parameters. If <code>null</code> then
* return all inout parameters.
* @return names of in parameters
*/
public final Collection<String> getInOutNames(Boolean useRequired) {
LinkedList<String> names = new LinkedList<String>();
for (ALDOpParameterDescriptor descr : parameterDescriptorsAll.values()) {
if ((useRequired == null || useRequired == descr.required)
&& (descr.direction == Parameter.Direction.INOUT)) {
names.add(descr.name);
}
}
return names;
}
/** Return true it this operator has at least one INOUT parameter
*
* @return
*/
public boolean hasInOutParameters() {
return getInOutNames(null).size() != 0;
}
// ................
/**
* Get the names of supplemental parameters
*
* @return names of supplemental parameters
*/
public final Collection<String> getSupplementalNames() {
LinkedList<String> names = new LinkedList<String>();
for (ALDOpParameterDescriptor descr : parameterDescriptorsAll.values()) {
if (descr.supplemental) {
names.add(descr.name);
}
}
return names;
}
/**
* Get the names of all parameters
*
* @return collection of all parameter names
*/
public final Collection<String> getParameterNames() {
return this.parameterDescriptorsAll.keySet();
}
/**
* Returns true if the operator has a currently active parameter of the given <code>name</code>,
* otherwise false.
*
* @param name
* @return true if parameter with name <code>name</code> exists
*/
public boolean hasParameter( String name) {
return this.parameterDescriptorsAll.containsKey(name);
}
/**
* Returns true if the operator has an annotated parameter <code>name</code>
* irrespective whether this parameter is currently active or not
*
* @param name
*/
public boolean isAnnotatedParameter( String name) {
return this.parameterDescriptorsAnnotated.containsKey( name);
}
/**
* Get the parameter descriptor for given name.
*
* @param name
* Name of the parameter to get the new value for
* @return descriptor value
* @throws ALDOperatorException of type <code>INVALID_PARAMETERNAME</code>if the parameter does not exist
*/
public final ALDOpParameterDescriptor getParameterDescriptor(String name)
throws ALDOperatorException {
if (!this.parameterDescriptorsAll.containsKey(name))
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.INVALID_PARAMETERNAME,
name + " is an unkown parameter");
return this.parameterDescriptorsAll.get(name);
}
/**
* Get the value of a parameter specified by name.
*
* @param name
* Name of the parameter to get the new value for
* @return value of the parameter
* @throws ALDOperatorException of type <code>INVALID_PARAMETERNAME</code>if the parameter does not exist
*/
public Object getParameter(String name) throws ALDOperatorException {
if (!this.parameterDescriptorsAll.containsKey(name))
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.INVALID_PARAMETERNAME,
name + " is an unkown parameter");
return getParameterDescriptor(name).getValue( genuineInstance);
// try {
// Field field = getParameterDescriptor(name).field;
// field.setAccessible(true);
// return field.get(genuineInstance);
// } catch (IllegalAccessException e) {
// throw new ALDOperatorException(
// ALDOperatorException.OperatorExceptionType.UNSPECIFIED_ERROR,
// "cannot get value for parameter <" + name + ">");
// }
}
/**
* Set the value of a parameter specified by name.
*
* @param name
* Name of the parameter to set a new value for
* @param value
* new value
* @throws ALDOperatorException of type <code><INVALID_PARAMETERNAME/code> if the
* parameter does not exist and of type <code>CALLBACK_ERROR</code>
* if the callback function may not be invoked or its invocations
* results in an exception
*/
public void setParameter(String name, Object value)
throws ALDOperatorException {
if (!this.parameterDescriptorsAll.containsKey(name))
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.INVALID_PARAMETERNAME,
name + " is an unkown parameter");
try {
getParameterDescriptor(name).setValue(value, genuineInstance);
// invoke callback function
String callback = getParameterDescriptor(name).getCallback();
if ( callback != null && ! callback.isEmpty()) {
java.lang.reflect.Method method;
method = genuineInstance.getClass().getDeclaredMethod( callback);
method.setAccessible(true);
method.invoke(genuineInstance);
}
} catch (Exception e) {
throw new ALDOperatorException(
ALDOperatorException.OperatorExceptionType.CALLBACK_ERROR,
name);
}
}
/**
* Init function for deserialized objects.
* <p>
* This function is called on an instance of this class being deserialized
* from file, prior to handing the instance over to the user. It takes care
* of a proper initialization of transient member variables as they are not
* initialized to the default values during deserialization.
* @return
*/
protected Object readResolve() {
this.reinitializeParameterDescriptors();
return this;
}
/**
* Reinitialize the field member of all parameter descriptors.
* This is required e.g. after de-serializing an operator object.
*/
@Deprecated
public void reinitializeParameterDescriptors() {
// this is a hash only find the first field with a name in the class hierarchy
LinkedList<String> pList =new LinkedList<String>();
Class<?> myclass = this.getClass();
do {
for (Field field : myclass.getDeclaredFields()) {
String name = field.getName();
Parameter pAnnotation = field.getAnnotation(Parameter.class);
// if field is annotated as parameter recreate descriptor
// and not already declared in a class downstream of the
// inheritance hierarchy
if (pAnnotation != null && ! pList.contains(name) ) {
pList.add( name);
ALDOpParameterDescriptor descr = parameterDescriptorsAll.get(name);
parameterDescriptorsAll.put( descr.name, descr.copy( field));
}
}
myclass = myclass.getSuperclass();
} while (myclass != null);
}
// ==========================
// runOp METHOD
/**
* A legal method to invoke the operator and handles everything necessary to
* protocol the processing history. This call has the same effect as
* <code>runOp( HidingMode.VISIBLE)</code>, i.e. runs the operator as visible in the history.
*
* @see ALDOperator#runOp(boolean)
*/
public final void runOp() throws ALDOperatorException,
ALDProcessingDAGException {
runOp(HidingMode.VISIBLE);
}
/**
* A legal method to invoke the operator and handles everything necessary to
* protocol the processing history. If <code>hidden</code> is true this call has the same effect as
* <code>runOp( HidingMode.HIDDEN)</code>, i.e. runs the operator as hidden.
* If <code>hidden</code> is false this call has the same effect as
* <code>runOp( HidingMode.VISIBLE)</code>, i.e. runs the operator as visible.
*
* @see ALDOperator#runOp(boolean)
*/
public final void runOp( boolean hidden) throws ALDOperatorException,
ALDProcessingDAGException {
if ( hidden ) {
runOp(HidingMode.HIDDEN);
} else {
runOp(HidingMode.VISIBLE);
}
}
/**
* A legal method to invoke the operator and handles everything necessary to
* protocol the processing history. Prior to calling <code>runOp</code>, all
* IN and INOUT parameters have to be set. When called <code>runOp</code>
* first validates the parameters. Validity requires for all operators, that
* all required IN and INOUT parameters to have non null values. In addition
* the implementation of an operator may impose further constrains defined
* by the method <code>validateCustom</code> which e.g. may restrict the
* interval of numerical parameters.
* <p>
* After successful validation the <code>operate</code> method is called to
* do the actuall processing of this operator. Upon return from
* <code>runOp</code>, resulting output data may be retrieved from the
* operator object.
* <p>
* <code>hidingMode</code> determines the visibility of this invocation in the processing history.
* If <code>hidingMode</code> equals <code>null</code> this is equivalent to
* <code>hidingMode</code> equal <code>VISIBLE</code> (for backward compatibility).
*
* @param hidingMode Determines the visibility of this invocation in the processing history
* @return
*/
public final void runOp(HidingMode hidingMode) throws ALDOperatorException,
ALDProcessingDAGException {
if ( this.debug) {
System.out.println("");
System.out.println("Start of runOp for operator " + this.name);
}
if (this.debug) {
this.print();
}
if ( hidingMode == null ) {
hidingMode = HidingMode.VISIBLE;
/*throw new ALDOperatorException(
OperatorExceptionType.VALIDATION_FAILED,
"ALDOperator.rnOp(): hidingMode is null in operator "
+ this.name);
*/
}
validate();
Stack<ALDOpNode> currentThreadsOpNodeStack = null;
ALDOpNode parentViaThread = null;
opNode = null;
ALDPort origPorts[] = null;
Collection<String> inInoutNames = null;
try {
// create an opNode for this operation in the DAG
// necessary also for progress events
opNode = new ALDOpNode(this, hidingMode);
// find parent opNode via opNode stack of this thread
currentThreadsOpNodeStack = findCurrentThreadsOpNodeStack();
parentViaThread = currentThreadsOpNodeStack.peek();
// handle progress events and obey hiding mode if inherited from parent
if ( parentViaThread != null) {
// register parent as a listener to this operators progress events
this.addOperatorExecutionProgressEventListener( parentViaThread.op);
// obey hiding mode if inherited from parent
if (parentViaThread.getHidingMode() == HidingMode.HIDDEN ||
parentViaThread.getHidingMode() == HidingMode.HIDE_CHILDREN)
opNode.setHidden(HidingMode.HIDDEN);
}
if ( constructionMode != ConstructioMode.NO_HISTORY ) {
// documentation in the processing history
if ( includeInHistory( hidingMode, parentViaThread.getHidingMode()) ) {
// obey hiding mode if inherited from parent
if (parentViaThread.getHidingMode() == HidingMode.HIDDEN ||
parentViaThread.getHidingMode() == HidingMode.HIDE_CHILDREN)
opNode.setHidden(HidingMode.HIDDEN);
// register this opNode to its parent opNode via thread parent
parentViaThread.addDirectChild(opNode);
opNode.setParent(parentViaThread);
if (this.debug) {
System.out
.println("ALDOperator::runOp adding direct registered child "
+ this.name
+ " ("
+ opNode
+ ")\n"
+ " to opNode "
+ parentViaThread
+ "("
+ parentViaThread.getName() + ")");
}
currentThreadsOpNodeStack.push(opNode);
// handle inputs
inInoutNames = getInInoutNames();
origPorts = new ALDPort[inInoutNames.size()];
// first we store the original dataport of inputs
int i = -1;
for (String inputName : inInoutNames) {
i++;
Object input = this.getParameter(inputName);
if (input != null) {
// register the input object
if (!portHashAccess.isRegistered(input))
portHashAccess.register(input);
// connect each input port of this opNode to the port
// of the input data the operator was supplied with
opNode.setInOrigin(i, input,
getParameterDescriptor(inputName).explanation);
origPorts[i] = portHashAccess.getHistoryLink(input);
} else {
opNode.setInOrigin(i, null,
getParameterDescriptor(inputName).explanation);
origPorts[i] = null;
}
}
// and now we can set the dataports of the data to the input ports
// (we have to do this in a second for-loop to handle multiple
// inputs with
// identical objects correctly)
i = -1;
for (String inputName : inInoutNames) {
i++;
Object input = this.getParameter(inputName);
if (input != null) {
// set the output port of the input to the input port of
// this opNode
portHashAccess
.setHistoryLink(input, opNode.getInputPort(i));
}
}
if (this.debug) {
System.out.println("");
System.out.println(" before operate");
for ( int i1 = 0 ; i1 < inInoutNames.size() ; i1++ ) {
i1++;
System.out.println(" port of " + i1 + "-th input "
+ opNode.getInputPort(i1) + " with origin "
+ opNode.getInputPort(i1).getOrigin());
}
}
} else {
if (this.debug) {
System.out
.println("ALDOperator::runOp do not add "
+ this.name
+ " to history");
}
}
}
if (this.debug)
System.out.println("Running operate...");
// do the work
operate();
if ( parentViaThread != null) {
// remove parent operator from progess event listener list
this.removeOperatorExecutionProgressEventListener( parentViaThread.op);
// remove reference to operator from opNode to allow garbage collection
if ( opNode != null ) {
opNode.op = null;
}
}
if (this.debug)
System.out.println("Running operate...done.");
if ( constructionMode != ConstructioMode.NO_HISTORY ) {
// documentation in the processing history
if ( includeInHistory( hidingMode, parentViaThread.getHidingMode() )) {
// handle output ports: connect output ports of opNode to the
// passing output parameters
Collection<String> outInoutNames = getOutInoutNames();
int i = -1;
for (String outputName : outInoutNames) {
i++;
Object output = this.getParameter(outputName);
// check if datum has already a port
if (output != null && !portHashAccess.isRegistered(output))
portHashAccess.register(output);
if (output != null) {
// register the output object to the history DB
if (!portHashAccess.isRegistered(output))
portHashAccess.register(output);
// connect each output port of this opNode to the output
// port
// its results (i.e. oututs) originate from
opNode.setOutOrigin(i, output,
getParameterDescriptor(outputName).explanation);
// store properties of output at the output port
if (output instanceof ALDData) {
Enumeration<String> keys = ((ALDData) output)
.getPropertyKeys();
while (keys.hasMoreElements()) {
String key = keys.nextElement();
opNode.getOutputPort(i).setProperty(key,
((ALDData) output).getProperty(key));
}
}
} else {
opNode.setOutOrigin(i, null,
getParameterDescriptor(outputName).explanation);
}
}
// restore port of inputs
i = -1;
for (String inputName : inInoutNames) {
i++;
if (origPorts[i] != null)
portHashAccess.setHistoryLink(this.getParameter(inputName),
origPorts[i]);
}
// handle outputs: connected leaving outputs parameters to output
// ports of this opNode
i = -1;
for (String outputName : outInoutNames) {
i++;
Object output = this.getParameter(outputName);
if (output != null) {
// set the output port of the output (i.e. result) of the
// operator
// to the output port of the opNode
portHashAccess.setHistoryLink(output,
opNode.getOutputPort(i));
}
}
if (this.debug) {
this.print();
for ( int i1 = 0 ; i1 < outInoutNames.size() ; i1++) {
i1++;
System.out.println(" port for " + i1 + "-th result "
+ opNode.getOutputPort(i1) + " with origin "
+ opNode.getOutputPort(i1).getOrigin());
if (opNode.getOutputPort(i1).getOrigin() != null)
opNode.getOutputPort(i1).getOrigin().print();
}
}
currentThreadsOpNodeStack.pop();
}
}
if ( this.debug) {
System.out.println(" End of runOp");
}
} finally {
// invalidate opNode
this.opNode = null;
}
}
// ===================================================================
// Helper for runOp()
/** Is this invocation to be included into the history?
*
*/
private boolean includeInHistory( HidingMode hidingMode, HidingMode parentHidingMode) {
return (constructionMode == ConstructioMode.COMPLETE_HISTORY) ||
((constructionMode == ConstructioMode.CONSIDER_HIDINGMODE) &&
(hidingMode != HidingMode.HIDDEN) &&
(parentHidingMode != HidingMode.HIDDEN) &&
(parentHidingMode != HidingMode.HIDE_CHILDREN));
}
/**
* Find the opNode stack for the current thread. Create a new one, if not
* existing
*
* @return opNode stack for the current thread
*/
private Stack<ALDOpNode> findCurrentThreadsOpNodeStack() {
Thread currentThread = Thread.currentThread();
Stack<ALDOpNode> currentThreadsOpNodeStack = opNodeStackHash
.get(currentThread);
if (currentThreadsOpNodeStack == null) {
try {
if (this.debug)
System.out
.println(" ALDOperator::runOp create opNodeStack for thread "
+ currentThread);
currentThreadsOpNodeStack = new Stack<ALDOpNode>();
opNodeStackHash.put(currentThread, currentThreadsOpNodeStack);
currentThreadsOpNodeStack.push(new ALDOpNode(new ALDToplevelOperator(), HidingMode.VISIBLE));
} catch (Exception e) {
e.printStackTrace();
}
}
if (this.debug)
System.out.println(" ALDOperator::runOp opNodeStack for thread "
+ currentThread + " found: " + currentThreadsOpNodeStack);
return currentThreadsOpNodeStack;
}
// ===================================================================
/**
* Validates the parameters and inputs of this operator. The generic part of
* this validation checks that each required parameter and input is set to a
* non-null value. The custom part of validation is operator depended and
* implemented via the method <code>validateCustom</code>. An
* ALDOperatorException is thrown if either validation fails.
*/
public final void validate() throws ALDOperatorException {
validateGeneric();
validateCustom();
}
/**
* Generic validation of the in and inout parameters of this operator.
* Validation succeeds if each required parameter and input is set to a
* non-null value or supplies a default value. An ALDOperatorException is
* thrown if validation fails.
*/
public final void validateGeneric() throws ALDOperatorException {
boolean gotError = false;
StringBuffer errString = new StringBuffer();
Collection<String> inInoutNames = getInInoutNames();
for (String inputName : inInoutNames) {
if (this.parameterDescriptorsAll.get(inputName).required
&& getParameter(inputName) == null) {
// && getParameterDescriptor(inputName).defaultValue == null) {
gotError = true;
errString.append ("\tRequired input parameter\" "
+ inputName + "\"" + " is null\n");
}
}
if ( gotError) {
System.out.println("ALDOperator.validateGeneric(): failed for operator "
+ this.name + "\n" +
errString);
throw new ALDOperatorException(
OperatorExceptionType.VALIDATION_FAILED,
"ALDOperator.validateGeneric(): failed for operator "
+ this.name + "\n" +
errString);
}
}
/** Returns all required IN an INOUT parameters which have a null value
*
* @return List of the parameter names
*/
@Deprecated
public List<String> getMissingRequiredInputs() {
return unconfiguredItems();
}
/** Returns all required IN an INOUT parameters which have a null value
*
* @return List of the parameter names
*/
@Override
public List<String> unconfiguredItems() {
LinkedList<String> missingParams = new LinkedList<String>();
try {
for ( String param : getInInoutNames(true)) {
if ( this.getParameter(param) == null)
missingParams.add( param);
}
}catch ( ALDOperatorException ex) {
// this should not happen !!
}
return missingParams;
}
/**
* Operator specific validation of parameters and inputs. Should be
* overridden when extending an operator to impose specific constraints.
*/
public void validateCustom() throws ALDOperatorException {
return;
}
@Override
public
boolean isConfigured() {
return (unconfiguredItems().size() == 0);
// return unconfiguredItems() == null;
}
// ===================================================================
// GETTER/SETTER for verbose parameter
/**
* Set the verbose state of this opertor.
*
* @param verbose
* New verbose state
*/
public void setVerbose(Boolean verbose) throws ALDOperatorException {
this.verbose = verbose;
}
/**
* Return the verbose state of this opertor.
*
* @return Current verbose state
*/
public Boolean getVerbose() throws ALDOperatorException {
return this.verbose;
}
// ===================================================================
// METHODS TO HANDLE HISTORY
/**
* Reads and set the history graph of the given object from file.
*
* @param obj
* Object for which the history is to be read.
* @param filename
* File from where the history is to be read.
* @see ALDPortHashAccess#readHistory(Object,String)
*/
public static void readHistory(Object obj, String filename) {
portHashAccess.readHistory(obj, filename);
}
/**
* Write the processing history if any to a graphml file. Equivalent to
* <code>writeHistory(obj, filename, ALDProcessingDAG.HistoryType.OPNODETYPE, false)</code>
*
* @param obj
* Object for which the history to write for.
* @param filename
* Filename to write the processing history into.
* For handling of extensions see
* {@link ALDPortHashAccess#writeHistory(Object, String, de.unihalle.informatik.Alida.operator.ALDProcessingDAG.HistoryType, boolean)}
*/
public static void writeHistory(Object obj, String filename)
throws ALDProcessingDAGException, ALDOperatorException {
writeHistory(obj, filename, ALDProcessingDAG.HistoryType.OPNODETYPE,
false);
}
/**
* Write the processing history if any to a graphml file. Equivalent to
* <code>writeHistory(obj, filename, historyType, false)</code>
*
* @param obj
* Object for which the history to write for.
* @param filename
* Filename to write the processing history into.
* For handling of extensions see
* {@link ALDPortHashAccess#writeHistory(Object, String, de.unihalle.informatik.Alida.operator.ALDProcessingDAG.HistoryType, boolean)}
* @param historyType
* Type/mode of the history.
*/
public static void writeHistory(Object obj, String filename,
ALDProcessingDAG.HistoryType historyType)
throws ALDProcessingDAGException, ALDOperatorException {
writeHistory(obj, filename, historyType, false);
}
/**
* Write the processing history if any to a graphml file.
*
* @param obj
* Object for which the history to write for.
* @param filename
* Filename to write the processing history into ingraphml/XML
* format.
* For handling of extensions see
* {@link ALDPortHashAccess#writeHistory(Object, String, de.unihalle.informatik.Alida.operator.ALDProcessingDAG.HistoryType, boolean)}
* @param historyType
* Type/mode of the history.
* @param ignoreHiding
* If true, hiding of opNodes is ignored.
*
* @see ALDPortHashAccess#writeHistory(Object,String,ALDProcessingDAG.HistoryType,boolean)
*/
public static void writeHistory(Object obj, String filename,
ALDProcessingDAG.HistoryType historyType, boolean ignoreHiding)
throws ALDProcessingDAGException, ALDOperatorException {
portHashAccess.writeHistory(obj, filename, historyType, ignoreHiding);
}
// ===================================================================
/**
* Write the parameter values to an xml file. Uses xstream for
* serialization.
*
* @param filename
* filename of the xml file to write to
*/
// public void writeParametersToXml(String filename) {
// try {
// PrintStream out = new PrintStream(filename);
//
// XStream xstream = new XStream(new DomDriver());
// String xml = xstream.toXML(new ALDParameterWrapper(this));
//
// out.println(xml);
// } catch (Exception e) {
// System.err.println(e);
// e.printStackTrace();
// }
//
// }
/**
* Parse the parameter values to an XmlObject. Uses xstream for
* serialization.
*
* @return serialization of the paraeter of this operator
*/
// public XmlObject parametersToXmlObject() throws XmlException {
//
// XStream xstream = new XStream(new DomDriver());
// String xml = xstream.toXML(new ALDParameterWrapper(this));
// XmlObject res = XmlObject.Factory.parse(xml);
//
// return res;
// }
/**
* Set the parameter values as read from an Xml file. The class and package
* name found in the Xml are compared to the operator to set the parameters
* to and are required to match.
*
* @param filename
* filename of the xml file to read from
* @return version string found in Xml file or null if Xml file could not be
* properly read or class or package name check failed
* @see ALDOperator#setParametersFromXml(String,String,String)
*/
// public String setParametersFromXml(String filename) {
// return setParametersFromXml(filename, getClass().getSimpleName(),
// getClass().getPackage().getName());
// }
/**
* Set the parameter values as read from an Xml file. The class and package
* name found in the Xml are compared to the <code>className</code> and
* <code>packageName</code> respectively. If one of these names is
* <code>null</code> any name in the Xml file is accepted.
*
* @param filename
* filename of the xml file to read from
* @param className
* class name expected in the Xml file or null
* @param packageName
* package name expected in the Xml file or null
* @return version string found in Xml file of null if Xml file could not be
* properly read or class or package name check failed
*/
// public String setParametersFromXml(String filename, String className,
// String packageName) {
//
// try {
// FileInputStream in = new FileInputStream(filename);
//
// XStream xstream = new XStream(new DomDriver());
//
// ALDParameterWrapper pw = (ALDParameterWrapper) (xstream.fromXML(in));
//
// if (className != null && !className.equals(pw.getClassName())) {
// System.err
// .println("ALDOperator::setParametersFromXml class name does not match, got "
// + pw.getClassName()
// + " but expected "
// + className);
// return null;
// }
//
// if (packageName != null && !packageName.equals(pw.getPackageName())) {
// System.err
// .println("ALDOperator::setParametersFromXml package name does not match, got "
// + pw.getPackageName()
// + " but expected "
// + packageName);
// return null;
// }
//
// // we have to set the values directly
// for (String pName : this.getParameterNames()) {
// try {
// setParameter(pName, pw.getParameteres().get(pName));
// } catch (ALDOperatorException e) {
// System.err
// .println("ALDOperator::setParametersFromXml Error: cannot get value for parameter "
// + pName);
// e.printStackTrace();
// }
// }
//
// return pw.getVersion();
//
// } catch (FileNotFoundException e) {
// System.err.println("ALDOperator::setParametersFromXml cannot open "
// + filename);
// return null;
// }
//
// }
/*
* Object serialization.
*/
/**
* Serializes the operator to an XML file.
* <p>
* Note that all member variables, i.e. the complete state of the object at
* the time of serialization is saved. Only transient members are ignored.
*
* @param filename
* File where to save the data.
*/
// public void serializeToXmlFile(String filename) {
// try {
// PrintStream out = new PrintStream(filename);
// XStream xstream = new XStream(new DomDriver());
// String xml = xstream.toXML(this);
// out.println(xml);
// } catch (Exception e) {
// System.err.println(e);
// e.printStackTrace();
// }
// }
/**
* Deserializes an operator state from the given file.
* <p>
* Only transient members are ignored.
*
* @param filename
* File from where to read the data.
*/
// public ALDOperator deserializeFromXmlFile(String filename) {
// try {
// FileInputStream in = new FileInputStream(filename);
// XStream xstream = new XStream(new DomDriver());
// return (ALDOperator) (xstream.fromXML(in));
// } catch (FileNotFoundException e) {
// System.err.println("ALDOperator::setParametersFromXml cannot open "
// + filename);
// }
// return null;
// }
// ===================================================================
// support for ALDOperators to act as event listeners
/**
* Adds a listener to this reporter.
* @param listener Listener to be added.
*/
public void addOperatorExecutionProgressEventListener(
ALDOperatorExecutionProgressEventListener listener) {
this.operatorExecutionEventlistenerList.add(ALDOperatorExecutionProgressEventListener.class, listener);
}
/**
* Removes a listener from this reporter.
* @param listener Listener to be removed.
*/
public void removeOperatorExecutionProgressEventListener(
ALDOperatorExecutionProgressEventListener listener) {
this.operatorExecutionEventlistenerList.remove(ALDOperatorExecutionProgressEventListener.class, listener);
}
/**
* Sends an event of changed execution progress to all registered listeners.
*
* @param ev Event to be send to all listeners.
*/
protected void fireOperatorExecutionProgressEvent(ALDOperatorExecutionProgressEvent ev){
// get list of listeners
Object[] listeners = this.operatorExecutionEventlistenerList.getListenerList();
/* listeners will always be non-null as getListenerList() is guaranteed
* to return a non-null array... */
// process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==ALDOperatorExecutionProgressEventListener.class) {
// lazily create the event:
try {
((ALDOperatorExecutionProgressEventListener)listeners[i+1]).handleOperatorExecutionProgressEvent(ev);
} catch (ALDWorkflowException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
// ===================================================================
// printing
/**
* Print some information of the current state this operator to System.out.
*/
public void print() {
print(System.out);
}
/**
* Print some information the current state of this operator to
* <code>outfile</code>.
*
* @param outfile
* Stream to print on
*/
public void print(PrintStream outfile) {
print(outfile, true);
}
/**
* Print information of the interface of this operator to System.out.
*/
public void printInterface() {
print(System.out, false);
}
/**
* Print information of the interface of this operator to
* <code>outfile</code>.
*
* @param outfile
* Stream to print on
*/
public void printInterface(PrintStream outfile) {
print(outfile, false);
}
/**
* Print information of the interface and values of this operator to
* <code>outfile</code>. If printValue is true, additional the current value
* is printed. This method note intended for public use.
*
* @param outfile
* Stream to print on
* @param printValue
*/
protected void print(PrintStream outfile, boolean printValue) {
outfile.println("Interface of ALDOperator: " + this.name);
// for ( String pName : getParameterNames() )
if (getInInoutNames(true).size() > 0)
System.out.println("Required input parameters");
for (ALDOpParameterDescriptor descr : sortedDescriptors( getInInoutNames(true)) )
descr.print(outfile, printValue ? this : null);
if (getInInoutNames(false).size() > 0)
System.out.println("Optional input parameters");
for (ALDOpParameterDescriptor descr : sortedDescriptors( getInInoutNames(false)) )
descr.print(outfile, printValue ? this : null);
if (getOutInoutNames().size() > 0)
System.out.println("Output parameters");
for (ALDOpParameterDescriptor descr : sortedDescriptors( getOutInoutNames()) )
descr.print(outfile, printValue ? this : null);
if (getSupplementalNames().size() > 0)
System.out.println("Supplemental parameters");
for (ALDOpParameterDescriptor descr : sortedDescriptors( getSupplementalNames()) )
descr.print(outfile, printValue ? this : null);
}
/**
* Returns a string containing printable information about this operator including parameters.
*/
public String toStringVerbose() {
StringBuffer buf = new StringBuffer();
for (String pName : getInInoutNames(true)) {
try {
buf.append(pName + "=" + getParameter(pName).toString() + "\n");
} catch (Exception e) {
}
}
return new String(buf);
}
// ================== helper function
/**
* Is this class allowed as Input and/or Output?
*/
boolean allowedClassForIO(Class<?> currentClass) {
if (this.debug) {
System.out
.println(" ALDOperator::allowedClassForIO for class "
+ currentClass.getName());
}
return !(currentClass == int.class || currentClass == byte.class
|| currentClass == short.class || currentClass == long.class
|| currentClass == float.class || currentClass == double.class
|| currentClass == boolean.class || currentClass == char.class);
}
/**
* Does any hash table contain the key, i.e. this field?
*/
protected boolean fieldContained(String key) {
return this.parameterDescriptorsAll.containsKey(key);
}
/** Return a collection of descriptors for the given parameter named
* which is sorted according to DataIoOrder.
*
* @param parameterNames
* @return
*/
private Collection<ALDOpParameterDescriptor> sortedDescriptors( Collection<String> parameterNames) {
LinkedList<ALDOpParameterDescriptor> descriptors = new LinkedList<ALDOpParameterDescriptor>();
for ( String pName : parameterNames) {
ALDOpParameterDescriptor descr = parameterDescriptorsAll.get(pName);
if ( descr != null) {
descriptors.add( descr);
}
}
java.util.Collections.sort( descriptors, new DescriptorComparator());
return descriptors;
}
//===================================================
private class DescriptorComparator implements Comparator<ALDParameterDescriptor> {
@Override
public int compare(ALDParameterDescriptor d1, ALDParameterDescriptor d2) {
if (d1 == null && d2 == null) {
return 0;
} else if (d1 == null) {
return 1;
} else if (d2 == null) {
return -1;
} else if ( d1.getDataIOOrder() == d2.getDataIOOrder() ) {
return 0;
} else if (d1.getDataIOOrder() > d2.getDataIOOrder() ) {
return 1;
} else {
return -1;
}
}
}
//===================================================
@Override
public void handleOperatorExecutionProgressEvent(
final ALDOperatorExecutionProgressEvent event) throws ALDWorkflowException {
// loop over all listeners and call their handleEvent method
final Object[] listeners = operatorExecutionEventlistenerList.getListenerList();
// create a new event with this operator to allow the workflow to find the node
final ALDOperatorExecutionProgressEvent newEvent =
new ALDOperatorExecutionProgressEvent( this, event.getEventMessage());
Thread eventThread;
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2) {
if (listeners[i]==ALDOperatorExecutionProgressEventListener.class) {
// Lazily create the event for each listener and invoke the listener in a new thread
final ALDOperatorExecutionProgressEventListener listener =
(ALDOperatorExecutionProgressEventListener) listeners[i+1];
eventThread = new Thread(){
@Override
public void run() {
try {
listener.handleOperatorExecutionProgressEvent( newEvent);
} catch (ALDWorkflowException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}};
eventThread.start();
}
}
}
}