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 recent days, CORBA has fast become a standard for the development of distributed applications. A CORBA application may consist of one or more CORBA server objects and many clients who connect to these servers. A CORBA server object makes itself available to the client by registering with the CORBA Naming Service or a CORBA Trader Service. A client locates the desired server object on the network by using this Naming or Trader service. Once the server object is located, the client receives a reference to it. Using this reference, the client can invoke methods on the server object and carry out its desired work. Thus it's the client that usually makes use of server facilities; the server simply returns the results of method invocations to the client. However, in some situations, it may be necessary for the server to invoke a method on the client object. For example, the server may like to notify the client of the occurrence of a certain event on the server or the completion of a processing job requested by the client. This method of invocation on the client is called Callback. CORBA specifications allow Callbacks on clients. This article discusses the implementation of CORBA callbacks using Java.

CORBA specification is language-neutral and thus both client and server programs can be implemented in different languages as selected by the programmer. To implement Callbacks, a client must pass a reference of itself to the server. The server is responsible for storing such references to different client objects and calling methods on the appropriate client as and when required. The server must store these references in a language-neutral format. Thus a proper CORBA data type should be used for storing such references. This article uses the example of a traffic light controller to discuss the implementation of CORBA Callbacks using Java. Java has been used as the implementation language for both client and server applications; however, any other language of choice may be used for the implementation.

The traffic light controller application design consists of a traffic light controller object and several traffic light objects (see Figure 1).

Figure 1
Figure 1:

Each traffic light object, when created, registers itself with the controller. The controller stores the reference to each registered object. The controller object acts as a CORBA server that registers itself with the CORBA Naming Service. A traffic cop object that wishes to control the lights at a particular junction locates the controller object by looking up the CORBA Naming Service for the desired name. Once the controller is located, it'll retrieve the number of lights that the controller is currently managing. The user interface of the cop application shown in Figure 2 displays the panel for each registered traffic light.

Figure 2
Figure 2:

Using these panels, the cop sets the states (colors) of the various lights and requests appropriate changes to the controller. The controller, in turn, scans through the list of registered lights and requests the lights to set the desired state (color) by calling a method on each of the light objects.

CORBA IDL
The development of a CORBA application begins by writing Interface Definition Language (IDL) code. The CORBA IDL for the traffic lights application is shown in Listing 1.

The module traffic defines two interfaces - TrafficLight and TrafficCoordinator. The TrafficLight interface defines CORBA traffic light objects while the TrafficCoordinator interface defines the CORBA coordinator interface.

The TrafficLight interface contains a short data type that stores the light number. It also provides a method called SetColor(), which is called by the coordinator to set the state of the traffic light. This is a Callback method, which is invoked by a CORBA server object.

The coordinator interface declares a CORBA sequence variable to hold references to registered TrafficLight objects. The sequence is implemented in Java using a Java array or a Java Vector class. The coordinator declares a method called Register(), which is called by the TrafficLight object to register itself with the coordinator. The coordinator declares another method called SetColor(), which is called by the traffic cop application. The SetColor() method receives two parameters - the traffic light number and the color for the light. The coordinator uses this traffic light number to locate the desired traffic light object and sets the color to the desired one by calling SetColor() method on the object.

Mapping IDL to Java
I used Visigenic VBroker for Java for the development of the application. The first step in developing the application is to map the IDL code to Java. The following command line will do the mapping. Note that Visigenic provides the idl2java utility.

idl2java -no_tie -no_comments traffic.idl

The -no_tie option tells the compiler not to generate the tie classes and the -no_comments option disables the comments generation. The compiler creates a Java package with the same name as the CORBA module - traffic. The two CORBA interfaces are mapped to two Java interfaces - TrafficLight and TrafficCoordinator. The idl2java compiler also creates the implementation classes and the example classes for the two interfaces. The files _example_TrafficLight.java and _example_TrafficCoordinator.java can be used to provide the implementation of the two CORBA interfaces. Maintain a backup of the original files to ensure that your implementation code isn't overwritten the next time you run idl2java compiler. Copy the _example_TrafficLight.java to TrafficLightImpl.java and _example_TrafficCoordinator.java to the TrafficCoordinator.java file. You'll write your implementation code in the newly copied files.

Developing the Application
The source code for TrafficLightImpl.java is given in Listing 2. The class declares a variable number of short data types for holding the light number. It declares one more variable of Java class type as TrafficLightServer. The source for the TrafficLightServer class is given in Listing 3 and is discussed later. The class TrafficLightServer creates the object of TrafficLightImpl class. The SetColor() method of the implementation class (TrafficLightImpl) uses this reference to call the SetColor() method on the TrafficLightServer object. The constructor for the TrafficLightImpl class receives two parameters - the reference to TrafficLightServer object, which called this constructor, and the light number. The two parameters are saved into the two class variables discussed above. The constructor prints an appropriate message to the user upon successful creation of the object. The accessor and modifier methods for the LightNumber attribute, respectively, retrieve and save the value to the local class variable - Number. The SetColor() method of TrafficLightImpl class simply calls the SetColor() method of the TrafficLightServer class.

