Oracle8i Enterprise JavaBeans and CORBA Developer's Guide
Release 2 (8.1.6)

A81356-01

Library

Product

Contents

Index

Prev Next

2
Enterprise JavaBeans

This chapter describes the development and deployment of Enterprise JavaBeans in the Oracle8i server environment. Although it is not a complete tutorial on EJB and the EJB architecture, this chapter supplies you with enough information to start developing EJB applications.

This chapter covers the following topics:

Defining Enterprise JavaBeans

Enterprise JavaBeans is an architecture for transactional, component-based distributed computing. The specification for EJBs lays out not just the format of a bean itself, but also a set of services that must be provided by the container in which the bean runs. This makes EJBs a powerful development methodology for distributed application development. Neither the bean developer nor the client application programmer needs to be concerned with service details such as transaction support, security, remote object access, and many other complicated and error-prone issues. The EJB server and container furnishes these features for you.

EJB architecture makes server-side development much easier for the Java application programmer. Because the implementation details are hidden from the developer, and because services such as transaction support and security are provided in an easy-to-use manner, you can develop EJBs relatively quickly. Furthermore, EJBs offer portability. A bean developed on one EJB server should run on other EJB servers that meet the EJB specification. Portability has not been tested yet for most servers, but it is a bright promise for the future.

EJB Development Roles

The EJB specification describes enterprise bean development in five roles:

The roles of the EJB server and EJB container developers are not clearly distinguished. There is, for example, no standardized API between the container and the server. For this reason, the same vendor is likely to perform initial implementations for EJB servers and containers. This is the case for Oracle8i.

EJBs as Distributed Components

Although the EJB specification is based on concepts developed for the Remote Method Invocation interface (RMI), EJB server vendors are not required to use the RMI transport. Oracle8i uses the Internet Inter-ORB Protocol (IIOP). Using IIOP means that a server can support EJBs whose methods can be invoked by other IIOP clients.

Enterprise beans can also call out to CORBA objects. See Figure 2-2.

Enterprise JavaBeans As Components

An EJB is a software component that runs in a server. This runtime environment is one factor that distinguishes an enterprise bean from a JavaBean. The JavaBean usually runs on a client system, such as a network computer, a PC, or a workstation, and it typically performs presentation tasks, such as implementing GUI widgets.

Types of EJBs

There are two types of EJBs: session beans and entity beans. An easy way to think of the difference is that a session bean implements one or more business tasks, while an entity bean implements a business entity. A session bean might contain methods that query and update data in a relational table; an entity bean represents business data directly. For example, an entity bean can represent a row in a relational table.

Session beans are often used to implement services. For example, an application developer might implement one or several session beans that retrieve and update inventory data in a database. You can use session beans to replace stored procedures in the database server, thereby achieving the scalability inherent in the Oracle8i Java server.

Persistence

Session beans are not inherently persistent. Be careful about this word. Persistence can refer either to a characteristic of the bean--entity beans are persistent, session beans are not inherently persistent--or it can refer to data that a bean might save, so that the data can be retrieved in a future instantiation. Persistent data is saved in the database.

Therefore, a session bean saves its state in an Oracle8i database, if required, but it does not directly represent business data. Entity beans persist the business data either automatically (in a container-managed entity bean) or by way of methods that use JDBC or SQLJ and are coded into the bean (bean-managed).

Implementing the synchronization interface can make data storage and retrieval automatic for session beans. See "Using Session Synchronization".

EJB Support in Oracle8i

The version 1.0 of the EJB specification requires that the EJB server support session beans. Entity bean support is optional. In the current release, the Oracle8i EJB server does not support entity beans. Entity beans will be supported in a future release.

Session Beans

Created by a client, a session bean is usually specific to that client. In Oracle8i more than one client can share a session bean.

Session beans are transient in that they do not survive a server crash or a network failure. When a session bean is re-instantiated, state of previous instances is not automatically restored.

Stateful Session Beans

A stateful session bean maintains its state between method calls. For example, a single instance of a session bean might open a JDBC database connection and use the connection to retrieve some initial data from the database. For example, a shopping-cart application bean could load a customer profile from the database as soon as it's activated, then that profile would be available for any method in the bean to use.

A typical stateful session EJB is a relatively coarse-grained object. A single bean almost always contains more than one method, and the methods provide a unified, logical service. For example, the session EJB that implements the server side of a shopping cart on-line application would have methods to return a list of objects that are available for purchase, put items in the customer's cart, place an order, change a customer's profile, and so on.

