12 Creating and Using EJB Jobs

This chapter describes how to use Oracle Enterprise Scheduler to create Enterprise Java Bean (EJB) jobs.

This chapter contains the following sections:

12.1 Introduction to Creating EJB Jobs

The EJB job type allows you to create Java-based jobs and take advantage of the convenience of the pre-deployed hosting application. In addition, the EJB can be located remotely on a different server.

Unlike Java SE-based jobs, EJB jobs are not required to be embedded inside the hosting application. This allows them to be located remotely and to be used with the pre-deployed hosting application. An EJB job can be invoked from any hosting application, including the pre-deployed hosting application. Note that the EJB implementation must be in the same WebLogic domain as the scheduler server.

The EJB conforms to an interface defined by Oracle Enterprise Scheduler (defined in a shared library). The EJB is non-transactional. Both synchronous and asynchronous EJB jobs are supported. When running asynchronously, the EJB returns quickly and the Oracle Enterprise Scheduler EJB is invoked later when the job completes. The EJB implementation can work with any of the three shared libraries—server (oracle.ess), client (oracle.ess.client), and thin client (oracle.ess.thin.client). The thin client shared library does not depend on Oracle Enterprise Scheduler data sources. See Creating a Thin Client Application for more information about using the thin client library.

The EJB can submit sub-requests and it can write to output and a log. The EJB interface is similar or the same as a Java job and can do similar things. To improve performance, it is possible to consolidate multiple job implementations under a single shared EJB.

An EJB job is a Java job that is executed remotely using the EJB remote business interface. The execution type is JAVA_TYPE. The remote job is an EJB deployed in a remote server. The remote business interface of this bean extends the oracle.as.scheduler.RemoteExecutable interface and defines the execute method. The contract between Oracle Enterprise Scheduler and the servicing component is defined with the execute method. Figure 12-1 shows the components in a typical EJB job deployment.

The EJB must be located in the same domain as the hosting application and the Subject object is propagated to the EJB. For JNDI lookup operations, you can supply optional credentials. The default identity is "anonymous".

Figure 12-1 EJB Job Environment

Description of Figure 12-1 follows
Description of "Figure 12-1 EJB Job Environment"

12.2 Planning Job Development

The Oracle Enterprise Scheduler is flexible and provides implementation and deployment options. Planning Job Development is a high-level discussion about how to plan your job development and deployment process.

12.3 Creating and Storing Job Definitions for EJB Job Types

To use EJB type jobs with Oracle Enterprise Scheduler, you must locate the Metadata Service and create a job definition. You create a job definition by specifying a name and a job type. When you create a job definition you must also set certain system properties.

You can store the job definition in the metadata repository using the Metadata Service. Sample metadata files are provided later in this chapter.

For information about how to use the Metadata Service, see Using the Metadata Service .

When you specify the JobType for the job definition, you can also specify SystemProperties that define the characteristics associated with the JobType. Table 12-1 and Table 12-2 describe the properties that specify how the request should be processed.

Table 12-1 EJB Job Type Properties

Property Name [Field in SystemProperty class] Description

SYS_EXT_jndiProviderUrl [JNDI_PROVIDER_URL]

Optional. Specifies the URL of the remote server. Required only if the EJB is remotely located.

The JndiProviderUrl can be specified to contain tokens that are resolved at runtime.

The following are two examples:

  • ${WIRING:urn:oracle:fmw:soa:t3}

    This URN is resolved at runtime and the actual URL value is fetched.

  • t3://localhost:19283

    Where localhost is the host where EJB's are deployed and 19283 is the server port number.

SYS_EXT_jndiMappedName [JNDI_MAPPED_NAME]

Required. Specifies the JNDI lookup name of a remote EJB implementation.

Example: ejb/fileAdapter

SYS_EXT_ejbOperationName [EJB_OPERATION_NAME]

Optional. Specifies a pass-through parameter used by the EJB implementation to branch to the appropriate business methods.

Example: manageFileAdapter

SYS_EXT_jndiCSFKey [JNDI_CSF_KEY]

Required only if the JNDI tree of the EJB server is secured. Points to the CSF alias that is mapped to the user name and password in the keystore. This specific user name/password pair is the credential required to access the secured JNDI for JndiMappedName lookup.

This property can be added to either the RequestParameters object or to the Oracle Enterprise Scheduler configuration of the hosting application.

Note:

