Oracle JDeveloper Tip

Creating a CMT Stateless SessionBean Facade for an Application Module

Author: Steve Muench, BC4J Development Team
Date: July 15, 2004

Contents
Overview
Our Application Module
Creating the Stateless Session Bean Wrapper
Aggregating a BC4J Application Module
Building a Test Client
Running the Sample
Conclusion
Code Listing

Overview

BC4J provides automatic facilities for deploying any application module as a stateful EJB session bean. If you want to leverage the features of your BC4J application module from a stateless EJB session bean, it's not automatic but it is straightforward to implement. This howto article explains the details.

NOTE:

You can download the statelesscmtsessionbean.zip workspace to try the example described in this paper in your own JDeveloper environment. See the README.txt file in the project for further tips.


For our example, we will create a stateless EJB session bean that uses a container-managed transaction. To keep things simple, let's assume our service has a single business method named createOrUpdateDepartment() with the following signature:
public boolean createOrUpdateDepartment(int id, String name, String loc)
The goal of this article is to illustrate how to use the BC4J application module named com.example.hr.HRApp as part of the implementation of this createOrUpdateDepartment method on our stateless enterprise bean. Let's assume that the HRApp application module has a view object member named Departments, based on the com.example.hr.DeptView view object, based on the familiar DEPT table and related to the com.example.hr.Dept entity object so our view can be updateable.

Our Application Module

We start with a BC4J ApplicationModule component named HRApp in the com.example.hr package. We've written a custom createOrUpdateDepartment() method in our HRAppImpl.java class and we've visited the ApplicationModule editor's Client Methods panel and shuttled createOrUpdateDepartment method into the list of selected methods to include on our application module's client interface. The method implementation tries to find an existing row in the Departments view object having the id passed in as its primary key, then either updates that existing row or creates a new row appropriately. It returns boolean true if a new row gets created. The code looks like this:

  /*
   * Returns true if new row was created.
   */
  public boolean createOrUpdateDepartment(int id, String name, String loc) {
    boolean createdNewRow = false;
    /*
     * Use the "Departments" view object instance of this AM
     */
    ViewObject departments = getDepartments();
    /*
     * Check to see if the Department with this ID already exists
     */
     Number deptId = new Number(id);
     Key k = new Key(new Object[]{deptId});
     Row[] found = departments.findByKey(k,1);
     if (found.length > 0) {
       /*
        * If we found it, then update it's Dname and Loc
        */
        Row existingDept = found[0];
        existingDept.setAttribute("Dname", name);
        existingDept.setAttribute("Loc", loc);
     }
     else {
       createdNewRow = true;
       /*
        * Otherwise create a new Dept row
        */
       Row newDept = departments.createRow();
       /*
        * Add the new row to the view object's default rowset
        */
       departments.insertRow(newDept);
       /*
        * Populate the attributes from the parameter arguments.
        */
        newDept.setAttribute("Deptno", new Number(id));
        newDept.setAttribute("Dname", name);
        newDept.setAttribute("Loc", loc);
     }
     return createdNewRow;
  }
By writing our custom code inside the lightweight application module component, we gain two benefits:
  • We can reuse this lightweight component both as a simple Java Bean as well as an EJB SessionBean
  • We can more easily test the lightweight component outside of the EJB container
Creating the Stateless Session Bean Wrapper

We can start by using the JDeveloper Enterprise Bean wizard to create a new stateless session bean called StatelessSample implemented by:

  • com.example.StatelessSampleBean (Bean class)
  • com.example.StatelessSampleHome (Home interface)
  • com.example.StatelessSample (Remote interface)
We then use the EJB Class Editor to add the createOrUpdateDepartment method to the StatelessSample bean's remote interface with the signature above. We edit the remote interface to make sure that it also reflects that the createOrUpdateDepartment method thows the AppException like this:
package com.example;
import javax.ejb.EJBObject;
import java.rmi.RemoteException;

public interface StatelessSample extends EJBObject  {
  boolean createOrUpdateDepartment(int id, String name, String loc)
    throws RemoteException, AppException;
}
The AppException is an example of an application-specific exception that our method will throw if any problems arise during its execution. Its code looks like this:
package com.example;
public class AppException extends Exception  {
  public AppException(String msg) {super(msg);}
}
Before we start adding BC4J into the picture for our Stateless SessionBean wrapper implementation, our StatelessSampleBean class looks like this:
package com.example;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;

