Building a CORBA Client

March 9, 2008 at 12:38 pm (CORBA, Unit 4) ()

Clients are often (though not always) simpler than servers by nature, so they are easier to implement in that regard as well.

Implementing the Client

There are only a handful of concepts involved: how to use client stubs in the client implementation, how to locate a server object, and how to use the interfaces of a server object after it has been located.

Using Client Stubs

When StockServer.idl is compiled, the IDL compiler generated client stubs as well as server skeletons. Open the _StockServerStub.java file and have a look at it:

public float getStockValue(String symbol) {

}

public String[] getStockSymbols() {

}

Marshal the parameters through the ORB to the remote object and then marshal the return value back to the client. The Java compiler is smart enough to compile this file automatically, but in C++ client implementation, the client stub object should be linked with the rest of the client application. The other thing to know about the client stub is that it specifies the actual interfaces for the server object.

Locating a Server Object

After a server registers itself with the Name Server, clients can locate that server object through the Name Server, bind to that server object, and subsequently call methods on the server object. In the StockMarketClient, binding to the server object takes place in the connect() method, as shown in Listing 1.5. This method first binds to the Name Server by looking for an object with the name NameService. Upon successfully locating a Name Server, the client proceeds to bind to an object with the name StockServer, which incidentally is the same name registered the StockServerImpl under. After this object is bound, the client is ready to do some work.

Listing 1.5. Binding to the StockServer server.

// Connect to the StockServer.

protected void connect() {

try {

// Get the root naming context.

org.omg.CORBA.Object obj = ourORB.

resolve_initial_references(“NameService”);

NamingContext namingContext = NamingContextHelper.narrow(obj);

// Attempt to locate a StockServer object in the naming context.

NameComponent nameComponent = new NameComponent(“StockServer”, “”);

NameComponent path[] = { nameComponent };

myStockServer = StockServerHelper.narrow(namingContext. resolve(path));

}

catch (Exception ex) {

System.err.println(“Couldn’t resolve StockServer: ” + ex);

myStockServer = null;

return;

}

System.out.println(“Succesfully bound to a StockServer.”);

}

Using Server Object Interfaces

Listing 1.6 shows an example of how the server object interfaces are used, after the client has bound the server object.

Listing 1.6. Using the StockServer services.

// Do some cool things with the StockServer.

protected void doSomething() {

try {

// Get the valid stock symbols from the StockServer.

String[] stockSymbols = myStockServer.getStockSymbols();

// Display the stock symbols and their values.

for (int i = 0; i < stockSymbols.length; i++) {

System.out.println(stockSymbols[i] + ” ” +

myStockServer.getStockValue(stockSymbols[i]));

}

}

catch (org.omg.CORBA.SystemException ex) {

System.err.println(“Fatal error: ” + ex);

}

}

In Listing 1.6, the StockServer is first asked, through a call to getStockSymbols(), for a list of all stock symbols recognized by the server. The client then iterates through the list of stock symbols and queries the server, using getStockValue(), for the value of each stock. Each stock symbol and its respective value are printed to standard output.

Compiling and Running the Client

The entire listing for StockMarketClient.java appears in Listing 1.7. Note that most of the work for the client is done in the connect() and doSomething() methods, which you’ve already looked at.

Listing 1.7. StockMarketClient.java.

// StockMarketClient.java

package StockMarket;

import org.omg.CORBA.ORB;

import org.omg.CosNaming.NameComponent;

import org.omg.CosNaming.NamingContext;

import org.omg.CosNaming.NamingContextHelper;

// StockMarketClient is a simple client of a StockServer.

public class StockMarketClient {

// Create a new StockMarketClient.

StockMarketClient() {

}

// Run the StockMarketClient.

public void run() {

connect();

if (myStockServer != null) {

doSomething();

}

}

// Connect to the StockServer.

protected void connect() {

try {

// Get the root naming context.

org.omg.CORBA.Object obj = ourORB.

resolve_initial_references(“NameService”);

NamingContext namingContext = NamingContextHelper.narrow(obj);

// Attempt to locate a StockServer object in the naming context.

NameComponent nameComponent = new NameComponent(“StockServer”, “”);

NameComponent path[] = { nameComponent };

myStockServer = StockServerHelper.narrow(namingContext.resolve(path));

}

catch (Exception ex) {

System.err.println(“Couldn’t resolve StockServer: ” + ex);

myStockServer = null;

return;

}

System.out.println(“Succesfully bound to a StockServer.”);

}

// Do some cool things with the StockServer.

protected void doSomething() {

try {

// Get the valid stock symbols from the StockServer.

String[] stockSymbols = myStockServer.getStockSymbols();

// Display the stock symbols and their values.

for (int i = 0; i < stockSymbols.length; i++) {

System.out.println(stockSymbols[i] + ” ” +

myStockServer.getStockValue(stockSymbols[i]));

}

}

catch (org.omg.CORBA.SystemException ex) {

System.err.println(“Fatal error: ” + ex);

}

}

// Start up a StockMarketClient.

public static void main(String args[]) {

// Initialize the ORB.

ourORB = ORB.init(args, null);

StockMarketClient stockClient = new StockMarketClient();

stockClient.run();

// This simply waits forever so that the DOS window doesn’t

// disappear (for developers using Windows IDEs).

while (true)

;

}

// My ORB.

public static ORB ourORB;

// My StockServer.

private StockServer myStockServer;

}

Compiling the client application is an uncomplicated process. Like the server, the client can be compiled simply with the command

javac StockMarket\StockMarketClient.java

Again, ensure proper directory when compiling the client. The client program should be in the same directory as the one in which the server is compiled. First, start the Name Service and the StockServer application, if they aren’t running already. Then to execute the client application, type the command

java StockMarket.StockMarketClient

If the client runs successfully, the output similar to Listing 1.8 will be displayed in the screen.

Listing 1.8. StockMarketClient output.

1: Succesfully bound to a StockServer.

2: PTLF 72.00064

3: SWPK 37.671585

4: CHHL 78.37782

5: JTUX 75.715645

6: HUPB 41.85024

7: OHQR 14.932466

8: YOEX 64.3376

9: UIBP 75.80115

10: SIPR 91.13683

11: XSTD 16.010124

The stock symbols and their values will appear exactly as they appear in the server output.

Permalink Leave a Comment

Setting Path for .NET Framework

March 9, 2008 at 4:12 am (.NET, Practical) (, )

View the demo to set path for .NET Framework

Click Here

Permalink Leave a Comment

Building a CORBA Application – Part 3

March 9, 2008 at 1:53 am (CORBA, Unit 4) ()

Explanation (Listing 1.2):

package StockMarket;

Because the StockServer interface is part of the StockMarket module, the IDL compiler places the Java class and interface definitions into the StockMarket package. For convenience, StockServerImpl is placed into this package as well.

import java.util.Vector;

StockServerImpl will make use of the Vector class. This import should look familiar to Java developers already. The import statement behaves much like the #include preprocessor directive in C++; the java.util.Vector class is a container class that behaves as a growable array of elements.

import org.omg.CORBA.ORB;

import org.omg.CosNaming.NameComponent;

import org.omg.CosNaming.NamingContext;

import org.omg.CosNaming.NamingContextHelper;

The classes being imported here are commonly used in CORBA applications. The first, of course, is the class that provides the ORB functionality; the other classes are related to the CORBA Naming Service.

// StockServerImpl implements the StockServer IDL interface.

