JDev: Custom selectionListener for ViewObjects in ‘RangePaging’ mode

Lately a question on the Oracle JDev forum came up, asking for a solution for a problem with a ViewObject in ‘RangePaging’ mode and a single selection af:table defined on this ViewObject. The problem is to get the current selected row in such a case. Under some circumstances (which are not always reproducible) using the default

#{bindings.YOUR_VIEWNAME.collectionModel.makeCurrent} 

doesn’t mark the selected record and a call in a bean to get the selected record returns null:

BindingContext lBindingContext = BindingContext.getCurrent();
BindingContainer lBindingContainer = lBindingContext.getCurrentBindingsEntry();
DCBindingContainer bindingsIte = (DCBindingContainer) lBindingContainer ;
DCIteratorBinding dciter = bindingsIte.findIteratorBinding("YOUR_VIEWNAMEIterator");
Row row = dciter.getCurrentRow();
if (row == null) {
    return null;    // no current row
}

For ViewObjects in ‘Scrollable’ mode you get the selected record without any problem. ViewObjectes in ‘RangePaging’ mode are mostly used for tables which contain many rows and the use case doesn’t allow to filter the result set to a reasonably number. The ‘RangePaging’ option is a tuning parameter in the ViewObject definition

Set a ViewObject to 'RangePaging' mode

Set a ViewObject to 'RangePaging' mode


I run into this condition myself and use the following work around:

  1. remove the current selectionlistener from the table (#{bindings.YOUR_VIEWNAME.collectionModel.makeCurrent})
  2. define a new selection listener (use the small arrow on the right side) in a bean of your choice. The scope of the bean has to be view or pageflow depending on where you need access to the selected row
  3. in the new selectionListener you get the selected row from the event, get the key of the row and store it in a bean attribute
  4. when you need the selected row you use the stored row key and work with this. If you need attributes from the row you have to query the row again, as you only have the key

If you only need the key of the row you can e.g. pass this key to a service method defined in the application module or the ViewObject. Here is a sample of such a selection listener:

public void singleSelectionListener(SelectionEvent selectionEvent) {
        RowKeySet rksAdd = selectionEvent.getAddedSet();
        if (rksAdd.isEmpty())
            return;  // no selection
 
        Object[] it = rksAdd.toArray();
        // as this is for single selection there should only be one, but...
        for (Object obj: (List) it[0]) {
            mLogger.fine("Selected :" + obj);  // log selected row
            Key k = (Key) obj;   // the object is the row key
            Object[] kv = k.getKeyValues();  // get the key value for later
            // strore the key value in a bean attribute: mLastSelectedOID is defined in the bean
            mLastSelectedOID = (Integer) kv[0]; // store the key value (if the key has multiple parts you need to store them all)
        }
    }

The variable mLastSelectedOID is defined in the bean. The type of the attribute depends on the type the primary key of the table has. If you like you can generate getter/setter methods for the attribute and use them instead of assigning the value directly.

Save (most of) your changes to the JDeveloper IDE

Under some circumstances you may need to rename or remove your system11.x.x.x folder to overcome errors with the IDE which can’t be solved otherwise. I blogged about this How to find and reset the system11.x.x.x folder for a JDeveloper installation.
However, this means that you loose all of the changes you made to IDE, e.g. connections to DBs, code templates and many more.
In the current version or JDeveloper there is no feature to save all the changes you made with a simple export or click on a button. An ER for this is about to be filed.

Until we see this ER implemented you need to store the changes you made yourself. First of all we need to know all the places were changes can be saved in a file or exported into a file. I put all those files under source control. This makes them available for other developers in the same team and allows to hold different configurations for different or the same JDeveloper version. This blog post lists all the places I know. If you know any other place, please drop a comment so that I can include it here.
To my knowledge the locations below are working for all JDeveloper version from 11.1.1.x up to the current version 11.1.2.1.0.

There are three locations where you can save your changes

  1. Recource Palette
  2. Preferences
  3. File menu

Lets start with the Resource Palette:

Resource Palette 1

Resource Palette 1


This will bring up
Resource Palette 2

Resource Palette 2


This dialog allows you to save all the connection to DBs and Weblogic Servers you have defined as well as Catalogs. All you have to do is to specify a path and a file name to store the information.

Next are the Preferences. Here are a couple of places where you can export your changes.
Audit Profiles:

Audit Profiles

Audit Profiles

Code Editor – Code Style

Code Editor - Code Style

Code Editor - Code Style

Code Editor – Code Templates

Code Editor - Code Templates

Code Editor - Code Templates

Code Editor – Syntax Colors

Code Editor - Syntax Colors

Code Editor - Syntax Colors

Database – SQL Formatter

Database - SQL Formatter

Database - SQL Formatter

Database – SQL Formatter – Oracle Formatting

SQL Formatter - Oracle Formatting

SQL Formatter - Oracle Formatting

Database – SQL Formatter – Other Vendors (each vendor can be saved)

 Database - SQL Formatter - Other Vendors

Database - SQL Formatter - Other Vendors


 Shortcut Keys

Shortcut Keys

Versioning – Comment Templates

Versioning - Comment Templates

Versioning - Comment Templates

Finally the ‘File’ menu which mainly allows to export the connections to the source control system you use

File - Export

File - Export

JDev 11.1.2.1.0: Dealing with ADF_FACES-60003 Error: Component with ID: r1:1:cb1 not registered for Active Data.

The last couple of weeks I saw some questions on OTN JDev forum dealing with file and image handling in ADF applications. All of the needed information to do this is already published in various blog posts and tutorials, still I did not find a post covering all aspects with a single demo application.

I’m in the progress of writing a mini series about file handling (upload and download) and image handling in ADF applications providing exactly this demo application. If you are interested in this stay tuned, as the first part is almost ready to publish.

Now, while I assembled the demo application I stumbled upon this error:

java.lang.IllegalStateException: ADF_FACES-60003:Component with ID: r1:1:cb1 not registered for Active Data.
	at oracle.adfinternal.view.faces.activedata.PageDataUpdateManager.unregisterComponent(PageDataUpdateManager.java:600)
	at oracle.adfinternal.view.faces.context.RichPhaseListener.handleStartAndStopActiveData(RichPhaseListener.java:502)
	at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._executePhase(LifecycleImpl.java:479)
	at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:204)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:312)
	at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
	at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
	at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:300)
	at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
	at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
	at oracle.adf.model.servlet.ADFBindingFilter.doFilter(ADFBindingFilter.java:173)
	at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
	at oracle.adfinternal.view.faces.webapp.rich.RegistrationFilter.doFilter(RegistrationFilter.java:122)
	at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:468)
	at oracle.adfinternal.view.faces.activedata.AdsFilter.doFilter(AdsFilter.java:60)
	at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl$FilterListChain.doFilter(TrinidadFilterImpl.java:468)
	at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl._doFilterImpl(TrinidadFilterImpl.java:293)
	at org.apache.myfaces.trinidadinternal.webapp.TrinidadFilterImpl.doFilter(TrinidadFilterImpl.java:199)
	at org.apache.myfaces.trinidad.webapp.TrinidadFilter.doFilter(TrinidadFilter.java:92)
	at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
	at weblogic.servlet.utils.FastSwapFilter.doFilter(FastSwapFilter.java:66)
	at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
	at oracle.security.jps.ee.http.JpsAbsFilter$1.run(JpsAbsFilter.java:111)
	at java.security.AccessController.doPrivileged(Native Method)
	at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:313)
	at oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:413)
	at oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:94)
	at oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:161)
	at oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:71)
	at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
	at oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:136)
	at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
	at weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27)
	at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:56)
	at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3715)
	at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3681)
	at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
	at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
	at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2277)
	at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2183)
	at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1454)
	at weblogic.work.ExecuteThread.execute(ExecuteThread.java:209)
	at weblogic.work.ExecuteThread.run(ExecuteThread.java:178)
...

