Oracle ADF Best Practices for web based application development

The Application Development Framework provides numerous controls and components to make Rich Client UI for the application. The following given best practices can allow the developer to use the available controls and components in the most optimized way.

  1. Avoid using the invokeAction in pageDefbecause will be executed several times. Use a task flow with a method call and the page can be reused in other task flows.
  2. Do not create view criteria’s containing the name of the view since the name of the view can be changes thus require change in the View Criteria also.
  3. Service methods should not be called from the application model as they are dependent of the view iterators Standard operators like standard operations CreateWithParams, ExecuteWithParams can be used to achieve the same.
  4. Always prefer to create the template for the JSP pages and include that in corresponding pages. The UI controls like Panel Splitter, PanelGroupLayout can be used with different facets using the common template structure.
  5. Prefer to create the iterators for the view in the service method ( java bean class) and default iterator provided by view object should be avoided.
  6. Avoid adding HTML content in the JSF pages. Styles or CSS files should be used instead as ADF Framework provides support for that.
  7. Do not use multiple database connection for the same Database, prefer to use nested application module (AppModule).
  8. Do not combine view accessors with data model master-detail because accessor attributes create distinct row sets based on an internal view object other than that from detail
  9. When a view criteria is applied programmatically in a business method from the application model later the view criteria must be removed.
  10. Always use the Connection Type as ‘JDBC DataSource’ and provide the JNDI name defined in the Data Source of Web Logic Server to leverage the Connection setting and pooling techniques provided by the Application Server.
  11. Avoid using the view’s attributes in the WHERE clause for filtering, instead use default criterias for each view instance from the application model
  12. Always define the scope in the JSF Page to use the page variables. Following scopes are used:
  • RequestScope,
  • backingBeanScope,
  • viewScope,
  • pageFlowScope,
  • sessionScope,
  • applicationScope,
  • backingBeanScope

SessionScope and PageFlowScope are preferred if the pages have limited variables and are required to be used by other applications pages.

  1. In the context of fragment based task flows, use viewScope in preference to request scope for a more predictable behavior within the context of the sub-flow that contains the fragments
  2. Use SetPropertyListenerinstead of SetActionListener for passing the values.
  3. Create separate style sheet for different devices in the application and retrieve the value from the <skin-family> tag.
  4. Avoid using heavy images as it increases the loading time of the page.

Caused By: java.net.SocketException: Write failed: Broken pipe

<oracle.adfinternal.view.faces.lifecycle.LifecycleImpl> <BEA-000000> <ADF_FACES-60098:Faces lifecycle receives unhandled exceptions in phase RENDER_RESPONSE 6
javax.faces.FacesException: Write failed: Broken pipe at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._renderResponse(LifecycleImpl.java:920)
at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl._executePhase(LifecycleImpl.java:367)
at oracle.adfinternal.view.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:222)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:266)

at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2179)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1490)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
Caused By: java.net.SocketException: Write failed: Broken pipe
at jrockit.net.SocketNativeIO.writeBytesPinned(Native Method)
at jrockit.net.SocketNativeIO.socketWrite(SocketNativeIO.java:46)
at java.net.SocketOutputStream.socketWrite0(SocketOutputStream.java)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
at weblogic.servlet.internal.ChunkOutput.writeChunkTransfer(ChunkOutput.java:568)
at weblogic.servlet.internal.ChunkOutput.writeChunks(ChunkOutput.java:539)

Solution:

The Broken Pipes messages are caused by applications taking more time to produce a response than Apache timeout. To solve this type of issues, the application needs to be tuned so that the response is provided before timeout fires. The Metalink Note (333862.1) provides the complete Solution.
If the application is OK and the response could not be delivered in a shorter time than Apache timeout, then increase the “Timeout” directive in the http.conf file. (The AS Control Console can be used for this purpose too).
1. In the AS control, select the HTTP Server component.
2. Then select properties.
3. Modify the timeout settings. Each unit represents a second. Default value is 300 (5 minutes).

For more details, refer Metalink Note (333862.1) related to this issue.


javax.faces.application.ViewExpiredException: – ADF_FACES-30107:The view state of the page has expired. Reload the page.

You need to define the value for org.apache.myfaces.trinidad.CLIENT_STATE_MAX_TOKENS in the web.xml of your web application.