Now look at the implementation of the TrafficLightServer class given in Listing 3. This class is derived from the Frame class and is a Java command line program. The program receives one command line argument that specifies the number for the traffic light to be created. The init() method sets the location of the frame, depending on the light number. For simplicity, only four traffic light objects are considered. The init() method then builds the user interface for the traffic light object by creating three objects of the TLightPanel class. The object hierarchy for the user interface of TrafficLightServer is shown in Figure 3.

Figure 3
Figure 3

The TLightPanel class is derived from Panel class and creates a traffic light in the panel painted in a given color.

After creating the three TLightPanel objects and adding them to the container, the init() method of the TrafficLightServer class sets the listener for window events, and sets the default light color to red by calling the SetRedLight() method. Once the user interface is constructed, the main() method of the TrafficLightServer class resolves the reference to the CORBA Naming Service and locates the coordinator object. It registers the newly created traffic light object with the coordinator by calling its Register() method. The program then waits for invocations to be made by the controller.

The TrafficCoordinatorImpl class provides the implementation for the CORBA TrafficCoordinator interface. The source for the TrafficCoordinatorImpl class is given in Listing 4. The class declares a variable called LightsList from the Java Vector class. This Vector variable is used for implementing the CORBA sequence declared in IDL. The class constructor prints an appropriate message to the user upon successful creation of the object. The accessor method for the lights attribute copies each element of the vector into an array of TrafficLight objects and returns the array to the caller. The modifier method for the lights attribute isn't implemented as this isn't required for the current application. The Register() method receives the reference to the traffic light object and copies it into the vector. The method then prints an appropriate message to the user upon successful registration of the light. The SetColor() method is called by the traffic cop application. The method receives two parameters - the light number and the color to be set. Note that the color parameter is passed as a Java String rather than as an object of the Java Color class. CORBA doesn't provide a Color data type. Thus, if you use the Color class in Java, you'll need to implement both the traffic cop application and the coordinator application. The method SetColor() iterates through the list of registered light objects, and for each object the internal light number is verified against the number received as a parameter. If the match is found, the SetColor() method on the matched light object is called. The TrafficCoordinatorImpl class is instantiated by the TrafficCoordinatorServer class.

The TrafficCoordinatorServer class source is given in Listing 5. The main() method of the class initializes the ORB, creates the coordinator object and exports it to ORB. The method then obtains a reference to the Naming Service and binds the newly created object to the Naming Service with the name Coordinator. The TrafficLight and TrafficCop objects locate the coordinator object using this name. The coordinator then simply waits for invocations to occur.

Finally, the TrafficCop class creates a traffic cop application. The cop application locates the desired controller object and receives a list of registered objects from the controller. The user interface then shows all the lights with the initial color for each light set to red. The object hierarchy for the user interface is shown in Figure 4.

Figure 4
Figure 4:

The user interface allows the user to click on each of the traffic light objects to select the desired color. After the selection of state for each light object, the user presses the Set button to set the various traffic lights to the desired states.

The main() method of the TrafficCop class initializes the ORB and obtains a reference to the Naming Service. It then locates the Coordinator object and obtains a reference to it. The program retrieves the array of light objects from the coordinator by calling the accessor method - lights() - on the coordinator object. The main() method then creates an instance of the TrafficCop class. The constructor of TrafficCop calls the init() method, of the class to construct the user interface of the application. The class constructor calls the init() method, which constructs the object of the TrafficBasePanel class and a button object and adds the two components to the container using BorderLayout manager. The program then sets the window event listener and displays the frame window to the user.

The TrafficBasePanel class is derived from the Panel class. The class constructor looks up the number of light objects received by the cop object and constructs the number of TrafficLightsPanel objects that's equal to this number.

MAXPANELS = Cop.Lights.length;
LightsPanel = new TrafficLightsPanel[MAXPANELS];

Each TrafficLightsPanel object displays a traffic light consisting of three light objects. The class constructor calls the init() method, which sets up a layout manager to display the four light panels and add them to the base panel. Once again, for simplicity, only four lights are considered.

The Update() method of the TrafficBasePanel class is called by the TrafficCop object whenever the user presses the Set button. This causes a refresh of all the panels displayed on the Cop user interface to reflect the changes made by the user. The Update() method iterates through all the displayed light panels, retrieves the color setting for each panel and calls the SetColor() method on each of the light objects.

for (int i=0; i<maxpanels; i++)
{
Cop.Lights[i].SetColor (LightsPanel[i].clr);
}

