JDev 12c: Debug Application Module Tester (BC4JTester) Problems

When you develop ADF Web Application you often use the ADF ApplicationModule Tester (BC4J Tester) to quickly test your business components data model and your self-written code in any EntityObject, ViewObject or ApplicationModule. For more information about how to do this look at JDeveloper & ADF: Use the Application Module Tester (BC4J Tester) to Test all your BusinessLogic.

Users who use one of the latest JDeveloper versions 12.2.1.1.0 and newer may have noticed, that the BC4J Tester application starts without an error, but doesn’t show the dialog. I run into this a couple of times lately and decided to dig into this problem. On the Oracle Development Spaces, I saw some threads about this too.

The reason for this behavior is that any EO, VO or other methods in the application module have an error, which can’t be found during compile time.

Use case

To show the effect, we start with a simple Workspace and a model project which only has one ViewObject in the Application Module’s data model

We implement a small use case where we want to see the total salary of all rows retrieved by the query behind the VO. Without any added where clause we get the total salary of all employees. If we add a filter e.g. by DepartmentId=90 we only get the total salary of all employees of department 90. Here are some images of the final running model in the BC4J Tester

Implementation

OK, so how do implement this use case?

We do this by adding a transient attribute to the EmployeesView and use a SQL default expression to do the calculation

sum(Employee.SALARY) OVER (PARTITION BY NULL ORDER BY NULL)

In the image below we see the definition of the transient attribute in the ViewObject

Problem

This should do the trick. However, when we try to test this in the BC4J Tester we get

In the log window, but no dialog where we see the application module. We don’t get any hint about what went wrong. The tester is up and running, but we don’t see anything.

Shay Shmeltzer mentioned in one of the ODC threads, that the reason for this is that there is an error in the application module (ViewObject, EntityObject or AM method). As the only thing we added is the SQL statement for the transient attribute, it’s clear that the statement must have an error. It’s simply a missing ‘s’ character, as the DB table we use is named ‘Employees’ and not ‘Employee’. So the correct statement is

sum(Employees.SALARY) OVER (PARTITION BY NULL ORDER BY NULL)

This will solve this problem and the BC4J Tester will start up and show (see the images above). But what if we added more things to multiple objects?

How to find the error then?

Older versions of JDev, the BC4J Tester did show an error message which showed the error and made solving the problem easy. Here is an image of the same application running using JDev 12.1.3.0.0

Solution

I did not manage to get the same output using JDev 12.2.1.1.0 or newer, but you can get the same message in the message window.

For this, you need to start the BC4J Tester with the java option

-Djbo.debugoutput=console

The option is added in the model projects ‘Run/Debug’ option in the project’s properties

Whenever you start the BC4J Tester and don’t get any dialog, you can assume that there is an error in the application module. To find out what the problem is, add the java option to the model project and you get the detailed information in the log window.

Pitfalls when using libraries of newer version than shipped with JDeveloper or WebLogic Server

A question on JDeveloper & ADF OTN forum cought my attention. A user wanted to use a method of the Apache Commons-IO library named FileUtils.getTempDiretory() but got an error when he tried to use code completion or when he tried to compile the code. The problem was that the compiler (or code completion) did not pick up the right java class from the library even as it was installed in the project a library.
As the original code used belongs to one of my samples I was interested in finding a reason for this behavior as I could see no obvious reason for this behavior.

An inspection of a provided test case quickly revealed the problem and a solution was found too. This blog is about the problem and the solution to it. Lets start with building a test case:


The test case had a model project which used a couple of libraries which we add too to make this sample as close as possible to the test case.
 Model Project Properties

Model Project Properties


There is no code whatsoever used in the model project just the libraries are defined!

To make use of the FileUtils.getTempDiretory() method we have to first download the Apache Commons-IO in a version higher then 2.0. The current version is 2.4 which you get from the given link. Once you unzip the zip (or tar.gz) to a directory of your choice we create a new library for JDeveloper (Tools->Manage Libraries…)

