Monday, December 30, 2013

ADF Dynamic ADF BC - Loading Multiple Instances (Nr. 100 in 2013)

This is Nr. 100 post in 2013 !

We learned how to build dynamic ADF BC passivation/activation safe in the previous post - ADF Dynamic ADF BC - Surviving Passivation/Activation Events. There is one more trick to learn - how to reload and open UI with dynamic ADF multiple times. This is useful when dynamic ADF form can  be opened from multiple menu items, passing parameter and re-drawing dynamic ADF UI.

This is implemented in the sample - ADFDynamicReportUI_v5.zip. Custom method from Application Module class constructs View Definition, each time when form is loaded from the menu - this method is invoked with parameter and new View Definition is created:


For the test purposes, we set Hire Date to be displayed only when parameter is not NULL:


Before creating new View Object instance, we should check if our dynamic View Object instance already exists. If yes - we should remove it first and only then create new one (otherwise there will be error about existing View Object instance with the same name):


This is mainly all about loading multiple instances. Now I will describe several improvements in UI part. ADF 12c supports declarative component tag, this simplifies complex ADF UI rendering. Sample application ADF UI form renders different kind UI components from iterator using ADF UI dynamic component tag:


We are referencing attributeModel from iterator and accessing Page Definition bindings:


Dynamic form in ADF 12c is created simply by drag and drop and selecting dynamic option - fairly simple and stable.

Sample application is based on Multi Task Flow Binding, described in my previous post for ADF 12c - Smooth Migration from ADF 11g R1/R2 Apps to ADF 12c. I'm loading ADF Task Flow with dynamic ADF UI, passing additional parameter for the second menu option (Hire Date will be displayed):


ADF Task Flow with dynamic ADF UI is closed and loaded from the menu dynamically, controlled by Multi Task Flow binding:


You can try to open first or second menu option, this will load the same ADF Task Flow, but reinitialise dynamic ADF BC with different parameter - dynamic ADF UI will be displayed accordingly:

Friday, December 27, 2013

ADF Dynamic ADF BC - Surviving Passivation/Activation Events

ADF dynamic ADF BC and dynamic ADF UI implementation is useful functionality and is required almost in every larger project. Primary area where this functionality is applied - report parameters screens, instead of building hundreds of static report parameter screens for every report, we can build one dynamic and regenerate required ADF BC objects structure, together with dynamic ADF UI. Here you can read my previous post for the same topic - ADF Generator for Dynamic ADF BC and ADF UI - Recreate. Today post provides improved sample application with added support for ADF dynamic functionality working in passivation/activation event scenario.

Download updated sample application - ADFDynamicReportUI_v4.zip. Previous sample application contained one dummy VO - DynamicView:


This VO was replaced on runtime with real dynamic VO, created programmatically in HrModule class. This didn't worked in stress test environment, simulated by disabling AM pooling:


Null pointer exception for ADF dynamic form - activation event was failing:


It was failing, because on activation, ADF runtime was trying to activate original dummy VO - not the one we have substituted programmatically:


In theory it should work to remove dummy VO and change it with programmatic one, but really it fails on activation event:


Solution is pretty simple for this - we can get rid of dummy VO completely and rely directly on VO instance created programmatically on runtime. There is no need to define dummy VO in AM Data Model:


There is no need to have dummy VO either:


As there is no dummy VO anymore, no need to remove it's instance. We can simply create new programmatic VO instance with given name:


In page definition we should reference VO instance by the same name, obviously it will be highlighted as design time error - as there is no such VO instance defined statically, but this will work on runtime:


There are few additional improvements to survive passivation/activation events better - I will list them all below:

1. Non editable primary key - you should add primary key attribute and hide it to be non editable


2. If there is no default value for the attribute, it can be marked as not selected in query and there will be no need to include it into SQL statement


3. Not specifically related to passivation/activation - but for dependent LOV's, we need to set AutoSubmit=true for the parent attribute:


Dependent attribute should be set with backward dependency, this will reset attribute value automatically, when parent attribute value is changed:


4. SQL statement includes only selected attributes, where default value is set:


5. Dynamic VO doesn't passivate and activate correctly by default. We need to passivate and activate such VO manually. Standard method for passivation should be overridden, we can read current row attribute values and passivate them:


Standard method for activation should be overridden, to activate and set values to the current row attributes back:


6. If there are LOV's created dynamically, all such LOV's must be assigned with primary key:


Here you can see how it works on UI. Let's select Location Id, based on selected value LOV for Department Id is filtered and returns 50:


If you change Location Id, Department Id will be cleared automatically and user could select new Department Id value corresponding to the currently selected Location Id:

Wednesday, December 25, 2013

Update for Red Samurai Performance Audit Tool - v 2.3

Christmas time and we have update for our performance audit tool. Previous version - Major Release for Red Samurai Performance Audit Tool v 2.0, is updated with additional functionality to track ADF BC activation impact for your ADF application runtime performance. Added functionality is based on the method described in my previous blog post - Update For: Recording ADF BC View Object Instance Activation Time. You could try it yourself.

I will go through couple of screens, where new functionality is included. There is a new tab with a graph displaying distribution of activation events across Application Modules:


New drill down graph - displaying activation events grouping based on activation time per event, records fetched and number of VO instances involved. User can select specific event and see in the details table information about each VO instance participating in the given event:


Drill down graph for slow query is improved - user can see selected Application Module, there is new option to see details data in the table view:


The same updates - graph selection and additional table to view details data, was added for large fetch drill down:

Tuesday, December 24, 2013

Update For: Recording ADF BC View Object Instance Activation Time

You may have seen my previous blog post - Recording ADF BC View Object Instance Activation Time. This post describes how to track activation events time for individual VO's, so you can understand how much activation process may slow down your ADF system runtime performance. I was testing it in stress test environment and discovered issue related to activation start time logging - start time variable value was lost in some cases and set as NULL. Today post describes a fix, activation time is logged more accurate with information from ADF BC AMStatistics helper utility class.

Here you can download updated sample application - stresstest_v6.zip. This sample logs activation time for each individual VO, including AM and VO names, number of fetched rows and activation label (this helps to group activation events from individual VO's and understand total exceeded time per AM activation event for all VO's):


As you can see, for the second VO - same activation label is assigned, this is because both VO's were activated during the same AM activation event:


VO with longest activation time reported in the same AM activation event group, always is activated last. Longest time represent total time for AM activation in the given activation event.

There are two VO activated, because there are two VO's included into ADF UI page - Jobs and Departments, both of them are activated (AM pool is switched off for test purpose):


Instead of logging AM activation start time in the separate method and keeping start time in VO class variable, as it was before - now I'm using only single method activateCurrentRow and within this method getting AM start time from AMStatistics class. AM start time represents time when AM was started during current activation event. As AM always starts first before any VO is activated, we can use this info in our method:

Saturday, December 21, 2013

Workaround for Infamous Bug 13626875

There is such issue logged on Metalink - inputListOfValues Field Not Updated When Selecting A Value Violating A Unique Key. (Doc ID 1402074.1). This is related to LOV functionality and validation. As per Oracle statement - LOV list must include only valid values, list should not return invalid values, this is by LOV design. However, this doesn't sound logical in most of the cases - often LOV may contain complete list of values and for specific attribute we need to enforce validation to accept only a subset of all values available in the list. Despite Oracle answer as such functionality is not possible b design, there is workaround to make it work.

Sample application contains required fix - LOVValidationApp.zip. This sample app is created with JDEV 12c, however same workaround can be applied for earlier JDEV versions. Firstly I'm going to describe, how it works without workaround - by default. Let's assume, we have Departments LOV defined for Department Id attribute:


Department Id is assigned with validation rule - Department Id value must be greater than 100. This is to simulate issue related to LOV behaviour:


On runtime I'm going to pick Employee with currently set Department Id 140 and open LOV dialog. I'm going to select Department Id 30 from LOV dialog and try to set to the field:


What we would get, is not what we would expect. Selected value is not assigned, previous value still is displayed:


On the next click, moving focus or selecting other value - then suddenly change LOV value gets updated and validation error is displayed. This is fine, but this should happen one step earlier:


We need to speed up validation process by one step - immediately after value was selected. Workaround is to set ExceptionMode = Immediate for the Data Control Usage in DataBindings.cpx file:


With ExceptionMode = Immediate, somehow magically LOV value is changed instantly and validation error is displayed when it should. Repeating the same test as before - selecting value below 100 and returning it from LOV:


Value is changed and validation is displayed as expected:


So, if Oracle answer - 'not supported by design', didn't help, try to apply ExceptionMode = Immediate setting for Data Control Usage in DataBindings.cpx

Wednesday, December 18, 2013

Detail View Object Instance Programmatic Access

Usually it is quite obvious how to retrieve rowset from VO. It is still basic to retrieve rowset from detail VO, but there is something to keep in mind when accessing detail VO's - current row in master VO, current row must be set. Otherwise, there will be no detail rowset retrieved. I will demo and explain this case here.

