Quantcast
Channel: Andrej Baranovskij Blog
Viewing all 685 articles
Browse latest View live

Creating ADF BC View Object Instances On The Fly

$
0
0
This post is to describe such use case, where we have a set of common Entity Objects and want to handle View Objects and UI dynamically. This is common use case for simpler screens, usually common Entity Objects are provided from the library, but instead of creating hundreds of similar View Objects and UI fragments - we can handle such screens in generic way, by creating View Object instances programmatically and later using them through dynamic iterator.

Sample application - ADFDynamicReportUI_v3.zip is based on my previous post - ADF Generator for Dynamic ADF BC and ADF UI - Recreate. This sample is utilising ADF BC API for ViewDefImpl, VO instances are created and registered on the fly using this API.

There are two EO's created in the sample application:


Custom method is defined in Application Module implementation class - constructVOInstance, this method is used to create VO instances programmatically:


Here you can see how VO instances are created and registered:


We pass as a parameter - EO name, based on this name for VO is constructed. We check if VO with the same name already is registered, if not - VO will be created from EO. There is no need to set attributes one by one for VO, we can get all attributes directly from EO. SQL statement is created by API, based on EO information. Finally - create VO instance, based on VO definition, this will expose it to the Data Control and we could access it later on runtime from bindings. VO name is returned by the method, this is used later in the page definition to supply dynamic reference to the iterator.

Dynamic reference of the VO instance is defined in the page definition, I'm getting it from Page Flow Scope (initialized through Method Call activity calling dynamic VO construction method):


UI table is rendered with the help of ADF dynamic table component, this is pretty easy part:


Before actual UI fragment with the table is opened, we call Method Call activity and invoke dynamic VO construction method exposed through AM client interface - this allows to prepare current VO instance based on passed EO name parameter:


EO name parameter is defined as required on the task flow level, rendering UI fragment with dynamic table:


For the test purposes, I have created simple main page and passing parameters for Employees and Departments having two different regions. In real use cases, this can be changed by loading the same region and passing different EO name from menu model:


Here what we can see on UI - first tab brings dynamic VO instance for Employees:


Second tab brings another dynamic VO instance, reusing the same UI - this time for Departments:


Controlling ADF BC Mandatory Attribute Validation Conditionally

$
0
0
I was looking for a solution to control ADF BC attribute mandatory validation conditionally, and there is one - we can implement dynamic switch for attribute mandatory validation. Thanks to Steve Muench, who was helping to implement this requirement - I'm able to provide working sample. The main idea is - based on master attribute value, set dependent attribute to become mandatory/non-mandatory automatically. This will be implemented by controlling dynamic mandatory attribute rule in ADF BC level.

Make sure to download sample application, to test this use case - DynamicMandatoryAttrApp.zip. Test is fairly simple, there is special column displaying true/false values - meaning if CommissionPct attribute is set to be required or no in the current row. CommissionPct attribute is set to be mandatory, if Salary attribute value is greater than 10000:


You should see for Employee ID = 108, CommissionPct attribute is set to be mandatory. Try to set Salary attribute value for this employee to be less than 10000, CommissionPct attribute becomes non-mandatory instantly:


We are going to check now, how such functionality is implemented in ADF BC. There is custom Entity Attributes Hints class registered in EO implementation class:


Through this custom class we can intercept all calls to ADF BC to retrieve hints for given attribute. Mandatory property is one of the hints, this is how we can return true or false conditionally.

If you are running ADF version starting from 11g R2 or 12c, there is internal issue - it requires to set attribute index explicitly through getAttributeHints(name) method. Otherwise, custom class for Entity Attribute Hints - will be ignored:


In the custom class for Entity Attribute Hints, we can override standard method - getHint(locale, name). In this method we could evaluate conditionally or mandatory checks, as in this example CommissionPct attribute is marked to be mandatory, only if Salary value is greater than 10000:


Initially, CommissionPct attribute is set to be non-mandatory:


There are several changes required on ADF UI level, to make it work correctly. I would recommend to set contentDelivery=immediate and immediate=true for the ADF table component, this allows to reduce number of validation error popups:


When Salary attribute changes, we need to refresh dependent CommissionPct attribute, however it would not work to use regular PartialTrigger dependency and bypass validation error. We need to create binding reference and call partial target refresh programmatically. Read more here - Conditionally Required Fields in Oracle ADF Faces Rich Client. Similar binding is created for Panel Collection:


Salary attribute is set with AutoSubmit=true and Value Change Listener (we refresh table component):


Refresh is done from table component:


Make sure to change ADF UI mandatory expression, to use row.bindings.CommissionPct.hints.mandatory. Otherwise, with default expression generated for ADF table column attribute by JDeveloper, ADF UI fails to trigger getHint method in ADF BC for mandatory check:

UKOUG Tech13 - Red Samurai Real ADF Experience Sessions

