ObjectAdapter represents the abstract model of an object
adapter that was introduced by ORT. This means that all
object adapters must:
- Have an ORB
- Have a name
- Have an adapter manager (represented by an ID)
- Have an adapter template
- Support getting and setting their ObjectReferenceFactory
- Provide access to their current state
- Support adding components to their profiles expressed in the adapter template
Other requirements:
- All object adapters must invoke ORB.AdapterCreated when they are created.
- All adapter managers must invoke ORB.AdapterManagerStateChanged when
their state changes, mapping the internal state to an ORT state.
- AdapterStateChanged must be invoked (from somewhere) whenever
an adapter state changes that is not due to an adapter manager state change.
Object adapters must also provide mechanisms for:
- Managing object reference lifecycle
- Controlling how servants are associated with object references
- Manage the state of the adapter, if the adapter desires to implement such mechanisms
Such mechanisms are all object adapter specific, and so we do not attempt to
create general APIs for these functions here. The object adapter itself
must provide these APIs directly to the user, and they do not affect the rest of the
ORB. This interface basically makes it possible to plug any object adapter into the
ORB and have the OA work propertly with portable interceptors, and also have requests
dispatched properly to the object adapter.
The basic function of an ObjectAdapter is to map object IDs to servants and to support
the dispatch operation of the subcontract, which dispatches requests to servants.
This is the purpose of the getInvocationServant method. In addition, ObjectAdapters must be
able to change state gracefully in the presence of executing methods. This
requires the use of the enter/exit methods. Finally, ObjectAdapters often
require access to information about requests. This is accomodated through the
OAInvocationInfo class and the thread local stack maintained by push/pop/peekInvocationInfo
on the ORB.
To be useful, this dispatch cycle must be extremely efficient. There are several
scenarios that matter:
- A remote invocation, where the dispatch is handled in the server subcontract.
- A local invocation, where the dispatch is handled in the client subcontract.
- A cached local invocation, where the servant is cached when the IOR is established
for the client subcontract, and the dispatch is handled in the client subcontract
to the cached subcontract.
-
Each of these 3 cases is handled a bit differently. On each request, assume as known
ObjectId and ObjectAdapterId, which can be obtained from the object key.
The ObjectAdaptorFactory is available in the subcontract registry, where it is
registered under the subcontract ID. The Subcontract ID is also available in the
object key.
- The remote pattern:
- oa = oaf.find( oaid )
- oa.enter()
- info = oa.makeInvocationInfo( oid )
- info.setOperation( operation )
- push info
- oa.getInvocationServant( info )
- sreq.setExecuteReturnServantInResponseConstructor( true )
- dispatch to servant
- oa.returnServant()
- oa.exit()
- pop info
REVISIT: Is this the required order for exit/pop? Cna they be nested instead?
Note that getInvocationServant and returnServant may throw exceptions. In such cases,
returnServant, exit, and pop must be called in the correct order.
- The local pattern:
- oa = oaf.find( oaid )
- oa.enter()
- info = oa.makeInvocationInfo( oid )
- info.setOperation( operation )
- push info
- oa.getInvocationServant( info )
- dispatch to servant
- oa.returnServant()
- oa.exit()
- pop info
This is the same as the remote case, except that setExecuteReturnServantInResponseConstructor
is not needed (or possible, since there is no server request).
- The fast local pattern: When delegate is constructed,
first extract ObjectKey from IOR in delegate,
then get ObjectId, ObjectAdapterId, and ObjectAdapterFactory (oaf). Then:
- oa = oaf.find( oaid )
- info = oa.makeInvocationInfo( oid ) (note: no operation!)
- push info (needed for the correct functioning of getInvocationServant)
- oa.getInvocationServant( info )
- pop info
The info instance (which includes the Servant) is cached in the client subcontract.
Then, on each invocation:
- newinfo = copy of info (clone)
- info.setOperation( operation )
- push newinfo
- oa.enter()
- dispatch to servant
- oa.returnServant()
// XXX This is probably wrong: remove it.
- oa.exit()
- pop info
XXX fast local should not call returnServant: what is correct here? |