The TrafficBasePanel class may hold up to four TrafficLightsPanel objects. The TrafficLightsPanel class constructor calls the init() method to do the user interface. The init() method creates three LightPanel objects for red, amber and green lights and adds them to the container. It then calls the SetRedLight() method of the class to set the default light selection to Red. The SetRedLight() method sets the color of the red light to red and the colors for the other two lights to gray. Similarly, the other two methods - SetAmberLight() and SetGreenLight() - set amber and green lights, respectively, and set the rest of the lights to gray. The TrafficBasePanel class implements the MouseListener interface. In the mousePressed() event, the clr string variable of the class is set to the appropriate color value, depending on the LightPanel object being clicked. The event handler also calls the appropriate set() method for setting the color of the traffic light to the desired one. For example, a click on the red light highlights the red light and the other two lights are turned gray.

Last, the LightPanel class is used for drawing individual lights - red, amber and green. The class constructor receives a reference to the TrafficLightsPanel object so the mouse events can be passed on to it. The second parameter specifies the color of the light. Depending on this parameter, the appropriate color string - red, amber or green - is printed on the light. The paint() method constructs the visual appearance of the traffic light. The SetColor() method of the class is called whenever the user updates the display of the cop application by pressing the Set button. The method copies the received color into the local class variable and repaints itself to show the changes.

Compiling the Application
As mentioned earlier, Visigenic VBroker for Java was used for developing and testing the application. The first step in building the application is mapping the IDL code to Java using the idl2java utility supplied by Visigenic. The following command line is used for mapping IDL code to Java:

idl2java -no_tie -no_comments traffic.idl

To compile the several Java classes discussed above and shown in Listings 2 through 6, use the make.bat file shown in Listing 7. This creates all relevant files for the application. The next step is to run the application.

Running the Application
To run the application, start the osagent service and the CORBA Naming Service. The following two command lines start these services:

start osagent –C

vbj -DORBservices=CosNaming -DSVCnameroot=TRAFFIC -DJDKrenameBug com.visigenic.vbroker.services.CosNaming.ExtFactory TRAFFIC namingLog

Next, start the coordinator service using the following command line:

start vbj -DORBservices=CosNaming -DSVCnameroot=TRAFFIC -DOAid=TSession TrafficCoordinatorServer

Once the coordinator is started, create the traffic lights using the following command:

vbj -DORBservices=CosNaming -DSVCnameroot=TRAFFIC -DOAid=TSession TrafficLightServer 1

This creates Traffic Light #1 and registers itself with the coordinator. The appropriate message is printed in the coordinator window. Likewise, create three more traffic lights, replacing the command line parameter with the appropriate number for each light.

At this stage, the screen displays four traffic lights (see Figure 2). Next, start the traffic cop application by using the following command line:

vbj -DORBservices=CosNaming -DSVCnameroot=TRAFFIC -DOAid=TSession TrafficCop

The user interface for the traffic cop is shown in Figure 2. Click on the individual lights to set the desired colors and press the Set button. The corresponding lights will be set on the four light objects.

I didn't provide an unregister method for the traffic light. Thus, if you close a traffic light and re-create it, two copies will be registered with the coordinator. If you restart the cop application, both copies will be shown on the cop panel. To avoid this situation, close the coordinator and the cop and rerun the application if any of the lights need to be closed.

Conclusion
Callbacks in CORBA allow the CORBA server to call a method on the client. The callbacks are achieved by saving the reference to the client in the server class. The server object is responsible for tracking such references and invoking any of the public methods on the desired client by using these references. Callbacks are very useful in real-life situations to notify the client of the occurrence of a certain event or of the completion of processing on the server end. This article has discussed one such real-life example and explained how CORBA callbacks are implemented using Java.

About the Author
P. G. Sarang, Ph.D., is president and CEO of ABCOM Information Systems Pvt. Ltd., a consulting firm specializing in Internet, Java, CORBA, Visual C++ and VB programming and training. He can be reached at [email protected]

	

Listing 1: traffic.idl
 
module traffic 
{ 
 interface TrafficLight 
 { 
  attribute short LightNumber; 
  void SetColor (in string color); 
 }; 

 interface TrafficCoordinator 
 { 
  typedef sequence <TrafficLight> LightsList; 
  attribute LightsList lights; 
  void Register(in TrafficLight light); 
  void SetColor (in short LightNumber, in string color); 
 }; 
} 

Listing 2: TrafficLightImpl.java
 
//******************************************************************* 
// File : TrafficLightImpl.java 
// This file contains implementation of following classes 
// 1. TrafficLightImpl 
// copyright 1998: ABCOM Information Systems Pvt. Ltd., 
All rights reserved. 
//******************************************************************* 
  

//******************************************************************* 
// Class implemented : TrafficLightImpl 
// Derived from  : _TrafficLightImplBase  
// Implements   : None 
// Description   : 
// TrafficLightImpl class provides the implementation for CORBA  
// TrafficLight interface 
//******************************************************************* 