You can use Oracle Enterprise Manager Fusion Middleware Control or WLST scripts to configure the CSF key aliases as a post installation step. Prior to the post installation step, the Keystore's CSF map can be set to the default value of oracle.ess.security.

Table 12-2 lists the properties that can be added either to the RequestParameters object or to the Oracle Enterprise Scheduler configuration of the hosting application. In a production environment, environment specific data should not be entered into the job definition because the job definition is replicated when going from the test environment to the production environment. Instead, this data should be entered separately as configuration data with the hosting application. The Oracle Enterprise Scheduler token substitution and logical cluster features allow you to abstract metadata so that it can be easily changed to correctly fit the target deployment during the T2P process. See Using Tokens and Logical Clusters for information about using these features.

Table 12-2 Additional Properties

Property Name [Field in SystemProperty class] Description

SYS_EXT_essJndiCsfKey [ESS_JNDI_CSF_KEY_NAME]

Optional. Specifies the CSF key alias of the authenticated Oracle Enterprise Scheduler server. This property is required only if the Oracle Enterprise Scheduler JNDI tree is authenticated.

Example: ess-jndi-csf-key

SYS_EXT_essRuntimeJndiMappedName{ESS_RUNTIME_JNDI_MAPPED_NAME]

Specifies the JNDI mapped name of Oracle Enterprise Scheduler's RuntimeService bean that is defined in the hosting application and bound to the Oracle Enterprise Scheduler server's JNDI tree.

This property is required only if you use a hosting application other than EssNativeHostingApp and the remote bean has to call the Oracle Enterprise Scheduler runtime bean (for example, to write output or log information, submit requests or operate on requests).

SYS_EXT_essMetadataJndiMappedName[ESS_METADATA_JNDI_MAPPED_NAME]

Specifies the JNDI mapped name of Oracle Enterprise Scheduler's MetadataService bean defined in the hosting application and bound to the Oracle Enterprise Scheduler server's JNDI tree.

This property is required only if you use a hosting application other than EssNativeHostingApp and the remote bean requires access to Oracle Enterprise Scheduler's metadata bean.

SYS_EXT_essAsyncRequestJndiMappedName[ESS_ASYNC_REQUEST_JNDI_MAPPED_NAME]

Specifies the JNDI mapped name of Oracle Enterprise Scheduler's AsyncRequest bean defined in the hosting application and bound to Oracle Enterprise Scheduler server's JNDI tree.

This property is required only if:

  • The EJB invocation is asynchronous

  • You use a hosting application other than EssNativeHostingApp

  • The remote bean has to call back to Oracle Enterprise Scheduler beans (for example, an asynchronous callback).

For more information about system properties, see Using Parameters and System Properties .

12.4 Secured Invocation

Secured invocation of remote EJBs is required when the JNDI tree of its server is authenticated. This is also true when a remote EJB calls back to Oracle Enterprise Scheduler EJBs using secured lookup. The following sections provide some guidance.

12.4.1 Forward Invocation

The following apply to forward invocation.

  • When Oracle Enterprise Scheduler invokes a remote EJB, the subject of the executing job is always propagated.

  • When Oracle Enterprise Scheduler executes a job, the JndiProviderUrl of the current Oracle Enterprise Scheduler Server is always supplied to the remote EJB through RequestParameters.

  • If the JNDI tree of the remote server is authenticated, the JNDI_CSF_KEY property must be specified in the request parameters or the EssConfiguration of the hosting application.

  • Oracle Enterprise Scheduler looks up the keystore for the CsfKey to retrieve the PasswordCredential and connects to the remote server.

12.4.2 Callback Invocation

The following apply to callback invocation.

  • If the remote EJB must call back to Oracle Enterprise Scheduler beans, the following properties can be specified:

    • The JNDI names of Oracle Enterprise Scheduler Runtime, Metadata and AsyncRequest beans exposed in HostingApp must be specified in request parameters or the EssConfiguration of the hosting application. If EssNativeHostingApp is used, these entries are not required.

    • If the JNDI tree of the Oracle Enterprise Scheduler server is authenticated, the ESS_JNDI_CSF_KEY_NAME property must be specified in the request parameters or EssConfiguration of the hosting application. Oracle Enterprise Scheduler ensures that this property is available to the remote EJB through RequestParameters.

  • A remote EJB can make use of the RemoteConnector API to get the remote instances of Oracle Enterprise Scheduler beans. This can be done by passing the following:

    • RequestParameters

    • RequestParameters and JndiMappedName of the bean (for hosting applications other than the native hosting application)

    • RequestParameters, user name and password (if the Oracle Enterprise Scheduler server is authenticated)

    • InitialContext (primarily for Java SE clients with EssNativeHostingApp)

    • InitialContext and jndiMappedName (primarily for Java SE clients with other hosting applications)

