Previous | Table of Contents | Next |
21.4.4.1 Client-side use of PICurrent
PICurrent is merely a slot table. Before a request, a service’s Current can store its context specific data into a slot in
PICurrent. When a request begins, PICurrent’s context transitions from a thread context to a request context. (That is, the
ORB logically makes a copy of the current PICurrent and places that copy on the request. Note that this could be a lazy copy.
A copy would only be necessary if PICurrent were modified. Since a copy may never actually be made, the term “logical copy?
is used in this section.) Each service’s Interceptor now has access to the data that its Current put into PICurrent’s slot
table. In other words, each service’s Interceptor now has access to the data within the calling client’s thread context even
though the request processing may be in a different thread.
For example, see the following pseudo-code. Within its ORBInitializer (see
Section 21.7.1, “ORBInitializer Interface,? on page 21-50), the transaction service
allocates a slot:
PortableInterceptor::SlotId mySlotId =orb_init_info.allocate_slot_id ();
When a transaction begins, the Transaction’s Current is called, which can place its context information in a slot on PICurrent:
any myData = ...; // get data from Transaction’s Current
PortableInterceptor::Current pic = orb.resolve_initial_references (“PICurrent?);
pic.set_slot (mySlotId, myData);
When an operation invocation begins, the ORB logically copies PICurrent from the thread context to the request context and
the slots are available to Interceptors via the ClientRequestInfo object. So the transaction service’s Interceptor could
look like:
any myData = info.get_slot (mySlotId);IOP::ServiceContext sc = ...;// convert myData to a SCinfo.add_request_service_context (sc);
The request scope PICurrent slots are read-only on the client. There is no set_slot on the ClientRequestInfo object.
21.4.4.2 Example of PICurrent to Handle Client-side Recursion
If an Interceptor itself makes an operation invocation, it shall have some means of breaking infinite recursion. For example:
the client calls operation X; send_request is called, which calls operation Y; send_request is called, which again calls operation
Y; and so on unless the implementation of send_request breaks the recursion.
Recursion can be broken using PICurrent. If an Interceptor knows it will recurse, it allocates a slot in PICurrent in its
ORBInitializer
(see Section 21.7.1,
“ORBInitializer Interface,? on page 21-50) that it will use for recursion:
PortableInterceptor::SlotId recurseId =orb_init_info.allocate_slot_id ();
At the point at which it recurses, say in send_request, it does so in a manner similar to the following:
any recurse = info.get_slot (recurseId);
// if we haven’t yet recursed, then the slot will be empty.if (recurse.type () == tk_null){
// Fill in the recurse slot before making// the recursive call.any recurseFlag = new any;recurseFlag.insert_boolean (true);PortableInterceptor::Current pic =
orb.resolve_initial_references (“PICurrent?);
pic.set_slot (recurseId, recurseFlag);
// Now make the recursive call.someObject.someOperation ();
}
When a client calls operation X, send_request is invoked for operation X. The recurse slot is empty, so the if block is executed:
the recurse slot is set to true for this thread’s PICurrent and the recursive call to someOperation is made. send_request
is again invoked, this time for someOperation. This time the recurse slot is not empty, so the if block is not executed and
the recursive call is not made, thus breaking the recursion.
21.4.4.3 Server-side use of PICurrent
The service contexts associated with the request may be propagated, using PICurrent, to the context of the thread that will
execute the operation. The request’s PICurrent is read and written via the get_slot and set_slot operations on ServerRequestInfo.
receive_request_service_contexts shall populate the slots of the request scope PICurrent. The ORB logically copies this PICurrent
to the thread scope after processing the receive_request_service_contexts list.
When the operation invocation completes, the send interception points still have read/write access to the request scope PICurrent.
For example, within its ORBInitializer
(see Section 21.7.1, “ORBInitializer
Interface,? on page 21-50), the transaction service allocates a slot:
PortableInterceptor::SlotId mySlotId =orb_init_info.allocate_slot_id ();
The Transaction Interceptor can move the transaction information from the service context list to PICurrent:
IOP::ServiceContext sc =
info.get_request_service_context (transactionId);
any myData = // convert SC to an any
info.set_slot (mySlotId, myData);
Within a server thread, the Transaction service can transfer its information from PICurrent to the TransactionCurrent:
PortableInterceptor::Current pic =
orb.resolve_initial_references (“PICurrent?);
any myData = pic.get_slot (mySlotId);
// Copy myData into the current context.
21.4.4.4 Request Scope vs Thread Scope
The thread scope PICurrent is the PICurrent that exists within a thread’s context. A request scope PICurrent is the PICurrent
associated with the request. On the client-side, the thread scope PICurrent is logically copied to the request scope PICurrent
from the thread’s context when a request begins and is attached to the ClientRequestInfo object. On the server-side, the request
scope PICurrent is attached to the ServerRequestInfo and follows the request processing. It is logically copied to the thread
scope PICurrent after the list of receive_request_service_contexts interception points are processed.
21.4.4.5 Flow of PICurrent between Scopes
For the following, TSC means Thread Scope PICurrent; and RSC means Request Scope PICurrent.
Refer to Figure 21-7 on page 21-39 for a graphical representation
of the following discussion. The numbered points below correspond to the numbers in
Figure 21-7.
Before operation invocation, the client thread may read and write the TSC. On an operation invocation, the flow proceeds as
follows:
1. The invocation proceeds to the ORB.
2. Before the sending interception points are called, a TSC is logically copied to the request scope.
3. The sending interception points are called. They have read-only access to this RSC. They may add entries to the service context list based on the slot data in the RSC.
4. On the server, an empty RSC is created. Interceptors shall populate this RSC from the service context list in receive_request_service_contexts.
5. The ORB logically copies the RSC to the server-side TSC after the receive_request_service_contexts points are processed and before the servant manager is called. This TSC is within the context for the receive_request points, the invocation of the servant manager, and the invocation of the target operation. The receive_request points may modify the RSC, but this no longer affects the TSC. The receive_request points are called. These points have access to the RSC
- though modifying the RSC at this point has no affect on the TSC. Since these points execute in the same thread as the target
operation invocation, these points may modify the server-side TSC.
6. After the receive_request points are called, control transfers to the server threads which may also read and write this server-side TSC.
7. The target operation invocation completes and control returns to the ORB.
8. The TSC from the thread on which the ORB invoked the target operation is copied back to the RSC, overwriting the slots in the RSC.
9. The send interception points have access to this RSC from which they may populate the reply service context list. After the invocation result is sent back to the client, the server-side RSC is logically destroyed.
10. The client receives the reply. The Interceptors may read the service contexts associated with the reply. They also have readonly access to the RSC was seen by the send interception points.
11. The invocation returns to the client. When the request completes, the client-side RSC is logically destroyed.
Figure 21-7 Thread Scope vs Request Scope
Figure 21-7 Legend
Dotted Line Flow of control (between the thread scopes and the request scopes, the dotted arrows indicate a logical copy).
Solid Line Access; single arrow is readonly, double arrow is read/write.
Thick Dotted Line Boundary between client and server.
21.4.4.6 Notes on PICurrent and Scopes
Since an Interceptor is running in a thread, it is running with a thread context and there is a PICurrent on that context.
If the Interceptor calls ORB::resolve_initial_references (“PICurrent?), it gets the PICurrent within its thread scope. This
PICurrent is different than the request scope PICurrent that the Interceptor obtains via calls to the Client-or Server- RequestInfo
object. So if an Interceptor makes an operation call, it is the Interceptor’s thread scope PICurrent that will be logically
copied to the request scope of that operation, not the PICurrent from the original operation invocation.
Even if a client-side Interceptor happens to be running in the same thread from which the invocation was made (this is vendor
dependent), the request scope PICurrent and the thread scope PICurrent are still different. The request scope PICurrent is
a copy of the thread scope PICurrent at the point when the invocation began. So even if an Interceptor changed the data in
its thread scope PICurrent, that does not change the request scope PICurrent.
Interceptors shall assume that each client-side interception point logically runs in its own thread, with no context relationship
between it and any other thread. While an ORB implementation may not actually behave in this manner, it is up to the ORB implementation
to treat PICurrent as if it did.
Interceptors shall assume that all server-side interception points except receive_request_service_contexts run in the same
thread as the target operation invocation, thereby sharing thread context information. receive_request_service_contexts, like
all client-side interception points, logically runs in its own thread, with no context relationship between it and any other
thread.