Monday, January 27, 2014

AMStatistics - Adding Custom Statistics to ADF BC

ADF BC Application Module provides standard class called AMStatistics. This class gives you info about AM creation time as for example, Web Session ID assigned to the current session, etc. What is cool about this class - it is not limited with out of the box statics only, it allows to add your custom statistics. I will describe use case of tracking activation timestamp for the AM and keeping it custom AMStatistics variable.

Here you can download completed sample application - AMStatisticsApp.zip. This sample overrides ADF BC method - activateState in Application Module Implementation class. Mehtod activateState is invoked by the framework, when activation event happens. At this time, we create new custom StatsInfo instance and save it in AMStatistics (it overrides previously saved statistic with the same name). Activation timestamp is saved into AMStatistics:


Custom method - checkLastActivationTime is accessing AMStatistics and reads AM activation time custom statistics saved earlier. This method is invoked from the button.

To see the log output, when checkLastActivationTime method is invoked, make sure to set INFO log level for the Application Module Implementation class:


For the test purposes, I have set Referenced Pool Size = 1, this means with two users active - it will start to passivate and activate Application Module instances and we would be able to see changed timestamp:


Here we can see output from the runtime test. When first user is activated, I press Check Last Activation Time button - timestamp is set and printed in the log:


Moving to the second user, activation is performed. Last activation time is updated:


Until Application Module instance remains assigned to the current user, activation time will remain unchanged - you can see this in the log:


This was an example of a use case, when AMStatistics can be used to keep custom statistic values.

Thursday, January 23, 2014

Practical Example for ADF Active Data Service

I have created more complex and complete Active Data Service example, based on the one posted in the previous post - Simple Example for ADF Active Data Service. Updated sample application is using JDBC to listen for updates in the DB. Updates counter is refreshed through ADS and displayed to the user. This sample is tested with Oracle XE 10g, you only need to grant change notification to the the user connecting from the data source.

If you want to see more detail runtime output for the sample application - LongRunningTaskPushApp_v2.zip, make sure to enable following ADF logger classes:


I would like to start explaining, how Model and ADS parts communicate. There is interface defined, this acts as a bridge between DB push controller and ADS engine to push refresh changes to the UI:


ADS controller class (the one responsible for ADS push logic), implements defined interface:


Push mechanism is started automatically by ADS framework, framework method startActiveData is invoked. Inside this method, we create new instance of DB push controller and pass instance of ADS controller (the one implementing interface):


DB push controller in turn starts listener for DB change notifications. You must execute select from DB table, the one you want to listen:


ADS provides method, this method is invoked automatically when ADS is deregistered - we are stopping DB push controller from here:


Here I'm running the test now. There are two different session, I change data in the first session and save to the DB:


As this changes is saved to the DB, it is propagated across all sessions registered with ADS - we can see new change number is available:


I can click Synch Changes - to re-execute ADF BC and bring all the latest changes in the current session, you can see changes count is reset to 0. Do a change again and press Save:


You are going to see change incremented in the second browser session, as it was not synchronised previously. It means - we had two updates in the DB, and currently displayed data needs to be synched:


From the ADF log we can see that when new browser session is opened, firstly it starts new ADS thread and then registers DB change push controller with DB notification listener. DB changes notifications are logged. At the end, when browser page with ADS support is closed, ADS thread is stopped automatically, it stops DB push controller and deregisters DB notification listener:


Once user clicks on Synch Changes link, we call action listener from ADS controller bean, where we set latest synch time and reset counter by pushing this change through ADS update event:


Latest synch time variable is referenced from ADF task flow parameter:


ADF task flow is set to refresh - ifNeeded, this means it will refresh automatically each time, when parameter is changed (to synchronise changes from DB using ADF BC):

Sunday, January 19, 2014

Update for Red Samurai Performance Audit Tool - v 2.4

This weekend we have finalized latest update for our ADF runtime performance audit tool - Red Samurai Performance Audit Tool v 2.4. You can read about features included into previous update v 2.3 in this post - Update for Red Samurai Performance Audit Tool - v 2.3. Current update v 2.4 is focused on Slow Query and Large Fetch drill down screens usability. We provide more detailed information to understand how your ADF application performs recently and how applied tuning improves performance.

List of improvements in v 2.4:

1. Improved nested Application Modules activation auditing

2. Improved first screen of the performance dashboard application. Types of Issues graph displays calculated total number of issues. There is option to filter issues by type:


3. Drill down screen for Slow Queries is more intelligent now. It displays latest issue occurrences (during 5 days), together with total occurrences over month. This allows to understand if applied tuning gives any result, also to distinguish new issues easier:


4. Previously Drill down screen for Slow Queries was displaying only number of issue occurrences. Now you are allowed to go even further and view the list of issues with SQL statements. Previously you could do this only from the first screen of the performance dashboard, now the same is enabled from drill down screens for your convenience:


5. Drill down screen for Large Fetches is enhanced in the same way as the one for Slow Queries. We can see recently logged issues, together with all logged issues over the last month:


6. Details for every issue occurrence can be viewed for each logged large fetch:


7. Logged Users graph was updated to display average number of users per hour, together with total number of users per day. This allows to understand better real workload during each day:

Saturday, January 18, 2014

Improving Scrolling Performance in ADF Read-Only Tables with Row Selection Timeout

There is great new feature available in ADF 11g PS6 and ADF 12c - option to enable row selection timeout for ADF read-only tables. By default, when user is pressing up/down keyboard keys - every time row gets selected, even if user is navigating through multiple records, before selecting the one he needs. With row selection timeout enabled, table rows will not be selected while scrolling, until scrolling stops and required record gets selected. This should be default setting, I wonder why Oracle didn't enabled it by default.