public class StockServerImpl extends _StockServerImplBase implements StockServer {

Given the StockServer IDL interface, the IDL compiler generates a class called StockServerImplBase and an interface called StockServer. To implement the StockServer IDL interface, the StockServerImpl class must extend _StockServerImplBase and implement StockServer, which is exactly what is declared here:

// Stock symbols and their respective values.

private Vector myStockSymbols;

private Vector myStockValues;

StockServerImpl uses Vectors to store the stock symbols and their values.

// Characters from which StockSymbol names are built.

private static char ourCharacters[] = { `A’, `B’, `C’, `D’, `E’, `F’, `G’, `H’, `I’, `J’, `K’, `L’, `M’, `N’, `O’, `P’, `Q’, `R’, `S’, `T’, `U’, `V’, `W’, `X’, `Y’, `Z’ };

The ourCharacters array contains the set of characters from which stock symbols are built.

// Path name for StockServer objects.

private static String ourPathName = “StockServer”;

The ourPathName variable stores the pathname by which this StockServer object can be located in the Naming Service. This can be any name.

// Create a new StockServerImpl.

public StockServerImpl() {

myStockSymbols = new Vector();

myStockValues = new Vector();

Although constructors aren’t a part of an IDL interface, the class implementing that interface will still have constructors so that the server can create the implementation objects. StockServerImpl has only a default constructor, but like any other class, a class that implements an IDL interface can have any number of constructors. This part of the constructor creates Vectors to hold the stock symbols and their respective values.

// Initialize the symbols and values with some random values.

for (int i = 0; i < 10; i++) {

Rather arbitrarily, the StockServerImpl creates ten stock symbols.

// Generate a string of four random characters.

StringBuffer stockSymbol = new StringBuffer(“ “);

for (int j = 0; j < 4; j++) {

stockSymbol.setCharAt(j, ourCharacters[(int)(Math.random()* 26f)]);

}

myStockSymbols.addElement(stockSymbol.toString());

For each stock symbol, the StockServerImpl creates a string of four random characters (chosen from the preceding ourCharacters array). The four-character length, like the number of symbols, was chosen arbitrarily. For the sake of simplicity, no checks are made for duplicate strings.

// Give the stock a value between 0 and 100. In this example,

// the stock will retain this value for the duration of the application.

myStockValues.addElement(new Float(Math.random() * 100f));

}

Here, a random value between 0 and 100 is given to each stock symbol. In this example, the stock will retain the assigned value for as long as the StockServerImpl runs.

// Print out the stock symbols generated above.

System.out.println(“Generated stock symbols:”);

for (int i = 0; i < 10; i++) {

System.out.println(“ ” + myStockSymbols.elementAt(i) + ” ” +

myStockValues.elementAt(i));

}

System.out.println();

}

Finally, the constructor prints out the stock symbols and their values.

// Return the current value for the given StockSymbol.

public float getStockValue(String symbol) {

// Try to find the given symbol.

int stockIndex = myStockSymbols.indexOf(symbol);

if (stockIndex != -1) {

// Symbol found; return its value.

return ((Float)myStockValues.elementAt(stockIndex)).

floatValue();

} else {

// Symbol was not found.

return 0f;

}

}

The getStockValue() method takes a String, attempts to find a match in the myStockSymbols data member, and returns the value for the stock symbol (if found). If the stock symbol is not found, a zero value is returned.

// Return a sequence of all StockSymbols known by this StockServer.

public String[] getStockSymbols() {

String[] symbols = new String[myStockSymbols.size()];

myStockSymbols.copyInto(symbols);

return symbols;

}

The getStockSymbols() method simply creates an array of Strings, copies the stock symbols (contained in myStockSymbols) into the array, and returns the array.

// Create and initialize a StockServer object.

public static void main(String args[]) {

The main() method in StockServerImpl creates a StockServerImpl object, binds that object to a naming context, and then waits for clients to call methods on that object.

try {

Because the methods that main() will later call might throw exceptions, those calls are wrapped in a try catch block.

// Initialize the ORB.

ORB orb = ORB.init(args, null);

Before doing anything with the ORB, the server application must first initialize the ORB.

// Create a StockServerImpl object and register it with the ORB.

StockServerImpl stockServer = new StockServerImpl();

orb.connect(stockServer);

Here a new StockServerImpl object is created and registered with the ORB.

// Get the root naming context.

org.omg.CORBA.Object obj = orb.

resolve_initial_references(“NameService”);

NamingContext namingContext = NamingContextHelper.narrow(obj);

Now for a little black magic. The CORBA Naming Service is a service that allows CORBA objects to register by name and subsequently be located, using that name, by other CORBA objects. In order for clients to connect to the StockServerImpl, they must have some way of locating the service on the network. One way to accomplish this is through the CORBA Naming Service. Here, a NamingContext object is located by resolving a reference to an object named NameService.

// Bind the StockServer object reference in the naming

// context.

NameComponent nameComponent = new NameComponent(ourPathName, “”);

NameComponent path[] = { nameComponent };

namingContext.rebind(path, stockServer);

Now the NamingContext object is asked to bind the StockServerImpl object to the pathname defined earlier (StockServer). Clients can now query the Naming Service for an object by this name; the Naming Service will return a reference to this StockServerImpl object.

// Wait for invocations from clients.

java.lang.Object waitOnMe = new java.lang.Object();

synchronized (waitOnMe) {

waitOnMe.wait();

}

}

Because the StockServerImpl object is now registered with the Naming Service, the only thing left to do is to wait for clients to invoke methods on the object. Because the actual handling of these method invocations occurs in a separate thread, the main() thread simply needs to wait indefinitely.

catch (Exception ex) {

System.err.println(“Couldn’t bind StockServer: ” + ex.

getMessage());

}

}

}