It happened when I used a af:fileDownloadActionListeneron a detail page fragment and navigated back to the master page fragment. As I never saw the error before and did not use ‘Active Data’ anywhere in my demo, I started digging.

There are some members of OTN hitting the same error (may be not under the exact same conditions) as this thread shows.
The thread points to an older post which mentions that this is caused by the bug 9218151 and is fixed in JDev 11.1.2.0.0. As I use JDev 11.1.2.1.0 this should not happen, or I see a regression of the bug in JDev 11.1.2.1.0. The bug database did not help either, as there is very little information on the bug itself.
The solution given in the thread to use a custom error handler (and ignore the error) did not seem right to me. I did not try the other solution to write a custom tag either, as it looks like overkill to me.

The normal debugging of this problem didn’t get me further to a solution. I tried a couple of things and even was able to get around the error with some hacks I will not publish here.

Luckily I met Frank Nimphius at the DOAG2011 and ask him about this bug (that’s what such events are for :)). He gave the right pointer to solve the problem.
With JDev 11.1.2.0.0 a new default ‘change event policy’ was introduced to the iterators and components. Now the policy is ‘ppr’ and not ‘none’ as before.
Jobinesh had blogged about the new ‘change event policy’ and its meaning here.

As I couldn’t reproduce this behavior in JDev 11.1.1.5.0 Franks suggestion was to set the change event policy back to none. After doing exactly this the error is gone, the application runs as expected.

The new policy can be changed (back to the old behavior) on a global level for applications you are building new under JDev 11.1.2.x. To do this open the adfc-config.xml file from the ‘Application Resources:

adfc-config.xml

adfc-config.xml

change to the ‘Overview’ tab and select the ‘Model’. Here you remove the selection from the check box:

adfc-Config.xml Change Event Policy

adfc-Config.xml Change Event Policy

If you already have done some work in your project, e.g. used some views on an UI page, you have to change the iterators one by one. For this open the bindings of the page and select an iterator:

Change Event Policy on Iterator

Change Event Policy on Iterator

You may let the default ‘change event policy’ be ‘ppr’ if you like, as there are some advantages (there must be a reason why Oracle changed it in the first place). Only if you hit the error you can change the policy for the iterators involved. Keep in mind, that changing the policy later may have some side effects to your existing pages. It’s up to you to decide and test this.

I’ll file an SR for this just to make sure that Oracle looks into this again. For me it looks like a bug as I don’t understand why I get an error at all.

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 ADF af:goLink: Build Destination URL with Parameter Value from af:inputField

A discussion on the OTN JDeveloper forum asked for an af:goLink which should not be static but use values from form fields as parameters for the link.
I set up a simple workspace with JDev 11.1.2.0.0 to show how to do this. The technique can be used in JDeveloper 11.1.1.x.0 too, only the provided workspace won’t work. To download the workspace see the link at the end of the post.
The workspace uses the HR schema to get access to the employees table and show an employee in a from on the only page.

Running App

Running App


The image shows the running application. You see the form showing an employee, the navigation buttons and the big af:goLink. A click on the link opens a new page with Google and searches for the last name of the employee. When you navigate over the employees the link changes its parameters to pass the last name of the selected employee in the form. To make it more interesting the last name filed is set to autoSubmit so you can search for a changed name without committing the recored first. The af:goLink uses an EL in the destination property to point to a method in a request scope bean which builds the final url with the attached parameter. The parameter is the current value of the last name attribute from the bindings.
Sample 1

Sample 1


Sample 2

Sample 2


Sample 3

Sample 3


Here is the code for the last name input field and the code in a request scope bean to calculate the destination for the af:goLink:

<af:inputText value="#{bindings.LastName.inputValue}"
                                      label="#{bindings.LastName.hints.label}"
                                      required="#{bindings.LastName.hints.mandatory}"
                                      columns="#{bindings.LastName.hints.displayWidth}"
                                      maximumLength="#{bindings.LastName.hints.precision}"
                                      shortDesc="#{bindings.LastName.hints.tooltip}" id="it3"
                                      autoSubmit="true">
                            <f:validator binding="#{bindings.LastName.validator}"/>
                        </af:inputText>
