Oracle JDeveloper 11gR2: Application Modules

Exclusive offer: get 50% off this eBook here
Oracle JDeveloper 11gR2 Cookbook

Oracle JDeveloper 11gR2 Cookbook — Save 50%

Over 85 simple but incredibly effective recipes for using Oracle JDeveloper 11gR2 to build ADF applications with this book and ebook

€29.99    €15.00
by Nick Haralabidis | January 2012 | Oracle

An application module in the ADF Business Components framework of JDeveloper, represents a basic transactional unit that implements specifc business use cases. It encompasses a data model comprising a hierarchy of view objects and optionally other application module instances, along with a number of custom methods that together implement a specifc business use case.

 

In this article, Nick Haralabidis, the author of Oracle JDeveloper 11gR2 Cookbook will cover:

 

  • Creating and using generic extension interfaces
  • Exposing a custom method as a web service
  • Accessing a service interface method from another application module
  • A passivation/activation framework for custom session-specifc data
  • Displaying application module pool statistics
  • Using a shared application module for static lookup data
  • Using a custom database transaction

(For more resources on JDeveloper, see here.)

Creating and using generic extension interfaces

In this recipe, we will go over how to expose any of that common functionality as a generic extension interface. By doing so, this generic interface becomes available to all derived business components, which in turn can be exposed to its own client interface and make it available to the ViewController layer through the bindings layer.

How to do it…

  1. Open the shared components workspace in JDeveloper
  2. Create an interface called ExtApplicationModule as follows:

    public interface ExtApplicationModule {
    // return some user authority level, based on
    // the user's name
    public int getUserAuthorityLevel();
    }

  3. Locate and open the custom application module framework extension class ExtApplicationModuleImpl. Modify it so that it implements the ExtApplicationModule interface.
  4. Then, add the following method to it:

    public int getUserAuthorityLevel() {
    // return some user authority level, based on the user's name
    return ("anonymous".equalsIgnoreCase(this.
    getUserPrincipalName()))?
    AUTHORITY_LEVEL_MINIMAL : AUTHORITY_LEVEL_NORMAL;
    }

  5. Rebuild the SharedComponents workspace and deploy it as an ADF Library JAR.
  6. Now, open the HRComponents workspace
  7. Locate and open the HrComponentsAppModule application module defnition.
  8. Go to the Java section and click on the Edit application module client interface button (the pen icon in the Client Interface section).
  9. On the Edit Client Interface dialog, shuttle the getUserAuthorityLevel() interface from the Available to the Selected list.

How it works…

In steps 1 and 2, we have opened the SharedComponents workspace and created an interface called HrComponentsAppModule. This interface contains a single method called getUserAuthorityLevel().

Then, we updated the application module framework extension class HrComponentsAppModuleImpl so that it implements the HrComponentsAppModule interface (step 3). We also implemented the method getUserAuthorityLevel() required by the interface (step 4). For the sake of this recipe, this method returns a user authority level based on the authenticated user's name. We retrieve the authenticated user's name by calling getUserPrincipal().getName() on the SecurityContext, which we retrieve from the current ADF context (ADFContext.getCurrent().getSecurityContext()). If security is not enabled for the ADF application, the user's name defaults to anonymous. In this example, we return AUTHORITY_LEVEL_MINIMAL for anonymous users, and for all others we return AUTHORITY_LEVEL_NORMAL. We rebuilt and redeployed the SharedComponents workspace in step 5.

In steps 6 through 9, we opened the HRComponents workspace and added the getUserAuthorityLevel() method to the HrComponentsAppModuleImpl client interface. By doing this, we exposed the getUserAuthorityLevel() generic extension interface to a derived application module, while keeping its implementation in the base framework extension class ExtApplicationModuleImpl.

There's more…

Note that the steps followed in this recipe to expose an application module framework extension class method to a derived class' client interface can be followed for other business components framework extension classes as well.

Exposing a custom method as a web service

Service-enabling an application module allows you, among others, to expose custom application module methods as web services. This is one way for service consumers to consume the service-enabled application module. The other possibilities are accessing the application module by another application module, and accessing it through a Service Component Architecture (SCA) composite. Service-enabling an application module allows access to the same application module both through web service clients and interactive web user interfaces. In this recipe, we will go over the steps involved in service-enabling an application module by exposing a custom application module method to its service interface.

Getting ready

The HRComponents workspace requires a database connection to the HR schema.

How to do it…

  1. Open the HRComponents project in JDeveloper.
  2. Double-click on the HRComponentsAppModule application module in the Application Navigator to open its defnition.
  3. Go to the Service Interface section and click on the Enable support for Service Interface button (the green plus sign icon in the Service Interface section). This will start the Create Service Interface wizard.
  4. In the Service Interface page, accept the defaults and click Next.
  5. In the Service Custom Methods page, locate the adjustCommission() method and shuttle it from the Available list to the Selected list. Click on Finish.
  6. Observe that the adjustCommission() method is shown in the Service Interface Custom Methods section of the application module's Service Interface. The service interface fles were generated in the serviceinterface package under the application module and are shown in the Application Navigator.
  7. Double-click on the weblogic-ejb-jar.xml fle under the META-INF package in the Application Navigator to open it.
  8. In the Beans section, select the com.packt.jdeveloper. cookbook.hr.components.model.application.common. HrComponentsAppModuleService Bean bean and click on the Performance tab. For the Transaction timeout feld, enter 120.

How it works…

