10. Building CORBA Distributed Applications
10.1. Introduction
In the previous chapter, we saw how to create distributed applications in Java using the RMI package. Here, we address the same problem, this time using the CORBA architecture. CORBA (Common Object Request Broker Architecture) is a specification defined by the OMG (Object Management Group), which brings together many companies in the IT industry. CORBA defines a “software bus” accessible to applications written in different languages:

We will see that building a distributed application with CORBA is similar to the method used with Java RMI: the concepts are alike. CORBA offers the advantage of interoperability with applications written in other languages.
10.2. The Development Process for a CORBA Application
10.2.1. Introduction
To develop a CORBA client-server application, we will follow these steps:
- Writing the server interface using IDL (Interface Definition Language)
- generating the server’s “skeleton” and “stub” classes
- Writing the server
- writing the client
- compiling all the classes
- Launching a CORBA service directory
- launching the server
- launching the client
We will use the echo server, already used in the RMI context, as our first example. This will allow the reader to see the differences between the two methods.
The application has been tested with JDK 1.2.
10.2.2. Writing the server interface
As with Java RMI, the server is defined by its interface in relation to the client. While the classes implementing the server are not required by the client, those of its interface are. Whereas Java RMI used a Java interface to generate the server’s “skeleton” and “stub” classes, the Java CORBA architecture requires the interface to be described in a language other than Java. This interface will generate several classes, some of which are used by the client and others by the server.
The description of the echo interface will be as follows:
The interface description will be stored in an echo.idl file. It is written in the OMG’s IDL (Interface Definition Language). To be usable, it must be parsed by a program that will generate source files in the language used to develop the CORBA application. Here, we will use the idltojava.exe program, which will generate the necessary .java source files for the application based on the previous interface. The idltojava.exe program is not included with the JDK. It can be downloaded from the Sun website at http://java.sun.com.
Let’s analyze a few lines of the previous IDL interface:
is equivalent to the Java **package echo**. Compiling the interface will generate the Java package *echo*, i.e., a directory containing Java classes.
is equivalent to the Java **interface iSrvEcho**. It will generate a Java interface.
is equivalent to the Java statement **String echo(String msg)**. The types in the IDL language do not correspond exactly to those in the Java language. The correspondences are explained later in this chapter. In the IDL language, the parameters of a function can be input (**in**), output (**out**), or input-output (**inout**) parameters. Here, the *echo* method receives an input parameter *msg,* which is a string, and returns a string as the result.
The previous interface is that of our echo server. Recall that a remote interface describes the server object’s methods accessible to clients. Here, only the echo method will be available to clients.
10.2.3. Compiling the server’s IDL interface
Once the server interface is defined, we generate the corresponding Java files.
E:\data\java\corba\ECHO>dir *.idl
ECHO IDL 78 03/15/99 13:56 ECHO.IDL
E:\data\java\corba\ECHO>d:\javaidl\idltojava.exe -fno-cpp echo.idl
The -fno-cpp option is used to indicate that no preprocessor should be used (most commonly used with C/C++). Compiling the echo.idl file creates an echo subdirectory containing the following files:
E:\data\java\corba\ECHO>dir echo
_ISRVE~1 JAV 1,095 03/17/99 17:19 _iSrvEchoStub.java
ISRVEC~1 JAV 311 03/17/99 17:19 iSrvEcho.java
ISRVEC~2 JAV 825 03/17/99 5:19 PM iSrvEchoHolder.java
ISRVEC~3 JAV 1,827 03/17/99 5:19 PM iSrvEchoHelper.java
_ISRVE~2 JAV 1,803 03/17/99 5:19 PM _iSrvEchoImplBase.java
The iSrvEcho.java file is the Java file describing the server interface:
/*
* File: ./ECHO/ISRVECHO.JAVA
* From: ECHO.IDL
* Date: Mon Mar 15 13:56:08 1999
* By: D:\JAVAIDL\IDLTOJ~1.EXE Java IDL 1.2 Aug 18 1998 16:25:34
*/
package echo;
public interface iSrvEcho
extends org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity {
String echo(String msg)
;
}
We can see that this is almost a word-for-word translation of the IDL interface. If you’re curious enough to look at the contents of the other .java files, you’ll find more complex things. Here’s what the documentation says about the role of these different files:
the server interface
implements the previous iSrvEcho interface. It is an abstract class, the server’s “skeleton,” providing the server with the CORBA functionality required by the distributed application.
This is the server "stub" that the client will use. It provides the client with the CORBA functionality needed to access the server.
Provides the methods needed to manage CORBA object references
Provides the methods needed to manage the input and output parameters of the interface’s methods.
10.2.4. Compiling the classes generated from the IDL interface
It is a good idea to compile the preceding classes. We will see in another example that errors caused by incorrect operation of the idltojava generator can be detected here. Here, everything goes smoothly, and after compilation, the following files are present in the echo package directory:
E:\data\java\corba\ECHO\echo>dir
_ISRVE~1 JAV 1,095 03/17/99 17:19 _iSrvEchoStub.java
ISRVEC~1 JAV 311 03/17/99 17:19 iSrvEcho.java
ISRVEC~2 JAV 825 03/17/99 5:19 PM iSrvEchoHolder.java
ISRVEC~3 JAV 1,827 03/17/99 5:19 PM iSrvEchoHelper.java
_ISRVE~2 JAV 1,803 03/17/99 5:19 PM _iSrvEchoImplBase.java
_ISRVE~1 CLA 2,275 03/18/99 11:25 _iSrvEchoImplBase.class
_ISRVE~2 CLA 1,383 03/18/99 11:25 _iSrvEchoStub.class
ISRVEC~1 CLA 251 03/18/99 11:25 iSrvEcho.class
ISRVEC~2 CLA 2,078 03/18/99 11:25 iSrvEchoHelper.class
ISRVEC~3 CLA 858 03/18/99 11:25 iSrvEchoHolder.class
10.2.5. Server implementation
10.2.5.1. Implementation of the iSrvEcho interface
We defined the iSrvEcho interface earlier. We will now write the class that implements this interface. It will be derived from the _iSrvEchoImplbase.java class, which, as noted above, already implements the iSrvEcho interface.
// imported packages
import echo.*;
// class implementing remote echo
public class srvEcho extends _iSrvEchoImplBase{
// method performing the echo
public String echo(String msg){
return "[" + msg + "]";
}// end of echo
}// end of class
The code is self-explanatory. This class is saved in the file srvEcho.java in the parent directory of the iSrvEcho interface package.
You can compile it to verify:
E:\data\java\corba\ECHO>j:\jdk12\bin\javac srvEcho.java
E:\data\java\corba\ECHO>dir
ECHO IDL 78 03/15/99 13:56 ECHO.IDL
SRVECH~1 CLA 488 03/18/99 11:30 srvEcho.class
SRVECH~1 JAV 252 03/15/99 14:02 srvEcho.java
ECHO <REP> 03/17/99 5:19 PM echo
10.2.5.2. Writing the server creation class
As with an RMI client-server application, a CORBA server must be registered in a directory to be accessible by clients. It is this registration procedure that, at the development level, differs depending on whether you have a CORBA or RMI application. Here is the one for the echo CORBA server registered in the serverEcho.java file:
// Imported packages
import echo.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
//----------- EchoServer class
public class EchoServer{
// ------- main: starts the echo server
// syntax: machineDirectory portDirectory serviceName
// machine: machine supporting the CORBA directory
// port: port of the CORBA directory
// serviceName: name of the service to register
public static void main(String arg[]){
// Are the arguments present?
if(arg.length!=3){
System.err.println("Syntax: pg directoryMachine directoryPort serviceName");
System.exit(1);
}
// retrieve the arguments
String machine = arg[0];
String port = arg[1];
String serviceName = arg[2];
try{
// We need a CORBA object to work with
String[] initORB = {"-ORBInitialHost", machine, "-ORBInitialPort", port};
ORB orb = ORB.init(initORB, null);
// We add the service to the service directory
// It will be called srvEcho
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
NameComponent nc = new NameComponent(serviceName, "");
NameComponent path[]={nc};
// create the server and associate it with the srvEcho service
srvEcho echoServer = new srvEcho();
ncRef.rebind(path, serverEcho);
orb.connect(echoServer);
// follow-up
System.out.println("Echo server ready");
// waiting for client requests
java.lang.Object sync = new java.lang.Object();
synchronized(sync){
sync.wait();
}
} catch (Exception e) {
// An error occurred
System.err.println("Error " + e);
e.printStackTrace(System.err);
}
}// main
}// EchoServer
Below, we outline the basics of starting the server without delving into details that may seem complex at first glance. It is important to remember the key points from the previous example, as they will be present in every CORBA server.
10.2.5.2.1. Server Parameters
A CORBA server must register with a directory service operating on a given machine and port. Our application will receive these two pieces of information as parameters. The registered service must have a name, which will be the third parameter.
10.2.5.2.2. Creating the CORBA Directory Service Access Object
To access the directory service and register our echo server, we need an object called an ORB (Object Request Broker), obtained using the following class method:
Args: array of string pairs, each pair in the form (parameter, value)
Prop: application properties
The example uses the following sequence to obtain the ORB object:
String[] initORB={"-ORBInitialHost",machine,"-ORBInitialPort",port};
ORB orb = ORB.init(initORB, null);
The (parameter, value) pairs used are as follows:
("-ORBInitialHost", machine): This pair specifies the machine on which the CORBA service directory operates; here, it is the machine passed as a parameter to the server.
("-ORBInitialPort",port): This pair specifies the port on which the CORBA service directory operates, in this case the port passed as a parameter to the server.
The second parameter of the init method is set to null. If the first parameter had also been set to null, the (machine,port) pair used would have been the default (localhost,900).
10.2.5.2.3. Registering the server in the CORBA service directory
Registering the server in the directory is done with the following operations:
// add the service to the service directory
// it will be named srvEcho
org.omg.CORBA.Object objRef=
orb.resolve_initial_references("NameService");
NamingContext ncRef=NamingContextHelper.narrow(objRef);
NameComponent nc = new NameComponent(serviceName, "");
NameComponent path[]={nc};
// create the server and associate it with the srvEcho service
srvEcho echoServer = new srvEcho();
ncRef.rebind(path, serverEcho);
orb.connect(echoServer);
The first part of the code involves preparing the service name. This name is represented in the code by the variable path. A service name consists of several components:
- an initial component objRef, a generic object that must be cast to a NamingContext type, here ncRef.
- the service name, here `serviceName`, which was passed as a parameter to the server
These name components (NameComponent) are collected in an array, here path. It is this array that precisely “names” the created service. Once the name is created, it remains
- to associate it with an instance of the server (the srvEcho class constructed previously)
srvEcho serverEcho = new srvEcho();
- and register it in the directory
10.2.5.3. Compiling the server launch class
Compile the previous class:
E:\data\java\corba\ECHO>j:\jdk12\bin\javac serverEcho.java
E:\data\java\corba\ECHO>dir
ECHO IDL 78 03/15/99 13:56 ECHO.IDL
SERVEU~1 CLA 1,793 03/18/99 1:18 PM serveurEcho.class
SERVEU~1 JAV 1,806 03/16/99 15:38 serverEcho.java
SRVECH~1 CLA 488 03/18/99 11:30 srvEcho.class
SRVECH~1 JAV 252 03/15/99 14:02 srvEcho.java
ECHO <REP> 03/17/99 17:19 echo
10.2.6. Client write
10.2.6.1. The code
We are writing a client to test our echo service. We will pass the same three parameters to the client as we did to the server:
Machine: the machine where the CORBA service directory is located
Port: the port on which this directory operates
serviceName: name of the echo service
The client connects to the echo service and then prompts the user to type messages on the keyboard. These messages are sent to the echo server, which sends them back. A log of this dialogue is displayed on the screen.
The CORBA client for the echo service is very similar to the RMI client already written. Here again, the client must connect to a directory service to obtain a reference to the server object it wishes to connect to. The difference between the two clients lies there and there alone. Here is the code for the CORBA echo client:
10.2.6.2. Connecting the client to the server
The CORBA client above connects to the server using the following statement:
// establish a connection to the echo server
iSrvEcho echoServer = getEchoServer(machine, port, serviceName);
After this operation, the client holds a reference to the echo server. From this point on, a CORBA client is no different from an RMI client. The private method that establishes the connection to the server is as follows:
// imported packages
import java.io.*;
import echo.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
// ---------- cltEcho class
public class cltEcho {
public static void main(String arg[]){
// syntax: cltEcho directoryMachine directoryPort serviceName
// machine: machine where the CORBA service directory operates
// port: port where the service directory operates
// serviceName: name of the echo service
// argument validation
if(arg.length!=3){
System.err.println("Syntax: pg machineDirectory portDirectory serviceName");
System.exit(1);
}
// retrieve the parameters
String machine = arg[0];
String port = arg[1];
String serviceName = arg[2];
// connect to the echo server
iSrvEcho echoServer = getEchoServer(machine, port, serviceName);
// client-server communication
BufferedReader in = null;
String msg = null;
String response = null;
iSrvEcho server = null;
try{
// Open the keyboard stream
in = new BufferedReader(new InputStreamReader(System.in));
// Loop to read messages to send to the echo server
System.out.print("Message: ");
msg = in.readLine().toLowerCase().trim();
while(! msg.equals("end")){
// Send the message to the server and receive the response
response = serverEcho.echo(msg);
// follow-up
System.out.println("Server response: " + response);
// next message
System.out.print("Message: ");
msg = in.readLine().toLowerCase().trim();
}// while
// Done
System.exit(0);
// error handling
} catch (Exception e){
System.err.println("Error: " + e);
System.exit(2);
}// try
}// main
// ---------------------- getEchoServer
private static iSrvEcho getServerEcho(String machine, String port,
String serviceName){
// request a reference to the echo server
// followed by
System.out.println("--> Connecting to CORBA server...");
// the echo server reference
iSrvEcho echoServer = null;
try{
// request a CORBA object to work with
String[] initORB = {"-ORBInitialHost", machine, "-ORBInitialPort", port};
ORB orb = ORB.init(initORB, null);
// use the directory service to locate the echo server
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
// The service we're looking for is called srvEcho—we request it
NameComponent nc = new NameComponent(serviceName, "");
NameComponent path[]={nc};
echoServer = iSrvEchoHelper.narrow(ncRef.resolve(path));
} catch (Exception e){
System.err.println("Error locating the echo server ("
+ e + ")");
System.exit(10);
}// try-catch
// return the reference to the
return echoServer;
}// getEchoServer
}// class
We see the same code sequences as in the server:
- we create an ORB object that will allow us to contact the CORBA service directory
String[] initORB = {"-ORBInitialHost", machine, "-ORBInitialPort", port};
ORB orb = ORB.init(initORB, null);
- we define the different components of the echo service name
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
NameComponent nc = new NameComponent(serviceName, "");
NameComponent path[]={nc};
- We request a reference to the echo service from the directory service (this is where we differ from the server)
10.2.6.3. Compilation
E:\data\java\corba\ECHO>j:\jdk12\bin\javac cltEcho.java
E:\data\java\corba\ECHO>dir
CLTECH~1 CLA 2,599 03/18/99 1:51 PM cltEcho.class
CLTECH~1 JAV 2,907 03/16/99 16:15 cltEcho.java
ECHO IDL 78 03/15/99 1:56 PM ECHO.IDL
SERVEU~1 CLA 1,793 03/18/99 1:18 p.m. serverEcho.class
SERVEU~1 JAV 1,806 03/16/99 3:38 p.m. serverEcho.java
SRVECH~1 CLA 488 03/18/99 11:30 srvEcho.class
SRVECH~1 JAV 252 03/15/99 14:02 srvEcho.java
ECHO <REP> 03/17/99 5:19 PM echo
10.2.7. Tests
10.2.7.1. Starting the directory service
On a Windows machine, we start the directory service as follows:
which starts the directory service on port 1000 of the machine.
The tnameserv directory service produces a screen display that looks like the following:
Initial Naming Context:
IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f
6e746578743a312e3000000000010000000000000030000100000000000a69737469612d30303900
044700000018afabcafe000000027620dd9a000000080000000000000000
TransientNameServer: setting port for initial object references to: 1000
It’s hard to read, but note the last line: the service is active on port 1000.
10.2.7.2. Launching the echo server
The echo service is launched with three parameters:
E:\data\java\corba\ECHO>start j:\jdk12\bin\java echoServer localhost 1000 srvEcho
The server displays:
10.2.7.3. Launching the client on the same machine as the server
E:\data\java\corba\ECHO>j:\jdk12\bin\java cltEcho localhost 1000 srvEcho
--> Connecting to the CORBA server...
Message: msg1
Server response: [msg1]
Message: msg2
Server response: [msg2]
Message: end
10.2.7.4. Launching the client on a Windows machine other than the server
E:\data\java\corba\ECHO>j:\jdk12\bin\java cltEcho tahe.istia.univ-angers.fr 1000 srvEcho
--> Connecting to the CORBA server...
Message: abcd
Server response: [abcd]
Message: efgh
Server response: [efgh]
Message: end
10.3. Example 2: an SQL server
10.3.1. Introduction
Here we revisit the SQL server code previously examined in the context of Java RMI, again to highlight the similarities and differences between the two approaches. As a reminder, the role of this SQL server is as follows: it runs on a Windows machine and allows remote clients to access the public ODBC databases on that Windows machine.

