Oracle8i Enterprise JavaBeans and CORBA Developer's Guide
Release 8.1.5

A64683-01

Library

Product

Contents

Index

Prev  Chap Top Next

A First EJB Application

This section demonstrates a complete example application, including:

This example has a single EJB, which queries an Oracle8i database to get name and salary information about an employee. The example is exactly the same in functionality as the first CORBA example presented in Chapter 3, "Developing CORBA Applications".

In this example, the client code is an application running on a client system. To see how to do an applet example, see the EJBClubMed example under the basic EJB examples that are shipped with this product.

The Interfaces

The first task of the bean provider is to design and code the home and remote interfaces. The home interface specifies how the server will create the bean, using the EJBCreate() method of the bean implementation. This example creates a stateful session bean that takes no parameters, because there is no initial state for the bean.

(How is it known that the bean is stateful? While this is a design property of the bean, the statefulness of the bean is declared in the deployment descriptor. See "Deployment Steps" for more information.)

The remote interface specifies the methods of the bean. In this example, there is a single method, getEmployee(), that takes an int as its single parameter, and that returns an EmpRecord class.

Home Interface

As required by the EJB specification, you must declare that any home interface create() method throws the javax.ejb.CreateException and java.rmi.RemoteException exceptions. When you try to deploy the bean, the deployejb verifier will exit with an error if this is not the case.

package employee;

import javax.ejb.EJBObject;
import java.rmi.RemoteException;

public interface EmployeeHome extends EJBHome {
  public Employee create()
       throws CreateException, RemoteException;
}

Remote Interface

The remote interface declares that the bean can throw a RemoteException (required by the specification), and a java.sql.SQLException, which is particular to this bean. Note that exceptions, such as SQLException, that are thrown to the bean by JDBC or other methods that it calls are propagated back to client, if the remote interface declares that the bean throws them.

Here is the code for the remote interface for this example EJB:

package employee;

import employee.EmpRecord;
import javax.ejb.EJBObject;
import java.rmi.RemoteException;

public interface Employee extends EJBObject  {
  public EmpRecord getEmployee (int empNumber)
       throws java.sql.SQLException, RemoteException;
}

The Bean Implementation

The bean implementation simply fills in the Java code, including appropriate JDBC methods, to perform the work of the getEmployee() method. Note that the JDBC code opens a default connection, which is the standard way that JDBC code that runs on the Oracle8i server opens a server-side connection. (It is in fact the only way that a JDBC connection can be opened in server-side JDBC code.)

A JDBC prepared statement is used to prepare the query, which has a WHERE clause. Then the setInt() method is used to associate the empNumber input parameter for the getEmployee() method with the '?' placeholder in the prepared statement query. This is no different from the JDBC code that you would write in a client application.

package employeeServer;

import java.sql.*;
import java.rmi.RemoteException;
import javax.ejb.*;

public class EmployeeBean implements SessionBean {
  SessionContext ctx;
  public EmpRecord getEmployee (int empNumber)
       throws SQLException, RemoteException {

    EmpRecord empRec = new EmpRecord(); 

    Connection conn =
      new oracle.jdbc.driver.OracleDriver().defaultConnection();
    PreparedStatement ps =
      conn.prepareStatement("select ename, sal from emp where empno = ?");
    ps.setInt(1, empNumber);
    ResultSet rset = ps.executeQuery();
    if (!rset.next())
        throw new RemoteException("no employee with ID " + empNumber);
    empRec.ename = rset.getString(1);
    empRec.sal = rset.getFloat(2);
    empRec.empno = empNumber;
    ps.close();
    return empRec;
  }

  public void ejbCreate() throws CreateException, RemoteException {
  }
  public void ejbActivate() {
  }
  public void ejbPassivate() {
  }
  public void ejbRemove() {
  }
  public void setSessionContext(SessionContext ctx) {
    this.ctx = ctx;
  }
}

This remote interface implementation shows the minimum methods required for an EJB implementation. At a minimum, an EJB must implement the following methods, as specified in the javax.ejb.SessionBean interface:

ejbActivate()  

Implement this as a null method, as it is never called in this release of the EJB server.  

ejbPassivate()  

Implement this as a null method, as it is never called in this release of the server.  

ejbRemove()  

A container invokes this method before it ends the life of the session object. This method to perform any required clean-up, for example closing external resources such as file handles.  