package traffic; 
import TrafficLightServer; 

public class TrafficLightImpl extends traffic._TrafficLightImplBase  
{ 
   //a variable which holds light number  
   private short Number;  
   // The LightServer variable declared below holds a  
   // reference to the server object which creates 
   // this object 
   private TrafficLightServer LightServer; 
  
   // class constructor - receives reference to TrafficLightServer 
   // object and the the light number to be assigned  
   // to the constructed object. 
   public TrafficLightImpl(TrafficLightServer LightServer, 
                           short LightNumber)  
   { 
      super("Traffic Light" + String.valueOf (LightNumber)); 
      this.LightServer = LightServer; 

      // print the message on the system console to inform 
      // the user that the Traffic Light is created. 
      System.out.println ("Traffic Light #"  
                          + String.valueOf (LightNumber) 
                          + " created"); 
      Number = LightNumber; 
   } 

   // no-argument constructor 
   public TrafficLightImpl() { 
      super(); 
   } 

   // The SetColor method calls the SetColor method  
   // on the server object to set the states of three 
   // lights 
   public void SetColor(java.lang.String color)  
   { 
      LightServer.SetColor (color); 
   } 

   // modifier method for LightNumber attribute 
   public void LightNumber(short LightNumber)  
   { 
      this.Number = LightNumber; 
   } 

   // accessor method for LightNumber attribute 
   public short LightNumber() { 
      return Number; 
   } 
} 
  
  

Listing 3: TrafficLightServer.java
 
//******************************************************************** 
// File : TrafficLightServer.java 
// This file contains implementation of following classes 
// 1. TrafficLightServer 
// 2. TLightPanel 
// copyright 1998: ABCOM Information Systems Pvt. Ltd., All rights reserved. 
//******************************************************************** 

// Import the classes we are going to use 
import traffic.TrafficLightImpl; 
import traffic.TrafficCoordinator;  
import org.omg.CosNaming.*; 
import org.omg.CORBA.*; 
import java.awt.*; 
import java.awt.event.*; 

//********************************************************************* 
// Class implemented : TrafficLightServer 
// Derived from  : Frame 
// Implements   : None 
// Description   : 
// The TrafficLightServer class defines a Java Command line  
// program. The server creates object of TrafficLightImpl class, 
// obtains a reference to the TrafficCoordinator object and registers 
// the newly created traffic light object with the coordinator by  
// calling Register method of the coordinator object.  
//********************************************************************* 
public class TrafficLightServer extends Frame  
{ 
   // declare three TLightPanel variables for three colors.  
   TLightPanel RedLight, AmberLight, GreenLight; 

   // class constructor 
   public TrafficLightServer (String[] args) 
   { 
      super ("# " + args[0]); 
      init (args); 
   } 
  
   // the program execution begins here 
   // the first command line argument specifies the light number.  
   static public void main (String[] args) 
   { 
      if (args[0] == null) 
      { 
         System.out.println ("Usage: Java TrafficLightServer LightNumber"); 
         System.exit(0); 
      } 
  
      // create an instance of the server class 
      TrafficLightServer obj = new TrafficLightServer (args); 
  
      try 
      { 
         // obtain a reference to ORB 
         ORB orb = ORB.init (args, null); 
         // create a traffic light implementation object 
         TrafficLightImpl TL =  
                               new TrafficLightImpl( 
                                       obj, 
                                       (short)Integer.parseInt(args[0])); 
         // Export the newly created object 
         //  orb.connect(TL); 

         // Get a reference to the Naming service 
         org.omg.CORBA.Object nameServiceObj =  
               orb.resolve_initial_references("NameService"); 
         if (nameServiceObj == null) 
         { 
            System.out.println("nameServiceObj = null"); 
            return; 
         } 

         // do type casting 
         NamingContext nameService =  
                     NamingContextHelper.narrow (nameServiceObj); 
         if (nameService == null) 
         { 
            System.out.println("nameService = null"); 
            return; 
         } 

         // Locate and register with coordinator 
         NameComponent[] Coordinator = {new NameComponent("Coordinator", "")}; 
  
         traffic.TrafficCoordinator MyCoordinator = 
                  traffic.TrafficCoordinatorHelper.narrow(nameService.resolve(Coordinator)); 
  
         if (MyCoordinator == null) 
            System.out.println ("could not locate Coordinator");  
         MyCoordinator.Register (TL); 
  
         // wait forever for current thread to die 
         Thread.currentThread().join(); 
      } 
      catch (org.omg.CORBA.SystemException e) 
      { 
         System.err.println (e); 
      } 
      catch(Exception e) 
      {  
         System.err.println(e); 
      } 
   } 
  
