HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

In the CORBA-based, service broker framework, the data that's required and shared among various heterogeneous systems is coordinated in a synchronized manner by a server process, yet maintained locally by each participating system.

Although lots of articles mention how to design a large-scale system, they often lack implementation details, due partly to the complexity of the issues involved. In this article I'll provide an example of a simple, generic and yet useful implementation of a large-scale system based on Java-CORBA architecture.

Background
Designing and writing large software is very different from writing a program that can be completed in one day. This article will be particularly useful to those of you involved in large-scale software development. My earlier article (JDJ Vol. 4, issue 1) proposed a way to design a loosely coupled, highly maintainable software product centered around an object known as the service broker. Thus some terms used in that article will be used here without redefinition or explanation. This article discusses how to extend the service broker based on CORBA architecture and written purely in Java.

CORBA-Based Service Broker
Overview
In a real business situation, supporting computer systems may exist in a heterogeneous environment. It's likely that each system consists of different subsystems, each maintaining their own data using methods chosen by their management. For example, a typical company may have an order entry system, a service delivery system and a billing system. Assuming each system was designed and maintained by different departments, you'll have a big headache if there's no coordination between them. Problems arise when the systems need to share common data. This is when a CORBA-enabled service broker is useful.

Technically speaking, each local application will instantiate its own copy of a client service broker (SBroker), which acts as a local proxy object for the remote object of the service broker. The SBroker proxy object can also become a factory object for each application, if there is such a need. This would reduce the overhead for naming service lookups from the CORBA client application.

The remote service broker server is implemented as a normal CORBA server. A client service broker can communicate via IIOP with a component that's a reachable CORBA object, called a service broker moniter, hosted by the service broker server. If you look at the SBroker code in Listing 1, you'll notice the getMonitor method and mon object of type monitor. This is the method that returns a CORBA object reference of the remote service broker server object, which is mon in this case. Referring to Listing 2, the service broker monitor basically allows a client to:

  • Register (add) itself to listening to a specific broadcast event.
  • Remove itself from event listening.
  • Broadcast an event to (notify) the listening application.
The Implementation
In this design I've chosen a pure Java-based ORB, JacORB (version 0.9f2) courtesy of Gerald Brose ([email protected]) since it's a free open source with more features than the Java IDL of Java 2 (JDK 1.2) from Sun Microsystems. It allows you to test the example in this article without a commercial ORB product. However, the design should work with other commercial ORBs as well with minimal modification.

JacORB is used in the CORBA-enabled service-broker framework in the following areas:

  • The COSS naming service to allow distributed listeners to locate the service broker in a standard CORBA way
  • To provide the ORB client and the ORB server with listeners to register event types they're interested in receiving and for the event notifications of sources to listeners via the service broker
  • Calling back of the service broker's monitor to the listeners - thus the ORB clients (in this case the listeners) have to be CORBA objects too

The service broker server architecture depicted in Figure 1 consists of a monitor CORBA object that has an event manager running as a separate thread, an optional Object Design, an ObjectStore ODBMS database for persistency and an ORB server, which is JacORB in this case, running a naming service as well as an Interface Repository (IR) daemon.

Figure 1
Figure 1:

Because broadcast events in this environment are asynchronous, I've used ObjectSpace's JGL 3.0 class library to maintain the events; it's popular and has many standard Java generic classes, plus I'm using JDK 1.1.6 to compile the framework. By the time this article is published, the JGL class library should be part of Java 2 and known as the Collection API.

JGL's Queue class is used in the following manner (see Listing 2):

  • To keep event objects in the queue so they're processed in the order they were received by the service broker
  • To avoid lost events when more than one source (subsystems) tries to broadcast at the same time
  • To delete an event from the queue if the call back inside a listener is returned successfully
To allow a more robust operation in this service broker framework, the server, source and listeners have to operate in a way that facilitates fault tolerance. For instance, whenever the service broker server wakes up (initial start or restarted from the last crash/hanged), it'll always process the event currently on the top of the queue, if any event exists. When a listener wakes up (initial start or restarted from the last crash/hanged), it'll always look for the service broker's monitor object and register itself with the monitor. Whenever a source wakes up (initial start or restarted from the last crash/hanged), on the other hand, it will broadcast a new event via the service broker only if the previous event is processed and removed from the queue by the event manager.

The next JGL class used is HashMap. It's used to keep the object reference of the listeners to facilitate the event-manager thread to call back the listeners. In this design example (see Listing 2) the listeners are associated with their unique application ID as the key.