The CORBA client could perform three operations:
- connect to the database of its choice
- send SQL queries
- close the connection
The server executes the client’s SQL queries and sends the results back to the client. This is its primary function, which is why we call it an SQL server. We apply the various steps previously covered with the echo server.
10.3.2. Writing the server’s IDL interface
As a reminder, here is the RMI interface we used for the server:
import java.rmi.*;
// the remote interface
public interface interSQL extends Remote{
public String connect(String driver, String url, String id, String password)
throws java.rmi.RemoteException;
public String[] executeSQL(String query, String separator)
throws java.rmi.RemoteException;
public String close()
throws java.rmi.RemoteException;
}
The roles of the various methods were as follows:
Connect: the client connects to a remote database, providing the driver, the JDBC URL, as well as its ID and password to access the database. The server returns a string indicating the result of the connection:
executeSQL: the client requests the execution of an SQL query on the database to which it is connected. It specifies the character that should separate the fields in the results returned to it. The server returns an array of strings:
for a database update query, where n is the number of rows updated
if the query generated an error
if the query returned no results
if the query returned results. The rows returned by the server are the result rows of the query.
Close: the client closes its connection to the remote database. The server returns a string indicating the result of this closure:
The server's IDL interface will be as follows:
module srvSQL{
typedef sequence<string> results;
interface interSQL{
string connect(in string driver, in string baseUrl, in string id, in string password);
results executeSQL(in string query, in string separator);
string close();
};// interface
};// module
The only new feature compared to what we saw with the echo server’s IDL interface is the use of the sequence keyword. This keyword allows you to define a one-dimensional array. The definition is done in two steps:
- defining a type to designate the array, here results:
The typedef keyword is well known to C/C++ programmers: it allows you to define a new type. Here, the type resultats is defined as equivalent to the type sequence<string>, i.e., a dynamic (unsized) array of character strings.
- using the new type where needed
The executeSQL method therefore returns an array of strings.
10.3.3. Compiling the server’s IDL interface
The previous IDL interface is placed in the file srvSQL.idl. We compile this file:
E:\data\java\corba\sql>d:\javaidl\idltojava -fno-cpp srvSQL.idl
E:\data\java\corba\sql>dir
SRVSQL IDL 275 03/19/99 9:59 srvSQL.idl
SRVSQL <REP> 03/19/99 9:41 srvSQL
We can see that the compilation created a directory named after the IDL interface module (srvSQL). Let’s look at the contents of this directory:
E:\data\java\corba\sql>dir srvSQL
RESULT~1 JAV 833 03/19/99 10:00 resultatsHolder.java
RESULT~2 JAV 1,883 03/19/99 10:00 resultatsHelper.java
_INTER~1 JAV 2,474 03/19/99 10:00 _interSQLStub.java
INTERS~1 JAV 448 03/19/99 10:00 interSQL.java
INTERS~2 JAV 841 03/19/99 10:00 interSQLHolder.java
INTERS~3 JAV 1,855 03/19/99 10:00 interSQLHelper.java
_INTER~2 JAV 4,535 03/19/99 10:00 _interSQLImplBase.java
Note that the Helper and Holder files are classes associated with the input/output parameters and results of the remote interface methods. The srvSQL directory contains all .java files related to the interSQL interface defined in the .idl file. It also contains files related to the results type created in the IDL interface.
The interSQL.java file is the Java file for our server’s interface. It is important to verify that what was automatically generated matches our expectations. The generated interSQL.java file is as follows:
/*
* File: ./SRVSQL/INTERSQL.JAVA
* From: SRVSQL.IDL
* Date: Fri Mar 19 09:59:48 1999
* By: D:\JAVAIDL\IDLTOJ~1.EXE Java IDL 1.2 Aug 18 1998 16:25:34
*/
package srvSQL;
public interface interSQL
extends org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity {
String connect(String driver, String urlBase, String id, String password)
;
String[] executeSQL(String query, String separator)
;
String close()
;
}
We can see that we have the same interface as the one used for the RMI client-server. So we can continue. Let’s compile all these .java files:
E:\data\java\corba\sql\srvSQL>j:\jdk12\bin\javac *.java
Note: _interSQLImplBase.java uses or overrides a deprecated API. Recompile with
"-deprecation" for details.
1 warning
E:\data\java\corba\sql\srvSQL>dir *.class
_INTER~1 CLA 3,094 03/19/99 10:01 _interSQLImplBase.class
_INTER~2 CLA 1,953 03/19/99 10:01 _interSQLStub.class
INTERS~1 CLA 430 03/19/99 10:01 interSQL.class
INTERS~2 CLA 2,096 03/19/99 10:01 interSQLHelper.class
INTERS~3 CLA 870 03/19/99 10:01 interSQLHolder.class
RESULT~1 CLA 2,047 03/19/99 10:01 resultsHelper.class
RESULT~2 CLA 881 03/19/99 10:01 resultatsHolder.class
10.3.4. Writing the SQL Server
We will now write the SQL server code. Recall that this class must derive from the abstract class _nomInterfaceImplBase generated by compiling the IDL file. Aside from this particularity and excluding the code sequences related to registering the service in a directory, the CORBA server code is identical to that of the RMI server:
// Imported packages
import java.sql.*;
import java.util.*;
import srvSQL.*;
// SQLServant class
public class SQLServant extends _interSQLImplBase{
// class global variables
private Connection DB;
// --------------- connect
public String connect(String driver, String url, String id,
String password){
// connect to the database at url using the driver driver
// authentication with username id and password mdp
String result = null; // result of the method
try{
// Load the driver
Class.forName(driver);
// connection request
DB = DriverManager.getConnection(url, id, mdp);
// OK
result="200 Connection successful";
} catch (Exception e){
// error
result = "500 Connection failed (" + e + ")";
}
// end
return result;
}
// ------------- executeSQL
public String[] executeSQL(String query, String separator){
// executes an SQL query on the database
// and places the results in an array of strings
// data required to execute the query
Statement S = null;
ResultSet RS = null;
String[] rows = null;
Vector results = new Vector();
String row = null;
try{
// Create the query container
S = DB.createStatement();
// execute query
if (! S.execute(query)) {
// update query
// return the number of updated rows
rows = new String[1];
lines[0] = "100 " + S.getUpdateCount();
return rows;
}
// This was a query
// retrieve the results
RS = S.getResultSet();
// number of fields in the ResultSet
int numFields = RS.getMetaData().getColumnCount();
// we process them
while(RS.next()){
// create the results row
row = "101 ";
for (int i = 1; i < nbChamps; i++)
line += RS.getString(i) + separator;
line += RS.getString(nbChamps);
// Add to the results vector
results.addElement(line);
}// while
// end of result processing
// release resources
RS.close();
S.close();
// return the results
int numLines = results.size();
if (numberOfLines == 0) {
lines = new String[1];
lines[0] = "501 No results";
} else {
lines = new String[results.size()];
for(int i=0;i<lines.length;i++)
lines[i] = (String) results.elementAt(i);
}//if
return lines;
} catch (Exception e){
// error
lines = new String[1];
lines[0] = "500 " + e;
return lines;
}// try-catch
}// executeSQL
// --------------- close
public String close(){
// closes the database connection
String result = null;
try{
DB.close();
result = "200 Database closed";
} catch (Exception e) {
result = "500 Error closing database (" + e + ")";
}
// Return the result
return result;
}
}// SQLServant class
This class is located in the SQLServant.java file that we are compiling:
E:\data\java\corba\sql>dir
SRVSQL IDL 275 03/19/99 9:59 srvSQL.idl
SRVSQL <REP> 03/19/99 9:41 srvSQL
SQLSER~1 JAV 2,941 03/15/99 9:09 SQLServant.java
E:\data\java\corba\sql>j:\jdk12\bin\javac SQLServant.java
E:\data\java\corba\sql>dir *.class
SQLSER~1 CLA 2,568 03/19/99 10:19 SQLServant.class
10.3.5. Writing the SQL Server Launch Program
The previous class represents the SQL server once it has been launched. Before that, it must be registered in a CORBA service directory. As with the echo service, we will do this using a special class to which we will pass three parameters at runtime:
Machine: the machine where the CORBA service directory is located
Port: the port on which this directory operates
serviceName: name of the SQL service
The code for this class is nearly identical to that of the class that performed the same task for the echo service. We have highlighted in bold the line that differs between the two classes: it does not create the same server object. We can see, therefore, that the server launch mechanism remains the same. If we isolate this mechanism into a class, as has been done here, it becomes virtually transparent to the developer.
// Imported packages
import srvSQL.*;
import org.omg.CosNaming.*;
import org.omg.CosNaming.NamingContextPackage.*;
import org.omg.CORBA.*;
//----------- SQLServer class
public class SQLServer{
// ------- main: starts the SQL server
public static void main(String arg[]){
// SQLServer machine port service
//do we have the correct number of arguments
if(arg.length!=3){
System.err.println("Syntax: pg machineCorbaDirectory portCorbaDirectory serviceName");
System.exit(1);
}
// retrieve the arguments
String machine = arg[0];
String port = arg[1];
String serviceName = arg[2];
String[] initORB = {"-ORBInitialHost", machine, "-ORBInitialPort", port};
try{
// We need a CORBA object to work
ORB orb = ORB.init(initORB, null);
// we add the service to the service directory
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
NameComponent nc = new NameComponent(serviceName, "");
NameComponent path[]={nc};
// Create the server and associate it with the srvSQL service
SQLServant sqlServer = new SQLServant();
ncRef.rebind(path, SQLServer);
orb.connect(SQLServer);
// monitoring
System.out.println("SQL server ready");
// waiting for client requests
java.lang.Object sync = new java.lang.Object();
synchronized(sync){
sync.wait();
}
} catch (Exception e) {
// An error occurred
System.err.println("Error " + e);
e.printStackTrace(System.err);
}
}// main
}// srvSQL
We compile this new class:
E:\data\java\corba\sql>j:\jdk12\bin\javac serverSQL.java
E:\data\java\corba\sql>dir *.class
SQLSER~1 CLA 2,568 03/19/99 10:19 SQLServant.class
SERVEU~1 CLA 1,800 03/19/99 10:33 serveurSQL.class
10.3.6. Client code
The CORBA server client is called with the following parameters:
machine: machine where the CORBA service directory is located
port: the port on which this directory operates
serviceName: name of the SQL service
driver: the driver that the SQL server must use to manage the desired database
baseUrl: JDBC URL of the database to be managed
id: client ID or null if no ID
password: client password or null if no password
separator: character that the SQL server must use to separate fields in the result rows of a query
Here is an example of possible parameters:
where:
machine: machine on which the CORBA service directory is located
port: the port on which this directory operates
srvSQL: srvSQL, the CORBA name of the SQL server
driver: sun.jdbc.odbc.JdbcOdbcDriver, the standard driver for databases with an ODBC interface
urlBase: jdbc:odbc:articles, to use an articles database declared in the list of public ODBC databases on the Windows machine
id: null, no ID
password: null, no password
separator: , result fields will be separated by a comma
Once launched with the above parameters, the client performs the following steps:
- it connects to the machine machine on port port to request the CORBA service srvSQL
- they request a connection to the articles database
- they ask the user to type an SQL query on the keyboard
- it sends it to the SQL server
- It displays the results returned by the server on the screen
- it prompts the user again to type an SQL query on the keyboard. It will stop when the query is finished.
The Java client code follows. The comments should be sufficient for understanding it. Note that:
- the code is identical to that of the RMI client already studied. It differs in the process of requesting the service from the directory, a process isolated in the getServeurSQL method.
- the getServeurSQL method is identical to the one written for the echo client
We can therefore see that:
- a CORBA client differs from an RMI client only in the way it contacts the server
- this method is identical for all CORBA clients
import srvSQL.*;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import java.io.*;
public class clientSQL {
// class-level global variables
private static String syntax =
"syntax: cltSQL machine port service driver urlBase id password separator";
private static BufferedReader in = null;
private static interSQL sqlServer = null;
public static void main(String arg[]){
// syntax: cltSQL machine port separator driver url id password
// machine port: machine & port of the CORBA service directory to contact
// service: service name
// driver: driver to use for the database to be used
// urlBase: JDBC URL of the database to be used
// id: user ID
// password: the user's password
// separator: string separating fields in query results
// Check the number of arguments
if(arg.length!=8)
error(syntax, 1);
// initialize database connection parameters
String machine = arg[0];
String port = arg[1];
String service = arg[2];
String driver = arg[3];
String baseURL = arg[4];
String id, password, separator;
if(arg[5].equals("null")) id=""; else id=arg[5];
if(arg[6].equals("null")) password=""; else password=arg[6];
if(arg[7].equals("null")) separator=" "; else separator=arg[7];
// CORBA directory service parameters
String[] initORB = {"-ORBInitialHost", arg[0], "-ORBInitialPort", arg[1]};
// CORBA client - request a reference to the SQL server
interSQL SQLServer = getSQLServer(machine, port, service);
// client-server communication
String request = null;
String response = null;
String[] rows = null;
String errorCode = null;
try{
// Open the keyboard input stream
in = new BufferedReader(new InputStreamReader(System.in));
// monitoring
System.out.println("--> Connecting to the database...");
// Initial database connection request
response = SQLServer.connect(driver, databaseURL, id, password);
// follow-up
System.out.println("<-- " + response);
// Analyze response
errorCode = response.substring(0, 3);
if(errorCode.equals("500"))
error("Aborted due to database connection error", 3);
// loop to read requests to send to the SQL server
System.out.print("--> Query: ");
query = in.readLine().toLowerCase().trim();
while(! query.equals("end")){
// Send the query to the server and receive the response
rows = SQLServer.executeSQL(query, separator);
// processing
displayRows(rows);
// next query
System.out.print("--> Query: ");
query = in.readLine().toLowerCase().trim();
}// while
// follow-up
System.out.println("--> Closing the connection to the remote database");
// closing the connection
response = sqlServer.close();
// followed by
System.out.println("<-- " + response);
// end
System.exit(0);
// error handling
} catch (Exception e){
error("Aborting due to error: " + e, 2);
}// try
}// main
// ----------- DisplayLines
private static void displayLines(String[] lines){
for (int i = 0; i < lines.length; i++)
System.out.println("<-- " + lines[i]);
}// displayLines
// ------------ error
private static void error(String msg, int exitCode){
// display error message
System.err.println(msg);
// release resources if necessary
try{
in.close();
SQLServer.close();
} catch (Exception e) {}
// exit
System.exit(exitCode);
}// error
// ---------------------- getSQLServer
private static interSQL getSQLServer(String machine, String port, String service){
// request a reference to the SQL server
// machine: machine from the CORBA service directory
// port: port of the CORBA service directory
// service: name of the CORBA service to request
// follow-up
System.out.println("--> Connecting to the CORBA server...");
// the SQL server reference
interSQL serverSQL = null;
// CORBA directory service parameters
String[] initORB = {"-ORBInitialHost", machine, "-ORBInitialPort", port};
try{
// Request a CORBA object to work with—to do this, we pass the port
// of the CORBA service directory
ORB orb = ORB.init(initORB, null);
// use the directory service to locate the SQL server
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
NamingContext ncRef = NamingContextHelper.narrow(objRef);
// The service we're looking for is called srvSQL—we request it
NameComponent nc = new NameComponent(service, "");
NameComponent path[]={nc};
SQLServer = interSQLHelper.narrow(ncRef.resolve(path));
} catch (Exception e){
System.err.println("Error locating the SQL server ("
+ e + ")");
System.exit(10);
}// try-catch
// return the reference to the
return sqlServer;
}// getSQLServer
}// class
Let's compile the client class:
E:\data\java\corba\sql>j:\jdk12\bin\javac clientSQL.java
E:\data\java\corba\sql>dir *.class
SQLSER~1 CLA 2,568 03/19/99 10:19 SQLServant.class
SERVEU~1 CLA 1,800 03/19/99 10:33 serveurSQL.class
CLIENT~1 CLA 3,774 03/19/99 10:45 clientSQL.class
We are ready for testing.
10.3.7. Tests
10.3.7.1. Prerequisites
We assume that an ACCESS database named Articles is publicly available on the SQL server’s Windows machine:

This database has the following structure:
name | type |
code | 4-character item code |
name | its name (string) |
price | its price (actual) |
current_stock | current stock (integer) |
min_stock | the minimum stock (integer) below which the item must be restocked |
10.3.7.2. Starting the directory service
E:\data\java\corba\sql>start j:\jdk12\bin\tnameserv -ORBInitialPort 1000
The directory service is launched on port 1000. It displays something like the following in a DOS window:
Initial Naming Context:
IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f
6e746578743a312e3000000000010000000000000030000100000000000a69737469612d30303900
052800000018afabcafe000000027693d3fd000000080000000000000000
TransientNameServer: setting port for initial object references to: 1000
10.3.7.3. Starting the SQL server
Starting the SQL server:
It displays the following in a DOS window:
10.3.7.4. Launching a client on the same machine as the server
Here are the results obtained with a client on the same machine as the server:
E:\data\java\corba\sql>j:\jdk12\bin\java clientSQL localhost 1000 srvSQL sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbc:articles null null ,
--> Connecting to CORBA server...
--> Connecting to the database...
<-- 200 Connection successful
--> Query: select name, current_stock, min_stock from items
<-- 101 bike,31,8
<-- 101 bow,9,8
<-- 101 canoe,7,7
<-- 101 rifle,9,8
<-- 101 water skis,13,8
<-- 101 decathlon,3,13,9
<-- 101 sperm whale,6,6
<-- 101 leopard,7,7
<-- 101 panther,7,7
--> Query: delete from articles where stock_mini<7
<-- 100 1
--> Query: select name, current_stock, min_stock from articles
<-- 101 bike,31,8
<-- 101 bow,9,8
<-- 101 canoe,7,7
<-- 101 rifle,9,8
<-- 101 water skis,13,8
<-- 101 decathlon,3,13,9
<-- 101 leopard,7,7
<-- 101 panther,7,7
--> Query: end
--> Closing connection to remote database
<-- 200 Database closed
10.3.7.5. Launching a client on a machine other than the server
Here are the results obtained with a client on a machine other than the server:
E:\data\java\corba\sql>j:\jdk12\bin\java clientSQL tahe.istia.univ-angers.fr 1000 srvSQL sun.jdbc.odbc.JdbcOdbcDriver jdbc:odbc:articles null null ,
--> Connecting to the CORBA server...
--> Connecting to the database
<-- 200 Connection successful
--> Query: select * from articles
<-- 101 a300,v_lo,1202,31,8
<-- 101 d600,bow,5000,9,8
<-- 101 d800,canoe,1502,7,7
<-- 101 x123,rifle,3000,9,8
<-- 101 s345,water skis,1800,13,8
<-- 101 f450,test3,3,13,9
<-- 101 z400,leopard,500000,7,7
<-- 101 g457,panther,800000,7,7
--> Query: end
--> Closing connection to remote database
<-- 200 Database closed
10.4. IDL - JAVA Correspondences
Here we provide the mappings between simple IDL and Java types:
IDL type | Java type |
boolean | boolean |
char | char |
wchar | char |
byte | byte |
string | java.lang.String |
wstring | java.lang.String |
short | short |
unsigned short | short |
long | int |
unsigned long | int |
long long | long |
unsigned long long | long |
float | float |
double | double |
Recall that to define an array of elements of type T in the IDL interface, we use the statement:
and that we then use TypeName to refer to the array type. Thus, in the SQL server interface, we used the declaration:
so that results refers to a String[] array in Java.