$
0
0
UKOUG Tech13 conference is around the corner and we are completely prepared. My colleague - Florin Marcus and myself, will be presenting together our sessions this coming Sunday, December 1st at UKOUG Tech13 Super Sunday event. If you are around, please stop by and ask ADF questions - we are going to be more than happy to help you out.

I would like to post short summary about sessions we are going to present. There are two sessions:

1. ADF Anti-Patterns: Dangerous Tutorials


We are going to share very important hints, usually hidden behind typical ADF tutorials available on the Web and demo side-effects for various default ADF settings. This will be live ADF code session, each of the points will be explained directly in JDeveloper, without using boring Power Point slides.

There will be real ADF tuning tricks explained, collected through years of ADF experience.

2. ADF Development Survival Kit


Wouldn't it be great to hear how to build your own ADF Performance Audit Tool? We are going to explain how our ADF Performance Audit Tool works and even more important - how it is built, so you can build yours, once back home. Here is architecture preview to be explained:


We are going to focus on importance of PL/SQL code reuse while building ADF applications and modernizing Oracle Forms systems. There will be a demo, followed by detailed explanation how our PL/SQL reuse tool for ADF is implemented and how it works from ADF BC:


We are going even further than that - will be explaining Red Samurai process to reuse existing PL/SQL or Web Services code in ADF BC through automation and injection:


Thanks for reading my blog and hope to see you on UKOUG, will be extremely happy to chat with you - blog reader.

ADF Anti-Patterns: Dangerous Tutorials - Real Experience in ADF

$
0
0
Florin and me were presenting two sessions on UKOUG - UKOUG Tech13 - Red Samurai Real ADF Experience Sessions. There was quite a lot of content described and demoed, this is why I decided to split it into two different posts. This post will be about ADF Anti-Patterns: Dangerous Tutorials. The main idea behind this session was to describe most common misunderstanding hidden by typical ADF tutorials available on the Web.



We have prepared special app for this session, separating each use case into different module. You can download complete sample application - DangerousApp.zip.

Here is the picture of us presenting:


You can check uploaded slides for more details, below I will describe in addition every point presented. All the code listed is part of sample application, you can download it and check directly.

1. Batches Of and Slow Query

I believe you had experienced such situation, when SQL query was executed fast in SQL Developer, but slow in ADF. You should remember - ADF is executed from the server and there is additional roundtrip to bring data from DB. Also it depends how many rows are fetched in result set from DB to the server. By default, Batches Of property is set to 1:


We recommend to increase it for better performance and communication between WebLogic server and DB - this would allow to bring more rows in less roundtrips. There is a way to do this task in generic way, programatically - check the source code of sample application:


If you want to track time taken to execute VO, you could do this from the same executeQueryForCollection method - simply get start, end times and log:


2. Large Fetch

You can monitor row fetches performed in ADF with standard ADF BC method - createInstanceFromResultSet:


We would recommend to disable full table scroll by setting RowCountThreshold property for iterator in Page Definition to -1. Read more about this here: How To Disable SELECT COUNT Execution for ADF Table Rendering:


Make sure -1 is not set for LOV ListRangeSize property, otherwise it will be fetching all rows from DB, when LOV popup will be opened. Read more about it here: Fix Rowset is Forward Only Error for ADF BC LOV Range Paging (11.1.2.1.0):


3. Groovy Misuse

Keep in mind - when using Groovy function, it calls basic SQL statement, fetches records into memory and performs intended function. This would mean, it could fetch lots of rows into memory and only later produce requested result. Instead, you should consider using optimised SQL query directly for better performance, without using Groovy function.

Here is Groovy sum function example:


From the log you could see basic SQL statement executed and all rows fetched (2 rows in this example, it will be much more in real life scenario):


Another possible slow performance case with Groovy - calling Java method from Groovy attribute value expression. Especially if this Java method in turn is calling VO to fetch data from DB. The problem is related to numerous invocation of the same method by Groovy expression defined for attribute value. Here is example of such Groovy expression calling Java method from attribute value:


Java method is basically calling VO and executing it:


From the log we can see - VO was invoked and SQL executed at least two times in this example:


4. Passivation/Activation

When rendering ADF table, by default two requests are made. Between these requests, passivation/activation may happen and this going to slow down application performance. We could minimise this up to one request by setting ContentDelivery=immediate for ADF table, to prevent unnecessary passivation/activation. You can read more about it in this post: Immediate Effect for ADF Table Content Delivery:


ORDER BY and large fetch related issue was described in addition, it is document in this post: Reproducing WebLogic Stuck Threads with ADF CreateInsert Operation and ORDER BY Clause

5. ADF Query Misuse

Make sure not mix-up Bind Variables in VO, while using them from View Criteria. In this case I demo wrong scenario - Bind Variable is defined as Required, Where type:


This Bind Variable is used later from View Criteria. For Required, Where type Bind Variables, JDeveloper allows to choose Ignore Null Values option. Eventually this will break DB index usage, as IS NULL will be applied for the column:

ADF Development Survival Kit - Essentials for ADF Developer