<context-param>
<description>Chooses how many tokens should be preserved at any one time.</description>
<param-name>org.apache.myfaces.trinidad.CLIENT_STATE_MAX_TOKENS</param-name>
<param-value>50</param-value>
</context-param>


Caused By: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (APPS.PS_TXN_PK) violated oracle.jbo.PCollException: JBO-28030: Could not insert row into table PS_TXN

This might happen when you deploy another application in the same server environment where the already defined Transaction Id is again attempted to add in the existing table and violates the unique identity constraint. Reset the sequence number.

Other Useful links for the topic in discussion

http://docs.oracle.com/cd/E17904_01/web.1111/b31974/bcstatemgmt.htm#ADFFD1306

http://docs.oracle.com/cd/E17904_01/web.1111/b31974/bcstatemgmt.htm#ADFFD1307

http://docs.oracle.com/cd/E17904_01/core.1111/e10105/repos.htm#ASADM11531


Defining caching rules for images in the ADF Faces Caching Filter

<adf-faces-config xmlns=”http://xmlns.oracle.com/adf/faces/config”>

<caching-rules>
<caching-rule id=”cache js”>
<cache>true</cache>
<compress>true</compress>
<duration>99999</duration>
<agent-caching>true</agent-caching>
<cache-key-pattern>*.js</cache-key-pattern>
</caching-rule>

<caching-rule id=”cache jpeg”>
<cache>true</cache>
<compress>false</compress>
<duration>99999</duration>
<agent-caching>true</agent-caching>
<cache-key-pattern>*.jpeg</cache-key-pattern>
</caching-rule>

<caching-rule id=”cache png”>
<cache>true</cache>
<compress>false</compress>
<duration>99999</duration>
<agent-caching>true</agent-caching>
<cache-key-pattern>*.png</cache-key-pattern>
</caching-rule>

<caching-rule id=”cache PNG”>
<cache>true</cache>
<compress>false</compress>
<duration>99999</duration>
<agent-caching>true</agent-caching>
<cache-key-pattern>*.PNG</cache-key-pattern>ion
</caching-rule>

<caching-rule id=”cache css”>
<duration>99999</duration>
<agent-caching>true</agent-caching>
<cache-key-pattern>*.css</cache-key-pattern>
</caching-rule>

</caching-rules>
</adf-faces-config>


How to execute method on page load method call in ADF Faces

1. Open the page definition of your JSF Page – TestOnPageLoad.jspx

2. Add the controllerlclass in the <PageDefinition> tag as given below

<pageDefinition xmlns=”http://xmlns.oracle.com/adfm/uimodel”
version=”11.1.1.60.13″ id=”TestOnPageLoadPageDef”
Package=”view.pageDefs”
ControllerClass=”com.test.bean.PageLoadBackingBean”>
3. Create the class – executeOnPageLoadMethod which implements PagePhaseListener and override the beforePhase method.

import oracle.adf.controller.faces.context.FacesPageLifecycleContext;
import oracle.adf.controller.v2.lifecycle.Lifecycle;
import oracle.adf.controller.v2.lifecycle.PagePhaseEvent;
import oracle.adf.controller.v2.lifecycle.PagePhaseListener;

import oracle.binding.BindingContainer;

public class executeOnPageLoadMethod implements PagePhaseListener {
private BindingContainer bc = null;

public void beforePhase(PagePhaseEvent event) {
FacesPageLifecycleContext ctx =
(FacesPageLifecycleContext)event.getLifecycleContext();
if (event.getPhaseId() == Lifecycle.PREPARE_MODEL_ID) {
bc = ctx.getBindingContainer();
onPageLoad();
bc = null;
}
}

public void afterPhase(PagePhaseEvent event) {
}

public void onPageLoad() {

}

}