...
                        <af:goLink text="LinkWithParams" id="gl1" targetFrame="_blank"
                                   destination="#{linkWithParams.linkWithParams}"
                                   inlineStyle="font-size:xx-large;"/>
import oracle.adf.model.BindingContext;
import oracle.binding.AttributeBinding;
import oracle.binding.BindingContainer;

public class LinkWPBean {
    public LinkWPBean() {
        super();
    }

    public String getLinkWithParams() {
        // get the binding container
        BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();


        // get an ADF attributevalue from the ADF page definitions
        AttributeBinding attr = (AttributeBinding) bindings.getControlBinding("LastName");
        String valLastName = (String) attr.getInputValue();

        String base = "http://www.google.com/#sclient=psy&q="+valLastName;
        return base;
    }
}

You can download the work space here: Workspace BlogLinkWithParams.zip You have to rename the file to BlogLinkWithParams.zip as the file contains a simple zip file.

Using Groovy Expression to set a Primary Key with a Sequence Number

Just set up a workspace for JDeveloper 11.1.2.0.0 to show how to use a Groovy expression to set the primary key of an entity object. Chris Muir blogged about this back in 2009 here ADF BC: Using Groovy to fetch sequence numbers for EO/VO attribute default values. There exists a white paper Introduction to Groovy Support in JDeveloper and Oracle ADF 11g which covers Groovy support in JDeveloper.
So, I don’t cover the basic here but only show how to use this in a sample application. The application uses the HR schema and allows you to insert a new employee. The workspace which you can download (see at the end of this blog) is build using JDeveloper 11.1.2.0.0.
I use the EMPLOYEES_SEQ defined in the HR schema to set the PK of the new employee, EMPLOYEE_ID to the next available sequence number.

Employee Sequence

Employee Sequence


Now we can open the Employee EO from the model layer. Double click on the Employees EO to open the properties inspector for the EO and select the ‘Attribute’ section.
Employees Attributes

Employees Attributes


Now select the EmployeeId in the attributes to get to the attributes properties.
EmployeeId Properties

EmployeeId Properties


Here we can add a default value as literal, expression or as SQL. We select the ‘Expression’ radio button and click on hte pencel on the right side of the input field.
Edit Expression Editor

Edit Expression Editor


Here we enter the Groovy expression to get the next sequence number

(new oracle.jbo.server.SequenceImpl("EMPLOYEES_SEQ",adf.object.getDBTransaction())).getSequenceNumber()

After submitting the dialog with OK you should set the ‘Refresh Expression Value’ to ‘true’ and the ‘Updatable’ LOV to ‘While New’.

Finished Dialog

Finished Dialog


A word of caution here: JDev 11.1.2.0.0 saves the setting for the refresh condition in the xml file, but the next time you open the dialog again the ‘Refresh Expression Value’ value is gone! I’ll file a bug for this later.
This wraps up the the model layer of the app. You can test your work with the Application Module Tester. When you create a new record you’ll see that the EmployeeId is set to the next sequence number.
Oracle ADF Model Tester

Oracle ADF Model Tester


The ViewController project is pretty simple. It consists of an ADF form with with navigation buttons and a button to call a bounded task flow to create the new employee.
Task Flows

Task Flows


The bounded task flow first calls the CreateInsert operation to create a new record which is then displayed in the form. As you notice, the EmployeeId is an af:outputText element, so that you can’t change it.
Running Application

Running Application

The workspace for JDeveloper 11.1.2.0.0 can be downloaded from here: Workspace BlogPKwithGrooy.zip
After downloading the file, remove the suffix ‘.doc’ and rename it to ‘ BlogPKwithGrooy.zip’, as the file is a Zip file.

Extending ViewCriteria to use SQL CONTAINS