public class StatelessSampleBean implements SessionBean {
  public void ejbCreate(){}
  public void ejbActivate(){}
  public void ejbPassivate(){}
  public void ejbRemove(){}
  public void setSessionContext(SessionContext ctx){
  }
  public boolean createOrUpdateDepartment(int id, String name, String loc)  
  throws AppException {
    // TODO: Implement method here
  }
}

We need to mark the createOrUpdateDepartment method as requiring a transaction. To do this, we can use the EJB Module editor to click on the StatelessSample bean, select the createOrUpdateDepartment method, and then use the Container Transaction Attribute drop-down list on the Remote Properties tab to pick the value Required from the list.

NOTE:

If you have included both Remote and Local interfaces on your bean as the example project has done, make sure that you visit both the Local Properties and the Remote Properties tab to set the Container Transaction Attribute to Required in both places!


If you double-click on the ejb-jar.xml file in the sample project you can see the results of setting the transaction attribute in the EJB Module Editor. Look for the <transaction-attribute> tag in the <container-transaction> sections in the file.
                                     
<ejb-jar>
  <enterprise-beans>
    <session>
      <description>Session Bean ( Stateless )</description>
      <display-name>StatelessSample</display-name>
      <ejb-name>StatelessSample</ejb-name>
      <home>com.example.StatelessSampleHome</home>
      <remote>com.example.StatelessSample</remote>
      <local-home>com.example.StatelessSampleLocalHome</local-home>
      <local>com.example.StatelessSampleLocal</local>
      <ejb-class>com.example.StatelessSampleBean</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>
    </session>
  </enterprise-beans>
  <assembly-descriptor>
    <container-transaction>
      <method>
        <ejb-name>StatelessSample</ejb-name>
        <method-intf>Local</method-intf>
        <method-name>createOrUpdateDepartment</method-name>
        <method-params>
          <method-param>int</method-param>
          <method-param>java.lang.String</method-param>
          <method-param>java.lang.String</method-param>
        </method-params>
      </method>
      <trans-attribute>Required</trans-attribute>
    </container-transaction>
    <container-transaction>
      <method>
        <ejb-name>StatelessSample</ejb-name>
        <method-intf>Remote</method-intf>
        <method-name>createOrUpdateDepartment</method-name>
        <method-params>
          <method-param>int</method-param>
          <method-param>java.lang.String</method-param>
          <method-param>java.lang.String</method-param>
        </method-params>
      </method>
      <trans-attribute>Required</trans-attribute>
    </container-transaction>
  </assembly-descriptor>
</ejb-jar>

                                  
Aggregating a BC4J Application Module

With the EJB aspects of our bean setup, we can proceed to implementing the BC4J application module aggregation.

The first thing we do is add private variables to hold the EJB SessionContext and the instance of the aggregated BC4J ApplicationModule, like this:

/*
   * Place to hold onto the aggregated appmodule instance.
   * 
   * NOTE: We're using the custom interface com.example.hr.common.HRApp
   *       (which extends oracle.jbo.ApplicationModule) that the BC4J
   *       design time creates for us when we exposed the 
   *       createOrUpdateDepartment() method on our application module's
   *       client interface.
   */
  transient private HRApp _am  = null;
  /*
   * Remember the SessionContext that the EJB container provides us
   */
  private           SessionContext    _ctx = null;
and we modify the default, empty implementation of the setSessionContext() method to remember the session context like this:
 
public void setSessionContext(SessionContext ctx){ _ctx = ctx; }
We add additional constants that hold the names of the transactional and non-transactional J2EE datasources that we want BC4J to use, as well as the fully-qualified name of the BC4J application module that we'll be aggregating:
/*
 * JNDI resource name for the J2EE datasource to use for application work
 * For OC4J, this is the name of the 'ejb-location' name from the OC4J
 * <data-source> element in the data-source.xml file.
 */  
