This document details Servus' API. First, we give an overview of the plugins implemented by Servus, and then we detail the important abstractions of the plugins.
Servus plugins use the base package org.eclipse.emf.servus. We will omit this part of the package names for brevity. The exception is the core package, which has exactly this signature, and will be therefore referenced by Core. This list contains the plugins already created in the CVS. Additional plugins must be created to complete the tool support, such as additional transformations and integration with the Eclipse IDE to drive the transformations.
- metamodel - defines the Servus meta-model as an Ecore model.
- Core - defines the API for all transformations and the data structures used by the transformation, as well as utility classes. Also defines extension points to be implemented by transformations.
- app - implements command line applications to run the transformations.
- app.tests - implements simple tests to drive the command line applications.
- samples - a container for sample artifacts used to test the applications. Contains WSDL documents, Servus models, Ecore models and so on.
- rule - a simple rule framework that allows transformations to be defined as AST traversals and typed rules.
The WSDLv1 Plugins depend on the wsdl4j library (javax.wsdl version 1.6.2), which can be imported as an orbit bundle.
- wsdlv1 - implements the extension points related to WSDL version 1, which defines transformations between WSDLv1 and Servus models.
- wsdlv1.wsdl2servus - uses the rule framework to implement the transformation from WSDL to Servus.
- wsdlv1.servus2wsdl - uses the rule framework to implement the transformation from Servus to WSDL.
- jaxws - implements the extension point related to JAX-WS, i.e,. implements a Servus to JAX-WS-based Java source code.
- metamodel.edit - edit functionality for the Servus meta-model.
- metamodel.editor - a simple editor for the Servus meta-model.
- profile - implements the extension point related to the Profile, which defines transformations between Servus models and profiled Ecore models.
- profile.servus2ecore - uses the rule framework to implement the transformation from Servus to Ecore.
The following diagram sketches the dependencies between the plugins. Dependencies are transitive.
The Core Plugin
The Core plugin (org.eclipse.emf.servus) defines the main API for using Servus' functionalities. This section describes its abstractions and data structures.
Servus manipulates many different types of artifacts. In order to simplify interfaces between transformations, Servus uses Container abstractions to encapsulate those artifacts. Besides carrying the artifacts around, containers are also responsible for knowing how to load and store the artifacts to URIs, usually using EMF's Resources and ResourceSets. The following containers are defined:
Represents the data related to the Servus space, i.e., it carries the Servus models and the referenced Ecore models (as DataModels). Data Models encapsulate an Ecore EPackage together with additional information, such as the Extended Meta-data used to create the EPackage from XSD and the source WSDL types element. Servus Models encapsulate a WebServicesDescription (defined by the meta-model) with additional information, such as its URI.
The container can store its contents (all Servus and Data models) to resources pointed by an URI. Furthermore, given an URI to a Servus model and to its referenced Data models, it can load them, together with all referenced Servus models.
Represents the data related to the WSDL space. It carries WSDL documents and the XSD documents referenced by them. XSDDocuments contain the XSDSchema root object and the corresponding URI. WSDLDocument is an abstract class that must be implemented by different versions of WSDL.
Represents the data related to the profile version of a ServusContainer. It contains the same DataModels as the ServusContainer, but instead of ServusModels it carries a profiled EPackage.
This container is passed around to carry configuration data to transformations. It loads configuration from a map to support tape-safe access to it, also considering the defaults.
Transforms are implementations of transformations. Simple Transforms implement a single transformation between two artifacts, such as between a WSDL document and a Servus model. TransformComposition is a transformation that composes two simple Transforms. For example, the WSDLProfileTransform combines WSDLServusTransform with ServusProfileTransform.
The transforms have very clear APIs. Their names represent the source and target artifact spaces concatenated (e.g., WSDLServusTransform will get WSDL artefacts and transform into Servus artefacts). They define only transform methods that take as parameters the artifacts that they need as input (or their URIs) and return containers that carry the result of the transformation. If the result is not an object, such as in JAX-WS code generation, the method returns void.
The following simple transforms are defined:
The following transform compositions are defined:
Throughout the source code, Servus tries to define very focused classes. Therefore, it extensively makes use of Helper classes, which carry functionality that is not specific for the class that is using them, and that can usually be reused by other classes. The Core plugin defines the NameHelper class, which provides utility methods for manipulating names, such as transforming between Java and NC names, getting corresponding getters and setters for an attribute and so on.
The rule Plugin
This plugin implements a small framework to modularize the implementation of the transformations. The framework supports transformations based on types. The input is the root of a typed graph and the output is the corresponding root. It contains the following three main abstractions.
The rule engine defines an execute method that transforms an object of a source type into an object of a target type. Engines are responsible for:
- keeping a set of rules to be applied when a node of a certain type is traversed
- determining the traversal algorithm, i.e., how to traverse the source graph to generate the target graph
- instantiate appropriate rule helpers
The framework also implements the most common traversals:
- DeepFirstRuleEngine - goes first into children, then siblings
- BreadthFirstRuleEngine - goes first to siblings, then into children
- PriorityRuleEngine - uses a user specified comparator to determine the priority of nodes to be visited
Rules determine how to transform nodes of source types into nodes of target types. A rule is responsible for:
- describe the types of nodes it can transform ( using its types() method)
- transform a node from the source into a set of target nodes (through its apply(..) method)
Note that a single source node can be transformed in a set of target nodes. Also, the apply method receives a RuleHelper, as specified bellow.
A rule helper keeps track of the relationships between nodes and extensions can help rules with additional global or context specific information. The base rule helper is responsible for:
- keeping track of "parent-child" relationships in the source graph. This can be used by rules to know the source objects that were transformed before them.
- keeping track of "source-target" relationships. This allows rules to find the target nodes corresponding to other source nodes (like their parents).
The jaxws Plugin
This plugin uses JET templates to generate JAX-WS based Java source code from Servus models. The plugin implements a Generator and some GeneratorAdapters that take advantage of EMF's code generation frameworks. This means that, if running inside Eclipse, the generators are incremental (thanks to JMerge) and also do formatting.
There are three main templates:
- ServiceInterface.javajet - to generate web service interfaces.
- ServerSkeleton.javajet - to generate server skeletons. It is possible to extend this template to insert code snippets into service methods (if they are annotated in Servus models).
- ClientProxy.javajet - to generate client proxies.
The templates are designed to be as simple as possible to read, understand, and possibly extend. Therefore, they make use of helpers to implement most of the logic and information gathering. This keeps the templates very clean and similar to the final result.