Alternatively, one can try out Object Manager JGL version 3.1 for ObjectStore, available free from Object Design's Web site. The modified version of the JGL library, which directly supports persistency via a scalable ObjectStore database, is known as dJGL. According to Object Design, ObjectStore PSE Pro 3.0 can recover from an application failure or system crash. If an application (in this case the service broker server) fails during a transaction, when you restart it, it'll return to the way the database was prior to the transaction. If an application fails during a transaction commit, when you restart it, the database will be either the same as it was before the transaction or it will reflect all of the transaction's changes. It depends on how far along in the commit process the application was when it terminated. ObjectStore ODBMS is a full-blown enterprise object database. It's also compatible with JDK1.2 Collection API, but the details aren't covered in this article.

The Assumptions
Before I show you the codes and explain them in depth, I'll share the two most important assumptions I've made in this design. While these assumptions may not be true in your application environment, they serve the purpose here.

  • A source can never broadcast a new event until the previous one has been processed by the event manager and consumed by the listening application.
  • Applications with the same application ID can't listen to a single event; in other words, each application can only listen to a particular event that's closely associated with its application ID.

If you need to broadcast more than one event at any time, a slight modification of the service broker server codes is needed. A more involved change is necessary if you wish to broadcast a specific event to more than one listening application. Some may argue that the word broadcast itself is a misnomer, since broadcast often means the target is more than one entity. Remember, the example given here is an oversimplified implementation. If there's a need to broadcast to more than one listening application using the same event, the event manager has to call back all the applications that are interested in the event before removing the event from the queue. Multiple sources broadcasting to a listener with the same event is also not advisable, though it's possible with some modifications.

A Typical Scenario
The easiest way to show you how to code under this CORBA service broker framework is to imagine how it works in a typical business environment. Imagine there are a few systems in this environment and they all communicate with the service broker server via IIOP protocol. All applications generally keep their own data, but they don't have to. Figures 2 and 3 illustrate the steps involved in this process.

Figure 2
Figure 2:
Figure 3
Figure 3:

When the service broker starts up, it will bootstrap its CORBA object and make it available to all source and listener applications (see Figure 2a). In this case the server registers its monitor object with the COSS naming service. After the server is ready, the framework is ready for virtually any source application to broadcast an event as well as any listening application to process it.

Assume that Application 2 needed to send data to Application 1. Typically, Application 1 will have to register itself with the service broker server. Remember, in this framework every application will have a local service broker proxy called SBroker. That's why you see a D-shaped capsule-like structure on top of each application. SBroker encapsulates the CORBA implementations from all participating applications in this framework. In other words, a source application that needs to broadcast an event (publish an event via the service broker server) to a listening application has to instantiate an SBroker object. The listening application has to do the same thing in order to subscribe to the event (pushed by the server once it's available). This is done by registering itself as a listener with the server (see Figure 2b).

The following code snippet shows you how to instantiate the monitor object from an application and obtain the remote object reference:

monitor mon = (new SBroker()).getMonitor();

Once the remote instance of a service broker object is obtained, registering listeners or broadcasting an event are straightforward steps. To register as a listener (see Listing 3 for a sample listerner code), an application invokes addRadioBroadcastListener of the monitor object. The following code snippet shows you how to do that:

//=== instantiate a copy of the listening application
RbListener rbListener = new RbListener();
//=== register itself as one of the radio listeners
boolean ret = rbListener.mon.addRadioBroadcastListener(rbListener);
---------------------- (1)

If you need to remove an application from listening, the application invokes the removeRadioBroadcastListener method of the monitor object as follows:

//=== remove itself from listening if there is a need
rbListener.mon.removeRadioBroadcastListener(rbListener);

How does a source broadcast an event? By notifying the service broker (see Figure 2c), which is done by invoking the notifyRadioBroadcastListeners method of the monitor object. The following code snippets show you that:

//=== instantiate a copy of the source application
RbSource rbSource = new RbSource();
//=== assuming that event id is equal to application id
RbEvent evt1 = new RbEvent("800");
---------------------- (2)
//=== setting the event type for listening application
evt1.setEventType(rbSource.getEventID1());
---------------------- (3)
//=== broadcast now
boolean ret = mon.notifyRadioBroadcastListeners(evt1);
---------------------- (4)

