This technical note should be read after Synchronous Communications between Domains since I have tried to avoid repeating myself too much here. Most asynchronous communications between domains involve:
- request wormholes (domain-crossing events or bridging processes) in client domains,
- control reception points (external events or synchronous services) in server domains,
- and request mappings in bridges.
However, asynchronous communications may also involve:
- solicit event parameters on request wormholes,
- asynchronous return wormholes in server domains,
- asynchronous return mappings in bridges,
- and transfer vector types.
Request wormholes are associated with a terminator in a client domain and include domain-crossing events and bridging processes. A domain-crossing event may have any number of carried data items. A bridging process may have any number of user-defined input or output parameters. However, output parameters are not relevant here when dealing with asynchronous communications. Bridging processes are normally used for synchronous communication. However, they may also be used for asynchronous communication as long as a synchronous return mapping exists.
Control reception points are associated with a terminator in a server domain and include external events and synchronous services. External events indicate internal events (state model, domain-crossing or polymorphic events) that can arrive from outside a given domain via a specific terminator. Events may have any number of carried data items. Synchronous services may have any number of user-defined input or output parameters. However, output parameters are not relevant here when dealing with asynchronous communications. Unlike bridging processes, synchronous services may be used in a purely asynchronous manner since the results may not be required by a particular client domain. Dummy return coordinates are passed to synchronous services when they are invoked asynchronously allowing the server domain to execute a dummy synchronous return unaware that it has been invoked asynchronously.
A request mapping in a client-server bridge is implemented using an Action Language statement block. It maps a request wormhole to a control reception point. If the request wormhole is a domain-crossing event then the carried data items are passed as input parameters into the request mapping. Otherwise, the input parameters of the bridging process are passed into the request mapping. Request mappings have no output parameters. The code in a request mapping must either generate the associated external event or invoke the associated synchronous service. It may also decide to do neither without consequence. Output parameters should not be accessed when invoking a synchronous service asynchronously. Any attempt to do so is a static coding error. There may be any number of request mappings for a given request wormhole.
External events may be both unsolicited and solicited. Request mappings to external events define unsolicited events which either represent a new thread of control within the server domain or extend the existing thread of control associated with the client domain's request wormhole. Solicited events within a client domain on the other hand extend an existing thread of control associated with a previously invoked request wormhole to a server domain. Solicited events are defined using solicit event parameters on request wormholes. A request wormhole (whether used synchronously or asynchronously) may have zero to many solicit event parameters. A solicit event parameter holds a complete event instance created in a client domain which is then passed to a server domain as a transfer vector. The transfer vector can then be used to invoke an asynchronous return wormhole in the server domain which as a consequence generates a solicited event in the client domain.
[Wormhole96] proposed that transfer vectors should encapsulate partial event instances with all event data items determined from asynchronous return wormhole input parameters. OOA09 doesn't allow partial event instances at all. It does allow an event instance to be created from another event instance allowing new event data item values to be supplied. It also allows event data items to be read from an event instance in the same way as attributes can be read from an object instance. This allows full or partial overriding of event data items on event instances. However, this always involves creating a new event instance since event instances are immutable in OOA09.
Solicited event parameters have a multiplicity and conditionality providing some indication as to how many solicited events are expected by the client domain. If more than one solicited event is generated when no more than one was expected then an error should be reported but the solicited event is still generated. If no solicited events are generated but at least one was expected and all transfer vectors go out of scope then an error should be reported. A solicited event is not automatically generated here. This behaviour differs from what happens when all return coordinates go out of scope and a synchronous return hasn't been invoked. This is because a missing asynchronous return is a protocol error which should be handled in the appropriate state models while a missing synchronous return is a permanently blocked concurrent thread.
An asynchronous return wormhole is an abstract process associated with a terminator in a server domain which may be invoked in any composed operation (action or synchronous service). It may have any number of user-defined input parameters. Asynchronous return wormholes have no output parameters. A self parameter with a transfer vector type is also automatically defined. However, explicit asynchronous return wormholes are not always required in OOA09 since transfer vectors may arrive in a domain in a complete state allowing a solicited event to be immediately generated without involving an asynchronous return mapping.
An asynchronous return wormhole is normally invoked on a transfer vector value using an invoke return statement, e.g.
transfer_vector.return(message:"Hello World");
However, an implicit asynchronous return wormhole involving a complete transfer vector (one not associated with an asynchronous return wormhole) is always invoked using an ordinary generate statement, e.g.
generate transfer_vector;
The generate statement is used in this case since an asynchronous return mapping is never involved, i.e. the transfer vector's event instance is immediately generated (or delayed if a delay clause is used).
An asynchronous return mapping in a client-server bridge is implemented using an Action Language statement block. It maps an asynchronous return wormhole to a solicited event parameter. It is invoked whenever an asynchronous return is performed using a partial transfer vector. No asynchronous return mappings are required (or possible) for complete transfer vectors. The input parameters associated with a asynchronous return mapping match the input parameters of the asynchronous return wormhole. Asynchronous return mappings have no output parameters. A self parameter with an event instance type is also automatically defined. The self parameter contains the event instance wrapped by the asynchronous return wormhole's transfer vector. It can be used immediately to generate a solicited event. However, some adjustment will normally be required using the input parameters. Any adjustment will involve creating a new event instance. The code in an asynchronous return mapping will normally generate the associated external event. However, it is not required to do so. If there are no asynchronous return mappings for an explicit asynchronous return wormhole then the partial transfer vector is treated like a complete transfer vector, i.e. a solicited event is automatically generated from the transfer vector's wrapped event instance. However, this should be reported as an error. This behaviour differs from what happens when no synchronous return mapping is specified. If you don't want an asynchronous return then you shouldn't pass a transfer vector into a control reception point.
A predefined partial transfer vector type is defined for each asynchronous return wormhole allowing partial transfer vectors to be safely passed around within a domain since the parameters associated with a partial transfer vector can be statically determined within Action Language code. A single predefined complete transfer vector type is also defined allowing solicited events to be generated without the need for an explicit asynchronous return wormhole or an asynchronous return mapping. The predefined complete transfer vector type is generic. The predefined partial transfer vector types are partially generic in that they can be used across multiple control reception points.