private static final String TRANSACTIONAL_DATASOURCE    = "jdbc/scottDS";
      
 /*
  * JNDI resource name for the non-transactional 2EE datasource to be 
  * used for AM snapshot passivation if your bean uses that feature.
  * This datasource will be used lazily by BC4J, but it must be set.
  * 
  * For OC4J, this is the name of the 'location' name from the OC4J
  * <data-source> element in the data-source.xml file.
  */  
 private static final String NONTRANSACTIONAL_DATASOURCE = "jdbc/scottCoreDS";

  /*
   * Fully-qualified BC4J application module name to aggregate
   */
private static final String APPMODNAME = "com.example.hr.HRApp";

NOTE:

When you create a connection named scott in the JDeveloper connection manager, at runtime JDeveloper automatically configures the data-sources.xml file to be used by the embedded OC4J instance to have that scott connection as a JDBC datasource with the JNDI ejb-location of jdbc/scottDS and the JNDI location of jdbc/scottCoreDS. The former ejb-location named datasource is transactional and participates in the CMT transaction. The latter location named datasource is a non-transactional datasource and does not participate in CMT transaction management. When you deploy an EJB JAR file in JDeveloper, it bundles up this data-sources.xml file and includes it in your *.ejbjar file as well. Later versions of JDeveloper provide declarative control over whether you want this automatic connection deployment or not.


We expand the now-empty ejbCreate() and ejbRemove() methods to create and destroy the aggregated instance of the BC4J application module that we'll use for the lifetime of the stateless session bean. When we're done, ejbCreate() it looks like this:
public void ejbCreate() throws CreateException {
    try {
      /*
       * Setup a hashtable of environment parameters for JNDI initial context
       */
      Hashtable env = new Hashtable();
      env.put(JboContext.INITIAL_CONTEXT_FACTORY,JboContext.JBO_CONTEXT_FACTORY);
      /*
       * NOTE: we want to use the BC4J app module in local mode as a simple Java class!
       */
      env.put(JboContext.DEPLOY_PLATFORM, JboContext.PLATFORM_LOCAL);
      /*
       * We set the internal datasource to be some convenient,
       * non-transactional datasource name.
       */
      env.put(PropertyConstants.INTERNAL_CONNECTION_PARAMS,NONTRANSACTIONAL_DATASOURCE);
      /*
       * Create an initial context, using this hashtable of environment params
       */
      InitialContext ic = new InitialContext(env);
      /*
       * Lookup a home interface for the application module
       */
      ApplicationModuleHome home = (ApplicationModuleHome)ic.lookup(APPMODNAME);
      /*
       * Using the home, create the instance of the appmodule we'll use
       */
      _am = (HRApp)home.create();
      /*
       * Register the BC4J factory to handle EJB container-managed transactions
       */
      registerContainerManagedTransactionHandlerFactory();
    }
    catch(Exception ex) {
       ex.printStackTrace();
      throw new CreateException(ex.getMessage());
    }
  }
        
and ejbRemove() looks like this:
 public void ejbRemove() {
  try {
    // Cleanup any appmodule resources before getting shutdown 
    _am.remove();
  }
  catch(JboException ex) { /* Ignore */ } 
} 
The helper method named reigsterContainerManagedTransactionHandlerFactory() looks like this:
/*
   * Handle setting up the correct BC4J transaction handler
   * for participating in CMT transactions.
   */
  private void registerContainerManagedTransactionHandlerFactory() {
    SessionImpl session = (SessionImpl)_am.getSession();
    session.setTransactionHandlerFactory(
      new TransactionHandlerFactory() {
        public TransactionHandler  createTransactionHandler() {
          return new ContainerManagedTxnHandlerImpl();
        }
        public JTATransactionHandler createJTATransactionHandler() {
          return new ContainerManagedTxnHandlerImpl();
        }
      }
    );
  }      
It utilizes some built-in classes in the BC4J framework to handle the interaction between the EJB container managed transaction and the BC4J application module's transaction. The last detail is to implement the createOrUpdateDepartment() method in the SessionBean. The implementation needs to:
  1. Connect the AM to the transactional datasource we want to use
  2. Delegate to the createOrUpdateDepartment method on the HRApp interface of the application module
  3. Post the pending changes in the application module component's unit of work, but do not commit them.

    NOTE: The EJB container's CMT transaction will orchestrate to the commit and the ContainerManagedTxnHandlerImpl we used above in our wrapper bean implementation will insure that the BC4J application module's pending work gets committed then.

  4. Disconnect the AM from its datasource