The state that a session bean maintains is called the "conversational state" of the bean, as the bean is maintaining a connection with a single client, similar to a telephone conversation.

Keep in mind that the state of a bean is still transient data, with respect to the bean itself. If the connection from the client to the bean is broken, the state can be lost. This depends on whether the client is unable to reconnect before timeout.

Stateless Session Beans

In most EJB implementations, a stateless session bean is used for short transactions with a client. In these implementations, the major difference between stateful and stateless session beans is that a stateless bean can change identity between method calls; a stateful bean maintains identity. If the client calls Method A in a stateless bean, then calls Method B in the same stateless bean class, the second method might be called on a separate instance of the bean.

In the Oracle8i implementation, stateless and stateful beans are identical. The inherent multi-threaded nature of the Oracle8i MTS data server makes stateful session beans functionally identical to stateless beans. There is no difference between the two for Oracle8i.

For example, a typical use of stateless session beans is a server maintaining a pool of beans ready to serve clients that are performing short OLTP-like transactions. But this is not required in the Oracle8i architecture for performance. Stateful beans can serve just as well in this situation.

Implementing an EJB

There are four major components that you must create to develop a complete EJB:

The home interface is an interface to an object that the container itself implements: the home object. The home interface has create() methods that specify how a bean is created. The home interface, with the home object, actually serves as a factory object for EJBs.

The remote interface specifies the methods that you implement in the bean. These methods perform the business logic of the bean. The bean must also implement additional service methods that the EJB container calls at various times in the life cycle of a bean. See Basic Concepts for more information about these service methods.

The client application itself does not access the bean directly. Rather, the container generates a server-side object known as the EJBObject that serves as a server-side proxy for the bean. The EJBObject receives the messages from the client, and thus the container can interpose its own processing before the messages are sent to the bean implementation.

Why is this level of indirection necessary? Remember that the container provides services transparently for the bean. For example, if you deploy the bean with a transaction attribute that declares that the bean must run in its own transaction context, then the container can start up the transaction before the message is passed to the bean and can do a commit or rollback, as required, before return messages or data is sent back to the client.

Figure 2-1 illustrates the interaction among these components.

Figure 2-1 Basic EJB Component Relationships


The bean implementation contains the Java code that implements the remote interface and the required container methods.

The deployment descriptor is an object that specifies attributes of the bean. For example, the deployment descriptor declares the transactional properties of the bean. At deployment time, the EJB deployer, together with the application developer, can decide whether the container should manage transaction support or have the client do it.

The EJB Architecture

EJBs are based conceptually on the Java Remote Method Invocation (RMI) model. For example, remote object access and parameter passing for EJBs follow the RMI specification.

The EJB specification does not prescribe that the transport mechanism has to be pure RMI. The Oracle8i EJB server uses RMI over IIOP for its transport protocol--a practice that is becoming common among server vendors.

Figure 2-2 shows the basic EJB architecture.

Figure 2-2 EJB Architecture


Basic Concepts

Before going into details about implementing EJBs, some basic concepts must be clarified. First of all, recall that a bean runs in a container. The container, which is part of the EJB server, provides a number of services to the bean. These include transaction services, synchronization services, and security.

To provide these services, the bean container must be able to intercept calls to bean methods. For example, a client application calls a bean method that has a transaction attribute that requires the bean to create a new transaction context. The bean container must be able to interpose code to start a new transaction before the method call, and to commit the transaction, if possible, when the method completes, and before any values are returned to the client.

For this reason and others, a client application does not call the remote bean methods directly. Instead, the client invokes the bean method through a two-step process, mediated by the ORB and by the container.

First, the client actually calls a local proxy stub for the remote method. The stub marshalls any parameter data, and then calls a remote skeleton on the server. The skeleton unmarshalls the data, and upcalls to the bean container. This step is required because of the remote nature of the call. Note that this step is completely transparent both to the client application developer as well as to the bean developer. It is a detail that you do not need to know about to write your application code, either on the client or the server. Nevertheless, it is useful to know what is going on, especially when it comes to understanding what happens during bean deployment.

In the second step, the bean container gets the skeleton upcall, then interposes whatever services are required by the context. These can include:

