/*
* WorkflowElement.java
*
* Version 1.0 Jul 11, 2008
*
* Copyright notice
*
* Brief description
*
* (c) 2008 by dbreuer
*/
package de.fhkoeln.cosima.workflow;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import de.fhkoeln.cosima.components.AbstractComponent;
/**
* This class represents a single workflow element within a workflow
* definition. The {@link WorkflowDefinition} is responsible for
* creating {@link WorkflowElement} instances and hold them through
* out the life cycle of a workflow definition. A single workflow
* element holds all information to find, allocate and invoke a
* service component. Furthermore it has information about what its
* position is in the overall workflow.
*
* @author Dirk Breuer
* @version 1.0 Jul 11, 2008
*/
public class WorkflowElement {
/**
* A simple inner class to represent a successor of the current
* element. The Successor class just wraps the URI of the successing
* element to have a better semantic.
*/
class Successor {
/**
* uri The URI of the successor. A URI of the same successor can
* never change during runtime.
*/
private final String uri;
/**
* The default constructor which sets the URI of the successor.
*
* @param uri
*/
public Successor(String uri) {
this.uri = uri;
}
/**
* @return The URI of this successor.
*/
public String getUri() {
return this.uri;
}
}
/**
* A simple wrapper class describing the input of an element. The
* input for an element be have one out of two characteristics:
*
* <ul>
* <li>
* The input is internal. Due to this the URI is a reference
* to some internal media storage system (like a media broker)
* </li>
* <li>
* The input is external. In this case the URI points to file
* or something else which is not stored in the system so far.
* This type of input is only acceptable for "producer" components.
* </li>
* </ul>
*/
public class Input {
private final String uri;
private final String data;
public Input(String uri, String data) {
this.uri = uri;
this.data = data;
}
public String getUri() {
return this.uri;
}
public String getData() {
return this.data;
}
/**
* TODO: This should be more explicit!
*
* @return If the input is external or not
*/
public boolean isExternal() {
return (data != null);
}
/**
* TODO: This should be more explicit!
*
* @return If the input is internal or not
*/
public boolean isInternal() {
return (data == null);
}
}
private String type;
private String uri;
private String description;
private String className;
private String namespace;
private Class<AbstractComponent> elementClass;
private List<Input> input;
private List<Map<String, String>> output;
private List<String> predecessors;
private List<Successor> successors;
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
public String getUri() {
return this.uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getClassName() {
return this.className;
}
public void setClassName(String className) {
this.className = className;
}
public String[] getInputKeys() {
String[] inputKeys = new String[this.input.size()];
int i = 0;
for (Input input : this.input) {
inputKeys[i] = input.getUri();
i++;
}
return inputKeys;
}
public List<Input> getInput() {
return this.input;
}
public void setInput(List<Map<String, String>> rawInput) {
this.input = new ArrayList<Input>();
Input input;
for (Map<String, String> singleRawInput : rawInput) {
if (singleRawInput.get("type").equalsIgnoreCase("external")) {
input = new Input(getUri() + "/input", singleRawInput.get("uri"));
} else {
input = new Input(singleRawInput.get("uri"), null);
}
this.input.add(input);
}
}
public List<Map<String, String>> getOutput() {
return this.output;
}
public void setOutput(List<Map<String, String>> output) {
this.output = output;
}
public List<String> getPredecessors() {
return this.predecessors;
}
public void setPredecessors(List<String> predecessors) {
this.predecessors = predecessors;
}
public List<Successor> getSuccessors() {
return this.successors;
}
public boolean hasSuccessors() {
if (this.successors != null && !this.successors.isEmpty()) {
return true;
} else {
return false;
}
}
public void setSuccessors(List<HashMap<String, String>> successors) {
this.successors = new ArrayList<Successor>();
for (Iterator<HashMap<String, String>> iterator = successors.iterator(); iterator
.hasNext();) {
Successor successor = new Successor(iterator.next().get("uri"));
this.successors.add(successor);
}
}
/**
* @return The AbstractComponent subclass representing this WorkflowElement instance.
* @throws ClassNotFoundException If the class could be found.
*/
@SuppressWarnings("unchecked")
@Deprecated
public Class<AbstractComponent> getElementClass()
throws ClassNotFoundException {
if (this.elementClass != null)
return this.elementClass;
try {
this.elementClass =
(Class<AbstractComponent>) Class.forName(getClassName());
} catch (ClassNotFoundException e) {
throw new ClassNotFoundException("Class " + getClassName()
+ " could not be found.");
}
return this.elementClass;
}
/**
* @return Either this element needs input or not.
*/
public boolean needsInput() {
return !input.isEmpty();
}
/**
* TODO: This is not so nice. Every element can only have one output
* port anyway. So we can either - store it into the workflow
* definition file or - make this implicit
*
* @return The URI of the output of this element
*/
public String getOutputUri() {
return output.get(0).get("uri");
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getNamespace() {
return namespace;
}
public void setDescription(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}