12.4.3 RemoteConnector API and the Server Affinity Property

If your code implementation relies on accessing Oracle Enterprise Scheduler EJBs, use the methods exposed in the RemoteConnector API class. The Oracle Enterprise Scheduler requires the server affinity property to be set in the InitialContext environment before doing a JNDI lookup and the RemoteConnector API class sets this property for you. Note that this is especially important in multi-node cluster scenarios. The RemoteConnector class is packaged in the Oracle Enterprise Scheduler client libraries.

If for some reason the RemoteConector class cannot be used, you can set the environment map property to the InitialContext before doing the look-up for the Oracle Enterprise Scheduler EJBs as shown in the following example.

if(PlatformUtils.isWebLogic())
   envProps.put("weblogic.jndi.enableServerAffinity", "true");

In a multi-node cluster environment, it is best to set the cluster algorithm to "round-robin-affinity".

12.4.4 CSF Lookup From a Remote Server

If the beans of Oracle Enterprise Scheduler Services are authenticated, remote applications must use a secured lookup to make callbacks to Oracle Enterprise Scheduler. You can use Oracle Enterprise Scheduler's RemoteConnector API which uses the ESS_JNDI_CSF_KEY_NAME property available in the request parameters to do the look-up. But to assist this CSF lookup, the code that invokes the RemoteConnector must grant permission for credential store access. The following XML fragment can be added to the jazn-data.xml file of the remote application.

 <jazn-policy>
    <grant>
      <grantee>
        <codesource>
          <url>file:${domain.home}/servers/${weblogic.Name}/tmp/ 	                _WL_user/<AppName>/-</url>
        </codesource>
      </grantee>
      <permissions>
      <permission>           <class>oracle.security.jps.service.credstore.CredentialAccessPermission
          </class>
          <name>context=SYSTEM,mapName=oracle.ess.security,keyName=*</name>
          <actions>READ</actions>
        </permission>
        <permission>
          <class>oracle.security.jps.JpsPermission</class>
          <name>IdentityAssertion</name>
          <actions>execute</actions>
        </permission>
        <permission>
          <class>oracle.security.jps.JpsPermission</class>
          <name>AppSecurityContext.setApplicationID.*</name>
        </permission>
      </permissions>
    </grant>
  </jazn-policy>  

12.5 Synchronous Bean

This section contains examples that illustrate how to create a synchronous bean.

12.5.1 Metadata

This section shows metadata as it applies to synchronous beans.

The following example shows a sample job definition for an EJB job located in the file oracle/apps/ess/custom/Jobs/EssGatewayJobDefn.xml

<?xml version = '1.0'?>
<job-definition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"                  xmlns="http://xmlns.oracle.com/scheduler"
                name="SoaEjbJobDefn"
                job-type="/oracle/as/ess/core/JobType/SyncEjbJobType.xml">
<description/>
  <display-name>EssGatewayBean</display-name>
  <parameter-list>
    <parameter name="SYS_EXT_jndiKeyName" data-type="string" read-only="true">
      ejb/essGatewayBean</parameter>
    <parameter name="SYS_EXT_jndiProviderUrl" data-type="string"        read-only="true">URL</parameter>
    <parameter name="SYS_EXT_ejbOperationName" data-type="string"  
      read-only="true">activateFileAdapter</parameter>
    <parameter name="SYS_effectiveApplication" data-type="string">
      ESS_NATIVE_HOSTING_APP_LOGICAL_NAME</parameter>
  </parameter-list>
</job-definition>
 

12.5.2 EJB Job Sample Code

This section shows a sample implementation of a synchronous EJB job expected by Oracle Enterprise Scheduler.

The following code snippet shows a fragment of the ejb-jar.xml file that defines this bean.

<session>
																      <description>ESS Gateway Bean</description>
      <ejb-name>EssGateway</ejb-name>
      <ejb-class>com.soa.beans.EssGatewayBean</ejb-class>
      <session-type>Stateless</session-type>
      <transaction-type>Container</transaction-type>     
      <security-identity>
        <use-caller-identity/>
      </security-identity>
