Archive for the ‘ADF Faces’ Category

ADF Faces: Passing a Java Collection from a Custom ViewObjectImpl Class to a PL/SQL Function

Sunday, August 23rd, 2009

(Originally posted on the “old” Jason Bennett’s Developer Corner, Sunday, August 17, 2008)

I recently had the challenge of creating several complex query search screens using ADF Faces.  These new search screens had to integrate seamlessly into our current application’s (not a J2EE application …) search screens (look the same, act the same, feel the same …).  One of the challenges that presented itself was to determine how to pass multiple search parameters with various operators (=, <, LIKE,SOUNDEX, etc …) and the values associated with them and map them to their associated columns in a dynamic where clause.  Since I was creating multiple screens with similar functionality, I needed a generic method of parameter passing.  The obvious answer was to use some sort of array or combination of arrays as the parameter transport mechanism.  The not so obvious part was how the heck I was going to pass an array of Java Objects to a PL/SQL function that was expecting a PL/SQL Collection object.  Luckily, this turned out to be less complicated than I thought thanks to Oracle and the developers of JDBC.  The Java to PL/SQL user-defined type mapping is accomplished using the java.sql.SQLData interface (http://java.sun.com/j2se/1.5.0/docs/api/java/sql/SQLData.html).  This interface was designed to allow for the mapping between a SQL UDT (user defined type) and a Java class.  The mapping of an array of these objects to an Oracle collection (or array) is accomplished using two Oracle JDBC classes: oracle.sql.ARRAY (http://www.oracle.com/technology/docs/tech/java/sqlj_jdbc/doc_library/javadoc/oracle.sql.ARRAY.html) and oracle.sql.ArrayDescriptor (http://www.oracle.com/technology/docs/tech/java/sqlj_jdbc/doc_library/javadoc/oracle.sql.ArrayDescriptor.html). Next problem … how to create a custom (generic) Programmatic ViewObjectImpl class that will accept a Collection object  as the parameter passing mechanism.  This turned out to be another simple task with the help of some Oracle ADF documentation: (http://download.oracle.com/docs/cd/B31017_01/web.1013/b25947/bcadvvo008.htm).  After that, it’s elementary!  All of the View Objects defined for each of my custom search screens were extended from this new custom ViewObjectImpl class.  The rest of this article details the steps and code I used to implement the solution.  For the sake of brevity, I will limit the code to just the generic ViewObjectImpl and PL/SQL collection mapping.  (The PL/SQL package used to implement the searches has some interesting bits of code, and I will publish that in a separate article.)

Step 1. Create SQL User Defined Types

Step one is to create the SQL user defined types.  In this instance I created two types.  The base type SEARCH_PARAM_TYPE and a collection of SEARCH_PARAM_TYPE called SEARCH_PARAM_ARRAY.  These two user defined types are defined by the following commands:

CREATE OR REPLACE TYPE SEARCH_PARAM_TYPE AS OBJECT(

PARAM_NAME      VARCHAR2(100),

PARAM_OPERATOR  VARCHAR2(4),

PARAM_VALUE     VARCHAR2(1000)

)

/

CREATE OR REPLACE TYPE SEARCH_PARAM_ARRAY AS TABLE OF SEARCH_PARAM_TYPE

/

The SEARCH_PARAM_TYPE contains a parameter name (or label or identifier), a parameter query operator code, and the value for the particular parameter.  The SEARCH_PARAM_ARRAY is just a simple array (PL/SQL Table) that may hold 0 or more SEARCH_PARAM_TYPES.  Each of these SQL types gets mapped in the Java code.

Step 2. Create Java Class to Match SQL Type SEARCH_PARAM_TYPE

Step two is to create a Java class to match the SQL user defined type SEARCH_PARAM_TYPE.  This class must implement java.sql.SQLData and java.io.Serializable.  The code below demonstrates how to implement the class that matches the SQL type SEARCH_PARAM_TYPE:

import java.io.Serializable;
import java.sql.SQLData;
import java.sql.SQLException;
import java.sql.SQLInput;
import java.sql.SQLOutput;

/***
* This class maps to an Oracle User Defined Type called
* SEARCH_PARAM_TYPE. It hold search parameter data
* consisting of a parameter name, operator code,
* and parameter value.
*
*/

public class SearchParamBean implements SQLData, Serializable{

/* Oracle User Defined Type Name */

private String sql_type = ”SEARCH_PARAM_TYPE”;

/* These String represent the attributes in the Oracle user defined type. */

Private String param_name = null;

private String param_operator = null;

private String param_value = null;

public SearchParamBean() {

}

public void setParamName(String p_param_name){
param_name = p_param_name;
}

public String getParamName(){
return param_name;
}

public void setParamOperator(String p_param_operator){
param_operator = p_param_operator;
}

public String getParamOperator(){
return param_operator;
}

public void setParamValue(String p_param_value){
param_value = p_param_value;
}

public String getParamValue(){
return param_value;
}

public String getSQLTypeName()
throws SQLException
{
return sql_type;
}

public void readSQL(SQLInput stream, String typeName)
{
/* No need to implement this */
}

public void writeSQL(SQLOutput stream) throws SQLException
{

/*
the order of values matters! The order must match the structure
of the user defined type exactly!
*/

stream.writeString(param_name);
stream.writeString(param_operator);
stream.writeString(param_value);

}

}

As you can see, this is a pretty straight forward class.  It is important to note that in the writeSQL method above, the order attribute assignements defined with the stream.writeString statements must match the order of attributes as defined in the SQL user defined type exactly (under the covers I’m sure it has to do with marshalling and unmarshalling the serialized objects and not knowing how to intuitively identify what value goes where).

Step 3. Create the Custom ViewObjectImpl Class

The third step is to create the (generic) custom ViewObjectImpl class that your actual ViewObjects will extend.  As stated at the start of this article, I made use of the example in the Oracle ADF documentation that details how to create a View Object using alternate data sources.  The key piece of code is the callStoredFunction method:

/**
* Mechanism to execute PL/SQL functions that populate rows and data
* for the ViewObject
* @param sqlReturnType
* @param stmt
* @param params
* @return
*/

protected Object callStoredFunction(int sqlReturnType,
String stmt,
SearchParamBean[] params) {

CallableStatement plsqlStmt = null;

StringBuffer sb_plsqlBlock = new StringBuffer();

Object dataSet = new Object();

try {

sb_plsqlBlock.append(”begin ? := ”).append(stmt).append(”; end;”);

plsqlStmt = getDBTransaction().createCallableStatement(

sb_plsqlBlock.toString(),0);

/* Register the first bind variable for the return value */

plsqlStmt.registerOutParameter(1, sqlReturnType);

/*This is where we map the Java Object Array to a PL/SQL Array */

ArrayDescriptor desc = ArrayDescriptor.createDescriptor(arrayDescriptor,plsqlStmt.getConnection());

ARRAY objectArray = new ARRAY (desc, plsqlStmt.getConnection(), params);

((OraclePreparedStatement) plsqlStmt).setARRAY(2,objectArray);

plsqlStmt.executeUpdate();

dataSet = plsqlStmt.getObject(1);

}

catch (SQLException e) {

throw new JboException(e);

}

finally {

if (plsqlStmt != null) {

try {

plsqlStmt.close();

}

catch (SQLException e) {System.err.println(e.getMessage());}

}

}

return dataSet;

}

The custom ViewObjectImpl also has methods that construct the ArrayList containing SearchParamBeans.  There are getter and setter methods provided in the class for adding and retrieving SearchParamBean objects. The SearchParamBean[] array you see in the code above is generated internally by the method:

/**
* Constructs the SearchParamBean array from the searchParams ArrayList
* @return
*/

protected SearchParamBean[] getParamBeanArray(){

return (SearchParamBean[])searchParams.toArray(new SearchParamBean[searchParams.size()]);

}

Rather than explain each method in detail, I’ll provide the code with appropriate comments.  It’s fairly straight forward code:

import adf.custom.beans.SearchParamBean;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import oracle.jbo.JboException;
import oracle.jbo.server.ViewObjectImpl;
import oracle.jbo.server.ViewRowImpl;
import oracle.jbo.server.ViewRowSetImpl;
import oracle.jdbc.OracleTypes;
import oracle.jdbc.driver.OraclePreparedStatement;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;

public class ObjectArrayVOImpl extends ViewObjectImpl{

/**
* Number of columns in result set returned by this VO.
*/

private int numberOfVOColumns = 0;

/**
* Name of PL/SQL function that will execute the query
* for the VO implemented by this code.
*/

private String queryFunction = null;

/**
* Name of PL/SQL function that will return the
* number of rows returned by this VO.
*/

private String countFunction = null;

/**
* Name of SQL User Defined Type/ PLSQL Collection Type
*/

private String arrayDescriptor = null;

/**
* ArrayList that holds SearchParamBean objects.
*/

private ArrayList searchParams = new ArrayList();

public ObjectArrayVOImpl() {

}

/**
* This method adds a SearchParamBean object to the ArrayList that
* is mapped to the PL/SQL Collection
* @param p_param_bean
*/

public void addSearchParamBean(SearchParamBean p_param_bean){

searchParams.add(p_param_bean);

}

public void clearSearchParamArray(){

searchParams.clear();

}

/**
* This method is used to set the name of the PL/SQL (packaged) Function that
* will accept the collection of parameters and execute a query returning the
* desired results.
* @param p_value
*/

public void setQueryFunction(String p_value){

queryFunction = p_value;

}

/**
* This method is used to set the name of the PL/SQL (packaged) Function that
* will return the number of rows that will be returned to the View Object from
* the PL/SQL package result set.
* @param p_value
*/

public void setCountFunction(String p_value){

countFunction = p_value;

}

/**
* The array descriptor is is used by the method callStoredFunction
* to map the SearchParamBean[] to the correct PL/SQL Array or SQL
* Type in the backing database.
* @param p_value
*/

public void setArrayDescriptor(String p_value){

arrayDescriptor = p_value;

}

public void setNumberOfVOColumns(int p_value){

numberOfVOColumns = p_value;

}

/**
* Returns the most current ArrayList containing search parameter beans.
* @return ArrayList
*/

public ArrayList getSearchParamArrayList(){

return searchParams;

}

/**
* Constructs the SearchParamBean array from the searchParams ArrayList
* @return
*/

protected SearchParamBean[] getParamBeanArray(){

return (SearchParamBean[])searchParams.toArray(new SearchParamBean[searchParams.size()]);

}

/**
* Overridden framework method.
*
* The role of this method is to ”fetch”, populate, and return a single row
* from the datasource by calling createNewRowForCollection() and populating
* its attributes using populateAttributeForRow().
*/

protected ViewRowImpl createRowFromResultSet(Object qc, ResultSet rs) {

/*
* We ignore the JDBC ResultSet passed by the framework (null anyway) and
* use the resultset that we’ve stored in the query-collection-private
* user data storage
*/

rs = getResultSet(qc);

/*
* Create a new row to populate
*/

ViewRowImpl r = createNewRowForCollection(qc);

try {

/*
* Populate new row by attribute slot number for current row in Result Set
*/

for (int x=0; x

populateAttributeForRow(r,x,rs.getString(x+1));

}

}

catch (SQLException s) {

throw new JboException(s);

}

return r;

}

/**
* Overridden framework method.
*
* Return true if the datasource has at least one more record to fetch.
*/

protected boolean hasNextForCollection(Object qc) {

ResultSet rs = getResultSet(qc);

boolean nextOne = false;

try {

nextOne = rs.next();

/*
* When were at the end of the result set, mark the query collection
* as “FetchComplete”.
*/

if (!nextOne) {

setFetchCompleteForCollection(qc, true);

/*
* Close the result set, we’re done with it
*/

rs.close();

}

}

catch (SQLException s) {

throw new JboException(s);

}

return nextOne;

}

/**
* Overridden framework method.
*
* The framework gives us a chance to clean up any resources related
* to the datasource when a query collection is done being used.
*/

protected void releaseUserDataForCollection(Object qc, Object rs) {
/*
* Ignore the ResultSet passed in since we’ve created our own.
* Fetch the ResultSet from the User-Data context instead
*/

ResultSet userDataRS = getResultSet(qc);

if (userDataRS != null) {

try {

userDataRS.close();

}

catch (SQLException s) {

/* Ignore */

}

}

super.releaseUserDataForCollection(qc, rs);

}

/**
* Mechanism to execute PL/SQL functions that populate rows and data
* for the ViewObject
* @param sqlReturnType
* @param stmt
* @param params
* @return
*/

protected Object callStoredFunction(int sqlReturnType,
String stmt,
SearchParamBean[] params) {

CallableStatement plsqlStmt = null;

StringBuffer sb_plsqlBlock = new StringBuffer();

Object dataSet = new Object();

try {
sb_plsqlBlock.append(”begin ? := ”).append(stmt).append(”; end;”);

plsqlStmt = getDBTransaction().createCallableStatement(
sb_plsqlBlock.toString(),0);

/* Register the first bind variable for the return value */

plsqlStmt.registerOutParameter(1, sqlReturnType);

/*This is where we map the Java Object Array to a PL/SQL Array */

ArrayDescriptor desc = ArrayDescriptor.createDescriptor(arrayDescriptor,plsqlStmt.getConnection());

ARRAY objectArray = new ARRAY (desc, plsqlStmt.getConnection(), params);

((OraclePreparedStatement) plsqlStmt).setARRAY(2,objectArray);

plsqlStmt.executeUpdate();

dataSet = plsqlStmt.getObject(1);

}

catch (SQLException e) {

throw new JboException(e);

}

finally {

if (plsqlStmt != null) {

try {

plsqlStmt.close();

}

catch (SQLException e) {System.err.println(e.getMessage());}

}

}

return dataSet;

}

/**
* Return a JDBC ResultSet representing the REF CURSOR return
* value from our stored package function.
*/

private ResultSet retrieveRefCursor(Object qc, SearchParamBean[] params) {

ResultSet rs = (ResultSet)callStoredFunction(OracleTypes.CURSOR,

queryFunction,

params);

return rs ;

}

/**
* Retrieve the result set wrapper from the query-collection user-data
*/

private ResultSet getResultSet(Object qc) {
return (ResultSet)getUserDataForCollection(qc);
}

/**
* Store a new result set in the query-collection-private user-data context
*/

private void storeNewResultSet(Object qc, ResultSet rs) {

ResultSet existingRs = getResultSet(qc);

/* If this query collection is getting reused, close out any previous rowset */

if (existingRs != null) {

try {existingRs.close();} catch (SQLException s) {}

}

setUserDataForCollection(qc,rs);

hasNextForCollection(qc); // Prime the pump with the first row.

}

/**
* Overridden framework method.
*/

protected void create() {

getViewDef().setQuery(null);
getViewDef().setSelectClause(null);
setQuery(null);

}

/**
* Overridden framework method.
*/

public long getQueryHitCount(ViewRowSetImpl viewRowSet) {

Long count = Long.valueOf(“0″);

if (!searchParams.isEmpty()){

count= (Long)callStoredFunction(OracleTypes.BIGINT,
countFunction,
getParamBeanArray());

}

return count.longValue();
}

/**
* Overridden framework method.
*/

protected void executeQueryForCollection(Object qc,Object[] params,
int numUserParams) {

if (!searchParams.isEmpty()){

storeNewResultSet(qc,retrieveRefCursor(qc,getParamBeanArray()));
super.executeQueryForCollection(qc, params, numUserParams);

}

}

}

Step 4. Create a View Object based on the Custom ViewObjectImpl

The last step is to create a new ViewObject based on the custom ViewObjectImpl that was created in step three.  The easiest way to do this is to use the JDeveloper View Object creation wizard.  Select the ”Rows populated programmatically”  option.  Add any attributes (return columns) you need.   Under the Java section of the View Object definition, and set the VO to extend the new ViewObjectImpl class.   Edit the new View Object class and configure it to use the correct PL/SQL (packaged) functions.  Here is an example:

import adf.custom.model.customViewObjectImpl.ObjectArrayVOImpl;

/* ———————————————————————
— File generated by Oracle ADF Business Components Design Time.
— Custom code may be added to this class.
— Warning: Do not modify method signatures of generated methods.
———————————————————————*/

public class EmployeeQueryVOImpl extends ObjectArrayVOImpl {

/**This is the default constructor (do not remove)
*/

public EmployeeQueryVOImpl() {

/*
Set the name of the PL/SQL function that will act as the
query execution agent. This function will also return
a result set.
*/

this.setQueryFunction(”EmployeeSearch.executeQuery”);

/*
Set the name of the PL/SQL function that will returns the
row count of the query result set for this VO.
*/

this.setCountFunction(”EmployeeSearch.getRowReturnCount”);

/*
This sets the name of the SQL Type representing the PL/SQL collection
or PL/SQL table.
*/

this.setArrayDescriptor(”SEARCH_PARAM_ARRAY”);

/*
The VO needs to know how many columns of data will be returned when
constructing the VO’s result set.
*/

this.setNumberOfVOColumns(5);

}

}

Wrapping it Up …

This article illustrated how to create a custom ViewObjectImpl class that passes an array of Java objects to a PL/SQL Collection based upon a user defined type.  The article touched on a lot of peripheral topics: Creating custom ViewObjectImpl’s, mapping Java objects to SQL user defined types, and converting a Java Object Array into an Oracle Collection/Array.  Basically, it covered a lot of ground in a very brief text.  If you have questions (or suggestions) please feel to shoot me an email.

ADF Faces: How To Use a Single JSP for both INSERTING and UPDATING

Sunday, August 23rd, 2009

(Originally posted on the “old” Jason Bennett’s Developer Corner, Thursday, June 05, 2008)

In this entry, I’ll go over my technique for using a single JSP for both inserting and updating data. This technique utilizes custom methods in the target ViewObjectImpl class, and Page Definition action methods in the Page Definition associated with our ADF/JSF JSP. There are probably other ways to do this, but this one is fairly straight forward. (Note: I believe Steve Muench recommended a similar technique using methods in the ApplicationModuleImpl class)

Preparing the View Object

Most of the View Objects in my applications (that are used for data entry) contain a bind variable in the WHERE clause that is associated with the target table’s primary key (I use dumb keys versus natural keys).   In order to put the page in update mode, we need to pass a PK value to the View Object and pre-populate it prior to rendering the page.  Otherwise, the page is rendered in insert mode.  This is pretty much a universal concept.  How do we go about passing the PK value (or parameter) to the View Object?  First, we need to create a couple of custom public methods in the View Object’s ViewObjectImpl class.   One method will take the PK param value and pre-populate the View Object instance, and the other method will clear the state of (empty the data from) the current instance of the View Object.   The  methods look  like this:

/***
* This method will be used to pre-populate the view object using a passed value.
*/

public void queryViewById(String p_id) {

/*setp_emp_id is ADF generated method for setting the bind variable
value defined in my View Object (p_emp_id). */

setp_emp_id(p_id);
executeQuery();

}

/***
* This method will clear any data out of the existing VO.
*/

public void clearView() {

if (getWhereClause() != null) {

setWhereClause(null);

}

executeQuery();

}

Preparing the Page Definition File

ADF Faces JSPs use an XML based Page Definition file to bind data to the user interface and to perform some actions prior to rendering the page (overly simplified definition …).  Each View Object referenced by an ADF Faces JSP component is represented in that page’s Page Definition file.  ADF Faces comes with some canned page actions (such as Create and Delete) that can be “dropped” into the page definition file and then applied to event (or actions) that occur later in JSP page.  We can also create custom actions (known as method actions) that are mapped to methods we have created.  The two methods we created in the last section (queryViewById and clearView) will be included as custom method actions the Page Definition file for our ADF/JSF JSP page.  The method action entries go in the “bindings” section of the page, and look like this (I have my own View Object referenced in the example):

<methodAction
MethodName=”clearView”
RequiresUpdateModel=”true” Action=”999″
IsViewObjectMethod=”true” DataControl=”AppModuleDataControl”
InstanceName=”AppModuleDataControl.MyemployeeView1″/>

<methodAction
MethodName=”queryViewById” RequiresUpdateModel=”true”
Action=”999″ IsViewObjectMethod=”true”
DataControl=”AppModuleDataControl”
InstanceName=”AppModuleDataControl.MyemployeeView1″>
<NamedData NDName=”p_id” NDValue=”#{param.p_emp_id}”
NDType=”java.lang.String” />
</methodAction>

Notice the “#{param.p_emp_id}” in NDValue attribute above.  Any request parameter passed to the your page can be accessed using “#{param.<parameter name>}”.  The only caveat is if you use the <f:param> tag in conjunction with a command link or command button and the navigation rule behind your navigation action specifies a “redirect” … the parameters will not be passed.  Here is a quick break down of the attributes for the “methodAction” tag above:

  • The “id” attribute represents the identifier of this methodAction tag as it relates to other components (tags) in the current Page Definition file.
  • The “MethodName” attribute defines the binding name for this method action when called from the “invokeAction” tag ( tag that is responsible for executing the code).
  • The “RequiresUpdateModel” attribute specifies whether or not the model needs to be updated prior to executing the method.
  • The “Action” attribute identifies the internal class for which the data control is created.  Always seems to be 999 for custom class.
  • The “IsViewObjectMethod” attribute indicates whether the method being invoked is defined within a View Object.
  • The “InstanceName” attribute points to the View Object instance as defined by the application data control.
  • The “NamedData” tag is used to map any parameters that the method might take. It contains attributes “NDName” (method parameter name), “NDValue” (value being passed), and “NDType” (data type of the parameter).

In order for the page to be rendered in INPUT mode, we have to include a “Create” action in the page definition.  Place the following tag in the “bindings” section (before or after the “methodAction” tags):

<action IterBinding=”MyemployeeView1Iterator”
InstanceName=”AppModuleDataControl.MyemployeeView1″
DataControl=”AppModuleDataControl” RequiresUpdateModel=”true”
Action=”41″/>

(Note:  The instance name references my View Object … you would replace the reference with yours.)

The next step in preparing the Page Definition is to add “invokeAction” tags to the “executables” section.  The “invokeAction” tags define what actions will be executed and under what conditions they will be executed.  The invoke actions for our methods look like:
<invokeAction
Binds=”clearView”
RefreshCondition=”#{adfFacesContext.postback == false and not empty param.p_emp_id}”
Refresh=”prepareModel”/>

<invokeAction
Binds=”queryViewById”
RefreshCondition=”#{adfFacesContext.postback == false and not empty param.p_emp_id}”
Refresh=”prepareModel”/>

<invokeAction Binds=”Create”
Refresh=”renderModel”
RefreshCondition=”${adfFacesContext.postback == false and empty param.p_emp_id and empty bindings.exceptionsList}”/>

The “RefreshCondition” condition attribute determines whether or not the action will be triggered. The three action invocations below determine how the page will be rendered to the user. If  the call to the page is not a post back from the current page, and the “p_emp_id” param is not null, then associated View Object(s) will be cleared of existing data, passed the p_emp_id param and will execute and populate. This will put the screen in UPDATE mode.  Otherwise, if the “p_emp_id” param is null and the call to the page is not a post back, the screen will be presented in INSERT mode.

Passing a Parameter to the Page

Passing a parameter is a fairly simple matter.  You could pass it via a command link or command button with a param tag (NOTE: The navigation rule definition for the “action” can not contain a redirect reference.):

<af:commandButton text=”Some Text” action=”SomeAction”>
<f:param value=”123″/>
</af:commandButton>

or

<af:commandLink text=”Some Text” immediate=”true”
action=”SomeAction”>
<f:param value=”#{somebinding.value}”/>
</af:commandLink>
You can also pass a parameter via a standard URL:

http://someserver.some.domain:7778/myapp/faces/somepage.jsp?p_emp_id=123

Passing no parameters will result in the page rendering in INPUT mode.

Wrapping It Up …

As always, if you have questions, or input, please shoot me an email.

ADF Faces JavaScript Hack: How to Move a Generated Tag Event Handler

Saturday, August 22nd, 2009

(Originally posted on the “old” Jason Bennett’s Developer Corner, Saturday, March 15, 2008)

You may have noticed that ADF Faces generates some very specific JavaScript code for handling page level (tag level) events (onclick, onChange, onBlur, etc …). These event handlers “handle” all of those cool features such as “Partial Submit” and “Auto Submit”. Most of the time, we as developers (and users of ADF) have no direct control over where these framework generated event handlers are placed, or specific control over when they will fire. The focus of this entry is on how to move a generated event handler from one event to another on the same tag. For example: Let’s say that you want to implement a feature that will allow a user to type in an employee Id and then have the rest of the employee information (name, etc ..) auto populate. No problem, you just bind a method from a backing bean to a ValueChangeListener and turn on Auto Submit and you are done! However, what if you also want to use a command link to implement an LOV dialog on the same data entry field and use the data (i.e. the employee id) to limit the results of the LOV? Now you have a problem. If you enter data in the employee id field, and then try to navigate to your LOV link, the value change event (onChange) fires before the LOV triggers and nullifies the LOV event. The solution to the problem is obvious … just change the triggering event from onChange to onKeyPress (for the auto population … you would also need to add code to check for the triggering “Hot Key”). But wait … that code was generated by ADF Faces. We (the developers) have no direct control over where they place their code. Now, the problem becomes slightly more challenging (or interesting). The solution (one solution anyway …) is to write a JavaScript function that will move it for you and leave the original code intact. My version of the function looks like this:

function moveEventFunction(p_id,p_curr_event,p_new_event,conditionalFunc){

/* Get instance of the tag we are modifying. */

var formItem = document.getElementById(p_id);

var eventFunc = null;

/* Get text of target event handler code */

var existingEventCode = formItem.attributes[p_curr_event].value;

/* Only execute the move if the targeted event handler is populated */

if (existingEventCode.length > 0){

/* Convert text of existing event handler back into a working function */

var existingFunction = new Function(existingEventCode);

/* Create a function that will assign a new event handler to the desired item event.
* This needs to be dynamic since we can only make a direct assignment under “normal”
* circumstances. Ex. node.onclick= or node.onchange
*/

var addNewEvent = new Function(“node”,”eventfunc”,”node.”+p_new_event+”=eventfunc;”);

/* We assign “nothing” to the existing event handler. This must be dynamic
* for the same reason as the function above.
*/

var removeExistingEvent = new Function(“node”,”node.”+p_curr_event+”=”;”);

/* If a conditinal function (boolean function that can halt the event …)
* is provided, then wrap it around the existing code. Otherwise, execute
* the original handler under the new event.
*/

if (typeof(conditionalFunc) != “undefined”){

eventFunc = function(){ if (conditionalFunc()){ existingFunction()}};

}else{

eventFunc = existingFunction;

}

/* Add the new event handler */

addNewEvent(formItem,eventFunc);

/* Remove the old event handler */

removeExistingEvent(formItem);

}

}

The function, moveEventFunction, will move or swap the code assigned to one event handler and move it to a new event handler on the same node (or tag). The function also gives the developer the option of wrapping a new conditional (Boolean) function around the original event handler code.

Now that we have a solution, how do we apply it? You have a couple of options. First, place the call to moveEventFunction at the bottom of the page (between script tags). It will fire after all of the ADF/JSF HTML has been rendered.

<script>

moveEventFunction(<id of target tag>,<existing event name>,<new event    name>,<optional conditional function>);

</script>

However, if you plan on making the target tag a partial target (dynamic refresh), you will lose the swap. The second option handles this situation. Place the call on the onFocus event of the target tag. Doing so guarantees it the swap:

onFocus=”moveEventFunction(this.id,<existing event name>,<new event name>,<optional conditional function>);”

The conditional function (the last parameter) can perform multiple tasks prior to executing the main function (original function). In the case of the scenario above, the conditional function would check for the “Hot Key” that triggers our auto population. However, it must return true or false at the end of its execution.  The conditional function needs to be defined in the manner:

var fnc_MyConditionalFunction = function MyConditionalFunction(){ …}

This will allows allows you to pass the actual function as a parameter without it actually being executed (or evaluated) . Instead of passing in MyConditionalFunction, you pass in fnc_MyConditionalFunction.

(Another option that isn’t JavaScript related might be to get an instance of the UIComponent prior to page rendering and make the swap … haven’t tried that yet.)

ADF Faces – How To Get a DBTransaction Object Anytime You Need One

Saturday, August 22nd, 2009

(Originally posted on the “old” Jason Bennett’s Developer Corner, Thursday, March 06, 2008)

If you decide to execute a SQL statement or some PL/SQL code from with your ADF Faces application outside of the ADF BC framework (i.e. without using Entity Objects and View Object), you will need access to a JDBC connection.  Do you need to instantiate your own connections, or maintain a separate connection pool?  The answer is no!  ADF BC provides us with (abstracted) access to the JDBC connection object that is associated with our current application session.  Access is provided through the oracle.jbo.server.DBTransaction class.  You can get an instance of the DBTransaction object from several places within the ADF BC Framework: ViewObjectImpl, TransactionEventImpl, EntityImpl, and ApplicationModuleImpl.  All of these classes have a method called getDBTransaction() that return an instance of the DBTransaction object.  Armed with this knowledge, how do we go about getting an instance of DBTransaction anytime we want one?  By “anytime time we want one”, I mean externally from a View Object or Entity Object instance.  The answer is pretty simple.  We just need to access to an instance of the current ApplicationModule.  Using the following code, you can get a DBTransaction object anytime you want:

/***
* This method returns the current instance of the session DBTransaction object.
* The method below is implemented from a Singleton Object for utilitarian purposes.
*/
public static synchronized DBTransaction getDBTransaction(){

FacesContext ctx = FacesContext.getCurrentInstance();

ValueBinding vb = ctx.getCurrentInstance().getApplication().createValueBinding(“#{data}”);
BindingContext bc = (BindingContext)vb.getValue(ctx.getCurrentInstance());

//Use your own data control name when creating the DataControl object
//Look in the DataBindings.cpx file … the id attribute of the BC4JDataControl tag
DataControl dc = bc.findDataControl(“MyApplicationModuleControl”);
ApplicationModuleImpl am = ((ApplicationModuleImpl)(ApplicationModule)dc.getDataProvider());

return am.getDBTransaction();

}

Place the code listed above in a utility class. I prefer to use a static class or Singleton.

ADF Faces: Retrieve and/or Set values in a SelectOneChoice Component backed by a RowSetIterator

Saturday, August 22nd, 2009

(Originally posted on the “old” Jason Bennett’s Developer Corner, Thursday, January 31, 2008)

This entry covers how to retrieve values from a SelectOneChoice component that is backed (populated) by a ViewObject as defined in a ADF Faces page definition file.

I’ve been working on a fairly large and complex ADF Faces project for my current employer.  I often find myself having to both retrieve and set values in SelectOneChoice components in my backing beans.  I was initially confounded by the fact that the HTML generated by the component did not include my own code values behind the select options. Rather, each option (option tag) uses a numeric value instead of the actual code you would normally see if you were creating the HTML yourself (such as “NC” as the code for description “North Carolina”).  After some digging, I found that the numbers correspond to the Iterator index values of the Iterator that is bound to SelectOneChoice component.   By the way, setting the valuePassThru attribute on the component to true did not work for some reason.

Armed with this new knowledge, I was able to create two utility methods that reside in my base (utility) managed bean class.

The first method, getSelectOneChoiceValues, retrieves both the code (the actual code from your database or view object) and the description value from the Iterator that is bound to the SelectOneChoice component given the index value.  Here is the code for first method:

/***
* This method returns the code and desc values from a SelectOneChoice.
* Parameters
* (1) p_iteratorIndex – represents the index value of the iterator row we want. You get
* this value from bound ADF component.
* Ex. (Integer)boundSelectItem.getValue()
*
* (2) p_iterator – Name of the Iterator that populates the SelectOneChoice component
* (3) p_code_colname – Column attribute name of the column containing the code value (get this
* from the PageDefinition file for the screen, or the ViewObject that
* is bound to the Iterator.)
* (4) p_codedesc_colname – Column attribute name of the column containing the code desc (get this
* from the PageDefinition file for the screen, or the ViewObject that
* is bound to the Iterator.)
* (5) p_noselection_val – Set this value to “true” if you chose to add a “No Selection” row
* or null value row to your selection object. This row will become the
* zero index row. This “null” value row is not represented in the
* Iterator and throws the index values off by 1.
*
* The return value is a HashMap, but you could create a simple class for this as well.
*/
protected HashMap getSelectOneChoiceValues(int p_iteratorIndex,
String p_iterator,
String p_code_colname,
String p_codedesc_colname,
boolean p_noselection_val)
{
HashMap hm_lovVals = new HashMap();
String lovTypeCode = null;
String lovTypeDesc = null;
int noSelectIncrementor = 0;

if (p_noselection_val){
noSelectIncrementor = 1;
}

try{

// The code for “getRowSetIterator” can be found in the blog entry I published directly
// before this entry or Google “Jason getRowSetIterator”

RowSetIterator lovIter = getRowSetIterator(p_iterator);

Row iterRow = null;

iterRow = lovIter.getRowAtRangeIndex(p_iteratorIndex-noSelectIncrementor);

lovTypeCode = iterRow.getAttribute(p_code_colname).toString();
lovTypeDesc = iterRow.getAttribute(p_codedesc_colname).toString();

}catch(Exception e){
System.err.println(“Error looking up values for LOV iterator “+p_iterator);
}

//the keys “code” and “desc” should not be hard coded values in your production code …
hm_lovVals.put(“code”,lovTypeCode);
hm_lovVals.put(“desc”,lovTypeDesc);

return hm_lovVals;
}

The second method, getSelectOneChoiceIndex, performs the opposite function. Given code value and code column, it returns the actual index value. This allows you set the value of SelectOneChoice component on the screen ( Ex. selectionComponent.setValue(indexVal); ). Here is the code for the second method:

/***
* This method returns the index value for an item in a SelectOneChoice.
* Parameters
*
* (1) p_iterator – Name of the Iterator that populates the SelectOneChoice component
* (2) p_code_value – Code value whose index we are looking for.
* Ex. We pass in “NC” and get the index for the row in the Iterator
* that contains the code “NC”.
*
* (3) p_code_column – Column attribute name of the column containing the code value (get this
* from the PageDefinition file for the screen, or the ViewObject that
* is bound to the Iterator.)
*
* (4) p_noselection_val – Set this value to “true” if you chose to add a “No Selection” row
* or null value row to your selection object. This row will become the
* zero index row. This “null” value row is not represented in the
* Iterator and throws the index values off by 1.
*
* The return value is an Integer.
*/

protected Integer getSelectOneChoiceIndex(String p_iterator,
String p_code_value,
String p_code_column,
boolean p_noselection_val){
int v_code_index = 0;
int noSelectIncrementor = 0;

if (p_noselection_val){
noSelectIncrementor = 1;
}

try{

// The code for “getRowSetIterator” can be found in the blog entry I published directly
// before this entry or Google “Jason getRowSetIterator”

RowSetIterator lovIter = getRowSetIterator(p_iterator);
Row lovRow = null;

for (int x=0;x

lovRow = lovIter.getRowAtRangeIndex(x);

if(lovRow.getAttribute(p_code_column).equals(p_code_value)){
v_code_index = x+noSelectIncrementor;
break;
}

}

}catch(Exception e){
System.err.println(“Error looking up index value for LOV iterator “+p_iterator);
}

return new Integer(v_code_index);

}

An ADF Faces Base Class for a Backing/Managed Bean

Saturday, August 22nd, 2009

(Originally posted on the “old” Jason Bennett’s Developer Corner, Friday, November 23, 2007)

Over the last few months, I’ve been working on an ADF based project for my current employer.  The project is my first venture into JSF and ADF.  In this time I’ve developed a little base class that I extend when creating a backing bean (or managed bean) for my pages.  The base class contains several helpful utility methods that I thought I would share.  Some of these I discovered for myself, and a few others were inspired by samples provided by folks like: Steve Muench, Frank Nimphius, and Jonas Jacobi.  I have put the code below.  Each method has a comment at the top to explain what the method does:

The Code …

import javax.faces.application.Application;
import javax.faces.context.FacesContext;
import oracle.binding.OperationBinding;
import oracle.adf.model.binding.DCBindingContainer;
import oracle.adf.model.binding.DCDataControl;
import oracle.adf.model.binding.DCIteratorBinding;
import oracle.adf.view.faces.component.core.data.CoreTable;
import oracle.adf.view.faces.context.AdfFacesContext;
import oracle.binding.BindingContainer;
import oracle.jbo.ApplicationModule;
import oracle.jbo.Row;
import oracle.jbo.RowSet;
import oracle.jbo.server.EntityImpl;
import oracle.jbo.RowSetIterator;
import oracle.jbo.ViewObject;
import oracle.jbo.server.ViewRowImpl;
import oracle.jbo.uicli.binding.JUCtrlValueBindingRef;

public class ManagedBeanBase {

/**
* Contains page binding references
* This can be populated manually or
* automatically based on config setting
* in faces-config.xml
*
* This is a sample of an entry you would put in
* the faces-config.xml file. Notice the ‘managed-property’
* tag with property name ‘bindings’. This property will be
* set by the faces servlet using the setBindings method below.
*
*
* MyPageBackingBean
* MyPageMB
* request
*
*
bindings * #{bindings}
*
*
*/
*/
protected BindingContainer bindings;

public ManagedBeanBase() {
}

public BindingContainer getBindings() {

return this.bindings;
}

public void setBindings(BindingContainer bindings) {
this.bindings = bindings;
}

/**
* Use this to manually set page bindingings.
*/
public void setBindings(){
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
bindings = (DCBindingContainer) app.getVariableResolver().resolveVariable(context, “bindings”);
}

/**
* Call this method to refresh the binding container
* with any changes.
*/
protected void refreshBindingContainer(){

DCBindingContainer dcBind = (DCBindingContainer)bindings;
dcBind.refresh();

}

/**
* This method is used the removed the currently selected
* row from and ADF (JSF) table. The method requires
* that the table object be passed in as a parameter.
*/
protected void deleteSelectedRow(CoreTable pageTable){

JUCtrlValueBindingRef rwData = (JUCtrlValueBindingRef)pageTable.getSelectedRowData();

Row rw = rwData.getRow();

rw.remove();

}

/**
* This method takes the name of a given iterator (as defined in the page def file)
* and returns the current rowset.
*/
protected RowSetIterator getRowSetIterator(String p_iterator){

DCBindingContainer dcBind = (DCBindingContainer)bindings;
DCIteratorBinding iterBind= (DCIteratorBinding)dcBind.get(p_iterator);

return iterBind.getLovRowSetIterator();

}

/**
* This method will return the ViewObject (object) associated
* with a given iterator.
*/
protected ViewObject getViewObjectFromIterator(String p_iterator){

DCBindingContainer dcBind = (DCBindingContainer)bindings;
DCIteratorBinding iterBind= (DCIteratorBinding)dcBind.get(p_iterator);

return iterBind.getViewObject();

}

/**
* This method will execute the query associated the view object
* with which the iterator is associated.
*/
protected void executeIterQuery(String p_iterator){

DCBindingContainer dcBind = (DCBindingContainer)bindings;

DCIteratorBinding iterBind= (DCIteratorBinding)dcBind.get(p_iterator);

iterBind.executeQuery();

}

/**
* This method issues a rollback again the current transaction.
*/
protected void rollbackCurrentChanges(){

DCBindingContainer dcBind = (DCBindingContainer)bindings;
dcBind.getDataControl().getApplicationModule().getTransaction().rollback();

}

/**
* Manually add a page component to the partial target list
* for partial page refresh.
*/
protected void addPartialTarget(UIComponent p_target_object){
AdfFacesContext.getCurrentInstance().addPartialTarget(p_target_object);
}

}

Oracle ADF Faces Tip: How to hide the Asterisk (*) when the “required” Property is Set to “true”

Saturday, August 22nd, 2009

(Originally posted on the “old” Jason Bennett’s Developer Corner, Monday, July 23, 2007)

If this one is common knowledge, then forgive me.  I just jumped into ADF and JSF a few weeks ago (I was a STRUTS man), and am drinking from the firehose!  There is a property on some of the ADF Faces components (inputText, selectOneChoice, etc …) called “required”.  If set to true, this property will ensure that the user enters a value for the item (in DB terms, it makes the field a NOT NULL field).  This is a convenient feature with one small exception.  Setting the property to true places a green asterisk(*) on the left side of the data entry item.  The asterisk appears whether you want it to or not  and there is no option/property available for turning it off (NOTE: This is an ADF inputText feature, not a standard JSF inputText feature).  This is an issue if your development standards say to put an asterisk on the RIGHT side of the input field (as mine do).

The solution to the problem was fairly straight forward.  Since I had implemented a custom skin for this ADF Faces application and created a custom CSS document (see this article by Jonas Jacobi), I simply over-rode the existing style for the required icon with this one:

.AFRequiredIconStyle { display:none }

Presto!  No more little green asterisk.