CORBA Metaprogramming Mechanisms, Part 1

This column describes the key concepts and components associated with CORBA Portable Interceptors.


March 01, 2003
URL:http://www.drdobbs.com/corba-metaprogramming-mechanisms-part-1/184403860

March 2003/Object Interconnections



CORBA middleware has been used successfully in domains ranging from telecommunications to aerospace, process automation, and e-commerce to enable developers to create applications rapidly that can meet a particular set of requirements with a reasonable amount of effort. Historically, however, many CORBA solutions have tightly coupled interfaces and implementations, which make it hard to adapt to requirement or environment changes that occur late in an application's life cycle (i.e., during deployment and/or at run time). To address this problem, CORBA supports metaprogramming mechanisms [1] that improve the adaptability of distributed applications by allowing their behavior to be modified with little or no change to existing application software.

This column describes CORBA Portable Interceptors, which are objects that an ORB invokes in the path of an operation invocation to monitor or modify the behavior of the invocation transparently. Portable Interceptors are a metaprogramming mechanism that implements the Interceptor pattern [2, 3], which allows applications to extend and control the behavior of a framework. Since the CORBA Portable Interceptor specification is fairly large, we focus on concepts and components in this column and defer our C++ programming examples until the next column. Subsequent columns will then discuss other CORBA metaprogramming mechanisms, such as extensible transports and smart proxies.

Overview of CORBA Metaprogramming Mechanisms

CORBA middleware provides stub and skeleton mechanisms that serve as a "glue" between the client and servants, respectively, and the ORB. CORBA stubs implement the Proxy pattern [4] and marshal operation information and data type parameters into a standardized request format. Likewise, CORBA skeletons implement the Adapter pattern [4] and demarshal the operation information and typed parameters stored in the standardized request format.

CORBA stubs and skeletons can be generated automatically from interfaces defined using OMG IDL. A CORBA IDL compiler transforms application-supplied OMG IDL definitions into stubs and skeletons written using a particular programming language, such as C++ or Java. In addition to providing programming language and platform transparency, an IDL compiler eliminates common sources of network programming errors and provides opportunities for automated compiler optimizations [5].

Traditionally, the stubs and skeletons generated by an IDL compiler are fixed (i.e., the code emitted by the IDL compiler is determined at translation time). This design shields application developers from the tedious and error-prone network programming details needed to transmit client operation invocations to server object implementations. Fixed stubs and skeletons make it hard, however, for applications to adapt readily to certain types of changes in requirement or environmental conditions, such as:

In applications based on CORBA middleware with conventional fixed stubs/skeletons, these types of changes often require reengineering and restructuring of existing application software. One way to minimize the impact of these changes is to employ metaprogramming mechanisms that allow applications to adapt to various types of changes with little or no modifications to existing software. For example, stubs, skeletons, and certain other points in the end-to-end operation invocation path can be treated as meta-objects [1], which are objects that refine the capability of base-level objects that comprise the bulk of application programs.

As shown in Figure 1, CORBA ORBs are responsible for transmitting client operation invocations to target objects. When a client invokes an operation, a stub implemented as a meta-object can act in conjunction with transport-protocol meta-objects to access and/or transform a client operation invocation into a message and transmit it to a server. Corresponding meta-objects on the server's request processing path can access and/or perform inverse transformations on the operation invocation message and dispatch the message to its servant. An invocation result is delivered in a similar fashion in the reverse direction.

As all operation invocations pass through meta-objects, certain aspects of application and middleware behavior can be adapted transparently when system requirements and environmental conditions change by simply modifying the meta-objects. To modify meta-objects, the DOC middleware can either (1) provide mechanisms for developers to install customized meta-objects for the client or (2) embed hooks implementing a MOP (meta-object protocol) [1] in the meta-objects and provide mechanisms to install objects implementing the MOP to strategize these meta-object behaviors. In the context of CORBA, there are various mechanisms that can implement the MOP:

This column focuses on Portable Interceptors; Servant Managers were described in [6]. Future columns in this series will cover Smart Proxies and Extensible Transports.

Overview of Portable Interceptors

As outlined above, CORBA Portable Interceptors are a metaprogramming mechanism that can increase the flexibility of client and server applications. Portable Interceptors are standard meta-objects that stubs, skeletons, and certain points in the end-to-end operation invocation path can invoke at predefined "interception points." Two types of interceptors are defined in the CORBA Portable Interceptor specification:

We describe both types of interceptors in this section.

Request Interceptors

Request interceptors can be decomposed into client request interceptors and server request interceptors, which are designed to intercept the flow of a request/reply sequence through the ORB at specific points on clients and servers, respectively. Developers can install instances of these interceptors into an ORB via an IDL interface defined by the CORBA Portable Interceptor specification. Regardless of what interface or operation is invoked, after request interceptors are installed they will be called on every operation invocation at the predetermined ORB interception points shown in Figure 2.

As shown in Figure 2, request interception points occur at four points along the end-to-end invocation path from client to server. There are a total of 10 different interception hook methods that can be called at different points in this interceptor chain, including:

Compared to a client invocation path, a server invocation path has an additional interception point called receive_request_service_contexts(), which is invoked before the POA dispatches a servant manager. This interception point prevents unnecessary upcalls to a servant. For example, in the CORBA Security Service [7] framework this interception point can be used to inspect security-related credentials piggybacked in a service context list entry. If the credentials are valid, the upcall can proceed to other interceptors (if they exist) or to the servant; if not, an exception will be returned to the client.

Application developers can customize the behavior of their software at interception points as follows:

  1. Subclass from the appropriate base class, such as PortableInterceptor::ClientRequestInterceptor or PortableInterceptor::ServerRequestInterceptor, and overriding the appropriate hook method(s), such as send_request() or receive_request().
  2. Creating an instance of the subclass and registering it with the ORB. Interceptors are installed in the ORB via an ORBInitializer object and registered by implementing its pre_init() or post_init() method and calling PortableInterceptor::register_orb_initializer() prior to calling CORBA::ORB_init().

At run time, an interceptor can examine the state of the request that it is associated with and perform various actions based on the state. For example, interceptors can invoke other CORBA operations, access information in a request, insert/extract piggybacked messages in a request's service context list, redirect requests to other target objects, and/or throw exceptions based on the object the original request is invoked upon and the type of the operation. Each of these capabilities is described below:

IOR Interceptors

IIOP v1.1 introduced an attribute called components, which contains a list of tagged components to be embedded within an IOR. When an IOR is created, tagged components provide a placeholder for an ORB to store extra information pertinent to the object. This information can contain various types of QoS information related to security, server thread priorities, network connections, CORBA policies, or other domain-specific information.

The original IIOP v1.0 specification provided no standard way for applications or services to add new tagged components into an IOR. Services that require this field were therefore forced to use proprietary ORB interfaces, which impeded their portability. The Portable Interceptors specification resolves this problem by defining IOR interceptors.

IOR interceptors are objects invoked by the ORB when it creates IORs. They allow an IOR to be customized (e.g., by appending tagged components). Whereas request interceptors access operation-related information via RequestInfos, IOR interceptors access IOR-related information via IORInfos. Figure 3 illustrates the behavior of IOR interceptors.

A server ORB that is responsible for creating an IOR contains an IOR interceptor repository. In turn, this repository contains a series of IOR interceptors that have been registered with the ORB. When the server process requests the ORB to create an IOR, the ORB iterates through the IOR interceptors in the repository using the establish_components() operation. The IOR interceptors then add tagged components to the IOR being generated by referring to the IORInfo passed in by calling add_ior_component() or add_ior_component_to_profile().

Concluding Remarks

CORBA shields developers from many tedious and error-prone aspects of programming distributed applications. Without proper support from the middleware, however, it can be hard to evolve distributed applications after they are deployed. This column has discussed how the concepts and components in the CORBA Portable Interceptors specification help the adaptability of distributed applications by allowing their behavior to be modified without changing existing software drastically. Interceptors can be applied to either servers or clients and can access operation-specific information. They therefore provide an effective metaprogramming mechanism to handle advanced features, such as authentication and authorization, transparently end-to-end.

This column concludes the introduction to our multi-part series on CORBA metaprogramming mechanisms. Our next column will illustrate how to program Portable Interceptors using C++. Subsequent columns will cover other CORBA metaprogramming mechanisms. As always, if you have comments, questions, or suggestions regarding CORBA or our column in general, please let us know at [email protected].

References