Some time ago a customer asked how to use more sophisticated search operands in a ViewCriteria like Oracles CONTAINS or CATSEARCH functions.
CONTAINS and CATSEARCH are part of the Oracle DB 10g and 11g (Enterprise) and offer full text search capabilities (Oracle Text) for columns (even columns containing pdf or word documents in a blob) and external data. As the customer extensively uses full text search the question was how to integrate this functionality in existing and new to develop ADF rich faces applications. As most of the queries are done using view criteria I looked for a way to integrate the CONTAINS search as operand in the ViewCriteria wizard. A thread on OTN I opened for this issue gave some inside hints on how to try to implement this.

Steve Muenchs hint to add the operator directly in the XML definition of the ViewObject (VO) did not work out. The solution I show in this article is a variation of Jobineshs blog. I overwrite the getCriteriaItemClause(…) method to generate the desired SQL clause and add it to the rest of the query. One problem needed to be solved: how to trigger the use of the CONTAINS in the query. As I mentioned before, putting the CONTAINS as operand into the definition of the VO is to cumbersome as it has to be done in every VO where you want to use the CONTAINS search. In the end I used the bind variable to trigger the special treatment.

Each bind variable provides custom properties which I use as trigger. I use the DESCRIPTION property (you can use your own name) and add CONTAINS as value. The overwritten getCriteriaItemClause(…) method checks for each ViewCriteriaItem if its uses a bind variable with the DESCRIPTION set to CONTAINS. If this is the case I generate the SQL clause for the CONTAINS search.

OK, lets walk through the implementation. First I need to create the CONTAINS index which I want to use in the ViewCriteria. I like the index to be case insensitive, so I need to define a preference which is used to alter the index in this way. As a CONTAINS index doesn’t automatically synchronize I change this behavior too, so that I don’t need to do this by hand. For more info about this kind of index check the Oracle Text Reference.

--create a preference to make the index case insensitive
begin
ctx_ddl.drop_preference('bloglex');
end;
/
begin
ctx_ddl.create_preference('bloglex', 'BASIC_LEXER');
ctx_ddl.set_attribute ('bloglex', 'mixed_case', 'NO');
end;
/
-- create the index with sync on commit 
drop index employee_ln_idx;
create index employee_ln_idx on employees(LAST_NAME) indextype is ctxsys.context PARAMETERS('LEXER bloglex SYNC(ON COMMIT)');

A typical SQL query using this index look like

SELECT Employees.EMPLOYEE_ID,
  Employees.FIRST_NAME,
  Employees.LAST_NAME,
  Employees.EMAIL,
  Employees.PHONE_NUMBER
FROM EMPLOYEES Employees
WHERE ( ( ( (contains(Employees.LAST_NAME, 'ha%' ) >0) ) ) );

The syntax I need to generate for a CONTAINS SQL where clause looks like: contains(Employees.LAST_NAME, :bindLN ) >0
I defined a ViewCriteria “ContainsLastNameCriteria” for this

ViewCriteria ContainsLastNameCriteria

ViewCriteria ContainsLastNameCriteria


The definition of the bind variable look like
Bind Variable "bindContainsLastName"

Bind Variable "bindContainsLastName"


