dinsdag 2 oktober 2012

OOW & JavaOne 2012: Thursday

Sunday - Monday - Tuesday - Wednesday - Thursday

 

HOL9967 Developing Applications for Mobile iOS and Android Devices with Oracle ADF Mobile: Hands-on Lab

Nice hands-on using the not-yet-available JDev R3 with the ADF mobile plugin.  Nice to see that we got rid of the Trinidad components and the simplified development and deployment architecture.
To get the rumors out of the way: they are still using the PhoneGap solution to interact with the device capabilities.

Very good news is the general availability of the solution.  Now this is targeted within 3 weeks.  Really looking forward to that.  To keep up to date, follow the ADF Mobile blog on http://blogs.oracle.com/mobile.

Oracle Usability Lab Tour

This was not a traditional session, but we were able to go to HQ of Oracle and see how the usability team is tackling the different challenges.  Nice to see is the amount of work they are doing and growth of the team itself.  Now you have people looking after the applications, fusion applications and even middleware solutions.  Also the developer tools are being monitored.
The coolest demo was off course the eye-tracker.  It keeps track on the focus of the eyes to determine how people look at pages when searching for information.  This information is then used to make the screen of the products more user-friendly.

We were back @5pm and that was then our last action @OOW12.
Hopefully the ready was interesting and we are looking forward to the release of all this great new products and features from Oracle.

If you still hungry for more information on OOW12, please join us @OracleExperienceDay.  Hope to see you all there.

OOW & JavaOne 2012: Wednesday

Sunday - Monday - Tuesday - Wednesday - Thursday

 

CON2425 Do It Yourself: Custom JavaFX Controls

It is always a good idea to start your day with an impressive demo of a "cool" technology.  Again an hour of impressive demo's.  One thing is sure, I really need to start getting into it.
The speaker talked about the different ways of creating your own JavaFX controls.  Looking at the result, it is really worthwhile.
Ending the hour with some very good tips:
  1. Use cache and cachehint
  2. Tricky effects: set the animation on the group, not on the shape
  3. Visualizations
  4. Read-only properties
  5. Use Scenic View: a separate tool for debugging your code and the JavaFX Components
  6. Use FxExperience tools: easy tool, allowing you to visually create your own styelsheet or to inspect an existing stylesheet.
  7. Get the source of the components.  
  8. JFXtras project: good resource for examples and a place where you can share your components with the community.
  9. Use FXML for design, not for animations

CON3870 What's New in JSF: A Complete Tour of JSF 2.2

Nice to hear that JSF was already present on the JavaOne2001 and that today it is used everywhere on the world, even Antarctica.
This new version tries to restate the scope of the features on JSF, between the server side and the client side.
They do not foresee any big releases anymore, like happened with the 2.0 release.  Off course, who can look into the future :-).
A small overview of the different new features:
  • HTML5 friendly markup support
  • Faces Flows: are like modules of pages.  Being an ADF developer, this sounds very familiar.  The need thing here is the fact that you can declare this flow in java or in xml.
  • Cross site request forgery protection
  • Load facelets via resourcehandlers
  • FileUpload component
  • Multi-templating
A bit strange to look at in the beginning, is the combination of writing pure HTML5 code and embed JSF attributes in them.  So you can do things like : <input type="color" jsf:value="#{requestScope.MyBean.colorValue}".  Once you are using this kind of construct, the standard input-component will be transformed into a JSF component.
Another cool concept is the ClientWindow, it maps to the browsers view and covers multiple view node (=pages).
Another feature is the viewactions.  You can declare an action and define when it should be executed, like after loading a page or during load or before load.  Really something that could be helpful in the ADF solution also.

CON9013 Best Practices for Extending Oracle Applications with Oracle WebCenter Portal

Nice to have again a typical Igor Polyakov session: a lot of very interesting information, even for seasoned webcenter  people.
WebCenter Portal is mostly used for application dashboarding and self-service environments.  These kind of applications rely heavily on integration.  Here are the different integration possibilities:
  • Markup Integration: this means integration on the glass.  It has a quick ROI and very little development effort.  Possible markup integration methods are:
    • WSRP Portlets
    • ADF Taskflows
    • Pagelet Producer: this a product of the WebCenter stack allowing you to extend existing applications or render existing applications as pagelets that can be used in portal environments.
  • Data Integration: here we are not integration UI, but the data sources themselves.  This means that you will need to create a new UI on top of the existing data sources.  Also here we have different possibilites:
    • Through API's: you are using web services or connect directly to different data sources.  On top of these you will need to create your UI, this can be done by ADF Taskflows, portlets or business mashups.
    • BI Integration: instead of going directly to the database, you can use the BI Presentation Services to deliver you pre-calculated information.  This can be done through BiReports and Dashboards.
    • BPM Integration: you can make use of the BPM Process Portal, which is integrated in your WebCenter Portal solution.  You can also make use of the BPM Human Tasks integration points.
    • Service Access Layer: is a new product which is going to be released in PS7 somewhere next year.  It is a solution that allows for separation of data gathering and data visualization, very comparable with the setup you do for a BiPublisher Report 11g.  How to work with this product:
      • Domain experts will need to address the applications integration challenges and will need to create the necessary SQL, WS or REST artifacts.
      • With these artifacts, one can create reusable data provider.
      • There will be OOTB data providers and you will be able to create your own.
      • These data providers will be exposed as REST endpoints, allowing different technologies to make use of them.
      • Now business users can use the new Data Presenter, which is a wizard driven development tool allowing users to create rich ui's based on the data providers.  All @runtime!!

CON9440 Mobile Enablement of Oracle Fusion Applications with Oracle Fusion Mobile Development

Welcome to the new buzz-word for Fusion Applications: TAP.  The name is not an abbreviation, but simply referring to the way one works with a tablet; through tapping on the device.
It has become a nice clean app with simple and consistent UI's.  For the application world, this is really a game changer, the technology world was already aware of these capabilities.
For Oracle mobility is all about true flexibility, getting things done.  It is not the purpose to recreate CRM on the tablet.  This application should really fit in the way you live and work.  Meaning when and where you can work and what kind of actions you perform the most.  It should increase your organization's velocity, not slowing momentum down.

What are the key capabilities of this TAP product:
  • Because it is available on a tablet, the application is always on. You don't need to wait for it.
  • There is a TAP composer, allowing you to define the layout of the tap application.
  • It has off-line capabilities, allowing you to work wherever there is no internet connection.  The way this works, is by caching everything you touch will you are on-line.  So once you are off-line, the same information is still available.
  • Possible deployments:
    • Cloud apps for mobile web browsers: not yet there, but soon :-)
    • Cloud apps for tablets: native apps
    • Cloud apps for smartphones: there are more focused on single applications. Not integration of different applications, like with TAP
  • It tries to give you the functionality you need depending on your role in the company
  • Productivity amplified: Live - Work - Connect: which is the key principal!
  • It is only available for cloud based solutions.  So you can not connect to your Fusion Applications running on-premise, for the moment.
  • You can download it right now from the Apple Store and play with.  When you open the application, you have the possibility to login or to use test data.  Use the latter if you just want to play around and you do not have a Fusion Application SAAS service running.
  • The whole idea is to combine different Fusion Applications into one single tablet app: TAP. No matter from which domain the information needs to come, it will be shown in the same app with the same UI controls.
  • It is designed for business users, who can access business information with it and transact on it.
  • License: you need a Fusion Cloud application license, this include the use of the TAP application.
  • They are still looking for early adapters.  So if you are interested, let them know.

CON8952 BPM: An Extension Strategy for Enterprise Applications

A good overview on the possible integration points between the Oracle Enterprise applications, like Siebel, eBusiness Suite, PeopleSoft, ... and the Oracle BPM product.  For best practices, visit their best practices page on http://www.oracle.com/technetwork/topics/index-096924.html.
Nice to see is that there is already a Belgium reference case: FN Herstal.  Who are using Oracle BPM for their Order2Cash Project, together with the Oracle Business Rules product.

OOW & JavaOne 2012 : Tuesday

Sunday - Monday - Tuesday - Wednesday - Thursday

 

KEY10723 Oracle OpenWorld Keynote:Oracle and EMC

This was the traditional Keynote of Thomas Kurian.  The main theme was also here the Cloud.  He gave a little more detail as Larry, but unfortunately nothing more.  Also a big drawback, was the fact that the demo's were simple powerpoint presentations.
One new information was the fact that by the end of the year, we should have a preview edition of the cloud services Collaboration and Analytics.

HOL10217 Getting Started with Oracle Java Cloud Service

This hands-on-lab started with a negative announcement: the lab environment was not available anymore.  Some problems occurred during the night.
With every negative force, there must be a positive one.  So we got a very nice demo and the possibility to ask any questions we wanted.  Hence the vast amount of information for this session.

For the use of the cloud services, the development tools of Oracle (JDeveloper, OEPE, NetBeans, SQLDeveloper) will get a new "plugin" for easy connection with your cloud service.  These special editions can be download from the cloud website.  Just follow the Resources - Download links on the cloud service page.

You can create as many trials as you want, certainly for the first couple of months.
Be aware that this is PAAS, not IAAS.  This means that you can not stop the clock.  With IAAS you can stop your environment and you do not need to pay anymore.  With PAAS, your environment is always running.  Once you stop it, it is gone.
Oracle has foreseen the concept of geo-locations.  This mean, that you can define where in the world you want to run your service.  Be aware, that the identity service runs per geo-locations.  Meaning you can not share your identities over geo-locations.  Hence, make sure that the services that need to work with each-other are running in the same geo-location.

The hardware setup for the database and java service is as follows:
  • The database service is based on a RAC based database running on ExaData machines.  Oracle is running a couple of databases on these machines.  But, according to them, they assure schema isolation, so no database isolation like Larry mentioned before.
  • The java service, which is composed of the WebLogic Server, runs on ExaLogic machines.
in this kind of environment it is not important to know on what the services are running, but instead knowing the SLA's that Oracle is setting forward.  An example of this, is the fact that Oracle will guarantee that your applications keep on running even after an upgrade done by Oracle.  This means that Oracle needs to make sure that it keeps there products backward compatible.

For the moment, the concept of friendly URL's isn't implemented yet.  The problem is the fact all URL's are SSL enabled and Oracle can only act as a CA for the oracle.com domain.

Once your java service has been activated(=instantiation of your environment) , you have 4 portals at your disposal:
  • My Accounts: allowing you to buy more services
  • My Services: portal for the service owner.  Also here you will get the notification of Oracle when they are going to upgrade your environment.
  • Identity Console: managing your users in the cloud
  • Service Instance Console: you have one console for each service instance.
In your environment, you have 2 kind of loggings.  One is the Job log, this is log for everything you ask Oracle to do something, like deploy application, stop application, ....  On the other hand you have the Service log, this is the logging of the application server and your applications.

There is a Cloud SDK, allowing you to do everything from the command line.  There is even the possibility to have a "tail" functionality of your log files.  Very cool.

Whenever you do a deployment, the following things happen:
  • Virus scanning of your application and sources
  • Whitelist scanning: looking for forbidden technology, like remote EJB's, unsupported protocols, ...
  • Deployment of your application
When you have different services started, under the same user name, then these services are linked automatically to each other.  For example: your Developer service will know about your java and database service and will have a connection to them declared automatically.  In your java service,you will have a JDBC connection declared automatically to your database service.

ESS11121 Oracle and NetSuite: Thriving in the Hybrid Cloud

Finally my first encounter with Larry's other flagship: NetSuite.  While Oracle is building solutions for the the fortune top 500 companies, NetSuite primary vision is the fortune top 5 million companies.
The solution is based on a single system to run your entire business on.  It is not only cloud enabled, but also internationalized; meaning that different languages, currencies and country specific regulations can live in the same system.
It was a great eye-opener.  Perhaps also a good candidate for the smaller market countries, like Belgium.

CON4644 JavaFX Extreme GUI Makeover

Again a waaauw session on JavaFX.  Very good demo's.  I really need to get my hands on these things.  The session started off with a bit unconventional menu based application.  It looked really impressive, but yet based on really simple building blocks like the viewport.  Again, CSS development is key here.  Really check out these demo's, they should be available after JavaOne on the presenters blog.

KEU10724 Oracle OpenWorld Keynote: Oracle and Infosys