In steps 1 through 6, we have exposed the adjustCommission() custom application module method to the application module's service interface. This is a custom method that adjusts all the Sales department employees' commissions by the percentage specifed. As a result of exposing the adjustCommission() method to the application module service interface, JDeveloper generates the following fles:

  • HrComponentsAppModuleService.java: Defnes the service interface
  • HrComponentsAppModuleServiceImpl.java: The service implementation class
  • HrComponentsAppModuleService.xsd: The service schema fle describing the input and output parameters of the service
  • HrComponentsAppModuleService.wsdl: The Web Service Defnition Language (WSDL) fle, describing the web service
  • ejb-jar.xml: The EJB deployment descriptor. It is located in the src/META-INF directory
  • weblogic-ejb-jar.xml: The WebLogic-specifc EJB deployment descriptor, located in the src/META-INF directory

In steps 7 and 8, we adjust the service Java Transaction API (JTA) transaction timeout to 120 seconds (the default is 30 seconds). This will avoid any exceptions related to transaction timeouts when invoking the service. This is an optional step added specifcally for this recipe, as the process of adjusting the commission for all sales employees might take longer than the default 30 seconds, causing the transaction to time out.

To test the service using the JDeveloper integrated WebLogic application server, right-click on the HrComponentsAppModuleServiceImpl.java service implementation fle in the Application Navigator and select Run or Debug from the context menu. This will build and deploy the HrComponentsAppModuleService web service into the integrated WebLogic server. Once the deployment process is completed successfully, you can click on the service URL in the Log window to test the service. This will open a test window in JDeveloper and also enable the HTTP Analyzer. Otherwise, copy the target service URL from the Log window and paste it into your browser's address feld. This will bring up the service's endpoint page.

On this page, select the adjustCommission method from the Operation drop down, specify the commissionPctAdjustment parameter amount and click on the Invoke button to execute the web service. Observe how the employees' commissions are adjusted in the EMPLOYEES table in the HR schema.

There's more…

For more information on service-enabling application modules consult chapter Integrating Service-Enabled Application Modules in the Fusion Developer's Guide for Oracle Application Development Framework which can be found at http://docs.oracle.com/cd/ E24382_01/web.1112/e16182/toc.htm.

Accessing a service interface method from another application module

In the recipe Exposing a custom method as a web service in this article, we went through the steps required to service-enable an application module and expose a custom application module method as a web service. We will continue in this recipe by explaining how to invoke the custom application module method, exposed as a web service, from another application module.

Getting ready

This recipe will call the adjustCommission() custom application module method that was exposed as a web service in the Exposing a custom method as a web service recipe in this article. It requires that the web service is deployed in WebLogic and that it is accessible.

The recipe also requires that both the SharedComponents workspace and the HRComponents workspace are deployed as ADF Library JARs and that are added to the workspace used by this specifc recipe. Additionally, a database connection to the HR schema is required.

How to do it…

  1. Ensure that you have built and deployed both the SharedComponents and HRComponents workspaces as ADF Library JARs.
  2. Create a File System connection in the Resource Palette to the directory path where the SharedComponents.jar and HRComponents.jar ADF Library JARs are located.
  3. Create a new Fusion Web Application (ADF) called HRComponentsCaller using the Create Fusion Web Application (ADF) wizard.
  4. Create a new application module called HRComponentsCallerAppModule using the Create Application Module wizard. In the Java page, check on the Generate Application Module Class checkbox to generate a custom application module implementation class. JDeveloper will ask you for a database connection during this step, so make sure that a new database connection to the HR schema is created.
  5. Expand the File System | ReUsableJARs connection in the Resource Palette and add both the SharedComponents and HRComponents libraries to the project. You do this by right-clicking on the jar fle and selecting Add to Project… from the context menu.
  6. Bring up the business components Project Properties dialog and go to the Libraries and Classpath section. Click on the Add Library… button and add the BC4J Service Client and JAX-WS Client extensions.
  7. Double-click on the HRComponentsCallerAppModuleImpl.java custom application module implementation fle in the Application Navigator to open it in the Java editor.
  8. Add the following method to it:

    public void adjustCommission(
    BigDecimal commissionPctAdjustment) {
    // get the service proxy
    HrComponentsAppModuleService service =
    (HrComponentsAppModuleService)ServiceFactory
    .getServiceProxy(
    HrComponentsAppModuleService.NAME);
    // call the adjustCommission() service
    service.adjustCommission(commissionPctAdjustment);
    }

  9. Expose adjustCommission() to the HRComponentsCallerAppModule client interface.
  10. Finally, in order to be able to test the HRComponentsCallerAppModule application module with the ADF Model Tester, locate the connections.xml fle in the Application Resources section of the Application Navigator under the Descriptors | ADF META-INF node, and add the following confguration to it:

    <Reference
    name="{/com/packt/jdeveloper/cookbook/hr/components/model/
    application/common/}HrComponentsAppModuleService"
    className="oracle.jbo.client.svc.Service" xmlns="">
    <Factory
    className="oracle.jbo.client.svc.ServiceFactory"/>
    <RefAddresses>
    <StringRefAddr addrType="serviceInterfaceName">
    <Contents>com.packt.jdeveloper.cookbook.hr.components.model.
    application.common.serviceinterface.HrComponentsAppModuleService
    </Contents>
    </StringRefAddr>
    <StringRefAddr addrType="serviceEndpointProvider">
    <Contents>ADFBC</Contents>
    </StringRefAddr>
    <StringRefAddr addrType="jndiName">
    <Contents>HrComponentsAppModuleServiceBean#com.packt.jdeveloper.
    cookbook.hr.components.model.application.common.
    serviceinterface.HrComponentsAppModuleService</Contents>
    </StringRefAddr>
    <StringRefAddr addrType="serviceSchemaName">
    <Contents>HrComponentsAppModuleService.xsd</Contents>
    </StringRefAddr>
    <StringRefAddr addrType="serviceSchemaLocation">
    <Contents>com/packt/jdeveloper/cookbook/hr/components/model/
    application/common/serviceinterface/</Contents>
    </StringRefAddr>
    <StringRefAddr addrType="jndiFactoryInitial">
    <Contents>weblogic.jndi.WLInitialContextFactory</Contents>
    </StringRefAddr>
    <StringRefAddr addrType="jndiProviderURL">
    <Contents>t3://localhost:7101</Contents>
    </StringRefAddr>
    </RefAddresses>
    </Reference>

