Friday, August 24, 2012

ODTUG Webinar - ADF Best Practices, Andrejus Baranovskis, Red Samurai Consulting

If you are looking for free of charge advanced technical ADF training - join my ODTUG webinar on September 18th. More info and registration is available here - ADF Best Practices, Andrejus Baranovskis, Red Samurai Consulting.

I will run this webinar using problem/solution approach. Problem will be described first, after that ADF best practice solution will be explained and demonstrated. I will accept questions during live session - there will be no need to wait for questions at the end.

Webinar abstract: This webinar highlights ADF best practices and will share information you can't read from a developer guide or book. Technical solutions based on day-to-day experiences from ADF development will also be included. The webinar will be organized in use case / solution best practice format. Featured topics include: resolving ADF BC Library imports, master-detail performance improvements, session scope access from ADF BC, LOV performance improvements, table loading performance, login and ADF security implementation, and finally, ADF BC activation/passivation and stress testing.


Talk to you soon !

Download presentation slides - ODTUG_WEB_ABaranovskis.pptx.

Thursday, August 23, 2012

Sample Application for Switching Application Module Data Sources

I was preparing proof of concept for such scenario, where ADF application was working with multiple data sources. Requirement was to be able to select data source on runtime, before login. We had several DB users, different DB security applied to each of them - separate data source was defined. Different data source per business site, not really per business user - this would be too much. I would like to post and describe prepared sample application. Data Source runtime switch is implemented based on concept described in Jobinesh blog - Modifying the Application Module's JDBC DataSource at run time.

Download sample application - UserDataADFBCSample_v3.zip. This sample is based on application from my previous posts, it is enhanced with Data Source selection from login page.

Data Source runtime switch is implemented basically in two steps:

1. In the Model there is custom class that implements EnvInfoProvider. Specifically one method is overriden - getInfo(String, Object). This method reads data source name from session scope (its where we set it during login) and puts it into AM configuration:


2. Each Application Module must be set with proper configuration for jbo.envinfoprovider property. This property must point to our custom EnvInfoProvider class (see above):


Default Data Source name defined for Application Module is still important, ADF BC will use it in case if no custom Data Source name was provided:


I'm getting list of Data Sources from static VO:


This VO is exposed through Application Module Data Control. Keep in mind, even VO is static - AM still we be initialized on VO access. This means AM will establish connection to database, at that time when we will load static VO data. Custom Data Source name will not be set yet - default Data Source name will be used. Instance of static VO with list of Data Sources:


UI list with Data Sources can be created by drag and drop of DataSourcesView1 instance from Data Control into JSF page. Select Single Selection -> ADF Select One Choice option:


Choose display attribute - press OK and choice list with Data Source names will be generated for you:


Once choice list was created, go to Login page definition and create Name attribute binding (based on same iterator as Data Source choice list):


This will allow us to access selected Data Source name from Login bean - doLogin() method:


Here how it looks on runtime - user selects Data Source from the list:


User logs in into application - Application Module configuration is initialized with Hr DB data source and data is rendered:


From the log we can see that after login, session cookie was changed. This happens because there are two Web sessions created always - before and after login (its how it works by default in ADF). This allows us to set custom Data Source name after login action is done. Remember - before login, Application Module is initialized with default Data Source:


Hr Test DB - is non existing Data Source, I'm using it only for test purpose -  application should fail, to prove Application Module is using Data Source selected during login:


Indeed application breaks:


From the log we can see that Application Module was trying to connect with jdbc/HrTest Data Source - correct as expected:


Wednesday, August 15, 2012

Solution to Control Global Editable/Readonly Mode in ADF BC

There is requirement, when we need to disable/enable editable data access globally per user session for entire application. When implementing this requirement, you should keep in mind ADF BC passivation/activation - data should stay in correct state even between activation/passivation iterations. Global control for editable mode in ADF BC can based on - Solution for Sharing Global User Data in ADF BC. Sample application in this post, is based on that article. Described solution for global editable/readonly mode is generic across all Task Flows, EO's and AM's, there is no dependency to specific Task Flow, EO or AM.

Download sample application - UserDataADFBCSample_v2.zip. Sample architecture is described here:


Editable/Readonly access is set from session scope, user can trigger it by certain action. We should not access session scope directly in ADF BC, its why we override Data Control class - CustomADFBCDataControl (read more here) and pass session scope value into ADF BC User Data. CustomADFBCDataControl class contains overriden executeIteratorBindingIfNeeded() method responsible to prepare iterator binding, this method is called each time when data collection is accessed, it allows to pass correct editable or readonly flag and store it in User Data. Custom User Data is passivated/activated with ADF BC lifecycle, same data is accessed from generic EO implementation class isAttributeUpdateable(int) method.

Solution is tested with disabled AM pooling, to proof it works under stress load:


isAttributeUpdateable(int) method checks User Data variable custom_ReadOnlyMode and decided to render editable or readonly data:


executeIteratorBindingIfNeeded() method updates User Data variable custom_ReadOnlyMode, each time when data is accessed - this allows to force editable or readonly rendering mode on any EO:


By default form is rendered in editable mode, in my sample:


User changes sessions scope variable to readonly, ADF BC custom User Data is updated - page refresh happens and EO isAttributeUpdateable(int) method marks all attributes to be readonly:


This change happens globally, across all Task Flows, AM's and EO's. Locations tab renderes read-only data from Locations Task Flow:


Switch back to editable - data is rendered editable again:


In the log you can see that, two AM were initialized - Locations and Departments. Data access (readonly/editable) variable was passed each time when data was accessed from iterator:


This allows to mark EO attributes in generic EO class for editable/readonly access.

Sample application implements different Task Flow for each tab, this means editable/readonly access is independent of Task Flow and control directly in ADF BC level through custom User Data variable initialized from Data Control class on data access generically:


Thursday, August 9, 2012

Red Samurai Performance Audit Tool - Runtime Diagnosis for ADF Applications

To tune ADF application, we need to know exactly what is the reason for performance bottleneck. In Red Samurai we are helping our customer to be happy with ADF. How we do that? Yes - hard quality work (and no bla bla talking) is one of the most important things. But also we use tools - one of such tools is in house developed ADF Runtime Performance Audit tool.

Before blaming ADF is slow, make sure to check the way data is retrieved from DB, also SQL execution performance. I agree, its not always easy to monitor DB/SQL performance for ADF applications. This is the main reason we have developed this tool.

Our tool splits into two parts - Audit Engine (6 KB JAR file) and Performance Audit Dashboard. Customer application needs to include only Audit Engine, the rest happens as magic - information about slow SQL starts to come to dashboard automatically. Tool is universal and runs in development, test and production environments.

Performance Audit Dashboard interface:


Main areas for performance bottleneck and tuning related to DB/SQL in ADF:

1. SQL time execution in DB. While SQL executes, ADF waits for response - we want as fast SQL execution as possible.

2. Duplicate SQL execution. Obviously we want to avoid duplicate SQL execution.

3. SQL count query execution. ADF invokes separate SQL count query to estimate rowset size, this may slow down performance for complex queries.

4. Resultset Fetch size. When fetching lots of records from DB, ADF is using more memory to create and maintain rowset, this potentially slows down application.

5. Passivation/Activation time. One of the slowest operations - need to monitor and avoid as much as possible.

Performance Audit Dashboard offers two charts for performance audit overview:

1. Type of Issues pie chart with selection in time

2. Monthly Issues tracking linear chart

List with issues displays:

1. Issue type
2. SQL execution time
3. Issue details
4. Issue date
5. Application/View Object name related to the issue
6. User name, ADF Web user who was triggering SQL from ADF application

Details section displays more detailed info, such as SQL query or complete info about large rowset fetch.

There is option to change audit parameters on the fly.

We are on track to innovate and improve ADF applications quality, this tool is newest addition to our other tools:

1. Red Samurai MDS Cleaner V2.0

2. JDeveloper 11g Extension to Validate ADF Code Quality

Red Samurai Performance Audit is available free of charge (existing/future Red Samurai customers).

Tuesday, August 7, 2012

Difference Between ADF BC Groovy Old Value and Posted Attribute

To keep it short - ADF BC Groovy keyword "oldValue" and ADF BC API method getPostedAttribute(index) are not the same thing. I spoke with ADF developer today, who have spent around 5 days debugging and hitting validation bug related to incorrect usage of "oldValue" by Groovy. Both approached - "oldValue" and getPostedAttribute(index) are valid for its own use cases. But you should clearly understand the difference, otherwise may hit some painful bugs in validation rules.