   public void init(String[] args) 
   { 
      // set the location for traffic lights frame 
      int x=0, y=0; 
  
      // only four lights are assumed here 
      switch (Integer.parseInt (args[0])) 
      { 
      case 1: 
         x=0; y=0; 
         break; 
      case 2: 
         x=125; y=0; 
         break; 
      case 3: 
         x=250; y=0; 
         break; 
      case 4: 
         x=375; y=0; 
         break; 
      } 
      // set the size and location of the application frame 
      setBounds (x, y, 5, 300); 
      // set the layout manager 
      setLayout (new GridLayout (3, 1, 10, 10)); 
  
      // create three light panel objects  
      // and add them to the container 
      RedLight = new TLightPanel (Color.red); 
      AmberLight = new TLightPanel (Color.orange); 
      GreenLight = new TLightPanel (Color.green); 
      add (RedLight); 
      add (AmberLight); 
      add (GreenLight); 
  
      // set up the window listener 
      addWindowListener (new WindowAdapter () 
         { 
         public void windowClosing (WindowEvent evt) 
         { 
         System.exit(0); 
         } 
         }); 
  
      // show the frame 
      show(); 
      // set lights to red  
      SetRedLight(); 
   } 
  
   // SetColor method receives the string describing the 
   // color for the light. It calls the apprpriate Set...  
   // method depending on the value of string received. 
   public void SetColor (String color) 
   { 
      if (color.equals ("Red")) 
         SetRedLight(); 
      else if (color.equals ("Amber")) 
         SetAmberLight(); 
      else if (color.equals ("Green")) 
         SetGreenLight(); 
      repaint(); 
   } 
  
   // The SetRedLight() method calls SetColor() method 
   // on individual light objects and enables red light 
   // disabling the other two lights 
   private void SetRedLight() 
   { 
      RedLight.SetColor (Color.red); 
      AmberLight.SetColor (Color.darkGray); 
      GreenLight.SetColor (Color.darkGray); 
   } 
  
   // The SetAmberLight() method calls SetColor() method 
   // on individual light objects and enables Amber light 
   // disabling the other two lights 
   private void SetAmberLight() 
   { 
      RedLight.SetColor (Color.darkGray); 
      AmberLight.SetColor (Color.orange); 
      GreenLight.SetColor (Color.darkGray); 
   } 
  
   // The SetGreenLight() method calls SetColor() method 
   // on individual light objects and enables Green light 
   // disabling the other two lights 
   private void SetGreenLight() 
   { 
      RedLight.SetColor (Color.darkGray); 
      AmberLight.SetColor (Color.darkGray); 
      GreenLight.SetColor (Color.green); 
   } 
} 

// class TLightPanel is extending from Panel class and is 
// used for displaying individual lights.  
class TLightPanel extends Panel 
{ 
   final int MARGIN=10; 
   Color color; 

   //class constructor 
   public TLightPanel(Color color) 
   { 
      super(); 
      this.color = color; 
   } 
  
   // create an oval shaped light and fill it with 
   // desired color. 
   public void paint (Graphics g) 
   { 
      Rectangle r = getBounds(); 
      setBackground (Color.lightGray); 
      g.draw3DRect (2, 2, r.width-4, r.height-4, false); 
      g.setColor (color); 
      g.fillOval (MARGIN,MARGIN,r.width-2*MARGIN,r.height-2*MARGIN); 
   } 
  
   // Set the color of this light object 
   public void SetColor (Color color) 
   { 
      this.color = color; 
      repaint(); 
   } 
} 
  
  

Listing 4:TrafficCoordinatorImpl.java
 
//****************************************************************************** 
// File  : TrafficCoordinatorImpl.java 
// This file contains implementation of following classes 
// 1. TrafficCoordinatorImpl 
// copyright 1998: ABCOM Information Systems Pvt. Ltd., All rights reserved. 
//*********************************************************************** 

package traffic; 

// Import the classes we are going to use 
import java.util.*; 

//*********************************************************************** 
// Class implemented : TrafficCoordinatorImpl 
// Derived from      : _TrafficCoordinatorImplBase 
// Implements        : None 
// Description       : 
// The TrafficCoordinatorImpl provides the  
// implementation for TrafficCoordinator interface  
// defined in our CORBA IDL. The class is derived  
// from _TrafficCoordinatorImplBase class which is  
// generated by   idl2java compiler. The instance  
// of this class acts   as a coordinator for  
// traffic  light objects. Each traffic light  
// object registers itself with  the coordinator.  
// The   traffic cop makes use of coordinator to 
// control the various traffic lights.  
//*********************************************************************** 
  

public class TrafficCoordinatorImpl extends traffic._TrafficCoordinatorImplBase  
{ 
   // declare a vector for storing references to traffic light objects 
   private Vector LightsList = new Vector(); 
  
   // class constructor 
   public TrafficCoordinatorImpl(java.lang.String name) { 
      super(name); 
      // print the message on the system console to inform 
      // the user that the object is created. 
      System.out.println ("Traffic Coordinator object created"); 
   } 

