Tuesday, December 1, 2009

To Restrict Resizing of ADF Table's column


<af:column sortable="true"headerText="#{bindings.EmployeesView1.hints.EmployeeId.label}" id="c12" align="center"
minimumWidth="100" partialTriggers="::t1">

<af:outputText value="#{row.EmployeeId}"
id="ot11">

<af:convertNumber groupingUsed="false"

pattern="#{bindings.EmployeesView1.hints.EmployeeId.format}"/>

</af:outputText>

<af:clientListener method="setColumnWidth"
type="propertyChange"/>

<af:serverListener type="server"
method="#{yourBackinbean.serverL}"/>

</af:column>

and your javaScript will be:

<af:resource type="javascript">

function setColumnWidth(event) {

var source = event.getSource()

source.setWidth("100px");

AdfCustomEvent.queue(source,"server", {}, false);

}

</af:resource>

and your method in backingbean will be :

public void serverL(ClientEvent clientEvent) {

RequestContext.getCurrentInstance().addPartialTarget(clientEvent.getComponent().getParent());

}





Hint : If you know how to refresh the table from javaScript
you don't need a serverListener

Tuesday, August 4, 2009

Doubts related to JavaScript

go through
http://thepeninsulasedge.com/frank_nimphius/adf-faces-rich-client-javascript-programming/

Calling JavaScript from a Managed Bean

A frequent request we got for ADF Faces in previous releases is for a method that allows developers to call JavaScript functions on a page from a managed bean. Trinidad implemented an API for this and because ADF Faces RC is based on Trinidad, this functionality now becomes available in ADF FAces as well

ExtendedRenderKitService service = Service.getRenderKitService(facesContext, ExtendedRenderKitService.class);
service.addScript(facesContext, "alert('foo');");

Note that calling a JavaScript method may fail if the command component uses PPR.

Thursday, July 23, 2009

Assert enable in jdeveloper

JDK 1.4 and the Assert Keyword (2394626,2394613)
The parser and the code editor do not know about the 'assert' keyword yet. The workaround to enable JDK 1.4 assert keyword support
in the code editor is to uncomment the following line in the $(JDEV_INSTALL_DIR)\jdev\bin\jdev.conf file, and restart JDeveloper:


AddVMOption -DEDITOR_ENABLE_ASSERT=true

Or
go to weblogic bin folder and edit setDomainEnv.bat file
and search
'set JAVA_OPTIONS=%JAVA_OPTIONS% %enableHotswapFlag% -da'
then change it to

'set JAVA_OPTIONS=%JAVA_OPTIONS% %enableHotswapFlag% -ea'
if you want to change default server then you will find bin folder in
system11.1.1.1.33.54.07\DefaultDomain\

Friday, July 17, 2009

How can we find row level changes while you updating a row?

When ever you are creating table, you need to give ROWDEPENDECIES with the CREATE Statement.
After you can access a psuedo column ORA_ROWSCN to get the state of perticular column. ORA_ROWSCN in your update clause to ensure that the row has not changed since the last time you read it
Example
Whene ever you access a record from table you need to get ORA_ROWSCN number store it with your record.
Update tablename set column where id=1 and ORA_ROWSCN= stored number.
if the staement execute none you can tigger the user,that the record has changed somewhere else.

Overcome Concurrency Limitations

Here is how you can solve the concurrency-limiting problem demonstrated in my test case using ROWDEPENDENCIES. The following code creates a new set of tables, opens two SQL*Plus sessions, and executes an anonymous block:


/* create the tables for the test case */
create table t1_rd (c1 number) rowdependencies pctfree 5;

create index idx_t1_rd on t1_rd(c1) pctfree 5;

/* now open 2 SQL*Plus sessions and cut-paste this code in both */

/* session 1*/
alter session set isolation_level=serializable;

begin
FOR i IN 1..10000
LOOP
insert into t1_rd values(i);
END LOOP;
end;


/* session 2*/
alter session set isolation_level=serializable;

begin
FOR i IN 1..10000
LOOP
insert into t1_rd values(i);
END LOOP;
end;

/* now in both sessions, execute the anonymous block*/

/* session 1 */
SQL>/

/* session 2*/

SQL>/
Here is the output from both sessions:

SQL> alter session set isolation_level=serializable;

Session altered.

SQL> begin
2 FOR i IN 1..10000
3 LOOP
4 insert into t1_rd values(i);
5 END LOOP;
6 end;
7 /

PL/SQL procedure successfully completed.
The code produced no errors. Now you can commit or rollback to end the transaction. After commit, you can see the rows inserted in the table.
Determine Which Rows Have Been Committed
You can use ROWDEPENDENCIES to determine which rows have been committed and which rows haven't been committed yet by the same session.



INSERT INTO t1_rd VALUES (100);

INSERT INTO t1_rd VALUES (101);

SELECT c1, ORA_ROWSCN FROM t1_rd WHERE ORA_ROWSCN IS NULL;

INSERT INTO t1 values (1000);

INSERT INTO t1 values (1001);

SELECT c1, ORA_ROWSCN FROM t1;

In tables with ROWDEPENDENCIES, the ORA_ROWSCN column is NULL for uncommitted rows.
With these techniques, you can improve application concurrency and avoid that dreaded ORA-8177 error.

A Java API for XQuery

A Basic Example
Here's a basic code example that uses XQJ to execute a query that illustrates a typical use. Note that error handling has been omitted for clarity.


// obtain an XQDataSource instance
XQDataSource xqds = (XQDataSource)
Class.forName("com.jsr225.xqj").newInstance();
// obtain a connection
XQConnection con = xqds.getConnection("usr", "passwd");

// prepare an XQuery Expression
String xqry = "for $i in fn:collection('dept') " +
"where $i/deptname = %dname return count($i/employees)";
XQPreparedExpression expr = con,preparedExpression(xqry);

// bind variable with value
expr.bindString(new Qname("dname"), "engineering");

// execute the XQuery Expression
XQResultSequence rs = expr.executeQuery();

// Consume results
while (rs.next())
{
System.out.printLn(rs.getInt());
}

// clean up resources
rs.close();
con.close();

In the preceding code, XQDataSource is an interface from which you obtain XQuery connections. You can create the initial implementation class for the XQDataSource interface via a typical data source instantiation mechanism, such as JNDI look up or an explicit class-loading method. This is similar to the design of JDBC's DataSource and Connection interfaces.

After obtaining an XQConnection, you execute the XQuery using either the XQExpression or XQPreparedExpression interfaces. You'd use XQExpression when you want to execute an XQuery expression once, and XQPreparedExpression when you want to prepare the XQuery expression once and execute it multiple times with different bind values, as illustrated in the preceding example. These two interfaces are similar to the concepts of Statement and PreparedStatement in JDBC, respectively.

An XQuery result is an instance of the XQuery data model. The XQResultSequence shown in the example provides a cursor-centric interface that allows users to iterate through each item in the result sequence. Users can obtain values from each item, either atomic values or XML nodes. This is similar to iterating through a JDBC result set.

After consuming the XQuery results, developers need to clean up the resources by calling the close() method on the XQResultSequence and XQConnection interfaces. Proper error-handling code for releasing resources is critical to avoid resource leakage. The framework implicitly closes items created from the sequence result when the sequence result is closed. Similarly, the sequence result is implicitly closed if the connection is closed.

Wednesday, June 24, 2009

to refresh Lov when its launching

RichInputListOfValues lovComp = (RichInputListOfValues)launchPopupEvent.getComponent(); FacesCtrlLOVBinding.ListOfValuesModelImpl lovModel = null; lovModel = (FacesCtrlLOVBinding.ListOfValuesModelImpl) lovComp.getModel(); lovModel.performQuery(lovModel.getQueryDescriptor());

Friday, June 19, 2009

Implementing auto suggest functionality in ADF Faces Rich Client

Introduction

A native auto suggest component for ADF Faces Rich Client is on the list of new features planned for a future release of Oracle JDeveloper. However, as mentioned before, its less the component than the functionality that is of interest and the functionality is what can be build with ADF Faces Rich client on-board means today. This articles explains the architecture and the JDeveloper 11g workspace of a first prototype that we plan to enhance to a declarative component to a later point in time. We decided to release our prototype with this article to make the suggest functionality available to ADF Faces customers in a guide for manual implementation.

Architecture