As you see I choose ‘Equals’ as operator. It does not really matter what I choose, as the query where clause I build will overwrite it anyway. Instead of the default name “DESCRIPTON” you can choose any other name you like, just overwrite the name field in the dialog.
Now using the technique mentioned in Jobineshs blog I overwrite the getCriteriaItemClause(…) method of the ViewObjectImpl class like:

    ADFLogger mLogger = ADFLogger.createADFLogger(EmployeesViewImpl.class);

    /**
     * Check if a given criteria item holds a bind variable with a property DESCRIPTION set to CONTAINS
     * If yes we build a special where clause part to execute a contains search using the the bind variable as
     * parameter.
     * @param aVCI Criteria item
     * @return where clause part for the criteria item
     */
    @Override
    public String getCriteriaItemClause(ViewCriteriaItem aVCI)
    {
        ArrayList<ViewCriteriaItemValue> lArrayList = aVCI.getValues();
        ViewCriteriaItemValue itemValue = (ViewCriteriaItemValue) lArrayList.get(0);
        if (itemValue.getIsBindVar())
        {
            Variable lBindVariable = itemValue.getBindVariable();
            // check for the special DESCRIPTION in the used bind variable
            Object obj2 = lBindVariable.getProperty("DESCRIPTION");
            String desc = (obj2 != null? obj2.toString(): "null");
            if ("CONTAINS".equalsIgnoreCase(desc))
            {
                if (aVCI.getViewCriteria().getRootViewCriteria().isCriteriaForQuery())
                {
                    // normal query execution
                    return getCONTAINSClauseForDatabaseUse(aVCI);
                }
                else
                {
                    // for in memory we don't need to anything so just return '1=1'
                    return "1=1";
                }
            }
            else
            {
                // no special treetment for all other CriteriaItems
                return super.getCriteriaItemClause(aVCI);
            }
        }
        return super.getCriteriaItemClause(aVCI);
    }

    protected String getCONTAINSClauseForDatabaseUse(ViewCriteriaItem aVCI)
    {
        ArrayList<ViewCriteriaItemValue> lArrayList = aVCI.getValues();
        ViewCriteriaItemValue itemValue = (ViewCriteriaItemValue) lArrayList.get(0);
        String whereCluase = "1=1";
        if (itemValue.getIsBindVar())
        {
            Variable lBindVariable = itemValue.getBindVariable();
            Object objVarVal = ensureVariableManager().getVariableValue(lBindVariable.getName());
            String varVal = null;
            if (objVarVal != null)
            {
                varVal = objVarVal.toString();
            }
            else
            {
                // if no parameter given we search for all
                varVal = "%";
            }

            String bindVarName = lBindVariable.getName();
            // can use entiy name only if VO is based on an EO
            String entityName =
                (this.getEntityDefCount() > 0? this.getEntityDef(0).getAliasName() + ".": "");
            whereCluase =
                    "(contains(" + entityName + aVCI.getColumnName() + ", :" + bindVarName + " ) >0) ";
        }
        mLogger.fine("Build clause: " + whereCluase);
        return whereCluase;
    }

That’s about it for the code, lets look at the running sample which you can download from here BlogContainsSearchCriteria.zip. Remove the ‘.doc’ suffix after downloading the sample work space for JDeveloper 11.1.2 as it contains a normal Zip archive.
After the start of the sample app you see a normal QueryPanel with table component which I dragged fro mthe DataContron onto a page fragment. Select ‘ContainsLastNameCriteria’ from the search select list and enter e.g. ‘ha%’ into the LastName input field.

First run using ContainsLastNameCriteria

First run using ContainsLastNameCriteria

The query returns all last names starting with ‘ha’, but also the last name ‘De Haan’ where the ‘ha’ starts the second part of the last name. This is normal expected behavior. This is the output in the log window:

[368] 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 ( ( ( (contains(Employees.LAST_NAME, :bindContainsLastName ) >0) ) ) )
[369] Bind params FOR ViewObject: [de.hahn.blog.containscriteria.model.dataaccess.EmployeesView]BCSCAppModule.EmployeesView1
[370] Binding param "bindContainsLastName": Ha%

Here we see the generated query using the CONTAINS index in the where clause. You may argument that this same result could archived using the normal ‘contains’ operator’ available in the ViewCriteria wizard. The generated where clause in this case looks like

... WHERE ( ( (UPPER(Employees.LAST_NAME) LIKE UPPER('%' || :bindLastName || '%') ) ) )

The big difference is the usage of ‘UPPER’ and the ‘%’ in front and after the bind variable. The usage of ‘UPPER’ is the result of selecting ‘Ignore case’ in the view criteria editor. One disadvantage of using UPPER is, that if you have defined an index on the column (LAST_NAME in this sample), it can only be used if it was created with the UPPER function too. For small data volumes it’s OK to use a query like this without an index, but if you query big volume data it’s an absolute (time) killer.
Next the usage of ‘%’ before the bind variable is problematic too fro big volume data, as the DB needs to read each value to match it against the expression. The result also differs from the desired as names like ‘Kochhar’ are found too.