</session>

The following code snippet shows a fragment of the weblogic-ejb-jar.xml file that defines this bean.

<weblogic-enterprise-bean>
      <ejb-name>FileAdapterBean</ejb-name>
      <stateless-session-descriptor>
         <business-interface-jndi-name-map>
            <business-remote>oracle.as.scheduler.RemoteCancellableExecutable
         </business-remote>
            <jndi-name>ejb/essGatewayBean</jndi-name>
         </business-interface-jndi-name-map>
      </stateless-session-descriptor>
 </weblogic-enterprise-bean>
import javax.ejb.Stateless;
import oracle.as.scheduler.SystemProperty;
import oracle.as.scheduler.ExecutionCancelledException;
import oracle.as.scheduler.ExecutionErrorException;
import oracle.as.scheduler.ExecutionPausedException;
import oracle.as.scheduler.ExecutionWarningException;
import oracle.as.scheduler.RemoteCancellableExecutable;
import oracle.as.scheduler.RequestExecutionContext;
import oracle.as.scheduler.RequestParameters;
 
@Stateless(name = "EssGateway", mappedName = "ejb/essGatewayBean")
public class EssGatewayBean implements RemoteCancellableExecutable
{
    public EssGatewayBean()
    {
    }
   
    public void execute(RequestExecutionContext context,
                    RequestParameters parameters) throws ExecutionErrorException,
                    ExecutionWarningException, ExecutionCancelledException,
                    ExecutionPausedException
    {
        //Get the value of 'SYS_EXT_ejbOperationName' property
        String opName = (String)parameters.getValue(SystemProperty.EJB_OPERATION_NAME);
 
        if("manageFileAdapter".equals(opName))
        {
            //
            //Call business method of this bean or some other bean
            //
            //Hint: User defined properties can be set in RequestParameters while
            //submitting the job and can be retrieved here for further processing.
        }
    }
 
    public void cancel(RequestExecutionContext context,
                    RequestParameters parameters)
    {
        //
        //Logic to cancel the execution of a business method.
        //
        // Execute the actual logic of cancellation, notifies back to ESS
        // by throwing ExecutionCancelledException through execute method.
    }
}

12.6 Asynchronous Bean

When Oracle Enterprise Scheduler invokes a bean asynchronously, it does not wait for the execute method to finish. For that reason, the bean implementation has to notify the Oracle Enterprise Scheduler after processing finishes. The RemoteAsyncHelper class can be used for this purpose. Alternatively, the AsyncRequestBean obtained from RemoteConnector can be used to notify Oracle Enterprise Scheduler with a status update.

Asynchronous EJBs are typically used:

  • For long-running operations

  • For processor-intensive tasks

  • For background tasks

  • To increase application throughput

  • To improve application response time if the method invocation result is not required immediately

The synchronous EJB job is more appropriate for short-running user business methods.

There are a couple of ways for Oracle Enterprise Scheduler to execute a bean asynchronously:

  • Explicit asynchrony: Use a synchronous stateless bean to invoke a message-driven bean asynchronously. (Add a Java Message Service message to a topic/queue that is listened to by a message-driven bean)

  • Implicit asynchrony: Use the EJB Asynchronous annotation to declare a business method (other than execute, cancel methods) to behave asynchronously.

Note:

Oracle Enterprise Scheduler can invoke a synchronous bean asynchronously. However, if you use this method the bean must be modeled in a way that long-running methods are marked for asynchrony.

Note:

As specified in the EJB standard, you cannot use the @Asynchronous annotation in the execute method or the entire class because the execute method throws custom exceptions which are not permitted. Oracle Enterprise Scheduler requires the execute method to throw custom exceptions.

12.6.1 Metadata

This section shows metadata as it applies to asynchronous beans.

This example shows a sample job definition for an EJB job located in the file oracle/apps/ess/custom/Jobs/AsyncJobDefn.xml

