Oracle8i CORBA Developer's Guide and Reference
Release 3 (8.1.7)

Part Number A83722-01

Library

Solution Area

Contents

Index

Go to previous page Go to beginning of chapter Go to next page

A First CORBA Application

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.

Figure 2-1 CORBA Application Components


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:

  1. Design and write the object interfaces in IDL.

  2. Generate stubs, skeletons, and helper and holder support classes.

  3. Write the server object implementations.

  4. Write the client implementation. This code runs outside of the Oracle8i data server on a workstation or PC.

  5. Compile the Java server implementation with the client-side Java compiler. In addition, compile all the Java classes generated by the IDL compiler. Generate a JAR file to contain these classes and any other resource files that are needed.

  6. Compile the client code using the JDK Java compiler.

  7. Load the compiled classes into the Oracle8i database, using the 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.

  8. Publish a name for the objects directly-accessible using the CosNaming service, so that you can access them from the client program.

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.

Writing Interfaces in IDL

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.


Note:

For a full description of IDL, see "The Interface Definition Language (IDL)".  


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:

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);
  };
};

Generate Stubs and Skeletons

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.


Note:

Because there is no use of the Tie mechanism in this example, you can invoke the compiler with the -no_tie option. This means that two fewer classes are generated.  


Figure 2-2 IDL Compilation Generates Support Files


Compile the IDL as follows:

% idl2java -no_tie -no_comments employee.idl


Note:

Because developing a CORBA application includes many compilation, loading, and publishing steps, Oracle recommends that if you are working in a command-line oriented environment, you always use a makefile or a batch file to control the process. Or, you can use IDE products such as Oracle's JDeveloper to control the process.  


In compiling the employee.idl file, you receive the following files:

File name   File type  

_example_Employee.java  

Implementation template for server object  

Employee.java  

Employee interface definition  

EmployeeInfo.java  

EmployeeInfo interface definition  

SQLError.java  

SQLError interface definition  

_st_Employee.java  

IDL client stub  

_EmployeeImplBase.java  

IDL server skeleton  

EmployeeHelper.java  

Helper class for Employee. The most important methods this class provides are the narrow method for typecasting a returned object to be a Employee object and the id method that returns the interface's identifier.  

EmployeeHolder.java  

Holder class for Employee. The Holder class enables a java object to pass values back to clients.  

EmployeeInfoHelper.java  

Helper class for EmployeeInfo.  

EmployeeInfoHolder.java  

Holder class for the EmployeeInfo
structure.  

SQLErrorHelper.java  

Helper class for SQLError.  

SQLErrorHolder.java  

Holder class for the SQLError exception.  

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.

Write the Server Object Implementation

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:

  1. Modify the 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.

  2. Implement the 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 class EmployeeImpl extends _EmployeeImplBase {
    
      /*constructor*/
    public EmployeeImpl() { } /*getEmployee method queries database for employee info*/
    public EmployeeInfo getEmployee (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.

Comparing Oracle8i Server Applications to Other ORB Applications

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.

Write the Client Code

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:

Object name

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.

IIOP Service Name

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.

Client Authentication Information

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.

Client Example

The client invokes the getEmployee method through the following steps:

  1. Instantiates and populates a JNDI InitialContext object with the required connect properties, including authentication information. See "JNDI Connection Basics".

  2. Invokes the 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.

  3. Using the object reference returned by the 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.

  4. Prints the values returned by 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

Compiling the Java Source

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:

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.

Load the Classes into the Database

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


Note:

You do not load any client implementation classes or any other classes not used on the server side.  


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

Publish the Object Name

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:

Run the Example

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:

If you are using JDBC, include one of the following JAR files:

If you are using SSL, include one of the following JAR files:

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.


Note:

The UNIX shell variable $ORACLE_HOME might be represented as %ORACLE_HOME% on Windows NT. The JDK_HOME is the installation location of the Java Development Kit (JDK).  


% 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:



Go to previous page
Go to beginning of chapter
Go to next page
Oracle
Copyright © 1996-2000, Oracle Corporation.

All Rights Reserved.

Library

Solution Area

Contents

Index