White Papers
Wrapping Legacy Applications: A
Distributed Computing Solution
This paper discusses the issues of wrapping legacy
applications using distributed objects. Wrapping applications is a method
of encapsulation that provides clients with well-known interfaces for
accessing server applications or components. The principal advantage is
that, behind the interface, the client need not know the exact
implementation. The developer could have implemented the method as a
simple variable update, as an inter-process socket invocation, or even as
a no-op. The class implementer provides a protocol via the class header,
that explains how to use the class without tying the client to any
particular implementation. The class can thus be reimplemented in numerous
ways without impacting the client.
C++ is an ideal language for implementing encapsulation. A
C++ class has a well-known public interface that clients use to access the
services the class provides. CORBA objects have additional benefits over
regular C++ objects because CORBA is both programming language and
platform independent. With CORBA, a developer can feel comfortable that
objects with interfaces defined in IDL will be accessible to an
ever-increasing set of users - programmers who are developing on multiple
platforms and operating systems, and who are using several programming
languages. Additionally, CORBA objects, though accessed through a local
surrogate object, may exist anywhere on the network, allowing
administrators to place them strategically across the network, leveraging
additional CPUs.
Three Scenarios
We now look at three examples that demonstrate the
benefits of using CORBA distributed object technology for wrapping legacy
applications. The first example deals with extending a standalone
simulation library by providing a well-defined, distributed interface
accessible by other remote applications. The second deals with migrating a
database application from a vendor-specific solution for accessing and
updating the database to a more flexible, non-proprietary solution. The
final example demonstrates how a standalone application can be converted
into an application with distributed-enabled components.
I. Wrapping a Simulation Library
Here, we deal with a library that provides a framework for
building simulations in C++. Developers use the library for building
simulation-enabled objects of different types, populating the simulation
with objects based on programmatic rules. Developers must initialize and
start the simulation engine, then populate it under various conditions,
followed by compiling the application, linking in the simulation library,
and running the application. The user interacts with the simulation via a
GUI, starting and stopping it, adding and removing entities, and querying
the engine for various details, such as the number of active simulation
entities.
Without a CORBA interface, developers can use the
simulation framework for building simple, stand-alone simulation
applications - but they cannot realize more complex, efficient uses. While
the GUI provides an interface for humans to access and interrogate the
simulation, other applications cannot access the simulation
programmatically. Any developer interested in building, running and
analyzing a simulation must run a local version of the simulation
application. Moreover, simulations often take a certain amount of up-time
in order to reach the steady state necessary to convey useful information,
and each developer must invest this ramp-up time to gain any meaningful
benefits. Simulations consume many computer cycles and need powerful
machines to handle their loads. Migrating the simulation between machines
at runtime is often necessary to run the simulation effectively as machine
loads change.
While the simulation framework does not provide this
capability, a CORBA interface that encapsulates the simulation engine can
solve most of these problems. Just as GUIs provide a graphical interface
for interacting with applications, CORBA IDL provides the programmatic
interface. IDL allows remote applications to "see" the simulation via a
set of well-defined CORBA interfaces, and allows multiple sites to
interact with the simulation simultaneously. Developers can port a
simulation library to a high-end platform to provide an efficient,
powerful system for running the application. Indeed, clients of the
simulation do not need to know where the actual simulation is running, as
long as they have an object reference to the simulation object that wraps
the simulation application.
Adding a simple CORBA interface to the simulation
application opens up several other issues that must be addressed. Among
them:
Should all users have privileges to start and stop the
simulation?
Is there a limit to the number of entities that can enter
the simulation?
Should some clients only have read access to the
simulation?
CORBA does not address these domain-specific questions.
The extent to which developers address them depends on the robustness and
usefulness of the simulation.
II. Wrapping a Database Application
The next example deals with a database client application
that accesses and updates personnel information on a database server.
Database clients access the data server via a database API that supports
SQL. A GUI application triggers the database with such requests as adding
employees and assigning them to departments and supervisors. Locally, the
personnel application treats all of the types maintained in the database
as classes, which map into corresponding tables while maintaining special
database tables to store relationships between classes. Although this is
not a complicated mapping, developers must be careful to maintain
synchronization between application classes and database tables.
One benefit provided by CORBA is encapsulating the
back-end database structure from the client code. Companies migrating from
one database product to another will find it inconvenient to redevelop
client code after each migration. Providing client access to the database
through an interface that stays constant, even when the back-end system
changes, eliminates this need for redesign.
This IDL hierarchy provides a flexible design to support
migration to a different back-end database without affecting the client
code:
The developer codes client applications to the interface
defined in AbstractDBInterface. Initially, the middleware developer
implements XyzRDBInterface and ties the implementation directly to the
legacy application. This arrangement gives the client, via the
AbstractDBInterface, the same functionality with respect to accessing the
database as using straight SQL. Simultaneously, or after implementing
XyzRDBInterface, the middleware developer can implement NewDBInterface
using any database technology. Since the interface of both XyzRDBInterface
and NewDBInterface matches AbstractDBInterface, a client of
AbstractDBInterface does not care whether an object of type
XyzRDBInterface or NewDBInterface is loaded in the system.
From the client perspective, the interface is constant.
Because the developer migrates the implementation, not the interface,
he/she need only update the client code once to match the interface of
AbstractDBInterface. An administrator can switch from a server object of
type XyzRDBInterface to NewDBInterface without impacting the
client.
To create an object-oriented CORBA interface for the
client, the server developer must analyze the current system and determine
appropriate methods in which to map the SQL commands contained within the
client environment. It is advisable to remove all transactional code
contained within the client code and migrate that to the server. This
transactional code represents the established business rules and logic of
the company - rules requiring, for example, that all employees with a
certain set of qualifications earn a salary within a set range. Such
business logic represents a higher level of intelligence that the database
cannot fully capture.
Classic client/server database systems place transactional
logic through a combination of transactional database calls on the client
and stored procedures on the server. This is an inelegant solution
because, in essence, the knowledge of the business is spread across both
the client and the server. Adding new client applications to this system
is difficult because the logic built into the initial client application
must be duplicated in each new client.
The ideal solution is to extract the business logic from
the client and provide the client with a CORBA interface to the database.
The CORBA implementation encapsulates the database, maintaining the
business logic as a layer on top of the database and outside the scope of
any particular client. In addition, the CORBA implementation can
asynchronously notify registered clients of important events, for example,
when it determines a critical shortage of office space, it notifies the
appropriate client. A CORBA-based middle tier becomes a highly flexible
and scalable solution.
III. Converting C++ into a Distributed
Application
The third example deals with converting a standalone home
accounting system to a distributed application. This example differs from
the others in that we are not interested in providing a CORBA interface to
a back-end system, but rather in reworking an application to take
advantage of distributed components internally.
The initial application provides the traditional
capabilities for managing personal finances, enabling a user to add and
manage bank, savings, and credit card accounts via a GUI. The application
also provides account reconciliation, report generation, and such
financial tools as amortization scheduling for mortgages and retirement
analysis.
Adding distributed components to this application greatly
extends its functionality within an office environment. A distributed
object model allows objects like report generators to be run on the most
powerful computer available on the network. From an application point of
view, distributed components appear as local objects, yet take advantage
of computing resources across the network.
Developers can add robustness without increasing the
complexity for your programming task. Although it is possible to extend
the functionality using threads, threads do not scale well because they
are limited to running on a single machine and can only take advantage of
multiple CPUs on that machine.
After determining the relevancy of using distributed
components, developers should target candidate classes for adding
distributed capability. While, logically, you could rewrite all classes
within the system as distributed objects, this is overkill. Practically
speaking, developers should target those classes that perform
time-consuming, complex operations such as the report generator and
amortization scheduler. Making heavily used classes like these distributed
objects frees up system resources.
The next step is to define the interface for this
component. In general, this task is quite simple: all public methods are
good choices as interface methods for the distributed version of this
class. After defining the interface, developers must define the behavior
of all of the methods of this class. The original version of the report
generator, for example, has an access method for initializing the
generator with information on which to report and a method to start report
generation.
This last method is synchronous and does not return until
it generates the report in its entirety. A better design provides a method
that returns immediately after informing the report generator to commence
with the generation, then has the report generator notify the client of
the report's completion. This asynchronous method of interacting with the
report generator allows the client application to continue processing in
parallel with the report generator. The client is free to process new
events without freezing the display and can even start up a new report
generation session.
A strict CORBA-based solution for adding distributed
components to the accounting application requires the development of an
IDL interface that contains operations for the different services provided
by the report generator. Here, the CORBA object simply calls the
corresponding report generator method from within each CORBA method.
A simpler alternative, one less intrusive on the overall
system design, converts the report generator class into a PowerBroker
Extended C++ class. PowerBroker Extended C++ classes look similar to
regular C++ classes, but add several key words for facilitating
distributed method invocations. Converting a regular C++ class into a
PowerBroker Extended C++ class requires much less work than writing a
full-scale CORBA object that redirects all methods to the original object.
Moreover, in using PowerBroker Extended C++ classes, PowerBroker generates
an asynchronous method for every method tagged as a distributed member
function within the Extended C++ class. With respect to the report
generator, for example, no extra coding on the server is needed to provide
notification of completion. Under a strict CORBA implementation, extra
coding is necessary to propagate the notification back to the
client.
Summary
These three scenarios demonstrate the benefits of using
distributed object technology for wrapping and extending legacy
applications. CORBA provides a straightforward mechanism for hooking into
legacy systems, providing desktop access, and extending the life of
valuable applications by treating them as reusable components. Using CORBA
along with an effective design can simplify the migration of legacy
applications and limit the coding impact on client-side applications.
CORBA does not solve every problem facing software developers, but it does
provide an elegant solution for reusing, migrating and reengineering
components that take advantage of distributed computing.

© Copyright 1997, Expersoft Corporation. All rights
reserved. Expersoft is a registered trademark of, and PowerBroker is a
trademark of Expersoft Corporation. Java is a trademark of Sun
Microsystems,
Inc. |