We add This new library to the view controller project


Next is to create a java bean where we try to use the FileUtils.getTempDiretory() method

Here we see the problem mentioned in the OTN question. The FileUtils.getTempDiretory() does not show up at all. The JavaDoc of the Apache Commons-IO 2.4 package shows that the method is available since version 2.0
JavaDoc of FileUtils Class

JavaDoc of FileUtils Class


If we try to compile the code we get an compilation error as seen in the last image.

What is the problem?
Well, it looks like there is another version of the Apache Commons-IO library already loaded in the classpath which gets loaded first. Once a library or class is loaded, another version of the same class will not overwrite the existing one.
First thing we can try is to move the new commons-io library to the top of the list of libraries.
In the test case presented here, this doesn’t work. We still get the same error. So there are libraries loaded before the view controller project libraries come to play.
Remember we added some libraries to the model project even as there is no code in the project at all?
Because the view controller project has dependency defined to the model project when we create an Fusion Web Application by default, libraries of the model project are loaded before the view controller projects.
We have can solve the problem in multiple ways:
1. remove the dependency to the model project. This is not recommended as it would mean that we have to build the model project ourselves if we have to change something in the model and want to run the application.
2. find the library which loads the FindUtils class and see if we can remove it (not all libraries are needed).
3. add the new Apache Commons-IO library to the model project and move it up front. This should load the newer version of the FindUtils class before any other.

Solution 1 isn’t really one. Solution 2 is possible and I’ll blog about it later. For this blog we use solution 3.

Solution
All we have to do is to add the Apache Commons-IO 2.4 library to the model project and move to the top of the list.

Model Project Properties with Commons-IO

Model Project Properties with Commons-IO


If we now rebuild the workspace we see that to error is gone
No Compilation Error

No Compilation Error


The code completion still shows the method red underlined. This is a bug in JDeveloper which doesn’t pick up the right library. Anyway, the compiler will use the right library and we can compile the application.

Now we add another method to the FileBean which returns the path to the temporary directory. This we use in a page index.jsf to show it on the ui.

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html>
<f:view xmlns:f="http://java.sun.com/jsf/core" xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <af:document title="index.jsf" id="d1">
    <af:form id="f1">
      <af:panelGridLayout id="pgl1">
        <af:gridRow height="50px" id="gr2">
          <af:gridCell width="100%" halign="stretch" valign="stretch" id="gc1">
            <!-- Header -->
            <af:outputText value="Preferred Package Test" id="ot1" inlineStyle="font-size:x-large;"/>
          </af:gridCell>
        </af:gridRow>
        <af:gridRow height="100%" id="gr1">
          <af:gridCell width="100%" halign="stretch" valign="stretch" id="gc2">
            <!-- Content -->
            <af:outputText value="Tempdir path = #{FileBean.tempDir}" id="ot2"/>
          </af:gridCell>
        </af:gridRow>
      </af:panelGridLayout>
    </af:form>
  </af:document>
</f:view>

When we run the application we get an exception

    at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
    at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)
Caused by: java.lang.NoSuchMethodError: org.apache.commons.io.FileUtils.getTempDirectoryPath()Ljava/lang/String;
    at de.hahn.blog.preferredpackages.view.beans.FileBean.getTempDir(FileBean.java:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)

Why’s that?
The application compiled without an error and we still get a NoSuchMethodError. The reason for this is that when we start the WebLogic Server the older version of the Apache Commons-IO jar is loaded first, blocking loading of the newer version we need to get to the FileUtils.getTempDirectoryPath() method.
To allow the server to load our newer version of the jar we need to change a descriptor named weblogic-application.xml which is specific for WebLogic Server. For other servers there exist other descriptors allowing the same.
In this descriptor we add a preferred package for the org.apache.commons.io package. Open the weblogic-appliaction.xml descriptor and select the ‘Class Loading…’ node.