   // no-argument constructor  
   public TrafficCoordinatorImpl() { 
      super(); 
   } 
  
   // This method will be called by a traffic light (TrafficLight) 
   // object. The method receives a reference to the traffic light 
   // object which is to be registered with the coordinator. The  
   // method stores the reference to the object in the local vector.  
   public void Register(traffic.TrafficLight light)  
   { 
      // add to the local vector 
      LightsList.addElement (light); 
      // print out the message for the user 
      System.out.println ("Registered Traffic Light # " +  
                          String.valueOf (light.LightNumber())); 
   } 
  
   // The SetColor method is called by the traffic cop. The method 
   // receives the light number and the color to be set. The method 
   // searches through the registered list of traffic lights for the 
   // given light number. If the number is found, it calls the  
   // SetColor method on the traffic light object to set the desired 
   // color. 
   public void SetColor(short LightNumber,java.lang.String color)  
   { 
      // Iterate through the list of registered lights 
      for (int i=0; i<LightsList.size(); i++) 
      { 
         TrafficLight light = (TrafficLight)LightsList.elementAt(i); 
         // if a matching light is found, call its SetColor method. 
         if (light.LightNumber() == LightNumber) 
         { 
            light.SetColor (color);  
            break; 
         }  
      } 
   } 
  
   // modifier method for the lights attribute. As the current  
   // application does not require to modify this attribute, this  
   // method is not implemented.  
   public void lights(traffic.TrafficLight[] lights) { 
      // implement attribute  writer... 
   } 
  
  
   // accessor method for lights attribute. The method 
   // returns an array of TrafficLight objects to the caller. 
   public traffic.TrafficLight[] lights() { 
      // create an array for holding traffic light objects  
      traffic.TrafficLight[]  lightsList =  
            new traffic.TrafficLight[LightsList.size()]; 
  
      // initialize each element of the array  
      for (int i=0;  i<LightsList.size(); i++) 
         lightsList[i] = (traffic.TrafficLight)LightsList.elementAt(i); 
  
      // return the array to the caller. 
      return (lightsList); 
   } 
} 
  
  

Listing 5: TrafficCoordinatorServer.java
 
//*********************************************************************** 
// File : TrafficCoordinatorServer.java 
// This file contains implementation of following classes 
// 1. TrafficCoordinatorServer 
// copyright 1998: ABCOM Information Systems Pvt. Ltd., All rights reserved. 
//*********************************************************************** 

// Import the classes we are going to use 
import traffic.TrafficCoordinatorImpl; 
import org.omg.CosNaming.*; 
import org.omg.CORBA.*; 

//*********************************************************************** 
// Class implemented : TrafficCoordinatorServer 
// Derived from  : None 
// Implements   : None 
// Description   : 
// The TrafficCoordinatorServer class defines a Java Command line  
// program. The server creates object of TrafficCoordinatorImpl class 
// and registers the object with CORBA naming service by using the name 
// "Coordinator" for the object. After registering the object, the  
// program simply waits for invocations to occur.  
//*********************************************************************** 

public class TrafficCoordinatorServer 
{ 
   // program execution begins here 
   static public void main (String[] args) 
   { 
      try 
      { 
         // obtain reference to ORB. 
         ORB orb = ORB.init (args, null); 
         // create object of our coordinator implementation class 
         TrafficCoordinatorImpl TC =  
               new TrafficCoordinatorImpl("TrafficCoordinator"); 
         // Export the newly created object 
         orb.connect(TC); 

         // Get a reference to the Naming service 
         org.omg.CORBA.Object nameServiceObj = 
               orb.resolve_initial_references ("NameService"); 
         if (nameServiceObj == null) 
         { 
            System.out.println("nameServiceObj = null"); 
            return; 
         } 
  
         // Do type casting 
         NamingContext nameService = 
               NamingContextHelper.narrow (nameServiceObj); 
         if (nameService == null) 
         { 
            System.out.println("nameService = null"); 
            return; 
         } 

         // bind the Count object to the Naming service 
         NameComponent[] Name = {new NameComponent("Coordinator", "")}; 
         nameService.rebind(Name, TC); 

         // wait forever for current thread to die 
         Thread.currentThread().join(); 
      } 
      catch (org.omg.CORBA.SystemException e) 
      { 
         System.err.println (e); 
      } 
      catch(Exception e) 
      {  
         System.err.println(e); 
      } 
   } 
} 

Listing 6: TrafficCop.java
 
//*********************************************************************** 
// File : TrafficCop.java 
// This file contains implementation of following classes 
// 1. TrafficCop 
// 2. TrafficBasePanel 
// copyright 1998: ABCOM Information Systems Pvt. Ltd., All rights reserved. 
//*********************************************************************** 

