The Container Framework
At the heart of the VAST Web services platform is the Web services container. As the term container implies, it is the object responsible for storage and manipulation of all information relating to deployed Web services.
Containers act as the equivalent of a SOAP node when processing a message. The container ensures proper handling of SOAP messages by identifying proper target node through the SOAP Actor attribute contained in the message headers. The SOAP Actor roles portrayed by a container are defined in the deployment descriptor. Although it is possible to have multiple containers in a single runtime environment, it is recommended that only one container be utilized.
Working with a Container
The first thing that must be done before a Web service can be hosted or invoked is to start a container. The SstWSContainer class API methods can be used for the creation and retrieval of container instances. Several examples follow.
To create a container using the default configuration:
SstWSContainer createContainerNamed: 'VAST'.
To create a container using a custom configuration:
SstWSContainer createContainerNamed: 'VASTCustom'
using: myContainerConfig.
To retrieve a previously created container:
SstWSContainer containerNamed: 'VAST'
To remove a previously created container:
SstWSContainer removeContainerNamed: 'VAST'
Setting up to use Document Literal Wrapped Style:
Document Literal Wrapped Style is a variation of Document Literal Style which is favored by many web services vendors and which has become a de facto standard. It has the advantages of being able to validate the complete SOAP message against schema and complies with WS-I by allowing only one child element under soap:Body.
To configure a container to process web services using document literal wrapped style, use this creation method:
SstWSContainer createContainerUsingDocLiteralWrappedNamed: 'yourContainerName'
Additional protocol on the SstWSContainer class enables the manipulation of containers. Users are encouraged to explore the container further. Figure 2 presents a high level architectural view of the container. At its most basic, the container is a coordinator delegating responsibility for the Web service environment to pluggable helper objects. These helper objects consist of factories and managers.
Managers and Factories
Managers and factories are integral parts of deployment and message processing. Each manager or factory was designed to encapsulate one distinct responsibility. For example, the Port Manager is responsible for tying together WSDL ports types to network access points. The VAST Web services platform includes a set of managers in the base framework. These managers are listed below with a description of their specific functionality.
The container is implemented with accessors for the standard managers. However, additional managers are manipulated in the container using the following API. To add a new manager to the container:
( SstWSContainer containerNamed: 'VAST')
addManager: SstWSServiceManager new
named: 'MyCustomManager'.
To retrieve a manager from the container:
( SstWSContainer containerNamed: 'VAST')
managerNamed: 'MyCustomManager'
The Web services framework was designed to cover a wide variety of usage scenarios. However, it is unrealistic to expect any framework to cover
all use cases. With this in mind, the container architecture was designed to be completely open and customizable by the user. For more information on container customization, see the section entitled
Extending/ Customizing the Web service platform.
Deployment Manager
Default Class: SstWSDeploymentManager
The deployment manager is the entry point for service deployment. It is the object that the container dispatches to when it receives the deploy: API method. The deployment manager has two primary responsibilities. First, it attempts to convert the deployment artifact passed as an argument into a collection of services. Second, it iterates over the collection of managers held onto by the container. Each manager is sent the deploy: method, with the argument being the newly created collection of services.
For example, in the 10 Minute Guide, services were deployed two ways. The first example deployed a service using a URL that resolved to a VAST specific deployment descriptor,
http://vasthost:63001/SstInvestmentAccountInterface.xml.
The second example used a URL that resolved to a WSDL document,
http://vasthost:63001/SstInvestmentAccountInterface.wsdl.
Notice that each time a service is made available, regardless of the type of artifact passed into the deployment manager, the API remains the same, deploy:.
Deployment Strategies
Like much of the framework, the deployment manager's responsibilities are broken down into pluggable pieces. Specifically, there is a collection of deployment strategies that are used to convert various deployment artifacts into a collection of services. These strategies are registered when the image is loaded.
The Web services framework makes extensive use of object registration when classes are loaded into the image. One pattern for this is to have the application class invoke the setupAfterLoad method on each of its defined classes. Advanced users may find it interesting to investigate all implementers of this method.
A single strategy may be registered in multiple ways. Typically, an extension is used, e.g. xml or wsdl, along with a URI. The URI is the namespace identifier of the type of XML document, e.g. http://schemas.xmlsoap.org/wsdl.
The deployment manager may make several attempts to determine the proper strategy to invoke for service deployment. Users wishing to walk through code should put a breakpoint in SstWSDeploymentManager>>deploy: method. The algorithm is as follows:
1. Does the deployment artifact have a known deployment identifier? This handles the scenario where the user is deploying a pre-instantiated object, e.g. an instance of SstWSDeploymentDescriptor.
2. If the deployment artifact does not have a deployment identifier, and it is a string, then an assumption is made that it is a URL, and the deployment manager looks at its extension. If the suffix is .WSDL, an assumption is made that the URL will resolve to a Web services description language document.
3. If the deployment manager cannot figure out which strategy to invoke, it uses the indeterminate strategy. This strategy is registered under the key WSIndeterminateUrlDeploymentStrategy. The indeterminate strategy is the second attempt at service deployment. It tries to parse the string into a DOM object in order to extract the namespace URL. If successful, the indeterminate strategy then checks to see if a development strategy has been registered under this URL, and if so, delegates deployment responsibilities to it.
Message Context Factory
When processing messages in a server environment, it is important to manage concurrency issues. One approach is to ensure that all handlers processing the message are stateless (or that it is safe to share state). In the VAST framework, message state is maintained by an instance of a message context.
The Message Context Factory is responsible for creating instances of the message context that are compatible with the incoming messages format. For example, a properly instantiated message context will contain the initial message processing handler, referred to as the engine.
One key aspect of the Message Context Factory is that it establishes the initial serialization configuration. This configuration manages a set of rules that are followed when serializing outgoing SOAP messages. The default serialization configuration is suitable for most scenarios; however, the Message Context Factory has a hook that enables developers to supply a block that is used to instantiate a custom serialization configuration. See the 'VA Smalltalk XML Support' section of the Visual Programming User Guide for information about serialization configurations.
To set a block that answers a custom serialization configuration:
(SstWScontainer containerNamed: 'VAST')
messageContextFactory serializationConfigurationCreationBlock:
AbtXmlObjectCache current serializationConfigurationNamed:
'MySoapDeserializationConfig' ]
Handler Factory
Message processing occurs by sending a context through a defined set of message handlers. The Handler Factory is responsible for the proper creation and registration of message handlers. Internally, the Handler Factory maintains a registry of handlers. Essentially, this is a namespace dictionary that manages where handlers have been defined.
Note:
Because much of the Web services world is defined by XML it was necessary to model some of the more prominent constructs that appear in XML. One of these was namespaces. The class SstNamespaceDictionary is simply a dictionary of dictionaries. This construct is not to be confused with namespace support in VAST Platform.
Handlers are registered by keys, for example WSGlobalClientInputHandler. This key has a value of wsGlobalClientInputHandler. These keys are located in the pool dictionary SstWSConstants. The Handler Factory attempts to find a handler inside its registry when asked. If no handlers are found, the factory will convert the value of the key into a message selector and perform the method against itself. For an example of this, see the implementors of wsGlobalClientInputHandler. Therefore, as an alternative to utilizing deployment descriptors, the class of the Handler Factory may be extended to include methods specifically designed to meet the requirements of user applications.
The Manager Collection
When service deployment occurs, each object in the containers manager collection is given an opportunity to deploy a collection of services. Each manager in this collection has a distinct, well-defined, responsibility. Although the framework comes populated with a predefined set of managers, specific usage scenarios may require that managers be added or replaced. Details on how to add managers are provided in the
'Extending/ Customizing the Web service platform'of this manual.
By default, this collection consists of the following objects:
• WSActorManager (SstWSActorManager): Specifies which roles the container is playing, as specified by the SOAP Actor attributes.
• WSEngineFactory (SstWSEngineFactory): Determines which message processing engine is to be used when handling incoming or outgoing messages.
• WSPortManager (SstWSPortManager): Responsible for managing the correlation between WSDL port types and network access points.
• WSSerializationManager (SstWSXmlObjectCache): Responsible for maintaining the type and mapping information necessary to automatically convert to and from objects.
• WSServiceDefinitionsManager (SstWSServiceDefinitionsManager): Used as a library type object to hold onto original service definitions parsed in from WSDL.
• WSServiceManager (SstWSServiceManager): Used to control various aspects of the service. This manager is critical in determining how messages are processed.
WSActorManager
During message processing, the container acts as a SOAP node whose roles are identified by a collection of URIs. These roles correspond to the SOAP Actor URIs that are explicitly or implicitly (when no actor is specified) included as part of a SOAP message.
By default, the Actor Manager initializes itself with two roles. The first allows it to behave as a well-formed SOAP node (http://schemas.xmlsoap.org/soap/actor/next) and is required by the SOAP 1.1 specification. The second, is a VAST specific URI (vast:anonymous) that indicates it can act as the ultimate receiver of SOAP messages. To create an intermediary, simply remove the vast:anonymous role from the actor manager. If the container behaves as an intermediary it is the responsibility of the user to ensure the SOAP message reaches the ultimate receiver.
WSEngineFactory
The Engine Factory is responsible for providing the initial message processor. To external applications the framework presents services as standard Smalltalk objects. However, it is often necessary internally to recognize if the object requested is to be used from a client perspective (initiating a message send) or a servers perspective (receiving a message).
Thus, there are two primary handlers that serve as message processing engines; SstWSClientEngine, and SstWSServerEngine. It is the responsibility of these engines to control the basic flow of messages through the various handler chains. Being the initial handler invoked, the engine serves as the bridge between the transport, e.g. HTTP, and the invocation framework. Advanced users may wish to investigate SstWSServlet>>basicProcess: to see how transports and handlers are tied together.
WSPortManager
WSDL provides a mechanism to define where your service will listen on the network. Consider the following example from the SstWSInsurancePolicyInterface.wsdl, that defines a WSDL port:
<port name="SstWSInsurancePolicyInterfacePort"
binding="vastif:SstWSInsurancePolicyInterfaceBinding">
<soap:address location="http://vasthost:63003/SstWSServlet"/>
</port>
When a service is deployed into the container, the Port Manager inspects the location of the service, and if applicable, starts listening on the network endpoint. The Port Manager is responsible for synchronizing the WSDL defined ports, with network access points. Exactly how an endpoint is started is the responsibility of a network transport strategy. Like the deployment strategies, these work to isolate a specific set of requirements. Each strategy registers itself under the transport that it supports, which is based upon the scheme defined in the location URL, e.g. HTTP.
During service deployment, the Port Manager will dispatch into the proper network transport strategy (currently, HTTP is the only supported transport). This strategy then determines if there is an endpoint already started capable of handling requests at the specified location. For HTTP endpoints, the strategy starts a new endpoint when an existing one is not found. The current implementation assumes the use of a servlet architecture and an SstServletEngine will be started. Unless you are providing your own port manager or HTTP transport strategy, it is recommended that your endpoints conform to this format.
WSSerializationManager
The Serialization Manager is responsible for managing rules that are applied during XML serialization and deserialization. The default Serialization Manager, SstWSObjectCache, is a subclass of AbtXmlObjectCache and manages the same types of XML resources. Schemas, mapping specifications, and serialization configurations are among the XML resources that are managed. The Serialization Manager API can be used to access locally specified resources as well as those defined in the globally accessible AbtXmlObjectCache singleton.
WSServiceDefinitionsManager
The Web services definition language (WSDL) provides a layered architecture for describing Web services. Although currently rare in practice, there can be multiple services defined inside one WSDL document. Services inside a WSDL document are contained under a definitions tag. Since there can be additional information carried along with this top level tag that pertain directly to its contained services, e.g. namespace mappings, it is important to maintain this information once processing is complete. The Definitions Managers responsibility is to preserve this information once the WSDL document has been parsed into an object model.
WSServiceManager
When a service is deployed, the container takes on the responsibility of managing the various aspects of its life cycle. A primary object that the container works with is the Service Manager.
The Service Manager provides a qualified location for a service. It is also responsible for maintaining the necessary lookup mechanisms for proper message processing. One mechanism used to determine which service is the ultimate receiver of the incoming message is to inspect the SOAP body namespace. Currently, the VAST framework assumes that this namespace is unique among hosted services.
The container attempts to present a simple API to the user. Service deployment will typically return the collection of services that were described in the provided artifact. Likewise, the method for locating a service inside a container is serviceNamed:inNamespace:. The name and namespace are derived directly from the WSDL document.