In this second keynote of Larry, we saw a bit of the same over again.  It is clear that this OOW is all about Cloud Computing, Fusion Applications and Mobile development.
Here are few of the key points, that I take back from this session:
  • Fusion Applications (FA) is a complete suite, not a point implementation
  • FA is based on best in class platform (a bit of marketing here :-))
  • Apparently already 400 FA Cloud customers
    • CRM(38%), ERP(23%), HCM(39%)
    • On Premise(26%), On Demand(9%), SAAS(65%)
    • EMEA(23%), APAC(10%), America(67%)
  • It is very easy to move your apps between the different solutions, like on premise, on demand and cloud
  • FA is off course based on the FMW and DB technologies
  • According to Larry, data privacy should be put at the VM architecture or using the Oracle 12c multitenant DB layer.  But certainly not in the application layer.
  • Oracle is the only one who have build their social solution as a platform and not as a suite of applications.  This allows them to put social functionality in all of the solutions based on FMW.

CON8901 Optimize Enterprise Business Processes with Oracle WebCenter and Oracle BPM

This session gave a simple overview of the different features of the product set.  Nice to see, clean demo, but no best practices on how to handle this.  But again, very nice to see the integration between the different Oracle products.

OOW & JavaOne 2012: Monday

Sunday - Monday - Tuesday - Wednesday - Thursday

 

CON6234 Do You Really Get Class Loaders?

Good session on not only the way classloaders are working and how many there actually are, but also on what situations you can get yourself into as a developer and how (not also) to solve this.  The use of real examples and naming the different type of exceptions and errors possible in a certain situation, was well received.
What was new for me :
  • Normally a classloader checks first the parent classloader and then his context in searching for a class.  Except the WAR-classloader, he checks first his own context and then calls out to his parent classloader.
  • You can get the URI of the class that is being loaded.  Doing this shows you from where the class is really loaded.
  • Nice help is the "-verbose:class" jvm attribute and the "javap -private MyClass" command to help you understand how the classloaders are loading your class
  • The full classname is build up from the Class name and the Classloader name, the same goes for the packaging.  This means that when different classloaders are loading classes from the same package, you can get into trouble.
  • Classloaders are build for applets, not application servers (according to the speaker).  Hence the different kind of problems you can run into.
What I'm not sure about, is the fact whether all JVM's do this in the same way.  But at least, if(when) something goes wrong, you know where to look for.
One really clear message he had for all of us: never trust your assumptions. Always verify them.

GEN9433 General Session: Oracle Fusion Applications - Overview, Strategy and Roadmap

A really packed session.  I counted 828 chairs, not one was free when the session started.
The strategy of Apps remains the same as it was years before:
  • Continued investment in the "old" applications (Siebel, eBusiness Suite, PeopleSoft, ...)
  • Combine both the "old" apps with the new Fusion Applications.
  • Or go for the full suite.
The objectives of Fusion Apps:
  • User Experience : Intelligent, Social, Mobile
  • Innovation : Easy extensions, Upgrade friendly, Standards base
  • Deployment : Incremental, Cloud, Engineerd
I still got the feeling they have some work to do on these objects :-).

Release 5 of 11g is coming out this or next month.

Something new, that I wasn't expecting to hear, was the fact that you are able to get information from the "social  network" sites on the internet, like Google+, LinkedIn, Facebook, discussion forums, on your brand.
There are 4 area's of personalization in the Fustion Apps:
  1. BI Perspective: changing graphs
  2. Application Composer: change business objects and logic
  3. Process Composer : change the business processes themselves
  4. Page Composer : personalize the pages themselves
They also have there mobile solution ready.  It is based on ADF Mobile (which itself is not available yet), allowing them to run on browsers, native apps and smarphone apps.  In this solution they take the ADF Mobile approach of having ADF UI and then using the REST SDK to call out to the REST API's of the Fusion Apps.

What does the future holds:
  • More Localization
  • More Mobile
  • More Industries
  • More Power (Exa-ranges)
  • More Configurability
What's coming in Release 5:
  • Time & Labor
  • Social Marketing
  • Resource and Project "Management"
 Your choice:
  • Continuee on your current path ("old" apps)
  • Adopt a Co-Existence Solution
  • Embrace the Complete Suite

GEN11418 General Session: Overview of Oracle's Public Cloud Strategy

They see a shift in the Cloud offerings from a "capacity cloud" to a "capability cloud".
Famous quote : "Think big, start small, fail fast, scale soon".
Technology trends:
  • Globalization
  • Big Data
  • Modernization
  • Mobility
  • Social Interactions
I believe these were the same last year also :-).
You have to look at cloud as a key enable of choice between service delivery (IAAS, PAAS, SAAS) and service deployment (private, hybrid, public).

IAAS offering: Storage, Compute, Secure Identity, Cache, Queues, Messaging services
PAAS offering: DB, Java, Developer, Mobile, Collaboration and Analytics services and Application Store.  These PAAS offering is based on the use of the IAAS offering !!
And PAAS itself is fully integrated with their SAAS solution.
On the SAAS side, much effort is done on the Social part of the cake, in terms of Social Marketing and Social Campaign.

My colleague will have more in depth information on this session.

CON8914 Oracle Coherence: past, present and future

Very nice overview on the history of Coherence.  A clean picture on the evolution of the product over the years.
Currently Coherence is focusing on the on-premises and cloud adoption.  In the whole Oracle FMW stack, Coherence is suited in the Oracle Cloud Application Foundation.  In the context of the Exa-machines, what important is to Coherence here is the Infiniband network, which reduces the time to recover a node by 1/16th.

Now that we know where we are coming from, let's see where we are going to.
Coherence 12c (12.1.2) will be expected somewhere next year (how very precise :-)).  The fact that Coherence got now a FMW numbering, remember they are coming from 3.7.x), signifies the importance of this product in the entire FMW stack.
Here are the themes for this release:
  • Database sync: use of the Goldengate adaptor to sync changes in the database with the grid.
  • Configuration and Usability Improvements
  • One programming model for all events (triggers, backing maps, ...).  Curious how that would like and how they would make sure all existing applications on Coherence wouldn't break.
  • Configuration Modernization
  • Asynchronous backups: speed vs consistency.  Possible use-cases: session management (apps servers are working like this also) and when you have big processing to be done when setting a value, like a Ticker feed.
  • Backup Management improvements.  This talks about the backups of your primary objects and backups above 1.  These weren't always assured.  They will also add rack- and server-safe backups.  Now only the primary objects had this feature.
  • Exabus Improvement
  • Install, Upgrade and Patching: they are going to use the OUI Installer for production release and a Quick Installer for development releases.  For patching they will be using OPatch.
    Oh my God!!!  I believe this was the pay off to have a FMW numbering :-)
  • Managed Coherence Servers being able to make use of the GAR (grid archive file)
  • Maven support
  • Execution Context ID (ECID).  This is something really cool.  Other FMW components had this already.  It is a unique id for a request throughout the entire FMW stack.  This enables you to follow the request from WebServer to Database and Coherence in between.  Very nice feature for debugging and impact analysis.
  • Dynamic Thread Pool Sizing for Proxy Servers.
  • OSGi support via Library bundling
  • Enterprise Manager 12c
  • OEPE support
  • Coherence Incubator
What's coming after 12c (initial release, except for everything that didn't went into the first release):
  • Cache Persistence: this feature will allow you to dump the cache objects onto discs and load it backup again after a crash or when you had data loss in the grid. 2 approaches : per node (very scalable) or by a network drive (less scalable).
  • Federated Caching: this actually the inclusion of a Coherence Incubator pattern in the product with some enhancements to it.  Allowing you to easily setup an Active-Active, Active-Passive and Hub&Spoke configuration.

CON4038 Project EASEL: Developing and Managing HTML5 in a Java World

Impressive project of the NetBeans people.  You can test it using the NetBeans 7.3 Beta release.
It is all about a client-side project and JQuery knowledge in the editor.  It gives you a very nice tight integration between the browser and your IDE.  Selecting something in the browser (with the install of the NetBeans plugin) will set the focus in the IDE to this component and viceversa.
Again, very impressive.

Nice after thought: there is a big change that this feature will find his way also into JDeveloper.  Thanks a lot for that folks.

BOF4279 In-dept layout and styling with the JavaFX Scene Builder

Nice overview of some techniques to take into account when working with the JavaFX Scene Builder.  There is already a preview version of the 1.1 available, worth while to test it out.

BeNeLux Architect Event @Jasper's

I traded in 3 sessions for this event and it was a good descission.
We had the opportunity to talk to the Oracle experts on different domains, like database, WebLogic Server, ADF, SOA, WebCenter (thanks to Yannick) and the applications.  Very good admosphere and I had many good and open conversations with the pm's.
Also nice to know that there is still a place for me @Oracle.  Thanks folks, very much appreciated.

zondag 30 september 2012

Overview unconventional sessions @OOW12 & @JavaOne

Hello everyone,

also this year I've received the opportunity to visit the biggest Oracle event of the year, namely Oracle OpenWorld.  According to some figures, it will be a very big event.  Hopefully I can hook up with some ex-Oracle colleagues and find out the nice nasty details on their roadmaps.

In this blog I'll keep track on the session I follow.  Hopefully it will become very interesting reading.
So keep track on this blog to find out the latest details.
Since there are too many sessions @OOW, I have a colleague doing the same thing. Visit his blog for more information.

 

Sunday - Monday - Tuesday - Wednesday - Thursday

 

UGF10577 Oracle WebLogic Server Overview

Very, very high level overview of Fusion Middleware.  Only 1 slide on WLS itself.  Very much talk on Fusion Middleware parts like SOA, WebCenter, OBIEE, BPM, Identity Management, ...

UGF10401 Oracle WebCenter Content, Oracle WebCenter Sites and the Oracle WebCenter Spaces features.  Which one is right for you?

A good session on the ever lasting question: which one of the 4 site building products of the WebCenter stack should I use.
I'll skip the individual product feature set, more on that on the Oracle Experience Day.
Question you should ask:
  • Who will be using this site : employees, partners, customers
  • What are these users trying to accomplish?
When to use what?
  • WebCenter Portal & Spaces : intranet - Oracle Look&Feel
  • WebCenter Sites : dot com sites - light weight => very scalable
  • WebCenter Content: use always
  • Exception: Partner Extranet : Sites or Portal => look for strenghts in dev team
How to use them together?
  • Content & Portal => Content Presentor TaskFlow
  • Content & Sites => One way connector => read-only
  • Portal & Sites : Pagelet producer & Business Mashups