The auto suggest functionality requires a client side and a server side implementation that communicate with each other using an asynchronous communication channel. On the server side we use logic to provide the list of values and to filter the list with each keystroke of the user. The list of values is chosen to display strings as labels and values. On the client side, of course, JavaScript is used to listen for the user keyboard input, to display the suggest list and to send the user entered characters as a payload to the server to filter the data.

A Poor Man's Process Chart

In this version of auto suggest, an af:inputTextField is used as the data input component. As soon as the user starts typing into the field, a JavaScript event is captured by the af:clientListener component, which passes the event on to a JavaScript function to handle the request. The JavaScript function looks at the incoming key code and if it is a valid character, opens the popup dialog below the text field if it is not open. The list box queries the list data from a managed bean that we added as an abstraction layer between the view and the model to allow list data to be read from ADF, POJO and similar. The truth also is that we need this abstraction layer to keep the suggest functionality generic, because we want the developer to decide about the caching strategy for fetched data. In the sample we use ADF Business Components to query the data and here we have the option to tell it to perform follow up queries from memory instead of a database query. When the list data is refreshed, the list component is added as a partial target to refresh at the end of the request. The input focus is put back to the input text field for the user to give us the next character.


ADF Business Components

The suggest list is retrieved from a client method that is exposed on the ADF Business Components Application Module. The method takes a string as an input argument to query the Jobs View Object and returns a List of strings back to the client.
Managed Bean

Two managed beans are used in this prototype: SuggestList and DemoAdfBcSuggestModel. The DemoAdfBcSuggestModel abstracts the ADF Business Components query and returns the list of strings to the SuggestList bean to provide the result to the client. If you plan to customize this sample to your needs, then you need to replace the DemoAdfBcSuggestModel bean with your implementation. The SuggestList provides two key methods:

public ArrayList<SelectItem> getJobList()

This method populates the suggest list. It is referenced from the f:selectItems element, which is a child element of the af:selectOneListbox element that resides in an af:popup component to suggest the values to the user.

 public ArrayList<SelectItem> getJobList() {
//first time query is against database
if (jobList == null){
jobList = new ArrayList<SelectItem>();
List<String> filteredList = null;
filteredList = suggestProvider.filteredValues(srchString, false);
jobList = populateList(filteredList);
}
return jobList;
}


private ArrayList<SelectItem> populateList(List<String> filteredList) {
ArrayList<SelectItem> _list = new ArrayList<SelectItem>();
for(String suggestString : filteredList){
SelectItem si = new SelectItem();
si.setValue(suggestString);
si.setLabel(suggestString);
_list.add(si);
}
return _list;
}

public void doFilterList
On every user keystroke in the suggest input field, the browser client calls the doFilterList method through the af:serverListener component.
 public void doFilterList(ClientEvent clientEvent) {
// set the content for the suggest list
srchString = (String)clientEvent.getParameters().get("filterString");
List<String> filteredList = suggestProvider.filteredValues(srchString, true);
jobList = populateList(filteredList);
RequestContext.getCurrentInstance().addPartialTarget(suggestList);
}

The af:selectOneListbox is refreshed at the end of each call to the doFilterList method so the new list value is populated

JSF page markup


The suggest field has two af:clientListener components assigned that listen for the keyUp and keyDown event. All keyboard events on the suggest field are send to the handleKeyUpOnSuggestField JavaScript function, which takes the event object as an input argument. The event object provides information about the event source, the component receiving the key stroke, and the keyCode pressed. Using the ADF Faces RC client JavaScript APIs, we don't need to deal with browser differences, which is big relief.


<!-- START Suggest Field -->
<af:inputText id="suggestField"
clientComponent="true"
value="#{bindings.JobId.inputValue}"
label="#{bindings.JobId.hints.label}"
required="#{bindings.JobId.hints.mandatory}"
columns="#{bindings.JobId.hints.displayWidth}"
maximumLength="#{bindings.JobId.hints.precision}"
shortDesc="#{bindings.JobId.hints.tooltip}">
<f:validator binding="#{bindings.JobId.validator}"/>
<af:clientListener method="handleKeyUpOnSuggestField"
type="keyUp"/>
<af:clientListener method="handleKeyDownOnSuggestField"
type="keyDown"/>

</af:inputText>
<!-- END Suggest Field -->

The suggest list is defined as follows

<!-- START Suggest Popup -->
<af:popup id="suggestPopup" contentDelivery="immediate" animate="false" clientComponent="true">
<af:selectOneListbox id="joblist" contentStyle="width: 250px;"
size="15" valuePassThru="true"
binding="#{SuggestListBean.suggestList}">
<f:selectItems value="#{SuggestListBean.jobList}"/>
<af:clientListener method="handleListSelection" type="keyUp"/>
<af:clientListener method="handleListSelection" type="click"/>

</af:selectOneListbox>
<af:serverListener type="suggestServerListener"
method="#{SuggestListBean.doFilterList}"/>

</af:popup>
<!-- END Suggest Popup -->

The af:selectOneListbox has two af:clientListener defined that listen for the keyUp and click event for the user to select a value (Enter key , click) or to cancel the action (Esc). The af:serverListener is called from the JavaScript that is executed when the user enters a new character into the suggest input field. The af:serverListener calls the doFilterList method in the SuggestList bean.


JavaScript


JavaScript has become popular with Ajax and also is an option to use with ADF Faces Rich Client. Unlike previous versions of ADF Faces, ADF Faces Rich Client has a real client side framework that by large is used internally, but also exposes public functions to prevent users from hacking the DOM tree.



Start Disclaimer



Before we get into JavaScript programming, we should mention that using JavaScript in ADF Faces Rich Client is the second best solution. The best solution always is to use the JavaServer Faces programming APIs because this is what we have good chances to see migrated from one release to the other, which also includes new browser versions that today we don't know are coming. However, some usecases, like the suggest functionality, require JavaScript to put the logic where it is needed and to save network roundtrips where possible.


End Disclaimer




In this version of Oracle JDeveloper 11g, JavaScript is added to the metacontainer facet of the af:document element. As soon as we see JDeveloper 11g R1 being productive, this part of the code may be changed to the new af:resource element.


<f:facet name="metaContainer">
<af:group>
<![CDATA[
<script>
//******************************************************************
//PROTOTYPE: AUTO SUGGEST
//STATUS: 1.0
//authors: Frank Nimphius, Maroun Imad
//Functionality
//====================================
// Implemented in v 1.0
//1 - Suggest window opens JOB_ID field
//2 - Initial query is to database, follow up queries are in memory
//3 - Enter list with down arrow
//4 - Enter key and mouse click to select
//5 - ESC to close
//******************************************************************

function handleKeyUpOnSuggestField(evt){
// start the popup aligned to the component that launched it
suggestPopup = evt.getSource().findComponent("suggestPopup");
inputField = evt.getSource();

//don't open when user "tabs" into field
if (suggestPopup.isShowing() == false &&
evt.getKeyCode()!= AdfKeyStroke.TAB_KEY){
//We reference a DOM area by using getClientId()+"::content" to position the suggest list. Shame
//on use that we are doing this, but there is no other option we found. Keep in mind that using
//direct DOM references may break the code in the future if the rendering of the component changes
//for whatever reason. For now, we want to feel safe and continue using it

hints = {align:AdfRichPopup.ALIGN_AFTER_START, alignId:evt.getSource().getClientId()+"::content"};
suggestPopup.show(hints);
//disable popup hide to avoid popup to flicker on key press. Note that we override the default framework
//behavior of the popup component for this instance only. When hiding the popup, we re-implement the default
//functionality. By all means, never change the framework functionality on the prototype level as this could
//have an unpredictable impact on all nstances of this type

suggestPopup.hide = function(){}
}

//suppress server access for the following keys
//for better performance

if (evt.getKeyCode() == AdfKeyStroke.ARROWLEFT_KEY
evt.getKeyCode() == AdfKeyStroke.ARROWRIGHT_KEY
evt.getKeyCode() == AdfKeyStroke.ARROWDOWN_KEY
evt.getKeyCode() == AdfKeyStroke.SHIFT_MASK
evt.getKeyCode() == AdfKeyStroke.END_KEY
evt.getKeyCode() == AdfKeyStroke.ALT_KEY
evt.getKeyCode() == AdfKeyStroke.HOME_KEY) {
return false;
}
//close the popup when teh ESC key is pressed
if (evt.getKeyCode() == AdfKeyStroke.ESC_KEY){
hidePopup(evt);
return false;
}

// get the user typed values
valueStr = inputField.getSubmittedValue();
// query suggest list on the server. The custom event references the af:serverListener component
// which calls a server side managed bean method. The payload we send is the current string entered
// in the suggest field

AdfCustomEvent.queue(suggestPopup,"suggestServerListener",
// Send single parameter
{filterString:valueStr},true);

// put focus back to the input text field. We set the timout to 400 ms, which is not the final answer but a
// value that worked for us. In a next version, we may improve this

setTimeout("inputField.focus();",400);
}

//TAB and ARROW DOWN keys navigate to the suggest popup we need to handle this in the key down event as otherwise
//the TAB doesn't work. Note that a TAB key cannot be used to navigate in the suggest list. Use the arrow keys for
//this. The TAB key can be done to navigate the list, but this requires some more JavaScript that we didn't complete
//in time

function handleKeyDownOnSuggestField(evt){
if (evt.getKeyCode() == AdfKeyStroke.ARROWDOWN_KEY) {
selectList = evt.getSource().findComponent("joblist");
selectList.focus();
return false;
}
else{
return false;
}
}

//method called when pressing a key or a mouse button on the list. The ENTER key or a mosue click select
//the list value and write it back to the input text field (the suggest field)

function handleListSelection(evt){
if(evt.getKeyCode() == AdfKeyStroke.ENTER_KEY
evt.getType() == AdfUIInputEvent.CLICK_EVENT_TYPE){
var list = evt.getSource();
evt.cancel();
var listValue = list.getProperty("value");
hidePopup(evt);
inputField = evt.getSource().findComponent("suggestField");
inputField.setValue(listValue);
}
//cancel dialog
else if (evt.getKeyCode() == AdfKeyStroke.ESC_KEY){
hidePopup(evt);
}
}

//function that re-implements the node functionality for the popup to then call it
//Please do as if you've never seen this code ;-)

function hidePopup(evt){
var suggestPopup = evt.getSource().findComponent("suggestPopup");
//re-implement close functionality
suggestPopup.hide = AdfRichPopup.prototype.hide;
suggestPopup.hide();
}
</script>
]]>
</af:group>
</f:facet>