As you've noticed by now, to broadcast an event via the service broker server by sending a notification message involves more steps than becoming a listener. In line 2, we're basically creating an event object to be sent to the listener. In this case it's assumed the event ID is the application ID (which is 800). An application ID is just a unique number assigned manually by the application developer. If the same ID has already been allocated to another registered application, registration of the new listener with the monitor will fail (see line 1). Next (in line 3), we set the type of the event, since an application can have multiple data that needs to be processed in different ways. Each event type may be associated with one or more data. The real pushing of an event to the service broker is done in line 4. Nevertheless, if the previous event (which has an ID of 800) is still not processed by the listener, this method call would fail with a return status of false.

The role of the service broker server is to receive events from the source and push them to the listener by calling back the broadcastPerformed method of the listener. In our scenario the service broker will call back Application 1 (shown in Figure 3a). Thus a listener must be a type of org.omg.CORBA.CORBject object too (see Listing 4).

What follows is the most critical step as far as the business environment is concerned - the exchange of data between applications. Application 1 (listener application) retrieves the data from Application 2 (source application) via a peer-to-peer communication (see Figure 3b).

Surprisingly, this framework makes no assumption of any method to achieve that. You may ask why. A simple answer is because it's meant to be generic! Nevertheless, one may find getDataRetrieveMethod and getDataStoreMethod methods of the RbEvent class useful (see Listing 5). They're the placeholders where you can specify how to retrieve the data from the source application and/or how to store the data in the listening application (e.g., if the data format is different). It may include properties like a host name, FTP server name, data server name, user name and password, or even jdbc strings. It can even be the data itself, e.g., the XML data. It's up to you to decide which methods you're most comfortable with or are most suitable for your specific environment.

The following code snippet shows you an example of the inside of a listening application:

public String getDataRetrieveMethod() {
return
"sourceFileDir=/WebApp/Download"
+ "&"
"sourceFile=T9806812.txt"
+ "&"
"ftpUrl=146.135.30.167"
+ "&"
"ftpUsr=A04"
+ "&"
"ftpPwd=A04A04";
}
public String getDataStoreMethod() {
return
"listenerFileDir=/usr/local/WebApp/Download"
+ "&"
"listenerFile=T9806812.txt";
}

In the example above, the source application happened to be a legacy system with no other means of communication except FTP protocol. You'll notice that the getDataRetrieveMethod returns enough information for retrieval purposes. In this case the listening application is a UNIX box and the downloaded file is local as far as the listener is concerned. Therefore it doesn't need to include much information in the getDataStoreMethod method. Of course, a proper way to set all these properties is via setter methods such as setDataRetrieveMethod and setDataStoreMethod.

Last, as soon as the data is fully transferred from Application 2 to Application 1, the callback returns control to the event manager of the service broker. When this happens, the event manager removes the event object from the queue and continues with the next event, if there's any in the queue (see Figure 3c). The whole process repeats itself relentlessly (from Figures 2b to 3c), and now we have a new service broker framework based on CORBA.

What Did I Miss?
Now, after going through one specific scenario, I guess you have lots of questions. It sounds too easy and is it of any practical value in a business environment? Yes and no. The answer is Yes if you're looking for a generic framework and you don't mind further customization. If you're looking for a full-blown framework, you'll be disappointed. You may want to consider some other commercial products available. This framework doesn't specify how data is exchanged among various sources and listeners. Furthermore, since it's meant to be simple, each event type is forced to directly associate with the listener's application ID. The listener's registration with the service broker server would fail if another listener with the same ID has already registered. New-event generation from a source application is blocked until the previous event is consumed by the listener application. In other words, the event buffer size is only size 1 and the event is considered consumed as soon as the callback of a corresponding listener (broadcastPerformed method) returns.

The event manager is very simple too. Currently, a listener's object reference isn't purged from the HashMap even if the listener crashed or died, resulting in an error when the listener restarted and tried to register itself again with the same application ID. If this happens, the easiest way to work around it is to restart the service broker server and all applications involved in the framework. Due to a similar problem, if a source tries to broadcast an event to an invalid listener (crashed/died or not running for whatever reason), the listener-bound event isn't processed and other subsequent events (if any) are blocked. The event should have been discarded if its associated application ID is no longer valid and the source application should be informed about the status of the event. Another way of overcoming this is to set a certain timeout period for each event processed so that if the corresponding listening application is unreachable, the event will be rendered invalid. Once the event is made invalid, the source application will realize this just before it's about to generate a new event for the listener.