Application Descriptors: weblogic-application.xml

Application Descriptors: weblogic-application.xml


Here we enter the package name org.apache.commons.io to the ‘Application Preferred Libraries’ section.

to get this result in the source view of the descriptor:

    <prefer-application-packages>
        <package-name>org.apache.commons.io</package-name>
    </prefer-application-packages>

After restarting the application the index.jsf page show up OK

Running Test Page

Running Test Page

You can download the sample application which was build using JDeveloper 12.1.3 from GitHub.

JDeveloper & ADF: Use the Application Module Tester (BC4J Tester) to Test all your BusinessLogic

This blog post describes how to use the Application Module Tester provided together with JDeveloper to test all your business logic without having to write or design the client UI (view controller part of a Fusion Web Application).
I consider this a ‘best practice’ to do this in each project. It allows the developer(s) of the business logic to run, debug and test all business logic before the designers have worked out the UI. Changes to interfaces can be done without an impact to the UI this way.

One other advantage of using the Application Module Tester is that it starts up really fast compared to the long init phase the full web application needs.

Before going into detail lets talk about what this blog shows and how it’s implemented. A sample work space build in JDeveloper 11.1.2.1.0 using the HR schema as DB can be downloaded using the link provided at the end of the blog.
First of all you can test the data model you designed into the application module, meaning that you can execute the VO and walk over the result set or show the result as table

Data Model of the Application Module

Data Model of the Application Module

The application module can implement service methods which your later use in the UI to archive a business need. In the sample the application module defines just one service method ‘howManyEmpEarnMoreThen’ which returns the number of employees who are earning more (or equal) to the given amount.

Service Method 'howManyEmpEarnMoreThen'

Service Method 'howManyEmpEarnMoreThen'

and the implementation of this method

    public oracle.jbo.domain.Number howManyEmpEarnMoreThen(oracle.jbo.domain.Number aSalary)
    {
        _logger.info("Call with salary: "+aSalary);
        EmployeesViewImpl lEmployeesView1 = this.getEmployeesView1();
        oracle.jbo.domain.Number n = lEmployeesView1.countEmpWihtSalaly(aSalary);
        return n;
    }

Next a VO might have some ViewCriteria attatched which you also want to test

ViewCriteria to Test

ViewCriteria to Test

and the last thing to test are service methods which are exposed in the VO instead of the application module (‘countEmpWihtSalaly’ in the sample)

Exposed Methods in a View Object

Exposed Methods in a View Object

and the implementation of the method

    public Number countEmpWihtSalaly(Number aSalary)
    {
        RowSet lCreateRowSet = this.createRowSet("counterView");
        ViewCriteriaManager lCriteriaManager = this.getViewCriteriaManager();
        String[] lAvailableViewCriteriaNames = lCriteriaManager.getAvailableViewCriteriaNames();
        for (String vcName :lAvailableViewCriteriaNames)
        {
            this.removeApplyViewCriteriaName(vcName) ;
        }
        lCreateRowSet.ensureVariableManager().setVariableValue("bindSal", aSalary);
        ViewCriteria lCriteria = this.getViewCriteria("EmpSalaryVC");
        this.applyViewCriteria(lCriteria);
        lCreateRowSet.executeQuery();
        long count = lCreateRowSet.getEstimatedRowCount();
        _logger.info("Count Emp wiht salay > " + aSalary + " = " + count);      
        lCreateRowSet.closeRowSet();    
        return new Number(count);
    }

Now let start up the the Application Module Tester and debug the business logic. To start the tester in debug mode, right click the application module facade and select ‘Debug’

Start the Application Module Tester in 'Debug' Mode

Start the Application Module Tester in 'Debug' Mode

which shows the tester like

Running Tester

Running Tester

A double click on a ViewObject (e.g. EmployeesView1) opens one record in form mode. You can navigate the result set using the icons in the header

Navigate Result Set

Navigate Result Set

