Using EMF to Model Your Build Process as a Workflow

There are a lot of tools available for building software, each with it’s own strengths and weaknesses. They all fundamentally do the same job – they convert source code into an application that can be delivered to a customer. Building an application generally involves multiple steps, and it seems natural that those steps could be described as a workflow. I will demonstrate how to model a build process using my EMF workflow model.

Let’s define a build process with more than one task.  We will compile a Java source file into a class file, jar the class file, and finally zip the jar file.  I started by creating domain specific extensions (Figure 1) to the EMF workflow model.  Remember that the workflow model is a framework and domain specific tasks are developed as extensions to the model.

Figure 1

Figure 1

I start by creating an Empty EMF Project and then a new Ecore Model.  Next, load the EMF workflow model as a resource of the ecore extension model.  Create three new classes: JavaCompiler, JavaJar, and ZipFile each extending WorkflowUnitOfWork. Finally, create non-containment references to WorkflowParameter as follows:

JavaCompiler

  • classNameParameter
  • classpathParameter
  • workingDirectoryParameter

JavaJar

  • classNameParameter
  • workingDirectoryParameter
  • outputFileParameter

ZipFile

  • workingDirectoryParameter
  • inputFileParameter
  • outputFileParameter

These con-containment references are created for convenience which will be apparent when the workflow is constructed.  Now that the model extensions have been defined, the model and edit code can be generated.  Remember to set Child Creation Extenders and Extensible Provider Factory to true.

EditProperties

The last piece of the development is to provide the executable functionality of each of the tasks.  Here are the implementations of each of the run() functions:

JavaCompiler

@Override
public WorkflowState run(WorkflowContext context) throws WorkflowRuntimeException
{
	File workingDirectory = new File((String) workingDirectoryParameter.getValue(context));
	String[] command = {"javac", "-cp", (String) classpathParameter.getValue(context), (String) classNameParameter.getValue(context) + ".java"};
	int rc = 0;
	
	try
	{
		logDebug(context, "Executing command: javac -cp " + command[2] + " " + command[3]);
		Process process = Runtime.getRuntime().exec(command, null, workingDirectory);
		rc = process.waitFor();
	}
	catch (Exception e)
	{
		logException(context, e);
		return StateFactory.eINSTANCE.createWorkflowErrorState();
	}
	
	return rc == 0 ? StateFactory.eINSTANCE.createWorkflowSuccessState() : StateFactory.eINSTANCE.createWorkflowFailedState();
}

JavaJar

@Override
public WorkflowState run(WorkflowContext context) throws WorkflowRuntimeException
{
	File workingDirectory = new File((String) workingDirectoryParameter.getValue(context));
	String[] command = {"jar", "-cf", (String) outputFileParameter.getValue(context), (String) classNameParameter.getValue(context) + ".class"};
	int rc = 0;
	
	try
	{
		logDebug(context, "Executing command: jar -cf " + command[2] + " " + command[3]);
		Process process = Runtime.getRuntime().exec(command, null, workingDirectory);
		rc = process.waitFor();
	}
	catch (Exception e)
	{
		logException(context, e);
		return StateFactory.eINSTANCE.createWorkflowErrorState();
	}
	
	return rc == 0 ? StateFactory.eINSTANCE.createWorkflowSuccessState() : StateFactory.eINSTANCE.createWorkflowFailedState();
}

ZipFile

@Override
public WorkflowState run(WorkflowContext context) throws WorkflowRuntimeException
{
	File workingDirectory = new File((String) workingDirectoryParameter.getValue(context));
	String[] command = {"zip", (String) outputFileParameter.getValue(context), (String) inputFileParameter.getValue(context)};
	int rc = 0;
	
	try
	{
		logDebug(context, "Executing command: zip " + command[1] + " " + command[2]);
		Process process = Runtime.getRuntime().exec(command, null, workingDirectory);
		rc = process.waitFor();
	}
	catch (Exception e)
	{
		logException(context, e);
		return StateFactory.eINSTANCE.createWorkflowErrorState();
	}
		
	return rc == 0 ? StateFactory.eINSTANCE.createWorkflowSuccessState() : StateFactory.eINSTANCE.createWorkflowFailedState();
}

Now that we have domain specific tasks that can do actual work, we can assemble them into a build process / workflow. Launch the runtime workbench, create a new project, and create a new ecore model. Here are the results:

Build Workflow

After the build workflow has been created, we can create a runtime model that contains the parameter values for the build.

Build Runtime

I’ve set up this example runtime to build Hello.java in the working directory /tmp/build. When you run the workflow, it will generate Hello.class, hello.jar, and finally hello.zip. You may have noticed that not all modeled parameters have values in the runtime model. I created parameter connections in the workflow model for those parameters that share values. For this example, I also created a second runtime to build Bye.java using the same build process. This complete example is available in CVS at dev.eclipse.org /cvsroot/modeling/org.eclipse.emf/org.eclipse.emf.mwe/examples.

There is a screencast available until I need the disk space.

About these ads

3 thoughts on “Using EMF to Model Your Build Process as a Workflow

  1. Thanks for this example – and more kudos for making a screencast! I haven’t looked at the workflow model before and I’m now thinking of where I could use it :) Can you run the workflow headless?

    • Yes, you certainly can run the workflow headless. The only runtime requirements are EMF, and EMF Transaction. In the past, you could use EMF without org.eclipse.core.runtime, but I’m not sure if that’s still true. Of the EMF workflow bundles, all you really need is the .core bundle. Please be aware that this code has not been officially released and is subject to API changes on a whim – for example, I’m thinking about removing the containment reference from WorkflowComponent to WorkflowParameter. Any feedback you have on the usability of the model would be appreciated.

  2. I’m just thinking about workflow-like stuff and your work interests me – event though I do not yet start to think about it seriously :-). I may follow up your workflow series

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s