// Import the classes we are going to use 

import traffic.TrafficLightImpl; 
import traffic.TrafficCoordinator;  
import org.omg.CosNaming.*; 
import org.omg.CORBA.*; 
import java.awt.*; 
import java.awt.event.*; 

//*********************************************************************** 
// Class implemented : TrafficCop 
// Derived from  : Frame 
// Implements   : ActionListener 
// Description   : 
// This class controls the various lights at a junction  
// with the help of traffic coordinator. The user interface 
// displays the available lights at the junction. The user 
// sets the lights to desired colors and presses set button 
// to request the controller to do the desired settings for 
// individual lights. 
//*********************************************************************** 

class TrafficCop extends Frame  
   implements ActionListener  
{ 
   // variable for holding reference to  
   // traffic coordinator 
   private static traffic.TrafficCoordinator MyCoordinator; 
   // set button variable 
   private Button SetButton; 
   // array to hold references to traffic light objects 
   public static traffic.TrafficLight[] Lights; 
   // base panel variable 
   private TrafficBasePanel basePanel; 

   // class constructor 
   public TrafficCop () 
   { 
      super ("Traffic Cop"); 
      init (); 
      // set size and location 
      setBounds (0,0, 200, 300); 
   } 
  
   // program execution begins here 
   static public void main (String[] args) 
   { 
      try 
      { 
         // initialize ORB 
         ORB orb = ORB.init (args, null); 

         // Get a reference to the Naming service 
         org.omg.CORBA.Object nameServiceObj = 
                  orb.resolve_initial_references ("NameService"); 
         if (nameServiceObj == null) 
         { 
            System.out.println("nameServiceObj = null"); 
            return; 
         } 

         // type cast the reference 
         NamingContext nameService = 
                  NamingContextHelper.narrow (nameServiceObj); 
         if (nameService == null) 
         { 
            System.out.println("nameService = null"); 
            return; 
         } 

         // Locate the Coordinator object 
         NameComponent[] Coordinator = {new NameComponent("Coordinator", "")}; 
  
         traffic.TrafficCoordinator t =  
            traffic.TrafficCoordinatorHelper.narrow (nameService.resolve(Coordinator)); 
         if (t == null) 
            System.out.println ("could not locate Coordinator"); 

         // retrieve the list of registered objects 
         Lights = t.lights(); 
      } 
      catch (org.omg.CORBA.SystemException e) 
      { 
         System.err.println (e); 
      } 
      catch(Exception e) 
      {  
         System.err.println(e); 
      } 
  
      // Create an instance of our application class 
      new TrafficCop (); 
   } 
  
   // init() provides the initialization of our application 
   public void init() 
   { 
      // create the set button and set action listener 
      SetButton = new Button ("Set"); 
      SetButton.addActionListener (this); 
      // create base panel object 
      basePanel = new TrafficBasePanel(this); 
      // add components to the container 
      add ("Center", basePanel); 
      add ("South", SetButton); 

      // set up window listener 
      addWindowListener (new WindowAdapter () 
         { 
         public void windowClosing (WindowEvent evt) 
         { 
         System.exit(0); 
         } 
         }); 

      // pack and show the frame 
      pack();  
      show(); 
   } 

   // process action events generated by set button 
   public void actionPerformed (ActionEvent evt) 
   { 
      if (evt.getSource() == SetButton) 
      { 
         // update the base panel to show 
         // changes to lights 
         basePanel.update(); 
      } 
   } 
} 

//*********************************************************************** 
// Class implemented : TrafficBasePanel 
// Derived from  : Panel 
// Implements   : None 
// Description   : 
// Class TrafficBasePanel provides a panel for showing the  
// individual light panels for all the registered traffic 
// lights.  
//*********************************************************************** 

class TrafficBasePanel extends Panel 
{ 
   private int MAXPANELS; 
   private TrafficCop Cop; 
   private TrafficLightsPanel[] LightsPanel; 
  
   // The update method iterates through all the displayed 
   // light panels and calls SetColor method on each. 
   public void update() 
   { 
      for (int i=0; i<MAXPANELS; i++) 
      { 
         Cop.Lights[i].SetColor (LightsPanel[i].clr); 
      }  
   } 
  
   // class constructor 
   public TrafficBasePanel(TrafficCop Cop) 
   { 
      super(); 
      this.Cop = Cop; 
      // set the variable to the number of lights 
      // received by the cop. 
      MAXPANELS = Cop.Lights.length; 
      // create light panels equal to the number  
      // of lights 
      LightsPanel = new TrafficLightsPanel[MAXPANELS]; 
      // initialize.  
      init(); 
   } 
  