I will describe first, how scrolling in ADF read-only tables works by default. For the test purpose, ADF BC method setCurrentRow is overridden to track how many records get selected while navigating with up/down keyboard button:


In order to see output message - make sure to enable ADF logger for Employees VO implementation class:


Select one of the available rows:


You will see row selection action is executed and reported in the log:


Navigate few records down:


You will see in the log, all records were selected - while navigating from the first to the last records:


We can tune this behaviour by enabling row selection timeout, while scrolling with keyboard up/down keys, timeout value will not be exceeded and row will not be selected until user will stop. Select ADF table component:


Change property - SelectionEventDelay, by default it is disabled. This property is available in ADF 11g PS6 or ADF 12c:


Set property SelectionEventDelay to be enabled. Selection timeout is 300 ms, meaning row is selected, if delay between pressing up/down keyboard keys is more than 300 ms:


With SelectionEventDelay = enabled, repeat the same test as above. Select a row in ADF read-only table:


Check in the log - row selection action was invoked:


Navigate few records down and stop:


There will be no records selected in between, only the last one - this will improve ADF read-only table scrolling performance with keyboard up/down keys greatly:


Download sample application - ADFTableScrollingTimeoutApp.zip.

Wednesday, January 15, 2014

Accessing Custom Attribute Property from ADF UI Expression

You may not know, but it is possible to access custom property defined for the VO/EO attribute from ADF UI expression. This may turn useful, when implementing custom generic functionality and standard attributes are not enough. In this example, I'm using custom property - alternativeName, in real use case this will be something else. Here I will pass alternative name for the attribute through this property:


Custom property defined for the attribute, can be accessed from ADF UI Expression, by referencing properties map - bindings.AttributeName.attributeDef.properties.PropertyName:


This is how property is accessed, later it can be displayed on UI - see label text for the CommissionPct attribute:


You can download sample application here - CustomPropertyApp.zip.

Saturday, January 11, 2014

ADF BC Application Module Instance Timeout and Web Session Timeout Dependency

What happens with AM instance, when Web session times out? I would like to answer this question. To find an answer, I have developed sample application with special settings for AM configuration - AMInstanceTimeoutApp.zip. This is important to understand, because we should try to avoid frequent AM passivations, same as frequent AM activations. Passivations consumes server resources and delays request processing for current active users.

We already know - when AM idle instance timeout is set to be less than Web session timeout, during user inactivity there will be AM passivations and activations happening. To minimize number of passivations/activations, we need to increase Referenced Pool Size, along with increasing AM idle instance timeout (read here - How to Minimize Number of ADF BC Application Module Activations).

Customized AM settings for the sample application:

1. Referenced Pool Size = 1, to simulate high load and to see what happens when second user arrives

2. Minimum Available Size = 0, to make sure all AM instances will be removed after timeout

3. Idle Instance Timeout = 900 (sec.), instance will be marked as candidate for removal after 15 mins.

4. Pool Pooling Interval = 60 (sec.), inactive AM instances will be removed in 1 minute intervals


Web session timeout on contrary to AM instance timeout is set to be less - only 5 minutes. This is done on purpose to timeout Web session, before associated AM instance will be timed out:


As practical test shows - once Web session times out, if another user accessing application before pool pooling interval - passivation will happen. This means, AM instance was not yet removed and is still reserved - as there are no available AM instances (Referenced Pool Size = 1), passivation happens and instance is given to the new user.

Web session times out for the first user:


Second user is accessing application, passivation happens for the AM instance previously used by already timed out session:


However, if second user would wait a bit more after first user session timed out - precisely would wait until pool pooling interval, there would be no passivation. This means, when Web session times out - AM instance is not removed instantly, it will stay active until the next event of pool cleanup (pool pooling interval). In my sample I set this interval to 1 minute, in real application it could be 5-10 minutes.

Web session timeout happened and after pool pooling interval - AM instance was removed:


If second user is accessing application at that time, there will be no passivation reported:

Tuesday, January 7, 2014

Simple Example for ADF Active Data Service

Active Data Service in ADF is very useful functionality, it allows to push data to the UI, without extra refresh/reload. However, due to its complexity, is not used too often. My goal is to provide as much as possible simple example for ADS use case in this post. In the future posts, I plan to post updated samples with more complex use case implementations.

ADS is configured in adf-config.xml file, here you can download complete sample application - LongRunningTaskPushApp.zip. There is active output text component, it displays number of open jobs and is refreshed by ADS:


Once we navigate to the Employees tab - Open jobs counter is reloaded:


Separate thread, where we generate new jobs is started when ADS is activated and is stopped automatically, when ADS is deactivated (when navigating away from page or closing browser):


Thread is stopped automatically, when browser is closed or navigating away to other page:


Active output text value is retrieved from managed bean method:


This managed bean is registered in session scope and is responsible to manage ADS lifecycle:


We can see that managed bean method is accessing binding and gets initial value from there - it comes from ADF BC attribute:


This relationship is defined in Page Definition - initial value is retrieved from ADF BC:


There is post construct method - we are setting up ADS model info, basically registering active output text component value to be reloaded automatically by push from ADS:


There are two standard methods from ADS model overridden to control ADS lifecycle start and stop events:


As you can see above - thread to push ADS changes is created in start method, automatically when ADS gets initialised after post construct method. Thread is stopped automatically, when ADS is deactivated (this happens when browser is closed or navigated to other page).

Active output text is reloaded by triggered method, where ADS event is generated - using registered active output text value:


When opening Employees tab, Open jobs counter is reloaded from resetData method, referenced from panel collection visible property: