Oracle8i CORBA Developer's Guide and Reference Release 3 (8.1.7) Part Number A83722-01 |
|
This section introduces the JServer CORBA application development process. It tells you how to write a simple but useful program that runs on a client system, connects to Oracle using IIOP, and invokes a method on a CORBA server object that is activated and runs inside an Oracle8i Java VM.
As shown in Figure 2-1, a CORBA application requires that you provide the client implementation, the server interface and implementation, and IDL stubs and skeletons. To create this, perform the following steps:
loadjava
tool and specifying the JAR file as its argument. Make sure to include all generated classes, such as stubs and skeletons. Client stubs are required in the server only when the server object acts as a client to another CORBA object.
The sample used in this chapter asks the user for an employee number in the EMP table and returns the employee's last name and current salary. It throws an exception if there is no employee in the database with the given ID number.
When writing a server application, you must create an Interface Definition Language (IDL) file to define the server's interfaces. An interface is a template that defines a CORBA object. As with any object in an object oriented language, it contains methods and data elements that can be read or set. However, the interface is only a definition and so defines what the interface to an object would be if it existed. In your IDL file, each interface describes an object and the operations clients can perform on that object.
This example contains a file, called employee.idl
, that contains only a single server-side method. The getEmployee
method takes an ID number and queries the database for the employee's name and salary.
This interface defines three things:
getEmployee
method that queries the database and returns the information
EmployeeInfo
data structure to hold the returned information
SQLError
exception to be thrown if the employee is not found
The contents of the employee.idl
file should look like:
module employee { struct EmployeeInfo { wstring name; long number; double salary; }; exception SQLError { wstring message; }; interface Employee { EmployeeInfo getEmployee (in long ID) raises (SQLError); }; };
Use the idl2java
compiler to compile the interface description. As shown in Figure 2-2, the compiler generates the interface, implementation template, helper, and holder classes for the three objects in the IDL file, as well as a stub and skeleton class for the Employee
interface. See "Using IDL" for more information about these classes and in the Oracle8i Java Tools Referenece for more information on the idl2java
compiler.
Compile the IDL as follows:
% idl2java -no_tie -no_comments employee.idl
In compiling the employee.idl file, you receive the following files:
The only file that you modify is the _example_Employee.java
file. You should rename the _example_Employee.java
file to a more appropriate name, such as EmployeeImpl.java
. Once renamed, you modify the file to add your server's implementation. The EmployeeImpl.java
file extends the IDL server skeleton, _EmployeeImplBase.java
. Add and implement the getEmployee
method that is defined in the Employee.java
interface definition. In addition, you need to create the client application that invokes these methods appropriately. "Write the Server Object Implementation" demonstrates how to create the server implementation of Employee
in EmployeeImpl.java
.
An implementation is an actual instantiation of an interface. That is, the implementation is code that implements all of the functions and data elements that were defined in the IDL interface. The following shows hot to implement the Employee
interface:
EmployeeImpl.java
file, which used to be the _example_Employee.java
file, to add your server implementation. Notice that the EmployeeImpl
extends the IDL-generated skeleton, _EmployeeImplBase
.
As shown in Figure 2-1, the _EmployeeImplBase
IDL skeleton exists between the ORB and the server application, so that any invocation for the server application is performed through it. The skeleton prepares the parameters, calls the server method, and saves any return values or any out or inout parameters.
getEmployee
method to query the database for the employee and return the appropriate name and salary in EmployeeInfo
.
package employeeServer; import employee.*; import java.sql.*; public classEmployeeImpl
extends_EmployeeImplBase
{ /*constructor*/
public EmployeeImpl() { } /*getEmployee method queries database for employee info*/
public EmployeeInfogetEmployee
(int ID) throws SQLError { try { /*create a JDBC connection*/
Connection conn = new oracle.jdbc.driver.OracleDriver().defaultConnection ();
/*Create a SQL statement for the database query*/
PreparedStatement ps = conn.prepareStatement ("select ename, sal from emp where empno = ?"); /*set the employee identifier and execute query. return the result in an EmployeeInfo structure */ try { ps.setInt (1, ID); ResultSet rset = ps.executeQuery (); if (!rset.next ()) throw new SQLError ("no employee with ID " + ID); return new EmployeeInfo (rset.getString (1), ID, rset.getFloat (2)); } finally { ps.close (); } /*If a problem occurs, throw the SQLError exception*/ } catch (SQLException e) { throw new SQLError (e.getMessage ()); } } }
This code uses the JDBC API to perform the database query. The implementation uses a prepared statement to accommodate the variable in the WHERE clause of the query. See the Oracle8i JDBC Developer's Guide and Reference for more about Oracle8i JDBC. You can use SQLJ, instead of JDBC, if your statement is static.
Most ORB applications must provide a server application that instantiates the server implementation and registers this instance with the CORBA object adapter. However, with Oracle8i, JServer instantiates the implementation and registers the resulting instance on demand for you. Thus, you do not need to provide code that initializes the ORB, instantiates the implementation, and registers the instance. The only server code that you provide is the actual server implementation. This means that your client cannot find an active server implementation instance through the ORB, since it is not instantiated until called. You must publish the implementation object in the CosNaming service. The client retrieves the object from the Name Service through a JNDI lookup
. Once retrieved, the client invokes the activate
method, which initializes an instance of the object. At this point, the client can invoke methods on the object.
After writing the server, the client needs to be created. To access the server object you must be able to refer to it by name. In order for the server object to be accessed by the client, you publish the server object in the Oracle8i database. The client code looks up the published name and activates the server object as a by-product of the look up. You can look up any server object either through JNDI or CosNaming. The JNDI option is shown in the example below. See "JNDI Connection Basics" for more information on JNDI and CosNaming.
When you perform the JNDI lookup, the ORB on the server side is started and the client is authenticated using the environment properties supplied when the initial context object is created. See "IIOP Security".
In order to retrieve the object from the Name Service, you must provide the following:
The object name specifies the complete path name of the published object that you want to look up. For example: /test/myServer
.
See "Retrieving the JNDI InitialContext" for further information about the lookup()
method.
The service name specifies a service that an IIOP presentation manages, and it represents a database instance. The format of the service URL is explained in "Accessing CORBA Objects Without JNDI". Briefly, the service name specifies the following components:
A typical example of a service name is sess_iiop://localhost:2481:ORCL
, where sess_iiop
is the URL prefix for the service, localhost
defaults to the host of the local database, 2481 is the default listener port for IIOP connections, and ORCL
is the SID.
You must authenticate yourself to the database each time you connect. The type of authentication information depends on how you want to authenticate--through a username/password combination or SSL certificates. See "IIOP Security" for more information.
The client invokes the getEmployee
method through the following steps:
InitialContext
object with the required connect properties, including authentication information. See "JNDI Connection Basics".
lookup()
method on the initial context, with a URL as a parameter that specifies the service name and the name of the object to be found. The lookup()
method returns an object reference to the Employee
CORBA server object. See "Using JNDI to Access Bound Objects" for more information.
lookup()
method invokes the getEmployee()
method on the object in the server. This method returns an EmployeeInfo
class, which is derived from the IDL EmployeeInfo
struct. For simplicity, an employee ID number is hard-coded as a parameter of this method invocation.
getEmployee()
in the EmployeeInfo
class.
import employee.*; import oracle.aurora.jndi.sess_iiop.ServiceCtx; import javax.naming.Context; import javax.naming.InitialContext; import java.util.Hashtable; public class Client { public static void main (String[] args) throws Exception { String serviceURL = "sess_iiop://localhost:2481:ORCL"; String objectName = "/test/myEmployee"; // Step 1: Populate the JNDI properties with connect and authentication
// information Hashtable env = new Hashtable (); env.put (Context.URL_PKG_PREFIXES, "oracle.aurora.jndi"); env.put (Context.SECURITY_PRINCIPAL, "SCOTT"); env.put (Context.SECURITY_CREDENTIALS, "TIGER"); env.put (Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN); Context ic = new InitialContext (env); // Step 2: Lookup the object providing the service URL and object name Employee employee = (Employee)ic.lookup (serviceURL + objectName); // Step 3 (using SCOTT's employee ID number): Invoke getEmployee EmployeeInfo info = employee.getEmployee (7788); // Step 4: Print out the returned values. System.out.println (info.name + " " + info.number + " " + info.salary); } }
When the client code is executed, it prints the following on the client console:
SCOTT 7788 3000.0
You run the client-side Java byte code compiler, javac
, to compile all the Java source that you have created. The Java source includes the client and server object implementations, as well as the Java classes generated by the IDL compiler.
For the Employee
example, you compile the following files:
employee/Employee.java
employee/EmployeeHelper.java
employee/EmployeeHolder.java
employee/EmployeeInfo.java
employee/EmployeeInfoHelper.java
employee/EmployeeInfoHolder.java
employee/SQLError.java
employee/SQLErrorHelper.java
employee/SQLErrorHolder.java
employee/_EmployeeImplBase.java
employee/_st_Employee.java
EmployeeImpl.java
Client.java
Other generated Java files are compiled following the dependencies that the Java compiler uses.
Oracle8i JServer supports the Java JDK compiler, releases 1.1.6 or 1.2. Alternatively, you might be able to use other Java compilers, such as a compiler incorporated in an IDE.
CORBA server objects, such as the EmployeeImpl
object created for this example, execute inside the Oracle8i database server. You must load all your classes into the server--through the loadjava
command-line tool--so that they can be activated by the ORB upon demand. You also load all dependent classes, such as IDL-generated Holder and Helper classes, and classes the server object uses, such as the EmployeeInfo
class of this example.
Use the loadjava
tool to load each of the server classes into the Oracle8i database. For the Employee
example, issue the loadjava
command in the following way:
% loadjava -resolve -user scott/tiger employee/Employee.class employee/EmployeeHolder.class employee/EmployeeHelper.class employee/EmployeeInfo.class employee/EmployeeInfoHolder.class employee/EmployeeInfoHelper.class employee/SQLError.class employee/SQLErrorHolder.class employee/SQLErrorHelper.class employee/_st_Employee.class employee/_EmployeeImplBase.class employeeServer/EmployeeImpl.class
It is sometimes more convenient to combine the server classes into a JAR file, and simply use that file as the argument to the loadjava
command. In this example, you could issue the command:
% jar -cf0 myJar.jar employee/Employee.class employee/EmployeeHolder.class \ employee/EmployeeHelper.class employee/EmployeeInfo.class \ employee/EmployeeInfoHolder.class employee/EmployeeInfoHelper.class \ employee/SQLError.class employee/SQLErrorHolder.class \ employee/SQLErrorHelper.class employee/_st_Employee.class \ employee/_EmployeeImplBase.class employeeServer/EmployeeImpl.class
Then, execute the loadjava
command as follows:
% loadjava -resolve -user scott/tiger myJar.jar
The final step in preparing the application is to publish the name of the CORBA server object implementation in the Oracle8i database. See "The Name Space" and the publish
section in the Oracle8i Java Tools Reference for information about publishing objects.
For the example in this section, you can publish the server object using the publish
command as follows:
% publish -republish -user scott -password tiger -schema scott -service sess_iiop://localhost:2481:ORCL /test/myEmployee employeeServer.EmployeeImpl employee.EmployeeHelper
This command specifies the following:
publish
--run the publish command
republish
--overwrite any published object of the same name
user scott
--scott is the username for the schema doing the publishing
-password tiger
--Scott's password
-schema scott
--the name of the schema in which to resolve classes
-service sess_iiop://localhost:2481:ORCL
--establishes the service name (see also "Service Context Class")
/test/myEmployee
--the name for the published object
employeeServer.EmployeeImpl
--the name of the class, loaded in the database, that implements the server object
employee.EmployeeHelper
--the name of the helper class
To run this example, execute the client class using the client-side JVM. For this example, you must set the CLASSPATH for the java
command to include:
classes.zip
)
vbjapp.jar
and vbjorb.jar
mts.jar
and aurora_client.jar
If you are using JDBC, include one of the following JAR files:
If you are using SSL, include one of the following JAR files:
javax-ssl-1_1.jar
and jssl-1_1.jar
for SSL 1.1 support
javax-ssl-1_2.jar
and jssl-1_2.jar
for SSL 1.2 support
You can locate these libraries in the lib
and jlib
directories under the Oracle home location in your installation.
The following invocation of the JDK java
command runs this example.
% java -classpath .:$(ORACLE_HOME)/lib/aurora_client.jar |
:$(ORACLE_HOME/lib/mts.jar |
:$(ORACLE_HOME)/jdbc/lib/classes111.zip: |
$(ORACLE_HOME)/sqlj/lib/translator.zip:$(ORACLE_HOME)/lib/vbjorb.jar: |
$(ORACLE_HOME)/lib/vbjapp.jar:$(JDK_HOME)/lib/classes.zip |
Client |
sess_iiop://localhost:2481:ORCL |
/test/myEmployee |
scott tiger
This example assumes that you invoke the client with the following arguments on the command line:
Note:
From the |
|
![]() Copyright © 1996-2000, Oracle Corporation. All Rights Reserved. |
|