   // init() method sets the user interface of the application. 
   private void init() 
   { 
      // set the layout manager. A maximum of 4 lights 
      // is assumed. 
      setLayout (new GridLayout (1, 4, 10, 10)); 
      // create the light panels and add to container. 
      for (int i=0; i<MAXPANELS; i++) 
      { 
         LightsPanel[i] = new TrafficLightsPanel(); 
         add (LightsPanel[i]);  
      } 
   } 
} 
  

//*********************************************************************** 
// Class implemented : TrafficLightsPanel 
// Derived from  : Panel 
// Implements   : MouseListener 
// Description   : 
// The TrafficLightsPanel class creates three LightPanel objects 
// and displays them to the user. When user clicks on any of the 
// lights, the class process the event and set the color  
// string variable. It then calls the appropriate Set.. method 
// to set the colors of three light objects. 
//*********************************************************************** 

class TrafficLightsPanel extends Panel implements MouseListener  
{ 
   // variable to hold three LightPanel objects 
   LightPanel RedLight, AmberLight, GreenLight; 
   // the color selected on this panel 
   String clr = "Red"; 
  
   // class constructor 
   public TrafficLightsPanel() 
   { 
      init(); 
   } 
  
  
   private void init() 
   { 
      setBackground (Color.lightGray); 
      // set layout manager 
      setLayout (new GridLayout (3, 1, 10, 10)); 
      // create three LightPanel objects and add 
      RedLight = new LightPanel (this, Color.red); 
      AmberLight = new LightPanel (this, Color.orange); 
      GreenLight = new LightPanel (this, Color.green); 
      add (RedLight); 
      add (AmberLight); 
      add (GreenLight); 
      // set default to red light 
      SetRedLight(); 
   } 
  
   // sets red light and others to gray. 
   private void SetRedLight() 
   { 
  
      RedLight.SetColor (Color.red); 
      AmberLight.SetColor (Color.darkGray); 
      GreenLight.SetColor (Color.darkGray); 
   } 
  
   // sets amber light and others to gray. 
   private void SetAmberLight() 
   { 
      RedLight.SetColor (Color.darkGray); 
      AmberLight.SetColor (Color.orange); 
      GreenLight.SetColor (Color.darkGray); 
   } 
  
   // sets green light and others to gray. 
   private void SetGreenLight() 
   { 
      RedLight.SetColor (Color.darkGray); 
      AmberLight.SetColor (Color.darkGray); 
      GreenLight.SetColor (Color.green); 
   } 
  
   // process mouse pressed events 
   public void mousePressed(MouseEvent evt)  
   { 
      // depeding on the source of mouse click 
      // event, set the appropriate light 
      if (evt.getSource() == RedLight) 
      { 
         clr = "Red"; 
         SetRedLight(); 
      } 
      if (evt.getSource() == AmberLight) 
      { 
         clr = "Amber"; 
         SetAmberLight(); 
      } 
      if (evt.getSource() == GreenLight) 
      { 
         clr = "Green"; 
         SetGreenLight(); 
      } 
   } 
  
   public void mouseExited (MouseEvent evt) {} 
   public void mouseClicked (MouseEvent evt) {} 
   public void mouseReleased (MouseEvent evt) {} 
   public void mouseEntered (MouseEvent evt) {} 
} 

// class LightPanel displays one traffic light  
class LightPanel extends Panel 
{ 
   private final int MARGIN=10; 
   private Color color; 
   private String str = ""; 

   // class constructor 
   public LightPanel(TrafficLightsPanel LightsPanel, Color color) 
   { 
      super(); 
  
      // depending on the input color parameter 
      // set the color string 
      this.color = color; 
      if (color == Color.red) 
         str = "Red"; 
      else if (color == Color.orange) 
         str = "Amber"; 
      else if (color == Color.green) 
         str = "Green"; 
      // set up mouse listener 
      addMouseListener (LightsPanel); 
   } 
  
   // draw the user interface for the light 
   public void paint (Graphics g) 
   { 
      Rectangle r = getBounds(); 
      setBackground (Color.lightGray); 
      g.draw3DRect (2, 2, r.width-4, r.height-4, false); 
      g.setColor (color); 
      g.fillOval (MARGIN,MARGIN,r.width-2*MARGIN,r.height-2*MARGIN); 
      FontMetrics tm = this.getFontMetrics (this.getFont ()); 
      if (color == Color.darkGray)  
         g.setColor (Color.white); 
      else 
         g.setColor (Color.black); 
      g.drawString (str,  
                    (int)(r.width/2.0 - tm.stringWidth ("Red")/2.0), 
                    (int)(r.height/2.0)); 
   } 
  
   // Set the color to the value of input color variable 
   public void SetColor (Color color) 
   { 
      this.color = color; 
      repaint(); 
   } 
} 

Listing 7. make.bat
 
javac -d . TrafficLightImpl.java 
javac TrafficLightServer. 
javajavac -d . TrafficCoordinatorImpl.java 
javac TrafficCoordinatorServer.java 
javac TrafficCop.java 
 

 

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.