Link to specification http://www.w3.org/TR/2011/REC-ws-transfer-20111213/
Link to implementation on GitHub https://github.com/dudaerich/cxf/tree/master/rt/ws/transfer (work in progress)
Contribution to Apache CXF is done by Erich Duda as part of diploma thesis on Faculty of Informatics, Masaryk University Brno, http://www.fi.muni.cz/
Red Hat Brno is motivating students to contribute into open source projects, Erich is guided by Rostislav Svoboda.
Similar contribution was done by Jan Martiska, see https://community.jboss.org/wiki/CXFWS-EventingJavaAPI.
WS-Transfer is a SOAP-based protocol, which enables to create, update, delete and get XML resources. Specification describes the form of the SOAP messages, which are sent between server and client. The server side consists from two entities - ResourceFactory and Resource. ResourceFactory is responsible for creation resources and returning back information needed to getting, updating or deleting the newly created resource. This information contains URL of the Resource entity and XML element, which identifies the concrete XML resource. The ResourceFactory can decide, which type of resource creates and where it will be stored. Since the XML resource is created, client can get, put (update) or delete this entity. These operation are provided by the Resource entity. One Resource entity may contain more XML entities, which are uniquely identified by a reference parameter.
The ResourceFactory is responsible for creation Resources. It provides one method called Create. The method creates resource and provides its initial representation. Representation sent by client may differ structurally from the representation returned by Resource. It may constitute the representation of a logical constructor. "The representation could be considered to be invalid if it does not conform to the schema(s) for the target resource, is empty and the implementation does not support empty representations, or otherwise violates some cardinality or type constraint. If an implementation that validates the presented representation detects that the presented representation is invalid for the target resource, then the implementation MUST generate a wst:InvalidRepresentation fault." (WS-Transfer, Section 5.1)
As mentioned the ResourceFactory should provide some mechanism, which would be enabled to validate and transform received XML representation. This representation can have more correct forms, which may be accepted by the ResourceFactory. In addition each form can be transformed by different way. For this purpose the ResourceFactory will contain a list of validators, which declare if the received representation is valid. If it is valid, validator may return appropriate ResourceTransformer, which transform it to desired form. The whole process is illustrated by Fig. 2.
Fig. 1 ResourceFactory diagram with Validator and Transformer relations.
Fig. 2 Activity diagram describing the validation process.
When a new XML representation is received, at first the ResourceFactory run the validation and transformation process. If there is no defined validators, which could be used to validate the resource, representation is automatically declared for valid. Otherwise it launchs validation process, where validators sequentially validate the representation. The first validator which validates the representation ends this process. Validator can return transformator object, if so it is applied to transform the representation. If all validators declare the representation as invalid the InvalidRepresentation fault will be generated. Using terminology from the Logic, the validators are concatenated by function OR. Validators can be described by XSD or DTD or programmer can write his own implementation, which will implement validate method. Transformation can be described by XSLT or also can be created own implementation.
ResourceFactory can decide, where XML resource will be stored. In other words it has to return the address of the Resource entity, which will provide functionality to get, update or delete the newly created XML resource. To implement such functionality will be used the ResourceResolver class, which will accept as a parameter the XML representation and will return the necessary information to create a new resource. More information about it will be mentioned later.
When the ResourceFactory creates the new resource, Resource entity is responsible for getting, updating and deleting the newly created XML resource. One Resource entity can contain more XML resources, which are uniqeuly identified by any XML element. To facilitate the implementation it will be used to identify the resource a unique identifier. Each operation must contain this identifier otherwise is generated UnknownResource fault. Methods Get and Delete does not accept any other parameter. Only method Put accepts the resource representation, which is used to update existing XML resource. Similar like the Create method in the ResourceFactory may Put generates InvalidRepresentation fault and the input representation may have other XML structure than that returned by the resource; in such a case, the semantics of the update operation is defined by the resource. It can be used the same mechanism of validators and transformators.
Each operation in both entities may be extended by an attribute with a name Dialect. It contains a IRI, which refers to additionail information for the service describing how to process this element. The specification also defines WS-Fragment dialect, which must be implemented otherwise the implementation is not compliant with this specification. The WS-Fragment specification defines dialect only for Get and Put methods and both require own implementation. Implementation of the Dialect must decide whether the dialect supports a method, where it is used. Otherwise it has to generate the UnknownDialect fault. In the code the dialect is represented by a Dialect interface, which provides one method called process. This method takes two parameters. The first is the body of the SOAP message and the second is the XML resource. Result of this method is sent to the client.
Fig. 3 WS-Fragment dialect diagram
Fig. 4 Processing Get request by the WS-Fragment dialect.
Fig. 5 Processing Put request by the WS-Fragment dialect.
WS-Fragment is a dialect, which is required by the WS-Transfer specification. It must be implemented otherwise the implementation would not be compliant with the specification. Therefore the WS-Fragment is part of the WS-Transfer and sources of the WS-Fragment will be located in the WS-Transfer package. Because of easy refactoring, all sources will be located in a separate package.
Communication between ResourceFactory and Resource
Separation ResourceFactory and Resource to individual entities creates a problem how entities will communicate between themselves. The possibly solution is to create a Storage entity, which will provide CRUD operations. The ResourceFactory and the Resource would connect with it and so they could communicate through it. Ideal candidate for this role is database engine, which provides CRUD operations and also enables to communicate using the TCP protocol. Each Resource entity has its own Storage. The ResourceFactory can decide where to store the received XML representation and then it has to send back to the client the URL of the Resource, which is associated with that Storage. If the more Resource entities will share one Storage, the same data could be obtained from the all Resources and it will be needed some mechanism, which could recognize data related to that Resource.
Fig. 6 Communication through the Storage (1 ResourceFactory : 1 Resource).
Fig. 7 Communication through the Storage (1 ResourceFactory : n Resources).
As we can see on the figure 7, disadvantage of this architecture is that the ResourceFactory has to be capable communicate with all Storage entities. There is no uniform interface for such communication, so the ResourceFactory should implement, in this case, 3 communication protocols.
Better solution is to cancel dependencies between ResourceFactory and Storage entities. It is displayed on the figure 8. Resource entities will provide operation create and Resource factory will just forward the SOAP messages to the appropriate Resource. The Storage entity is not needed anymore, because the ResourceFactory communicate with the Resource directly and there is no reason to create the third entity, which would mediate communication.
Fig. 8 Communication directly with the Resource.
Although the second solution is more flexible and gives mentioned benefits it also requires additional requirements. It should be secured communication between ResourceFactory and Resource otherwise client could send Create request directly to the Resource. Communication between these entities using SOAP protocol increases overhead. If both entities are running in the same JVM it is much faster to communicate between themselves on the object level.
Fig. 9 The whole class diagram.
The implementation provides two types of the Resource - ResourceLocal and ResourceRemote. Difference between these two objects is that the ResourceRemote implements both interfaces the Resource and the ResourceFactory. It provides two endpoints. The first endpoint is public and the second is private given for the ResourceFactory. This endpoint contains one method Create. Public endpoint contains Get, Put and Delete methods. The ResourceFactory makes decision where to store the XML representation using by a ResourceResolver. This class contains one method resolve, which accepts the XML representation and returns a ResourceReference. The ResourceReference has two attributes a resourceManager and a resourceUrl. If the resourceManger is not null so the ResourceManager is running in the same JVM and the ResourceFactory can create the Resource directly by calling the create method on the ResourceManager object. The resourceUrl specifies endpoint url to the appropriate Resource. If the resourceManager is null so the ResourceFactory creates from the resourceUrl url of the Resource endpoint and sends the create request. It can create the url of the endpoint by adding the suffix "_factory" to the resourceUrl. One ResourceFactory can create resources locally and also remotely.
Fig. 10 Decision process where to store the XML representation.
Fig. 11 Creation of the Resource locally.
Fig. 12 Creation of the Resource remotely.
The ResourceResolver returns the ResourceReference. If it contains a pointer to the ResourceManager, the ResourceFactory can call create method directly on the ResourceManager object. This situation is displayed on the figure 11. Otherwise the Create message is forwarded to the appropriate Resource, which contains the pointer to the ResourceManager. As we can see on the figure 12, the second approach requires bigger overhead, but it enables to run the Resource in the separate execution enviroment.