Detecting and handling user session expiry

A frequent question on the JDeveloper OTN forum, and also one that has been asked by customers directly, is how to detect and graceful handle user session expiry due to user inactivity. The problem of user inactivity is that there is no way in JavaEE for the server to call the client when the session has expired. Though you could use JavaScript on the client display to count down the session timeout, eventually showing an alert or redirecting the browser, this goes with a lot of overhead. The main concern raised against unhandled session invalidation due to user inactivity is that the next user request leads to unpredictable results and errors messages. Because all information stored in the user session get lost upon session expiry, you can't recover the session and need to start over again.

The solution to this problem is a servlet filter that works on top of the Faces servlet. The web.xml file would have the servlet configured as follows


<filter>
<filter-name>ApplicationSessionExpiryFilter</filter-name>
<filter-class>adf.sample.ApplicationSessionExpiryFilter</filter-class>
<init-param>
<param-name>SessionTimeoutRedirect</param-name>
<param-value>SessionHasExpired.jspx</param-value>
</init-param>
</filter>

This configures the "ApplicationSessionExpiryFilter" servlet with an initialization parameter for the administrator to configure the page that the filter redirects the request to. In this example, the page is a simple JSP page that only prints a message so the user knows what has happened.

Further in the web.xml file, the filter is assigned to the JavaServer Faces servlet as follows


<filter-mapping>
<filter-name>ApplicationSessionExpiryFilter</filter-name>
<servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

The Servlet filter code compares the session Id of the request with the current session Id. This nicely handles the issue of the JavaEE container implicitly creating a new user session for the incoming request. The only special case to be handled is where the incoming request doesn't have an associated session ID. This is the case for the initial application request.


package adf.sample;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ApplicationSessionExpiryFilter implements Filter {
private FilterConfig _filterConfig = null;
public void init(FilterConfig filterConfig) throws ServletException {
_filterConfig = filterConfig;
}
public void destroy() {
_filterConfig = null;
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
String requestedSession = ((HttpServletRequest)request).getRequestedSessionId();
String currentWebSession = ((HttpServletRequest)request).getSession().getId();
boolean sessionOk = currentWebSession.equalsIgnoreCase(requestedSession);
// if the requested session is null then this is the first application
// request and "false" is acceptable
if (!sessionOk && requestedSession != null){
// the session has expired or renewed. Redirect request
((HttpServletResponse) response).sendRedirect(_filterConfig.getInitParameter("SessionTimeoutRedirect")); }
else{
chain.doFilter(request, response);
}
}
}

This servlet filter works pretty well, except for sessions that are expired because of active session invalidation e.g. when nuking the session to log out of container managed authentication. In this case my recommendation is to extend line 39 to also include a check if security is required. This can be through another initialization parameter that holds the name of a page that the request is redirected to upon logout. In this case you don't redirect the request to the error page but continue with a newly created session.Ps.: For testing and development, set the following parameter in web.xml to 1 so you don't have to wait 35 minutes


<session-config>
<session-timeout>1</session-timeout>
</session-config>


Thursday, June 18, 2009

How to implement drop down list in ADF

In this how-to example I am defining a department drop down list, which shows a list of departments.

Add the following code in the ADF page.

          <af:selectOneChoice label="Department"
value="#{ModelData.department}">
<f:selectItems value="#{DepartmentOptions.departments}"/>
</af:selectOneChoice>

In ADF, selectOneChoice is used for drop down list.

selectOneChoice picks the list of values from 'selectItems' tag.

You can define a managed bean to bind an ArrayList of SelectItem objects to 'selectItems'. or can define a view object and bindings. In this example I have defined a managed bean which provides an ArrayList of SelectItem objects.

Department list Backing bean code.

import java.util.ArrayList;
import java.util.List;

import javax.faces.model.SelectItem;

public class DepartmentOptions {
private List departments;

public DepartmentOptions() {
departments = new ArrayList();
SelectItem department = new SelectItem("10", "Electric");
departments.add(department);
department = new SelectItem("20", "Mechanic");
departments.add(department);
department = new SelectItem("30", "Computer");
departments.add(department);
}

public void setDepartments(List departments) {
this.departments = departments;
}

public List getDepartments() {
return departments;
}
}

How to Implement Dependent Drop Down List in ADF

In this How-to example, I am going to explain, how dependent drop down list can be implemented in ADF.

Here I am creating two drop down lists "Department" and "Employee".
On selecting department, the list of employees will change.


I am assuming that you have sample HR schema installed in your database.

Create View Object DepartmentListVO for Department SelectItems.
Query: Select department_id, department_name from departments

Create View Object EmployeeListVO for Employee SelectItems.
Query: select employee_id, first_name from employees where dapartment_id = :DeptId

Define Bind variables DeptId in EmployeeListVO

Create View Object EmpDeptVO for defining the form elements.
This query varies according to your requirement. At least include employee_id and department_id in your select clause.

Define an Application Module and add above view objects to this application module.

Create a jspx page, drag EmpDeptVO to the jspx page and drop EmpDeptVO as ADF form.

Delete form elements for employee_id and department_id from the page.

Drag DepartmentId from data control under EmpDeptVO and drop as select one choice.
Click on add to define binding for List. Select DepartmentListVO from the Add data source drop down.
Select Display Attribute as DepartmentName.

Id of this select one chioce is auto populated as selectOneChoice1
Drag EmployeeId from data control under EmpDeptVO and drop as select one choice.
Click on add to define binding for List. Select EmployeeListVO from the Add data source drop down.
Select Display Attribute as FirstName.

Id of this select one chioce is auto populated as selectOneChoice2

Select selectOneChoice1 in structure window and go to properties.
Set AutoSubmit property to true

Select selectOneChoice2 in structure window and go to properties.
Set PartialTruggers property to selectOneChoice1

          <af:selectOneChoice value="#{bindings.Departmentid.inputValue}"
label="Department"
id="selectOneChoice1" autoSubmit="true"">
<f:selectItems value="#{bindings.Departmentid.items}"
id="selectItems1"/>
</af:selectOneChoice>
<af:selectOneChoice value="#{bindings.Employeeid.inputValue}"
label="Employee"
id="selectOneChoice2"
partialTriggers="selectOneChoice1">
<f:selectItems value="#{bindings.Employeeid.items}"
id="selectItems2"/>
</af:selectOneChoice>