If any exceptions are thrown by any of the methods called, they are caught and handled here.

Compiling and Running the Server

Compiling the server application is simple. Issue the command

javac StockMarket\StockServerImpl.java


Tip: Before compiling the server, make sure that your CLASSPATH contains the appropriate directory or file for the CORBA classes. For Sun’s JavaIDL package, the file (directory where JavaIDL is installed) /lib/classes.zip will appear in the CLASSPATH. Consult your CORBA product’s documentation to determine your CLASSPATH setting.


The exact method for running the Name Server varies from product to product, but the end result is the same. For Sun’s JavaIDL, simply running nameserv will bring up the Name Server.

When the Name Server is running, you’re ready to run the server. You can invoke the server with the command

java StockMarket.StockServerImpl

If everything works correctly, see output similar to Listing 1.4 will be produced.

Listing 1.4. Sample StockServer output.

Generated stock symbols:

PTLF 72.00064

SWPK 37.671585

CHHL 78.37782

JTUX 75.715645

HUPB 41.85024

OHQR 14.932466

YOEX 64.3376

UIBP 75.80115

SIPR 91.13683

XSTD 16.010124



Permalink Leave a Comment

Building a CORBA Application – Part 2

March 9, 2008 at 12:46 am (CORBA, Unit 4) ()

Contd… from Part 1

 

Implementing the Server Interfaces

 

·         The IDL compiler generates a number of files; for each IDL interface, the compiler will generate a source file and header file for the client stub and a source file and header file for the server skeleton, resulting in four files per interface. (This is for an IDL compiler targeting C++; an IDL compiler targeting Java will not generate header files.)

·         Additionally, the IDL compiler can create separate directories for IDL modules; it can also create additional files for helper classes. Also, most IDL compilers allow to specify the suffix to use for client stubs and server skeletons. For example, the client stub files can be named StockMarket_c.h and StockMarket_c.cpp, or StockMarket_st.h and StockMarket_st.cpp.

 

Using Server Skeletons

·         The server skeleton provides a framework upon which to build the server implementation.

·         In the case of C++, a server skeleton is a set of classes that provides pure virtual methods (methods with no implementations) or methods that delegate to methods in another class (tie class).

·         The developer has to provide the implementations for these methods. In the case of Java, a server skeleton combines a set of helper classes with an interface, for which you, again, provide the implementation.

·         The compiler produced a directory called StockMarket (corresponding to the name of the IDL module defined in StockMarket.idl). Within this directory are a number of files containing client stub and server skeleton definitions:

StockSymbolHelper.java

StockSymbolListHolder.java

StockSymbolListHelper.java

StockServer.java

StockServerHolder.java

StockServerHelper.java

_StockServerStub.java

_StockServerImplBase.java

·         Note that the Java interface describing the StockServer services is contained in the StockServer.java file. Its contents appear in Listing 1.2.

·         The StockServerImplBase.java file contains a helper class from which the implementation classes are derived.

 

Listing 1.2. StockServer.java.

/*

 * File: ./StockMarket/StockServer.java

 */

package StockMarket;

public interface StockServer extends org.omg.CORBA.Object {

    float getStockValue(String symbol);

    String[] getStockSymbols();

}

·         Examining Listing 1.2, the StockServer interface is placed in the StockMarket package. Furthermore, this interface extends the org.omg.CORBA.Object interface.

·         All CORBA object interfaces extend this interface.

