![]() ![]() ![]() ![]() ![]() ![]() ![]() |
Developing a CORBA request-level interceptor typically involves the following steps:
Also identify the machines on which you plan to deploy the interceptors.
The preceding steps are usually iterative. For example, the first time you build and test your interceptor, you might have only the most basic code in the interceptor that merely verifies that the interceptor is running. With subsequent builds and tests, you gradually implement the full functionality of the interceptor.
The sections that follow explain each of these steps in detail, using the sample interceptors packaged with the Oracle Tuxedo software for examples.
Notes: | The Oracle Tuxedo CORBA Java client and Oracle Tuxedo CORBA Java client ORB were deprecated in Tuxedo 8.1 and are no longer supported. All Oracle Tuxedo CORBA Java client and Oracle Tuxedo CORBA Java client ORB text references, associated code samples, should only be used to help implement/run third party Java ORB libraries, and for programmer reference only. |
Note: | Technical support for third party CORBA Java ORBs should be provided by their respective vendors. Oracle Tuxedo does not provide any technical support or documentation for third party CORBA Java ORBs. |
Deploying an interceptor on a given machine constitutes a significant overhead because that interceptor will be invoked every time any application on that machine issues (in the case of a client-side interceptor) or receives (target-side interceptor) a request. Therefore, any interceptor you create must be well-matched to those applications.
For example, a security interceptor typically needs to know about what kinds of requests are of concern, and what kinds of data are being handled in the request.
Any interceptor that deals with specific requests needs to be able to extract the interface repository ID from the request. With that interface knowledge, the interceptor then has a way of knowing what kind of data is in the request, and can then handle that data in a request-specific fashion.
In addition, if a request is sent that is not of interest, the interceptor needs to be able to pass the request through quickly and efficiently.
The PersonQuery example described in
PersonQuery Sample Application, uses an interceptor that determines whether the user of the PersonQuery client application can receive addresses. If the identity of the user matches specific criteria, the interceptor allows the full address number to be returned to the client. If no match exists, the interceptor returns only the string of x
characters to the log file in place of the address.
The topics that follow discuss implementation considerations that may be typical of many interceptors. Examples from the InterceptorData interceptors, which are described in InterceptorData Sample Interceptors, are provided.
You can use the code fragments included in Appendix A as a place to start implementing your interceptor. You may use the code included in Appendix A, or you may copy the following starter files available at the WebLogic Enterprise Developer Center on the Oracle Web site:
Interceptor header starter file. The contents of this file, and instructions for using it, are in the section "Step 3: Create the Interceptor Header File" on page -7.
|
|
For information about getting these starter files from the WebLogic Enterprise Developer Center, see the Release Notes.
You can start your interceptor implementation using the sample interceptor code provided in Appendix A, where YourInterceptor
represents the name of the interceptor you are implementing. The ORB will always pass nil references for the ServiceContextList
and CORBA::DataOutputStream
parameters. You should not use or reference those parameters. You should not test those parameters for nil
because this restriction may change in a future version.
All interceptors are instantiated when the ORB is initialized. At no other time are request-level interceptors instantiated. As part of initializing, the interceptor’s initialization routine must instantiate an instance of an implementation for a client interceptor, or a target interceptor, or both, depending upon what the interceptor intends to support. As mentioned earlier, a single shareable image can support both the client-side and target-side interceptors. The instances of any interceptor instantiated are then returned from the initialization routine and registered with the ORB run time.
The following code fragment is from the InterceptorData interceptor, and shows the declaration of the initialization operation invoked by the client-side ORB when that ORB is initialized:
void InterceptorDataClientInit(
CORBA::ORB_ptr TheORB,
RequestLevelInterceptor::ClientRequestInterceptor ** ClientPtr,
RequestLevelInterceptor::TargetRequestInterceptor ** TargetPtr,
CORBA::Boolean * RetStatus)
The following code fragment shows the statements to instantiate the InterceptorData client interceptor class. Note that this fragment uses a class named tracker
, which is used for keeping track of each incoming client request so that it can be matched with the response returned by the target object. The tracker class is described in the section "Identifying Operations in the Request" on page -5.
ClientInterceptorData * client = new ClientInterceptorData(TheORB, tracker);
if (!client)
{
tmpfile << "InterceptorDataClientInit: Client alloc failed"
<< endl << endl;
*RetStatus = CORBA_FALSE;
delete tracker;
return;
}
The following code fragment shows the statements to return the interceptor class to the ORB:
*ClientPtr = client;
*TargetPtr = 0;
*RetStatus = CORBA_TRUE;
return;
If you have an interceptor that works with specific interfaces or requests, the interceptor needs a way to extract the interface ID associated with a request so that the interceptor can identify it and thus know how to handle the data in the request. For example, the InterceptorData interceptor manipulates the request parameters sent in requests from the PersonQuery application. To manipulate the request parameters, the interceptor needs to know which request is being sent.
The following code fragment from the InterceptorData sample shows the interface ID extracted from the RequestContext structure:
if (strcmp(request_context.interface_id.in(),
PersonQuery::_get_interface_name()) != 0)
return ret_status;
Using the extracted interface ID, the InterceptorData sample uses a simple switch
statement to identify the operation in the client request. That way, the interceptor will know what do with the request parameters contained in the request.
The following code fragment shows the switch statement that checks for either the Exit
operation or the operation to query the database for a person by name. Note the use of the parser
object, which extracts operations from the request retrieved from the tracker
object.
m_outfile << “ Operation: “ << request_context.operation << endl;
PQ parser;
PQ::op_key key = parser.MapOperation(request_context.operation.in());
switch (key)
{
default:
m_outfile << “ ERROR: operation is not member of “
<< request_context.interface_id.in() << endl;
excep_val = new CORBA::BAD_OPERATION();
return Interceptors::REPLY_EXCEPTION;
case PQ::Exit:
m_outfile << endl;
return ret_status;
case PQ::ByPerson:
{
PersonQuery::Person per;
parser.GetByPerson(request_arg_stream, &per);
m_outfile << “ Parameters:” << endl;
m_outfile << per << endl;
}
break;
Extracting an interface ID out of a client request is fairly straightforward. However, it’s not quite as simple to do that with a target response. If an interceptor needs to know what interface and operation is associated with the response it receives from the ORB, it needs to have special logic for tracking requests. It is the interceptor’s responsibility to track requests coming from the client.
The InterceptorData samples implement a language object, called Tracker
, that keeps a record of the target-bound requests, and then matches the target responses to them when those responses arrive back at the interceptor.
The client_response
and target_response
operations on the InterceptorData samples extract interface and operation information from the Tracker
object when responses are returned from the target.
The following InterceptorData code fragment extracts the request associated with a response:
RequestInfo * req_info = m_tracker->CompleteRequest(reply_context);
if (!req_info)
{
m_outfile << “ unable to find request for this reply (must not be one
we care about)” << endl << endl;
return Interceptors::RESPONSE_NO_EXCEPTION;
}
//
// This is the interface we are expecting. Now identify the operation
// being invoked, so we can parse the request parameters.
//
m_outfile << “ ReplyStatus: “;
OutputReplyStatus(m_outfile, reply_context.reply_status);
m_outfile << endl;
m_outfile << “ Interface: “ << req_info->intf() << endl;
m_outfile << “ Operation: “ << req_info->op() << endl;
PQ parser;
PQ::op_key key = parser.MapOperation(req_info->op());
Now that the interceptor has obtained the request associated with the response, the interceptor can handle the data in the response appropriately.
The following code fragment shows an example of how the InterceptorData sample places the request parameters from a data stream into a structure. The parameter S
in the following code fragment represents a pointer to a DataInputStream
structure that can be used by the interceptor implementation to retrieve the value of the reply parameters of the PersonQuery operation. The code encapsulated by the braces in this code fragment extracts the parameters of the response from the DataInputStream
structure. For more information about the DataInputStream
structure, see
Request-Level Interceptor API.
void PQ::get_addr(CORBA::DataInputStream_ptr S,
PersonQuery::Address *addr)
{
addr->number = S->read_short();
addr->street = S->read_string();
addr->town = S->read_string();
addr->state = S->read_string();
addr->country = S->read_string();
}
Exceptions from interceptors returned via the excep_val
parameter can only be a derived type from the CORBA::SystemException
base class. (Any other exception type that the interceptor implementations return to the ORB is converted by the ORB to a CORBA::UNKNOWN
exception, which is passed via the excep_val
parameter.) You need to map exceptions to a CORBA::SystemException
class or one of its derivatives.
After you have created any implementation code in the interceptor implementation file, you need to provide any data or operations as needed to the interceptor header file.
The following code example shows basic information that is required in the header file for an interceptor implementation file that implements both client- and target-side interceptors.
In this code example, YourInterceptor
represents the name of the interceptor you are creating.
#include <CORBA.h>
#include <RequestLevelInterceptor.h>
#include <security_c.h> //for security
class YourInterceptorClient : public virtual RequestLevelInterceptor::ClientRequestInterceptor
{
private:
YourInterceptorClient() {}
CORBA::ORB_ptr m_orb;
public:
YourInterceptor
Client(CORBA::ORB_ptr TheOrb);
~YourInterceptor
Client() {}
Interceptors::ShutdownReturnStatus shutdown(
Interceptors::ShutdownReason reason,
CORBA::Exception_ptr & excep_val);
CORBA::String id();
void exception_occurred (
const RequestLevelInterceptor::ReplyContext & reply_context,
CORBA::Exception_ptr excep_val);
Interceptors::InvokeReturnStatus client_invoke (
const RequestLevelInterceptor::RequestContext & request_context,
RequestLevelInterceptor::ServiceContextList_ptr service_context,
CORBA::DataInputStream_ptr request_arg_stream,
CORBA::DataOutputStream_ptr reply_arg_stream,
CORBA::Exception_ptr & excep_val);
Interceptors::ResponseReturnStatus client_response (
const RequestLevelInterceptor::ReplyContext & reply_context,
RequestLevelInterceptor::ServiceContextList_ptr service_context,
CORBA::DataInputStream_ptr arg_stream,
CORBA::Exception_ptr & excep_val);
};
classYourInterceptor
Target : public virtual RequestLevelInterceptor::TargetRequestInterceptor
{
private:
YourInterceptor
Target() {}
CORBA::ORB_ptr m_orb;
SecurityLevel1::Current_ptr m_security_current; //for security
Security::AttributeTypeList * m_attributes_to_get; //for security
public:
YourInterceptor
Target(CORBA::ORB_ptr TheOrb);
~YourInterceptor
Target();
Interceptors::ShutdownReturnStatus shutdown(
Interceptors::ShutdownReason reason,
CORBA::Exception_ptr & excep_val);
CORBA::String id();
void exception_occurred (
const RequestLevelInterceptor::ReplyContext & reply_context,
CORBA::Exception_ptr excep_val);
Interceptors::InvokeReturnStatus target_invoke (
const RequestLevelInterceptor::RequestContext & request_context,
RequestLevelInterceptor::ServiceContextList_ptr service_context,
CORBA::DataInputStream_ptr request_arg_stream,
CORBA::DataOutputStream_ptr reply_arg_stream,
CORBA::Exception_ptr & excep_val);
Interceptors::ResponseReturnStatus target_response (
const RequestLevelInterceptor::ReplyContext & reply_context,
RequestLevelInterceptor::ServiceContextList_ptr service_context,
CORBA::DataInputStream_ptr arg_stream,
CORBA::Exception_ptr & excep_val);
};
Interceptors are built into shareable libraries. Therefore, the steps for building an interceptor are platform-specific. For details about the specific commands and options used to build interceptors on any particular platform, execute the makefile that builds the interceptor sample applications provided with the Oracle Tuxedo software, and view the results of the build in the log file that results from the build.
The command to build the sample interceptors is as follows:
> nmake -f makefile.nt
> make -f makefile.mk
For more information about building and running the sample interceptors provided with the Oracle Tuxedo software, see PersonQuery Sample Application.
Testing an interceptor requires you to perform the following tasks:
For information about registering interceptors, see Deploying CORBA Request-Level Interceptors.
![]() ![]() ![]() |