How it works…

In steps 1 and 2, we have made sure that both the SharedComponents and HRComponents ADF Library JARs are deployed and that a fle system connection was created, in order that both of these libraries get added to a newly created project (in step 5). Then, in steps 3 and 4, we create a new Fusion web application based on ADF, and an application module called HRComponentsCallerAppModule. It is from this application module that we intend to call the adjustCommission() custom application module method, exposed as a web service by the HrComponentsAppModule service-enabled application module in the HRComponents library JAR. For this reason, in step 4, we have generated a custom application module implementation class. We proceed by adding the necessary libraries to the new project in steps 5 and 6. Specifcally, the following libraries were added: SharedComponents.jar, HRComponents.jar, BC4J Service Client, and JAX-WS Client.

In steps 7 through 9, we create a custom application module method called adjustCommission(), in which we write the necessary glue code to call our web service. In it, we frst retrieve the web service proxy, as a HrComponentsAppModuleService interface, by calling ServiceFactory.getServiceProxy() and specifying the name of the web service, which is indicated by the constant HrComponentsAppModuleService.NAME in the service interface. Then we call the web service through the retrieved interface.

In the last step, we have provided the necessary confguration in the connections.xml so that we will be able to call the web service from an RMI client (the ADF Model Tester). This fle is used by the web service client to locate the web service. For the most part, the Reference information that was added to it was generated automatically by JDeveloper in the Exposing a custom method as a Web service recipe, so it was copied from there. The extra confguration information that had to be added is the necessary JNDI context properties jndiFactoryInitial and jndiProviderURL that are needed to resolve the web service on the deployed server. You should change these appropriately for your deployment. Note that these parameters are the same as the initial context parameters used to lookup the service when running in a managed environment.

To test calling the web service, ensure that you have frst deployed it and that it is running. You can then use the ADF Model Tester, select the adjustCommission method and execute it.

There's more…

For additional information related to such topics as securing the ADF web service, enabling support for binary attachments, deploying to WebLogic, and more, refer to the Integrating Service-Enabled Application Modules section in the Fusion Developer's Guide for Oracle Application Development Framework which can be found at http://docs.oracle.com/ cd/E24382_01/web.1112/e16182/toc.htm.

Oracle JDeveloper 11gR2 Cookbook Over 85 simple but incredibly effective recipes for using Oracle JDeveloper 11gR2 to build ADF applications with this book and ebook
Published: January 2012
eBook Price: €29.99
Book Price: €49.99
See more
Select your format and quantity:

(For more resources on JDeveloper, see here.)

A passivation/activation framework for custom session-specifc data

In order to improve performance and preserve a stateful notion while utilizing a stateless protocol (that is, HTTP) the ADF Business Components framework implements the concept of application module pooling. This is a technique of maintaining a limited number of application modules, the exact number specifed by confguration, in a pool, which are preserved across multiple user requests for the same HTTP session. If an application module instance for a session already exists in the application module pool, it gets reused. When all available application modules in the pool have been associated with specifc sessions, an application module already linked with a particular session must be freed. This requires that the data associated with the application module is saved.

The process of saving the information associated with the specifc application module is called passivation. The information is stored in a passivation store, usually a database, in XML format. The opposite process of restoring the state of the application module from the passivation store is called activation. Custom data is associated with specifc application modules, and therefore with specifc user sessions, by using a Hashtable obtained from an oracle.jbo.Session object. The Hashtable is obtained by calling getSession(). getUserData() from the application module implementation class.

If you are using such custom data as part of some algorithm in your application and you expect the custom data to persist from one user request to another, passivation (and subsequent activation) support for these custom data must be implemented programmatically. You can add custom passivation and activation logic to your application module implementation class by overriding the ApplicationModuleImpl methods passivateState() and activateState() respectively. The passivateState() method creates the necessary XML elements for the application module's custom data that must be passivated. Conversely, the activateState() method detects the specifc XML elements that identify the custom data in the passivated XML document and restores them back into the session custom data.

This recipe will show you how to do this, and at the same time build a mini framework to avoid duplication of the basic passivation/activation code that you must write for all the application modules in your project.

This recipe is also using the HRComponents workspace. The HRComponents workspace requires a database connection to the HR schema.

