Oracle8i CORBA Developer's Guide and Reference Release 3 (8.1.7) Part Number A83722-01 |
Library | Service | Contents | Index

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

- a `getEmployee` method that queries the database and returns the information

- an `EmployeeInfo` data structure to hold the returned information

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

### 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

- IIOP Service Name

- Client Authentication Information

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

- URL prefix for the service

- the name of the host that manages the service presentation

- the port number of the listener for the target database instance on that host

- the system identifier (SID) for the database instance on the host

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:

- `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.

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

- `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

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

- the standard Java library archive (`classes.zip`)

- any class files the client ORB uses, such as those in VisiBroker for Java `vbjapp.jar` and `vbjorb.jar`

- the Oracle8i-supplied JAR files: `mts.jar` and `aurora_client.jar`

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

- `classes111.zip` for JDBC 1.1 support

- `classes12.zip` for JDBC 1.2 support

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.

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:

- CLASSPATH libraries

- client object

- service name

- name of the published object to activate

- username

- password

  Note: From the `java` command you can see why it is almost always better to use a makefile or a batch file to build CORBA applications.

| Copyright © 1996-2000, Oracle Corporation. All Rights Reserved. |
Library | Service | Contents | Index