ADF Faces: How To Use a Single JSP for both INSERTING and UPDATING
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 first method looks 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(); }
The second method (used to clear the data from the view object) looks like this:
/***
* This method will clear any data out of the existing VO.
*/
public void clearView() {
if (getWhereClause() != null) {
setWhereClause(null);
}
executeQuery();
}
Add these two methods (modified to fit your View Object) to the ViewObjectImpl class associated with your View Object. Some might say that you could combine the two methods (since both will be end up being called to put the page in update mode). I chose to keep them separate in case I wanted (or needed) to call one without the other at some point.
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 id="clearView" MethodName="clearView" RequiresUpdateModel="true" Action="999" IsViewObjectMethod="true" DataControl="AppModuleDataControl" InstanceName="AppModuleDataControl.MyemployeeView1"/>
<methodAction id="queryViewById" 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:
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 id="Create" 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 id="clearViewObject" Binds="clearView" RefreshCondition="#{adfFacesContext.postback == false and not empty param.p_emp_id}" Refresh="prepareModel"/>
<invokeAction id="queryViewObject" Binds="queryViewById" RefreshCondition="#{adfFacesContext.postback == false and not empty param.p_emp_id}" Refresh="prepareModel"/>
<invokeAction Binds="Create" id="invokeCreate" 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 name="p_emp_id" value="123"/> </af:commandButton>
or
<af:commandLink text="Some Text" immediate="true" action="SomeAction"> <f:param name="p_emp_id" 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.
9:50:12 PM
|