Introduction to the InstantSOAP architecture

The InstantSOAP architecture aims to ballance the following qualities:

  • High performance: Must be able to handle many requests, and slow down gracefully with extra load rather than fail catastrophically
  • Low overhead: InstantSOAP itself must not soak up unreasonable resources, as these would be better used on the exposed business logic
  • Highly configurable: Where ever possible, it should be possible to provide new business logic and new components in the request handling without modifying existing code
  • Modular build: Each software component should be built and tested seperately of all others, minimizing spurious dependencies and maximizing the modularity and therefore reusability of the components.

These concerns are addressed by the InstantSOAP architecture in two ways. Performance, resource and scaling concerns are handled by minimising per-invocation object instantiation within the dispatch stack, and by using threaded job queues. Configurability and modularity are ensured by using multiple, fine-grained maven modules, each providing APIs or implementation code for a single defined task. Concrete implementations of these APIs are then aggregated at run-time into a fully configured graph of objects; there are no constructor calls to concrete classes present anywhere in the Java codebase itself.

Major components

The major components involved in processing a client request are: the client; the webservice or web application container hosting InstantSOAP; the SOAP library that handles the messaging; the InstantSOAP dispatch stack; and the business logic.

The client is any software component capable of using SOAP over HTTP. This may be acting directly as an agent for a user (for example, embedded in a web page or GUI) or for another software agent (for example, part of a workflow). The client will innitiate an interaction with an InstantSOAP deployment by SOAP messaging the deployment's URL.

The webservice container is responsible for managing an HTTP server and routing requests for specific URLs on to the components that will handle them. The container manages the lifecycle of all the components it contains, creating instances as required and performing load ballancing, fail over and other dependebility functions. When the client contacts the InstantSOAP deployment's URL, the web service container will recieve this, do any HTTP-specific handling that is required and then hand this off to the SOAP library.

The SOAP library is responsible for mapping between the HTTP protocol and objects representing SOAP messages. It is also responsible for routing these messages through to the Java service objects that will do the actual handling. When the SOAP library recieves a HTTP message from the webservice container, it will parse it from XML, build InstantSOAP request objects and invoke the right method of the InstantSOAP service object.

The InstantSOAP dispatcher recieves requests for describing and running applications. It manages resources corresponding to result files, maintains queues of pending jobs, and decouples the asynchronous or synchronous invocation semantics exposed to the client from the strategy used internally. When the SOAP library invokes the InstantSOAP service object, this passes control directly to the dispatcher. This then validates the request and enqueues it. The request is then dequeued by a different thread, and is passed on to the business logic that will handle this particular request.

The buisness logic is the actual work that is done to generate responses. This may execute some Java code, a native application or invoke an interpreter to support code in any language. When the dispatcher passes control to the business logic, it generates the response and returns this to the dispatcher.

None of these components need know any of the specifics about how their neighbours work. They exclusively communicate through their APIs. This provides great flexibility in how the system can be deployed, and allows one component to be replaced or updated without other components being affected.

Dispatcher components

The dispatch stack is where people deploying InstantSOAP can inject custom policies for managing request processing. This section disusses the upper and lower tier of the dispatch stack, and describes some of the more important classes and interfaces involved. The upper tier of the stack is responsible for bridging the service oriented architecture exposed as a web service to an object-oriented architecture used for implementation. The lower tier of the stack is responsible for managing the invocation of business logic, and in particular, for decoupling the flow of control in the business logic from that in the dispatch stack. These two tiers are discussed more fully in the following subsections.

Service Interface and the Service Dispatchers

The web service interface for InstantSOAP is WebServiceDispatcher . This provides one method to list the names of all applications that the installation can handle, methods for describing applications and their inputs and outputs given the appilcation name, and methods for invoking an application in blocking (synchronous) or non-blocking (asynchronous) modes.

The standard implementation of this interface does the minimal work needed to bridge from a service-based invocation style to the standard models used when programming Java. It then delegates all of the work on to synhronous and synchronous service dispatchers.

Job Invocation via Strategy Dispatchers

The service dispatcher classes provided by InstantSOAP pass control on to an object implementing the StrategyDispatcher interface. The strategy dispatcher level is responsible for ensuring that the correct buisness logic handles each request, and that the control flow of the buisness logic is decoupled from the controll flow of the incomming requests.

Executing a job specification using a strategy dispatcher is a two stage process, validation followed by invocation. Validation is initiated when the invoker calls the validateJob(JobSpecification) method on the dispatcher. This method will firstly validate the job. If the job is clearly going to fail then this can be reported emediatelly, avoiding tieing resources up further down stream. If the job passes the validation test, then the dispatcher creates a ValidatedJob that can be used to launch the job.

Invocation is initiated by the client calling dispatch() on the validated job. This returns a UUID that uniquely identifies this invocation, and starts the process of launching the buisness logic associated with the job. The same validated job can be dispatched any number of times, and each time a new UUID will be returned.

The dispatch() method takes a listener. This is the object that will be informed as the buisness logic is actually executed. It has a method to indicate that the job has started, that it has completed successfully, and that it has completed with failure. Any or all of these methods may be invoked at any time, both during and after the dispatch() method has returned control to the invoker, and both in the same or a different thread. The client should make no assumptions about any of these possibilites.

Strategy Dispatcher Implementations

The underlying execution system can process tasks at a rate dictated by the available hardware. Incomming requests may arrive faster or slower than this rate. Inserting a queue between the incomming requests and the job handling allows load to be handled more evenly. The QueuedDispatcher class provides an implementation of the dispatcher interface that enqueues jobs when dispatch is invoked, and processes the queue using a threadpool.

Several different dispatchers may be responsible for handling different applications. The MultiplexingStrategyDispatcher class provides an implementation of strategy dispatcher that sends requests on to other dispatchers. It maintains a set of dispatchers. Incomming requests are matched against each of these in turn, untill a nested dispatcher that can handle the request is found. The request is then forwarded on to this dispatcher for further processing. This affords developers of business logic quite a degree of latitude about how individual kinds of applications are presented to the system.

Exposing the business logic itelf is achieved by providing an implementation of strategy dispatcher that performs the required task when dispatch is invoked. The InstantSOAP codebase provides one such implementation, MapStrategyDispatcher . If you wish to develop a new binding for InstantSOAP, you can either write a new dispatcher implementation, or instead expose it directly as an object that MapStrategyDispatcher can expose. There are arguments to be made for both approaches.

Default deployment