Sample application is prepared as usual - MasterDetailAccessApp.zip. This application contains one Master VO and one Detail:


Here you can see example, where current row is not set for Master VO. In this case - there will be no rows returned for detail VO:


You would need to fix it, as for example by calling first() method. This will ensure first row is selected as current. As result - detail VO will be aware about current Master VO record and will be able to fetch proper value for bind variable to be included into SQL query:


Test from AM exposed interface:


Detail row is fetched and displayed:

Tuesday, December 17, 2013

How to Minimize Number of ADF BC Application Module Activations

As I have described in my previous post - you can track how long it takes to perform ADF BC activation in your system - Recording ADF BC View Object Instance Activation Time. Activation event can be potentially slow, as it involves re-quering and re-fetching of all active VO instances, initialized by current AM. In order to speed up ADF application runtime performance, we should tune it in a such way to avoid activation events as much as possible. Main goal of this post, is to prove with practical experiment, theory behind AM tuning for minimizing number activation events.

Firstly, you need to assign proper Referenced Pool Size value in AM properties configuration screen, to make sure it is equal to expected number of concurrent users. Don't forget to enable DB pooling - Stress Testing Oracle ADF BC Applications - Do Connection Pooling and TXN Disconnect Level, this will minimize open DB connections.

One of the key parts is to set longer time out value for inactive AM instance, you can set it to be equal to Web session timeout set in web.xml. This must be increased together with AM time to live setting to -1, as this will guarantee AM instance will be never removed forcefully. As AM time to live by default is 1 hour, ADF will remove AM instance, no matter for how long AM instance time out is set. This is based on recommendations posted by Duncan Mills - ADF Performance Presentation from UKOUG.

This is how sample application stresstest_v5.zip looks - there are two tabs, each using different AM. Navigation is involved, together with data update operation through ADF BC custom method - all this will tested by running JMeter stress load script:


JMeter script - ADFBC_Tuning.jmx, is created in a such way to simulate real user behaviour as much as possible. Script is starting 60 threads with 40 seconds delay, there are three breaks included - 3, 2 and 2 minutes. This allows to stretch stress test time and create more realistic load between requests:


AM from sample application is configured with 1 minute of Idle Instance Timeout and 1 minute of Pool Pooling Interval. By default these values are 10 minutes each, but I set both to be 1 minute, to fit it into JMeter script better - where breaks are by 3 and 2 minutes. There should be enough time for inactivity period, to mark AM instance as inactive and remove it. We are going to see how short inactivity time affects number of AM activations and runtime performance at the end. Updated settings for AM instance Idle Instance Timeout and Pool Pooling Interval. Of course, DB pooling is enabled as well, as per above recommendations:


Referenced Pool Size is set to 70, there should be enough available instances to handle 60 threads started from JMeter. Let's see how it works in practice.

Based on EM output - we can see that activations are happening for AM 1:


Similar picture for Activations is for AM 2:


This doesn't look logical at first, but really it is. Simply, when there is no activity - but user session is still active, inactive AM's are removed fast. When user is resuming his work - new AM instances are created again, this is when activation happens.

In order to avoid such effect, we need to increase Idle Instance Timeout, in this example I'm setting it to 3 hours (I would say this should be equal to web session timeout configured in web.xml):


Make sure to set AM time to live to be -1, otherwise AM instance will be forcefully removed after default 1 hour:


With these settings, we are getting much better results. For Referenced Pool Size = 70 and 60 concurrent JMeter threads, there are no activation events logged over longer time, there are no new AM instances, all active AM instances are reused:


The same is true for the second AM - no activation events are logged:


I can increase JMeter concurrent threads to 80, this will be higher than configured Referenced Pool Size = 70:


Naturally, this results in activation events - as Referenced Pool Size is too small to handle 80 concurrent threads in this situation - this is expected:


One final test - we need to verify if setting AM time to live to be -1 is really necessary. I'm going to set AM time to live to be 4 minutes, meaning after 4 minutes AM instance will be removed, no matter it is active or idle:


As it was presumed - we are starting to see AM activation events. This means it is not enough just to increase AM instance Idle Instance Timeout, but is really important to set AM instance Time to Live setting to be -1, or at least increase it to be longer than Idle Instance Timeout:


The same is for the second AM:


Summary - if you want to minimize number of AM activations in the system, make sure to set at least  these three settings described in this post:

1. Enable DB pooling
2. Increase AM instance Idle Instance Timeout
3. Increase or set to -1, AM instance Time to Live