One of the icons (the field glass) allows you to specify one or more of the available view criteria and hitting the ‘Find’ button after selecting a view criteria opens a dialog to enter bind variables

Specify View Criteria

Specify View Criteria

Specify Bind Variables

Specify Bind Variables

The result of this is again shown as a result set with navigation. If you like to see the result a table you can right click on the VO and select ‘Show Table’.

Show Result as Table

Show Result as Table

So how do we execute the ‘countEmpWihtSalaly’ method which is exposed in the client interface of the VO?
If you look at the image above you’ll see the option ‘Operations’ which will open a new tab showing all available operations which are exposed to the client interface of the VO.

Available Operations

Available Operations

After selecting the method you can hit execute and the method is executed

Result of Operation

Result of Operation

To access the public available methods from the application module you right click on the application module and select ‘Show’. After that you see a tab like the one for the VO operation.

Application Module Operations

Application Module Operations

Result of Operation

Result of Operation

This might not look as much to you, but the advantage of the Application Module Tester is that you can debug the code in the application module methods or view object operation easily. You can set needed variables when calling the methods and use the outcome of the operations in calls to other operations. This way you can easily test the whole business logic without the need to have an UI present.

For more information you can check the Oracle® Fusion Middleware Fusion Developer’s Guide for Oracle Application Development Framework 11g Release 2 (11.1.2.1.0)

You can download the sample workspace, build with JDev 11.1.2.1.0 and depending on the HR db schema, from here: BlogBC4JTester.zip.doc
Please rename the file to ‘.zip’ after downloading it!

JDeveloper Gem: Debug Ant Scripts

I’m not sure if this feature of JDeveloper is widely known, but JDev allows you to debug ANT scripts as if they where java classes of a project.

I guess you normally don’t need to debug an ANT script, but sometimes it comes handy. A use case which comes up quite often lately is the installation for the FOD sample application. A couple of users have run into trouble running the MasterBuildScript from the FOD sample application. You can download the FOD sample from here.Be sure to load the FOD version for the JDeveloper version you are using.

After unzipping the demo you open the ‘Infrastructre’ work space from within JDev, open the ‘MasterBuildScript’ project and open the ‘Resources’ node. Here you find the ‘build.properties’ file which you need to adapt with your environmental settings.
Here is my sample build.properties file:

# Master Ant properties file for Fusion Order Demo
# All build files refer to this master list of properties
# Continuous builds override these settings
# $Id: build.properties 812 2007-02-20 07:14:33Z lmunsing $

# Base Directory for library lookup
jdeveloper.home=P:/jdeveloper
src.home=..//..


# JDBC info used to create Schema
jdbc.driver=oracle.jdbc.OracleDriver
jdbc.urlBase=jdbc:oracle:thin:@tdb02
jdbc.port=1521
jdbc.sid=ORCL

# Information about the default setup for the demo user.
db.adminUser=system
db.demoUser=FOD
db.demoUser.password=fusion
db.demoUser.tablespace=USERS
db.demoUser.tempTablespace=TEMP{code}

Now, to debug an ANT script, open the build.xml file in the MasterBuildScript project and search for the ‘init’ target. Here you set a break point as if this were a java source file.

'init' Taget

'init' Taget

Now right click the ‘build.xml’ file and select ‘Debug Ant Target…’ from the list. From the submenu you select the ‘buildAll’ traget.

Select Target to Debug

Select Target to Debug

You should quickly hit the break point set on the ‘init’ target. You can step over (F8) or step into (F7) like you can do with normal Java files. Best feature (which is the reason for the blog post) is that you can see and change the properties defined by the ANT script.

See and change ANT properties

See and change ANT properties

This should help you find bugs in ANT scripts and hopefully solve them too.

Chris Muir (in his comment) pointed to one more use case which should be mentioned. To get even more knowledge about the targets which are executed in an ANT script you can set more options. To get to the dialog you select ‘Advanced…’ from the list of targets

Select  'Advanced...' to get to more options

Select 'Advanced...' to get to more options


Then you select the target for which you want to set more options
Select target

Select target


and then go to the ‘Options’ step to set e.g. ‘Verbose’ output
Set 'Verbose' option

Set 'Verbose' option


When you finished the dialog the selected target starts running and produces this output
Verbose output

Verbose output


The interesting part is, that using the ‘Advances…’ target only sets the options for the one run or debug of the selected target. If you like to set one of the options permanently, you can do this in the ‘Manage Ant Settings…’ or the project settings
Permanent settings of options

Permanent settings of options

ADFLogger: Using a Custom Formatter Class to Print Log Messages

Based on some posts on the OTN JDeveloper forum this article shows how to implement a custom fdormatter class to use with ADFLogging and how to integrate it with the embedded WLS instance in JDeveloper. Sample workspace for the custom logger is available at the end of the article.
For this post I assume you now your way around java.util.logging. I show how to implement a custom formatter class to format the log messages with more information and a different style. The picture below shows the general java logging model:

General Logging Model

General Logging Model


As the model shows the formatter is used by the log handler which gets a log record and processes it by piping the record through a filter and then through a formatter to finaly pass it to the attached output target. In most cases the output target is a file, a db table, a system log or a stream. For the console logger its most often a stream (e.g. stdout and/or stderr).

A typlical JDev log message from the ConsoleFormatter looks like this:

<AdfcAppInitializer> <loadDebugFacades> ADFc: Initializing ADF Debugger

I’ll change this to:

FINE: 22.09.2011 13:18:17 - de.hahn.blog.popupregion.backingbeans.pageflow.SelectionBean$beaVersion0_39.selectionListenerEmp(SelectionBean.java:92) - 15 - de.hahn.blog.popupregion.backingbeans.pageflow.SelectionBean
  Selected: oracle.jbo.Key[105 ]

The general layout of the log message is

data in [] is customizable, data in {} is printed only if available
level: date time [- threadId] [- class] [- method] [- message] {- throwable.message}
These parameters configure which information to print
       t = thread
       n = logger name
       l = line number; if 'l' is selected 'c' and 'm' are not used
       c = class name
       m = method name

As you see there is more information printed, e.g. source and line number and log level. As this creates long log lines I made this customizable. How the parameters are passed to the logger is shown later.

First of all I implement a class DebugFormatter which extends java.util.logging.SimpleFromatter as this class is an implementation of the abstract class java.util.logging.Formatter the base of all formatter attached to a log handler. The key part of this class is the method

public String format(LogRecord record) {...}

which gets a log record and returns a string of the information which send to the handler for further action. The format method checks the parameters given and returns a string according to them.

To wire things up I modify the logging.xml file which can be reached from the ‘Application Server Navigator’. Right click on the integrated WLS and select ‘Configure Oracle Diagnostic Logging for …’. This will open a nice graphical overview

Logging.xml

Logging.xml


Now I add a new logger by clicking the green ‘+’ sign and specifying the log level and the name of the logger, which is actually the part of the class path the logger reacts on.
Add  Logger

Add Logger


this creates a new line in the logging.xml file looking like
Added Line

Added Line


Next I set up a new log handler in the logging.xml file which uses my DebugLogger class as formatter. Together with the log handler I specify the parameters which configure the output format of the string. The DebugLogger is not used directly, but instead a wrapper class WLSConsoleFormatter used which specifies default parameter set to the DebugFormatter. This way you can omit the parameters in the setup. Below is the resulting log handler entry in the logging.xml file:

        <log_handler name='blog-console-handler'
                     class='de.hahn.blog.consoleformatter.logger.BlogConsoleHandler' level='ALL'
                     encoding='UTF-8'>
            <property name='formatStyle' value='tnlcm'/>
            <property name='formatter'
                      value='de.hahn.blog.consoleformatter.logger.WLSConsoleFormatter'/>
        </log_handler>