Right click on the page and go to page definition.
Right click on Bindings -Select 'Insert Inside Bindings' - Select 'Generic Bindings' - select 'Action'

Select EmployeeListVO from data collection
Select Iterator as EmployeeListVOIterator
Select Operation as ExecuteWithParams
Set the value of parameter 'DeptId' as #{bindings.Departmentid.inputValue}
Click OK

Right click on executables - Select 'Insert Inside executables' - select 'InvokeAction'

Give one meaningful id 'InvokeExecuteWithParams'.
Set 'Binds' as 'ExecuteWithParams'
Set 'Refresh' as 'RenderModel'
Click Finish

Drag InvokeExecuteWithParams above EmployeeListVOIterator

Run the page.

  <bindings>
<action IterBinding="EmployeeListVOIterator" id="ExecuteWithParams"
InstanceName="HRAppModuleDataControl.EmployeeListVO"
DataControl="HRAppModuleDataControl" RequiresUpdateModel="true"
Action="executeWithParams">
<NamedData NDName="DeptId"
NDValue="#{bindings.Departmentid.inputValue}"
NDType="oracle.jbo.domain.Number"/>
</action>
..........
..........
</bindings>

<executables>
<invokeAction id="InvokeExecuteWithParams" Binds="ExecuteWithParams"
Refresh="renderModel"/>
<iterator Binds="EmployeeListVOIterator" RangeSize="-1"
DataControl="HRAppModuleDataControl" id="EmployeeListVOIterator"/>
...........
...........
</executables>



How to get Reference of one Managed Bean from other Managed Bean

FacesContext ctx = FacesContext.getCurrentInstance();

Application app = ctx.getApplication();

MyManagedBeanClass mb = (MyManagedBeanClass) app.getVariableResolver().resolveVariable(ctx,"MyManagedBean");

How to override the sort behavior of table column ?

Add following code to managed bean that is accessed from the table's sort listener. In this example, whenever users try to sort on the DepartmentName by clicking onto the table header, the sort criteria is modified to DepartmentId .

import java.util.ArrayList;
import java.util.List;

import oracle.adf.view.faces.component.core.data.CoreTable;
import oracle.adf.view.faces.event.SortEvent;
import oracle.adf.view.faces.model.SortCriterion;


public class Sortbean {
public Sortbean() {
}

public void onSort(SortEvent sortEvent) {

List sortList = sortEvent.getSortCriteria();
SortCriterion sc = (SortCriterion) sortList.get(0);

//override sort by DepartmentName and make it sort by DepartmentId instead
if (((String)sc.getProperty()).equalsIgnoreCase("DepartmentName")){
System.out.println("You wanted to sort " +sc.getProperty());

sortList = new ArrayList();
SortCriterion sc2 = new SortCriterion("DepartmentId",true);
System.out.println("This is what I want you to sort for "+sc2.getProperty());
sortList.add(sc2);

CoreTable ct = (CoreTable)sortEvent.getComponent();
ct.setSortCriteria(sortList);
}
}
}

How to avoid JBO-35007 error?

When row currency validation fails JBO-35007 error is reaised.

Row currency validation safe gaurds ADF application from browser back button issue.

What is browser back button issue?
Form Duncan Mills ""Oracle JDeveloper 10g for Forms and PL/SQL Developers" book :
Users may be accustomed to clicking the browser's Back button to return to the preceding page or the Refresh button to reload the page. This can cause problems with web applications that use a Controller layer, like the JSF controller or Struts, because the browser Back button returns to the preceding page in the browser's page history without calling code in the Controller layer. The controller will therefore, not know the state of the application's data and the preceding page will either not load properly or may place the application into an inconsistent or unstable state. The same problem occurs with the browser's Refresh button, which just reloads the same page, again without calling Controller layer code. This is a problem in all web applications, not only those using J2EE technology or ADF libraries.

How to ignore row currnecy validation?
There are two ways to avoid this validation.(Note: As Row currency validation safe gaurds ADF application from browser back button issue, it is not suggested to ignore row currency validation)

Method I
Set the EnableTokenValidation to false in the page definition file.
1)In the Application Navigator, right-click the JSP page for which you want to disable validation, and choose Go to Pa ge Definition.
2)In the Structure window, right-click the pagenamePageDef node and choose Properties from the context menu.
3)In the PageDef Properties dialog, select the Advanced Properties tab.
4)In the Enable Token Validation box and choose False. The EnableTokenValidation attribute is added to the PageDef.xml file namespace with a value of false.

Method II
Disable row currency validation on an iterator by setting the "StateValidation" property of an iterator to "false" without disabling it for all iterators in the page definition.

How to prevent navigation thorugh browser back button using java script in ADF page

Add the following java script to Onload attribute of afh:body tag in ADF page.

if (history.forward() != null) history.forward()

Preventing execution of queries when page loads for first time (ADF)

Sometimes you want to prevent the automatic execution of a query when page loads for first time.

To achieve this ...

In ADF 10.1.3, add ${adfFacesContext.postback == true} to refresh condition of the iterator that displays the data in your page.

In ADF 11g, add #{!adfFacesContext.initialRender} to refresh condition of the iterator that displays the data in your page.

Saturday, May 30, 2009

JavaScript Date Functilons


//
===================================================================


// Author: Vipin K R


// WWW:
http://www.careeritdevelopers.blogspot.com/


//


// NOTICE: You may use this code for
any purpose, commercial or


// private, without any further
permission from the author. You may


// remove this notice from your final
code if you wish, however it is


// appreciated by the author if at
least my web site address is kept.



//


// You may *NOT* re-distribute this
code in any way except through its


// use. That means, you can include it
in your product, or your web


// site, or any other form where the
code is actually being used. You


// may not put the plain javascript up
on your site for download or


// include it in your javascript
libraries for download.


// If you wish to share this code with
others, please just point them


// to the URL instead.


// Please DO NOT link directly to my
.js files from your site. Copy



// the files to your server and use
them there. Thank you.


//
===================================================================





// HISTORY


//
------------------------------------------------------------------


// May 17, 2003: Fixed bug in
parseDate() for dates <1970


// March 11, 2003: Added parseDate()
function


// March 11, 2003: Added "NNN"

formatting option. Doesn't match up


// perfectly with
SimpleDateFormat formats, but


//
backwards-compatability was required.





//
------------------------------------------------------------------


// These functions use the same
'format' strings as the


// java.text.SimpleDateFormat class,
with minor exceptions.


// The format string consists of the
following abbreviations:


//



// Field | Full Form |
Short Form


//
-------------+--------------------+-----------------------


// Year | yyyy (4 digits) |
yy (2 digits), y (2 or 4 digits)


// Month | MMM (name or abbr.)|
MM (2 digits), M (1 or 2 digits)


// | NNN (abbr.) |


// Day of Month | dd (2 digits) |
d (1 or 2 digits)


// Day of Week | EE (name) |
E (abbr)


// Hour (1-12) | hh (2 digits) |
h (1 or 2 digits)


// Hour (0-23) | HH (2 digits) |
H (1 or 2 digits)



// Hour (0-11) | KK (2 digits) |
K (1 or 2 digits)


// Hour (1-24) | kk (2 digits) |
k (1 or 2 digits)


// Minute | mm (2 digits) |
m (1 or 2 digits)


// Second | ss (2 digits) |
s (1 or 2 digits)


// AM/PM | a |


//


// NOTE THE DIFFERENCE BETWEEN MM and
mm! Month=MM, not mm!


// Examples:


// "MMM d, y" matches:
January 01, 2000



// Dec 1, 1900


// Nov 20, 00


// "M/d/yy" matches:
01/20/00


// 9/2/00


// "MMM dd, yyyy hh:mm:ssa"
matches: "January 01, 2000 12:30:45AM"



//
------------------------------------------------------------------





var MONTH_NAMES=new
Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');


var DAY_NAMES=new
Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');


function LZ(x)
{return(x<0||x>9?"":"0")+x}






//
------------------------------------------------------------------


// isDate ( date_string, format_string
)


// Returns true if date string matches
format of format string and


// is a valid date. Else returns false.


// It is recommended that you trim
whitespace around the value before


// passing it to this function, as
whitespace is NOT ignored!