setSessionContext(SessionContext ctx)  

Set the associated session context. The container calls this method after the bean creation. The enterprise bean can store the reference to the context object in an instance variable, for use in transaction management. Beans that manage their own transactions can use the session context to get the transaction context.  

A Parameter Object

The EmployeeBean getEmployee() method returns an EmpRecord object, so this object must be defined somewhere in the application. In this example, an EmpRecord class is included in the same package as the EJB implementation.

The class is declared as public, and must implement the java.io.Serializable interface, so that it can be passed back to the client by value, as a serialized remote object. The declaration is as follows:

package employee;

public class EmpRecord implements java.io.Serializable {
  public String ename;
  public int empno;
  public double sal;
}

Note: the java.io.Serializable interface specifies no methods, it just indicates that the class is serializable. So there is no need to implement extra methods in the EmpRecord class.

The Deployment Descriptor

The most convenient way to implement the deployment descriptor for a bean is to write a descriptor file in text form. The EJB deployment tool can read the text form descriptor, parse it, signal parse errors, and then verify that the descriptor itself, and the interface and bean implementation declarations meet the standard. For example, bean implementations and interface specifications must be declared as throwing certain specified exceptions. If they do not, the deployment tool (see deployejb) lists the error(s) and exits.

The text form deployment descriptor is usually stored in a file with a .ejb extension, though this naming convention is not required. In the EJB examples that are shipped with this product, the deployment descriptors are in the base directory of the example, along with the client application implementations and the Makefile and Windows NT batch files.

Here is the deployment descriptor for this example. For a complete description of the deployment descriptor attributes, see "The Deployment Descriptor".

SessionBean employeeServer.EmployeeBean {
  BeanHomeName = "test/employeeJDBCBean";
  RemoteInterfaceClassName = employee.Employee;
  HomeInterfaceClassName = employee.EmployeeHome;

  AllowedIdentities = {SCOTT};
  StateManagementType = STATEFUL_SESSION;
  RunAsMode = CLIENT_IDENTITY;
  TransactionAttribute = TX_REQUIRED;
}

The Client Code

This section shows the client code that can be used to send messages to the example bean described above, and get and print results from it. This client code demonstrates how a client:

Locating Remote Objects

The first step with any remote object implementation, whether it's pure RMI, or EJBs, or CORBA, is to find out how to locate a remote object. To get a remote object reference you have to know:

With EJBs, the initial object name is the name of an EJB home interface, and you locate it using the Java Naming and Directory Interface (JNDI). The EJB specification requires that EJB implementations expose a JNDI interface as the means of locating a remote bean.

About JNDI

JNDI is an interface to a naming and directory service. For example, JNDI can be used as an interface to a file system, that you can use to look up directories and the files that they contain. Or, JNDI can be used as an interface to a naming or directory service, for example a directory protocol such as LDAP.

This section presents a short description of JNDI. The EJB specification requires that JNDI be used to provide the interface for locating remote objects by name.

This section of the manual describes only those parts of JNDI that you need to know to write EJB applications for Oracle8i. To obtain the complete JNDI API (and SPI) specifications, see the URLs in "For More Information".

JNDI is supplied by Sun in the packages in javax.naming, so you must import these packages in your client code:

import javax.naming.*;

For the Oracle8i EJB server, JNDI serves as an interface (SPI driver) to the OMG CosNaming service. But you do not have to know all about CosNaming, or even all about JNDI, to write and deploy EJBs for the Oracle8i server. In fact, to start off all you really need to know is how to use the JNDI methods that are used to get access to permanently-stored home interface objects, and how to set up the environment for the JNDI Context object.

The remainder of this JNDI section describes the data structures and methods of the javax.naming package that you will need to access EJB objects.

Getting the Initial Context

The very first JNDI call to code is the one that gets a Context object. The first Context object that you get is bound to the root naming context of the Oracle8i publishing context. EJB home interfaces are published in the database, arranged in a file system-like hierarchy. See "publish" for more details about publishing EJB home interfaces, and about the Oracle8i published object directory structure.

You get the root naming context by creating a new JNDI InitialContext, as follows:

Context initialContext = new InitialContext(environment);

The environment parameter is a Java hashtable. There are six properties that you can set in the hashtable, that are passed to the javax.naming.Context. The properties are shown in Table 2-1.

