Workflow Configuration

Workflow Configuration

A workflow is wired up using an XML configuration language based on the dependency injection pattern (DI). Here is an example (not working, just an example!):

<workflow>
	<property name='genPath' value='/home/user/target'/>
	<property name='model' value='/home/user/model.xmi'/>
	<component class='org.eclipse.xtend.typesystem.emf.XmiReader'>
		<model value='${model}'/>
	</component>
	<component class='org.eclipse.xtend.typesystem.xpand2.Generator'>
		<outlet>
			<path value='${genPath}'/>
		</outlet>
	</component>
</workflow>

The root element is named workflow , then there are some property declarations followed by the declaration of two components.

Here is a tree representation of the resulting Java object graph:

Figure 1. Java Object Graph

Java Object Graph


The configuration language expresses four different concepts:

Borrowing from Apache Ant, we use the concept of properties. Properties can be declared anywhere in a workflow file. They will be available after declaration.

We have two different kinds of properties

  1. simple properties

  2. property files

Here is an example:

<workflow>
	<property name='baseDir' value='./'/>
	<property file='${baseDir}/my.properties'/>
	<component
		class='my.Comp'
		srcDir='${baseDir}'
		modelName='${model}'
		pathToModel='${pathToModel}'/>
</workflow>

First, there is a simple property baseDir with the value "." defined. This property can be used in any attributes in the workflow file. The second property statement imports a property file. Property files use the well-known Java properties file syntax. There is one feature we added: You can use previously declared properties inside the properties file.

Example:

model = myModel
pathToModel = ${baseDir}/${model}.xmi

This section describes how to implement workflow components, how they can communicate with each other and how the workflow execution can be controlled.

Workflow components have to communicate among each other. For example, if an XMIReader component reads a model that a constraint checker component wants to check, the model must be passed from the reader to the checker. The way this happens is as follows: In the invoke operation, a workflow component has access to the so-called workflow context . This context contains any number of named slots. In order to communicate, two components agree on a slot name, the first component puts an object into that slot and the second component takes it from there. Basically, slots are named variables global to the workflow. The slot names are configured from the workflow file. Here is an example:

<?xml version="1.0" encoding="windows-1252"?>
<workflow>
	<property file="workflow.properties"/>

	<component id="xmiParser"
		class="org.eclipse.xtend.typesystem.emf.XmiReader">
		<outputSlot value="model"/>
	</component>

	<component id="checker" class="datamodel.generator.Checker">
		<modelSlot value="model"/>
	</component>
</workflow>

As you can see, both these workflow components use the slot named model . Below is the (abbreviated) implementation of the XmiReader. It stores the model data structure into the workflow context in the slot whose name was configured in the workflow file.

public class XmiReader implements WorkflowComponent {

	private String outputSlot = null;

	public void setOutputSlot(String outputSlot) {
		this.outputSlot = outputSlot;
	}

	public void invoke(WorkflowContext ctx, ProgressMonitor monitor,
		Issues issues) {
		Object theModel = readModel();
		ctx.put( outputSlot, theModel );
	}

}

The checker component reads the model from that slot:

public class Checker implements WorkflowComponent {

	private String modelSlot;

	public final void setModelSlot( String ms ) {
		this.modelSlot = ms;
	}

	public final void invoke(WorkflowContext ctx,
		ProgressMonitor monitor, Issues issues) {

		Object model = ctx.get(modelSlot);
		check(model);
	}
}

There is an implicit way of controlling the workflow: if there are errors reported from any of the checkConfiguration operations of any workflow component, the workflow will not start running.

There is also an explicit way of terminating the execution of the workflow: if any invoke operation throws a WorkflowInterruptedException (a runtime exception) the workflow will terminate immediately.

If you have described your generator process in a workflow file, you might want to run it. There are different possibilities for doing so.