The container then delegates the method call to the bean. The bean method executes. When it returns, the thread of control returns to the bean container, which interposes whatever services are required by the context. For example, if the method is running in a transaction context, the bean container performs a commit operation, if possible, depending on the transaction attributes in the bean descriptor.

Then the bean container calls the skeleton, which marshalls return data and returns it to the client stub.

These steps are completely invisible to client-side and server-side application developers. One of the major advantages of the EJB development model is that it hides the complexity of transaction and identity management from developers.

The Home Interface

When a client needs to create a bean instance, it does so through the home interface, which specifies one or more create() methods. A create() method can take parameters passed in from the client when the bean is created.

For each create method in the home interface, there must be a corresponding ejbCreate() method specified in the remote interface, with the same signature. The only difference is that create() is specified to return the bean type; ejbCreate() is a void method. When a client invokes create() on the home interface, the container interposes whatever services are necessary at that point and then calls the corresponding ejbCreate() method in the bean itself.

The deployejb tool publishes a reference to the home object in the database. See "deployejb". This is the object that the client looks up to create instances of the bean.

The Remote Interface

The bean developer writes a remote interface for each EJB in the application, which specifies the business methods that the bean contains. Each method in the bean that the client accesses must be specified in the remote interface. Private methods in the bean are not specified in the remote interface.

The signature for each method in the remote interface must match the signature in the bean implementation.

PL/SQL developers will recognize that the remote interface is similar to a package specification, and the remote interface implementation resembles the package body. However, the remote interface does not declare public variables, but declares only the methods that are implemented by the bean.

The remote interface must be public, and it must subclass javax.ejb.EJBObject. For example, you could write a remote interface for an employeeManagement bean as follows:

public interface employeeManagement extends javax.ejb.EJBObject {
    
  public void hire(int empNumber, String startDate, double salary)
        throws java.rmi.RemoteException;
  public double getCommission(int empNumber) throws java.rmi.RemoteException;
  // empRecord is a class that is defined separately as part of the bean
  public empRecord getEmpInfo(int empNumber) throws java.rmi.RemoteException;
  ...
}

All methods in the remote interface are declared as throwing RemoteException. This is the usual mechanism for notifying the client of runtime errors in the bean. However, the bean container can throw other exceptions, such as SQLException. Any exception can be thrown to the client, as long as it is serializable.

Runtime exceptions are transferred back to the client as a remote runtime exception, which contains the stack trace of the remote exception.

Accessing the Bean Methods

Invoking a bean's methods is a two-step process.

  1. Look up the bean home interface, which is published in the Oracle8i database as part of the bean deployment process. Use the Java Naming and Directory Interface (JNDI) to look up the home interface.

  2. Create instances of the bean in the server through the home interface. For those who know CORBA, the bean home interface is acting similar to a CORBA factory object, able to produce new CORBA objects on demand.

Once you have the home interface and then the bean reference returned by the home interface create() method, you call the bean methods using the normal Java syntax: bean.method().

These steps are completely illustrated by example in "A First EJB Application".

As a quick first example, suppose that myBeanHome is a reference that you have obtained to the home interface of a bean called myBean. myBean must have at least one create() method that lets you instantiate the bean. You create a new instance of the bean on the remote server by coding:

myBean home = 
  (myBean) initialContext.lookup(URL);  // get the home interface using JNDI
myBean tester = home.create();          // create a new bean of type myBean

and then call myBean's methods using the usual syntax

tester.method1(p1, p2);

Parameter Passing

When you implement an EJB or write the client code that calls EJB methods, you have to be aware of the parameter-passing conventions used with EJBs.

A parameter that you pass to a bean method, or a return value from a bean method, can be any Java type that is serializable. Java primitive types (int, double) are serializable. Any non-remote object that implements the java.io.Serializable interface can also be passed.

A non-remote object passed as a parameter to a bean or returned from a bean is passed by copy, not by reference. So, for example, if you call a bean method as follows:

public class theNumber {
  int x;
}
...
bean.method1(theNumber);

then method1() in the bean gets a copy of theNumber. If the bean changes the value of theNumber object on the server, this change is not reflected back to the client, because of the pass-by-copy semantics.

If the non-remote object is complex, for example a class containing several fields, only the non-static and non-transient fields are copied.

When passing a remote object as a parameter, the stub for the remote object is passed. A remote object passed as a parameter must extend remote interfaces.

The next section demonstrates parameter passing to a bean and remote objects as return values.