$
0
0
This post is about our second session on UKOUG Tech12 conference. We were presenting and describing essential tools for successful ADF development. These tools are not available from Oracle, but can be implemented by yourself. I'm going to give a walk through for our session in this post.


1. Red Samurai Performance Audit

We believe monitoring of ADF BC and interaction with DB is the key for ADF application performance tuning. This is why we focus primarily on ADF BC and offer statistical information not available through Oracle Enterprise Manager and DMS servlet out of the box.

We offer this ADF performance audit tool for our customers only, there is no direct download. However, you can send me email with your request - you should describe ADF performance problem you want to fix, I will evaluate it and send install files to you.

Here you can see main dashboard for performance audit, displaying overall system performance - all transactions, logged users, query distribution per AM, number of users vs. number of activations:


Every Application Module performance is displayed using ADF dial gauge component:


We log following statistic for slow ADF performance:


Even more:


Overall performance overview:


This is how our audit is implemented (you can see more details in slides). Our ADF BC generic classes are injected into ADF application, statistical information is written to DB through separate thread. There is separate ADF application implemented as dashboard to review logged statistics:


2. PL/SQL code reuse

We were presenting custom made JDeveloper extension to call PL/SQL logic through declarative way, avoiding writing Java logic over and over again:


If you are interested in demo application and see how it works, let me know by email:


3. Semi-Automated Business Logic Reuse for Forms modernisation

Semi-Automated process was presented based on generic DB Validator to simplify PL/SQL or Web Service logic reuse in ADF applications. Here you can see diagram, send me email if you are interested in more details:


4. OJAudit extension for JDeveloper

Finally, we were presenting our extension for JDeveloper, implementing a set of custom OJAudit rules. We are going to merge it with ADF EMG OJAudit extension available for public download.

Recording ADF BC View Object Instance Activation Time

$
0
0
Probably you already now - if there are too many Passivation/Activation events happening in the system, this may slow down your ADF application significantly. There are ways how to minimize number of Passivation/Activation occurrences by tuning Application Module settings. This post is about how to track actual time that takes to activate View Object instances - SQL execution and data fetch times during activation.

We need to use several overridden methods from ADF BC API, to track each View Object instance activation time. We are interested in View Object instance activation time, as this is where actual SQL execution and data fetch happens during activation - most of the time during activation is consumed here. Activation happens in following order:

1. Application Module instance is activated
2. View Object instance executes SQL statement
3. View Object instance fetches records from DB
4. Next View Object instance executes SQL statement
5. Next View Object instance fetches records from DB

As you can see, Application Module finishes activation before View Object instances are starting activation. This is the reason, we need to override several methods from ADF BC, to properly track activation time for each View Object.

Sample application - stresstest_v4.zip is using similar concepts as implemented in our ADF performance audit tool - Major Release for Red Samurai Performance Audit Tool v 2.0. Generic Application Module Implementation class overrides activateState method, we are using it to set activation event identifier, remember - Application Module is activated before View Objects. We are able to group later all View Objects activated during the same activation event by this identifier - stored temporary in ADF BC memory scope of user data:


Activation start time for each View Object instance is recorded in prepareForActivation method. End time is logged in activateCurrentRow method - this method is invoked after SQL query execution and data fetch, it makes it perfect place to log end time per individual View Object instance:


Application Module Pooling for sample application is disabled - this allows to test how activation time is logged:


This sample application UI - Jobs and Departments View Objects are exposed, both of them should participate in activation events:


Here we can see the log - activation events for Jobs and Departments are started right before Application Module activation ends. Jobs View Object activation ends after Jobs SQL query was executed and data was fetched, activation for this View Object is completed in 16 milliseconds:


Departments View Object is activated next - SQL query is executed, along with data fetching in 47 seconds. Keep in mind - last View Object activation time always will be the longest - as all View Objects instances are prepared for activation before the first View Object instance was activated. Activation process is sequential, each View Object instance one by one. Last View Object instance activation time will show total activation time for all View Objects:

How to Minimize Number of ADF BC Application Module Activations

$
0
0
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 

Detail View Object Instance Programmatic Access

$
0
0
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:


Workaround for Infamous Bug 13626875

$
0
0
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

Update For: Recording ADF BC View Object Instance Activation Time

$
0
0
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:

Update for Red Samurai Performance Audit Tool - v 2.3

$
0
0
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:

ADF Dynamic ADF BC - Surviving Passivation/Activation Events

$
0
0
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:

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

$
0
0
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:

Simple Example for ADF Active Data Service

$
0
0
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:

ADF BC Application Module Instance Timeout and Web Session Timeout Dependency

$
0
0
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 even 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:


Accessing Custom Attribute Property from ADF UI Expression

$
0
0
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.

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

$
0
0
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.

Update for Red Samurai Performance Audit Tool - v 2.4

$
0
0
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:

Practical Example for ADF Active Data Service

$
0
0
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):

AMStatistics - Adding Custom Statistics to ADF BC

$
0
0
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.
Viewing all 685 articles
Browse latest View live