Table 2-1 Context Properties

Property 

Purpose 

javax.naming.Context.
URL_PKG_PREFIXES
 

The environment property that specifies the list of package prefixes to use when loading in URL context factories. You must use the value "oracle.aurora.jndi" for this property.  

javax.naming.Context.
SECURITY_AUTHENTICATION
 

The type of security for the database connection. The three possible values are:
oracle.aurora.sess_iiop.ServiceCtx.
NON_SSL_LOGIN
oracle.aurora.sess_iiop.ServiceCtx.
SSL__CREDENTIAL
oracle.aurora.sess_iiop.ServiceCtx.
SSL_LOGIN
 

javax.naming.Context.
SECURITY__PRINCIPAL
 

The Oracle8i username, for example "SCOTT".  

javax.naming.Context.
SECURITY_CREDENTIALS
 

The password for username, for example "TIGER".  

oracle.aurora.sess_iiop.
ServiceCtx.SECURITY_ROLE
 

An optional property that establishes a database role for the connection. For example, use the string "SYSDBA" to connect with the SYSDBA role.  

oracle.aurora.sess_iiop.
ServiceCtx.SSL_VERSION
 

The client-side SSL version number.  

See Chapter 4, "Connections and Security", for more information about JNDI and connecting to an Oracle8i instance.

Getting the Home Interface Object

Once you have the "initial references" context, you can invoke its methods to get a reference to an EJB home interface. To do this, you must know the published full pathname of the object, the host system where the object is located, the IIOP port for the listener on that system, and the database system identifier (SID). When you get this information, for example from the EJB deployer, you construct a URL using the following syntax:

<service_name>://<hostname>:<iiop_listener_port>:<SID>/<published_obj_name>

For example, to get a reference to the home interface for a bean that has been published as /test/myEmployee, on the system whose TCP/IP hostname is myHost, the listener IIOP port is 2481, and the system identifier (SID) is ORCL, you construct the URL as follows:

sess_iiop://myHost:2481:ORCL/test/myEmployee

The listener port for IIOP requests is configured in the listener.ora file. The default for Oracle8i is 2481. See the Net8 Administrator's Guide for more information about IIOP configuration information. See also Chapter 4, "Connections and Security" for more information about IIOP connections.

You get the home interface using the lookup() method on the initial context, passing the URL as the parameter. For example, if the home interface published name is /test/myEmployee, you would code:

...
String ejbURL = "sess_iiop://localhost:2481:ORCL/test/myEmployee";
Hashtable env = new Hashtable();
env.put(javax.naming.Context.URL_PKG_PREFIXES, "oracle.aurora.jndi");
// Tell sess_iiop who the user is
env.put(Context.SECURITY_PRINCIPAL, "SCOTT");
// Tell sess_iiop what the password is
env.put(Context.SECURITY_CREDENTIALS, "TIGER");
// Tell sess_iiop to use non-SSL login authentication
env.put(Context.SECURITY_AUTHENTICATION, ServiceCtx.NON_SSL_LOGIN);
// Lookup the URL
EmployeeHome home = null;
Context ic = new InitialContext(env);
home = (EmployeeHome) ic.lookup(ejbURL);
...

Invoking EJB Methods

Once you have the home interface for the bean, you can invoke one of the bean's create() methods to instantiate a bean. For example:

Employee testBean = home.create();

Then you can invoke the EJB's methods in the normal way:

int empNumber = 7499;
EmpRecord empRec = testBean.getEmployee(empNumber);


Here is the complete code for the client application:

import employee.Employee;
import employee.EmployeeHome;
import employee.EmpRecord;

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";
    int empNumber = 7499;   // ALLEN
    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);

    EmployeeHome home = 
      (EmployeeHome) ic.lookup(serviceURL + objectName);  // lookup the bean
    Employee testBean = home.create();   // create a bean instance
    EmpRecord empRec = new EmpRecord();  // create a slot for the incoming data
    empRec = testBean.getEmployee(empNumber); // get the data and print it
    System.out.println("Employee name is " + empRec.ename);
    System.out.println("Employee sal is  " + empRec.sal);
  }
}



Prev

Top

Next
Oracle
Copyright © 1999 Oracle Corporation.

All Rights Reserved.

Library

Product

Contents

Index