In order to be good CMT "citizens" in the transaction, if any JboException is raised during the execution of the method, we perform the required step of calling:
_ctx.setRollbackOnly();
on the session context to signal to the container that something went wrong in posting our pending changes so that the overall container transaction should not proceed.

The final createOrUpdateDepartment() wrapper code to perform these steps looks like this:

public boolean createOrUpdateDepartment(int id,
                                                       String name,
                                                       String loc)
  throws AppException {
    boolean createdNewRow = false;
    try {
      /*
       * Connect the AM to the datasource we want to use for
       * the duration of this single method call.
       */
      _am.getTransaction().connectToDataSource(null,
                              TRANSACTIONAL_DATASOURCE,
                              false);
      /*
       * Delegate the method call to the implementation of
       * the custom HRApp interface of our HRApp application
       * module.
       */
      createdNewRow = _am.createOrUpdateDepartment(id,name,loc);
      /*
       * Post all changes in the AM, but we don't commit them.
       * The EJB container managed transaction handles
       * the commit.
       */
      _am.getTransaction().postChanges();
      return createdNewRow;
    }
    catch(JboException ex) {
      /*
       * To be good EJB Container-Managed Transaction "citizens"
       * we have to mark the transaction as needing a rollback 
       * if there are problems
       */
      _ctx.setRollbackOnly();
      throw new AppException("Error creating dept "+ id
                               +"\n"+ex.getMessage());
    }
    finally {
      try {
        /*
         * Disconnect the AM from the datasource we're using
         */
        _am.getTransaction().disconnect();
      }
      catch(Exception ex) { /* Ignore */ }
    }
  }

Building a Test Client

With the EJB-Tier work done, we can build a sample client program to test this new stateless EJB Session Bean by selecting the bean in the JDeveloper IDE and choosing "Create Sample Java Client" from the right-mouse menu.

NOTE:

This option appears only if your bean supports remote interfaces.


When the "Sample EJB Client Details" dialog appears, we take the defaults of connecting to embedded OC4J container. Clicking the (OK) button generates the following test class:

import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import com.example.StatelessSampleEJB;
import com.example.StatelessSampleEJBHome;