//
------------------------------------------------------------------


function isDate(val,format) {


var
date=getDateFromFormat(val,format);



if (date==0) { return false; }


return true;


}





//
-------------------------------------------------------------------


//
compareDates(date1,date1format,date2,date2format)


// Compare two date strings to see
which is greater.



// Returns:


// 1 if date1 is greater than date2


// 0 if date2 is greater than date1
of if they are the same


// -1 if either of the dates is in an
invalid format


//
-------------------------------------------------------------------


function
compareDates(date1,dateformat1,date2,dateformat2) {


var
d1=getDateFromFormat(date1,dateformat1);


var
d2=getDateFromFormat(date2,dateformat2);



if (d1==0 || d2==0) {


return -1;


}


else if (d1 > d2) {


return 1;



}


return 0;


}





//
------------------------------------------------------------------


// formatDate (date_object, format)


// Returns a date in the output format
specified.



// The format string uses the same
abbreviations as in getDateFromFormat()


//
------------------------------------------------------------------


function formatDate(date,format) {


format=format+"";


var result="";


var i_format=0;



var c="";


var token="";


var y=date.getYear()+"";


var M=date.getMonth()+1;


var d=date.getDate();



var E=date.getDay();


var H=date.getHours();


var m=date.getMinutes();


var s=date.getSeconds();


var
yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;


// Convert real date parts into
formatted versions



var value=new Object();


if (y.length < 4)
{y=""+(y-0+1900);}


value["y"]=""+y;


value["yyyy"]=y;



value["yy"]=y.substring(2,4);


value["M"]=M;


value["MM"]=LZ(M);


value["MMM"]=MONTH_NAMES[M-1];



value["NNN"]=MONTH_NAMES[M+11];


value["d"]=d;


value["dd"]=LZ(d);


value["E"]=DAY_NAMES[E+7];



value["EE"]=DAY_NAMES[E];


value["H"]=H;


value["HH"]=LZ(H);


if (H==0){value["h"]=12;}



else if (H>12){value["h"]=H-12;}


else {value["h"]=H;}


value["hh"]=LZ(value["h"]);



if (H>11){value["K"]=H-12;}
else {value["K"]=H;}


value["k"]=H+1;


value["KK"]=LZ(value["K"]);



value["kk"]=LZ(value["k"]);


if (H > 11) { value["a"]="PM";
}


else { value["a"]="AM";
}



value["m"]=m;


value["mm"]=LZ(m);


value["s"]=s;


value["ss"]=LZ(s);



while (i_format < format.length)
{


c=format.charAt(i_format);


token="";


while
((format.charAt(i_format)==c) &amp;&amp; (i_format <

format.length)) {


token +=
format.charAt(i_format++);


}


if (value[token] != null) {
result=result + value[token]; }


else { result=result + token; }


}



return result;


}




//
------------------------------------------------------------------


// Utility functions for parsing in
getDateFromFormat()


//
------------------------------------------------------------------


function _isInteger(val) {


var digits="1234567890";



for (var i=0; i < val.length;
i++) {


if
(digits.indexOf(val.charAt(i))==-1) { return false; }


}


return true;


}



function
_getInt(str,i,minlength,maxlength) {


for (var x=maxlength; x>=minlength;
x--) {


var token=str.substring(i,i+x);


if (token.length <
minlength) { return null; }


if (_isInteger(token)) { return
token; }



}


return null;


}




//
------------------------------------------------------------------


// getDateFromFormat( date_string ,
format_string )


//



// This function takes a date string
and a format string. It matches


// If the date string matches the
format string, it returns the


// getTime() of the date. If it does
not match, it returns 0.


//
------------------------------------------------------------------


function getDateFromFormat(val,format)
{


val=val+"";


format=format+"";



var i_val=0;


var i_format=0;


var c="";


var token="";


var token2="";



var x,y;


var now=new Date();


var year=now.getYear();


var month=now.getMonth()+1;


var date=1;


var hh=now.getHours();



var mm=now.getMinutes();


var ss=now.getSeconds();


var ampm="";




while (i_format < format.length)
{



// Get next token from format
string


c=format.charAt(i_format);


token="";


while
((format.charAt(i_format)==c) &amp;&amp; (i_format <
format.length)) {



token +=
format.charAt(i_format++);


}


// Extract contents of value
based on format token


if (token=="yyyy" ||
token=="yy" || token=="y") {



if (token=="yyyy")
{ x=4;y=4; }


if (token=="yy")
{ x=2;y=2; }


if (token=="y")
{ x=2;y=4; }



year=_getInt(val,i_val,x,y);



if (year==null) { return 0;
}


i_val += year.length;


if (year.length==2) {


if (year > 70) {
year=1900+(year-0); }


else {
year=2000+(year-0); }



}


}


else if
(token=="MMM"||token=="NNN"){


month=0;


for (var i=0;
i<MONTH_NAMES.length; i++) {



var
month_name=MONTH_NAMES[i];


if
(val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase())
{


if
(token=="MMM"||(token=="NNN"&amp;&amp;i>11))
{


month=i+1;



if (month>12)
{ month -= 12; }


i_val +=
month_name.length;


break;


}


}


}



if ((month <>12)){return
0;}


}


else if
(token=="EE"||token=="E"){


for (var i=0;
i<DAY_NAMES.length; i++) {



var
day_name=DAY_NAMES[i];


if
(val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase())
{


i_val +=
day_name.length;


break;


}


}



}


else if
(token=="MM"||token=="M") {



month=_getInt(val,i_val,token.length,2);



if(month==null||(month<1)||(month>12)){return 0;}



i_val+=month.length;}


else if
(token=="dd"||token=="d") {



date=_getInt(val,i_val,token.length,2);



if(date==null||(date<1)||(date>31)){return 0;}



i_val+=date.length;}


else if
(token=="hh"||token=="h") {



hh=_getInt(val,i_val,token.length,2);



if(hh==null||(hh<1)||(hh>12)){return 0;}



i_val+=hh.length;}


else if
(token=="HH"||token=="H") {



hh=_getInt(val,i_val,token.length,2);



if(hh==null||(hh<0)||(hh>23)){return 0;}



i_val+=hh.length;}


else if
(token=="KK"||token=="K") {



hh=_getInt(val,i_val,token.length,2);



if(hh==null||(hh<0)||(hh>11)){return 0;}



i_val+=hh.length;}


else if
(token=="kk"||token=="k") {



hh=_getInt(val,i_val,token.length,2);



if(hh==null||(hh<1)||(hh>24)){return 0;}



i_val+=hh.length;hh--;}


else if
(token=="mm"||token=="m") {



mm=_getInt(val,i_val,token.length,2);



if(mm==null||(mm<0)||(mm>59)){return 0;}



i_val+=mm.length;}


else if
(token=="ss"||token=="s") {



ss=_getInt(val,i_val,token.length,2);



if(ss==null||(ss<0)||(ss>59)){return 0;}



i_val+=ss.length;}


else if (token=="a")
{


if
(val.substring(i_val,i_val+2).toLowerCase()=="am")
{ampm="AM";}


else if
(val.substring(i_val,i_val+2).toLowerCase()=="pm")
{ampm="PM";}



else {return 0;}


i_val+=2;}


else {


if
(val.substring(i_val,i_val+token.length)!=token) {return 0;}


else {i_val+=token.length;}


}



}


// If there are any trailing
characters left in the value, it doesn't match


if (i_val != val.length) { return
0; }


// Is date valid for month?


if (month==2) {


// Check for leap year



if ( (
(year%4==0)&amp;&amp;(year%100 != 0) ) || (year%400==0) ) {
// leap year


if (date > 29){ return
0; }


}


else { if (date > 28) {
return 0; } }



}


if
((month==4)||(month==6)||(month==9)||(month==11)) {


if (date > 30) { return 0; }


}


// Correct hours value



if (hh<12 &amp;&amp;
ampm=="PM") { hh=hh-0+12; }


else if (hh>11 &amp;&amp;
ampm=="AM") { hh-=12; }


var newdate=new
Date(year,month-1,date,hh,mm,ss);



return newdate.getTime();


}





//
------------------------------------------------------------------


// parseDate( date_string [,
prefer_euro_format] )


//


// This function takes a date string
and tries to match it to a


// number of possible date formats to
get the value. It will try to



// match against the following
international formats, in this order:


// y-M-d MMM d, y MMM d,y y-MMM-d
d-MMM-y MMM d


// M/d/y M-d-y M.d.y MMM-d
M/d M-d


// d/M/y d-M-y d.M.y d-MMM
d/M d-M


// A second argument may be passed to
instruct the method to search


// for formats like d/M/y (european
format) before M/d/y (American).


// Returns a Date object or null if no
patterns match.


//
------------------------------------------------------------------


function parseDate(val) {



var
preferEuro=(arguments.length==2)?arguments[1]:false;


generalFormats=new
Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');


monthFirst=new
Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d');


dateFirst =new
Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M');


var checkList=new
Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');


var d=null;



for (var i=0; i<checkList.length;
i++) {


var l=window[checkList[i]];


for (var j=0; j<l.length;
j++) {



d=getDateFromFormat(val,l[j]);


if (d!=0) { return new
Date(d); }



}


}


return null;


}

Friday, May 22, 2009

Understanding Application Module Pooling Concepts and Configuration Parameters

Abstract

Oracle ADF provides a sophisticated and high-performance solution for managing pools of lightweight application module components. This article describes the pooling behavior and the different configuration parameters that allow you to control how the pools behaves at runtime.
NOTE:
This article is valid for ADF Business Components in JDeveloper 10g and beyond, as well as for Business Components for Java (BC4J) in JDeveloper 9.0.4 and earlier.
Overview

At its most simple, an application module pool is a collection of instances of a single application module type which are shared by multiple application clients. For example, the ADF Toy Store application has an application module named toystore.model.services.ToyStoreService. An application module pool supporting the Toy Store demo would have one or more instances of this application module component in it, based on the number of users that are visiting the site.

This pool of AM instances is shared by multiple browser clients whose typical "think time" between submitting web pages allows optimizing the number of AM components to be effectively smaller than the total number of "active" users working on the system. That is, twenty users shopping the web site from their browser might be able to be serviced by 5 or 10 application module instances instead of having as many AM instances as you have browser users.
Application module components can be used to support web application scenarios that are completely stateless, or they can be used to support a unit of work which spans multiple browser pages. Just imagine a scenario where an application user needs to accomplish the task of:

* Defining the details for a new warehouse
* Adding contact information for multiple contacts for this new warehouse
* Adding a number of initial inventory items to this new warehouse
Each of these steps might be accomplished using the popular "Step-by-Step" or "Wizard-Style" user interface that leads the user through a logical sequence of pages to complete the task, and allows them to iterate through the steps as many times as necessary to finish the application task. When the task is done, the user can commit everything or cancel the entire unit of work. Since this is a web application using the stateless HTTP protocol, implementing a sophisticated web application that builds up pending state over many web pages requires some state management strategy and software infrastructure to implement it. ADF application modules provides the ability to snapshot and reactivate their pending state to XML (stored on the file system or in the database), and the ADF application module pooling mechanism leverages this capability to deliver a "managed state" option to web application developers that simplifies building applications like the example just given.

As a performance optimization, when an instance of an AM is returned to the pool in "managed state" mode, the pool keeps track that the AM is referenced by that particular session. The AM instance is still in the pool and available for use, but it would prefer to be used by the same session that was using it last time because maintaining this so-called "session affinity" improves performance.

So, at any one moment in time, the instances of application modules in the pool are logically partitioned into three groups, reflecting their state:

1. Unconditionally available for use
2. Available for use, but referenced for session affinity reuse by an active user session XYZ
3. Unavailable, inasmuch as it's currently in use (at that very moment!) by some thread in the web container.

The next section describes the application module pool configuration parameters and how they affect the behavior of the pool.

Setting Pool Configuration Parameters

You control the runtime behavior of an application module pool by setting appropriate configuration parameters. The simplest way to assign values to these parameters is to use the application Configuration Manager. This dialog appears when you select an application module in the JDeveloper Application Navigator, and choose Configurations... from the right-mouse menu. While editing a configuration using this dialog.
TIP:

We'll explain in the Database Connection Pool Parameters section below why it is best practice to leave the Connection Pool parameters in this dialog at their defaults and to set your desired values for them globally using Java System Parameters.

Pooling and Scalability Tab of the Configuration Manager
Pooling and Scalability Tab of the Configuration Manager

The values that you supply through the Configuration Manager are saved in an XML file named bc4j.xcfg. All of the configurations for all of the application modules in a single Java package are saved in the same file. For example, if you have a EmployeeReviewModule and a BonusAssignment application module which both live in the com.yourcompany.hr package, then the configuration information for both of these modules will be saved in the bc4j.xcfg file in the ./com/yourcompany/hr/common directory in your project's source path. When your project is compiled, this bc4j.xcfg file gets copied to the same directory in your project's out path, so that the ADF framework can find it at runtime.

If you look inside the file, you'll notice that each named configuration is saved in an XML section in the file like this:

test.model.TestModule
LOCAL
scott
test.model.TestModule
Model


Note that child elements of the tag appear with tag names matching their property values. It's also important to understand that if a property is currently set to its runtime default value, then the Configuration Manager does not write the entry to the bc4j.xcfg file.

As an alternative to specifying configuration properties in the bc4j.xcfg file, you can also set Java VM system parameters with the same property names. These system parameters will be used only if a corresponding property does not exist in the relevant bc4j.xcfg file for the application module in question. In other words, configuration parameters that appear in the application module configuration take precedence over parameters of the same name supplied as Java system parameters.

You typically set Java system parameters using the -D command line flag to the Java VM like this:

java -Dproperty=value -jar yourserver.jar

Alternatively, your J2EE container probably has a section in its own configuration files where Java system parameters can be specified for use at J2EE container startup time.

TIP:

Many customers adopt the best practice technique of supplying site-specific default values for ADF configuration parameters as Java system parameters and then make sure that their bc4j.xcfg files do not include references to these parameters unless an application-module-specific exception to these global default values is required.

Using OC4J you can specify these parameters either as -D Java system parameters on the command line that starts OC4J, or provide them — one per line — in the oc4j.properties file and add the -properties oc4j.properties command line flag to OC4J at startup.


CAVEAT:

The values of Idle Instance Timeout, Pool Polling Interval settings for both the Application Pool and the database Connection Pool are displayed and edited in this dialog as a number of seconds, but are saved to the configuration file in milliseconds. If you provide a value for any of these four parameters as a Java System parameter — or if you hand-edit the bc4j.xcfg file — make sure to provide these time interval values in milliseconds!

AM State Snapshots and the Internal Connection

In order to manage application module pending work, the application module pool asks AM instances to "snapshot" their state to XML at different times. What is saved to the snapshot is not a copy of all data that's been queried by the view objects in the application module, but rather a kind of "redo log" of entity cache information about what pending entity object instances have been created, deleted, and modified, along with some view rowset iterator bookkeeping information for view objects with active rowsets.

If the value of the jbo.dofailover configuration parameter is true, then this XML snapshotting will happen each time the AM instance is released to the pool. You control this in the Configuration Manager by the checkbox labeled Failover Transaction State Upon Managed Release on the Pooling and Scalability tab. The default is to have this checkbox checked, meaning the parameter has a value of true. If the value is false, then an XML snapshot of pending work will only be taken on demand when an AM instance that was referenced by session "A" had to be handed out to another session "B" before session "A", that used it last and released it in managed state mode, came back to use it again. Those XML state snapshots are used by the pool to reinstate the pending work that your session had done up to the last time the AM instance was released to the pool in the case that your session cannot end up exploiting the session affinity optimization.

The setting of the jbo.passivationstore parameter controls whether the XML snapshots are written to files on disk (when the value is file) or to a BLOB column in a row in the PS_TXN table in the database (when the value is database). The default setting for this property is the string-value "null", which causes a database-based passivation scheme to be used against Oracle or DB2, and a file-based passivation scheme to be used otherwise.

While the file-based option is a little faster, unless your multiple application server instances share a file system, then the the database-backed passivation scheme is the most robust for application server-farm and failover scenarios.

If you use database passivation, then the framework will use a JDBC connection from a database connection pool for "internal connection" instances. The internal connection credentials are controlled by the value of the jbo.server.internal_connection configuration parameter. Its value can be a fully-qualified JDBC connection URL (e.g. jdbc:oracle:thin:statemgmtuser/password@penguin:1521:ORCL) or a JNDI name for a JDBC DataSource (e.g. java:comp/env/jdbc/AnotherConnectionDS). It is typically a different database account than your application data. Nothing prevents you from setting the internal connection to be using a database on a different machine as well, if desired.

