field-theory.org
the blog of wolfram schroers

CORBA for distributed objects

This tutorial belongs to a series on parallel and distributed computing. It focuses on using CORBA for implementing distributed objects. It includes a couple of working code samples that illustrate particular features of the typical work flow. It also lists strengths and possible weaknesses that a developer should be aware of before deciding to use CORBA. The sample codes are also available on the software page for direct download.

Table of contents:

Introduction
Work flow of designing distributed objects
Example CORBA programs
More advanced CORBA topics
Summary and conclusions
References and further reading

Introduction

CORBA is a middleware that supports distributed objects. It is quite complex and possibly more difficult to learn than other communication infrastructures. On the other hand it is extremely powerful and gives access to a lot of functionality including independence of the programming language and the operating system. The bindings to a wide choice of programming languages are standardized as is the format of the communication. The latter feature means that programs written using different CORBA vendors are fully interoperable.

A distinct advantage of CORBA is its level of maturity. CORBA has been standardized by the OMG (Object Management Group). The standard has matured for two decades now (since 1991) and is neither too restrictive (which might limit portability and room for optimization) nor too lax (which endangers interoperability of different products). In fact, it provides a real-world-proven and tested compromise with respect to both flexibility, power and performance.

However, there is also criticism. The main complaint is complexity of the architecture and that the official specification still leaves several implementation details unaddressed. This thread on StackOverflow summarizes different perspectives of developers regarding several practical aspects of CORBA.

It should be pointed out that some of the power CORBA offers targets niche markets. Such features are typically referred to as “vertical” markets. Vertical features are of interest for a specific group of users and/or applications, whereas horizontal features are of interest to all users of a technology. Thus, it is sufficient to only focus on the features that a specific application demands – there is generally no need to know about all of CORBA. This makes the complexity of CORBA less intimidating.

This tutorial is organized as follows: First, we will look at the work flow of designing and implementing a distributed system. Next, we look at a set of four example programs that illustrate particular features of CORBA — the first goes from local to distributed method calls, the second illustrates a more involved interface. We then test the portability and platform independence of CORBA. The last example introduces the Naming service. This article then lists a few advanced features of CORBA. Finally, references and pointers for further reading are given.

Work flow of designing distributed objects

In general, debugging and optimization becomes much more complicated when code is run remotely. This makes a good design of the system imperative! Thus, designing the communication pattern is probably the most important decision; any flaws made in the design phase are substantially more costly when they need to be repaired later on!

In general, the work flow looks as follows:

1. Scrutinize the manner in which objects need to be distributed
This means deciding which functions need to be made available as remote calls and what parameters they take and return. Rules of thumb are: a) Do as much locally as possible. Do not fear redundancy. b) Try to eliminate concurrency as much as possible – any parallelism should be kept independent as much as possible. c) Try to prefer fewer method invocations with more data per invocation over more invocations with less data per transaction.
2. Specify the interface
This means writing the “IDL file” (Interface Definition Language), translating the design you devised in a language-independent interface. This file is translated into a language- and system-dependent binding. Conceptually, the IDL file is similar to a job description – it does not tell who does the job or how it's done. It just says what the responsibilities are.
3. Implement the remote object(s)
If the IDL provides the job description, then this step finds and hires an employee. Note that there may be several people who do the same job; possibly working at different times or for different bosses, maybe even with different reliabilities (I kid you not). Similarly, there may be several objects written in different programming languages that provide a service; the user does not need to care about the details of the implementation. This is in general a merit of the modularization provided by object oriented design and this power naturally carries over to CORBA.
Technical: The calling conventions at this point are fixed by the language mapping. The IDL compiler generates a skeleton file which practically is a template. At this point most coding is done by inserting the business logic into a template.
4. Implement the server(s)
Practically, you need to pick a programming language, find an ORB (Object Request Broker) vendor and then code the server. If you have chosen multiple services in step 3, you need to develop the server for all of them.
Technical: This is not as tough as it sounds; typically, the server merely contains boilerplate initialization, authentication and registration code for the objects already implemented.
5. Design and implement the client(s)
Pick a language and an ORB implementation for the client. Note that this step can be repeated as often as you like for different clients. Different clients may use the same interface just as different servers can provide the same interface. They can all work together transparently. That's the cool part about CORBA!
Technical: Similar to what happened in Step 3, the interface of the remote objects is already defined. Clients import a stub file, paste in some boilerplate initialization code (similar to what the server did) and from then on the remote object looks just like a local one.

In the following we will see how this is done in practice for a series of example programs.

Example CORBA programs

This section links to four parts: First, we present a simple example of a single method that provides an echo service. This example is inspired by the Orbit2 echo example. Next, we present the more complicated interface of a protocol service that extends echo's service to a global enterprise-wide protocol facility. The third case demonstrates how this facility is accessed by clients written in different programming languages and different ORBs. Finally, the fourth case illustrates use of the Naming service, an example of a distributed object that is standardized together with CORBA.

Part I
Going from a local object to a distributed one.
Part II
A more involved distributed application – an enterprise-wide event logging/protocol facility.
Part III
The protocol facility with different ORBs, specifically Orbit2 (using the C programming language) and the Java SDK ORB.
Part IV
The Naming Service allows for enterprise-wide distribution even without a distributed network filesystem.

More advanced CORBA topics

The specific examples given above illustrate a range of uses of CORBA. There are other topics that are useful to have heard about:

Services:
We have already come across the Naming service. The OMG has specified a few other interfaces for services; the implementation is vendor-dependent, i.e., launching a server will proceed differently for each CORBA provider. All these services are defined using the existing CORBA mechanisms, i.e., they are simply defined as interfaces in the IDL language and one can write them by using the work flow described above.
Collocation:
CORBA allows “remote” objects to be in the same address space, too. Since using the objects does not require changes in the client-code, this usage is completely transparent; however, it is substantially faster and an ORB may even optimize it by completely replacing it to local calls. The command responsible for this behavior is called CORBA::ORB::collocated(TRUE);.
One single interface, multiple servers:
A single interface can be implemented by several classes. This sounds bizarre from the viewpoint of object oriented design. It sounds logical from the viewpoint of distributed objects. It can be either, depending on how it is used. In the example of our Protocol facility one could have one implementation that writes the information to a log file, another that publishes them on a website and a third one that prints the data on a local printer. A client can decide which implementation to work with. Since the implementation is not dependent on any particular programming language, one could even imagine writing a debugging version in C++ and replace it later by a proper implementation written in Common Lisp.
Multiple interfaces, one single server:
The reverse is also possible: One object can implement several interfaces. This is probably quite obvious from a CORBA point of view, although good object oriented design would discourage this. However, as CORBA is a communication architecture, in the correct circumstances this feature may be a good design choice.
The any data type:
This is CORBA's equivalent of void. The type can be dynamically assigned and thus be used to communicate dynamic applications. It is not always the best choice – e.g. it may be better to package a list as an array for communication instead of constructing a list using the any means. In any case it is a powerful way to add dynamism.
Introspection:
We already looked into the CORBA work flow above and learned that the IDL compiler generates skeleton files for the server and stubs for the clients. Sometimes there are cases when the exact interface may not be available at the time the client and/or server are created. Therefore, CORBA offers services which allow introspection, i.e., allow the client to inquire about an interface at runtime (DII, Dynamic Invocation Interface). On the server-side such a service is called Dynamic Skeleton Interface (DSI). I advocated above that a thorough and well-planned object design is indispensable to any distributed system, so uses of these services should be strictly limited to those niches where people clearly understand what they are doing and why they have no alternative to doing it this way!

Finally, all the issues mentioned in the parallel computing tutorial might be a concern for distributed systems, too. As individual parts of the entire program flow may happen concurrently, all issues arising from interdependency are potential pitfalls. This is a concern that matters most at the design level of the object system. It is for this reason that I stress so adamantly and repeatedly that the design stage is the most important step of all since any mistakes at this stage will translate to very costly corrections later on during the implementation, debugging or deploying phase of a project!

Summary and conclusions

We have seen what distributing application logic means, what the work flow of designing a system looks like and then looked at four examples which highlighted specific aspects of distributed programming. What I have intentionally left out is the question of how CORBA works internally and how the initialization logic works in detail. I believe that these parts are not as important as the other aspects and I also point the reader to a couple of excellent introductions on the web that cover these topics in sufficient detail.

Most important are the general design of object distribution and the implementation of the application logic. I believe that anybody who reads this page understands the latter. What often provides a bigger challenge is the former since it necessitates a non-trivial understanding of both the technical limitations, the problem at hand and proper object design. In real-world applications these demands may be conflicting — just remember the example in Part 2 where breaking encapsulation can lead to improved performance. The “art” of designing distributed system lies in understanding that sometimes rules must be broken and the judgment of what rules that should be in a given situation.

Beyond the basic understanding I hope that you have grasped the particular strengths and also challenges of working with CORBA. Granted, it is not the best choice in all situations, but it is my goal to show where it really excels and put you in a position to make an adequate choice for your real-world challenges!

References and further reading

There are a couple of good books available on the net for free and there are also some good tutorials and sample codes out there. However, many of them focus on the part that's least important: the way the CORBA middleware works. I have largely left this part out in this tutorial and merely referred to “boilerplate init” code wherever appropriate. This part looks and feels the same in many circumstances and can easily be adapted in the others.

These resources provide excellent overviews on other aspects of CORBA:

CORBA explained simply is a free online book that is both up-to-date and quite thorough. It does not focus on code examples, though, but rather explains the concepts underlying a CORBA application. A minus is that there are no exercises and thus it is hard to get “hands-on” experience by using this book alone.

Teach Yourself CORBA In 14 Days is a well-written, but slightly dated introduction which goes into a lot of technical details yet is very broad in scope. With this resource alone you are in an excellent position to apprehend many of the technical aspects that you will encounter as a developer. A plus are the questions and assignments at the end of each day, making those two weeks a very good investment, indeed.

The Orbix manual is another useful introduction to CORBA. It is thorough and well-written. Although the manual contains some information that is specific to Orbix, most of it applies to any other implementation, too. After reading it, maybe you will decide using Orbix for your upcoming project?