public class SampleStatelessSampleEJBClient {
  public static void main(String [] args) {
    SampleStatelessSampleEJBClient sampleStatelessSampleEJBClient =
       new SampleStatelessSampleEJBClient();
    try {
      Hashtable env = new Hashtable();
      env.put(Context.INITIAL_CONTEXT_FACTORY, 
              "com.evermind.server.rmi.RMIInitialContextFactory");
      env.put(Context.SECURITY_PRINCIPAL, "admin"); 
      env.put(Context.SECURITY_CREDENTIALS, "welcome");
      env.put(Context.PROVIDER_URL, 
              "ormi://localhost:23891/current-workspace-app");
      Context ctx = new InitialContext(env);
      StatelessSampleEJBHome statelessSampleEJBHome =
           (StatelessSampleEJBHome)ctx.lookup("StatelessSampleEJB");
      StatelessSampleEJB statelessSampleEJB;

      // Use one of the create() methods below to create a new instance
      // statelessSampleEJB = statelessSampleEJBHome.create();

      // Call any of the Remote methods below to access the EJB
      // statelessSampleEJB.createDepartment( int id,
      //                                      String name,
      //                                      String loc );
    }
    catch(Throwable ex) {
      ex.printStackTrace();
    }
  }
}
I modified the sample client slightly to produce one that attempts to test our createOrUpdateDepartment method in a few different ways, and which includes the appropriate PROVIDER_URL values for connecting to the SessionBean running on the embbed OC4J container as well as an external OC4J container:
package com.example;
import com.example.StatelessSample;
import com.example.StatelessSampleHome;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
public class StatelessSampleClient {
  public static void main(String[] args) throws Throwable {
    StatelessSampleClient statelessSampleClient = 
                             new StatelessSampleClient();
      Context context = getInitialContext();
      /*
       * Lookup the Home Interface
       */
      StatelessSampleHome statelessSampleHome =
        (StatelessSampleHome) PortableRemoteObject.narrow(
                              context.lookup("StatelessSample"),
                              StatelessSampleHome.class);
      /*
       * Use one of the create() methods below to create a new instance
       */
      StatelessSample statelessSampleEJB = statelessSampleHome.create();
      /*
       * Call any of the Remote methods below to access the EJB
       */
    boolean created = false;
    try {
      created = statelessSampleEJB.createOrUpdateDepartment(13, "Test1", "Loc1");
      System.out.println((created ? "Created" : "Updated")+" department 13");
    }
    catch (AppException ax) {
      System.err.println("AppException: " + ax.getMessage());
    }
    try {
      statelessSampleEJB.createOrUpdateDepartment(14, "Test2", "Loc2");
      System.out.println((created ? "Created" : "Updated")+" department 14");
    }
    catch (AppException ax) {
      System.err.println("AppException: " + ax.getMessage());
    }
    try {
      /*
       * Try setting a department id that is too large!
       */
      statelessSampleEJB.createOrUpdateDepartment(23456, "Test3", "Loc3");
      System.out.println((created ? "Created" : "Updated")+" department 23456");
    }
    catch (AppException ax) {
      System.err.println("AppException: " + ax.getMessage());
    }
    try {
      /*
       * Try setting a location of "Loc5" which will fail during
       * post-time if you have run the ExampleTriggerToMakeUpdateFail.sql
       * script in this project.
       */
      statelessSampleEJB.createOrUpdateDepartment(14, "Test2", "Loc5");
      System.out.println((created ? "Created" : "Updated")+" department 14");
    }
    catch (AppException ax) {
      System.err.println("AppException: " + ax.getMessage());
    }    
  }
  private static Context getInitialContext() throws NamingException {
    Hashtable env = new Hashtable();
    env.put(Context.INITIAL_CONTEXT_FACTORY,
      "com.evermind.server.rmi.RMIInitialContextFactory");
    env.put(Context.SECURITY_PRINCIPAL, "admin");
    env.put(Context.SECURITY_CREDENTIALS, "welcome");
    /*
     * Use this URL if you want to test against the stateless session
     * bean running on the embedded OC4J container.
     * 
     * NOTE: Remember to "Run" the session bean first to start the
     * ----  embedded container before running this client, or you'll
     *       get an expected "Cannot connect" error since the server 
     *       bean won't be running and available for client connections.
     */
    String provider_url = "ormi://localhost:23891/current-workspace-app";
    /*
     * Use this URL instead if you want to test on an externally deployed
     * OC4J instance.
     */
    // String provider_url = "ormi://localhost/bc4jcmtslsb";
    env.put(Context.PROVIDER_URL,provider_url);
    return new InitialContext(env);
  }
}
Running the Sample

To run the example inside the JDeveloper IDE (9.0.3 or later) you need to:

  • Have previously created a named JDeveloper database connection named "scott" (case-sensitive!), pointing to the familiar SCOTT/ TIGER account where the DEPT table lives.

To run the example on the embedded OC4J container:

  1. Run the StatelessSample SessionBean on the embedded OC4J container by clicking on StatelessSample Session Bean in the navigator and chosing Run from the right-mouse context menu.
  2. With the embedded OC4J server running your session bean, run your StatelessSampleClient.java class by again clicking on it and picking Run from the context menu.
NOTE:

If you make any changes to the implementation of the sample EJB SessionBean, note that you'll need to terminate the embedded OC4J container, and rerun your modified SessionBean in order for the client to "see" the changed server-side implementation.


To run the example on the external, standalone OC4J container:

  1. Use the JDEVHOME/jdev/bin/start_oc4j.bat script to start the external OC4J instance.
  2. Define an Application Server connection, for example named localoc4j, and use the admin username with password of welcome as credentials.
  3. Use the ejbjar.deploy deployment profile in the project to deploy the EJB to the external server, by clicking on ejbjar.deploy and selecting Deploy to > localoc4j
  4. Comment out the line in StatelessSampleClient that sets the PROVIDER_URL for the embedded OC4J container...

    // String provider_url = "ormi://localhost:23891/current-workspace-app";
    
    and uncomment the line below with the value for the external container:

    String provider_url = "ormi://localhost/bc4jcmtslsb"
    
