(For more resources on Oracle, see here.)
The following diadram illustrates the roles of each layer.
Use AJAX to boost up the performance of your web pages
Avoid mixing of html tags with ADF Faces components
Avoid long Ids for User Interface components
It's always recommended to use short Ids for your User Interface (UI) components. Your JSF page finally boils down to html contents, whose size decides the network bandwidth usage for your web application. If you use long Ids for UI (User Interface) component, that increases the size of the generated html content. This becomes even worse, if you have many UI elements with long Ids.
If there's no Id is set for a UI component explicitly, ADF Faces runtime auto generates Ids for you. ADF Faces let you to control the auto generation of component ids by setting context parameter 'oracle.adf.view.rich.SUPPRESS_IDS' in the web.xml file. The <context-param> entry in the web.xml file may look like as shown below.
<param-value>auto or explicit </param-value>
Possible values for oracle.adf.view.rich.SUPPRESS_IDS are listed below.
- auto: Components can suppress auto generated IDs, but explicitly set ID will be honored.
- explicit: This is the default value for oracle.adf.view.rich.SUPPRESS_IDS parameter. In this case both auto generated IDs and explicitly set IDs would get suppressed.
Avoid mixing JSF/ADF Faces and JavaServer Pages Standard Tag Library (JSTL) tags
Stick on JSF/ADF Faces components for building your UI as much as you can. JSF component may not work properly with some JSTL tags as they are not designed to co-exist. Relying on JSF/ADF Faces components may give you better extensibility and portability for your application as bonus.
Don't generate client component unless it's really needed
ADF Faces runtime generates the client components only when they are really required on the client. However you can override this behavior by setting the attribute clientComponent to true, as shown in the following code snippet.
<af:commandButton text="DoSomething" clientComponent="true">
<af:clientListener method="doSomething" type="action"/>
In the above diagram, you can see that no client side component is generated for the server component whose clientComponent attribute is set to false.
Prefer not to render the components over hiding components from DOM tree
If you need to hide UI components conditionally on a page, try achieving this with rendered property of the component instead of using visible property. Because the later creates the component instance and then hides the same from client side DOM tree, where as the first approach skips the component creation at the server side itself and client side DOM does not have this element added. Apparently setting rendered to false, reduces the client content size and gives better performance as bonus.
(For more resources on Oracle, see here.)
Prefer to use click-To-Edit over edit-All mode for tables
The click-To-Edit mode table lets the end user to edit the selected rows in a lockstep fashion, one row at a time. Advantages of using click-To-Edit mode are listed below.
- In a click-To-Edit, non editable rows are rendered as output components which tend to generate less HTML than input components.
- Client components are not created for the read-only rows.
- Validation phase is also optimized to handle one row at a time.
- Request and Response data is significantly lower in this mode as data relevant to the current editable row alone is being transferred between client and server. Really a good option if the table has large number of rows.
Fine tune the UI tables, displayed on your web page
- Use appropriate content delivery mode
Pick up the suitable content delivery mechanism for your UI table to accelerate the performance. Data can be delivered to table either upon rendering the page or lazily as separate Partial Page Request (PPR). This behavior is controlled by the contentDelivery attribute. Possible values for this attribute are:
- Use suitable fetch size
Data fetch size for a table plays critical role in deciding the performance of the containing pages. The attribute fetchSize decides the number of rows needs to be retrieved during each server round trip. You may need to ensure that value specified for this attribute is good enough to fill the displayed table rows to avoid further server round trips.
The above discussion is applicable for tree and tree table as well.
Pickup right component to display list of values (LOV)
ADF Faces provides multiple components or modes to display the 'list of values'. You may need to choose the right one based on your business requirements.
Input Text with List of Values
Combo Box with List of Values
Choice List, Combo Box, List Box, Radio Group
Both af:inputListOfValues and af:inputComboboxListOfValues are smart enough to load the list of values on demand(lazy loading) where as af:selectOneChoice reads the entire list and populates the same when the page renders(greedy loading). You need to me be aware of the performance cost associated with each of these components. As a rule of thumb, consider af:selectOneChoice to display the list of values if the number of elements is less (say 15 or less) .In all other cases consider using either af:inputListOfValues or af:inputComboboxListOfValues, which loads list on demand.
Use customized Skins to style your pages
If you need to specify custom styles (look and feel) such as height, width, font size etc. for components on a page, then use ADF Faces skinning solution. Though you can do this by overriding inline style for each component, this may not be a viable solutions if this style needs to be applied across pages. ADF Faces always lets you to override the default look and feel for a component by creating custom skins. Skinning let you to override the look and feel of UI components across application. If you need to apply the style to a specific group of components alone, then you can create a style class with standard selector(s), and apply them by setting the styleClass attribute of the component to the desired style class.
Choose the right layouts to design your pages
While lay outing components on page, choose the right layout component that meets your requirement. If you don’t want stretch-to-fit layout, then dot use them at all. A stretch-to-fit layout is not as good performant as fixed height-width layouts. Situation becomes worse, if you have nested containers with many child UI components inside. Apart from these geometry management components, there are certain attributes which may need special attention on the same context. You may need to be measured while opting for columnStretching property for a table to stretch the column to fit the available width. The columnStretching adds extra overhead on the client side at runtime. When the table is a complex one with large number of columns and rows, this becomes very expensive operation. The same point is applicable for table with frozen columns (frozen=true), they are also expensive on the client side.
Avoid repetitive coding by improving the reusability
When you build an application, avoid replicating the same piece of code or component definitions across pages. ADF Faces is built focusing on maximum reusability and minimal boiler plate code. Consider one of the approaches explained below, to improve the reusability in your application.
- Page templates
Page template helps you to keep generic page definition in one place and reuse the same as basis for building pages and page fragments. New pages generated based on the page template inherit the layout defined for the page template and these pages can add the custom contents in the place holders provided by the template. You may need to be cautious while choosing layout for page template as this repeats across multiple pages in your application. Try to keep the layout simple and efficient.
- Declarative components
The declarative components follows composite design pattern, where you can assemble individual UI components into one composite reusable component. The same can be used declaratively in multiple pages. This really helps you to build complex reusable UI by composing multiple components. Declarative components can also be used in page templates.
- ADF task flows
Task flows provide a modular approach for defining control flow in an application. If you have use case which involves multiple tasks that needs to be carried out in a step by step manner, apparently that turns out to a perfect candidate for a 'task flow'. Task flow encapsulates business logic, process flow, and UI components all in one package, which can then be consumed by multiple teams declaratively.
- Page Fragments
If you page is cluttered with huge chunk of UI components and the same repeats across pages in your application, try considering creating reusable page fragments and later consume them from the client pages. A page fragment, as the name stands represents portion of page embedded inside <jsp:root> tag.
Use resource bundles intelligently
Success of a product depends on its marketability across the globe. Obviously, localization of messages and labels play a very vital role in this context. As you use Java for building fusion web application, you may need to use java.util.ResourceBundle to store locale specific objects like messages or labels. A couple of points on the effective usage of ResourceBundles are listed below.
- If the size of your resource bundle is huge, logically split that into multiple resource bundles. While splitting, please make sure that a single page doesn't need to look in to multiple bundles to get the localized strings.
- Don’t over engineer your product by caching the ResourceBundle in your managed bean or through a custom way, it's already cached for you by design.
Be bold enough to bypass the JSF lifecycle phases as and when needed
The JSF lifecycle is not trivial; each request is routed through definite stages before rendering the page. However there are scenarios where you can bypass certain phases and leverage some performance bonus. While navigating from one page to another, using navigation components, there is no need to stick on the full JSF life cycle. You can short circuit the lifecycle phases by keeping immediate=true for navigation/action components. You can see this in the following diagram that life cycle execution skips to RenderResponse phase when immediate property set as true for an action button.
Please note that, you can skip to the RenderResponse phase by calling javax.faces.context.FacesContext::renderResponse() from any phase of execution.
Always design your Managed Bean for High Availability
Managed Beans are very essential elements for a JSF based application. They act as back up for UI component model and can hold view specific custom business logic as well. There are six types of scopes available for managed beans in a fusion web application as listed in the below diagram.
You may need to take care of following points in regards to managed bean while developing a high available fusion web application.
- Keep the managed beans in the lowest possible scope
While defining managed bean always try to keep them in the lowest possible scope, which reduces the runtime overhead associated with state replication across nodes in a clustered environment.
- Keep the getters/setters of your managed bean (data model) lightweight
You may need to understand that getters and setters for a managed bean used in a page may get called multiple times during the life cycle. Always make sure that assessors specified for the data model doesn't have any complex logic. Use managed bean only to store book keeping information, business logic should reside in your business service layer.
- Bean should be serializable
If the managed bean scope is higher than request, then its state needs to be serialized and copied to other nodes at the end of each request. Obviously beans need to implement java.io.Serializable interface. Note that, member variable of you class should also be serializable, or marked as transient if their state does not need to be replicated at the end of a request.
- Mark ADF scopes as dirty to enable state replication
ADF optimizes state replication of ADF scoped beans to avoid the blind copy of the state at the end of each request. So you may need to ask for state replication by marking them as dirty, based on bean mutation state. Use the below API to ensure the state replication for viewScope or pageFlowScoped bean if its modified for any request.
Log your debugging messages smartly with ADFLogger
It's a bad practice to use System.out.println() to log your debugging or diagnostic messages. There is no easy way to turn off or control these logs when your application goes for production. This may dump all unwanted logs in your application server, adding extra overhead for your system administrator. If the numbers of logs statements are large in number, this may affect your system's runtime performance too. For fusion web application, it is recommended to use oracle.adf.share.logging. ADFLogger to log all debugging messages which gives more control on the logging part. You can easily change log levels (turn off or customize) of ADFLogger using the configuration parameters present in logging.xml.
Speed up your web application by caching static contents
<?xml version="1.0" encoding="windows-1252" ?>
<caching-rule id="cache js">
<caching-rule id="cache jpeg">
In this article, we have learned tips on how to improve the performance and scalability of the view layer of a Fusion Web Application.
- Oracle JRockit: The Definitive Guide [Book]
- Java in Oracle Database [Article]
- Debugging Java Programs using JDB [Article]