How Many Pools are Created, and When?

There are two kinds of pools in use when running a typical ADF web application, Application Module pools and database connection pools. It's important to understand how many of each kind of pool your application will create, so let's explore both kinds in turn.

Application Module Pools

Application Module components can be used at runtime in two ways:

1. As a application module the client accesses directly, or
2. As a reusable component aggregated (or "nested") inside of another application module instance.

When a client accesses it directly, an application module is called a root application module. Clients access nested application modules indirectly as a part of their containing application module instance. It's possible, but not common, to use the same application module at runtime in both ways. The important point is that ADF only creates an application module pool for a root application module. Nested application modules are "along for the ride", so to speak, with the eventual root application module instance that contains them.

The basic rule is:

One application module pool is created for each root application module used by an ADF web application in each Java VM where a root application module of that type is used by the ADF controller layer.


NOTE:

While you can make direct use of the PoolMgr and ApplicationPool API's directly in your own web-tier infrastructure code, most customers use the default support provided by the ADF controller layer which handles interacting with the pool for them as described in the Lifecycle of a Web Page Request Using Struts and ADF section of the ADF Toy Store Demo whitepaper.

Database Connection Pools

ADF web applications always use a database connection pool, but which one they use for your application modules depends on whether your they define their connection using a:

* JDBC URL (e.g. jdbc:oracle:thin:@penguin:1521:ORCL), or a
* JNDI Name for a Datasource (e.g. java:comp/env/jdbc/YourConnectionDS)

If you supply a JDBC URL connection while configuring your application module — which happens when you select a JDeveloper named connection which encapsulates the JDBC URL and username information — then the ADF database connection pool will be used for managing the connection pool.

If instead you supply the JNDI name of a JDBC Datasource then the ADF database connection pool will not be used and the configuration parameters described below relating to the ADF database connection pool are not relevant.

NOTE:

To configure the database connection pool for JDBC Datasources looked-up by JNDI from your J2EE Web and/or EJB container, consult the documentation for your J2EE container to understand the pooling configuration options and how to set them.

Using ADF database connection pooling, we have the following basic rule:

One database connection pool is created for each unique pair, in each Java VM where a connection is requested by a root application used by the ADF controller layer.

Applying These Rules of Thumb to a Scenario

To better understand these rules of thumb, let's apply them to a simple scenario. We'll make the following assumptions:

* Your web application makes use of two application modules HRModule and PayablesModule.
* You have a CommonLOVModule containing a set of commonly used view objects to support list-of-values in your application, and that both HRModule and PayablesModule aggregate a nested instance of CommonLOVModule to access the common LOV view object's it contains.
* You have configured both HRModule and PayablesModule to use the same JDeveloper connection definition named appuser
* In both HRModule and PayablesModule you have configured jbo.passivationstore=database (the default) and configured the ADF "internal connection" (jbo.server.internal_connection) used for state management persistence to have the value of a fully-qualified JDBC URL that points to a different username than the appuser connection does.

Let's look at how many pools of which kinds are created for this application in both a single JVM and multiple JVM runtime scenario.

Single OracleAS Instance, Single OC4J Container, Single JVM

If we deploy this application to a single Oracle Application Server instance, configured with a single OC4J container having a single Java VM, there understandably only a single Java VM available to service the web requests coming from our application users.

Assuming that all the users are making use of web pages that access both the HRModule and the PayablesModule, this will give us:

* One AM pool for the HRModule root application module
* One AM pool for the PayablesModule root application module
* One DB connection pool for the appuser connection
* One DB connection pool for the JDBC URL supplied for the internal connection for state management.

This gives us a total of 2 AM pools and 2 database pools in this single Java VM.

NOTE:

There is no separate AM pool for the nested instances of the reusable CommonLOVModule. It goes along for the ride with instances of HRModule and PayablesModule in their respective AM pools.

Multiple OracleAS Instances, Single OC4J Container, Multiple JVMs

Let's consider next a deployment environment involving multiple Java VM's. Assume that we have installed Oracle Application Server 10g (version 9.0.4) onto two different physical machines, with a hardware load-balancer in front of it. On each of these two machines, imagine that the OracleAS instance is configured to have one OC4J container with two JVMs. As users of our application access the application, their requests end up getting "fanned out" across these two OracleAS instances, and within each OracleAS instance, across the two JVMs that its OC4J container has available.

Again assuming that all the users are making use of web pages that access both the HRModule and the PayablesModule, this will give us:

*

(1 HRModule Root AM) x (2 OracleAS Instances) x (2 OC4J JVMs each) =

Four AM pools for HRModule, one in each of 4 JVMs.
*

(1 PayablesModule Root AM) x (2 OracleAS Instances) x (2 OC4J JVMs each) =

Four AM pools for PayablesModule, one in each of 4 JVMs.
*

(1 appuser DB connection pool) x (2 OracleAS Instances) x (2 OC4J JVMs each) =

Four DB connection pools for appuser, one in each of 4 JVMs.
*

(1 internal connection JDBC URL DB connection pool) x (2 OracleAS Instances) x (2 OC4J JVMs each) =

Four DB connection pools for the internal connection JDBC URL, one in each of 4 JVMs.

This gives us a total of 8 AM pools and 8 DB connection pools spread across 4 JVMs.

As we begin to explore the configuration parameters for the AM pools in the next section, keep in mind that they apply to a given AM pool for a given application module in a single JVM. As the load balancing spreads user request across the multiple JVMs where ADF is running, each individual AM pool in each JVM will have to support one Nth of the user load — where N is number of JVMs available to service those user requests. The appropriate values of the AM and DB connection pools need to be set with the number of Java VM's in mind.

Application Module Pool Parameters

The application module pool configuration parameters fall into two logical categories relating to pool sizing and pool cleanup behavior.

Pool Sizing Parameters

Table 1 lists the application module configuration parameters that affect the sizing of the application module pool.
Table 1: Application Module Pool Sizing Configuration Parameters
Pool Parameter Configuration Parameter Name Description
Initial Pool Size jbo.ampool.initpoolsize

The number of AM instances to created when the pool is initialized.

The default is 0 (zero) instances.
Maximum Pool Size jbo.ampool.maxpoolsize

The maximum number of AM instances that the pool can allocate.

The pool will never create more AM instances than this limit imposes. The default is 5000 instances.
Referenced Pool Size jbo.recyclethreshold

The maximum number of AM instances in the pool that attempt to preserve session affinity for the next request made by the session which used them last before releasing them to the pool in managed-state mode.

The referenced pool size should always be less than or equal to the maximum pool size. The default is to allow 10 available instances to try and remain "loyal" to the affinity they have with the most recent session that released them in managed state mode.

Pool Cleanup Parameters

A single "application module pool monitor" per Java VM runs in a background thread and wakes up every so often to do resource reclamation. Table 2 lists the parameters that affect how resources are reclaimed when the pool monitor does one of its resource cleanup passes.

TIP:

Since there is only a single application monitor pool monitor per Java VM, the value that will effectively be used for the AM pool monitor polling interval will be the value found in the AM configuration read by the first AM pool that gets created. To make sure this value is set in a predictable way, it is best practice for all application modules to use the same Pool Polling Interval value.

Table 2: Application Module Resource Management Configuration Parameters
Pool Parameter Configuration Parameter Name Description
Pool Polling Interval jbo.ampool.monitorsleepinterval

The length of time in milliseconds between pool resource cleanup.

While the number of AM instances in the pool will never exceed the maximum pool size, available instances which are candidates for getting removed from the pool do not get "cleaned up" until the next time the AM pool monitor wakes up to do its job. The default is to have the AM pool monitor wake up every 600000 milliseconds (which is 600 seconds, or ten minutes).

Note: Value in the configuration UI is in shown/edited in seconds, but saved in milliseconds.
Maximum Available Size jbo.ampool.maxavailablesize

The ideal maximum number of AM instances in the pool when not under abnormal load.

When the pool monitor wakes up to do resource cleanup, it will try to remove available AM instances to bring the total number of available instances down to this ideal maximum. Instances that have been not been used for a period longer than the idle instance timeout will always get cleaned up at this time, then additional available instances will be removed if necessary to bring the number of available instances down to this size. The default maximum available size is 25 instances.
Minimum Available Size jbo.ampool.minavailablesize