Normal 'contains' criteria - Wrong result

Normal 'contains' criteria - Wrong result


The very popular web side Ask Tom has plenty of threads discussing this.

The sample workspace contains this criteria and a mixed criteria to show that you can mix normal criteria and the special criteria in one criteria group. Feel free to play with these cafeterias too.

The technique shown here can be used for almost any other SQL where clause which is not part of the ViewCritera editor (e.g. you want to call a pl/sql function as part of the ViewCriteria).

Using diferent VOs for Master Detail Navigation (the Declatative Way)

A user on the OTN forum asked a question how to do a master detail like navigation where the master VO is not equal to the detail VO and no accessors or link is available between the tow VOs.

A use case for this scenario is e.g. you have a read only table as master which holds an attribute which is the foreign key to an other table (the master table has a FK to the detail you like to change). In the sample I’m talking about in this blog I used the HR schema, the employees table as master and the the department as detail. I show how to use the employees as read only table, select an employee to edit the department the employee is assigned to.

Here is the data model of the sample:

Data Model

Data Model


As you can see there are no view links defined which could be used to navigate from the employee to the related department.

I’ll do all this the declarative way, so I don’t use a bean or other Java code. I use a bounded task flow and start with a query panel with the read only employees table. Each row shows the id of the employee, the name and the department id. I add a button to the department id of each row and use this to navigate to the departments edit page. Here you see the running app, the query panel which I used to select employees records and the button which I added to the department is column.

Start Screen

Start Screen

I used a button here because of an error in this version (11.1.2) of jdev which prevent the table from selection the current row when you just hit a link in a row. Frank Nimphius provided a workaround for this here:JDeveloper 11.1.2 : Command Link in Table Column Work Around. A click on the ‘Department’ button for ‘Jannette King’ will navigate to Department ’80’ which is editable

Select a Department from the Table and Edit Department

Select a Department from the Table and Edit Department

The work flow is implemented as shown below:

Work Flow

Work Flow

As you see the whole work is done in bounded task flow which first presents the query panel together with the resulting employees table (read only). The column ‘Department ID’ shows the button I use to navigate to the editable departments page. As there is no view link, it’s not enough to select the employees row to mark it as current row. I have to extract the department id from the selected row and use this to search for the department before showing the departments edit page.

I store the department id in a page flow scope variable named ‘#{pageFlowScope.depKey}’. If you like you can store the value of the department id elsewhere e.g. in the variables iterator of the page binding. To extract and store the value I use a af:setPropertyListener which allows to react on the action of the button and transfer the value to page flow scope variable. Here is the code of the department id column:

                            <af:column sortProperty="#{bindings.EmployeesView1.hints.DepartmentId.name}"
                                       sortable="true"
                                       headerText="#{bindings.EmployeesView1.hints.DepartmentId.label}"
                                       id="resId1c4" width="114">
                                <af:outputText value="#{row.DepartmentId}" id="ot5">
                                    <af:convertNumber groupingUsed="false"
                                                      pattern="#{bindings.EmployeesView1.hints.DepartmentId.format}"/>
                                </af:outputText>
                                <af:commandButton text="ShowDepartment" id="cb2" action="showDep">
                                    <af:setPropertyListener from="#{row.DepartmentId}"
                                                            to="#{pageFlowScope.depKey}"
                                                            type="action"/>
                                </af:commandButton>
                            </af:column>

The button action navigates to he method call ‘SetCurrentRowWithKeyValue’ in the bounded task flow. This method I dragged from the data control palette from the DepatermetnsView1 operation onto the bounded task flow definition page

SetCurrentRowWithKeyValue from DepartmentsView1

SetCurrentRowWithKeyValue from DepartmentsView1

The method searches the department using the the value stored in the page flow scope variable. The dialog below opens automatically when you drop the method on the task flow and lets me enter the key value to search for:

setCurrentRowWithKeyValue  Edit Action Binding

setCurrentRowWithKeyValue Edit Action Binding

Here is the pagedef file for the method call:

PageDef of setCurrentRowWithKeyValue Method