A First EJB Application

This section demonstrates a complete example of an 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 identical in functionality to 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. For 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? Although 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, a single method, getEmployee(), takes an int as its single parameter, thereby returning 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. 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.EJBHome;
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 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 identical to 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 illustrates 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, because it is never called in this release of the EJB server.  

ejbPassivate()  

Implement this as a null method, because 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 performs 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 interfaces.

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. Therefore, 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 errors 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 "Deploying an EJB".

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 you can use 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 must 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 serve as an interface to a file system that you can use to look up directories and the files 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 briefly describes JNDI. The EJB specification requires the use of JNDI 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".

Sun Microsystems supplies JNDI in the javax.naming package, so you must import these classes 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. To start, all you must know is how to use the JNDI methods used to access 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

You use JNDI to retrieve a Context object. The first Context object that you receive is bound to the root naming context of the Oracle8i publishing context. EJB home interfaces are published in the database, and are arranged in a manner similar to a file system 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. Table 2-1 contains the six properties that you can set in the hashtable that are passed to the javax.naming.Context.

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 the 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 obtain this information--for example, from the EJB deployer--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, 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's 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);
  }
}

Deploying an EJB

The EJB deployment process consists of the following steps:

Write the Deployment Descriptor

The enterprise bean deployer supplies a deployment descriptor for each EJB in the application.

There is a text form of the descriptor, which is described in this section. You can also use the Oracle8i JServer ejbdescriptor command-line tool to convert a text form of the deployment descriptor to the serialized class, or to convert back from the serialized object to a text file. The ejbdescriptor is documented in "ejbdescriptor".


Note:

You can only use 7-bit ASCII characters in the deployment descriptor. Do not use ISO Latin-1 or other non-ASCII characters.  


Text Format

The text form of the session bean descriptor follows the conventions of Java code-- the descriptor has the syntax of a Java class. The text format always begins with a SessionBean keyword, which is followed by the fully-qualified class name of the bean. The body of the declaration contains a list of descriptor attributes and their values. For example:

SessionBean ejb.test.server.ExampleBeanImpl
{
    <attribute>=<value>
    ...
}

In this example, ejb.test.server is the name of the package that contains the implementation of the bean class ExampleBean.


Note:

Bean deployment will change significantly for the next release of the EJB specification. The preliminary version of that specification calls for the bean deployment information to be specified using XML.  


There are three different types of bean attributes:

The attributes of a session bean descriptor correspond to the attributes of the class javax.ejb.deployment.SessionDescriptor and its super class javax.ejb.deployment.DeploymentDescriptor.

Table 2-2 lists the attributes that you can use in the deployment descriptor.

Table 2-2 Deployment Descriptor Attributes (Cont.)
Table 2-3

Attribute Name 

Values 

Required? 

BeanHomeName  

A Java String that represents the published name of the bean.  

Yes  

HomeInterfaceClassName  

The fully-qualified name of the bean home interface class.  

Yes  

RemoteInterfaceClassName  

The fully-qualified name of the bean remote interface class.  

Yes  

Reentrant  

The literal "true" or "false". For entity beans.  

No  

SessionTimeout  

In seconds from the time that the last bean client disconnects. The default value is 0, which means that the session terminates when the last connection has terminated.  

No  

StateManagementType  

STATEFUL_SESSION | STATELESS_SESSION
Determines whether a session bean is stateful or stateless. Not relevant for the Oracle8i implementation. The default is STATEFUL_SESSION, which you should always use.  

No  

TransactionAttribute  

TX_BEAN_MANAGED | TX_MANDATORY | TX_NOT_SUPPORTED |
TX_REQUIRED | TX_REQUIRES_NEW | TX_SUPPORTS (the default).
See Transaction Management for EJBs for the semantics of the transaction attributes.  

No  

IsolationLevel  

TRANSACTION_READ_COMMITTED | TRANSACTION_READ_UNCOMMITTED | TRANSACTION_REPEATABLE_READ | TRANSACTION_SERIALIZABLE
This is not supported in the Oracle8i EJB server.  

No  

RunAsMode  

CLIENT_IDENTITY | SPECIFIED_IDENTITY | SYSTEM_IDENTITY  

No  

RunAsIdentity  

A username in the database. Cannot be a role.  

Yes, if RunAsMode is used.  

AllowedIdentities  

