Previous Up Next

Chapter 15  Meta-information Programming

15.1  What is Meta-information Programming?

In many computer languages, when you write a program, you know at compilation time what data-types you will manipulate and the compiler performs strong type checking to ensure that you access those data-types correctly. Some programming languages defer type checking until runtime. In such languages, there is some meta information (also known as runtime type information) associated with objects; the runtime system of the language uses this information to check that a program accesses objects in a legal way. Some languages that use runtime type checking even allow programmers to inspect an object’s meta information in order to find out what operations the object has and the names and types of its instance variables. This capability is often called introspection or reflection.

The Smalltalk language is famous for its runtime type checking. Java provides compile-time type checking but also provides APIs for the java.lang.Class type that allow runtime type checking (and introspection) to be performed. In contrast, the C programming language does not provide meta information and C++ provides only very limited support for it with its dynamic cast capability.

15.1.1  Uses of Meta-information Programming

Most CORBA programs are written with compile-time knowledge of the IDL data-types that they will manipulate and the IDL interfaces that they will implement and/or invoke upon. However, CORBA also maintains meta information about objects and data-types, and makes it possible to write programs that make use of such meta information. This capability of CORBA is rarely used, but it does make it possible for some very important types of application to be written. For example:

CORBA’s support for meta-information programming is spread over several distinct, but complementary, APIs. These APIs are discussed in the following sections.

15.2  TypeCodes and the Interface Repository

CORBA uses the CORBA::TypeCode type to represent meta information. The kind() operation provided by CORBA::TypeCode returns an enum value that specifies if the TypeCode represents one of the built-in types (long, boolean and so on) or a user-defined type (struct, union, interface and so on). If the TypeCode represents a user-defined type then more operations can be invoked upon it to determine the names and TypeCodes of the members of a struct or union and so on.

A TypeCode provides the meta information required by the ORB runtime system to determine how the bytes within a raw chunk of memory are laid out as the fields/components of a compound data-structure. However, the information provided by TypeCodes is insufficient, by itself, for general-purpose, meta-information programming. For example, a TypeCode does not specify the signatures of operations that are provided by an interface. Neither does a TypeCode provide a list of all the types (and nested modules) that are declared within a module. CORBA complements TypeCodes with the Interface Repository (IFR), which stores this more general meta information.

You can think of the IFR as being a database of meta information about IDL types. This database has a CORBA server “wrapper” around it; it is this wrapper that is called the IFR. The IDL interfaces of the IFR provide operations for storing meta information in the IFR and also operations for querying the contents of the IFR. The IFR organizes the meta information in a manner similar to how the internals of a compiler organize information in a parse tree. Because of this, querying meta information in the IFR is similar to traversing a parse tree in a compiler.

Although CORBA specifies the IDL interface of the IFR, CORBA does not specify how administration of the IFR is performed. Typically, a CORBA product provides a proprietary command-line tool that parses an IDL file and invokes operations on the IFR to store the parsed information in the IFR. The name of this command-line tool varies from one CORBA product to another. With some CORBA products, this tool is a stand-alone utility; with other CORBA products this functionality is provided as a command-line option on the IDL compiler.

The information provided by the IFR subsumes the information provided by TypeCodes. However, each call to the IFR is a remote call so it incurs the performance overhead of network latency. In contrast, querying the information in a TypeCode involves just a local operation call, so this is much faster. A common way to structure a meta information program is to use the APIs of the the IFR to navigate down to the parse-tree node of a particular type and then obtain a TypeCode that allows the details of that type to be examined much more efficiently with just local operation calls.

15.3  The any and DynAny Types

One of the IDL built-in types is called any. This serves a similar purpose to the void* type in C/C++ or the java.lang.Object type in Java: it is a way to pass around data when you do not have any compile-time knowledge of the type of the data. Of course, when doing this you need to have some way of finding out at runtime what is the type of the data. Internally, an any contains the raw data plus a CORBA::TypeCode (Section 15.2) that specifies the data’s type.

The any type is used about as infrequently as the void* type is used in C/C++ or java.lang.Object is used in Java. In other words, it is used extensively for some specialized programming tasks, but is irrelevant for many other, more general-purpose tasks.

When any is used in IDL, it is often used to define a type that holds a name and arbitrary value, as shown in Figure 15.1.

struct NameValuePair { string name; any value; };
Figure 15.1: Use of type any to define a name and value

The IDL compiler generates operations that can be used to insert a user-defined type into an any, to query the type of data inside an any, and a type-safe way to extract data of a specified type from an any. These operations can be used by applications that have been compiled with the stub code (Section 1.4.5) of an IDL file. However, these APIs for inserting values into, and extracting values from, an any can be used only by applications that have been compiled with the stub code of the type that is embedded inside the any.

If an application wants to manipulate data embedded inside an any without being compiled with the relevant stub code then the application must convert the any into a DynAny, which is the base type of a hierarchy of local interfaces (Section 9.1). There are sub-types of DynAny for each IDL construct. For example, there are types called DynStruct, DynUnion, DynSequence and so on.

The operations on the DynAny interfaces allow a programmer to recursively drill down into a compound data-structure that is contained within the DynAny and, in so doing, decompose the compound type into its individual components that are built-in types. Operations on the DynAny interface can also be used to recursively build up a compound data-structure from built-in types.

A DynAny object can be converted to an any, and back again. This is important because many CORBA APIs take parameters of type any instead of DynAny.

15.4  Dynamic Invocation Interface (DII)

The dynamic invocation interface (DII) is a set of APIs that allows a client application to make invocations on an object reference (Chapter 10) without the client application being compiled with the stub code for either the relevant IDL interface or the types passed as parameters. A DII-based client typically does the following:

The DII APIs are used when a client is compiled without knowledge of the IDL interfaces upon which it will make calls. This generally means that the client application does not have much hard-coded “business logic” to dictate what parameter values it should use when making remote calls, or even which operations it should invoke. Instead, the remote invocations made by a DII-based client are typically driven by some external meta-data. Two example uses of DII-based applications—gateways and test clients—were briefly discussed in Section 15.1.1. I now discuss the architecture of a DII-based test client in slightly more detail.

When writing a CORBA server, it is useful to have a simulation client application that can be used to perform ad-hoc testing of the server. A GUI-based “generic” test client could be built using the DII, and it might work as follows.

It is possible to imagine such a GUI that would record the parameter values inputted by the user and then generate a regression testing program that could be rerun independently of the interactive GUI.

15.5  Dynamic Server Interface (DSI)

The dynamic server interface (DSI) is often described as being the server-side equivalent of the DII. It is a set of APIs that allows a server application to process incoming requests on IDL interfaces for which it does not have the relevant stub code or skeleton code. Like the DII, the DSI can be used to build gateways or testing applications. For example, a DSI-based testing server might accept incoming requests and assign values to inout and out parameters based on values it obtains from a random number generator or a configuration file/database.

Previous Up Next