Join me at the Oracle Experience day( #oracleopenxperience ) for more in depth information.

UGF10362 Netbeans and JavaFX

Waauw, there is really not other word for the things I saw in this session.  Amazing graphics being used, developed in JavaFX but used in Swing clients, NetBeans platform based applications and in other JavaFX client applications.
As you may know, running a standard Swing application on an iPad is, ...  just leave at impossible.
But what you could do is develop it with HTML 5, that runs virtually everywhere.  Counterpart of this is that you would have 2 code streams to manage.
Solution: build your graphical app in HTML 5, run it within JavaFX components (WebView) and show this JavaFX component in your Swing client.

The only open question I had was : what amount of JavaFX code is needed to get this working.
But at least this session showed me that the possibilities with JavaFX are almost infinitive.

UGF10414 Oracle Fusion Middleware Roundtable

No Comment

UGF10397 To Exalogic or not to Exalogic: An Architectural Journey

Nice overview on the road of actions they took to come to a decision to buy ExaLogic.
Unfortunately, the deal didn't go through :-(.

UGF10400 Oracle Enterprise Manager 12c: Monitoring, Metric Extensions and Configuration Best Practices

Fully booked room, this was a first one.  It may be because, this was a DBA session.
The speaker had a very good knowledge on EM 10g-11g-12c.
Key takeaways:
  • Metrics Extension: use pl-scripts to create your own metrics
  • SQL Monitor
  • ASH Analytics: the future of "Top Activity"
  • LoadMap: to indicate the importance of tuning some sessions

KEY10721 Oracle OpenWorld Welcome Keynote: Oracle and Fujitsu 

Starting with the Fujitsu keynote, we see that they are doing a lot of the same thing that Oracle does with their integrated systems.  Not so innovative.  What they do well, is presenting this as part of our day-to-day live.

Following was the keynote of Larry on Cloud and ExaData.
The following main topics were touched:
  • Cloud = SAAS + PAAS + IAAS
  • Announcement 1 : Oracle Cloud: now also with IAAS.  A bit of a strange announcement, since we are still waiting on the other parts of the Oracle Cloud solution, which were promised last year.
  • Announcement 2 : Oracle Private Cloud.  Which is the same concept as the Oracle Cloud, except for the fact that the hardware will be placed on-premise, behind your firewall.  Just wondering what openings are needed in the firewall to allow Oracle to manage their (because you only rent and pay a monthly fee) machines.
  • Announcement 3 : Oracle Database 12c for 2013.  A multitenant DB through the construct of a "Container Database".
  • Announcement 4: ExaData X3 with an impressive 26TB of DRAM & Flash and a 10x compression rate
  • Announcement 5: ExaData X3-2 Eight Rack 

 

dinsdag 18 september 2012

ADF BC: Logging to the essentials

Challenge

You want to be able to see all the sql-statements and DML-statements that your ADF application is executing.  But in contrast to the previous blog, I only want to see the statements themselves, not clutter information.

Context

JDeveloper & ADF : 11.1.1.5.0
OS: Windows 7

Solution

In this previous blog, we examined already different options.  Here we will focus on the using the base classes for ADF BC to render the information we need.
To get this working, we only 2 base classes : the EntityImpl and ViewObjectImpl base class.

Here is the code for the EntityImpl class:
package be.contribute.demo.model.framework;

import java.util.ArrayList;
import java.util.List;

import oracle.adf.share.logging.ADFLogger;

import oracle.jbo.server.AttributeDefImpl;
import oracle.jbo.server.EntityImpl;

import org.apache.commons.lang.StringUtils;


public class BaseEntityImpl extends EntityImpl {
    protected static final ADFLogger LOGGER =
        ADFLogger.createADFLogger(BaseEntityImpl.class);


    /**
     * Overwriting the buildDMLStatement to be able to show the dml statement in the logging.
     * Only in DEBUG mode, the logging will be activated
     * @param i
     * @param attributeDefImpl
     * @param attributeDefImpl2
     * @param attributeDefImpl3
     * @param b
     * @return
     * @writer Filip Huysmans
     */
    @Override
    protected StringBuffer buildDMLStatement(int i,
                                             AttributeDefImpl[] attributeDefImpl,
                                             AttributeDefImpl[] attributeDefImpl2,
                                             AttributeDefImpl[] attributeDefImpl3,
                                             boolean b) {
        StringBuffer returnValue =
            super.buildDMLStatement(i, attributeDefImpl, attributeDefImpl2,
                                    attributeDefImpl3, b);
        if (LOGGER.isFinest()) {
            loggingDML(returnValue, attributeDefImpl);
        }
        return returnValue;
    }

    /**
     * This method will call sub methods to gather the necessary information to show
     * the logging.  Depnding on the type of dml a different method is called.
     * This method will actually show the parsed statement in the logging
     * @param dmlStatement
     * @param attributeDefImpl
     * @writer Filip Huysmans
     */
    private void loggingDML(StringBuffer dmlStatement,
                            AttributeDefImpl[] attributeDefImpl) {
        if (dmlStatement != null) {
            String logDMLStatement = dmlStatement.toString();
            if (logDMLStatement.startsWith("INSERT")) {
                logDMLStatement =
                        loggingINSERT(dmlStatement, attributeDefImpl);
            } else if (logDMLStatement.startsWith("UPDATE")) {
                logDMLStatement =
                        loggingUPDATE(dmlStatement, attributeDefImpl);
            } else if (logDMLStatement.startsWith("DELETE")) {
                logDMLStatement =
                        loggingDELETE(dmlStatement, attributeDefImpl);
            }

            LOGGER.finest("Doing DML : " + logDMLStatement);
        } else {
            LOGGER.finest("DML statement was NULL");
        }
    }

    /**
     * This inner class is used to store information needed for the logging
     * @writer Filip Huysmans
     */
    private class LoggingInfo {
        private final String columnName;
        private String bindParam;
        private Object value;

        public LoggingInfo(String columnName) {
            this.columnName = columnName;
        }

        public LoggingInfo(String columnName, String bindParam) {
            this.columnName = columnName;
            this.bindParam = bindParam;
        }

        public void setBindParam(String bindParam) {
            this.bindParam = bindParam;
        }

        public void setValue(Object value) {
            this.value = value;
        }

        public String getColumnName() {
            return this.columnName;
        }

        public String getBindParam() {
            return this.bindParam;
        }

        public Object getValue() {
            return this.value;
        }
    }

    /**
     * This method will search for each of the entries of the list, the values
     * for the attributes.  This value will then be added to the LoggingInfo object.
     * @param list List with LoggingInfo objects where the columnName is already filled in
     * @param attributeDefImpl
     * @return List with LoggingInfo objects containing the columnName and values
     * @writer Filip Huysmans
     */
    private List searchValues(List list,
                                           AttributeDefImpl[] attributeDefImpl) {
        // For each of the columns search the value and replace the bind param with this value
        if (list != null && !list.isEmpty()) {
            for (LoggingInfo li : list) {
                // Find the attribute that correspond to this attribute
                if (attributeDefImpl != null && attributeDefImpl.length > 0) {
                    for (int k = 0; k < attributeDefImpl.length; k++) {
                        AttributeDefImpl attribute = attributeDefImpl[k];
                        String attributeColumnName =
                            attribute.getColumnNameForQuery();
                        attributeColumnName =
                                StringUtils.split(attributeColumnName, ".")[1];
                        if (attributeColumnName.equals(li.getColumnName())) {
                            // This is the correct attribute; find the value
                            li.setValue(getAttributeInternal(attribute.getName()));
                        }
                    }
                }
            }
        }
        return list;
    }

    /**
     * This method will replace the bind parameters (like :1) with the corresponding value.
     * The necessary information is gathered from the list parameter.
     * @param list List of LoggingInfo objects containing bindParameter and Value objects
     * @param dmlStatement The string of the statement with the bind parameters intact
     * @return String of the statement with the bind parameters replaced by their values
     * @writer Filip Huysmans
     */
    private String replaceBindParamsWithValue(List list,
                                              String dmlStatement) {
        String returnValue = dmlStatement;
        if (list != null) {
            for (LoggingInfo li : list) {
                // Replacing the bind param with the actual value
                returnValue =
                        StringUtils.replace(returnValue, // The current log statement
                            li.getBindParam(), // The bind param like ':1'
                            li.getValue() != null ? li.getValue().toString() :
                            "null"); // The string representation of the value
            }
        }
        return returnValue;
    }

    /**
     * This method will add the necessary LoggingInfo objects based upon the columnsString.
     *
     * @param columnsString This string must be a sequence of  = , seperated by the seperator.  Ex: "id=:2, name=:5" or "id=:2 AND name=:5"
     * @param list Existing list of LoggingInfo objects
     * @param seperator The seperator that seperateds the different instances of columns in the columnsString
     * @return List of LoggingInfo objects based upon the columnsString and the already existing list
     * @writer Filip Huysmans
     */
    private List addColumnsToList(String columnsString,
                                               List list,
                                               String seperator) {
        String[] setListOfColumns = columnsString.split(seperator);
        if (setListOfColumns != null && setListOfColumns.length > 0) {
            for (int i = 0; i < setListOfColumns.length; i++) {
                String[] column = setListOfColumns[i].split("=");
                list.add(new LoggingInfo(column[0], column[1]));
            }
        }
        return list;
    }

    /**
     * This method is used in the case of an INSERT statement.
     * @param dmlStatement
     * @param attributeDefImpl
     * @return
     * @writer Filip Huysmans
     */
    private String loggingINSERT(StringBuffer dmlStatement,
                                 AttributeDefImpl[] attributeDefImpl) {
        String returnValue = dmlStatement.toString();
        List list = new ArrayList();
        // Getting the list of columns
        String attributeListString =
            dmlStatement.substring(dmlStatement.indexOf("(") + 1,
                                   dmlStatement.indexOf(")"));
        String[] attributeList = attributeListString.split(",");
        // Getting the list of values
        String attributeBindVarListString =
            dmlStatement.substring(dmlStatement.indexOf("(",
                                                        dmlStatement.indexOf("(") +
                                                        1) + 1,
                                   dmlStatement.indexOf(")",
                                                        dmlStatement.indexOf(")") +
                                                        1));
        String[] attributeBindVarList = attributeBindVarListString.split(",");
        // Adding the columns to the list
        if (attributeList != null && attributeList.length > 0) {
            for (int i = 0; i < attributeList.length; i++) {
                list.add(new LoggingInfo(attributeList[i],
                                         attributeBindVarList[i]));
            }
        }
        // Searching the values
        list = searchValues(list, attributeDefImpl);

        // Replacing the bind params with the values
        returnValue = replaceBindParamsWithValue(list, returnValue);

        return returnValue;
    }

    /**
     * This method is used in case of an UPDATE statement.
     * @param dmlStatement
     * @param attributeDefImpl
     * @return
     * @writer Filip Huysmans
     */
    private String loggingUPDATE(StringBuffer dmlStatement,
                                 AttributeDefImpl[] attributeDefImpl) {
        String returnValue = dmlStatement.toString();
        List list = new ArrayList();
        // Getting the list of columns
        String setListString =
            dmlStatement.substring(dmlStatement.indexOf("SET ") + 4,
                                   dmlStatement.indexOf(" WHERE "));
        list = addColumnsToList(setListString, list, ",");
        // Do the same for the where clause
        String whereListString =
            dmlStatement.substring(dmlStatement.indexOf(" WHERE ") + 7);
        list = addColumnsToList(whereListString, list, " AND ");
        // Searching the values
        list = searchValues(list, attributeDefImpl);
        // Replacing the bind params with the values
        returnValue = replaceBindParamsWithValue(list, returnValue);
        // Return the parsed statement
        return returnValue;
    }

    /**
     * This method is used in case of a DELETE statement.
     * @param dmlStatement
     * @param attributeDefImpl
     * @return
     * @writer Filip Huysmans
     */
    private String loggingDELETE(StringBuffer dmlStatement,
                                 AttributeDefImpl[] attributeDefImpl) {
        String returnValue = dmlStatement.toString();
        List list = new ArrayList();
        // Getting the columns of the where clause
        String whereListString =
            dmlStatement.substring(dmlStatement.indexOf(" WHERE ") + 7);
        String[] whereListOfColumns = whereListString.split(" AND ");
        if (whereListOfColumns != null && whereListOfColumns.length > 0) {
            for (int i = 0; i < whereListOfColumns.length; i++) {
                String[] column = whereListOfColumns[i].split("=");
                list.add(new LoggingInfo(column[0], column[1]));
            }
        }
        // Searching the values
        list = searchValues(list, attributeDefImpl);
        // Replacing the bind params with the values
        returnValue = replaceBindParamsWithValue(list, returnValue);
        // Returning the parsed statement
        return returnValue;
    }

    /**
     * This method will parse a statment with '?' by the list of objects
     * This can be used to log custom preparedStatements.
     * @param statement Ex: select id from table where id = ?
     * @param objects List of objects to put in place of the ?.  The order must be the same as the order of the ?
     * @writer Filip Huysmans
     */
    public void logDynamicStatements(String statement, Object... objects) {
        String toLog = statement;
        for (Object o : objects) {
            if (o == null) {
                // When the object is null, replace the ? by the word null
                toLog = toLog.replaceFirst("\\?", "null");
            } else {
                toLog = toLog.replaceFirst("\\?", o.toString());
            }
        }
        LOGGER.finest(toLog);
    }
}

If you see a bizarre line 309, please ignore it!!

Here is the code for the ViewObjectImpl class:
package be.contribute.demo.model.framework;


import oracle.adf.share.logging.ADFLogger;

import oracle.jbo.AttributeList;
import oracle.jbo.Variable;
import oracle.jbo.VariableValueManager;
import oracle.jbo.server.ViewObjectImpl;


public class BaseViewObjectImpl extends ViewObjectImpl {
    protected static final ADFLogger LOGGER =
        ADFLogger.createADFLogger(BaseViewObjectImpl.class);


    /**
     * Overriding the executeQuery method for debug reasons.
     * Each time a query is executed on a view, we show the query,
     * the value of the bind variables and the number of result records
     * @writer Filip Huysmans
     */
    @Override
    public void executeQuery() {
        long start = 0;
        if (LOGGER.isFinest()) {
            showQueryMetadata();
            start = System.currentTimeMillis();
        }

        // Executing the query
        super.executeQuery();
        if (LOGGER.isFinest()) {
            showQueryStatistics(System.currentTimeMillis() - start);
        }
    }

    @Override
    protected void executeQueryForCollection(Object object, Object[] object2,
                                             int i) {
        long start = 0;
        if (LOGGER.isFinest()) {
            showQueryMetadata();
            start = System.currentTimeMillis();
        }

        // Executing the query
        super.executeQueryForCollection(object, object2, i);
        if (LOGGER.isFinest()) {
            showQueryStatistics(System.currentTimeMillis() - start);
        }
    }

    private void showQueryStatistics(long paQueryTime) {
        LOGGER.finest("Query time (ms) : " + paQueryTime);
        // Showing the number of records
        LOGGER.finest("Nbr results : " + getAllRowsInRange().length);
        LOGGER.finest("End ExecuteQuery for " + getClass().getName());
    }

    private void showQueryMetadata() {
        LOGGER.finest("Start ExecuteQuery for " + getClass().getName());
        // Showing the query
        LOGGER.finest("query : " + getQuery());
        // Showing the bind variables
        getParametersAsStorageTypes();
        // Getting the bind variables
        AttributeList attributeList = getNamedWhereClauseParams();
        String[] attributeNames = attributeList.getAttributeNames();
        if (attributeNames == null || attributeNames.length == 0) {
            LOGGER.finest("No bind variables found");
        } else {
            for (int i = 0; i < attributeNames.length; i++) {
                LOGGER.finest("Bind variable : " + attributeNames[i] +
                              " - Value : " + attributeList.getAttribute(i));
            }
        }
    }

    @Override
    public VariableValueManager ensureVariableManager() {
        // TODO Called too many times but restricting execution seems to cripple the functionality.
        VariableValueManager evm = super.ensureVariableManager();
        Variable[] variable = evm.getVariables();
        if (variable != null) {
            for (int i = 0; i < variable.length; i++) {
                String name = variable[i].getName();

                Object value = evm.getVariableValue(name);

                if (value != null && (value instanceof String) &&
                    ((String)value).contains("*")) {
                    evm.setVariableValue(name,
                                         ((String)value).replaceAll("\\*",
                                                                    "%"));

                }
            }
        }
        return evm;
    }

    /**
     * Overriding this method to allow for more complete debug info.
     * @return
     * @writer Filip Huysmans
     */
    @Override
    public Object[] getParametersAsStorageTypes() {
        Object[] object = super.getParametersAsStorageTypes();
        if (object != null) {
            for (int i = 0; i < object.length; i++) {
                Object[] parameter = (Object[])object[i];
                LOGGER.finest("VIEWLINK bindparameter for " + getName() +
                              " : " + parameter[0] + " = " + parameter[1]);
            }
        }
        return object;
    }

}


After creating these java classes, you need to register them within JDeveloper or your project.






Now when you run the application, you would not see the message immediately because we are using the ADFLogger.  Per default no logging is done for our custom classes.  To activate it, just have a look at this previous blog and activate the logging for our base classes.
Now you will get an output like this one:
<BaseViewObjectImpl> <showQueryMetadata> Start ExecuteQuery for ac.spaces.portal.app.model.vo.DepartmentsViewImpl
<BaseViewObjectImpl> <showQueryMetadata> query : SELECT Departments.DEPARTMENT_ID,         Departments.DEPARTMENT_NAME,         Departments.MANAGER_ID,         Departments.LOCATION_ID,         Departments.COST_CENTER,         Employees.FIRST_NAME,         Employees.EMPLOYEE_ID,         Employees.LAST_NAME,         (select 'a' from dual) AS stupid FROM DEPARTMENTS Departments, EMPLOYEES Employees WHERE Departments.MANAGER_ID = Employees.EMPLOYEE_ID
<BaseViewObjectImpl> <showQueryMetadata> No bind variables found
<BaseViewObjectImpl> <showQueryStatistics> Query time (ms) : 3
<BaseViewObjectImpl> <showQueryStatistics> Nbr results : 13
<BaseViewObjectImpl> <showQueryStatistics> End ExecuteQuery for ac.spaces.portal.app.model.vo.DepartmentsViewImpl
<BaseEntityImpl> <loggingDML> Doing DML : INSERT INTO DEPARTMENTS(DEPARTMENT_ID,DEPARTMENT_NAME,MANAGER_ID,LOCATION_ID) VALUES (4,Filip Dept,100,1000)
<BaseEntityImpl> <loggingDML> Doing DML : UPDATE DEPARTMENTS Departments SET LOCATION_ID=null WHERE DEPARTMENT_ID=4
<BaseEntityImpl> <loggingDML> Doing DML : DELETE FROM DEPARTMENTS Departments WHERE DEPARTMENT_ID=4

vrijdag 14 september 2012

ADF BC Logging

Challenge

You want to be able to see all the sql-statements and DML-statements that your ADF application is executing.

Context

JDeveloper & ADF : 11.1.1.5.0
OS: Windows 7

Solution

The most blogged solution is the one where you put on the jbo logging on the level of the jvm.
In this case you just add the following java option to the run configuration : -Djbo.debugoutput=console
While this will give you everything you need, you get a lot of clutter and it is difficult to see the information you are looking for.

Another solution would be to implement some java code in your base classes to show the necessary information.  See the following blog for more information on it.
while this will give you only the information you really need, the code is depending on the de ADF BC framework directly and is not supported to work over different versions.

The solution I came across today, thanks to some forum discussions, is the use of the ADF Logger.
While you just run your application, no special run configuration or debug setting is needed, you can change the log level of the different ADF components.  The change is immediate active, no rerun or stopping of the jvm is needed.
The trick is to find just the one you need.
In case you want to see the SQL and DML statements you need to set the oracle.jbo.common.ADFLoggerDiagnosticImpl to FINEST, anything lower will not show the statements.

How to set this logger level?

Follow this procedure to use the logger level:
  1. Just run or debug your application.
  2. In the Log-pane you should see your application starting up.
  3. In this pane, there is an Action-menu.  Choose here the "Oracle Diagnostic Logging"-option.



  4. This will open a new tab, called "logging.xml".
  5. Now walk through the tree until you find the oralce.jbo.common.ADFLoggerDiagnosticImpl
  6. And then select in the Level column "Finest" or type "TRACE:32"
  7. This change is active immediately
  8. You should see appearing the SQL-statements in the Log pane when you are walking through your application.
While it still generates a lot of clutter, the advantage to activate it at the moment you need it, is really a big step forward.

When you stop and restart the JVM/WLS, just close this "logging.xml"-tab and restart the procedure as mentioned above.

 A nice enhancement feature would be to have an option to only see the SQL- and DML-statements.

maandag 3 september 2012

ADF: Table filters case insensitive and programmatic wildcards

Challenge

When the user uses the filter functionality on top of the ADF tables, every character based columns should be made case insensitive and will need the necessary wildcards.  So when the user adds wildcards, then no extra wildcards are necessary.  When the user doesn't use wildcards, add them programmatically.

Context

JDeveloper & ADF : 11.1.1.5.0
OS:  Windows 7

Solution

Since this is a feature that we want to apply to multiple tables, we are going to build a very generic solution.
To simplify the usage of the solution, we are going to put the necessary java code in a "base"-bean.  The latter is comparable with the base-classes in ADF Business Components.  Every managed bean that needs this functionality, just needs to extend from this "base"-bean.

Here are the different steps to undertake:
  • Create the "base"-bean.

Just create a new java class, or use an existing one.  Like with the base classed of ADF BC, it is best to put this in a seperate application or at least in a different package structure.  But do not put them, the BC and the view once, together.  They always should remain in different projects.
Here is the content of the java class:

package view.framework;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import oracle.adf.view.rich.component.rich.data.RichTable;
import oracle.adf.view.rich.event.QueryEvent;
import oracle.adf.view.rich.model.FilterableQueryDescriptor;

import oracle.adfinternal.view.faces.model.binding.FacesCtrlSearchBinding;

import oracle.jbo.AttributeDef;
import oracle.jbo.common.JboTypeMap;
import oracle.jbo.uicli.binding.JUCtrlHierBinding;
import oracle.jbo.uicli.binding.JUFormBinding;

import org.apache.commons.lang.StringUtils;
import org.apache.myfaces.trinidad.model.CollectionModel;

import view.JSFUtils;

public class BaseBean {
    public BaseBean() {
    }
    /**
     * This method can be used to replace the existing queryListener for a table.
     * It will automatically put the used, char based columns into case insensitive
     * and add the necessary wild cards, when the user hasn't done so already.
     * It assumes that the Iterator name equals the Query name.
     * For example : DepartmentsView1Iterator and DepartmentsView1Query
     * @param queryEvent
     * @writer Filip Huysmans
     */
    public void onQuery(QueryEvent queryEvent) {
        boolean invokeQuery = true;
        List<String> columnsWithExtraWildCards = new ArrayList<String>();
        // pre-processing code here
        // Fetching the necessary objects
        FilterableQueryDescriptor fqd = (FilterableQueryDescriptor)queryEvent.getDescriptor();
        Map<String, Object> map = fqd.getFilterCriteria();
        RichTable rt = (RichTable)queryEvent.getComponent();
        CollectionModel model = (CollectionModel)rt.getValue();
        JUCtrlHierBinding data = (JUCtrlHierBinding)model.getWrappedData();
        String iteratorName = data.getIteratorBinding().getName();
        // Creating the search filter feature of case insensitive
        Set<FilterableQueryDescriptor.FilterFeature> featureSet = new HashSet<FilterableQueryDescriptor.FilterFeature>();
        featureSet.add(FilterableQueryDescriptor.FilterFeature.CASE_INSENSITIVE);
        Map<String, Set<FilterableQueryDescriptor.FilterFeature>> _filterFeatures = new HashMap<String, Set<FilterableQueryDescriptor.FilterFeature>>();
        // Looping through the entire set of attributes
        for (int i = 0; i < data.getAttributeCount(); i++) {
            AttributeDef attributeDef = data.getAttributeDef(i);
            if (JboTypeMap.isCharType(attributeDef.getSQLType())) {
                // this is a string type
                // Get the filter value for this attribute
                String stringValue = (String)map.get(attributeDef.getName());
                // When the user has filled in a search string and didn't use any wildcards
                // add the necessary wildcards
                if (stringValue != null && !stringValue.isEmpty()) {
                    if (!stringValue.contains("%")) {
                        // Adding the wildcards
                        stringValue = "%" + stringValue + "%";
                        map.put(attributeDef.getName(), stringValue);
                        // Adding this column to the list of custom wild cards
                        columnsWithExtraWildCards.add(attributeDef.getName());
                    }
                    // Setting the field Case Insensitive
                    ((HashMap)_filterFeatures).put(attributeDef.getName(), featureSet);
                }
            }
        }
        // Setting the new list of filter features
        fqd.setFilterFeatures(_filterFeatures);
        // Executing the query
        if (invokeQuery) {
            //Finding the name of the searchRegionBinding based on the name of the iterator
            String searchRegionBindingName = null;
            JUFormBinding bindings = (JUFormBinding)JSFUtils.get("#{bindings}");
            List executableBindings = bindings.getExecutableBindings();
            if (executableBindings != null && executableBindings.size() > 0) {
                for (Object o : executableBindings) {
                    if (o instanceof FacesCtrlSearchBinding) {
                        FacesCtrlSearchBinding fcsb = (FacesCtrlSearchBinding)o;
                        // Create the iterator name from the query name
                        String newIteratorName = StringUtils.strip(fcsb.getName(), "Query") + "Iterator";
                        if (newIteratorName.equals(iteratorName)) {
                            // This is the correct SearchRegionBinding
                            searchRegionBindingName = fcsb.getName();
                        }
                    }
                }
            }
            // Executing the query manually
            JSFUtils.invokeMethodExpression("#{bindings." + searchRegionBindingName + ".processQuery}", Object.class, QueryEvent.class, queryEvent);
        }
        // post processing code here
        // Loop through the map of filter values and remove the added wildcards
        Set<Map.Entry<String, Object>> entrySet = map.entrySet();
        if (!map.isEmpty()) {
            for (Map.Entry<String, Object> e : entrySet) {
                if (isInList(columnsWithExtraWildCards, e.getKey())) {
                    // This column has had extra wildcards
                    // Remove them
                    String s = (String)e.getValue();
                    s = s.replaceAll("%", "");
                    map.put(e.getKey(), s);
                }
            }
        }
    }
    /**
     * Verifies whether a String exists in a list of strings
     * Should reside in another utility class
     * @param list
     * @param value
     * @return
     * @writer Filip Huysmans
     */
    private boolean isInList(List<String> list, String value) {
        boolean returnValue = false;
        if (list != null && !list.isEmpty()) {
            for (String s : list) {
                if (s.equals(value)) {
                    returnValue = true;
                    break;
                }
            }
        }
        return returnValue;
    }

}

For the JSFUtils reference: look here.
  • Create the managed bean that will be used for the table references.

Now that the base-bean exists, create a managed bean or use an existing one.  This managed bean doesn't need to have anything else in it, just the reference to the BaseBean class.  Request-scope is fine for this managed bean.

package view.mb;

import view.framework.BaseBean;

public class CustomTableFiltersMB extends BaseBean {
}

Here is the code for the taskflow definition:

  <managed-bean id="__17">
    <managed-bean-name id="__15">CustomTableFiltersMB</managed-bean-name>
    <managed-bean-class id="__16">view.mb.CustomTableFiltersMB</managed-bean-class>
    <managed-bean-scope id="__18">request</managed-bean-scope>
  </managed-bean>
  • Change the queryListener property of the table to the onQuery method.

Now just create a table on a page.  In my example, I've used the DepartmentsView and dropped it on an empty page as a Read-Only table.  Just remember to activate the Filtering functionality.  Everything else, I left to their default values.
When you look at the source of your page, you will notice that in the af:table tag, a queryListener property was set.  The only thing you need to do, is to remplace this queryListener property with the onQuery-property of your managed bean.
Here is the code of the entire page:

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:h="http://java.sun.com/jsf/html"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view>
    <af:document id="d1">
      <af:messages id="m1"/>
      <af:form id="f1">
        <af:table value="#{bindings.DepartmentsView1.collectionModel}" var="row"
                  rows="#{bindings.DepartmentsView1.rangeSize}"
                  emptyText="#{bindings.DepartmentsView1.viewable ? 'No data to display.' : 'Access Denied.'}"
                  fetchSize="#{bindings.DepartmentsView1.rangeSize}"
                  rowBandingInterval="0"
                  filterModel="#{bindings.DepartmentsView1Query.queryDescriptor}"
                  queryListener="#{CustomTableFiltersMB.onQuery}"                  filterVisible="true" varStatus="vs" id="t1">
          <af:column sortProperty="DepartmentId" filterable="true"
                     sortable="false"
                     headerText="#{bindings.DepartmentsView1.hints.DepartmentId.label}"
                     id="c2">
            <af:outputText value="#{row.DepartmentId}" id="ot3">
              <af:convertNumber groupingUsed="false"
                                pattern="#{bindings.DepartmentsView1.hints.DepartmentId.format}"/>
            </af:outputText>
          </af:column>
          <af:column sortProperty="DepartmentName" filterable="true"
                     sortable="false"
                     headerText="#{bindings.DepartmentsView1.hints.DepartmentName.label}"
                     id="c4">
            <af:outputText value="#{row.DepartmentName}" id="ot2"/>
          </af:column>
          <af:column sortProperty="ManagerId" filterable="true" sortable="false"
                     headerText="#{bindings.DepartmentsView1.hints.ManagerId.label}"
                     id="c1">
            <af:outputText value="#{row.ManagerId}" id="ot1">
              <af:convertNumber groupingUsed="false"
                                pattern="#{bindings.DepartmentsView1.hints.ManagerId.format}"/>
            </af:outputText>
          </af:column>
          <af:column sortProperty="LocationId" filterable="true"
                     sortable="false"
                     headerText="#{bindings.DepartmentsView1.hints.LocationId.label}"
                     id="c3">
            <af:outputText value="#{row.LocationId}" id="ot4">
              <af:convertNumber groupingUsed="false"
                                pattern="#{bindings.DepartmentsView1.hints.LocationId.format}"/>
            </af:outputText>
          </af:column>
        </af:table>
      </af:form>
    </af:document>
  </f:view>
</jsp:root>
Run this page and you will notice that for every character based field, the filters are case insensitive and that the wildcards are added to them.
I also made sure, that the wildcards that are added, are also removed after the query.  This to keep the user interface clean.  Wildcards added by the end-users are left in tact.

ToDo

If somebody can help me in linking the Iterator to the SearchRegion, or viceversa, in a more ellegant manner then based on the name, would be a big step foreward.

ADF 11g: ADFUtils & JSFUtils

Challenge

Having some nice utility classes to handle JSF and ADF-view related operations.

Context

JDeveloper & ADF : 11.1.1.5.0

Solution


JSFUtils

package view.util;

import java.text.SimpleDateFormat;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import java.util.Set;

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.MethodExpression;
import javax.el.ValueExpression;

import javax.faces.application.Application;
import javax.faces.application.FacesMessage;
import javax.faces.application.ViewHandler;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;

import javax.servlet.http.HttpServletRequest;

import oracle.adf.model.binding.DCIteratorBinding;
import oracle.adf.view.rich.component.rich.data.RichTable;

import oracle.jbo.uicli.binding.JUCtrlHierBinding;

import org.apache.myfaces.trinidad.model.CollectionModel;
import org.apache.myfaces.trinidad.model.RowKeySet;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;

public final class JSFUtils {
    private static final String NO_RESOURCE_FOUND = "Missing resource: ";
    /**
     * Don't allow instantiation of this utility type class.
     * @writer Rudy De Busscher
     */
    private JSFUtils() {
    }
    /**
     * This method will handle a navigation case programmatically.
     * @param outcome
     */
    public static void handleNavigation(String outcome) {
        FacesContext ctx = JSFUtils.getFacesContext();
        ctx.getApplication().getNavigationHandler().handleNavigation(ctx, "",
                                                                     outcome);
    }
    /**
     * Method for taking a reference to a JSF binding expression and returning
     * the matching object (or creating it).
     * @param expression EL expression
     * @return Managed object
     */
    public static Object resolveExpression(String expression) {
        FacesContext facesContext = getFacesContext();
        Application app = facesContext.getApplication();
        ExpressionFactory elFactory = app.getExpressionFactory();
        ELContext elContext = facesContext.getELContext();
        ValueExpression valueExp =
            elFactory.createValueExpression(elContext, expression,
                                            Object.class);
        return valueExp.getValue(elContext);
    }
    public static String resolveRemoteUser() {
        FacesContext facesContext = getFacesContext();
        ExternalContext ectx = facesContext.getExternalContext();
        return ectx.getRemoteUser();
    }
    public static String resolveUserPrincipal() {
        FacesContext facesContext = getFacesContext();
        ExternalContext ectx = facesContext.getExternalContext();
        HttpServletRequest request = (HttpServletRequest)ectx.getRequest();
        return request.getUserPrincipal().getName();
    }
    public static Object resolveMethodExpression(String expression,
                                                 Class returnType,
                                                 Class[] argTypes,
                                                 Object[] argValues) {
        FacesContext facesContext = getFacesContext();
        Application app = facesContext.getApplication();
        ExpressionFactory elFactory = app.getExpressionFactory();
        ELContext elContext = facesContext.getELContext();
        MethodExpression methodExpression =
            elFactory.createMethodExpression(elContext, expression, returnType,
                                             argTypes);
        return methodExpression.invoke(elContext, argValues);
    }
    /**
     * Method for taking a reference to a JSF binding expression and returning
     * the matching Boolean.
     * @param expression EL expression
     * @param paTargetClass Class used to cast the result of the method.
     * @return Managed object
     */
    public static <T> T resolveExpression(String expression,
                                          Class<T> paTargetClass) {
        return (T)resolveExpression(expression);
    }
    /**
     * Convenience method for resolving a reference to a managed bean by name
     * rather than by expression.
     * @param beanName name of managed bean
     * @return Managed object
     */
    public static Object getManagedBeanValue(String beanName) {
        StringBuffer buff = new StringBuffer("#{");
        buff.append(beanName);
        buff.append('}');
        return resolveExpression(buff.toString());
    }
    /**
     * Method for setting a new object into a JSF managed bean
     * Note: will fail silently if the supplied object does
     * not match the type of the managed bean.
     * @param expression EL expression
     * @param newValue new value to set
     */
    public static void setExpressionValue(String expression, Object newValue) {
        FacesContext facesContext = getFacesContext();
        Application app = facesContext.getApplication();
        ExpressionFactory elFactory = app.getExpressionFactory();
        ELContext elContext = facesContext.getELContext();
        ValueExpression valueExp =
            elFactory.createValueExpression(elContext, expression,
                                            Object.class);
        //Check that the input newValue can be cast to the property type
        //expected by the managed bean.
        //If the managed Bean expects a primitive we rely on Auto-Unboxing
        //I could do a more comprehensive check and conversion from the object
        //to the equivilent primitive but life is too short
        Class bindClass = valueExp.getType(elContext);
        if (bindClass.isPrimitive() || bindClass.isInstance(newValue)) {
            valueExp.setValue(elContext, newValue);
        }
    }
    /**
     * Convenience method for setting the value of a managed bean by name
     * rather than by expression.
     * @param beanName name of managed bean
     * @param newValue new value to set
     */
    public static void setManagedBeanValue(String beanName, Object newValue) {
        StringBuffer buff = new StringBuffer("#{");
        buff.append(beanName);
        buff.append('}');
        setExpressionValue(buff.toString(), newValue);
    }

    /**
     * Convenience method for setting Session variables.
     * @param key object key
     * @param object value to store
     */
    public static void storeOnSession(String key, Object object) {
        FacesContext ctx = getFacesContext();
        Map sessionState = ctx.getExternalContext().getSessionMap();
        sessionState.put(key, object);
    }
    /**
     * Convenience method for getting Session variables.
     * @param key object key
     * @return session object for key
     */
    public static Object getFromSession(String key) {
        FacesContext ctx = getFacesContext();
        Map sessionState = ctx.getExternalContext().getSessionMap();
        return sessionState.get(key);
    }
    public static String getFromHeader(String key) {
        FacesContext ctx = getFacesContext();
        ExternalContext ectx = ctx.getExternalContext();
        return ectx.getRequestHeaderMap().get(key);
    }
    /**
     * Convenience method for getting Request variables.
     * @param key object key
     * @return session object for key
     */
    public static Object getFromRequest(String key) {
        FacesContext ctx = getFacesContext();
        Map sessionState = ctx.getExternalContext().getRequestMap();
        return sessionState.get(key);
    }
    /**
     * Pulls a String resource from the property bundle that
     * is defined under the application &lt;message-bundle&gt; element in
     * the faces config. Respects Locale
     * @param key string message key
     * @return Resource value or placeholder error String
     */
    public static String getStringFromBundle(String key) {
        ResourceBundle bundle = getBundle();
        return getStringSafely(bundle, key, null);
    }

    /**
     * Convenience method to construct a <code>FacesMesssage</code>
     * from a defined error key and severity
     * This assumes that the error keys follow the convention of
     * using <b>_detail</b> for the detailed part of the
     * message, otherwise the main message is returned for the
     * detail as well.
     * @param key for the error message in the resource bundle
     * @param severity severity of message
     * @return Faces Message object
     */
    public static FacesMessage getMessageFromBundle(String key,
                                                    FacesMessage.Severity severity) {
        ResourceBundle bundle = getBundle();
        String summary = getStringSafely(bundle, key, null);
        String detail = getStringSafely(bundle, key + "_detail", summary);
        FacesMessage message = new FacesMessage(summary, detail);
        message.setSeverity(severity);
        return message;
    }
    /**
     * Add JSF info message.
     * @param msg info message string
     */
    public static void addFacesInformationMessage(String msg) {
        FacesContext ctx = getFacesContext();
        FacesMessage fm =
            new FacesMessage(FacesMessage.SEVERITY_INFO, msg, "");
        ctx.addMessage(null, fm);
    }

    // Informational getters
    /**
     * Get view id of the view root.
     * @return view id of the view root
     */
    public static String getRootViewId() {
        return getFacesContext().getViewRoot().getViewId();
    }
    /**
     * Get component id of the view root.
     * @return component id of the view root
     */
    public static String getRootViewComponentId() {
        return getFacesContext().getViewRoot().getId();
    }
    /**
     * Get FacesContext.
     * @return FacesContext
     */
    public static FacesContext getFacesContext() {
        return FacesContext.getCurrentInstance();
    }
    /**
     * Internal method to pull out the correct local
     * message bundle
     */
    public static ResourceBundle getBundle() {
        FacesContext ctx = getFacesContext();
        UIViewRoot uiRoot = ctx.getViewRoot();
        Locale locale = uiRoot.getLocale();
        ClassLoader ldr = Thread.currentThread().getContextClassLoader();
        return ResourceBundle.getBundle(ctx.getApplication().getMessageBundle(),
                                        locale, ldr);
    }
    /**
     * Get an HTTP Request attribute.
     * @param name attribute name
     * @return attribute value
     */
    public static Object getRequestAttribute(String name) {
        return getFacesContext().getExternalContext().getRequestMap().get(name);
    }
    /**
     * Set an HTTP Request attribute.
     * @param name attribute name
     * @param value attribute value
     */
    public static void setRequestAttribute(String name, Object value) {
        getFacesContext().getExternalContext().getRequestMap().put(name,
                                                                   value);
    }
    /*
   * Internal method to proxy for resource keys that don't exist
   */
    private static String getStringSafely(ResourceBundle bundle, String key,
                                          String defaultValue) {
        String resource = null;
        try {
            resource = bundle.getString(key);
        } catch (MissingResourceException mrex) {
            if (defaultValue != null) {
                resource = defaultValue;
            } else {
                resource = NO_RESOURCE_FOUND + key;
            }
        }
        return resource;
    }
    /**
     * Locate an UIComponent in view root with its component id. Use a recursive way to achieve this.
     * Taken from http://www.jroller.com/page/mert?entry=how_to_find_a_uicomponent
     * @param id UIComponent id
     * @return UIComponent object
     */
    public static UIComponent findComponentInRoot(String id) {
        UIComponent component = null;
        FacesContext facesContext = FacesContext.getCurrentInstance();
        if (facesContext != null) {
            UIComponent root = facesContext.getViewRoot();
            component = findComponent(root, id);
        }
        return component;
    }
    /**
     * Locates all components.
     * @return UIComponent object
     */
    public static List<UIComponent> findAllComponentsinRoot() {
        List<UIComponent> result = new ArrayList<UIComponent>();
        FacesContext facesContext = FacesContext.getCurrentInstance();
        if (facesContext != null) {
            UIComponent root = facesContext.getViewRoot();
            result = root.getChildren();
        }
        return result;
    }
    /**
     * Locate an UIComponent from its root component.
     * Taken from http://www.jroller.com/page/mert?entry=how_to_find_a_uicomponent
     * @param base root Component (parent)
     * @param id UIComponent id
     * @return UIComponent object
     */
    public static UIComponent findComponent(UIComponent base, String id) {
        if (id.equals(base.getId())) {
            return base;
        }
        UIComponent children = null;
        UIComponent result = null;
        Iterator childrens = base.getFacetsAndChildren();
        while (childrens.hasNext() && (result == null)) {
            children = (UIComponent)childrens.next();
            if (id.equals(children.getId())) {
                result = children;
                break;
            }
            result = findComponent(children, id);
            if (result != null) {
                break;
            }
        }
        return result;
    }

    /**
     * Locate an UIComponent from a base component and looking in his parents.
     * @param base root Component
     * @param id UIComponent id to search
     * @return UIComponent object
     */
    public static UIComponent findClosestComponent(UIComponent base,
                                                   String id) {
        if (id.equals(base.getId())) {
            return base;
        }
        UIComponent child = null;
        UIComponent result = null;
        Iterator children = base.getParent().getFacetsAndChildren();
        while (children.hasNext() && (result == null)) {
            child = (UIComponent)children.next();
            result = findComponent(child, id);
        }
        if (result == null && !(base instanceof UIViewRoot)) {
            result = findClosestComponent(base.getParent(), id);
        }
        return result;
    }

    /**
     * Determines all the components that have the value specified as parameter as their id.
     * @param id
     * @return
     * @writer Rudy De Busscher
     */
    public static List<UIComponent> findComponentsInRoot(String id) {
        List<UIComponent> result = new ArrayList<UIComponent>();
        FacesContext facesContext = FacesContext.getCurrentInstance();
        if (facesContext != null) {
            UIComponent root = facesContext.getViewRoot();
            findComponents(result, root, id);
        }
        return result;
    }
    /**
     * Locate all the UIComponents from its root component.
     * @param components The list that will be populated with the found components
     * @param base root Component (parent)
     * @param id UIComponent id
     * @writer Rudy De Busscher
     */
    public static void findComponents(List<UIComponent> components,
                                      UIComponent base, String id) {
        if (id.equals(base.getId())) {
            components.add(base);
            return;
        }
        UIComponent child = null;
        Iterator children = base.getFacetsAndChildren();
        while (children.hasNext()) {
            child = (UIComponent)children.next();
            if (id.equals(child.getId())) {
                components.add(child);
                break;
            }
            findComponents(components, child, id);
        }
    }
    /**
     * Method to create a redirect URL. The assumption is that the JSF servlet mapping is
     * "faces", which is the default
     *
     * @param view the JSP or JSPX page to redirect to
     * @return a URL to redirect to
     */
    public static String getPageURL(String view) {
        FacesContext facesContext = getFacesContext();
        ExternalContext externalContext = facesContext.getExternalContext();
        String url =
            ((HttpServletRequest)externalContext.getRequest()).getRequestURL().toString();
        StringBuffer newUrlBuffer = new StringBuffer();
        newUrlBuffer.append(url.substring(0, url.lastIndexOf("faces/")));
        newUrlBuffer.append("faces");
        String targetPageUrl = view.startsWith("/") ? view : "/" + view;
        newUrlBuffer.append(targetPageUrl);
        return newUrlBuffer.toString();
    }
    /**
     * Refresh the current page.
     */
    public static void refreshCurrentPage() {
        FacesContext context = FacesContext.getCurrentInstance();
        String currentView = context.getViewRoot().getViewId();
        ViewHandler vh = context.getApplication().getViewHandler();
        UIViewRoot x = vh.createView(context, currentView);
        context.setViewRoot(x);
    }
    /**
     * Force the validation and updates model phase.  Usefull in the situation where
     * we have an ilmmediate true action but want to keep the values.
     * @param paComponent The component to validate, call it with the view root.
     * @param paContext The FacesContext
     * @writer Rudy De Busscher
     */
    public static void forceValidateAndUpdateField(UIComponent paComponent,
                                                   FacesContext paContext) {
        if (paComponent instanceof EditableValueHolder) {
            EditableValueHolder field = (EditableValueHolder)paComponent;
            paComponent.processValidators(paContext);
            field.setValid(true); // In case something went wrong, just ignore it now.
            paComponent.processUpdates(paContext);
        }
        Iterator<UIComponent> iter = paComponent.getFacetsAndChildren();
        while (iter.hasNext()) {
            UIComponent childOrFacet = iter.next();
            forceValidateAndUpdateField(childOrFacet, paContext);
        }
    }
    /**
     * Helper method to execute the an Method EL with one parameter.
     * @param expr the EL expression
     * @param paParameter
     */
    public static void invokeMethodExpression(String expr,
                                              Object paParameter) {
        invokeMethodExpression(expr, Object.class,
                               new Class[] { paParameter.getClass() },
                               new Object[] { paParameter });
    }
    /**
     * Helper method to execute the QueryListener EL for methods with a return type.
     * @param expr The method you want to execute
     * @param returnType The return type of the method
     * @param argTypes The types of the arguments
     * @param args the arguments passed to the method (must match argTypes)
     */
    public static Object invokeMethodExpression(String expr, Class returnType,
                                                Class[] argTypes,
                                                Object[] args) {
        FacesContext fc = FacesContext.getCurrentInstance();
        ELContext elctx = fc.getELContext();
        ExpressionFactory elFactory =
            fc.getApplication().getExpressionFactory();
        MethodExpression methodExpr =
            elFactory.createMethodExpression(elctx, expr, returnType,
                                             argTypes);
        return methodExpr.invoke(elctx, args);
    }
    public static Object invokeMethodExpression(String expr, Class returnType, Class argType, Object argument) {
        return invokeMethodExpression(expr, returnType, new Class[] { argType }, new Object[] { argument });
    }

    public static String resolveFromResourceBundle(String paResourceBundle,
                                                   String paKey) {
        StringBuilder expression = new StringBuilder();
        expression.append("#{adfBundle['").append(paResourceBundle).append("'].").append(paKey).append("}");
        return resolveExpression(expression.toString(), String.class);
    }
    private static final String DATEFORMATPATTERN = "dd/MM/yyyy";
    /**
     * This method will fetch a string from the resourcebundle for a specific key.
     * Afterwards it will replace all the keys from the dynamicParams map with
     * their corresponding values.
     * When the value is of type java.sql.Date, the Date will be transformed into
     * a String using the format 'DD/MM/YYYY'.
     *
     * @param paResourceBundle Path + Name of the resourceBundle
     * @param paKey The key in the resourceBundle to fetch the text
     * @param dynamicParams A map of dynamic constants to be replaced in the string of the resourcebundle
     * @return
     * @writer Filip Huysmans
     */
    public static String resolveFromResourceBundle(String paResourceBundle,
                                                   String paKey,
                                                   Map dynamicParams) {
        // Determine the string from the resource bundle
        String resourceBundleValue =
            resolveFromResourceBundle(paResourceBundle, paKey);
        // Replace the dynamic parts of the string by looping through the map
        if (dynamicParams != null && !dynamicParams.isEmpty()) {
            for (Map.Entry entry : (Set<Map.Entry>)dynamicParams.entrySet()) {
                Object value = entry.getValue();
                // Transforming the key to the exact representation in the resource bundle string
                String key = "\\{" + entry.getKey() + "\\}";
                // Handling some special cases of a date
                if (value instanceof java.sql.Date) {
                    // Format the date before putting it into the string
                    java.sql.Date newDate = (java.sql.Date)value;
                    SimpleDateFormat formatDate =
                        new SimpleDateFormat(DATEFORMATPATTERN);
                    value = formatDate.format(newDate);
                }
                // Replacing all occurances of the key with the value
                resourceBundleValue =
                        resourceBundleValue.replaceAll(key, (String)value);
            }
        }
        // Returning the result String
        return resourceBundleValue;
    }
    public static void writeJavaScriptToClient(String paScript) {
        FacesContext fctx = FacesContext.getCurrentInstance();
        ExtendedRenderKitService erks = null;
        erks =
Service.getRenderKitService(fctx, ExtendedRenderKitService.class);
        erks.addScript(fctx, paScript);
    }
    /**
     * Get the value of an EL expression.
     * @param expr
     * @return
     */
    public static Object get(String expr) {
        FacesContext fc = JSFUtils.getFacesContext();
        return fc.getApplication().evaluateExpressionGet(fc, expr,
                                                         Object.class);
    }
    /**
     * Set the a value into an EL Expression
     * @param expr
     * @param value
     */
    public static void set(String expr, String value) {
        Object valToSet = value;
        if (isELExpr(value)) {
            valToSet = get(value);
        }
        set(expr, valToSet);
    }
    /**
     * Check whether the given parameter is a valid EL Expression
     * @param o
     * @return
     */
    private static boolean isELExpr(Object o) {
        if (o instanceof String) {
            String str = (String)o;
            str = str.trim();
            return str.startsWith("#{") && str.endsWith("}");
        }
        return false;
    }
    /**
     * Set the a value into an EL Expression
     * @param expr
     * @param value
     */
    public static void set(String expr, Object value) {
        FacesContext fc = JSFUtils.getFacesContext();
        ELContext elc = fc.getELContext();
        ExpressionFactory ef = fc.getApplication().getExpressionFactory();
        ValueExpression ve = ef.createValueExpression(elc, expr, Object.class);
        ve.setValue(elc, value);
    }
    public static void addFacesMessageError(String componentId,
                                            String message) {
        FacesContext context = getFacesContext();
        context.addMessage(componentId,
                           new FacesMessage(FacesMessage.SEVERITY_ERROR, "",
                                            message));
    }
    public static void addFacesMessage(String id, FacesMessage fm) {
        JSFUtils.getFacesContext().addMessage(id, fm);
    }
    /**
     * Add JSF error message.
     * @param msg error message string
     */
    public static void addFacesErrorMessage(String msg) {
        FacesContext ctx = getFacesContext();
        FacesMessage fm =
            new FacesMessage(FacesMessage.SEVERITY_ERROR, msg, "");
        ctx.addMessage(null, fm);
    }
    /**
     * Add JSF warning message.
     * @param msg warning message string
     */
    public static void addFacesWarningMessage(String msg) {
        FacesContext ctx = getFacesContext();
        FacesMessage fm =
            new FacesMessage(FacesMessage.SEVERITY_WARN, msg, "");
        ctx.addMessage(null, fm);
    }
    /**
     * This method will set the focus on a field in the current row from a table
     * @param table The reference to the table component
     * @param fieldId The name(=Id) of the field to focus on
     * @writer Filip Huysmans
     */
    public static void setFocusOnField(RichTable table, String fieldId) {
        // Getting the iterator from the table component
        CollectionModel cm = (CollectionModel)table.getValue();
        JUCtrlHierBinding tb = (JUCtrlHierBinding)cm.getWrappedData();
        DCIteratorBinding icd = tb.getDCIteratorBinding();
        // Take the key of the current row and set the current row active
        ArrayList lst = new ArrayList(1);
        lst.add(icd.getCurrentRow().getKey());
        table.setActiveRowKey(lst);
        // Looking for the necessary id's to create the focus call
        String tableId = table.getClientId(JSFUtils.getFacesContext());
        RowKeySet rks = table.getSelectedRowKeys();
        if (rks != null && rks.size() > 0) {
            // Only when there are rows in the table
            Object rowKey = rks.iterator().next();
            String rowId =
                table.getClientRowKeyManager().getClientRowKey(JSFUtils.getFacesContext(),
                                                               table, rowKey);
            String inputId = tableId + ":" + rowId + ":" + fieldId;
            // Creating the Javascript to put the focus on the field
            ExtendedRenderKitService service =
                Service.getRenderKitService(JSFUtils.getFacesContext(),
                                            ExtendedRenderKitService.class);
            // Adding a timeout to wait for the components to render
            service.addScript(JSFUtils.getFacesContext(),
                              "setTimeout(function(){comp = AdfPage.PAGE.findComponent('" +
                              inputId + "'); comp.focus();}, 500)");
        }
    }

    /**
     * method for removing Session variables.
     * @param
     * @writer Christophe Gobled
     */
    public static void removeFromSession(String key) {
        FacesContext ctx = getFacesContext();
        Map sessionState = ctx.getExternalContext().getSessionMap();
        sessionState.remove(key);
    }
}

ADFUtils

package view.util;

import java.util.ArrayList;
import java.util.List;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;

import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.model.binding.DCIteratorBinding;
import oracle.adf.model.binding.DCParameter;
import oracle.adf.share.logging.ADFLogger;
import oracle.adf.view.rich.component.rich.RichPopup;
import oracle.adf.view.rich.component.rich.data.RichTable;
import oracle.adf.view.rich.context.AdfFacesContext;
import oracle.adf.view.rich.event.QueryEvent;
import oracle.adf.view.rich.model.AttributeCriterion;
import oracle.adf.view.rich.model.AttributeDescriptor;
import oracle.adf.view.rich.model.Criterion;
import oracle.adf.view.rich.model.QueryDescriptor;

import oracle.binding.AttributeBinding;
import oracle.binding.BindingContainer;
import oracle.binding.ControlBinding;
import oracle.binding.OperationBinding;

import oracle.jbo.ApplicationModule;
import oracle.jbo.Key;
import oracle.jbo.Row;
import oracle.jbo.uicli.binding.JUCtrlHierBinding;
import oracle.jbo.uicli.binding.JUCtrlHierNodeBinding;
import oracle.jbo.uicli.binding.JUCtrlValueBinding;

import org.apache.myfaces.trinidad.event.SelectionEvent;
import org.apache.myfaces.trinidad.model.CollectionModel;
import org.apache.myfaces.trinidad.model.RowKeySet;
import org.apache.myfaces.trinidad.render.ExtendedRenderKitService;
import org.apache.myfaces.trinidad.util.Service;

/**
 * A series of convenience functions for dealing with ADF Bindings.
 * Note: Updated for JDeveloper 11
 *
 * @author Duncan Mills
 * @author Steve Muench
 *
 * $Id: ADFUtils.java 141 2011-11-28 11:07:16Z HEAVEN\cgd $.
 */
public final class ADFUtils {
    private static final String NOT_FOUND = "' not found";
    public static final ADFLogger LOGGER = ADFLogger.createADFLogger(ADFUtils.class);
    /**
     * Don't allow instantiation of utility class.
     * @writer Rudy De Busscher
     */
    private ADFUtils() {
        // Don't allow instantiation of utility class.
    }
    /**
     * Get application module for an application module data control by name.
     * @param name application module data control name
     * @return ApplicationModule
     */
    public static ApplicationModule getApplicationModuleForDataControl(String name) {
        return (ApplicationModule)JSFUtils.resolveExpression("#{data." + name + ".dataProvider}");
    }

    /**
     * A convenience method for getting the value of a bound attribute in the
     * current page context programatically.
     * @param attributeName of the bound value in the pageDef
     * @return value of the attribute
     */
    public static Object getBoundAttributeValue(String attributeName) {
        return findControlBinding(attributeName).getInputValue();
    }
    /**
     * A convenience method for setting the value of a bound attribute in the
     * context of the current page.
     * @param attributeName of the bound value in the pageDef
     * @param value to set
     */
    public static void setBoundAttributeValue(String attributeName, Object value) {
        findControlBinding(attributeName).setInputValue(value);
    }
    /**
     * Returns the evaluated value of a pageDef parameter.
     * @param pageDefName reference to the page definition file of the page with the parameter
     * @param parameterName name of the pagedef parameter
     * @return evaluated value of the parameter as a String
     */
    public static Object getPageDefParameterValue(String pageDefName, String parameterName) {
        BindingContainer bindings = findBindingContainer(pageDefName);
        DCParameter param = ((DCBindingContainer)bindings).findParameter(parameterName);
        return param.getValue();
    }
    /**
     * Convenience method to find a DCControlBinding as an AttributeBinding
     * to get able to then call getInputValue() or setInputValue() on it.
     * @param bindingContainer binding container
     * @param attributeName name of the attribute binding.
     * @return the control value binding with the name passed in.
     *
     */
    public static AttributeBinding findControlBinding(BindingContainer bindingContainer, String attributeName) {
        if (attributeName != null && bindingContainer != null) {
            ControlBinding ctrlBinding = bindingContainer.getControlBinding(attributeName);
            if (ctrlBinding instanceof AttributeBinding) {
                return (AttributeBinding)ctrlBinding;
            }
        }
        return null;
    }
    /**
     * Convenience method to find a DCControlBinding as a JUCtrlValueBinding
     * to get able to then call getInputValue() or setInputValue() on it.
     * @param attributeName name of the attribute binding.
     * @return the control value binding with the name passed in.
     *
     */
    public static AttributeBinding findControlBinding(String attributeName) {
        return findControlBinding(getBindingContainer(), attributeName);
    }
    /**
     * Return the current page's binding container.
     * @return the current page's binding container
     */
    public static BindingContainer getBindingContainer() {
        return BindingContext.getCurrent().getCurrentBindingsEntry();
    }
    /**
     * Return the Binding Container as a DCBindingContainer.
     * @return current binding container as a DCBindingContainer
     */
    public static DCBindingContainer getDCBindingContainer() {
        return (DCBindingContainer)getBindingContainer();
    }
    /**
     * Get List of ADF Faces SelectItem for an iterator binding.
     *
     * Uses the value of the 'valueAttrName' attribute as the key for
     * the SelectItem key.
     *
     * @param iteratorName ADF iterator binding name
     * @param valueAttrName name of the value attribute to use
     * @param displayAttrName name of the attribute from iterator rows to display
     * @return ADF Faces SelectItem for an iterator binding
     */
    public static List<SelectItem> selectItemsForIterator(String iteratorName, String valueAttrName, String displayAttrName) {
        return selectItemsForIterator(findIterator(iteratorName), valueAttrName, displayAttrName);
    }
    /**
     * Get List of ADF Faces SelectItem for an iterator binding with description.
     *
     * Uses the value of the 'valueAttrName' attribute as the key for
     * the SelectItem key.
     *
     * @param iteratorName ADF iterator binding name
     * @param valueAttrName name of the value attribute to use
     * @param displayAttrName name of the attribute from iterator rows to display
     * @param descriptionAttrName name of the attribute to use for description
     * @return ADF Faces SelectItem for an iterator binding with description
     */
    public static List<SelectItem> selectItemsForIterator(String iteratorName, String valueAttrName, String displayAttrName, String descriptionAttrName) {
        return selectItemsForIterator(findIterator(iteratorName), valueAttrName, displayAttrName, descriptionAttrName);
    }
    /**
     * Get List of attribute values for an iterator.
     * @param iteratorName ADF iterator binding name
     * @param valueAttrName value attribute to use
     * @return List of attribute values for an iterator
     */
    public static List attributeListForIterator(String iteratorName, String valueAttrName) {
        return attributeListForIterator(findIterator(iteratorName), valueAttrName);
    }
    /**
     * Get List of Key objects for rows in an iterator.
     * @param iteratorName iterabot binding name
     * @return List of Key objects for rows
     */
    public static List<Key> keyListForIterator(String iteratorName) {
        return keyListForIterator(findIterator(iteratorName));
    }
    /**
     * Get List of Key objects for rows in an iterator.
     * @param iter iterator binding
     * @return List of Key objects for rows
     */
    public static List<Key> keyListForIterator(DCIteratorBinding iter) {
        List<Key> attributeList = new ArrayList<Key>();
        for (Row r : iter.getAllRowsInRange()) {
            attributeList.add(r.getKey());
        }
        return attributeList;
    }
    /**
     * Get List of Key objects for rows in an iterator using key attribute.
     * @param iteratorName iterator binding name
     * @param keyAttrName name of key attribute to use
     * @return List of Key objects for rows
     */
    public static List<Key> keyAttrListForIterator(String iteratorName, String keyAttrName) {
        return keyAttrListForIterator(findIterator(iteratorName), keyAttrName);
    }
    /**
     * Get List of Key objects for rows in an iterator using key attribute.
     *
     * @param iter iterator binding
     * @param keyAttrName name of key attribute to use
     * @return List of Key objects for rows
     */
    public static List<Key> keyAttrListForIterator(DCIteratorBinding iter, String keyAttrName) {
        List<Key> attributeList = new ArrayList<Key>();
        for (Row r : iter.getAllRowsInRange()) {
            attributeList.add(new Key(new Object[] { r.getAttribute(keyAttrName) }));
        }
        return attributeList;
    }
    /**
     * Get a List of attribute values for an iterator.
     *
     * @param iter iterator binding
     * @param valueAttrName name of value attribute to use
     * @return List of attribute values
     */
    public static List attributeListForIterator(DCIteratorBinding iter, String valueAttrName) {
        List attributeList = new ArrayList();
        for (Row r : iter.getAllRowsInRange()) {
            attributeList.add(r.getAttribute(valueAttrName));
        }
        return attributeList;
    }
    /**
     * Find an iterator binding in the current binding container by name.
     *
     * @param name iterator binding name
     * @return iterator binding
     */
    public static DCIteratorBinding findIterator(String name) {
        DCIteratorBinding iter = getDCBindingContainer().findIteratorBinding(name);
        if (iter == null) {
            throw new RuntimeException("Iterator '" + name + NOT_FOUND);
        }
        return iter;
    }
    /**
     * @param bindingContainer
     * @param iterator
     * @return
     */
    public static DCIteratorBinding findIterator(String bindingContainer, String iterator) {
        DCBindingContainer bindings = (DCBindingContainer)JSFUtils.resolveExpression("#{" + bindingContainer + "}");
        if (bindings == null) {
            throw new RuntimeException("Binding container '" + bindingContainer + NOT_FOUND);
        }
        DCIteratorBinding iter = bindings.findIteratorBinding(iterator);
        if (iter == null) {
            throw new RuntimeException("Iterator '" + iterator + NOT_FOUND);
        }
        return iter;
    }
    /**
     * @param name
     * @return
     */
    public static JUCtrlValueBinding findCtrlBinding(String name) {
        JUCtrlValueBinding rowBinding = (JUCtrlValueBinding)getDCBindingContainer().findCtrlBinding(name);
        if (rowBinding == null) {
            throw new RuntimeException("CtrlBinding " + name + NOT_FOUND);
        }
        return rowBinding;
    }
    /**
     * Find an operation binding in the current binding container by name.
     *
     * @param name operation binding name
     * @return operation binding
     */
    public static OperationBinding findOperation(String name) {
        OperationBinding operation = getDCBindingContainer().getOperationBinding(name);
        if (operation == null) {
            throw new RuntimeException("Operation '" + name + NOT_FOUND);
        }
        return operation;
    }
    /**
     * Find an operation binding in the current binding container by name.
     *
     * @param bindingContianer binding container name
     * @param opName operation binding name
     * @return operation binding
     */
    public static OperationBinding findOperation(String bindingContianer, String opName) {
        DCBindingContainer bindings = (DCBindingContainer)JSFUtils.resolveExpression("#{" + bindingContianer + "}");
        if (bindings == null) {
            throw new RuntimeException("Binding container '" + bindingContianer + NOT_FOUND);
        }
        OperationBinding operation = bindings.getOperationBinding(opName);
        if (operation == null) {
            throw new RuntimeException("Operation '" + opName + NOT_FOUND);
        }
        return operation;
    }
    /**
     * Get List of ADF Faces SelectItem for an iterator binding with description.
     *
     * Uses the value of the 'valueAttrName' attribute as the key for
     * the SelectItem key.
     *
     * @param iter ADF iterator binding
     * @param valueAttrName name of value attribute to use for key
     * @param displayAttrName name of the attribute from iterator rows to display
     * @param descriptionAttrName name of the attribute for description
     * @return ADF Faces SelectItem for an iterator binding with description
     */
    public static List<SelectItem> selectItemsForIterator(DCIteratorBinding iter, String valueAttrName, String displayAttrName, String descriptionAttrName) {
        List<SelectItem> selectItems = new ArrayList<SelectItem>();
        for (Row r : iter.getAllRowsInRange()) {
            selectItems.add(new SelectItem(r.getAttribute(valueAttrName), (String)r.getAttribute(displayAttrName), (String)r.getAttribute(descriptionAttrName)));
        }
        return selectItems;
    }
    /**
     * Get List of ADF Faces SelectItem for an iterator binding.
     *
     * Uses the value of the 'valueAttrName' attribute as the key for
     * the SelectItem key.
     *
     * @param iter ADF iterator binding
     * @param valueAttrName name of value attribute to use for key
     * @param displayAttrName name of the attribute from iterator rows to display
     * @return ADF Faces SelectItem for an iterator binding
     */
    public static List<SelectItem> selectItemsForIterator(DCIteratorBinding iter, String valueAttrName, String displayAttrName) {
        List<SelectItem> selectItems = new ArrayList<SelectItem>();
        for (Row r : iter.getAllRowsInRange()) {
            selectItems.add(new SelectItem(r.getAttribute(valueAttrName), (String)r.getAttribute(displayAttrName)));
        }
        return selectItems;
    }
    /**
     * Get List of ADF Faces SelectItem for an iterator binding.
     *
     * Uses the rowKey of each row as the SelectItem key.
     *
     * @param iteratorName ADF iterator binding name
     * @param displayAttrName name of the attribute from iterator rows to display
     * @return ADF Faces SelectItem for an iterator binding
     */
    public static List<SelectItem> selectItemsByKeyForIterator(String iteratorName, String displayAttrName) {
        return selectItemsByKeyForIterator(findIterator(iteratorName), displayAttrName);
    }
    /**
     * Get List of ADF Faces SelectItem for an iterator binding with discription.
     *
     * Uses the rowKey of each row as the SelectItem key.
     *
     * @param iteratorName ADF iterator binding name
     * @param displayAttrName name of the attribute from iterator rows to display
     * @param descriptionAttrName name of the attribute for description
     * @return ADF Faces SelectItem for an iterator binding with discription
     */
    public static List<SelectItem> selectItemsByKeyForIterator(String iteratorName, String displayAttrName, String descriptionAttrName) {
        return selectItemsByKeyForIterator(findIterator(iteratorName), displayAttrName, descriptionAttrName);
    }
    /**
     * Get List of ADF Faces SelectItem for an iterator binding with discription.
     *
     * Uses the rowKey of each row as the SelectItem key.
     *
     * @param iter ADF iterator binding
     * @param displayAttrName name of the attribute from iterator rows to display
     * @param descriptionAttrName name of the attribute for description
     * @return ADF Faces SelectItem for an iterator binding with discription
     */
    public static List<SelectItem> selectItemsByKeyForIterator(DCIteratorBinding iter, String displayAttrName, String descriptionAttrName) {
        List<SelectItem> selectItems = new ArrayList<SelectItem>();
        for (Row r : iter.getAllRowsInRange()) {
            selectItems.add(new SelectItem(r.getKey(), (String)r.getAttribute(displayAttrName), (String)r.getAttribute(descriptionAttrName)));
        }
        return selectItems;
    }
    /**
     * Get List of ADF Faces SelectItem for an iterator binding.
     *
     * Uses the rowKey of each row as the SelectItem key.
     *
     * @param iter ADF iterator binding
     * @param displayAttrName name of the attribute from iterator rows to display
     * @return List of ADF Faces SelectItem for an iterator binding
     */
    public static List<SelectItem> selectItemsByKeyForIterator(DCIteratorBinding iter, String displayAttrName) {
        List<SelectItem> selectItems = new ArrayList<SelectItem>();
        for (Row r : iter.getAllRowsInRange()) {
            selectItems.add(new SelectItem(r.getKey(), (String)r.getAttribute(displayAttrName)));
        }
        return selectItems;
    }
    /**
     * Find the BindingContainer for a page definition by name.
     *
     * Typically used to refer eagerly to page definition parameters. It is
     * not best practice to reference or set bindings in binding containers
     * that are not the one for the current page.
     *
     * @param pageDefName name of the page defintion XML file to use
     * @return BindingContainer ref for the named definition
     */
    private static BindingContainer findBindingContainer(String pageDefName) {
        BindingContext bctx = getDCBindingContainer().getBindingContext();
        return bctx.findBindingContainer(pageDefName);
    }
    /**
     * @param opList
     */
    public static void printOperationBindingExceptions(List opList) {
        if (opList != null && !opList.isEmpty()) {
            for (Object error : opList) {
                LOGGER.severe(error.toString());
            }
        }
    }
    /**
     * Adding an UI Component to the list of partial targets.
     * When the component is null, nothing will be done.
     * @param component
     * @writer Filip Huysmans
     */
    public static void addComponentToPartialTarget(UIComponent component) {
        if (component != null) {
            AdfFacesContext.getCurrentInstance().addPartialTarget(component);
        }
    }
    /**
     * Setting the focus (through javascript) on the current row
     * and put the focus in the field given.
     * The focus will be set after 500ms, to avoid the refresh done by PPR.
     * @param tbl Binding of the table
     * @param columnName The Id of the field that you want the focus to go to
     * @writer Filip Huysmans
     */
    public static void selectTableColumn(RichTable tbl, String columnName) {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        String tableId = tbl.getClientId(facesContext);
        RowKeySet rks = tbl.getSelectedRowKeys();
        String inputId = "";
        if (rks != null && rks.size() > 0) {
            Object rowKey = rks.iterator().next();
            String rowId = tbl.getClientRowKeyManager().getClientRowKey(facesContext, tbl, rowKey);
            inputId = tableId + ":" + rowId + ":" + columnName;
        }
        ExtendedRenderKitService service = Service.getRenderKitService(facesContext, ExtendedRenderKitService.class);
        service.addScript(facesContext, "setTimeout('" + "comp = AdfPage.PAGE.findComponent(\\'" + inputId + "\\'); comp.focus();', 500)");
    }
    /**
     * Checks if the user has any search criteria specified in the AF/query search fields.
     * If not, shown an error messag. Otherwise performa the query
     * @param paQueryEvent The Query event
     * @param paOriginalADFQueryListener The ADF query listener that performs the search
     * @writer Rudy De Busscher
     */
    public static void onExecuteQueryListener(QueryEvent paQueryEvent, String paOriginalADFQueryListener) {
        QueryDescriptor qdesc = paQueryEvent.getDescriptor();
        Object val;
        AttributeDescriptor attrDescriptor;
        boolean validQuery = false;
        for (Criterion criterion : qdesc.getConjunctionCriterion().getCriterionList()) {
            attrDescriptor = ((AttributeCriterion)criterion).getAttribute();
            val = ((AttributeCriterion)criterion).getValues().get(0);
            // When Dropdown encountered, there's always a selected value: 0 for blank
            if (AttributeDescriptor.ComponentType.selectOneChoice != attrDescriptor.getComponentType()) {
                validQuery = val != null;
            } else {
                validQuery = Integer.parseInt(val.toString()) != 0;
            }
            if (validQuery) {
                break;
            }
        }
        if (validQuery) {
            JSFUtils.invokeMethodExpression(paOriginalADFQueryListener, paQueryEvent);
        } else {
            JSFUtils.addFacesErrorMessage(JSFUtils.getStringFromBundle("ERROR_QUERY_ALL_FIELD_EMPTY"));
        }
    }
    public static JUCtrlHierBinding getTreeBinding(String name) {
        //get reference to tree binding by its ID in the PageDef
        return (JUCtrlHierBinding)getBindingContainer().get(name);
    }
    /** * Synchronizes the table UI component row selection with the
     * selection in the ADF binding layer
     * @param selectionEvent event object created by the table
     * component upon row selection
     */
    public static void makeCurrent(SelectionEvent selectionEvent) {
        RichTable table = (RichTable)selectionEvent.getSource();
        //the Collection Model is the object that provides the
        //structured data
        //for the table to render
        CollectionModel tableModel = (CollectionModel)table.getValue();
        //the ADF object that implements the CollectionModel is
        //JUCtrlHierBinding. It is wrapped by the CollectionModel API
        JUCtrlHierBinding adfTableBinding = (JUCtrlHierBinding)tableModel.getWrappedData();
        //Acess the ADF iterator binding that is used with
        //ADF table binding
        DCIteratorBinding tableIteratorBinding = adfTableBinding.getDCIteratorBinding();
        //the role of this method is to synchronize the table component
        //selection with the selection in the ADF model
        Object selectedRowData = table.getSelectedRowData();
        //cast to JUCtrlHierNodeBinding, which is the ADF object that represents a row
        JUCtrlHierNodeBinding nodeBinding = (JUCtrlHierNodeBinding)selectedRowData;
        //get the row key from the node binding and set it as the current row in the iterator
        Key rwKey = nodeBinding.getRowKey();
        tableIteratorBinding.setCurrentRowWithKey(rwKey.toStringFormat(true));
    }
    /**
     * This method will create a List of SelectItems to be used in a selectonechoice or others.
     * It now only works for iterators based on the CodesLOV-view.
     * @param iteratorName
     * @return
     * @writer Filip Huysmans
     */
   /* public static List<SelectItem> createListSelectItemsFromIterator(String iteratorName) {
        List<SelectItem> returnList = new ArrayList<SelectItem>();
        // Getting the iterator with the possible values
        DCIteratorBinding stagemLOVIterator = ADFUtils.findIterator(iteratorName);
        stagemLOVIterator.setRangeSize(-1);
        Row[] allRowsInRange = stagemLOVIterator.getAllRowsInRange();
        if (allRowsInRange != null && allRowsInRange.length > 0) {
            for (Row r : allRowsInRange) {
                CodesLOVRowImpl row = (CodesLOVRowImpl)r;
                returnList.add(new SelectItem(row.getId(), row.getLabel()));
            }
        }
        return returnList;
    }

*/
    /**
     * Opens the popup passed as parameter
     * @param popup
     * @writer Chrisophe Goblet
     */
    public static void showPopup(RichPopup popup) {
        String popupId = popup.getClientId(FacesContext.getCurrentInstance());
        ExtendedRenderKitService erkService = Service.getService(FacesContext.getCurrentInstance().getRenderKit(), ExtendedRenderKitService.class);
        erkService.addScript(FacesContext.getCurrentInstance(), "var hints = {autodismissNever:true}; " + "AdfPage.PAGE.findComponent('" + popupId + "').show(hints);");
    }
    /**
     * Opens the popup passed as name
     * @param popupId the id of the popup to open
     * @writer Filip Huysmans
     */
    public static void showPopup(String popupId) {
        RichPopup popup = (RichPopup) JSFUtils.findComponentInRoot(popupId);
        popup.show(new RichPopup.PopupHints());
    }
}