PageDef of setCurrentRowWithKeyValue Method


After the search the current row is set in the DepaertmensView1 and I can navigate to to the edit page. That’s about it.

You can download the sample work space from here Sample Workspace blogmasterdetaildeclarative_v2-zip. You have to rename the file to ‘.zip’ after download!

Validate Data before Export via af:exportCollectionActionListener or af:fileDownloadActionListener

ADF rich faces offer a nice and easy feature to stream data to the client (e.g. Excel) using the af:exportCollectionActionListener or af:fileDownloadActionListener component. Both of the components get the output stream from the response, so the application an add the data.
One problem is that the two components fire before the application has a chance to validate other data on the page or do some other needed work.
To overcome this shortcoming you can implement the trick I’m outlining in this blog. The idea is to use a normal af:commandbutton or af:commandToolbarButton on the page which calls an actionListener in a bean. In there you can validate other page data or do some other stuff in the model, and then queue an event inside the bean method to call another invisible button on the page which has the af:exportCollectionActionListener attached.

As it turned out (thanks Jiandong Xin for pointing it out), there is a problem if the button we queue the action event to has a client behavior tag attached. This is the case for af:exportCollectionActionListener or af:fileDownloadActionListener. These tags don’t work properly if we only queue an event to the parent button. As Jobinesh pointed out in his blog we need to insert a JavaScript function into the page which handles the event queuing from JavaScript and call it from the bean. This way we are able to set the needed parameters (e.g. not to wait for a response).

Now lets implement this: Lets start with a toolbar button which resides on a panel collection holding the table we want to export. The button has a binding to the bean (binding=”#{exportBean.exportCollectionButton}”) to make it easier to call it from the bean. If you don’t like to bind the button to the bean, you can search for the component by name inside the action listener we implement below. The page contains the custom handler (customHandler(event)) which we call from the bean method. This handler then queues the event to activate the button which starts the file download. The connection between the customHander and hte commandToolbarButton is the ID of the commandToolbarButton (“ctb1”). You have to change this if your button has a different ID.

<af:resource type="javascript">
  function customHandler(event){
    var exportCmd = AdfPage.PAGE.findComponentByAbsoluteId("ctb1");
    var actionEvent = new AdfActionEvent(exportCmd);
    actionEvent.forceFullSubmit();
    actionEvent.noResponseExpected();
    actionEvent.queue();
  }
</af:resource>
<af:panelCollection id="pc1">
  <f:facet name="menus"/>
    <f:facet name="toolbar">
      <af:toolbar id="t2" binding="#{exportBean.toolbar}">
        <af:commandToolbarButton text="Export..." id="ctb1"
            binding="#{exportBean.exportCollectionButton}"
            visible="false">
          <af:exportCollectionActionListener type="excelHTML" exportedId="t1"
              title="Export"/>
        </af:commandToolbarButton>
...

The vital part is that the visible property is set to “false”, so that the button will not show up on the page, but is fully functional. Somewhere else on the page (or even on the same toolbar) we have an with an action listener pointing to a bean method (exportBean in the sample). This button is visible and used to initiate the export.

...
<af:commandButton text="export via bean" id="cb8" 
    actionListener="#{exportBean.exportprgActionListener}"/>
...

The exportBean actionListener looks like this

    // toolbar button with export listner attatch bound from page
    private RichCommandToolbarButton exportCollectionButton;
...
    public void exportprgActionListener(ActionEvent actionEvent) {
        // Add event code (validation or other) here...

        // queue the event via a JavaScript inserted into the page
        FacesContext context = FacesContext.getCurrentInstance();
        ExtendedRenderKitService erks =
        Service.getService(context.getRenderKit(), ExtendedRenderKitService.class);
        erks.addScript(context, "customHandler();");
    }

In the action listener above you can validate other data on the page or call service methods in your application module before starting the export, or cancel the export if you like. The export runs as if you click the af:exportCollectionActionListener directly.
You can download a sample workspace BlogFileDownLoadTest.zip
After download remove the ‘.doc’ suffix!

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.