Other Considerations
One of the most critical features of an enterprise solution is the transaction. The processing of events by listeners and the subsequent removal of the events from the queue is not an atomic operation. What happens if after a listener has processed an event it fails just before the event is removed from the queue by the event-manager thread? How does it affect the integrity of the data when the listener wakes up again? To answer these questions, I used ObjectStore PSE Pro and the persistent version of JGL class library, dJGL, which enabled me to provide a scalable transactional capability to this service broker framework.

The following code snippet shows how minimal additions (in blue) into the service broker server codes (see Listing 2) will provide the transactional support commonly required in business environments:

...
//=== use djgl class library instead of jgl
import com.objectspace.djgl.*;
//=== add ObjectStore package too
import COM.odi.*;

public class monitorImpl extends Thread implements monitor
...

Database db = null;
Transaction tx = null;
monitorImpl() {
Session.create(null, null).join();
db = create("Queue.odb");
tx = Transaction.begin(ObjectStore.UPDATE);

queue = new Queue();
...
}

private static Database create(String dbName) {
try {
Database.open(dbName, ObjectStore.OPEN_UPDATE).destroy();
} catch (DatabaseNotFoundException e) {
}
return Database.create(dbName, 0777);
}

...
public void run() {
...
while( true ) {

tx = Transaction.begin(ObjectStore.UPDATE);
queue = (Queue)db.getRoot("queue");

if ( !queue.isEmpty() ) {
...
}

tx.commit();

}
}
...

Besides the transactions, you should consider the security issues as well. A mechanism needs to be in place so that only valid or authorized sources or listeners can broadcast events or register and receive the events, respectively. Other enhancements may include cross-system exceptions mapping and a centralized logging facility.

Conclusion
In a nutshell, this CORBA-based service broker framework allows required data that's shared among various heterogeneous subsystem applications to be synchronized by a server process, yet maintained locally in each application. It provides centralized control of the means of retrieving and storing data advertised to the service broker by the participating applications. It also provides a standardized way for a CORBA-based interface as an interprocess communication among various enterprise applications. Best of all, it allows companies not only to keep their existing "legacy" systems but to extend their functionalities as well as their roles, via Java and distributed CORBA-based technology.

Reference
Lewis, G., Barber, S. and Siegel, E. (1998). Programming with Java IDL. Wiley Computer Publishing.

Author Bio
E Ming Tan was the chief architect of corporate intranet-based paging applications at Singapore Telecom. He has worked with Cable & Wireless, Inc., and is currently working with MCI Worldcom on a Web-based customer billing system. He can be reached at [email protected]

	

Listing 1: 

(see source code file SBroker.java for details): 
public class SBroker { 
   public monitor getMonitor() { 
   } 
   monitor init() { 
   } 
   public static void main( String[] args ) { 
   } 
   static void out(String msg) { 
   } 
} 
  
Listing 2:  

(see source code file monitorImpl.java for details): 
public class monitorImpl extends Thread implements monitor { 
    monitorImpl() { 
    } 
    public sbroker.listener getApp(int id) { 
    } 
    public int getAppID(sbroker.listener rbListener) { 
    } 
    boolean getEventProcessed(sbroker.event evt) { 
    } 
    public boolean notifyRadioBroadcastListeners(sbroker.event rbEvent) { 
    } 
    public boolean addRadioBroadcastListener(sbroker.listener rbListener) { 
    } 
    public boolean removeRadioBroadcastListener(sbroker.listener rbListener) { 
    } 
    private void out(String msg) { 
    } 
    public void run() { 
    } 
} 
  
Listing 3:   

(see source code file RbListener.java for details): 
class RbListener extends Thread implements RadioBroadcastListener { 
     public RbListener() { 
     } 
     public int getAppID() { 
     } 
     public void broadcastPerformed(sbroker.event rbEvent) { 
     } 
     public static void main(String argv[]) { 
     } 
     public void run() { 
          while(true) {}; 
     } 
} 
  
Listing 4: 

(see source code file RadioBroadcastListener.java and sbroker.listener.java for details): 
 public interface listener extends org.omg.CORBA.CORBject { 
    void broadcastPerformed(sbroker.event rbEvent); 
} 
  
Listing 5: 

(see source code file RbEvent.java for details): 
public class RbEvent extends java.util.EventObject implements java.io.Serializable,
 sbroker.event { 
    public RbEvent(String eventID) { 
    } 
    public String getEventID() { 
    } 
    public void setEventType(String evt) { 
    } 
    public String getEventType() { 
        return eventType; 
    } 
    public String getDataRetrieveMethod() { 
    } 
    public String getDataStoreMethod() { 
    } 
} 

  

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.