NOTE:

If you make any changes to the implementation of the sample EJB SessionBean, note that you'll need to redeploy the EJB to the external OC4J container in order for the client to "see" the changed server-side implementation.


When you run the StatelessSampleClient the first time, you'll see output like:
Created department 13
Created department 14
AppException: Error creating dept 23456
JBO-27010: Attribute set with value 23456 for Deptno in Dept has invalid precision/scale
Updated department 14
If you want to experiment with failures that can occur during an update, you might experiment by running the ExampleTriggerToMakeUpdateFail.sql script against your SCOTT account and then try running the StatelessSampleClient again. This scripts creates the simple database trigger below which rejects any attempt to insert or update a row in the DEPT table with a LOC value of "Loc5" (case-insensitive):
create trigger reject_dept_loc5
before insert or update on dept for each row
begin
  if (upper(:new.loc) = 'LOC5') then
    raise_application_error(-20001,'Cannot have location of LOC5');
  end if;
end;
If you create this trigger and rerun the StatelessSampleClient, you'll see output like this:
Updated department 13
Updated department 14
AppException: Error creating dept 23456
JBO-27010: Attribute set with value 23456 for Deptno
           in Dept has invalid precision/scale
AppException: Error creating dept 14
JBO-26041: Failed to post data to database during "Update":
           SQL Statement " UPDATE DEPT Dept SET DNAME=:1,LOC=:2 WHERE DEPTNO=:3".
Conclusion

Hopefully this article has illustrated that it is straightforward to utilize the full power of BC4J in local mode as part of your EJB Stateless Session Beans using container-managed transaction. This example illustrated delegating to the single createOrUpdateDepartment method in the application module, but by replicating the same code pattern above, we could easily expose many methods on the Stateless SessionBean in the same way.

NOTE:

The steps discussed here are valid for BC4J in JDeveloper 9.0.3 and 9.0.4, as well as for ADF Business Components in JDeveloper 10g.


Code Listing

The full code listing for the StatelessSampleBean bean implementation class looks like this:

/**
 * StatelessSampleBean 
 * 
 * Illustrates how to use an aggregated BC4J application module
 * in local mode as part of the implementation of a stateless
 * EJB session bean using container-managed transaction.
 * 
 * HISTORY
 * smuench          15-JUL-2004 Updated
 * smuench/dmutreja 14-FEB-2002 Created
 */package com.example;
import com.example.hr.common.*;

import java.util.Hashtable;

import javax.ejb.CreateException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;

import javax.naming.InitialContext;

import oracle.jbo.ApplicationModuleHome;
import oracle.jbo.JboContext;
import oracle.jbo.JboException;
import oracle.jbo.common.PropertyConstants;
import oracle.jbo.server.JTATransactionHandler;
import oracle.jbo.server.SessionImpl;
import oracle.jbo.server.TransactionHandler;
import oracle.jbo.server.TransactionHandlerFactory;
import oracle.jbo.server.ejb.ContainerManagedTxnHandlerImpl;
public class StatelessSampleBean implements SessionBean  {
  /*
   * Place to hold onto the aggregated appmodule instance.
   * 
   * NOTE: We're using the custom interface com.example.hr.common.HRApp
   *       (which extends oracle.jbo.ApplicationModule) that the BC4J
   *       design time creates for us when we exposed the 
   *       createOrUpdateDepartment() method on our application module's
   *       client interface.
   */
  transient private HRApp _am  = null;
  /*
   * Remember the SessionContext that the EJB container provides us
   */
  private           SessionContext    _ctx = null;

  /*
   * JNDI resource name for the J2EE datasource to use for application work
   * For OC4J, this is the name of the 'ejb-location' name from the OC4J
   * <data-source> element in the data-source.xml file.
   */  
  private static final String TRANSACTIONAL_DATASOURCE    = "jdbc/scottDS";
  
