|
|
JDBC via CORBAby Marlin W. Pierce <marlinp@xdb.com> Complete source for this example: corbajdbc.tar corbajdbc.zip Some people are trying to get JDBC to go through CORBA and ultimately over IIOP. After harping about how this will inherently be slow, I decided to post instructions on how to this, so people would spend little time discovering how bad it was. However, when I worked on the demonstration, it turned out to be reasonably fast at least for a single user going over IIOP between two NT hosts on an Ethernet LAN. I am willing to admit when I am wrong, but I'm not ready to eat my words yet. Sometimes I notice some lag, and a single user over a fast LAN is no demonstration that this has an acceptable performance. However, my reasons for posting this now include showing people how to do this, as well as helping people come to a quicker conclusion on when it won't be acceptable. My only fear is that this demo will mislead people into thinking it is acceptable, when it is really slow out in the field. Nonetheless, I am publishing the instructions to help others do what they are trying to do. The ArchitectureWe are going to write a JDBC Driver, which resolves all of its calls by going through CORBA to CORBA services which call some other JDBC Driver. For simplicity, I will only work with enough of the Connection, Statement, and ResultSet interfaces to return the results from a query. Completing the rest of JDBC is an exercise left to the reader. We will also add a sayhello() method, to test the creation of each object as we go. On both the Server and Client side, we will delegate the calls for our server side Services and client side JDBC Driver to another related object. The Services will delegate the calls to a JDBC object. The Client JDBC Driver will delegate the calls to the CORBA references. The reasons I used delegation are:
The IDLFirst of all, we will need the IDL for the services we will be implementing.
If we are careful, the client stubs generated will One thing we notice is that CORBA does not have constructors. Furthermore, JDBC deals with a DriverManager. Creating the original Connection object will take a little thought. The ResultSet object is created from the Statement object with the Statement.executeQuery(String) method. Likewise, the Statement object is created from the Connection object from the Connection.createStatement() method. What we will do via CORBA is create another "factory" object, ConnectionFactory, which will have a method which creates Connection objects. This will solve the bootstrapping problem for the IDL. (The DriverManager solution will be discussed later.) For our stripped-down demo, the IDL will be the following: module corbajdbc interface CorbaStatement interface CorbaConnection interface CorbaConnectionFactory
Here we see that the ConnectionFactory has a method, connect(), which
takes all the information which will be needed to call the An Example JDBC DriverBefore going into the CORBA implementation, I will introduce an example JDBC Driver. This Driver has primitive methods to implement the JDBC interfaces, however, it does not return meaningful data. Since it returns a string for the getString() method, we can use it for our CORBA implementation. One purpose of this driver is testing the performance issues of CORBA alone. Since getString() returns a String immediately, all the time in returning the results on the client are due to going through CORBA. The time it takes for an actual database to generate the results of a query is eliminated. The other purposes for this example JDBC Driver, is that it will be helpful
in implementing the Services, since the method calls are For our purposes, we will implement the Connection, Statement, and ResultSet interfaces. We will also need a implementation of the Driver interface to create the Connection object in a JDBC way. Simple implementations of these, which are enough to satisfy the implements requirement are the following: Source code for the dummy driver: DummyDriver, DummyResultSet, DummyStatement, DummyConnection Implementing the ServicesNext, we will implement the CORBA Services. First we need to compile the IDL into the server side code. From the command line, we will run idltojava as follows, assuming we created a file named jdbc.idl from the IDL above: idltojava -fserver jdbc.idl This will create a corbajdbc subdirectory with a number of Server side Java files. Implementing the ResultSet ServicesNext, to implement the ResultSet services, we will create a ResultSetServant
Java file. Our ResultSetServant will take a JDBC Source code for ResultSetServant.java I didn't deal with sending the SQLExceptions across to the Client. That is left as an exercise for the reader. I did, however, leave the import statements for the packages which would be necessary to finish this class for the full ResultSet API. Implementing the Statement and Connection InterfacesNext, the Statement and Connection interfaces are handled the same way. However, when they return a ResultSet and a Statement respectively, they will actually return a ResultSetServant and a StatementServant. Notice that these classes cannot implement the JDBC Statement and Connection interfaces because they return different object types for executeQuery() and createStatement(). Thus these servants cannot also be a JDBC Driver. Source code for StatementServant and ConnnectionServant Implementing ConnectionFactoryServantNext, we have the ConnectionFactory to implement. Unlike the previous servants, the ConnectionFactory does not look like a JDBC class. The critial method in this Factory object is the connect method which returns a ConnectionServant. First, all the Drivers which are supported by this service are registered, once, when this class is referenced and loaded, from the static code block. Then, when the connect() method is called, the ConnectionFactory calls the DriverManager.getConnection() method. The connection returned from this call is used for the constructor to the ConnectionServant. Source code for ConnectionFactoryServant The JDBCServerFinally, we need a server to start the ORB, and bind the ConnectionFactory service in the nameserver. This code looks like the following: Source code for JDBCServer Implementing the Client JDBC DriverFor the Client side, first we must generate the Client stubs. From the command line, we will run idltojava as follows, assuming we created a file named jdbc.idl from the IDL above: idltojava -fclient jdbc.idl This will create a corbajdbc subdirectory with a number of Client side Java files. Next, to implement the ResultSet services, we will create a C_ResultSet Java file. Our C_ResultSet will take a Corba stub CorbaResultSet object, and delegate the calls to it. Likewise, we will do the same for Statement and Connection. Thus the files will look like the following: Source code for C_ResultSet, C_Connection and C_Statement Implementing C_DriverNow, we need a JDBC Driver class. A JDBC Driver class is supposed to (1) have a constructor with no arguments, and (2) register itself whenever the class is simply referenced. To meet this goal simply, I hard coded the address of the ORB. Thus, this driver can create multiple Connections, but all Connections go to the same ORB to find the JDBC Services. We could have passed the address of the ORB through the Properties object. However, you want to avoid creating an ORB reference for every Connection. Remember, if there are multiple Connections, many will probably go to the same ORB. This Driver also takes JDBC URLs starting with jdbc:corba:. Then
it passes the rest of the URL with the jdbc: prefix to the Source code for C_Driver Building the ProgramsIncluded in the corbajdbc.tar file is a buildcorbajdbc script. This is a Bourne shell script which has been run on Solaris 2.5.1 with the Java IDL 1.1 FCS for Solaris and JDK 1.1.4. It assumes that both the JDK and Java IDL have been set up to be on the PATH, and that CLASSPATH contains at least ".". The buildcorbajdbc script also assumes that it is being run from the directory into which corbajdbc.tar was unpacked. Those of you on Microsoft OSes are on your own at this point. Before building the programs, you will have to alter the host name in C_Driver.java to match the name of the machine on which you intend to run the servers. Running the Test ProgramThe test program looks like any JDBC program. The only thing is that since our Dummy driver always returns true for the ResultSet.next() call, we were careful to only fetch twenty records. Source code for test program TestCorbaJDBC After we compile all the Java files, we need to start the nameserver. Go to the bin directory where you installed the JavaIDL and run the following command: nameserv -ORBInitialPort 1080 Next, start the corbajdbc services. Go to the server and run the following command: java corbajdbc.JDBCServer -ORBInitialPort 1080 Finally go to the client and run the following command: java TestCorbaJDBC For the convenience of Solaris users, a runcorbajdbc script is included in the corbajdbc.tar file. |