Monday, December 19, 2011

ADF Performance Tuning Tips

Below are important tips learnt by experience to imporve performance of an Fussion Middleware ADF Application.
- Make sure to have unique/Primary key defined on every View Object
- Ensure none of Page definitions should have more than one data control If not needed. This may result in increasing number of database connections.
- Avoid binding UI components in backing beans, If used make them as transient
- Ensure each backing bean/Manage bean should implements java.io.Serializble interface.
- Ensure not to have any member level variables at application module level.
- Split as much as possible to smaller application module based on functional area.
- Never ever use ApplicationModule Locator to get the instance of any application module anywhere project except Web services project. Implement Nested application module technique if there is requirement to get instance of any application module
- Remove unused VOIterators on JSFF Page definitions.
- Avoid writing more complex logic in backing beans, instead redirect/move business logic associated AMImpl.
- Close rowsetIterators finally.
- This is only for Transient View objects - General -> Tuning -> Ensure to check ONLY 'No Rows' options rest all unchecked aslo check ' Passivate State' option.
- Avoid storing data into Session Scope as much as can.
- use "blocking=true" for and to avoid multiple clicks on submit buttons.
- Use Programmatic VO's ( Transient VO's) only if required.
- While using tree or table components, set correct fetch size(this determines the number of rows to be sent to the client in one round trip) value.
- Best practice to define Navigational flows in the task flows instead Using NavigationalHandler in backing bean scope to define the Navigation.
- Use blocking=true for submit buttons to avoid multiple clicks
- Set immediate property value to 'true' wherever needed.
- Remove unused VOIterators from page(jsff/jspx) definitions.
- Use PPR as much as needed.
- Remove unused data controls from page definitions files, this may result in increased database connections.
- Don't use JSF/ADF Faces & JSTL together.
- Ensure each backing bean must implements java.io.serializable
- Ensure to define same scope ( Pageflow,Backingbean) for a backing bean across all .jsff , task flows and adfc-config.cml.
- Never use getRowCount() unless if it is really needed
- Avoid smart logic for SQL conditional where clause - Most of the times we try to avoid multiple view objects usage while we are building large scale web applications using Fusion middleware. For eg We may have scenario to query Employee table using different bind variables based on requirement , We may not like to create such number of Read only view objects or Updateable view objects for each bind parameter (like : first name, last name, salary, etcc) what we do is we will create one ROVO and specify CONDITIONAL WHERE CLAUSE like below

Have a purge job to clean up PS_TXN  table frequently
- Unselect 'Disconnect Application Module Upon Release' option. For better understanding about this

