|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
In my series on enterprise CORBA development using J2SE (Java 2 Platform, Standard Edition) 1.4, Part 1 served as a gentle introduction to CORBA and J2SE 1.4's enterprise CORBA features. Parts 2 and 3 provided a thorough treatment of the Portable Object Adapter (POA) and its role in creating enterprise applications that perform and scale with CORBA. In this concluding article, I discuss portable interceptors and the Interoperable Naming Service (INS). Portable interceptors provide standard hooks into the ORB (object request broker) runtime and offer a mechanism for plugging in additional ORB behavior or even modifying existing ORB behavior. The Interoperable Naming Service (INS) is a URL-based naming system built on top of the CORBA Naming Service. It specifies a common bootstrap mechanism that lets applications share a common initial naming context across ORB vendor providers.
Read the whole series, "J2SE 1.4 Breathes New Life into the CORBA Community:"
Portable interceptors are hooks into the ORB that allow ORB services to intercept, at well-defined points, the ORB's normal flow of execution. Two types of interceptors can be registered:
IORInterceptor: Sometimes, so the client's ORB service implementation will function properly, a portable ORB service implementation might
need to add information describing the server's or object's ORB service-related capabilities to object references. The IORInterceptor and IORInfo interfaces support that functionality. The IORInterceptor establishes tagged components in the profiles within an interoperable object reference (IOR).
RequestInterceptor: A request interceptor intercepts the flow of a request/reply sequence through the ORB at specific points so that services
can query the request information and manipulate the service contexts, which propagate between clients and servers. Request
interceptors are primarily used for enabling ORB services to transfer context information between clients and servers. Two
types of request interceptors exist:
ClientRequestInterceptor intercepts the flow of a request/reply sequence through the ORB on the client side.
ServerRequestInterceptor intercepts the flow of a request/reply sequence through the ORB on the server side.
To show you how to use interceptors, I created a simple logging service based on request interceptors:
package hello;
import org.omg.CORBA.Any;
import org.omg.CORBA.ORB;
import org.omg.CORBA.TCKind;
import org.omg.IOP.ServiceContext;
import org.omg.PortableInterceptor.*;
import org.omg.Dynamic.Parameter;
import java.util.logging.Logger;
public class LoggingServiceInterceptor extends org.omg.CORBA.LocalObject
implements ClientRequestInterceptor, ServerRequestInterceptor
{
private Current piCurrent;
private int outCallIndicatorSlotId;
private Logger logger = Logger.getLogger("hello.LoggingServiceInterceptor");
public LoggingServiceInterceptor(Current piCurrent, int outCallIndicatorSlotId)
{
this.piCurrent = piCurrent;
this.outCallIndicatorSlotId = outCallIndicatorSlotId;
}
public String name()
{
return "LoggingServiceInterceptor";
}
public void destroy()
{
}
//
// ClientRequestInterceptor operations
//
public void send_request(ClientRequestInfo ri)
{
log(ri, "send_request");
}
public void send_poll(ClientRequestInfo ri)
{
log(ri, "send_poll");
}
public void receive_reply(ClientRequestInfo ri)
{
log(ri, "receive_reply");
}
public void receive_exception(ClientRequestInfo ri)
{
log(ri, "receive_exception");
}
public void receive_other(ClientRequestInfo ri)
{
log(ri, "receive_other");
}
// Server interceptor methods
public void receive_request_service_contexts(ServerRequestInfo ri)
{
log(ri, "receive_request_service_contexts");
}
public void receive_request(ServerRequestInfo ri)
{
log(ri, "receive_request");
}
public void send_reply(ServerRequestInfo ri)
{
log(ri, "send_reply");
}
public void send_exception(ServerRequestInfo ri)
{
log(ri, "send_exception");
}
public void send_other(ServerRequestInfo ri)
{
log(ri, "send_other");
}
//
// Utilities
//
public void log(RequestInfo ri, String point)
{
// IMPORTANT: Always set the TSC outcall indicator in case
// other interceptors make outcalls for this request.
// Otherwise the outcall will not be set for the other interceptor's
// outcall, resulting in infinite recursion.
Any indicator = ORB.init().create_any();
indicator.insert_boolean(true);
try {
piCurrent.set_slot(outCallIndicatorSlotId, indicator);
} catch (InvalidSlot e) { }
try {
indicator = ri.get_slot(outCallIndicatorSlotId);
// If the RSC outcall slot is not, set then log this invocation.
// If it is, set that indicates the interceptor is servicing the
// invocation of loggingService itself. In that case, do
// nothing (to avoid infinite recursion).
if (indicator.type().kind().equals(TCKind.tk_null)) {
logger.info(point + "::" + ri.request_id() + "::" + ri.operation());
}
} catch (InvalidSlot e) {
System.out.println("Exception handling not shown.");
}
}
}
The implementation is fairly straightforward. The LoggingServiceInterceptor class extends org.omg.CORBA.LocalObject to ensure that an instance of this class does not get marshalled, since an interceptor instance is intimately tied to the
ORB with which it is registered. LoggingServiceInterceptor also implements the ClientRequestInterceptor and ServerRequestInterceptor interfaces, which indicate that both clients and servers can use the same logging service. All interface methods delegate
the real work to the log() method, which logs a message using the J2SE 1.4 logging facility. Reading the comments, you see that I have done some extra
work to avoid potential infinite recursion, in which the logging service keeps calling the log() method.
The class ORBInitializer (actually a class that implements the ORBInitializer interface) facilitates interceptor registration and ORB initialization. As I mentioned before, interceptors are intended
to be a means by which ORB services (such as the logging service created above) access ORB processing, thus effectively becoming
part of the ORB. Therefore, by the time the init() method call on the ORB class returns an ORB instance, the interceptors have already been registered. It follows that interceptors
cannot be registered with an ORB instance returned from the init() method call.
In J2SE 1.4, ORBInitializers can be registered via Java ORB properties. The property names take the following form: org.omg.PortableInterceptor.ORBInitializerClass.<Service>, where <Service> is the string name of a class that implements org.omg.PortableInterceptor.ORBInitializer. Hence, to register an interceptor, create an associated ORBInitializer class that implements the ORBInitializer interface and register this initializer via a Java ORB property. One such initializer for the logging service is shown below:
package hello;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.PortableInterceptor.*;
import java.util.logging.Logger;
public class LoggingServiceORBInitializer extends org.omg.CORBA.LocalObject
implements org.omg.PortableInterceptor.ORBInitializer
{
public LoggingServiceORBInitializer()
{
Logger logger = Logger.getLogger("hello.LoggingServiceORBInitializer");
logger.info("LoggingServiceORBInitializer::Constructor called");
}
public void pre_init(ORBInitInfo info)
{
Logger logger = Logger.getLogger("hello.LoggingServiceORBInitializer");
logger.info("LoggingServiceORBInitializer::pre_init called");
}
public void post_init(ORBInitInfo info)
{
Logger logger = Logger.getLogger("hello.LoggingServiceORBInitializer");
logger.info("LoggingServiceORBInitializer::post_init called");
try {
Current piCurrent = CurrentHelper.narrow(info.resolve_initial_references("PICurrent"));
// Allocate a slot id to use for the interceptor to indicate
// that it is making an outcall. This is used to avoid
// infinite recursion.
int outCallIndicatorSlotId = info.allocate_slot_id();
// Create (with the above data) and register the client
// side interceptor.
LoggingServiceInterceptor interceptor =
new LoggingServiceInterceptor(piCurrent, outCallIndicatorSlotId);
info.add_client_request_interceptor(interceptor);
info.add_server_request_interceptor(interceptor);
} catch (Throwable t) {
System.out.println("Exception handling not shown.");
}
}
}
During the ORB initialization (that is, the init() method call), the ORB runtime collects the ORB properties that begin with org.omg.PortableInterceptor.ORBInitializerClass; each property's <Service> portion is extracted; an initializer object is instantiated with the <Service> string as its class name; and the pre_init() and post_init() methods are called on the initializer object. If any exceptions occur, the ORB ignores them and proceeds with further initialization.