Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

JWT Transformations (up to JWT 1.2.0 included)

Introducing JWT Transformations

Terminology

In this page, transformation stands for a transformation of a workflow from one format to another.

Since JWT workflow file type is the core of this project, the term import will stand for transformations that produce a JWT workflow file, and the term export will stand for transformations that produce a description of a workflow into another format, from JWT.

Aim

The aim of transformations is to make possible to use workflows designed with JWT in another contexts, and vice versa, all the more since the JWT workflow (file) format is on its own not a standard used by other workflow editors or engines. In fact, transformations are the basis of compatibility, and what makes of JWT a bridge between various tools and platforms, not only in the workflow domain but also elsewhere like e.g. SOA, or conceptual diagrams, allowing to use them all together.

Use Cases

Here are a few use cases of transformations :

  • description : import workflow description from another format (ex. BPMN to JWT transformation)
  • execution : export JWT workflows to an executable format, so they can be executed on a runtime that supports the format (ex. JWT to XPDL or jPDL transformations)
  • integration : use JWT tools along with other, complementary tools and platforms (ex. JWT to STP-IM)
  • migration : export JWT workflows to use them elsewhere
  • migration : import other workflow description file types not to discourage users that would migrate from external workflow editor to JWT
  • simulation : Transformations will also be used when we will implement a function that will deploy the JWT workflow on an embedded workflow engine only with a few clicks (upcoming in JWT Desktop, using Bonita engine)

How to use it

You need a JWT WE with the jwt-transformations-base plugin installed as well as any transformation plugin you want to use, for example jwt-bpmn or jwt-xpdl.

This makes available "Export" and "Import" buttons in the JWT WE toolbar, and under those any transformations provided by the installed plugins. To use for example the XPDL transformation, choose Export, and there choose JWT2XPDL in the dialog box ; fill in the output file name, and start the transformation by clicking on OK.

Alternatively, do File->Export from the main toolbar after opening the workflow model in eclipse. Type "Export process" in the filter text area, and then choose Java Workflow Tooling->Export process into another metamodel. Select one of the transformations: XPDL, STP-IM, BPMN according to the format you want to export in.

Transformations Gallery

Here are the file types that are already compatible, or that will soon be, with JWT

XPDL

XPDL is an XML-based, executable workflow language standardized by the WfMC.

Only export JWT to XPDL is available. But there are some limitations. Scarbo provides an enriched version of it.

This transformation uses XSLT.

Produces executable XPDL that has been validated on the Bonita 4 workflow engine.

See the JWT2XPDL documentation for extensive specifications.

jPDL

jPDL is jBoss jBPM's XML-based executable workflow language.

This transformation uses XSLT.

Thoughts

Since jPDL is not an EMF-based metamodel, there are 3 main ways to process this transformation:

  • Use XSLT
    • pros: XSLT is standard, not IP issue, easy to integrate
    • cons: XSLT not really extensible, customizable, maintainable...
  • Use JWT model API and a DOM/SAX API for output
    • pros: DOM or SAX API are embedded in Java, no IP issue
    • cons: DOM/SAX not so fun to use
  • Use JWT model API and jpdl Java API (package org.jbpm.jpdl)
    • pros: full Java, maybe easier to use
    • cons: code from jBpm API => IP issues for integration into JWT, a lot of deps...

Here are some mappings:

  • jwt:Activity(Name) -> process-definition(name)
  • InitialNode -> start-state
  • (automatic) Action (without role) -> node
    • Application -> action (same a Bonita hook)
  • (human) Action (with role) -> task
  • role -> swimlane


BPMN

BPMN is a business process representation format standardized by the OMG. Here we use the (EMF-based) XML format defined by STP's BPMN editor.

We have two different transformations:

  • one from JWT to BPMN, allowing to export JWT workflow models to
  • and one the other way round (from BPMN to JWT).

These transformations use ATL.


STP-IM

STP-IM is an SOA intermediate model by the SOA Tools Project dedicated to help bridging SOA-minded problematics and concerns.

We have a transformation from JWT to the STP Intermediate Model (STP-IM). This intermediate model allows the further development of JWT in SCA, BPMN, BPEL, etc.

This transformation uses ATL.



For developers

Architecture

To facilitate the add of a transformation, we chose to use the extensions-based Eclipse plug-in architecture, as described by the picture:

JWT Transfo archi.jpg

When the plugin is started