A list of usernames or roles in the database, enclosed in braces. Example: {SCOTT, WENDY, OTTO}.  

No  

The example below demonstrates a deployment descriptor:

SessionBean ejb.test.server.DatabaseWorkImpl
{
  BeanHomeName = "test/dbwork";  // this is the published name of the bean
  RemoteInterfaceClassName = ejb.test.DatabaseWork;
  HomeInterfaceClassName = ejb.test.DatabaseWorkHome;

  AllowedIdentities = {SCOTT}; 

  SessionTimeout = 30;   // in seconds
  StateManagementType = STATEFUL_SESSION;

  RunAsMode = CLIENT_IDENTITY;

  TransactionAttribute = TX_REQUIRES_NEW;
  
  // Add any environment properties that the bean requires
  EnvironmentProperties {
    prop1 = value1;
    prop2 = "value two";
  }

  public ejb.test.EmpRecord getEmployee(int e) throws TestException{ 
    RunAsMode = CLIENT_IDENTITY;      
    AllowedIdentities = { SCOTT };
  }
  public void update(int e, double s) throws TestException{ 
    RunAsMode = SPECIFIED_IDENTITY;      
    AllowedIdentities = { OTTO };
  }
}

Create a JAR File

The deployejb command-line tool creates a JAR file to use on the client side to access the bean.

Publish the Home Interface

A bean provider must make the bean's home interface available for JNDI lookup so that clients can find and activate the bean. In JServer, you publish the bean home interface in an Oracle8i database with the deployejb command-line tool. It publishes the bean in the instance CosNaming namespace under the name that you specify in the BeanHomeName attribute of the deployment descriptor.

Dropping an EJB

Drop an EJB from the database by following these steps:

See Chapter 6, "Tools", for documentation of the dropjava and session shell tools.

Implementing Transactions

Enterprise JavaBeans are inherently transactional. Transaction support is supplied for the bean by the EJB container. You do not need to implement explicit transaction methods in the bean or call transaction services from the client.

EJB supports declarative transactions. The bean deployer can specify, in the deployment descriptor, the transaction attributes for a bean or for an individual method in a bean. For example, if the deployment descriptor for a bean declares that the bean has the transaction attribute TX_REQUIRES_NEW, the bean container starts a transaction before each method call to the bean and attempts to commit the transaction when the method ends.

TransactionAttribute

The bean deployer declares the transaction handling characteristics of a bean in the deployment descriptor, which is specified in the transaction attribute. The attribute has six possible values:

"Transaction Management for EJBs" describes the semantics of these attribute values.

Access Control

The EJB deployment descriptor enables you to specify access control lists. You can specify access control either on the entire bean or on individual methods of the bean.

In the text form of the deployment descriptor, specify the AllowedIdentities attribute with a list containing usernames, roles, or a mixture of the two. Only users, or users with the roles specified in the AllowedIdentities attribute, can access the bean, or the methods that are restricted by the attribute. For example:

AllowedIdentities = {SCOTT};  // only SCOTT can access the bean
AllowedIdentities = {PUBLIC}; // all users can access the bean


public int Rmethod (int p1, double p2) throws TestException{ 
    RunAsMode = CLIENT_IDENTITY;      
    AllowedIdentities = { ROGERS };   // only ROGERS can invoke this method
}

When you specify method access control, the method must be either a public business method of the bean or the ejbCreate() method.

Transaction Isolation Level

The current release does not support the transaction isolation level attribute.

Using Session Synchronization

An EJB can optionally implement the session synchronization interface, to be notified by the container of the transactional state of the bean. Use this interface to save the bean state in the database at transaction boundaries. "Session Synchronization Interface" describes this interface.

Deployment Steps

The format used to package EJBs is defined by the EJB specification. The format is adaptable--you can use it to distribute a single EJB or to distribute a complete server-side application made up of tens or even hundreds of beans. This section describes the steps that the EJB developer and the EJB deployer take to compile, package, and deploy an EJB. Oracle8i supplies a deployment tool, deployejb, that automatically performs most of the steps necessary to deploy an EJB. The deployejb tool deploys only one bean at a time. This tool is described in "deployejb".