<?xml version = '1.0'?>
<job-definition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.oracle.com/scheduler" name="EssAsyncJobDefn"
	job-type="/oracle/as/ess/core/JobType/AsyncEjbJobType.xml">
  <display-name>EssGatewayBean</display-name>
  <parameter-list>
    <parameter name="SYS_EXT_jndiKeyName" data-type="string" 
       read-only="true">ejb/essAsyncGatewayBean</parameter>
    <parameter name="SYS_EXT_jndiProviderUrl" data-type="string" 
      read-only="true">t3://localhost:10801</parameter>
    <parameter name="SYS_EXT_ejbOperationName" 
      data-type="string"read-only="true">activateFileAdapter</parameter>
    <parameter name="SYS_effectiveApplication" data-type="string">
      ESS_NATIVE_HOSTING_APP_LOGICAL_NAME</parameter>
  </parameter-list>
</job-definition>

12.6.2 EJB Job Sample Code

This section includes sample code that illustrates how to implement asynchrony using both the explicit and implicit methods described in Asynchronous Bean.

12.6.2.1 Sample Implementation of Asynchrony Using a Message-Driven Bean

The following code sample shows a synchronous stateless bean that is used to invoke a message driven bean asynchronously.

package com.soa.test;
 
import java.io.Serializable;
import java.util.ArrayList;
import javax.ejb.Stateless;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
 
import javax.naming.InitialContext;
 
import oracle.as.scheduler.AsyncRequestBeanRemote;
import oracle.as.scheduler.ExecutionCancelledException;
import oracle.as.scheduler.ExecutionErrorException;
import oracle.as.scheduler.ExecutionPausedException;
import oracle.as.scheduler.ExecutionWarningException;
import oracle.as.scheduler.RemoteCancellableExecutable;
import oracle.as.scheduler.RequestExecutionContext;
import oracle.as.scheduler.RequestParameters;
import oracle.as.scheduler.request.RemoteConnector;
 
@Stateless(name = "EssAsyncPilot")
public class EssAsyncPilotBean implements RemoteCancellableExecutable 
{
	public EssAsyncPilotBean() {
	}
 
	public void execute(RequestExecutionContext requestExecutionContext,
			RequestParameters requestParameters)
			throws ExecutionErrorException, ExecutionWarningException,
			ExecutionPausedException, ExecutionCancelledException {
		// Delegate the job request cancellation to message driven bean
		postToQueue("execute", requestExecutionContext, requestParameters);
	}
 
	public void cancel(RequestExecutionContext requestExecutionContext,
			RequestParameters requestParameters) {
		RemoteConnector connector = new RemoteConnector();
		AsyncRequestBeanRemote asyncRequest;
 
		// Delegate the job request cancellation to message driven bean
		try {
			postToQueue("cancel", requestExecutionContext, requestParameters);
		} catch (Exception e) {
			//Mark this request as ERRORed
		}
		/*
		 * Other ways to cancel the job request.
		 * asyncRequest = connector.getAsyncRequestEJB(requestParameters);
		 * asyncRequest.onCancel(requestExecutionContext);
		 *
		 * (or)
		 *
		 * asyncRequest = connector.getAsyncRequestEJB(requestParameters);
		 * asyncRequest.setRequestStatus(
		 *      requestExecutionContext, AsyncStatus.CANCEL, "Cancelling the job");
		 *
		 * (or simply)
		 *
		 * RemoteAsyncHelper asyncHelper = new RemoteAsyncHelper(
		 *      requestExecutionContext, requestParameters);
		 * asyncHelper.onCancel();
		 *
		 */
	}
 
	private void postToQueue(String instruction,
			RequestExecutionContext context, RequestParameters params) {
		try {
			QueueConnectionFactory qconFactory;
			QueueConnection qcon;
			QueueSession qsession;
			QueueSender qsender;
			Queue queue;
			ObjectMessage msg;
			InitialContext ic = new InitialContext();
 
			qconFactory = (QueueConnectionFactory) ic
					.lookup("EssAsyncJmsConnFactory");
			qcon = qconFactory.createQueueConnection();
			qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
 
			queue = (Queue) ic.lookup("EssAsyncJmsQueue");
 
			qsender = qsession.createSender(queue);
			msg = qsession.createObjectMessage();
			qcon.start();
 
			ArrayList<Serializable> objsList = new ArrayList<Serializable>(2);
			objsList.add(context);
			objsList.add(params);
			objsList.add(instruction);
			msg.setObject(objsList);
			qsender.send(msg);
 
			System.out.println("The message, " + instruction
					+ ", has been sent to the EssAsyncJmsQueue.");
			qsender.close();
			qsession.close();
			qcon.close();
		} catch (Exception e) {
			System.out.print("error " + e);
		}
	}
}
import java.util.List;
import java.io.Serializable;
import javax.ejb.MessageDriven;
 
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.ObjectMessage;
 