Activator is called on the generic transformation plug-in. This activation calls the ProcessServiceMember.process method, which will get all informations to get informations from the extension point and add it to a registry that will be use later. (This mechanism is done as explained at http://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html) This part of the code is used only once, at activation.

When a transformation is called

The method that handle the call just has to call TransformationsRegister.getInstance.getTransformation(transformationName_defined_in_extension).transform It is aimed to have one or several generic handlers that would be defined in generic plug-in, to unify transformations that have the same goal (export to model, export to execution platform compliant type...)

Extensibility

If necessary, it is easy to add some metadata to a transformation. To do it, just add an attribute to the extension point, add it as an attribute to the transformationService class, and set it when you load the extension is ProcessServiceRegistry.


How do I add a transformation to JWT?

Nothing is easier!

Of course, it requires org.eclipse.jwt.transformation.base plug-in.

You just have to implement a class that extends TransformationService, with its method transform (that will be called to apply the transformation). Then, you create an extension for the extension point org.eclipse.jwt.transformations that defines a name for your transformation and the class that implements the transformation (extending TransformationService), and more other optional fields.

Take a look at the extension of StubTransformation from JWT repository to give you a concrete example.


XSLT Based Transformation

XSL transformations allow to transform a JWT workflow model (and its model extensions) from its own (EMF based) XML representation to any kind of XML or text, by writing an XSL template. It is a good all-around choice if you want to get XML or simple files (csv...) out of your workflow model.

  • For XSL transformations, there is a tool plugin called jwt-transformations-xslt-tools which contains some stuff to call XSL transformations and some extension classes that can be used to "introspect" the JWT XML model file.
  • These transformations use Xalan 2.7.1 (for XSLT) and (Xerces 2.9) for XPath processors (dependency taken from Orbit)
  • Important: Any plugin that wishes to add an extension class have to add in its MANIFEST.MF this line Eclipse-RegisterBundle: org.apache.xalan


ATL Based Transformation

ATL transformations allow to transform the JWT workflow model (and its model extensions) from its EMF model to another EMF model, by writing a model-to model transformation in the ATL language. It is less common and more complex, but a powerful choice, especially if you already have an EMF version (.ecore file) of your target model. Note that if you don't have it, you have to find or write an ATL compatible version of your model first, for instance with the XML2Ecore tool if your target model is in XML.

  • there is no JWT plugin that gathers useful ATL stuff for JWT yet, but you can have a look in existing ATL-based transformation plugins (jwt-bpmn, jwt-stpim...), or even copy-paste one of them as a basis.
  • an ATL based transformation plugin requires the org.eclipse.m2m.atl.engine plugin.
  • How to write an ATL transformation (.atl file) ? Have a look at the ATL language reference at ATL/User_Guide as well as at existing ATL-based transformation plugins (jwt-bpmn, jwt-stpim...)
  • to compile the .atl file to its .asm executable couterpart, give to your project the ATL nature (right-click on project > Add ATL Nature). This gives it the ATL Builder, which will automatically compile all .atl files of your project.
    • However you may not want to keep the ATL nature all the time (and remove it, by right-click on project > Remove ATL Nature), because it inclines to regenerate all .asm files a bit too often, which is meddlesome notably when working with source versioning.

How to call an ATL transformation in java (e.g. in a transformation plugin)

Here is a piece of code (from the jwt-bpmn plugin) that can be used to run ATL transformations in Java. Linked in ATL Howtos

/**
 * This sample is shared under WTFPL
 * http://sam.zoy.org/wtfpl/
 */
package org.eclipse.jwt.transformations.bpmn;
 
import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
 
import org.eclipse.emf.common.util.URI;
import org.eclipse.m2m.atl.drivers.emf4atl.ASMEMFModel;
import org.eclipse.m2m.atl.engine.AtlEMFModelHandler;
import org.eclipse.m2m.atl.engine.AtlLauncher;
import org.eclipse.m2m.atl.engine.AtlModelHandler;
 
/**
 * Should implement a template method pattern...
 */
class ATLTransformation {
 
	private static ATLTransformation instance = null;
 
	private final static String resourcePath = "/org.eclipse.jwt.transformations.bpmn/src/org/eclipse/jwt/transformations/bpmn/resources/";
 
	private AtlEMFModelHandler modelHandler;
	private URI XML_ModelResource;
	private URI JWT_ModelResource;
	private URI BPMN_ModelResource;
	private URL JWT2BPMN_TransfoResource;
	private URL BPMN2JWT_TransfoResource;
	private ASMEMFModel xmlMetamodel;
	private ASMEMFModel jwtMetamodel;
	private ASMEMFModel bpmnMetamodel;
 
	private URL JWT2BPMN_Pool_TransfoResource;
 
	private URL JWT2BPMN_Sub_TransfoResource;
 
	static public ATLTransformation getInstance() {
		if (instance == null)
			instance = new ATLTransformation();
		return instance;
	}
 
 
	private void createResources() {
		modelHandler = (AtlEMFModelHandler) AtlModelHandler
				.getDefault(AtlModelHandler.AMH_EMF);
		XML_ModelResource = URI.createPlatformPluginURI(resourcePath + "XML.ecore", false);
		JWT_ModelResource = URI.createPlatformPluginURI(resourcePath + "jwt.ecore", false);
		BPMN_ModelResource = URI.createPlatformPluginURI(resourcePath + "bpmn.ecore", false);		
 
		JWT2BPMN_TransfoResource = ATLTransformation.class.getResource("resources/JWT2BPMN.asm");
		JWT2BPMN_Pool_TransfoResource = ATLTransformation.class.getResource("resources/Jwt2BpmnAllInPool.asm");
		JWT2BPMN_Sub_TransfoResource = ATLTransformation.class.getResource("resources/Jwt2BpmnAllInSub.asm");
		BPMN2JWT_TransfoResource = ATLTransformation.class.getResource("resources/BPMN2JWT.asm");
	}	
 
	private void initMetamodels(Map<String, Object> models) {
		xmlMetamodel = (ASMEMFModel) modelHandler.loadModel(
				"XML", modelHandler.getMof(), XML_ModelResource);
		jwtMetamodel = (ASMEMFModel) modelHandler.loadModel(
				"jwt", modelHandler.getMof(), JWT_ModelResource);
		bpmnMetamodel = (ASMEMFModel) modelHandler.loadModel(
				"bpmn", modelHandler.getMof(), BPMN_ModelResource);
 
		models.put("XML", xmlMetamodel);
		models.put("jwt", jwtMetamodel);
		models.put("bpmn", bpmnMetamodel);
	}	
 
 
	public void jwt2bpmn(String inFilePath, String outFilePath) {
		try {
			Map<String, Object> models = new HashMap<String, Object>();			
			createResources();			
			initMetamodels(models);
 
			// get/create models
			ASMEMFModel jwtInputModel = (ASMEMFModel) modelHandler.loadModel("IN", jwtMetamodel, URI.createFileURI(inFilePath));
			ASMEMFModel bpmnOutputModel = (ASMEMFModel) modelHandler.newModel("OUT", URI.createFileURI(outFilePath).toFileString(), bpmnMetamodel);
			// load models
			models.put("IN", jwtInputModel);
			models.put("OUT", bpmnOutputModel);
			// launch
			AtlLauncher.getDefault().launch(this.JWT2BPMN_Pool_TransfoResource,
					Collections.EMPTY_MAP, models, Collections.EMPTY_MAP,
					Collections.EMPTY_LIST, Collections.EMPTY_MAP);
 
			modelHandler.saveModel(bpmnOutputModel, outFilePath, false);
			dispose(models);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	public void bpmn2jwt(String inFilePath, String outFilePath) {
		try {
			Map<String, Object> models = new HashMap<String, Object>();			
			createResources();			
			initMetamodels(models);
 
			// get/create models
			ASMEMFModel bpmnInputModel = (ASMEMFModel) modelHandler.loadModel("IN", bpmnMetamodel, URI.createFileURI(inFilePath));
			ASMEMFModel jwtOutputModel = (ASMEMFModel) modelHandler.newModel("OUT", URI.createFileURI(outFilePath).toString(), jwtMetamodel);
			// load models
			models.put("IN", bpmnInputModel);
			models.put("OUT", jwtOutputModel);		
			// launch
			AtlLauncher.getDefault().launch(this.BPMN2JWT_TransfoResource,
					Collections.EMPTY_MAP, models, Collections.EMPTY_MAP,
					Collections.EMPTY_LIST, Collections.EMPTY_MAP);
 
			modelHandler.saveModel(jwtOutputModel, outFilePath, false);
			dispose(models);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
 
	private void dispose(Map<String, Object> models) {
		for (Object model : models.values())
			((ASMEMFModel)model).dispose();
	}	
}

As you can see, ATL transformations can be called in 4 steps:

  • Add metamodel description to ATL
  • Add models to ATL (specifying the metamodel that is used to describe them)
  • Call the transformation (specifying the resource that describes the transformation and input and output files)

Remark: You can see that this piece of code loads directly ATL compiled files (*.asm) instead of ATL files. We could easily generate asm files from ATL at runtime using ATLCompiler class; however, it is better to assume that we have the compiled version of transformations. This way, we avoid compiling each time we call a transformation, and make the transformation faster.

Back to the top