To add this you need to change to the source view for the logging.xml file.
Finally I change the added logger to use the new handler

        <logger name='de' level='TRACE:1' useParentHandlers='false'>
            <handler name='blog-console-handler'/>
            <handler name="odl-handler"/>
        </logger>

I have to set the useParentHandlers to false to prevent that the messages get printed multiple times. To be able to analyze the messages with the log analyzer I add the ODL handler too. Now all log messages are printed to the console and to the ODL logger.

Now that the logger are setup in the logging.xml all I need to do is to make the classes available to the WLS instance. For this I build a jar from the project and put the resulting BlogConsoleFormatter.jar in a folder where WLS picks it up while starting. There a a couple of folder, but I choose <ide.system.dir>/DefaultDomain/lib folder. ide.system.dir is also known as the systemfolder of your JDeveloper installation. If you don't know where to find it check this blog. You can either copy the jar into the folder or setup the deployment profile to generate the jar in this folder.

Sample Oiutout

Sample Oiutout

The picture above show a small code sample with the generated output from DebugFormatter. As you see the log lines are marked as links. If you click on such a line you see that you are transfered to the code location of the message.

You can download the source code for the BlogLogConsoleFormatter.zip and a BlogPopupRegion.zip using the ADFLogger to generate messages in different log levels. After downloading the files you need to remove the ‘.doc’ suffix and rename them to ‘.zip’ as the files are normal zip files.
The sample workspaces are developed with JDeveloper 11.1.2.0.0, BlogPopupRegion uses the HR schema as DB connection.

JDev: Always Test Your App with ApplicationModule Pooling turned off

In the last couple of weeks I saw a couple of question which mentioned a sporadic misbehavior of the application under different circumstances. In the end they could be answered:

“Your application has not been tested with application module pooling turned off”

Whenever you encounter a sporadic misbehavior of the application under different circumstances, this should ring a bell. Most developers came across a situation like this when programming ADF applications. At some point the application does not react normal or throws exceptions. The errors are not reproducible (most of the times) and you only see them on the production server (never on the developer machine).

The first time I came across this problem it took me about a week to figure it out and solve it. Basically the problem has been private data (stored with the session) which is part of the application module and is stored in the user data hash map. This is not a problem as long as you can guarantee that each user always works with the same application module. This is the case when you test run your application on the developers machine (you are the only user and the application module pool always returns the same application module to the client). On a production server where more then one user uses the application at the same time, the application may be forced to reuse an application module which was formally used by a different user. At this point application module pooling take over.

The general algorithm used is that the application module pool has a number of application module available to use. If more requests arrive the pool generates the additional module until a high water mark is reached. Further requests getting rejected. Currently not used modules are given back to the pool and are available for the next request. The pool tries to return the same application module as long as it’s available to the same session for subsequent requests. If it is not available it uses a currently available module stores the current status of the module into a store (DB or file), clears the module from all information and reconstructs the state from the other session from saved state information. Once the application module is restored you can’t distinguish if it’s a new application module or a reused one. This way your application don’t need an module for each user request, but it shares the available modules between the requests, saving lots of resources.

All this can be read about here 43.2 Introduction to Fusion Web Application State Management.

After this more theoretical prologue, lets do a practical project (workspace for JDev 11.1.2 available, see end of article). To make it as simple as possible, but still useful for anybody running into problems with activation/passivation, we use the HR schema and try to emulate a scenario where a user only sees employee data which depends on a department number. This department number should be set in the application module and be accessible for all queries. In a real world scenario this information is connected to the login of a user and stored in a central place. In the sample we use the user data of the application module to store the number.
The applications start page (I do spare the login part) has a af:query panel to select employees which might be filtered by their last name. As there is no login I added a field to enter the department number which should be used to further filter the result set.The Web UI lokke like

Test app UITest Application UI

