BPEL ModelLast modified on December 7, 2005
This document attempts to explain many of the design decisions present in the BPEL model, as well as where to locate key code and how to make changes.
The model will track the evolving OASIS WS-BPEL specification as it approaches 2.0. Current support of the model is at the 1.1 level plus the following resolved OASIS issues:
- Issue 13 (Expressions and Queries in Elements instead of Attributes)
- Issue 34 (No Dependency on WS-A)
- Issue 37 and 202 (Add "join" value to initiate attribute of Correlation)
- Issue 68 (Catch syntax broken)
Most of the BPEL model objects, with some exceptions, are located in the org.eclipse.bpel.model package.
Message properties and property aliases are located in org.eclipse.bpel.model.messageproperties.
Partner link types and roles are located in org.eclipse.bpel.model.partnerlinktype.
Reading and Writing BPEL Files
Most of the conversion from the .bpel file into an EMF model occurs in org.eclipse.bpel.core.resources.BPELReader. This class is instantiated by BPELResourceImpl, which in turn is created by BPELResourceFactoryImpl, which is registered in the plugin.xml file as the extension parser for .bpel files.
BPELReader has methods for translating each of the BPEL elements and attributes from DOM objects into EMF objects. At the moment, the DOM objects are discarded by the reader once the EMF objects are created, and they are recreated by the BPELWriter. However, this has the disadvantage of losing any user formatting and comments in the source file upon save. The model should use the same approach as the WSDL model in that the DOM tree would be kept in memory in parallel to the EMF model, and the two kept in sync.
Here is a snippet of code which will load a BPEL process from an IFile:
// New resource set, or add to an existing one ResourceSet resourceSet = new ResourceSetImpl(); // In non-workbench cases, find another way to create your URI URI uri = URI.createPlatformResourceURI(file.getFullPath().toString()); // Use getResource(), not createResource() Resource resource = resourceSet.getResource(uri, true); // There's only one thing in the list Process process = (Process)resource.getContents().get(0);
To save the process, call resource.save().
BPEL is an extensible language. The specification builds upon the extensibility support in WSDL. Many BPEL elements are subtypes of ExtensibleElement. Such elements may contain attributes and elements which are not defined in the BPEL specification. The reader must therefore be extensible. When it encounters an unknown attribute or element (an ExtensibilityElement), it should query an appropriate deserializer to reconstitute the EMF model object. Likewise, the writer should query an appropriate serializer to reconstitute the DOM element from the EMF model object.
Extenders of the BPEL model should register a BPELExtensionSerializer and BPELExtensionDeserializer for each of their ExtensibilityElements. The BPELExtensionRegistry holds onto these registrations, and they may be made during the execution of your EMF Package�s init() method. If the reader or writer encounters an ExtensibilityElement for which a serializer or deserializer is not found in the registry, the default implementations BPELUnknownExtensionSerializer and BPELUnknownExtensionDeserializer will be used.
Support for non-Workbench scenarios
The BPEL Model, while based on EMF, is intended to be functional both in an Eclipse Workbench (either a full Workbench or headless scenario) and independently of an Eclipse Workbench. The latter scenario makes the model suitable to scenarios such as command-line validation, or use in a Java-based runtime which is not based on Eclipse.
To facilitate the non-Workbench scenario, the plug-in class org.eclipse.bpel.core.BPELPlugin extends EMFPlugin. EMFPlugin is designed for exactly this scenario. Also see org.eclipse.bpel.core.terms.BPELTerms, which has special logic to handle both the Workbench and non-Workbench cases.
Committers must ensure that they do not introduce any code which relies on the Workbench running. Platform.isRunning() is a safe test that can be performed to determine whether or not the Workbench is running.
org.eclipse.xsd is the Eclipse XSD model, referenced by BPEL Variables and other locations.
org.eclipse.wst.wsdl and org.wsdl4j are the WSDL model, referenced in a number of places from BPEL.
org.eclipse.emf.* is the EMF runtime.
org.apache.xerces is the Xerces parser from Apache. The BPEL reader and writer use this to turn the XML into model elements and vice versa.
org.eclipse.core.runtime is used by all plug-ins in an Eclipse environment.
org.eclipse.core.resources is used only in BPELPlugin. In general, the model should not use IResources or any other functionality from this plug-in due to the required support for non-Workbench scenarios.
EMF supports object references in such a way that it is not necessary to load all referenced files up front. To this end, a particular EMF object may be a Proxy, which is resolved when a getter method returns a particular object.
As an example, consider a BPEL Variable, which references an XSD type (as represented by org.eclipse.xsd.XSDTypeDefinition). The Variable API getType() is used to access this type. However, until getType() is called, the referenced XSD file is not loaded, and the XSDTypeDefinition is only a proxy. The auto-generated logic in getType() causes the proxy to be resolved, causing the XSD file to be loaded and the proxy replaced with a real XSDTypeDefinition, which is returned to the caller.
In package org.eclipse.bpel.model.proxy, find proxy classes for all referenced object types. These proxies each have a unique URI encoding which contains all of the information necessary to resolve the proxy.
Notice also that there are proxy classes for object references within the BPEL file, for references such as Variables. When deserializing a BPEL file, when the reader encounters a variable reference (in a Receive, for example), it should create a VariableProxy to put in the Receive. This proxy would be resolved to the appropriate Variable when getVariable() is called. However, it doesn�t work like that today. Instead, Process.getPostLoadRunnables() provides access to a list of runnables which are executed after the first reading pass. Today, classes such as VariableProxy are only used when the post-load runnable fails to find a particular referenced object.
- Registration of serializers and deserializers for extensibility elements may be registered with the BPELExtensionRegistry. This registration should be made in the package init() method of the plugin containing your serializer and deserializer, and these classes must implement BPELExtensionSerializer and BPELExtensionDeserializer, respectively.
- BPEL provides for an extensible ServiceReference scheme, in the same way as it allows language extensibility for expressions and queries. To serialize and deserialize the service references, implement ServiceReferenceDeserializer and ServiceReferenceSerializer, and make your registrations in your package init() method, calling BPELExtensionRegistry.registryServiceReference[De]serializer().
- Depending on how one defines a schema for extensibility elements, order of elements and attributes may be important. To do this, register in the plug-in extension point org.eclipse.bpel.model.extensions_reordering, and provide a class which implements IExtensibilityElementListHandler. This class will be called upon serialization and you will be given the opportunity to rearrange the list of extensibility elements for a given BPEL element. Note that this currently only works in a Workbench environment, as it relies on the plug-in extension point.
Tolerance for incomplete files
The BPEL model, generally speaking, is tolerant of BPEL files which are incomplete (and hence, technically, syntactically invalid), as long as they are well-formed XML and have a process at the document root. This is necessary because, from an editing point of view, it is clearly unreasonable to force the user to specify all mandatory attributes and elements before saving for the first time � it is an iterative process. The model must then save and load this incomplete file, even though it may not pass syntactic validation.
Making Changes to the Model
The model classes are generated from the EMF Ecore models located in the org.eclipse.bpel.model/src/model folder.
To set your workspace up to regenerate the model, you need to do the following:
- Have org.eclipse.bpel.model in loaded in your workspace from CVS
- File->Import->External Plug-ins and Fragments. Select org.eclipse.xsd, org.eclipse.emf.ecore and org.eclipse.wst.wsdl and import them into your workspace. These plug-ins need to be in the workspace so their ecore and genmodel files can be loacted by EMF.
If you double-click on one of the ecore files (such as bpel.ecore), you can add or remove model objects or properties. After making changes, save the ecore file and close it. Double-click to open the corresponding genmodel file. Right-click on the root node in the editor, and Generate Model Code. EMF will generate all of the necessary Java code.
Please note that any methods in the model objects which do not contain the @generated javadoc tag will be left alone. (As a convention, we usually mark hand-modified methods with @customized for clarity).
After doing this, please open the class CorrelationPattern and replace
public static final CorrelationPattern OUTIN_LITERAL = new CorrelationPattern(OUTIN, "outin");with
public static final CorrelationPattern OUTIN_LITERAL = new CorrelationPattern(OUTIN, "out-in");