How it works in ADF 11g R2:

1. "oldValue" Groovy keyword returns last valid value
2. getPostedAttribute(index) returns value from database

In most of the cases, we need to compare user input against original value from the database. This makes Groovy "oldValue" keyword pretty useless in such use cases where we want to validate data against original one.

Download sample application where both cases are demonstrated - OldNewValueValidationApp.zip.

Sample application defines one validation rule for CommissionPct attribute:


This rule is using Groovy oldValue and newValue keywords:


Second validation rule is defined for Salary attribute, its based on Java method. We are going to call getPostedAttribute(index) method from there:


Here is the code sample for getPostedAttribute(index) invocation:


1. Test for Groovy oldValue keyword

Initial value for CommissionPct is 0.1:


Change it to negative -0.1, this will trigger validation rule:


Old value is reported to be 0.1, this is correct. Now enter positive valid value 0.2:


Type -0.2 now, old value is reported as 0.2 - this is last valid value, but not the original value from database (we didn't commited yet our change to database):


2. Test for getPostedAttribute(index) method

Initial value for Salary is 16000:


Change it to 300, validation error is shown and you can check that old value is reported as 1600 (correct):


Change to new valid value 17000 now:


Again change back to invalid 400 - old value is reported correctly, the one original from database 16000:


Sunday, August 5, 2012

Resolving Invalid ADF BC Library Import in JDeveloper 11g R2

This week I came across ADF BC library import problem onsite. ADF BC library was very large, around 1000 EO's. EO's were not visible through JDeveloper wizard from consuming project after import. At first I was this is related to library size - too many ADF BC objects, JDeveloper fails to list them through ADF library import. But this proved to be false assumption, when I tested with smaller library. At the end I found there was duplicate definition for EO package path inside consuming project, it was duplicate to the one from ADF library. This was a reason why JDeveloper wizard was not resolving imported ADF BC. I will describe this case in a bit more detail, I believe this might be helpful (JDeveloper version - 11g R2 (11.1.2.x)).

Download working sample application with ADF BC library import - adflibimport.zip.

ADF BC library contains one EO object - com.redsamurai.common.model.entities package:


Project is deployed as ADF library and connected through JDeveloper resource catalog - EO object for Employees is included:


All is correct ay this point. But in my case imported ADF lib JAR file was showing imported package, but content was empty. Exactly as you can see in this screenshot - no content for com.redsamurai.common.model.entities package:


It seems like JDeveloper randomly may register package from imported library inside local Model.jpx ADF BC configuration file. When this happens - there will be duplicate package on class path and no ADF library objects shown in JDeveloper wizards. Its what I had in my case - imported package name was populated as well into local Model.jpx file:


After imported package name entry was removed from local Model.jpx, JDeveloper wizard instantly started to show imported EO object name:


If you will encounter the same situation - no ADF BC objects visible from imported library, make sure to double check local Model.jpx file, may be you will find duplicate entry for package name from imported library.

Thursday, August 2, 2012

ADF BC Passivation/Activation and SQL Execution Tuning

Passivation/activation in ADF BC is designed to keep temporary user data across requests, when there are more online users than application pool can handle. If you are new to this, please read from Oracle developer guide - 40 Application State Management. There is added cost to passivation/activation - additional SQL execution. During activation event, its not only temporary data gets initialized - but complete VO SQL gets executed again. This means system could suffer significant performance issues, if there are lots of passivation/activation events happening. In order to avoid frequent passivation/activation, make sure to tune referenced pool size properly for your environment - Stress Testing Oracle ADF BC Applications - Passivation and Activation.

This post demonstrates additional SQL execution during activation event. Download sample application - ActivationSQLApp_v2.zip.

Form is loaded for the first time:


One SQL execution happens as it should:


We are running test with AM pooling disabled, this allows to simulate stress test environment and trigger activation/passivation events:


With AM pool disabled, without closing screen, press Next button in the form - this will navigate to the next record:


SQL will execute one more time:


From the detail log, we can see that SQL execution event is logged as well, when there is activation event:


During normal scenarios, SQL is executed once and data stays in memory. Keep attention, how often passivation/activation happens in your system - this can affect performance significantly.