As you see there is an input field for the last name, in the bottom era an input field to insert the department number and an other panel to retrieve the currently set department number from the application module.
Lets have a look at the service method to get/set the department number and how it is stored:

    private static final String PRIVATEDATA = "privData";

    public void setPrivateToUserData(String aVal) {
        mLogger.info("Set PrivData:" + aVal);
        if (aVal == null)
            return;

        Session lSession = getSession();
        if (lSession == null) {
            mLogger.warning("getSession returned null!");
            return;
        }
        Hashtable lHashtable = lSession.getUserData();
        if (lHashtable == null) {
            mLogger.warning("getUserData returned null!");
            return;
        }
        lHashtable.put(PRIVATEDATA, aVal);
    }

    public String getPrivateToUserData() {
        Session lSession = getSession();
        if (lSession == null) {
            mLogger.warning("getSession returned null!");
            return null;
        }
        Hashtable lHashtable = lSession.getUserData();
        if (lHashtable == null) {
            mLogger.warning("getUserData returned null!");
            return null;
        }
        String lData = (String) lHashtable.get(PRIVATEDATA);
        mLogger.info("Get PrivData: " + lData);
        return lData;
    }

As you see the string from the UI is stored and retrieved under the key PRIVATEDATA = “privData” in the userData hash map of the application module. This is the place to store data for the current user session (Storing Information About the Current User Session)
The configuration of the application module is the default you see after generating a ‘Fusion Web Application’.

ApplicationModule Default Configuration

ApplicationModule Default Configuration


As you can see ‘Application Module Pooling’ is on. When we run the application, set the department number to e.g. 30, send the data to the AM and hit the search button in the query panel we see
Pooling On

Pooling On


You can hit the edit button in a row to edit the employee and come back to the page and see the application running as expected.
Now, we switch ‘Application Module Pooling’ off and run again:
Application Module Pooling Off

Application Module Pooling Off


Doing the same actions as earlier it look like the application does not see the department number at all:
Application Module Pooling Off

Application Module Pooling Off


Even if you set the department number and directly hit the ‘Get User Data’ button you’ll don’t get the department number back.

The reason for this behavior is that we store the department number in the user data hash map which is NOT passivated when the application module is given back to the pool and given to an other requester. This happens every time you go the the server when am pooling is switched off.
What we need to to is to passivate the session user data together with the other state data stored by the framework and load it back when the AM is requested the next time (when it gets activated again). To do this we have to overwrite two methodes in the ApplicationModuleImpl class.

    @Override
    protected void activateState(Element aElement) {
        super.activateState(aElement);
        mLogger.info("++++++++++ activateState");

        Hashtable lData = getSession().getUserData();
        if (aElement != null) {
            // 1. Search the element for any <PrivData> elements
            NodeList nl = aElement.getElementsByTagName(PRIVATEDATA);
            if (nl != null) {
                // 2. If any found, loop over the nodes found
                for (int i = 0, length = nl.getLength(); i < length; i++) {
                    // 3. Get first child node of the <PrivData> element
                    Node child = nl.item(i).getFirstChild();
                    if (child != null) {
                        // 4. Set the data value to the user data hashmap
                        String lDataString = child.getNodeValue();
                        String[] lSplitkeyval = lDataString.split(";");
                        for (int ii = 0; ii < lSplitkeyval.length; ii++) {
                            mLogger.fine("..."+lSplitkeyval[ii]);
                            String[] lSplit = lSplitkeyval[ii].split("=");
                            lData.put(lSplit[0], lSplit[1]);
                        }
                        break;
                    }
                }
            }
        }
    }


    @Override
    protected void passivateState(Document aDocument, Element aElement) {
        super.passivateState(aDocument, aElement);
        mLogger.info("---------- passivateState");

        // 1. Retrieve the value of the user data to save and build a string representation
        Session lSession = getSession();
        Hashtable lData = lSession.getUserData();
        String lDataString = "";
        Set<String> keyset = lData.keySet();
        if (!keyset.isEmpty()) {
            Iterator<String> keys = keyset.iterator();
            while (keys.hasNext()) {
                String key = keys.next();
                mLogger.fine("..."+key + "=" + lData.get(key));
                lDataString += key + "=" + lData.get(key) + ";";
            }
        }

        // 2. Create an XML element to contain the value
        Node node = aDocument.createElement(PRIVATEDATA);
        // 3. Create an XML text node to represent the value
        Node cNode = aDocument.createTextNode(lDataString);
        // 4. Append the text node as a child of the element
        node.appendChild(cNode);
        // 5. Append the element to the parent element passed in
        aElement.appendChild(node);
    }

