Messages are passed through a decorator pattern represented by a series of handlers. Each handler supports a simple, common, API that allows developers to produce complex functionality by chaining together simple parts. Utilizing this pattern, developers are free to create and plug-in any handlers necessary to customize their Web services environment. The container uses the Handler Factory to manager handlers.Decorator pattern is a concept developed on page 175 of Design Patterns: Elements of Reusable Object-Oriented Software.Global - Manage tasks that are required for all Web services messages. Global handlers should be considered valid for all messages. For example, in the current design of the framework, global chains are responsible for the parsing and dispatching of SOAP message headers. Another use of global handlers would be to log every message processed.Service - These handlers facilitate operation level definition of handlers. Continuing with the logging example, using service level handlers facilitates logging only for specific messages.Transport - These handlers are responsible for binding a specific transport to the invocation framework. For example, for incoming messages, the HTTP transport handlers ensure that there is a SOAP Action present. For outgoing messages, these handlers place the proper content type and return code in the HTTP header.Chains - Handlers are typically built to perform very granular tasks. Interrelated handlers can be logically grouped into constructs called chains. Handler chains implement the same interface as standard handlers; however, they combine the functionality of multiple handlers into a single unit.In the example above, when the #invoke: method of the SstWSSimpleChain instance is invoked, the two declared handlers are sequentially invoked. The first handler (MyInitializationHandler) might perform an initialization function to prepare the message context for the invocation of the second handler (MyServiceHandler).Constants for these keys have been defined in the pool SstWSConstants. The constant is the string value with the 'ws' capitalized i.e. 'wsGlobalResponseServerHandler' is WSGlobalResponseServerHandler.
Process any body elements that appear in the request. The default algorithm for handling SOAP body messages is the same as SstWSHeaderProcessor.
• Results of executing the message are written to the message context using the addResult: API. The results are serialized as the payload of the SOAP Body element in the response message.
• If no handler is found, then check for a service and method mapping in the service manager using the name and namespace of the header element. If the service exists, but no method name was specified, use the default method, process:context:. Invoke the method passing the header element and the message context as arguments.
• Results of executing a header message are written to the message context using the addResultHeader: API. The results are passed back as SOAP header entries in the response stream.These keys are used by the transport endpoints. For example, when the SstWSServlet receives a request it asks the container for a new message context for that message. It then places the names of the transport handlers e.g.WSHttpServerRequest, in the context using the known transport identifier keys. When the transport handlers are to be invoked, the invocation framework gets the proper name from the message context, and combined with the global namespace, looks for the handler in the Handler Factory.
There is a logical flow to message processing that is controlled by the server engine. The Message Processing Server figure illustrates how messages pass through the framework. Notice that the handler groups are further broken down into those that handle the incoming message, and those that handle the outgoing message. Although this is a logical separation, this does not place a restriction that separate handlers be used. The behavior of each handler is triggered by sending the invoke: method. This method takes an instance of SstWsMessageContext as its argument. In the server, the process originates at the actual network endpoint. As the information is passed through the handler chains, it is ultimately sent to the user application through an instance of the class SstWSService.During message processing, the framework must make a decision that it is no longer processing input, but preparing output. When this occurs, we say that the message context has past the pivot from input to output (sometimes correlated to request/response). On the server, the pivot is passed when the SstWebService returns from the method send into the user application. In the scenario above, the pivot is passed between service handler invocation.While executing, the handler can access the active header element using the message context reserved key SstWSConstants::WSCustomHandlerElement (##wsCustomHandlerElement).Header elements that are included in the WSDL abstract response message can be saved in the message context using the method #addResultHeader:. During serialization, the result header collection is added to the SOAP Header of the outgoing message. The Web services insurance example contains an operation that demonstrates this behavior.In either case, it is the instance of SstWSService that acts as a façade for the user application. This reinforces the notion of location transparency and allows the application architect to freely move services around the network.The message context object protocol propertyNamed:, and addProperty:named:, enable simple storage and retrieval of vital information during message processing. In addition, the message context is used to encapsulate the serialization and deserialization of Web services messages through the currentMessage API. Any required information that needs to be shared among handlers should be stored in the message context.Depending on the perspective of the message send, processing begins with an instance of either SstWSClientEngine, or SstWSServerEngine. Since these are handlers, the entry API is invoke:The implementation is to call basicInvoke: wrapped by an exception handler. Subclasses of SstWSEngine implement basicInvoke: to lookup and call the handlers defined in the container. The default exception handler looks up the defined fault handlers and invokes them. Because message processing is inside an exception block by default, to participate in exception processing, a handler need only implement the invoke: method.
1. Custom handler assumes complete control. In this scenario, a custom handler has been deployed into the container. This handler implements the following methods; basicInvoke:, handleException:with:. This indicates to the message processing framework that the exception has been completely handled. It is up to the user to ensure all messages return properly to the ultimate sender. It is recommended that only advanced users adopt this approach.
2. Custom handler 'participates' in exception processing. This approach is similar to the one above in that a handler is introduced that implements basicInvoke:, handleException:with:. However, upon completion of the handleException: method, an exception is signaled again. This could be the same exception that is passed as an argument to the method, or, it can be a new exception created by the handler. The only caveat is that it must be a child of ExAll. When the exception is signaled, it will be caught by the 'outer' exception block in the engine and handled appropriately. This is the recommended approach.In an attempt to provide maximum protection against unforeseen problems the implementation of invokeFaultHandlers: has been wrapped inside of an exception handler block, e.g.Both of these techniques for extending the message behavior are demonstrated by the Web services insurance example which is discussed in a later chapter.
• In the WSDL binding, add a header extension to the SOAP input definition of the operation that will pass the header.
• Modify the body extension of the SOAP input definition to list the parts that should be included in the SOAP Body. If the parts attribute is absent from the body extension, the VA Smalltalk Web services support assumes that all parts within the abstract message are intended for the SOAP body.Applications can also add header entries to outbound SOAP messages using custom handlers. This may be desirable when including common information in all outgoing messages. Handlers can add elements to the outgoing SOAP header using the #addHeaderElement: method of the SstSoapEnvelope. Be aware that all added header elements must be capable of properly rendering themselves as XML.There are many aspects of a Web service environment that rely on external files. WSDL documents are an obvious example, which themselves rely on XML schema. Often, the contents of these files are resolved at runtime. In order to provide an external mechanism for describing Web services, the concept of a deployment descriptor has been introduced. This section will detail deployment and describe how to effectively utilize the deployment descriptor.A deployment descriptor is an XML file that conforms to the schema defined in the sstwsdep.xsd file. These files are used for both containers and services. Although one file can deploy both containers and services, it is common practice to have a separate deployment descriptor file for each set of these related artifacts.For the sake of simplicity, collections of elements are contained in a top-level tag. For example, <imageComponentUrls> is a top-level tag that represents a collection of <imageComponentUrl> tags. While reviewing this section it may be helpful to browse the sample files SstWSSampleContainer.xml and SstWSInsurancePolicyInterface.xml regardless of whether the deployment descriptor is describing a container or a service, all deployment descriptors define the following meta-information:Deployment Descriptor Version - urn:VASTWebServiceDeployment600 represents the URI of the VA Smalltalk Web services deployment descriptor.Image components - This entry specifies the URLs that point to the ICs to load as the first step in service deployment. For ICs only, these must resolve to a local file. It is expected that all code necessary to support deployment be contained in these ICs.Mapping Specifications - This section specifies a list of resolvable URLs, e.g. http://myhost/myMappingSpec, that are utilized by the XML parser to map class names to tag names. See the XML guide for additional information about mapping specifications.Handlers - This section is used to define the handlers that will be utilized by the framework during message processing. Each handler is defined with the key that will be used to find it in the Handler Factory. For container handlers, the Handler Factory utilizes the global namespace attribute when caching entries in its registry.When defining a handler, the Smalltalk class that implements the desired behavior, or another handler may be specified. When specifying a class, the class attribute is utilized. When specifying a reference to another handler, the type attribute is used.As mentioned above, deployment descriptors are broken down into two broad sections, one for container information and one for service information. The deployment descriptor uses two enclosing tags to represent the internal separation of these segments, <container> and <service> respectively.For the most part, the deployment descriptor is simply the serialized form of many common Web services constructs. An example of this is the <configuration> tag. As its name implies, this tag represents a container configuration object (SstWSContainerConfiguration). In fact, both the serialization and deserialization of the configuration object utilizes XML schema based mapping support.The managers collection may also be specified in the deployment descriptor. The SstWSSampleContainer.xml file illustrates how to specify the pre-defined managers, e.g. the Port Manger. However, this is not a finite list. Framework users may include additional managers of their design simply by following the pattern in the example deployment descriptor. At runtime, the custom managers may be retrieved from the container by using the managerNamed: protocol on the container.Service deployment works in the same manner as container deployment. All information relating to a collection of services is included in an enclosing XML tag named <services>. Each individual entry has its own <service> tag.One of the most important aspects of describing the service is the name and namespace. The service name and namespace are the mechanism used to link together deployment information and information specified in the WSDL implementation document. The entries in these documents MUST BE THE SAME, otherwise, the Web services framework will not be able to determine which service corresponds to the parsed in WSDL information.The next piece of information specified by the service deployment descriptor is the service interface class. This is the class that the framework utilizes as the link between the framework and the user application. For remote services, this class acts as a proxy and is the start of the invocation chain for network messages. Hosted services utilize this class as a thin layer to wrap the application interface, referred to as the provider class. The provider class is the user application class representing the business logic interface. An instance creation method attribute can be provided to facilitate specialized instance creation.The final aspect of service deployment is mapping WSDL operation names to Smalltalk selectors. Currently, the framework requires that all operations inside of the WSDL document be mapped. Below is an example operation mapping from the SstWSInsurancePolicyInterface.xml document.This maps the Smalltalk selector ratePolicy: to the fully qualified service operation swsipi:ratePolicy. In the WSDL document for the service, the swsipi prefix maps to the namespace urn:SstWSInsurancePolicyInterface which is defined as the namespace of the serialized soap:body. By default, the Web services framework will dispatch the incoming message and place the results in the message context.However, under certain circumstances, the user application may need to assume complete control of the incoming or outgoing messages. In this scenario, an operation flow handler should be used. Here is an example of how the flow handler may be defined:This handler from the insurance examples deployment descriptor defines the getCompanyInfo method utilizing an operation handler.With one exception, operation handlers work in the same manner as all other handlers. During service invocation, this handler is found and its invoke: API is called. Internal to this invocation, the handler will determine the current state of the message context and invoke the corresponding nested handler, e.g. the input, output, or fault handler.
![]() |