If jbo.doconnectionpooling=false, which is the default, then when an AM instance is created in any pool it acquires a JDBC connection from the appropriate connection pool (based on the JDBC URL in the ADF case, or from the underlying JDBC datasource implementation's pool in the case of a JNDI datasource name). That AM instance holds onto the JDBC connection object that it acquired from the pool until the AM instance is removed from the AM pool. During its lifetime, that AM instance may service many different users, and ADF worries about issuing rollbacks on the database connection so that different users don't end up getting pending database state confused. This provides the best performance in general because, by holding onto the JDBC connection, it allows each AM instance to keep its JDBC PreparedStatements's open and usable across subsequent accesses by clients.
If jbo.doconnectionpooling=true, then each time a user session finishes using an AM (typically at the end of each HTTP request), the AM instance disassociates itself with the JDBC connection it was using on that request and it returns it to the JDBC connection pool. The next time that AM instance is used by a user session, it will reacquire a JDBC connection from the JDBC connection pool and use it for the span of time that that AM is checked out of the AM pool (again, typically the span of one HTTP request). Since the AM instance "unplugs" itself from the JDBC connection object used to create the PreparedStatements it might have used during the servicing of the current HTTP request, those PreparedStatements are no longer usable on the next HTTP request because they are only valid in the context of the Connection object in which they were created. So, using the connection pooling mode turned "on" like this, the tradeoff is a slightly more JDBC setup/overhead each time in return for using a smaller number of overall database connections.


SELECT first_name, last_name, subsidiary_id, employee_id FROM employees WHERE ( subsidiary_id = :sub_id OR :sub_id IS NULL ) AND ( employee_id = :emp_id OR :emp_id IS NULL ) AND ( UPPER(last_name) = :name OR :name IS NULL )

This is not good approach because, above conditional where clause thorws any idexes out the window when the query is being executed. So better to avoid Conditional where clause bind parameters as much as needed, Instead we can try using 'View Criteria'


- If any ViewObject dragged onto page fragment as component, Make sure fetchSize should be #{bindings.MyView.rangeSize} - Good practice to keep fetchSize as low as possible.
- If there are any common LOV's are being used in respective page fragments ad a independent components, then define them in 'faces-config.xml' and use wherever needed instead of binding to each page fragment.

- Tune Data Source Connection Pool

- Inactive Session Time Out - Configure this value corresponding to the data source in weblogic console, leaving blank this value means it is disabled.In order to optimize Data Source usage, you need to enable Inactive Connection Timeout option in WebLogic Console. With this option enabled, WebLogic will try to return inactive reserved connections from Connections in Use pool to Available Connections pool. This will prevent Connections Pool Size grow. Just set positive number of seconds:


- Make sure in VO->General->Tuning-> Batches of field must be updated with VO Iterator range size ( By default 25 you see in Page Def) plus 1

- Reference Pool Size :  Number of AM's in the pool that attempts to preserve session affinity for the next request, by default this value is '10' , that you can find in  'Pool and Scalability' section of Application Module, Bump up this value for better performance.

- Maximum Available Pool Size : By default this value is '25', Higher values makes more AM's available and improves performance

- Idea instance time out : By default this value is 10 Minutes, Bump up this value for better performance, This is strictly based on nature of the users who access the screens, If the nature of application , intented audience access the pages for lesser than 10 minutes for a given instance, then keep this value as it is, If users spends more time on/off on the screen, then increase this value.

- Maximum Instance Time to Live(jbo.ampool.timetolive) : Milli seconds that an application module instance lives in the pool, By default this value is '1hr' , Set this value to '-1' for better performance

- Partial Submit - Make us of the powerful AJAX capabilities, Use Partial page requests instead of full page requests. Set wherever possible on all buttons, links, menu-items 'partial-submit=true'

- Include only selected attributes in the select clause, Reduce the number of attributes retrieved from the database for each query.

- If it is Table layout, Set 'Only up to row number to '250' rather than 'All Rows' in View Object -> General -> Tuning section.

- View Object Range Paging -  If you have to display more than 500 rows in a table, Set View Object -> General-> Tuning -> Access Mode -> 'Range Paging' , This will allows you to move quickly to bottom of the <af:table> component by  just scrolling down vertical scroll bar & Set 'Range Size' value to '50'

- Scopes - Use small memory scopes as much possible.

- Make Id's value as small as possible, This will avoid too much HTML to the browser.

- PanelTabbed Child Creation - Use 'childCreation="lazyUnCached" ' or 'childCreation="lazy" ' to defer taskflow execution of all tabs until the tab is opened.

- For Popups, use  'childCreation="deferred" '

-  Select ' Customize Runtime instantation Behavior' and select 'Lazy Loading' in Application Module Tuning section - This will defer the runtime instantiation of view object and nested Application Module instances until the time they used

- set 'contentDelivery ="lazy" ' for table, treeTable, tree, popup and menu components.

- 'Apache JMeter' ,'Oracle Application Testing Suite (OATS)' are proven testing tools to test the performance of an ADF applications, HttpWatch,Fiddler2 tools for http watch


Performance Tools

Below are the best performance monitoring tools can be used to keep track.

Oracle JRockit Flight Recordings
Dyna Trace Tool
Solar Winds
KeyNote
Solanium
JMeter
Soapui
LoadRunner


          How to download and install JMeter
          How to Configure JMeter
          JMeter - How To Login Into A Web Application
          How To Use Apache JMeter To Perform Load Testing on a Web Server
          Apache JMeter

Follow Below link for more info
http://docs.oracle.com/cd/E17904_01/core.1111/e10108/adf.htm
http://andrejusb.blogspot.com/2010/02/optimizing-oracle-adf-application-pool.html
http://www.oracle.com/technetwork/developer-tools/jdev/index-097578.html

Thursday, December 8, 2011

How to Reset ADF Table filter values by single button click

Problem : If you noticed anytime using ADF table component enabled filters for all/some of the columns. If you perform filter using one or multiple columns , Then user manually has to remove filter criteria to perform any further search on ADF table component.

To explain more clear : Let us assume ADF table component with 5 columns and filter criteria enabled for each column. If user enters filter criteria for col1, col2, col3 and col4 and hit Enter button , User will find the search results based on filter criteria entered in above columns, If user decided to perform search back without any filters, User has to manually remove the entered filter criteria and then perform search

Solution :
-> Create a command button on UI screen and bind to a backing bean method
-> In Method implementation , get FilterableQueryDescriptor from the ADF Table which is binded to backing bean
-> Clear the filter criteria.
Eg Code Snippet:

public void resetFilter(ActionEvent actionEvent)
{
// Add event code here...
FilterableQueryDescriptor queryDescriptor =

(FilterableQueryDescriptor) .getBindTable().getFilterModel();

if (queryDescriptor != null &&
queryDescriptor.getFilterCriteria() != null)

{

queryDescriptor.getFilterCriteria().clear();

getTollsntaxes().queueEvent(new QueryEvent(getBindTable(),
queryDescriptor));

}

Problems with getting Current Row Index using component

If you noticed you are not getting the correct row index from component in your backing bean where you have binded a Trancient VO as component , The fix is Make sure to have one Primary key attribute in Trancient VO and the value of that must be unique.