Most new software is developed through the use of object-oriented technology. Within Netscape ONE, you can use JavaScript objects, Java objects, and plug-ins (written in object-oriented C++). On your corporate intranet, you can encapsulate legacy applications in an object "wrapper."
Every business application (whether its a legacy application or a new object-oriented application) represents a model of some portion of your company's business. In an ideal world, those applications could be interconnected to increase corporate productivity and collaboration. Unfortunately, these applications run on computers from different vendors that are spread around the corporate campus or even around the world.
Since April 1989, many of the world's largest corporations have been quietly working on a solution. Over 470 companies have formed a consortium known as the "Object Management Group," which has released a series of open standards for distributed applications.
One approach to corporate application integration is to get the entire corporation on the same hardware, the same operating system, the same network protocol, and the same application format. Good luck-it would be easier to herd cats.
The alternative is to agree on standards by which an application on one hardware platform running under one operating system can reach out over the network and find an application on another platform that can provide some service.
A typical corporation has hundreds of business functions running on hundreds or even thousands of computers. As illustrated in Figure 8.1, Engineering wants to send design changes directly to Manufacturing, the Purchasing department wants to send purchase orders to the Receiving dock, and the Receiving staff should be able to tell Purchasing what was received, in what quantity, and in what condition. Receiving, Manufacturing, and Shipping should all have real-time access to the inventory files so that the account representatives can give accurate information to prospective clients. When orders are shipped, that information should go directly to the accounts receivable application so that an accurate, timely invoice can be generated.
Reality falls far short of this ideal. Each application is often supported by a different team of hardware, operating system, and application specialists. New versions of all of these components are continually being released-keeping up with these changes is a full-time job. Until recently, these applications had to be integrated by hand-crafted code that might break in response to a maintenance release-or they weren't integrated at all.
In recent years, software engineers have become convinced that object technology improves software design. One of the major attractions of object technology is its support of information hiding-the practice of separating the interface from the implementation. As illustrated in Figure 8.2, a well-behaved object requires its clients to access its services through its interface. If the developer chooses to change the implementation, none of the client code needs to be changed since the interface remains stable. The client doesn't have to know anything about how the service is provided. It's enough that the client know how to find and use the interface.
Figure 8.2 : Object technology naturally supports information hiding.
Object Request Brokers This same object-oriented approach, extended across a network, can serve as the basis for distributed application interoperability. Figure 8.3 illustrates how application objects can connect to services, without having to know any specifics about how the services are provided.
Figure 8.3 : Object technology can be distributed across a network to provide interoperability.
An application object might be a component of an existing application,
a legacy application with an object wrapper, or a new application
that is written to take advantage of distributed object services.
When such a client object needs some service, it contacts the
Object Request Broker, or ORB. The ORB is responsible for
knowing where to find that service. It may send the request itself
and get the answer for the client, or it may put the client directly
in touch with the server. Either way, the client application's
need is met.
Note |
Pure client/server systems, in which the client application knows how to directly contact the server, are sometimes called two-tier systems. By contrast, systems in which the client application contacts a third party (the ORB) in order to be put in touch with the server are often called three-tier systems. |
Later, if the client needs the service again, the ORB may return
a different answer. The client doesn't care, as long as its needs
continue to be met. This design gives the corporation a great
deal of flexibility both in mixing and matching components from
different vendors and in mixing different hardware and operating
systems. As long as each of the components can reach the ORB,
all of the objects can communicate.
Note |
While the client object may be an entire application, it may also be a small part of an application. Taken to its logical conclusion, a three-tier system can distribute the portions of an application all over the network, and the end user does not need to know which computer is running which part of the application. In one common design, illustrated in Figure 8.4, the client (the first tier) is responsible for the user interface, a server (the third tier) holds data the client needs, and a middle layer (the second tier) contains the business rules that define which data should be given to the client. |
The Interface Definition Language An ORB may broker the services of dozens of different objects. A new service may contact the ORB and attempt to register its interface at any time. Before standardization, a programmer had to write an interface between the client application and the server. One of the Object Management Group's biggest contributions was to define a standard language for defining services so that server objects could register their interface without the intervention of a programmer.
The standard is called the Interface Definition Language, or IDL. It is a multiple-inheritance, public interface specification language, with bindings from a range of languages, including C++, Ada, COBOL, and Smalltalk. You can write a server object in one of these languages and then invoke a compiler to produce IDL. As shown in Figure 8.5, you first install the server object on one of your network's machines; then you register the IDL with the ORB, enabling applications to make dynamic requests for your service through the ORB.
Standardization has been a breeding ground for acronyms, and distributed object standards is no exception. The three most important acronyms in this field are DCOM (Microsoft's Distributed Component Object Model), DSOM (the Distributed System Object Model promulgated by IBM and others), and CORBA (the Common Object Request Broker Architecture). To understand CORBA and, ultimately, IIOP, its useful to understand DCOM and DSOM. To understand DCOM and DSOM, we must first look at their undistributed cousins, COM and SOM.
Microsoft's Component Object Model An important part of component architecture is the capability to put two objects together and have them discover that one object can offer a service that the other object needs. An important element of this interface is that such an introduction should not depend upon the language in which the objects are written-the binary output from a C++ compiler should be able to communicate with a Smalltalk object, for example.
Microsoft introduced this technology as part of its Object Linking and Embedding, or OLE, technology. They call it the Component Object Model, or COM. The COM specification defines a binary standard by which two objects may communicate. Objects that conform to the COM specification are called Windows Objects. Thus, Windows Object A can ask Windows Object B what services Object B supports. Object B returns a list. (Microsoft calls each service an interface.) If any of those interfaces are of interest to Object A, it can request a table of pointers to the functions that are associated with that interface.
COM is available on Windows platforms but can cross application boundaries. A Windows Object can communicate with objects in the same application, in a Dynamic Link Library (DLL), or in another application (EXE).
The System Object Model The System Object Model, or SOM, addresses almost the same problem as Microsoft's COM but with a different implementation. SOM's designers wanted to enable developers to use language-neutral class libraries. For example, suppose you want to build an application that knows about various kinds of transportation. You buy a third-party class library that includes such classes as ship, plane, and bus. Using SOM, you can use the library to derive your own classes (for example, cruiseShip) without worrying about what language the class library is written in. Furthermore, if the library vendor sends out a new release of the library with a new implementation of class ship, you won't need to recompile your class cruiseShip, if you use SOM.
Figures 8.6 and 8.7 illustrate how you develop SOM libraries and SOM clients, respectively. This example and the DSOM example in the next section are based on IBM's reference implementation on their RS/6000 platform under AIX. Other SOM and DSOM implementations are similar.
Figure 8.6 : To make your class library SOM-compatible, compile the IDL source into the library.
The IDL source file shown in both Figure 8.6 and 8.7 is the same
Interface Definition Language specified by the Object Management
Group for communication with an ORB. The Interface Repository
is a database that holds information from the IDL file. Programs
can access this repository at runtime to get information about
methods, attributes, and types.
Note |
Another database, the Implementation Repository, resides on the network and contains information regarding which objects provide which services. Each DSOM implementation provides a way to associate classes and servers in the Implementation Repository. |
The binary class library shown in Figure 8.6 does not appear in Figure 8.7 since it isn't used to build the client, but it does appear at runtime. One of the design goals of SOM is to support shared class libraries. You could run a dozen different clients on the same machine by using a single binary copy of the class library.
Listing 8.1 shows a simple example of an IDL interface: a specification for a simple stack.
Listing 8.1 -An IDL Specification of Class Tstack
#include <somobj.idl> interface TStack: SOMObject { //Constants const long kStackSize = 100; //Public Methods boolean isFull(); boolean isEmpty(); long top(); void pop(); void push(in long el); //implementation-dependent code; not publically accessible implementation { releaseorder : isFull, isEmpty, top, pop, push; dllname = "stack.dll"; //Method modifiers somInit: override; //Instance data long stackimpl[kStackSize]; } };
The similarities between IDL and C++ are obvious. C++ has many features that are not available in IDL. Exceptions are one example; inlining is another. SOM cannot handle anything that cannot be expressed in IDL.
Note that, unlike C++, SOM objects derive from a common class-SOMObject. Also note that the implementation portion of the IDL file contains code that is specific to a platform and a SOM compiler. The rest of the file is standard OMG IDL.
One of the outputs of the SOM compiler is the skeleton C++ file. The skeleton of the method isFull() is:
#include <stack.ih> ... SOMScope boolean SOMLINK isFull(TStack somSelf, Environment* ev) { TStackData* somThis = TStackGetData(somSelf); TStackMethodDebug("Stack", "isEmpty"); /* Return statement to be customized */ return; }
As the programmer, you would complete the implementation by filling out the skeleton, as shown in the bold line in the following code fragment.
#include <stack.ih> ... SOMScope boolean SOMLINK isFull(TStack somSelf, Environment* ev) { TStackData* somThis = TStackGetData(somSelf); TStackMethodDebug("Stack", "isEmpty"); return (_stackimpl[0] == kStackSize); }
Once you have a class library that includes the stack class, you can write a SOM-compliant client to use that class. Listing 8.2 shows such a client.
Listing 8.2 -A SOM Client that Links to Class Tstack
#include <stack.h > int main() { Tstack theStack; Environment* theEnvironment; theEnvironment = SOM_CreateLocalEnvironment(); theStack = TStackNew(); _push(theStack, theEnvironment, 100); _push(theStack, theEnvironment, 200); if (!_isEmpty(theStack, theEnvironment)) somPrintf("Top: %d\n", _top(theStack, theEnvironment)); _somFree(theStack); SOM_DestroyLocalEnvironment(theEnvironment); return(0); }
Distributed COM and SOM On a single platform, both COM and SOM are sometimes more trouble than they're worth. If objects could communicate across a network the way COM and SOM allow them to do on a single platform, however, such a technology might be useful.
Both Microsoft and the OMG recognized the usefulness of defining a distributed version of their single-platform specification. This section describes Distributed SOM, or DSOM. Microsoft's Distributed COM (DCOM) is similar but runs only on Windows platforms.
DSOM is an object-oriented framework for accessing objects across address spaces-on the same machine or across networked machines. SOM insulates clients from the server object's implementation; DSOM further insulates the client from the server object so that the client doesn't even have to know the server's location.
If all this talk about insulating the client object from the server object sounds familiar, it should. DSOM is an implementation of OMG's Common Object Request Broker Architecture (CORBA) for an ORB.
The similarities between DSOM and SOM are striking. Listing 8.3 shows how to convert the SOM client from Listing 8.2 into a DSOM client. Again, the bold lines show the changes.
Listing 8.3 -A DSOM Client that Links to Class Tstack
#include <somd.h> #include <stack.h > int main() { Tstack theStack; Environment* theEnvironment; theEnvironment = SOM_CreateLocalEnvironment(); // theStack = TStackNew(); // The following lines replace the SOM call to TStackNew SOMD_Init(theEnvironment); TStackNewClass(TStack_MajorVersion, TStack_MinorVersion); theStack = _somdNewObject(SOMD_ObjectMgr, theEnvironment, "Stack", ""); _push(theStack, theEnvironment, 100); _push(theStack, theEnvironment, 200); if (!_isEmpty(theStack, theEnvironment)) somPrintf("Top: %d\n", _top(theStack, theEnvironment)); //somFree(theStack); //The following lines replace the SOM call to somFree _somDestroyObject(SOMD_ObjectMgr, theEnvironment, theStack); SOMD_Uninit(theEnvironment); SOM_DestroyLocalEnvironment(theEnvironment); return(0); }
The stack class itself doesn't have to be modified. To implement a DSOM Stack Server you need a DSOM server, which consists of a separate thread of execution (for example, a process), a server object, and one or more class libraries with object implementations. DSOM comes with a default server program, named somdsvr, and a default server object, SOMDServer. To implement the Stack Server, you do the following:
Note |
The dynamically loadable library (DLL) in IBM's implementation of UNIX is similar in function to the Dynamic Link Library (also called DLL) of Microsoft Windows. |
To register the TStack implementation so that the ORB knows where to find it, you take the following three steps:
regimpl -A -StackServer regimpl -a -I StackServer -c TStack
When the DSOM client runs and requests an object of class TStack, the DSOM daemon looks in the Implementation Repository to find out which server offers class TStack. Because we ran regimpl, the client finds StackServer. When the client requests StackServer, the DSOM daemon starts the somdsvr server program, which uses the default server object SOMDServer, which loads the class DLL.
At runtime, the client machine has a stub stack.dll. The real stack.dll, and the real instance of the class TStack (which our client calls theStack) are on the machine that is running StackServer.
DSOM and CORBA The Common Object Request Broker Architecture (CORBA) specifies how clients talk to the ORB, how servers register with the ORB, and how ORBs talk to each other. Various ORB vendors implement slightly different parts of the CORBA specification-DSOM is one such implementation. Nevertheless, ORB vendors have adopted CORBA to such a high degree that you can count on an "out-of-the-box" guarantee of compatibility between any two CORBA-compliant ORBs.
ORBs have been around since the early '90s. If you work in a corporate environment, chances are good that one or more of the applications you use on your desktop is communicating through an ORB. Recall from Figure 8.3 that a typical ORB installation includes object services and common facilities. Typical common facilities include support for:
The OMG has identified the following seven major areas for object services:
Developers use object services and common facilities as building blocks to assemble application objects. Since the exact mix of services varies with the user's requests, the set of software that comprises the application is dynamically activated and connected at runtime. Developers in end-user organizations can buy server objects from multiple vendors and integrate them under one or more client applications. A single set of business objects can be shared across the entire enterprise, or each division can buy and access those objects that meet its specific needs.
Just as the corporate LAN has grown to become the intranet, so CORBA has expanded to include the Internet. Recall that the CORBA specification includes information about how two ORBs can communicate. The CORBA architecture exemplified by DSOM now includes the Internet Inter-ORB Protocol, or IIOP, which specifies how ORBs communicate over the Internet or a corporate intranet.
Netscape's LiveConnect technology allows you to integrate JavaScript, Java applets, and plug-ins on a single platform. Even though all of the components may come from different hosts, they are downloaded to a single machine (the client machine) and execute there.
When IIOP becomes widespread, look for something like a LiveConnect page to be distributed. The page might include a plug-in that is downloaded to the client machine, as well as applets that run remotely. Both the applets and the plug-ins may call back out to the Internet and request services from any CORBA-2.0-compliant application in order to get their job done.
A developer also might be able to write an object in C++, Java,
or some other language and register services for use by other
parts of the application that are distributed around the network.
ON THE WEB |
http://home.netscape.com/comprod/columns/techvision/iiop.html Be sure to read Marc Andreessen's vision of distributed objects on the Internet. Andreessen envisions intranets that are based on open standards, in which directory services are distributed by using LDAP, encryption is provided by using SSL, and search engines look for objects as well as content. Communications for this system would be provided by IIOP. |
Netscape has announced that both Navigator 4.0 and the next generation
of servers will be IIOP-compliant. In addition, they have announced
that they are integrating VisiBroker, Visigenic's IIOP-compliant
Java-based ORB, into Netscape ONE. Developers can use another
Visigenic product, Caffeine, to program IIOP-compliant objects
directly in Java.
ON THE WEB |
http://www.visigenic.com/ This site includes the press releases about VisiBroker and Caffeine, as well as information about the company's products. |
Netscape's plan for communicating with the ORB is called Distributed LiveConnect. When a service becomes available, it registers itself, just as the stack server was registered under DSOM. A Netscape ONE application references the service by using a well-known name (such as StackServer). After that, the service appears as a LiveConnect component. Just as a developer can now say
<APPLET NAME="myApplet" ...> <FORM> <INPUT TYPE="Button" VALUE="doSomething NAME="doSomethingButton" onClick="document.myApplet.doSomething()"> </FORM>
the developer with a service in his or her document will be able
to directly call the methods associated with the service.
Tip |
For more information on LiveConnect, be sure to see Part V, "LiveConnect." |
Development of an application that is based on distributed LiveConnect is similar to the development of a single-computer application. The two major differences have to do with bandwidth and system load.
If the components of your application reside on only a single machine (for example, the user's desktop computer), there is little opportunity for sharing code (which reduces required disk space) or data (which increases corporate collaboration). On the other hand, the user never has to wait for something to download over the network. If the computer is fast enough, the user perceives the application as having good performance.
If the application's components are distributed but require downloading to the desktop machine (as are applets), the amount of disk space required is reduced, but the user incurs delay time when downloading the components. Many applets can fit into just a few kilobytes-a 12K applet is considered large. Such an applet takes about five seconds to download over a 28.8Kbps dial-up link. On most intranets, the download time will be a fraction of a second.
The browser needs a few more seconds to load the applet and start the thread. Size and start-up time are similar for plug-ins. Of course, plug-ins are generally downloaded only once and are stored on the local hard drive.
If the amount of data used by the application is large, you have little choice but to leave the data on a server and send queries to the server. LiveWire Pro, with its server-side JavaScript, and CGI scripts, with an interface to a database management system, work this way. The results of the query can often be downloaded in just a second or so, even over a dial-up link. The speed of the application is determined largely by the speed of the server and by the number of simultaneous requests for access.
If your application uses distributed LiveConnect, consider leaving as much of the application on large, powerful servers as possible. This way, you avoid downloading penalties and you can take advantage of shared data. Increase the capacity of the servers to meet heavy demand. (Often you can get a dramatic improvement in server performance just by adding memory.)
Most user interface components, which should provide near-instantaneous response to keypresses and mouse clicks, should be downloaded and run on the user's desktop machine. You can leverage your development effort by writing as many of these components in Java and JavaScript as possible. If you need platform-specific capability, write a Navigator plug-in.
Netscape is bundling a runtime version of Visigenic's VisiBroker for Java ORB, formerly known as Black Widow, into Navigator (starting with version 4) and its servers (starting with the Orion-class servers). Using the runtime version of the ORB, you can open Java applets that are IIOP-aware and use them to access remote applications.
To transform IDL into Java, you'll need Visigenic's development
version. They support development on Windows 95, Windows NT, and
major versions of UNIX.
ON THE WEB |
http://www.visigenic.com/prod/vbjpd.html This site is a cornucopia of information about VisiBroker for Java and includes links to a Java-enabled white paper, as well as links to the product tutorial and reference manual. |
The development process under VisiBroker for Java is similar to the development process provided earlier in this chapter for SOM and DSOM. Use the VisiBroker IDL to Java compiler to transform IDL into Java; then expand the Java to form a complete class. Finally, access the remote class from a Java applet. Visigenic's documentation shows a simple application that returns bank balances.
Banker Client First, here's the client's side of the application. Listing 8.4 shows the HTML file that contains the applet; Listing 8.5 shows the applet itself.
Listing 8.4 -The HTML File that Embeds the Applet
<HTML> <HEAD> <TITLE>Black Widow Client Applet</TITLE> </HEAD> <BODY> <H1>Black Widow Client Applet</H1> <HR> <CENTER> <APPLET CODE=ClientApplet.class WIDTH=200 HEIGHT=60> <H2>You are not running a Java-enabled browser.</H2> </APPLET> </CENTER> </HR> </BODY> </HTML>
Listing 8.5 -The Banker Applet-Half of This Distributed
Application
import java.awt.*; public class ClientApplet extends java.applet.Applet { private TextField _nameField, _balanceField; private Button _checkBalance; private Bank.AccountManager _manager; public void init() { // This GUI uses a 2 by 2 grid of widgets. setLayout(new GridLayout(2, 2)); // Add the four widgets. add(new Label("Account Name")); add(_nameField = new TextField()); add(_checkBalance = new Button("Check Balance")); add(_balanceField = new TextField()); // make the balance text field non-editable. _balanceField.setEditable(false); try { // Initialize the ORB (using the Applet). CORBA.ORB orb = CORBA.ORB.init(this); // Locate an account manager. _manager = Bank.AccountManager_var.bind("Post-Modern Bank"); } catch(CORBA.SystemException e) { System.out.println(e); } } public boolean action(Event ev, Object arg) { if(ev.target == _checkBalance) { try { // Request the account manager to open a named account. // Get the account name from the name text widget. Bank.Account account = _manager.open(_nameField.getText()); // Set the balance text widget to the account's balance. _balanceField.setText(Float.toString(account.balance())); } catch(CORBA.SystemException e) { System.out.println(e); } return true; } return false; } }
Banker Server Listing 8.6 shows the IDL that
is used to describe the server interface. Once that IDL has been
processed by the VisiBroker server, the programmer adds implementations
to the Java skeleton to finish the Java application. Listing 8.7
shows the finished Java classes for the server.
Note |
When you write Java, you should put each class in its own file and give the file the same name as the class. VisiBroker's IDL to Java compiler follows that rule. Listing 8.7 breaks that rule in order to show the major server classes concisely on the printed page. |
Listing 8.6 -The Banker Server's Interface Definition
Module Bank { interface Account { float balance(); }; interface AccountManager { Account open(in string name); }; };
Listing 8.7 -The Banker Server-The Other Half of
This Distributed Application
public interface Account public class _sk_Account extends Skeleton implements Account { protected _sk_Account(); protected _sk_Account(String _iName); public abstract float balance() throws SystemException; }; public class AccountImpl extends _sk_Account { AccountImpl(float balance) { _balance = balance; } public float balance() throws CORBA.SystemException { return _balance; } private float _balance; }; public interface AccountManager extends Object { public abstract Account open(String name) throws SystemException; }; public class _sk_AccountManager extends Skeleton implements AccountManager { protected _sk_AccountManager(String _iname); protected _sk_AccountManager(); import java.util.* public class AccountManagerImpl extends Bank._sk_AccountManager { AccountManagerImpl(String name) { super(name); } public Bank.Account open(String name) throws CORBA.SystemException { Bank.Account account = (Bank.Account) _accounts.get(name); if (account == null) { float balance = Math.abs(_random.nextInt()) % 100000 / 100f; account = new AccountImpl(balance); System.out.println("Created " + name + "'s Account: " + account); _boa().obj_is_ready(account); _accounts.put(name, account); } return account; } private Dictionary _accounts = new Hashtable(); private Random _random = new Random(); } public final class Account_var extends Object { public Account_var(); public Account_var(Account value); public static Account narrow(Object object) throws SystemException; public static Account bind(String name) throws SystemException; public static Account bind() throws SystemException; public static Account bind(String name, String host) throws SystemException; public static Account bind(String name, String host, BindOptions options) throws SystemException; public static Account any(Any x) throws SystemException; public static TypeCode typecode() throws SystemException; //AccountManager_var is similar to Account_var, and is omitted here. public class Server { public static void main(String[] args) { try { CORBA.ORB orb = CORBA.ORB.init(); CORBA.BOA boa = orb.BOA_init(); Bank.AccountManager manager = new AccountManagerImpl("Post-Modern Bank"); boa.obj _is_ready(manager); System.out.println(manager + " is ready."); boa.impl_is_ready(); } catch(CORBA.SystemException e) { System.err.println(e); } } }
The VisiBroker for Java ORB comes with a program called GateKeeper, which provides the bridge between clients and servers. You can start GateKeeper from the command prompt:
java pomoco.iiop.GateKeeper
Once you have GateKeeper running, and class Server has registered itself, the client code
manager = Bank.AccountManager_var.bind("Post-Modern Bank");
succeeds and manager is associated with a valid AccountManager. As Listing 8.7 shows, you can call open on an AccountManager to map a name to an account. Once you have an account, you can call balance(). Each account's balance is initialized with a random number. Accounts are stored in the Dictionary object accounts.
Netscape is going after the corporate intranet market and has
made it easier for Netscape ONE applications to access CORBA-compliant
legacy applications through the IIOP. For more information on
Netscape's implementation of IIOP and the Java ORB, visit http://developer.netscape.com/library/one/technologies.html#IIOP.
ON THE WEB |
http://www.visigenic.com/BW/tutorials.html Some of the best material on the new Java ORB isn't on Netscape's site-it's on VisiGenic's. This page is the starting point for tutorials on writing applets and applications which use the Java ORB now included with Netscape ONE. Note that Black Widow is the original name for VisiBroker for Java. Visigenic also has the reference manuals for VisiBroker online. See http://www.visigenic.com/BW/reference_manuals.html. |