To deploy an EJB, follow these four steps:

  1. Compile the code for the bean. This includes:

    • the home interface

    • the remote interface

    • the bean implementation

    • all Java source files dependent on the bean implementation class (this dependency is normally taken care of by the Java compiler)

      Use the standard client-side Java compiler to compile the bean source files. A bean typically consists of one or more Java source files and might have associated resource files.

      Oracle8i supports the Sun Microsystems Java Developer's Kit version 1.1.6 compiler. Although, you might be able to use another JCK-tested Java compiler to create EJBs to run in the Oracle8i server, Oracle supports JDK 1.1.6 or later.

  2. Write a deployment descriptor for the EJB. See Programming Restrictions for specific information about creating deployment descriptors.

  3. Create a JAR file containing the interface and implementation class files--the home interface, the remote interface, and the bean implementation--for the bean. If you have other dependent classes and resource files, it is better to create a separate JAR file for these. The deployejb tool uses this JAR file as an input file.

  4. Call the deployejb tool (see "deployejb") to load and publish the JAR'd bean.

Programming Techniques

This section describes some of the programming techniques you can use when developing EJB session beans. You can use all the capabilities supplied by the Oracle8i multi-threaded server to manage multiple sessions, use SQLJ to simplify data acquisition and update, and employ the UserTransaction interface to manage transactions.

Using SQLJ

The bean developer can employ the Oracle8i SQLJ translator to simplify EJBs that access the database using static SQL statements. For example, "The Bean Implementation" required about seven JDBC calls. The same bean implementation can use SQLJ, which requires only two major SQLJ statements, as shown below:

package employeeServer;

import employee.EmpRecord;

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

public class EmployeeBean implements SessionBean {
  SessionContext ctx;

  public void ejbCreate() throws CreateException, RemoteException {
  }

  public void ejbActivate() {
  }

  public void ejbPassivate() {
  }

  public void ejbRemove() {
  }

  public void setSessionContext(SessionContext ctx) {
    this.ctx = ctx;
  }

  public EmpRecord query (int empNumber) throws SQLException, RemoteException
  {
    String ename;
    double sal;

    #sql { select ename, sal into :ename, :sal from emp 
                  where empno = :empNumber }; 

    return new EmpRecord (ename, empNumber, sal);
  }
}

The complete example is available on the distribution CD in the demo.tar file, as sqljimpl in the examples/ejb/basic directory.

Setting a Session Timeout

The session timeout value in the deployment descriptor determines how long a session stays active after the last bean client disconnects. It can be important to keep a session alive in at least two cases:

The EJB deployer can set a session timeout value, using the SessionTimeout attribute in the bean deployment descriptor (see "The Deployment Descriptor").

Saving an EJB Handle

Using the Oracle8i EJB server, it is possible for a client to connect to a session that was started by another client, and to access a bean in that session. This is true as long as the second client can authenticate as a valid user of the database.

However, to access a session established by another user, the client must have access to a handle for a bean in that session. A client can provide such a handle to another client using the getHandle() method, which returns a bean object reference.

The following code demonstrates one way to get a bean handle and save it to a file using an output stream. You can also use Java streams to write the bean handle to another reader object.

First, get a reference to a bean, in the usual way:

saveHandleHome home =
 (saveHandleHome) ic.lookup("sess_iiop://localhost:2481:ORCL/test/myEmployee");
saveHandle testBean = home.create();

Next, create an object output stream from a file stream:

FileOutputStream fostream = new FileOutputStream(handlefile);
ObjectOutputStream ostream = new ObjectOutputStream(fostream);

Then get the bean handle using getHandle(), and write it to the output stream:

ostream.writeObject(testBean.getHandle());

Finally, clean up the streams:

ostream.flush();
fostream.close();

See the complete example in examples/ejb/basic/saveHandle in the demo.tar file on the distribution CD.

EJB as Client

It is possible for an EJB to serve as a client to another EJB. In this case, the client EJB simply looks up the other EJB in the same way that a Java non-EJB client would.

See the example in the examples /ejb/session/clientserverserver directory in the demo file (demo.tar or demo.zip).

Programming Restrictions

The EJB 1.0 specification contains the following programming restrictions, which you must follow when implementing the methods of an EJB class:

The 1.0 EJB specification states that "an EJB is not allowed to use read/write static fields. Using read-only static fields is allowed. Therefore, all static fields must be declared as final." This is not a restriction for Oracle8i.

For More Information

Here are some references to specifications and other material that provides more information about EJBs and related services.




Prev

Next
Oracle
Copyright © 1999 Oracle Corporation.

All Rights Reserved.

Library

Product

Contents

Index