The passivateState method gets a Document and an Element as parameter. After calling super() to let the framework do its work, we get the user data hash map and store each key-value pair in a string which is then appended as a node to the element we got as parameter. In a real world application I would use a java to XML serialization tool like XStream which is capable to store more complex data.
The activateState method gets an Element as parameter which we search for the node we save when passivateState was called and restore the user data hash map.

After putting the two methods in the ApplicationModuleImpl class (the one you get when you create the java classes for an application module) the application run OK again, application module pooling still turned off.

When you examine the sample workspace which you can get here BlogActivatePassivateSample_V1.zip (remove the ‘.doc’ extension after downloading the workspace!) you’ll notice, that EmployeesViewImpl class too have the two methods to store private data which is not automatically saved by the framework. Further there are log messages throughout the code to let you follow the action in the log window.

As you see it’s essential to test an application with application module pooling turned off to find activation/passivation errors before the application goes to production.

Dump VO query and it’s parameter with their values

Based on a request on JDeveloper and ADF forum I wrote a small method to dump the query of a VO together with it’s bind variables (autom. inserted by the framework and user defined) and their values.
The method below gets the query in it’s actual state, checks the variables and dumps their names and values. I’m using a simple ‘System.out.println’ to dump the information for simplicity. If you like to use the method in a more general way (e.g. in a base class) I would recommend to use a ADFLogger. See Duncan Mills bloghere

    public void dumpQueryAndParameters()
    {
        // get the query in it's current state
        String lQuery = getQuery();
        //get Valriables
        VariableValueManager lEnsureVariableManager = ensureVariableManager();
        Variable[] lVariables = lEnsureVariableManager.getVariables();
        int lCount = lEnsureVariableManager.getVariableCount();
        // Dump query
        System.out.println("---query--- " + lQuery);
        // if variables found dump them
        if (lCount > 0)
        {
            System.out.println("---Variables:");
            for (int ii = 0; ii < lCount; ii++)
            {
                Object lObject = lEnsureVariableManager.getVariableValue(lVariables[ii]);
                System.out.println("  --- Name: " + lVariables[ii].getName() + " Value: " +
                                   (lObject != null ?  lObject.toString() : "null"));
            }
        }
    }

You can overwrite the executeQuery() method of the ViewObjectImpl class and call the method above like

    @Override
    public void executeQuery()
    {
        dumpQueryAndParameters();
        super.executeQuery();
    }

Executing a Query you should see output like

---query--- SELECT Employees.EMPLOYEE_ID,         Employees.FIRST_NAME,         Employees.LAST_NAME,         Employees.EMAIL,         Employees.PHONE_NUMBER,         Employees.HIRE_DATE,         Employees.JOB_ID,         Employees.SALARY,         Employees.COMMISSION_PCT,         Employees.MANAGER_ID,         Employees.DEPARTMENT_ID FROM EMPLOYEES Employees WHERE ( ( (Employees.LAST_NAME LIKE ( :vc_temp_1 || '%') ) ) )
---Variables:
  --- Name: vc_temp_1 Value: gr%
  --- Name: bindHireDate Value: null

The nice part of this method is that it dumps user defined bind variables as well as automatically added variables by the framework. In the output above vc_temp_1 is a variable of a filter entered in an af:table component.