[1] Nanbor Wang, Douglas C. Schmidt, Ossama Othman, and Kirthika Parameswaran. "Evaluating Metaprogramming Mechanisms for ORB Middleware," IEEE Communication Magazine, October 2001.

[2] Douglas C. Schmidt, Michael Stal, Hans Rohnert, and Frank Buschmann. Pattern-Oriented Software Architecture: Patterns for Concurrent and Networked Objects (Wiley and Sons, 2000).

[3] Steve Vinoski. "Toward Integration: Chain of Responsibility," IEEE Internet Computing, November/December 2002, pp. 80-83.

[4] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1995).

[5] Eric Eide, Kevin Frei, Bryan Ford, Jay Lepreau, and Gary Lindstrom. "Flick: A Flexible, Optimizing IDL Compiler," Proceedings of ACM SIGPLAN '97 Conference on Programming Language Design and Implementation (PLDI), Las Vegas, NV, June 1997.

[6] Douglas C. Schmidt and Steve Vinoski. "C++ Servant Managers for the Portable Object Adapter," C++ Report, September 1998.

[7] Object Management Group. "Security Service Specification," OMG Document formal/02-03-11version 1.8, March 2002.

[8] Steve Vinoski and Douglas C. Schmidt. "Object Interconnections: Dynamic CORBA: Part 1, The Dynamic Invocation Interface," C/C++ Users Journal C++ Experts Forum, July 2002, <www.cuj.com/experts/2007/vinoski.htm>.

[9] Steve Vinoski and Douglas C. Schmidt. "Object Interconnections: Dynamic CORBA: Part 2, Dynamic Any," C/C++ Users Journal C++ Experts Forum, September 2002, <www.cuj.com/experts/2009/vinoski.htm>.

[10] Steve Vinoski and Douglas C. Schmidt. "Object Interconnections: Dynamic CORBA: Part 3, The Dynamic Skeleton Interface," C/C++ Users Journal C++ Experts Forum, November 2002, <www.cuj.com/experts/2011/vinoski.htm>.

[11] Ossama Othman, Carlos O'Ryan, and Douglas C. Schmidt. "An Efficient Adaptive Load Balancing Service for CORBA," IEEE Distributed Systems Online, March 2001.

[12] Object Management Group. "The Common Object Request Broker: Architecture and Specification Revision 3.0," OMG Technical Document formal/XYZ02-06-33, July 2002.

[13] Michi Henning and Steve Vinoski. Advanced CORBA Programming with C++ (Addison-Wesley, 1999).

About the Author

Steve Vinoski is vice president of Platform Technologies and chief architect for IONA Technologies and is also an IONA Fellow. A frequent speaker at technical conferences, he has been giving CORBA tutorials around the globe since 1993. Steve helped put together several important OMG specifications, including CORBA 1.2, 2.0, 2.2, and 2.3; the OMG IDL C++ Language Mapping; the ORB Portability Specification; and the Objects By Value Specification. In 1996, he was a charter member of the OMG Architecture Board. He is currently the chair of the OMG IDL C++ Mapping Revision Task Force. He and Michi Henning are the authors of Advanced CORBA Programming with C++, published in January 1999 by Addison Wesley Longman. Steve also represents IONA in the W3C (World Wide Web Consortium) Web Services Architecture Working Group.

Doug Schmidt is a full professor at Vanderbilt University. His research focuses on patterns, optimization principles, model-based software development, and empirical analyses of object-oriented techniques that facilitate the development of high-performance, real-time distributed object computing middleware on parallel processing platforms running over high-speed networks and embedded-system interconnects. He is the lead author of the books Pattern-Oriented Software Architecture: Patterns for Concurrent and Networked Objects, published by Wiley and Sons, and C++ Network Programming: Mastering Complexity with ACE and Patterns and C++ Network Programming: Systematic Reuse with ACE and Frameworks both published by Addison-Wesley. He can be contacted at [email protected].

March 2003/Object Interconnections/Figure 1

Figure 1: CORBA ORBs are responsible for transmitting client operation invocations to target objects

March 2003/Object Interconnections/Figure 2

Figure 2: Request interception points occur at four points along the end-to-end invocation path from client to server

March 2003/Object Interconnections/Figure 3

Figure 3: The behavior of IOR interceptors

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.