How to do it…

  1. Open the SharedComponents workspace in JDeveloper and load the ExtApplicationModuleImpl application module framework extension class in the Java editor.
  2. Add the following methods to the ExtApplicationModuleImpl application module framework extension class:

    protected String[] onStartPassivation() {
    // default implementation: no passivation ids
    // are defined
    return new String[] { };
    }
    protected String onPassivate(String passivationId) {
    // default implementation: passivates nothing
    return null;
    }
    protected void onEndPassivation() {
    // default implementation: does nothing
    }
    protected String[] onStartActivation() {
    // default implementation: no activation ids
    // are defined
    return new String[] { };
    }
    protected void onActivate(String activationId,
    String activationData) {
    // default implementation: activates nothing
    }
    protected void onEndActivation() {
    // default implementation: does nothing
    }

  3. Override the void passivateState(Document, Element) method. Add the following code after the call to super.passivateState():

    // begin custom data passivation: returns a
    // list of the custom data passivation identifiers
    String[] passivationIds = onStartPassivation();
    // process all passivation identifiers
    for (String passivationId : passivationIds) {
    // check for valid identifier
    if (passivationId != null &&
    passivationId.trim().length() > 0) {
    // passivate custom data: returns
    // the passivation data
    String passivationValue =
    onPassivate(passivationId);
    // check for valid passivation data
    if (passivationValue != null &&
    passivationValue.length() > 0) {
    // create a new text node in the
    // passivation XML
    Node node =
    document.createElement(passivationId);
    Node cNode =
    document.createTextNode(passivationValue);
    node.appendChild(cNode);
    // add the passivation node to the
    // parent element
    element.appendChild(node);
    }
    }
    }
    // inform end of custom data passivation
    onEndPassivation();

  4. Override the activateState(Element element) method. Add the following code after the call to super.activateState():

    // check for element to activate
    if (element != null) {
    // begin custom data activation: returns a
    // list of the custom data activation identifiers
    String[] activationIds = onStartActivation();
    // process all activation identifiers
    for (String activationId : activationIds) {
    // check for valid identifier
    if (activationId != null &&
    activationId.trim().length() > 0) {
    // get nodes from XML for the specific
    // activation identifier
    NodeList nl =
    element.getElementsByTagName(activationId);
    // if it was found in the activation data
    if (nl != null) {
    // activate each node
    for (int n = 0, length =
    nl.getLength(); n < length; n++) {
    Node child =
    nl.item(n).getFirstChild();
    if (child != null) {
    // do the actual custom data
    // activation
    onActivate(activationId,
    child.getNodeValue().toString());
    break;
    }
    }
    }
    }
    }
    // inform end of custom data activation
    onEndActivation();
    }

  5. Rebuild and redeploy the SharedComponents ADF Library JAR.
  6. Open the HRComponents workspace and load the HrComponentsAppModuleImpl and HrComponentsAppModule application module custom implementation classes into the Java editor.
  7. Add the following getActivationPassivationIds() helper method. Also, ensure that you define a constant called CUSTOM_DATA_PASSIVATION_ID indicating the custom data passivation identifier.


    private static final String CUSTOM_DATA_PASSIVATION_ID =
    "customDataPassivationId";
    private String[] getActivationPassivationIds() {
    // return the passivation/activation identifiers
    return new String[] { CUSTOM_DATA_PASSIVATION_ID };
    }

  8. Override the onStartPassivation(), onPassivate(), onStartActivation(), and onActivate() methods. Provide the following implementation for them:
  9. protected String[] onStartPassivation() {
    // return the passivation identifiers
    return getActivationPassivationIds();
    }
    protected String onPassivate(String passivationId) {
    String passivationData = null;
    // passivate this application module's
    // custom data only
    if (CUSTOM_DATA_PASSIVATION_ID.equals(
    passivationId)) {
    // return the custom data from the Application
    // Module session user data
    passivationData = (String)getSession()
    .getUserData().get(CUSTOM_DATA_PASSIVATION_ID);
    }
    return passivationData;
    }
    protected String[] onStartActivation() {
    // return the activation identifiers
    return getActivationPassivationIds();
    }
    protected void onActivate(String activationId,
    String activationData) {
    // activate this application module's custom data only
    if (CUSTOM_DATA_PASSIVATION_ID.equals(activationId)) {
    // add custom data to the Application
    // Module's session
    getSession().getUserData().put(
    CUSTOM_DATA_PASSIVATION_ID, activationData);
    }
    }

  10. Finally, for testing purposes, override the prepareSession() method and add the following code after the call to super.prepareSession():

    // add some custom data to the Application
    // Module session
    getSession().getUserData()
    .put(CUSTOM_DATA_PASSIVATION_ID,
    "Some custom data");

How it works…

In the first two steps, we have laid out a basic passivation/activation framework by adding a number of methods to the ExtApplicationModuleImpl application module framework extension class dealing specifically with this process. Specifically, these methods are:

  • onStartPassivation(): The framework calls this method to indicate that a passivation process is about to start. Derived application modules that need to passivate custom data will override this method and return a java.lang.String array of passivation identifiers, indicating custom data that needs to be passivated.
  • onPassivate(): The framework calls this method to indicate that some specific custom data, identified by the passivationId parameter, needs to be passivated. Derived application modules will override this method to passivate the specific custom data. It returns the passivated data as a java.lang.String.
  • onEndPassivation(): This method is called by the framework to indicate that the passivation process is complete. Derived application modules could override this method to perform post-passivation actions.
  • onStartActivation(): This method is called by the framework to indicate that an activation process is about to begin. Derived application modules in need of activating custom data, should override this method and return a list of activation identifiers.
  • onActivate(): This method is called by the framework when some custom data— that is, the parameter activationData—needs to be activated. The custom data is identified by a unique identifier indicated by the parameter activationId. Derived application modules should override this method and restore the custom data being activated into the application module's user data Hashtable.
  • onEndActivation(): This method indicates the end of the activation process. It can be overriden by derived application modules to do some post-activation actions.

These methods do nothing at the base class level. It is when they are overridden by derived application modules (see step 8) that they come to life.

In step 3, we have overridden the ADF Business Components framework method passivateState() and hooked up our own passivation/activation framework to it. ADF calls this method to indicate that a passivation is taking place. In it, after calling super. passivateState() to allow for the ADF processing, we first call onStartPassivation(). If a derived application module has overridden this method, it should return a list of passivation identifiers. These identifiers should uniquely identify the application module custom data that needs to be passivated at the application module level. We then iterate over the passivation identifiers, calling onPassivate() each time to retrieve the passivation data. We create a new XML node for the passivation identifier, we add the passivation data to it and append it to the parent XML node that is passed as a parameter by the ADF framework (the element parameter) to passivateState(). When all passivation identifiers have been processed, onEndPassivation() is called.