  /*
   * JNDI resource name for the non-transactional 2EE datasource to be 
   * used for AM snapshot passivation if your bean uses that feature.
   * This datasource will be used lazily by BC4J, but it must be set.
   * 
   * For OC4J, this is the name of the 'location' name from the OC4J
   * <data-source> element in the data-source.xml file.
   */  
  private static final String NONTRANSACTIONAL_DATASOURCE = "jdbc/scottCoreDS";

  /*
   * Fully-qualified BC4J application module name to aggregate
   */
  private static final String APPMODNAME = "com.example.hr.HRApp";

  public void ejbCreate() throws CreateException {
    try {
      /*
       * Setup a hashtable of environment parameters for JNDI initial context
       */
      Hashtable env = new Hashtable();
      env.put(JboContext.INITIAL_CONTEXT_FACTORY,JboContext.JBO_CONTEXT_FACTORY);
      /*
       * NOTE: we want to use the BC4J app module in local mode as a simple Java class!
       */
      env.put(JboContext.DEPLOY_PLATFORM, JboContext.PLATFORM_LOCAL);
      /*
       * We set the internal datasource to be some convenient,
       * non-transactional datasource name.
       */
      env.put(PropertyConstants.INTERNAL_CONNECTION_PARAMS,NONTRANSACTIONAL_DATASOURCE);
      /*
       * Create an initial context, using this hashtable of environment params
       */
      InitialContext ic = new InitialContext(env);
      /*
       * Lookup a home interface for the application module
       */
      ApplicationModuleHome home = (ApplicationModuleHome)ic.lookup(APPMODNAME);
      /*
       * Using the home, create the instance of the appmodule we'll use
       */
      _am = (HRApp)home.create();
      /*
       * Register the BC4J factory to handle EJB container-managed transactions
       */
      registerContainerManagedTransactionHandlerFactory();
    }
    catch(Exception ex) {
       ex.printStackTrace();
      throw new CreateException(ex.getMessage());
    }
  }

  public void ejbActivate() {}
  public void ejbPassivate() {}

  public void ejbRemove() {
    try {
      /*
       * Cleanup any appmodule resources before getting shutdown
       */
      _am.remove();
    }
    catch(JboException ex) { /* Ignore */ }
  }

  public void setSessionContext(SessionContext ctx){ _ctx = ctx; }

  /*
   * Returns true if new row was created.
   */
  public boolean createOrUpdateDepartment(int id, String name, String loc)
  throws AppException {
    boolean createdNewRow = false;
    try {
      /*
       * Connect the AM to the datasource we want to use for the duration
       * of this single method call.
       */
      _am.getTransaction().connectToDataSource(null,TRANSACTIONAL_DATASOURCE,false);
      /*
       * Delegate the method call to the implementation of the custom
       * HRApp interface of our HRApp application module.
       */
      createdNewRow = _am.createOrUpdateDepartment(id,name,loc);
      /*
       * Post all changes in the AM, but we don't commit them.
       * The EJB container managed transaction handles the commit.
       */
      _am.getTransaction().postChanges();
      return createdNewRow;
    }
    catch(JboException ex) {
      /*
       * To be good EJB Container-Managed Transaction "citizens" we have
       * to mark the transaction as needing a rollback if there are problems
       */
      _ctx.setRollbackOnly();
      throw new AppException("Error creating dept "+ id +"\n"+ex.getMessage());
    }
    finally {
      try {
        /*
         * Disconnect the AM from the datasource we're using
         */
        _am.getTransaction().disconnect();
      }
      catch(Exception ex) { /* Ignore */ }
    }
  }
  /*
   * Handle setting up the correct BC4J transaction handler
   * for participating in CMT transactions.
   */
  private void registerContainerManagedTransactionHandlerFactory() {
    SessionImpl session = (SessionImpl)_am.getSession();
    session.setTransactionHandlerFactory(
      new TransactionHandlerFactory() {
        public TransactionHandler  createTransactionHandler() {
          return new ContainerManagedTxnHandlerImpl();
        }
        public JTATransactionHandler createJTATransactionHandler() {
          return new ContainerManagedTxnHandlerImpl();
        }
      }
    );
  }
}

false ,,,,,,,,,,,,,,,