·         Finally, the StockServer interface contains two methods that correspond to the IDL methods in StockServer.idl. Note, however, that the IDL types have been mapped to their Java counterparts: StockSymbol, which was typedef‘ed as an IDL string, maps to a Java String; StockSymbolList, which was a sequence of StockSymbols, is mapped to a Java array of Strings. The IDL float is mapped to a Java float.

 

Writing the Implementation

The implementation for the StockServer is straightforward.

Listing 1.3. StockServerImpl.java.

// StockServerImpl.java

package StockMarket;

import java.util.Vector;

import org.omg.CORBA.ORB;

import org.omg.CosNaming.NameComponent;

import org.omg.CosNaming.NamingContext;

import org.omg.CosNaming.NamingContextHelper;

// StockServerImpl implements the StockServer IDL interface.

public class StockServerImpl extends _StockServerImplBase implements StockServer {

// Stock symbols and their respective values.

          private Vector myStockSymbols;

          private Vector myStockValues;

          // Characters from which StockSymbol names are built.

          private static char ourCharacters[] = { `A’, `B’, `C’, `D’, `E’, `F’,   `G’, `H’, `I’, `J’, `K’, `L’, `M’, `N’, `O’, `P’, `Q’, `R’, `S’, `T’, `U’, `V’, `W’, `X’, `Y’, `Z’ };

          // Path name for StockServer objects.

          private static String ourPathName = “StockServer”;

         

          // Create a new StockServerImpl.

          public StockServerImpl() {

                  myStockSymbols = new Vector();

                myStockValues = new Vector();

                // Initialize the symbols and values with some random values.

                for (int i = 0; i < 10; i++) {

                                // Generate a string of four random characters.

                                StringBuffer stockSymbol = new StringBuffer(“    “);

                                for (int j = 0; j < 4; j++) {

                                                stockSymbol.setCharAt(j, ourCharacters[(int)(Math.random()* 26f)]);

                                }

                                myStockSymbols.addElement(stockSymbol.toString());

                                // Give the stock a value between 0 and 100. In this example,

                                // the stock will retain this value for the duration of the application.

                                myStockValues.addElement(new Float(Math.random() * 100f));

                }

                // Print out the stock symbols generated above.

                System.out.println(“Generated stock symbols:”);

                for (int i = 0; i < 10; i++) {

                                System.out.println(“  ” + myStockSymbols.elementAt(i) + ” ” + myStockValues.elementAt(i));

                }

                System.out.println();

          }

 

          // Return the current value for the given StockSymbol.

          public float getStockValue(String symbol) {

                // Try to find the given symbol.

                int stockIndex = myStockSymbols.indexOf(symbol);

                if (stockIndex != -1) {

                                // Symbol found; return its value.

                                return ((Float)myStockValues.elementAt(stockIndex)). floatValue();

                }

                else {

                                // Symbol was not found.

                                return 0f;

                }

          }

 

          // Return a sequence of all StockSymbols known by this StockServer.

          public String[] getStockSymbols() {

                String[] symbols = new String[myStockSymbols.size()];

                myStockSymbols.copyInto(symbols);

                return symbols;

          }

         

          // Create and initialize a StockServer object.

          public static void main(String args[]) {

                try {

                                // Initialize the ORB.

                                ORB orb = ORB.init(args, null);

                                // Create a StockServerImpl object and register it with the ORB.

                                StockServerImpl stockServer = new StockServerImpl();

                                orb.connect(stockServer);

                                // Get the root naming context.

                                org.omg.CORBA.Object obj = orb.resolve_initial_references(“NameService”);

                                NamingContext namingContext = NamingContextHelper.narrow(obj);

                                // Bind the StockServer object reference in the naming context.

                                NameComponent nameComponent = new NameComponent(ourPathName,”");

                                NameComponent path[] = { nameComponent };

                                namingContext.rebind(path, stockServer);

                                // Wait for invocations from clients.

                                java.lang.Object waitOnMe = new java.lang.Object();

                                synchronized (waitOnMe) {

                                                waitOnMe.wait();

                                }

                }

                catch (Exception ex) {

                                System.err.println(“Couldn’t bind StockServer: ” + ex. getMessage());

                }

          }

}



Permalink Leave a Comment