import oracle.as.scheduler.RequestExecutionContext;
import oracle.as.scheduler.RequestParameters;
import oracle.as.scheduler.async.RemoteAsyncHelper;
 
/**
 * This message driven bean sample relies on execute/cancel instructions.
 * Upon completion of execution or cancellation, this bean notifies
 * ESS about its status so that the job request is marked for completion.
 */
@MessageDriven(mappedName = "ejb/essAsyncJms")
public class EssAsyncJmsBean implements MessageListener {
    public void onMessage(Message message) {
        if (message instanceof ObjectMessage) {
            ObjectMessage objMessage = (ObjectMessage)message;
            try {
                List<Serializable> objsList = (List<Serializable>)objMessage.getObject();
                RequestExecutionContext ctx = (RequestExecutionContext)objsList.get(0);
                RequestParameters params = (RequestParameters)objsList.get(1);
                String instruction = (String)objsList.get(2);
                RemoteAsyncHelper asyncHelper = new RemoteAsyncHelper(ctx, params);
                if ("cancel".equalsIgnoreCase(instruction)) {
                    //EssAsyncJmsBean.cancel: Cancelling the Execution
                    try {
                        //Do the actual cancellation
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                    }
                    asyncHelper.onCancel();
                    //EssAsyncJmsBean.cancel: Completed cancellation
                } else {
                    //EssAsyncJmsBean.execute: Started the Execution ");
                    try {
                        //Do the actual execution
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                    }
                    asyncHelper.onSuccess();
                    //EssAsyncJmsBean.execute: Completed the Execution ");
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
12.6.2.2 Sample Implementation of Asynchrony Using Annotations

The following code snippet uses the EJB Asynchronousto declare a bean or its methods to behave asynchronously.

package com.soa.test;
 
import java.util.concurrent.Future;
 
import javax.annotation.Resource;
 
import javax.ejb.AsyncResult;
import javax.ejb.Asynchronous;
import javax.ejb.SessionContext;
import javax.ejb.Stateless;
 
import javax.xml.transform.Result;
 
import oracle.as.scheduler.ExecutionCancelledException;
import oracle.as.scheduler.ExecutionErrorException;
import oracle.as.scheduler.ExecutionPausedException;
import oracle.as.scheduler.ExecutionWarningException;
import oracle.as.scheduler.RemoteExecutable;
import oracle.as.scheduler.RequestExecutionContext;
import oracle.as.scheduler.RequestNotFoundException;
import oracle.as.scheduler.RequestParameters;
import oracle.as.scheduler.RuntimeServiceException;
import oracle.as.scheduler.SchedulerException;
import oracle.as.scheduler.async.RemoteAsyncHelper;
 
@Stateless(name = "EssAsyncAnnotatedBean", mappedName = "ejb/essAsyncAnnBean")
public class EssAsyncAnnotatedBean implements RemoteExecutable {
    @Resource
    SessionContext sessionContext;
 
    public void execute(RequestExecutionContext requestExecutionContext,
                        RequestParameters requestParameters) throws 
    ExecutionErrorException, ExecutionWarningException,
    ExecutionPausedException,ExecutionCancelledException 
    {
        RemoteAsyncHelper asyncHelper = null;
 
        try {
            asyncHelper = new RemoteAsyncHelper(requestExecutionContext, requestParameters);
            
            //Initiate processing
            initiateProcessing(requestExecutionContext, requestParameters);
 
            //Get processed results
            Future<Result[]> results = getProcessedResults(requestExecutionContext, requestParameters);
 
            //do further processing
 
            //Finally, complete the request
            asyncHelper.onSuccess();
        } 
        catch (Exception e) 
        {
            try 
            {
                asyncHelper.onBizError(e.getMessage());
            } 
            catch (Exception f) 
            {
            }
        }
    }
 
    @Asynchronous
    public void initiateProcessing(RequestExecutionContext requestExecutionContext,
                                   RequestParameters requestParameters) 
    {
        //startProcessing
    }
 
    @Asynchronous
    public Future<Result[]> getProcessedResults(RequestExecutionContext requestExecutionContext,
                                                RequestParameters requestParameters) 
    {
        Result[] resultsArr = null;
        //do processing
        return new AsyncResult<Result[]>(resultsArr);
    }
 
}