Step 4 is somewhat similar and does the activation. In this case, we have overridden the ADF activateState() method, which is called by the framework to indicate that the activation process is taking place. In it, we first call super.activateState() to allow for framework processing and then call onStartActivation() to get a list of the activation identifiers. We iterate over the activation identifiers, looking for each identifier in the activated XML data for the application module element. This is done by calling element. getElementsByTagName(). This method could possibly return multiple nodes, so for each we call onActivate() to activate the specific custom data. When we call onActivate(), we pass the activation identifier and the activation data to it as arguments. It is then the responsibility of the derived application module to handle the specifics of the activation. Finally, when all activation identifiers have been processed, we call onEndActivation() to indicate that the activation process has ended.

After we have added these changes to the ExtApplicationModuleImpl application module framework extension class, we make sure that the SharedComponents ADF Library JAR was redeployed (in step 5).

In steps 6 through 8, we have added passivation/activation support for custom data to the HrComponentsAppModule application module in the HRComponents workspace. This is done by overriding the onStartPassivation(), onPassivate(), onStartActivation(), and onActivate() methods (in step 8). The list of passivation and activation identifiers comes from the getActivationPassivationIds() method that we added in step 7. For this recipe, only a single custom data, identified by the constant CUSTOM_DATA_PASSIVATION_ID, is passivated. Custom data is saved at the user data Hashtable in the oracle.jbo.Session associated with the specific application module. It is retrieved by calling getSession().getUserData().get(CUSTOM_DATA_ PASSIVATION_ID) in the onPassivate() method. Similarly, it is set in onActivate() by calling getSession().getUserData().put(CUSTOM_DATA_PASSIVATION_ID and activationData().

In this case, the activation data is passed as an argument (the activationData parameter) to the onActivate() by the activateState() implemented in application module framework extension class, as in step 4.

Finally, note the code in step 9. In the overridden prepareSession(), we have initialized the custom data by calling getSession().getUserData().put(CUSTOM_DATA_ PASSIVATION_ID, "Some custom data").

20 To test the custom data passivation/activation framework, run the application module with the ADF Model Tester. The ADF Model Tester provides support for passivation and activation via the Save Transaction State and Restore Transaction State menu items under the File menu. Observe the generated passivation XML data in the JDeveloper Log window when File | Save Transaction State is chosen. In particular, observe that the <'customDataPassivationId>Some custom data<'/customDataPassivationId> node is added to the <'AM> node of the passivated XML document. This is the session data added in step 9 for testing purposes to demonstrate this passivation/activation framework.

There's more…

Note that the activateState() method is called by the ADF Business Components framework after the view objects instances associated with the application module have been activated by the framework. If you need to activate custom data that would be subsequently accessed by your view objects, then you will need to enhance the custom data passivation/ activation framework by overriding prepareForActivation() and provide the activation logic there instead.

Also, note that the ADF Business Components framework provides similar passivateState() and activateState() methods at the view object level for passivating and activating view object custom data. In this case, custom data is stored in the user data Hashtable of the oracle.jbo.Session associated with the specific application module that contains the particular view object in its data model.

Finally, observe the following points:

  • This framework does not cover the passivation/activation of view object custom data. If needed, you will need to expand this framework to support this extra requirement.
  • It is important that during the development process you test your application modules for being activation-safe. This is done by disabling the application module pooling in the application module configuration. For more information on this topic, consult the Testing to Ensure Your Application Module is Activation-Safe section in the Fusion Developer's Guide for Oracle Application Development Framework.
Oracle JDeveloper 11gR2 Cookbook Over 85 simple but incredibly effective recipes for using Oracle JDeveloper 11gR2 to build ADF applications with this book and ebook
Published: January 2012
eBook Price: €29.99
Book Price: €49.99
See more
Select your format and quantity:

(For more resources on JDeveloper, see here.)

Displaying application module pool statistics

In the A passivation/activation framework for custom session-specific data recipe in this article, we touched upon how application module pools are used by the ADF Business Components framework. In this recipe, we will introduce the oracle.jbo.common. ampool.PoolMgr application module pool manager and oracle.jbo.common.ampool. ApplicationPool application module pool classes, and explore how they can be utilized to collect statistical pool information. This may come in handy when debugging.

The use case that will be implemented by the recipe is to collect application module statistics and make them available in a generic view object, that can then be used by all application modules to gather and present statistical information to the frontend user interface.

Getting ready

You will need to have access to the SharedComponents workspace. Additional functionality will be added to the ExtApplicationModuleImpl custom framework class.

This recipe also uses the HRComponents workspace. The HRComponents workspace requires a database connection to the HR schema.

How to do it…

  1. Open the SharedComponents workspace in JDeveloper.
  2. Create a new view object called ApplicationModulePoolStatistics using the following SQL query as its data source:

    SELECT NULL AS POOL_NAME, NULL AS APPLICATION_MODULE_CLASS, NULL
    AS AVAILABLE_INSTANCE_COUNT, NULL AS INIT_POOL_SIZE, NULL AS
    INSTANCE_COUNT, NULL AS MAX_POOL_SIZE, NULL AS
    NUM_OF_STATE_ACTIVATIONS, NULL AS NUM_OF_STATE_PASSIVATIONS,
    NULL AS NUM_OF_INSTANCES_REUSED, NULL AS REF_INSTANCES_RECYCLED,
    NULL AS UNREF_INSTANCES_RECYCLED, NULL AS
    REFERENCED_APPLICATION_MODULES, NULL AS NUM_OF_SESSIONS, NULL AS
    AVG_NUM_OF_SESSIONS_REF_STATE FROM DUAL

  3. With the exception of the PoolName and ApplicationModuleClass attributes, which should be String data types, all other attributes should be Number types.
  4. Designate the PoolName and ApplicationModuleClass attributes as key attributes.
  5. In the Java section, create a custom view row class and ensure that the Include accessors checkbox is also checked.
  6. Open the ExtApplicationModuleImpl application module custom framework class in the Java editor and add the following two methods to it:

    public ExtViewObjectImpl
    getApplicationModulePoolStatistics() {
    return (ExtViewObjectImpl)findViewObject(
    "ApplicationModulePoolStatistics");
    }
    public void getAMPoolStatistics() {
    // get the pool manager
    PoolMgr poolMgr = PoolMgr.getInstance();
    // get the pools managed
    Enumeration keys = poolMgr.getResourcePoolKeys();
    // iterate over pools
    while (keys != null && keys.hasMoreElements()) {
    // get pool name
    String poolname = (String)keys.nextElement();
    // get the pool
    ApplicationPool pool =
    (ApplicationPool)poolMgr.getResourcePool(poolname);
    // get the pool statistics
    Statistics statistics = pool.getStatistics();
    // get and populate pool statistics view object
    ExtViewObjectImpl amPoolStatistics =
    getApplicationModulePoolStatistics();
    if (amPoolStatistics != null) {
    // empty the statistics
    amPoolStatistics.executeEmptyRowSet();
    // create and fill a new statistics row
    ApplicationModulePoolStatisticsRowImpl poolInfo
    (ApplicationModulePoolStatisticsRowImpl)
    amPoolStatistics.createRow();
    poolInfo.setPoolName(pool.getName());
    poolInfo.setApplicationModuleClass(
    pool.getApplicationModuleClass());
    poolInfo.setAvailableInstanceCount(new
    Number(pool.getAvailableInstanceCount()));
    poolInfo.setInitPoolSize(new
    Number(pool.getInitPoolSize()));
    poolInfo.setInstanceCount(new
    Number(pool.getInstanceCount()));
    poolInfo.setMaxPoolSize(new
    Number(pool.getMaxPoolSize()));
    poolInfo.setNumOfStateActivations(new
    Number(statistics.mNumOfStateActivations));
    poolInfo.setNumOfStatePassivations(new
    Number(statistics.mNumOfStatePassivations));
    poolInfo.setNumOfInstancesReused(new
    Number(statistics.mNumOfInstancesReused));
    poolInfo.setRefInstancesRecycled(new
    Number(statistics.mNumOfReferencedInstancesRecycled));
    poolInfo.setUnrefInstancesRecycled(new
    Number(statistics.mNumOfUnreferencedInstancesRecycled));
    poolInfo.setReferencedApplicationModules(new
    Number(statistics.mReferencedApplicationModules));
    poolInfo.setNumOfSessions(new
    Number(statistics.mNumOfSessions));
    poolInfo.setAvgNumOfSessionsRefState(new
    Number(statistics.mAvgNumOfSessionsReferencingState));
    // add the statistics
    amPoolStatistics.insertRow(poolInfo);
    }
    }
    }

  7. Open the ExtApplicationModule application module custom framework interface and add the following code to it:

    public void getAMPoolStatistics();

  8. Redeploy the SharedComponents ADF Library JAR.
  9. Now, open the HRComponents workspace and in the Resource Palette create a file system connection for the ReUsableJARs directory where the SharedComponents.jar is deployed. Add the SharedComponents.jar to the HRComponentsBC business components project.
  10. Double-click on the HrComponentsAppModule application module in the Application Navigator to open its definition.
  11. Go to the Data Model section and locate the ApplicationModulePoolStatistics view object in the Available View Objects list. Shuttle it to the Data Model list.
  12. Finally, go to the Java section, locate and add the getAMPoolStatistics() method to the HRComponents application module client interface.

How it works…

In steps 1 through 5, we created ApplicationModulePoolStatistics, a read-only view object, which we used to collect the application module pool statistics. By adding this view object to the SharedComponents workspace, it becomes available to all other projects in all workspaces throughout the ADF application that import the SharedComponents ADF Library JAR. In step 6, we have added the necessary functionality to collect the application module statistics and populate the ApplicationModulePoolStatistics view object. This is done in the getAMPoolStatistics() method. This gets an instance of the oracle. jbo.common.ampool.PoolMgr application module pool manager, via the call to the static getInstance(), along with an Enumeration of the application module pools managed by the pool manager by calling getResourcePoolKeys() on the pool manager. We iterate over all the pools managed by the manager and retrieve each pool using getResourcePool() on the pool manager. Then for each pool we call getStatistics() to get the pool statistics. We create a new ApplicationModulePoolStatistics view object row and populate it with the statistics information.

In step 7, we have added the getAMPoolStatistics() to the ExtApplicationModule application module framework extension interface, so that it becomes available to all application modules throughout the application.

In steps 8 and 9, we redeploy the SharedComponents library and created a file system connection in the Resource Palette. We use this file system connection to add the shared components SharedComponents.jar ADF Library JAR to the HRComponents business components project.

In steps 10 and 11, we add the ApplicationModulePoolStatistics view object to the HrComponentsAppModule application module data model. Notice how the ApplicationModulePoolStatistics view object is listed in the available view objects list, although it is implemented in the SharedComponents workspace.

Finally, in step 12, we add getAMPoolStatistics() to the HrComponentsAppModule application module client interface. By doing so, we will be able to call it using the ADF Model Tester.

To test the recipe, run the HrComponentsAppModule application module with the ADF Model Tester. In the ADF Model Tester double-click on the HrComponentsAppModule application module to open it, select the getAMPoolStatistics method from the Method combo, and click on the Execute button. Then open the ApplicationModulePoolStatistics view object to see the results.

Now you can bind both the getAMPoolStatistics method and the ApplicationModulePoolStatistics view object to any of your ViewController projects in your ADF application, and present a visual of this statistical information for debugging purposes.

There's more…

Note that the oracle.jbo.common.ampool.ApplicationPool interface provides a method called dumpPoolStatistics() to dump all pool statistics to a PrintWriter object. You can use this method to quickly print the application module pool statistics to the JDeveloper Log window, as shown in following code:

PrintWriter out = new PrintWriter(System.out, true);
pool.dumpPoolStatistics(new PrintWriter(out));
out.flush();

Using a shared application module for static lookup data

Shared application modules allow you to share static read-only data models across multiple user sessions. They are the ideal place to collect all the static read-only view accessors used throughout your ADF application for validation purposes or as data sources for your list of values (LOVs). This is because a single shared application module is constructed and used throughout the ADF application for all user sessions, thus minimizing the system resources used by it. In this case, a single database connection is used. In addition, by collecting all of your static read-only view objects in a shared application module, you avoid possible duplication and redefinition of read-only view objects throughout your ADF application.

Internally, the ADF Business Components framework manages a pool of query collections for each view object as it is accessed by multiple sessions by utilizing a query collection pool, something comparable to application module pools used for session-specific application modules. The framework offers a number of configuration options to allow for better management of this pool. Moreover, as multiple threads will access the data, the framework partitions the iterator space by supporting multiple iterators for the same rowset, preventing race conditions among iterators on different sessions.

In this recipe, we will define a shared application module called HrSharedAppModule, and we will migrate to it all of the static read-only view objects defined for the HrComponents project. Furthermore, we will update all the view objects that currently reference these static read-only view objects, so that they are now referencing the view objects in the shared application module.

Getting ready

This recipe was developed using the HRComponents workspace. The HRComponents workspace requires a database connection to the HR schema.

How to do it…

  1. Right-click on the com.packt.jdeveloper.cookbook.hr.components.model. application package on the Application Navigator and select New Application Module….
  2. Follow the steps in the Create Application Module wizard to create an application module called HrSharedComponentsAppModule.
  3. In the Data Model page, expand the com.packt.jdeveloper.cookbook. hr.components.model.view.lov package and shuttle all of the view objects currently under this package from the Available View Objects list to the Data Model list. Click on Finish when done.
  4. Now, double-click on the HRComponentsBC in the Application Navigator to bring up the Project Properties dialog.
  5. Locate the Application Module Instances page by selecting ADF Business Components | Application Module Instances in the selection tree.
  6. Click on the Application tab and shuttle the HrSharedComponentsAppModule application module from the Available Application Modules list to the Application Module Instances list. Click OK to dismiss the Project Properties dialog.
  7. For each view object that was added to the HrSharedComponentsAppModule shared application module, locate (through Find Usages) where it is used as a view accessor, and change its usage so that it is referenced from inside the HrSharedComponentsAppModule shared application module. The following screenshot shows the view accessors that were added to the Employees view object.
  8. Also for each view accessor used as a data source for an LOV, ensure that you are now using the view accessor included in HrSharedComponentsAppModule.

How it works...

In steps 1 through 6, we have defined a new application module called HrSharedComponentsAppModule and added all static read-only view objects developed so far—throughout the HRComponents business components project—in its data model. We have indicated that HrSharedComponentsAppModule will be a shared application module through the Application Module Instances page in the Project Properties, when we indicate that HrSharedComponentsAppModule will be an instance at application-level rather than an instance at session-level (in steps 4 through 6). By defining an application module at application-level, we allow all user sessions to access the same view instances contained in the application module data model.

In steps 7 and 8, we have identified all read-only view objects used as view accessors throughout the HRComponents business components project and updated each one at a time, so that the view object instance residing within the shared HrSharedComponentsAppModule application module is used. We have also ensured that for each LOV, we redefined its data source by using the updated view accessor.

There's more...

Ideally, the shared application module should contain a static read-only data model. If you expect that the data returned by any of the view objects might be updated, ensure that it will always return the latest data from the database by setting the view object Auto Refresh property to true in the Tuning section of the Property Inspector. This property is accessible while in the General section of the view object definition.

The auto-refresh feature relies on the database change notification feature, so ensure that the data source database user has database notification privileges. This can be achieved by issuing the following grant command for the database connection user:

grant change notification to <ds_user_name>

For more information on shared application modules, consult the Sharing Application Module View Instances chapter in the Fusion Developer's Guide for Oracle Application Development Framework.

Using a custom database transaction

In this recipe, we will cover how to use these classes, so that we can implement our own custom transaction implementation. The use case for this recipe will be to provide logging support for all transaction commit and rollback operations.

Getting ready

You will need to have access to the SharedComponents workspace. Additional functionality will be added to the ExtDatabaseTransactionFactory and ExtDBTransactionImpl2 custom framework classes.

This recipe also uses the HRComponents workspace. The HRComponents workspace requires a database connection to the HR schema.

How to do it...

  1. Open the SharedComponents workspace and open the ExtDatabaseTransactionFactory.java file in the Java editor.
  2. Override the DatabaseTransactionFactory create() method and replace the return super.create() method with the following code:

    // return custom transaction framework
    // extension implementation
    return new ExtDBTransactionImpl2();

  3. Load the ExtDBTransactionImpl2.java file in the Java editor, add an ADFLogger to it and override the commit() and rollback() DBTransactionImpl2 methods. The code should look similar to the following:

    // create an ADFLogger
    private static final ADFLogger LOGGER =
    ADFLogger.createADFLogger(ExtDBTransactionImpl2.class);
    public void commit() {
    // log a trace
    LOGGER.info("Commit was called on the transaction");
    super.commit();
    }
    public void rollback() {
    // log a trace
    LOGGER.info("Rollback was called on the transaction");
    super.rollback();
    }

  4. Rebuild and redeploy the SharedComponents workspace into an ADF Library JAR.
  5. Open the HRComponents workspace and open the HrComponentsAppModule application module definition by double-clicking on it in the Application Navigator.
  6. Go to the Configurations section.
  7. Select the HrComponentsAppModuleLocal configuration and click the Edit selected configuration object button (the pen icon).
  8. In the Edit Configuration dialog, click on the Properties tab and locate the TransactionFactory property. For the property value, enter the custom transaction framework extension class com.packt.jdeveloper.cookbook.shared. bc.extensions.ExtDatabaseTransactionFactory.

How it works...

In steps 1 and 2, we have overridden the DatabaseTransactionFactory create() method for the custom transaction factory framework class ExtDatabaseTransactionFactory. Now it will return our custom transaction implementation class ExtDBTransactionImpl2. This informs the ADF Business Components framework that a custom oracle.jbo. server.DBTransaction implementation will be used. Then, in step 3, we provide custom implementations for our ExtDBTransactionImpl2 transaction commit and rollback operations. In this case, we have provided a global transaction logging facility for all commit and roll back operations throughout the ADF application for application modules utilizing our custom DBTransaction implementation. We then rebuild and redeploy the shared components workspace (step 4).

In steps 5 through 8, we have explicitly indicated in the HrComponentsAppModule local configuration, the one used to configure session-specific application modules, that a custom transaction factory will be used. We did this by setting the TransactionFactory configuration property to our custom transaction factory implementation class com.packt.jdeveloper.cookbook.shared.bc.extensions. ExtDatabaseTransactionFactory.

There's more...

In order to change application module configuration parameters for all application modules throughout your ADF application, adopt the practice of using Java systemdefined properties via the -D switch at JVM startup. In this case, ensure that no specific configuration parameters are defined for individual application modules, unless needed, as they would override the values specified globally with the -D Java switch. You can determine the specific parameter names that you must specify with the D switch, from the Property field in the Edit Configuration dialog. For example, for this recipe you will specify DTransactionFactory="com.packt.jdeveloper.cookbook.shared. bc.extensions.ExtDatabaseTransactionFactory" at JVM startup, to indicate that the custom transaction factory will be used. For WebLogic, these startup parameters can be specified via the JAVA_OPTIONS environment variable or in any of the WebLogic startup scripts (setDomainEnv.*, startWebLogic.*, startManagedWebLogic.*). These scripts can be found in the bin directory under the WebLogic domain directory. Furthermore, the WebLogic server Java startup parameters can be specified using the administrator console in the server Configuration | Server Start tab.

Summary

In this article, we seen a number of recipes related to application modules. We learned how to create and user generic extension interfaces, expose a custom application module method as a web service, and access a service interface from another application module. Additional recipes cover topics such as a passivation/activation framework, using shared application modules for static lookup data and custom database transactions.


Further resources on this subject:


About the Author :


Nick Haralabidis

Nick Haralabidis has over 20 years experience in the Information Technology industry, and a multifaceted career in such positions as Senior IT Consultant, Senior Software Engineer and Project Manager for a number of U.S. and Greek corporations (Compuware, Chemical Abstracts Service, NewsBank, CheckFree, Intrasoft International, Unisystems, MedNet International and others). His many years of experience have exposed him to a wide range of technologies ranging from Java, J2EE, C++, C, and Tuxedo, to a number of database technologies.

For the last four years Nick has been actively involved in large implementations of next generation enterprise applications utilizing Oracle’s JDeveloper, Application Development Framework (ADF) and SOA technologies.

He holds a B.S. in Computer Engineering and an M.S. in Computer Science from the University of Bridgeport.

When he is not pursuing ADF professionally, he writes on his blogs JDeveloper Frequently Asked Questions (http://jdeveloperfaq.blogspot.com) and ADF Code Bits (http://adfcodebits.blogspot.com). He is active in the Oracle Technology Network (OTN) JDeveloper and ADF forum where he both learns from and helps other forum users.

Books From Packt


Oracle ADF Enterprise Application Development—Made Simple
Oracle ADF Enterprise Application Development—Made Simple

EJB 3.0 Database Persistence with Oracle
EJB 3.0 Database Persistence with Oracle

WS-BPEL 2.0 for SOA Composite Applications with Oracle SOA Suite 11g
WS-BPEL 2.0 for SOA Composite Applications with Oracle SOA Suite 11g

Web 2.0 Solutions with Oracle WebCenter 11g
Web 2.0 Solutions with Oracle WebCenter 11g

Processing XML documents with Oracle JDeveloper 11g
Processing XML documents with Oracle JDeveloper 11g

BPEL PM and OSB operational management with Oracle Enterprise Manager 10g Grid Control
BPEL PM and OSB operational management with Oracle Enterprise Manager 10g Grid Control

Middleware Management with Oracle Enterprise Manager Grid Control 10g R5
Middleware Management with Oracle Enterprise Manager Grid Control 10g R5

Oracle Weblogic Server 11gR1 PS2: Administration Essentials
Oracle Weblogic Server 11gR1 PS2: Administration Essentials


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software