3. Open the Class PageLoadBackingBean and extend the class – executeOnPageLoadMethod
public class PageLoadBackingBean extends executeOnPageLoadMethod {

4. Implement the method onPageLoad in the class – PageLoadBackingBean which is defined in the class – executeOnPageLoadMethod

/**
* Method to override the onPageLoad method of the executeOnPageLoadMethod
* which implements the PagePhaseListener Class
*/
public void onPageLoad() {
if (!AdfFacesContext.getCurrentInstance().isPostback()) {
executeSomeMethod();
}
}

5. public void executeSomeMethod() {

// execute some logic here
}


How ADF client authentication can be defined or set in the web.xml

<security-constraint>

<web-resource-collection>
<web-resource-name>allPages</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>valid-users</role-name>
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<web-resource-name>adfAuthentication</web-resource-name>
<url-pattern>/adfAuthentication</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>valid-users</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>CLIENT-CERT</auth-method>
</login-config>
<security-role>
<role-name>valid-users</role-name>
</security-role>


mime types to be defined in web.xml for pdf, css, images,javascript in the mime-mapping tag

If you are using the PDF or JavaScript or images with differnt extensions png, jpeg, gif then that should be defined

in the mime-mapping tag in the web.xml . Example is given below.
<mime-mapping>
<extension>pdf</extension>
<mime-type>application/pdf</mime-type>
</mime-mapping>
<mime-mapping>
<extension>javascript</extension>
<mime-type>application/x-javascript</mime-type>
</mime-mapping>
<mime-mapping>
<extension>css</extension>
<mime-type>text/css</mime-type>
</mime-mapping>
<mime-mapping>
<extension>swf</extension>
<mime-type>application/x-shockwave-flash</mime-type>
</mime-mapping>
<mime-mapping>
<extension>txt</extension>
<mime-type>text/plain</mime-type>
</mime-mapping>
<mime-mapping>
<extension>png</extension>
<mime-type>image/png</mime-type>
</mime-mapping>


How to identify the different user agent values for browsers in ADF Faces

Place the below sample code in your application to receive the user agent values for browsers like safari, chrome ,IE , Mozilla

public String getUserAgentValue() {
FacesContext facesCtx = FacesContext.getCurrentInstance().getCurrentInstance();
ExternalContext externalctx = facesCtx.getExternalContext();
HttpServletRequest request = (HttpServletRequest)externalctx.getRequest();
String userAgentVal = null;
userAgentVal=request.getHeader(“User-Agent”);
userAgentVal=userAgentVal.toLowerCase();

if (userAgentVal != null && userAgentVal.indexOf(“iphone”) > -1) {
userAgentVal = “iPhone”;
}

else if (userAgentVal != null && userAgentVal.indexOf(“android”) > -1) {
if (userAgentVal.indexOf(“mobile”) > -1)
userAgentVal = “Android Phone”;
else
userAgentVal = “Android Tablet”;
}

else if (userAgentVal != null && userAgentVal.indexOf(“ipad”) > -1) {
userAgentVal = “iPad”;
}

else if (userAgentVal != null && userAgentVal.indexOf(“macintosh”) > -1) {
userAgentVal = “Macbook”;
}

else if (userAgentVal != null && userAgentVal.indexOf(“windows”) > -1) {
userAgentVal = “Windows”;
}

else
{
userAgentVal=”Could not identify…”;
}

return userAgentVal;
}


How to remove default value “ALL” from the and

If you see the below given value in the SelectItem it does not show the value for “ALL” but still the option “ALL” will be shown
in the mutiple selection.

<af:selectManyChoice label=”SelectManyChoiceExp”
binding=”#{backingBeanScope.backing_sample.smc1}”
id=”smc1″>
<af:selectItem label=”One” value=”One”
binding=”#{backingBeanScope.backing_sample.si1}”
id=”si1″/>
<af:selectItem label=”Two” value=”Two”
binding=”#{backingBeanScope.backing_sample.si2}”
id=”si2″/>
</af:selectManyChoice>

<af:selectManyListbox label=”SelectManyListBoxExp”
binding=”#{backingBeanScope.backing_sample.sml1}”
id=”sml1″>
<af:selectItem label=”One” value=”One”
binding=”#{backingBeanScope.backing_sample.si3}”
id=”si3″/>
<af:selectItem label=”Two” value=”Two”
binding=”#{backingBeanScope.backing_sample.si4}”
id=”si4″/>
<af:selectItem label=”Three” value=”Three”
binding=”#{backingBeanScope.backing_sample.si5}”
id=”si5″/>
</af:selectManyListbox>

To remove this, select the component af:selectManyListbox or af:selectManyChoice and open the Apperance Tab in the Property Inspector
Search for the property field: SelectAllVisible and set it to FALSE.