The minimum number of available AM instances that the pool monitor should leave in the pool during a resource cleanup operation. Set to zero (0) if you want the pool to shrink to contain no instances when all instances have been idle for longer than the idle timeout.

The default is 5 instances.
Idle Instance Timeout jbo.ampool.maxinactiveage

The number of milliseconds after which to consider an inactive AM instance in the pool as a candidate for removal during the next resource cleanup.

The default is 600000 milliseconds of idle time (which is 600 seconds, or ten minutes).

Note: Value in the configuration UI is in shown/edited in seconds, but saved in milliseconds.
Maximum Instance Time to Live jbo.ampool.timetolive

The number of milliseconds after which to consider an AM instance in the pool as a candidate for removal during the next resource cleanup regardless of whether it would bring the number of instances in the pool below minavailablesize.

The default is 3600000 milliseconds of total time to live (which is 3600 seconds, or one hour)

Note: This property only appears in the Properties panel, not on the Pooling and Scalability Tab Database Connection Pool Parameters

If you are using a JDBC URL for your connection information so that the ADF database connection pool is used, then configuration parameters listed in Table 3 can be used to tune the behavior of the database connection pool. A single "database connection pool monitor" per Java VM runs in a background thread and wakes up every so often to do resource reclamation. The parameters in Table 2 include the ones that affect how resources are reclaimed when the pool monitor does one of its resource cleanup passes.
TIP:

Since the tuning parameters for all ADF database connection pools — regardless of value — will be set based on the parameters found in the configuration for the first AM pool that is created. To insure the most predictable behavior, it is best practice to leave the values of the parameters in the Connnection Pooling section of the Pooling and Scalability tab at their default values — so that no entry for them is written into the bc4j.xcfg file — and to instead set the desired values for the database connection pooling tuning parameters as Java System Parameters in your J2EE container.
In fact, to a Bug# 3678499 in JDeveloper 10g (version 9.0.5.x) database connection pool tuning parameters that appear in your application module configuration files (bc4j.xcfg) are inadvertently ignored and default settings are used, including the default setting of jbo.poolminavailablesize controlling the minimum number of instances to always remain in the pool. So in the 9.0.5.x release, the only way to set non-default database pooling parameters is to set them using Java System parameters.
Table 3: Database Connection Pool Parameters
Pool Parameter Configuration Parameter Name Description
Initial Pool Size jbo.initpoolsize

The number of JDBC connection instances to created when the pool is initialized

The default is an initial size of 0 instances.
Maximum Pool Size jbo.maxpoolsize

The maximum number of JDBC connection instances that the pool can allocate.

The pool will never create more JDBC connections than this imposes. The default is 5000 instances.

Note: Value in the configuration UI is in shown/edited in seconds, but saved in milliseconds.
Pool Polling Interval jbo.poolmonitorsleepinterval

The length of time in milliseconds between pool resource cleanup.

While the number of JDBC connection instances in the pool will never exceed the maximum pool size, available instances which are candidates for getting removed from the pool do not get "cleaned up" until the next time the JDBC connection pool monitor wakes up to do its job. The default is 600000 milliseconds of idle time (which is 600 seconds, or ten minutes).

Note: Value in the configuration UI is in shown/edited in seconds, but saved in milliseconds.
Maximum Available Size jbo.poolmaxavailablesize

The ideal maximum number of JDBC connection instances in the pool when not under abnormal load.

When the pool monitor wakes up to do resource cleanup, it will try to remove available JDBC connection instances to bring the total number of available instances down to this ideal maximum. Instances that have been not been used for a period longer than the idle instance timeout will always get cleaned up at this time, then additional available instances will be removed if necessary to bring the number of available instances down to this size. The default is an ideal maximum of 25 instances (when not under load).
Minimum Available Size jbo.poolminavailablesize

The minimum number of available JDBC connection instances that the pool monitor should leave in the pool during a resource cleanup operation. Set to zero (0) if you want the pool to shrink to contain no instances when all instances have been idle for longer than the idle timeout.

The default is to not let the minimum available size drop below 5 instances.
Idle Instance Timeout jbo.poolmaxinactiveage

The number of seconds after which to consider an inactive JDBC connection instance in the pool as a candidate for removal during the next resource cleanup.

The default is 600000 milliseconds of idle time (which is 600 seconds, or ten minutes).

Note: Value in the configuration UI is in shown/edited in seconds, but saved in milliseconds.
Maximum Instance Time to Live jbo.pooltimetolive

The number of milliseconds after which to consider an connection instance in the pool as a candidate for removal during the next resource cleanup regardless of whether it would bring the number of instances in the pool below minavailablesize.

The default is 3600000 milliseconds of total time to live (which is 3600 seconds, or one hour)
Note: This property only appears in the Properties panel, not on the Pooling and Scalability Tab

Notice that since the BC4J database connection pool does not implement the heuristic of session affinity, there is no configuration parameter for the database connection pool which controls the referenced pool size.

You should take care not to configure the jbo.ampool.monitorsleepinterval (for the AM pools) or the jbo.poolmonitorsleepinterval (for the DB pools) to be too short of a time period because the chance exists — with a large number of AM pools to cleanup — that your next pool monitor "wakeup" might occur while your previous cleanup-cycle is still going on. The default of 10 minutes (600000 milliseconds) is reasonable. Setting it to something like 10 seconds (10000 milliseconds) might cause trouble. Forewarned is forearmed.

Understanding How Database and Application Module Pools Cooperate

How ADF application module pools use the database connection pool depends on the setting of the jbo.doconnectionpooling AM configuration parameter. you set this parameter using the checkbox labelled Disconnect Application Module Upon Release.
NOTE:

The notion of disconnecting the application module upon release to the pool better captures what the actual feature is doing than the related configuration parameter name (jbo.doconnectionpooling) does. As we'll see the setting of jbo.doconnectionpooling=false does not mean that there is no database connection pooling happening. What it means is that the AM is not disconnected from its JDBC connection upon checkin back to the AM pool.

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.
The key difference is seen when many AM pools are all using the same underlying database user for their application connection.

* If 50 different AM pools each have even just a single AM instance in them, with jbo.doconnectionpooling=false there will be 50 JDBC application connections in use. If the AM pooling parameters are set such that the AM pools are allowed to shrink to 0 instances after an appropriate instance idle timeout by setting jbo.ampool.minavailablesize=0, then when the AM is removed from its pool, it will put back the connection its holding onto.
* In contrast, if 50 different AM pools each have a single AM instance and jbo.doconnectionpooling=true, then the amount of JDBC connections in use will depend on how many of those AM's are simultaneously being used by different clients. If an AM instance is in the pool and is not currently being used by a user session, then with jbo.doconnectionpooling=true it will have released its JDBC connection back to the connection pool and while the AM instance is sitting there waiting for either another user to need it again, or to eventually be cleaned up by the AM pool monitor, it will not be "hanging on" to a JDBC connection.

For highest performance, we recommend not disconnecting the application module instance from its database connection on each check in to the AM pool. Accordingly, the default setting of the jbo.doconnectionpooling configuration parameter is false. The pooling of application module instances is already an effective way to optimize resource usage, and there are runtime efficiencies that the ADF framework can gain if we do not have to disconnect AM instances from their associated JDBC connection after each release to the pool. Effectively, by pooling the application modules which are related one-to-one with a JDBC connection, you are already achieving a pooling of database connections that is optimal for most web applications.

In contrast to our default recommendation, one situation in which it might be opportune to use database connection pooling is when you have a large number of application module pools all needing to use database connections from the same underlying application user at the database level. In this case, the many application module pools can perhaps economize on the total overall database sessions by sharing a single, underlying database connection pool of JDBC connections, albeit at a loss of efficiency of each one. This choice would be favored only if total overall database sessions is of maximum priority.
CAVEAT:
Disconnecting the AM from it's JDBC connection at each AM checkin is fundamentally incompatible with the use of the ADF Business Components feature to call postChanges() — without committing — on the current transaction. Having this feature work correctly relies on allowing the AM to retain its database connection so that interim posted database changes — which have yet to be committed — are maintained by the database. The use of postChanges() is often a sign that you are not aware that the ADF pending state management mechanism will automatically keep track of pending new, modified, and deleted rows for you across web page requests without needing to post them to the database until the final transaction commit.