Showing posts with label Adf Faces. Show all posts
Showing posts with label Adf Faces. Show all posts

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

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.

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.

Tuesday, May 19, 2009

Custom Component On top of ADF - JSF UI Components

Building Custom JSF UI Components

Overview

One of the key strengths of JavaServer Faces (JSF) is that not only does it provide substantial technology for easy, out of the box component based J2EE Web applications assembly, but it also is a very flexible API which allows for a wide breadth of customizations in numerous and innovative ways. This article introduces and explores the component developer's experience of building custom JSF user interface (UI) components.

Intended Audience

First off, this article is intended for component developers who already have an understanding of the overall JSF application development process but want to learn how to start developing their own custom JSF UI components. For those who are still new to JSF development, readers are highly recommended to first consult JSF application tutorials such as Rick Hightower's article on basic JSF development:

#http://www-106.ibm.com/developerworks/library/j-jsf1/

Or my earlier JavaPro article, which also introduces JSF:
http://www.fawcette.com/javapro/2004_01/magazine/features/cschalk/

In contrast to those introductory JSF articles, this article introduces the more advanced task of building custom JSF UI components by first explaining all of the "moving parts" associated with custom UI Components starting with a simple custom "HelloWorld" UI Component as an example.

The article then shows how to extend the simple "HelloWorld" component into more useful examples that show live stock quote information using a Web service. At the end of the article readers will have an appreciation of what exactly are the key tasks associated with building custom UI Components along with a full understanding of all the various sub-components that make up a typical "JSF UI Component".

When to Customize JSF .Before jumping into custom JSF component development just for the sake of it, some research should be done on whether custom development is necessary at all and at what level it is needed. As mentioned before, JavaServer Faces' base UI component library actually provides a modest amount of practical UI and non-UI components in its specification. In addition to visible components such as input/output fields, menu components and form buttons the JSF specification also has non-UI components which handle things like basic validation and/or data conversion. In many cases a developer may find that he/she may only need to customize a specific sub-component such as a new validation method as opposed to building an entirely new UI Component.

An easy google search or browsing through sites such as jsfcentral.com many usable and often free component libraries (and implementations) that can be experimented with. Some of the more popular and powerful ones include:

MyFaces - A general purpose and open source component library and implementation. - http://myfaces.apache.org


Oracle's ADF Faces - A rich library of useful JSF UI Components - http://www.oracle.com/technology ... ange/jsf/index.html

JScape's WebGalileo Faces - http://www.jscape.com/webgalileofaces/

Once the decision has been made to build some custom components as opposed to just using some existing ones, here's how to get started.

The "Moving Parts" of a JSF UI Component

The term "JSF UI Component" is generally used to describe a set of sub-components which each which perform their own specific task such as rendering the component, validating its input, and/or performing any data conversions (such as a String to a Date conversion). This may often give the impression to a novice JSF developer that JSF component development is fairly complicated and possibly tedious, but this is also JSF's strength in that each UI Components' sub-components can be individually customized and re-configured into new and varied combinations. In fact it is JSF's flexible API and it's "pluggable renderering" technology which allows UI Components to written for multiple Web clients thus drastically decreasing the complexity for the Web developer of assembling multi-client Web applications. Let's review the various "moving parts" of what constitutes a JSF UI Component.


The general term "JSF UI Component" refers to a collection of the following:

UIComponent Class - A Java class derived from either the UIComponentBase or extended from an existing JSF UIComponent such as outputText. This is the actual Java class representing the core logic of the component. It can optionally contain the logic to "render" itself to a client, or rendering logic can be separated into a separate "renderer" class.


Renderer Class - This is a class that only contains code to render a UIComponent. Rendering classes can provide different renderings for a UI Component. For such as either a button or hyperlink for the UICommand component. Renderers can also provide different rendering options for the same UI Component on different client types such as browsers, PDAs etc. This allows JSF the ability to run on any client device providing a corresponding set of renderer classes are built for the specific client type.

UI Component Tag Class - This is a JSP tag handler class that allows the UI Component to be used in a JSP. It can also associate a separate renderer class with a UIComponent class. (Note: The UI Component Tag handler class is only required for usage in a JSP deployment environment. Keep in mind that UI Components can also be used in non-JSP environments.)

Tag Library Descriptor File - This is a standard J2EE JSP tag library descriptor (tld) file which associates the tag handler class with a usable tag in a JSP page. (Required only For JSP usage only.)
Associated helper classes - These include a collection of standard (included in JSF RI) or custom helper classes such as Converters, Validators, ActionListeners etc., that can be programmatically bound to UI Components. For example a JSF UI Input Field component can be associated with a built-in number range Validator which ensures that an entered number is within a certain range. These helper classes can also be customized to perform any type of validation not provided out of the box with the JSF RI. For example a custom credit card Validator could be used with a JSF Input field to validate credit card numbers or a custom Converter could be used to convert currencies.

A Simple "HelloWorld" Custom UI Component Example

Before showing how to build a "Hello World" custom component, let's review quickly how to use it. To invoke the component we have a JSF enabled JSP page with an extra taglib directive specifying a custom tag library (tld) which contains the custom tag, "jsfhello", which is associated with our custom UI Component. To use the jsfhello tag, we simply place it into the body of the JSP and set an optional "hellomsg" attribute.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"><%@ page contentType="text/html;charset=windows-1252"%><%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%><%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%><%@ taglib uri="http://theserverside.com/customfacescomponents" prefix="cf"%><f:view> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1252"></meta> </head> <body> <h:form> <p>A simple HelloWorld Custom Component:</p> <p>The HelloWorld UI Component:</p> <cf:jsfhello hellomsg="Hello world! This is output from a custom JSF Component!" /> </h:form> </body> </html></f:view>
When the page is run, the JSF UI Component displays the "Hello World" message provided in the "hellomsg" attribute along with the current date and time. We'll review the details of the tag library and how the tag handler class invokes the UI Component shortly, but first let's review how to build the core UI Component class.

Building the"HelloWorld" Custom UI Component Step 1: Creating a UIComponent Class

For our HelloWorld example, our UIComponent will extend the UIComponentBase abstract class, which is provided in the JSF specification, and render a formatted HelloWorld message. Note: We could have also based our new UI Component class on the concrete UIOutput base class which is basically the same as the UIComponentBase with the exception that it has a "value" attribute. Since we aren't using one, we'll simply base it on the UIComponentBase abstract class.

package tss.hello;

import java.util.Date;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import java.io.IOException;
import javax.faces.context.ResponseWriter;
public class HelloUIComp extends UIComponentBase
{
public void encodeBegin(FacesContext context) throws IOException
{
ResponseWriter writer = context.getResponseWriter();
String hellomsg = (String)getAttributes().get("hellomsg");
writer.startElement("h3", this);
if(hellomsg != null)
writer.writeText(hellomsg, "hellomsg");
else
writer.writeText("Hello from a custom JSF UI Component!", null);
writer.endElement("h3");
writer.startElement("p", this);
writer.writeText(" Today is: " + new Date(), null);
writer.endElement("p");
}
public String getFamily() { return "HelloFamily"; }
}
As you can see, this custom UI Component renders a formatted Helloworld message using and encodeBegin() method. Also notice that we have defined a method getFamily(). This is actually required for UI Components that extend UIComponentBase since it could come from any component family. Since in our example we won't be creating a new family of components, we can just return any String value such as "HelloFamily". Before examing the code further, a quick note on encoding and decoding.

A Quick Note on Encoding Methods

UI Components and/or associated renderer classes use encode*() methods display themselves to a client. The above HelloWorld example simply renders an HTML header (h3) with the custom hello message (if supplied) along with a paragraph containing the current date and time. For this component a single encodeBegin() (or encodeEnd() ) method is all that is needed to render the complete tag since it does not contain any children. The encodeBegin actually renders the beginning or the complete (bodiless) tag. UI Components with children tags/components will override encodeChildren() along with encodeEnd(). The encodeChildren() method allows children components to be rendered and encodeEnd() renders the closing parent tag.

A Closer Look at the encodeBegin() Method

Upon closer examination of the encodeBegin() method, we see that it receives the FacesContext as an argument. An extension to the servlet and JSP context, the FacesContext provides access to the many useful objects for JSF/JSP/Servlet development. In this example, we simply extract a "writer" object in order to "write" our rendered response back to the client.

public void encodeBegin(FacesContext context) throws IOException { ResponseWriter

writer = context.getResponseWriter();
Next we get the value of the attribute "hellomsg" which is passed from the tag from our JSP page using getAttributes(). The getAttributes method comes from the UIComponentBase class which is the base class for all UI Components.
String hellomsg = (String)getAttributes().get("hellomsg");
Rendering the HTML message is done using the writer methods in the code:
writer.startElement("h3", this);
if(hellomsg != null)
writer.writeText(hellomsg, "hellomsg");
else
writer.writeText("Hello from a custom JSF UI Component!", null);
writer.endElement("h3");
writer.startElement("p", this);
writer.writeText(" Today is: " + new Date(), null);
writer.endElement("p");
which when executed displays a formatted HTML "HelloWorld" message to the client.
Note: You'll notice that when the attribute (hellomsg) or "property" is written to the client, an additional String value representing the name of the property "hellomsg" is also included as an argument to the writeText() method. The idea behind this is to provide development tools environments the ability to display the name of the property in a visual editor. Leaving the second argument null is also acceptable and will not harm the execution of the component.
Step 2. Registering the custom UI Component in Faces-config.xml
Before moving on to building a JSP tag handler and a TLD file, we'll add a required entry for our custom component in the faces-config.xml file. The syntax for adding our custom UI component is:...
<faces-config xmlns="http://java.sun.com/JSF/Configuration"> <component> <component-type>tss.hello.JsfHello</component-type> <component-class>tss.hello.HelloUIComp</component-class> </component>
...</faces-config>
The component-type is the "JSF recognized" name of our custom component: "tss.hello.JsfHello". (We'll refer to this later in our tag handler.) The component-class is the actual class path address of our UI Component.
Step 3. Building a Custom JSP Tag Library
In order to be able to use our custom component in a JSP, we need a custom tag library comprised of a tag library descriptor file (TLD) along with references to taghandlers classes. (This example uses just a single tag handler.)
Building the Tag Handler
For JSF component development, the JSP taghandler class is derived from javax.faces.webapp.UIComponentTag. It's main purpose is to:
Associate a JSP callable tag (handler class) with the UI Component.
Associate a separate renderer class (if needed) to the UI Component.
Set the properties from the submitted tag attribute values to the UI Component.
Here is the source code for our tag handler class:
package tss.hello;
import javax.faces.application.Application;
import javax.faces.webapp.UIComponentTag;
import javax.faces.component.UIComponent;
import javax.faces.el.ValueBinding;
import javax.faces.context.FacesContext;
public class FacesHelloTag extends UIComponentTag
{
// Declare a bean property for the hellomsg attribute.
public String hellomsg = null;
// Associate the renderer and component type.
public String getComponentType() { return "tss.hello.JsfHello"; }
public String getRendererType() { return null; }
protected void setProperties(UIComponent component)
{
super.setProperties(component);
// set hellomsg
if (hellomsg != null){
if (isValueReference(hellomsg)){
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ValueBinding vb = app.createValueBinding(hellomsg);
component.setValueBinding("hellomsg", vb);}
else

component.getAttributes().put("hellomsg", hellomsg);
}
}
public void release(){
super.release();
hellomsg = null;
}
public void setHellomsg(String hellomsg){
this.hellomsg = hellomsg;
}
}
The first thing to note is the "hellomsg" bean property of type String along with its associated getter and setter methods at the bottom of the class. The hellomsg bean property, "hellomsg", is also an attribute in the JSP tag. (<sf:jsfhello hellomsg="Hello world!"../>)
Next we see two methods which associate this tag handler with our registered UI Component: "tss.hello.JsfHello" as well as associate the renderer. Since we don't have a separate renderer class, this statement returns a null value.
// Associate the renderer and component type.
public String getComponentType() { return "tss.hello.JsfHello"; }
public String getRendererType() { return null; }
The next method, setProperties(), sets the incoming values from the JSP tag by first calling the parent class' setProperties method along with custom code to set the value from the hellomsg tag attribute. Notice that a check is first done to see if the incoming attribute is a "ValueReference", which takes the form of a JSF EL expression: #{Bean.Property}. If a "ValueReference" is detected, it uses slightly different logic to set the application's value binding.
protected void setProperties(UIComponent component)
{
super.setProperties(component);
// set hellomsg
if (hellomsg != null)
{if (isValueReference(hellomsg)){
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ValueBinding vb = app.createValueBinding(hellomsg);
component.setValueBinding("hellomsg", vb);
}else
component.getAttributes().put("hellomsg", hellomsg);
}
}
Asides from the hellomsg getter and setter methods the only method required in the taghandler class is the release() method which resets the bean properties back to an unused state.
public void release()
{
super.release();
hellomsg = null;
}
and that's it for our tag handler class. Next we'll quickly review the JSP Tag Library Descriptor (TLD) required for this tag.

Step 4. Building the Tag Library Descriptor File

In order for us to use our custom JSP tag handler class, we need to create an associated TLD file which contains the tag entry associated with the tag handler class. Here is an example of the TLD file needed for this tag. The TLD associates the tag name, "jsfhello" with the tag class "tss.hello.FacesHelloTag" along with it's associated attributes. For our tag, we include our custom attribute, "hellomsg", along with the superclass' core attributes: "id", "binding" and "rendered".

<?xml version="1.0" encoding="ISO-8859-1" ?><!DOCTYPE taglib

PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"

"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd"><taglib><tlib-version>0.01</tlib-version><jsp-version>1.2</jsp-version>

<short-name>simple</short-name>

<uri>http://theserverside.com/simplefacescomponents</uri>

<description>This tag library contains simple JSF Component examples.</description>

<tag><name>jsfhello</name><tag-class>tss.hello.FacesHelloTag</tag-class>

<attribute> <name>binding</name> <description>A value binding that points to a bean property</description></attribute>
<attribute> <name>id</name> <description>The client id of this component</description></attribute>
<attribute> <name>rendered</name><description>Is this component rendered?</description></attribute>
<attribute> <name>hellomsg</name><description>a custom message for the Component</description></attribute>
</tag>
</taglib>
Following standard J2EE architecture, the custom TLD file is placed in the /WEB-INF/. sub-directory of the J2EE Web Module containing the application.
Running the simple HelloWorld Example
Just to review, our custom JSF component java classes must be compiled and available on the classpath of a J2EE Web Module. The Web Module must also have in it's class path the required JSF runtime jar files which include: jsf-api.jar, jsf-impl.jar along with the commons jar files (commons-beanutils.jar, commons-collections.jar, commons-digester.jar, commons-logging.jar). The other two required jar files come from JSTL (jstl.jar and standard.jar).
For more info on the Commons and JSTL libraries refer to the Jakarta Apache Project website: http://jakarta.apache.org/ .) For a runtime deployment, all the required jar files must be placed in the /WEB-INF/lib subdirectory of your J2EE Web Module.
Assuming your runtime environment is properly configured, you can test the simple JSF Hello World custom component by first creating a JSF enabled JSP page and then adding the taglib directive and dropping the tag into your page. (As explained before..)
When the JSF page is run, you will see the execution of your HelloWorld JSF Custom Component!
Extending the HelloWorld Custom Component
Now that we've created a simple HelloWorld component, we can now expand upon this very easily. One straightforward extension would be to make the HelloWorld component call a Web service for a specific stock symbol and print out it's value. So instead of providing a hellomsg, our tag/component attribute will contain a stock symbol. The renderer code will then query a stock quote Web service (made available to us via another class) with the symbol provided by the tag and print the current price in the response.
Here's how to modify the HelloWorld Custom Component to display a live stock quote using a Web service.
Create a Web Service Proxy Client
In order to call a Web service from java, you'll need to create a proxy java client which enables any other Java class the ability to call a stock Web service. Many free stock quote Web services are available on the Internet. This example uses the "Delayed Stock Quote Service" available from Xmethods.com. The actual Web Proxy creation step is left to the reader to implement since it is out of the bounds of JSF development however several Java Integrated Development Environments such as Oracle JDeveloper, can automatically generate the necessary client code which enables communication to a Web service.
Oracle JDeveloper 10.1.3 Preview's Web Service Proxy Wizard
Once a Web service Proxy class is created, we'll modify our hellomsg attribute to become a stock symbol attribute and call the Web service with this value and then print it out. This involves the following changes:
Create or Modify the HelloWorld UIComponent Class to Work with "Symbol" Attribute
Change or create a new UIComponent class which refers to a stock symbol attribute, "symbol", instead of the "hellomsg".
public class StockUIComp extends UIComponentBase
{
public void encodeEnd(FacesContext context) throws IOException
{
ResponseWriter writer = context.getResponseWriter();
String symbol = (String)getAttributes().get("symbol");...
Note: If you create a new UI Component such as StockUIComp, don't forget to register it in your faces-config file ( You could use the name: "tss.hello.JsfStock" mapped to the classpath address "tss.hello.StockUIComp").
Once you've retrieved the attribute value for the stock symbol, you can call your Web service proxy class to get the current price:
//get stock price using generated Web service Proxy
String stockprice = NetXmethodsServicesStockquoteStockQuotePortClient.getStockPrice(symbol);
Rendering the the stock price is easily done with the following code:
writer.startElement("p", this);

if(symbol != null)
writer.writeText("The stock price for " + symbol + " is: " + stockprice + ".", null);
else
writer.writeText("You must provide a Stock Symbol by setting the symbol attribute.", null);
writer.endElement("p");
The changes to the tag handler and TLD is a trivial search and replace of "hellomsg"" with "symbol". Your tag handler class will also have to refer to the different Stock UI Component: "tss.helloJsfStock", but the remaining code in the taghandler is basically the same as before with the "symbol" attribute replacing the "hellomsg" attribute:
public class StockTag extends UIComponentTag {
public String symbol = null;
public String getRendererType() { return null; } public String getComponentType() { return "tss.hello.JsfStock"; }
protected void setProperties(UIComponent component)
{
super.setProperties(component);
// set symbol
if (symbol != null){
if (isValueReference(symbol)){
FacesContext context = FacesContext.getCurrentInstance();
Application app = context.getApplication();
ValueBinding vb = app.createValueBinding(symbol);
component.setValueBinding("symbol", vb);

} else
component.getAttributes().put("symbol", symbol);
}...
Once you've updated your TLD with a new tag "simplestock" mapped to the taghandler "StockTag", you can then add the new tag to your JSP:
<p>The SimpleStock UI Component:</p> <sf:simplestock symbol="orcl" />
Here's the output for the HelloWorld Component along with the new Stock UI Component:
Extending the Stock UI Component Further
Now that we've extended the HelloWorld UI Component into something useful, let's further extend the stock component to make it more user friendly. Our modified stock component will now render an input field along with a submit button. This will allow users to enter a new stock symbol at runtime as opposed to hardcoding the attribute value in the JSP source.
This modification will introduce how to build a decode() method which is used to "decode" the incoming form field values as opposed to simply retrieving tag attribute values. We will also extend our simple encode() method to now render in input field along with a submit button.
Back to the UI Component
This time we'll name the UI Component "HtmlInputStock" following the JSF specification's naming convention. This time we'll extend extend the class from the UIInput component since it will be accepting input.
public class HtmlInputStock extends UIInput
{...
This component will have a more detailed encode() method. This time our encodeBegin() method will call separate encode methods to render the differerent elements: an input field, a submit button, and an output field which displays the returned price of the stock. Notice that I've add the identifiers ".inputbutton" and ".submitbutton" to the clientIds respectively when calling the encode methods. This will ensure that the names of the rendered HTML: fields will be unique on the client. In general this is good practice should you need to refer to the rendered name of the HTML field.
The encodeBegin() method is as follows:
public void encodeBegin(FacesContext context) throws IOException {

ResponseWriter writer = context.getResponseWriter();
String clientId = getClientId(context);
encodeInputField(writer, clientId+".inputbutton");
encodeSubmit(writer, clientId+".submitbutton");
encodeOutputField(context);
}
The encodeInputField() method is as follows:
private void encodeInputField(ResponseWriter writer, String clientId) throws IOException {
// render a standard HTML input field
writer.startElement("input", this);
writer.writeAttribute("type", "text", null);
writer.writeAttribute("name", clientId, "clientId");
Object v = getValue();
if (v != null)
writer.writeAttribute("value", v.toString(), "value");
writer.writeAttribute("size", "6", null);
writer.endElement("input");
}
Notice the name of the input field is assigned the clientId. We'll use this later to identify the field when we decode the input.

The encodeSubmit() is rendered with:

private void encodeSubmit(ResponseWriter writer, String clientId) throws IOException {// render a submit buttonwriter.startElement("input", this);writer.writeAttribute("type", "Submit", null);write.writeAttribute("name", clientId, "clientId");writer.writeAttribute("value", "Enter Stock Symbol", null); writer.endElement("input");}And finally the encodeOutputField() which is similar to before:public void encodeOutputField(FacesContext context) throws IOException{
ResponseWriter writer = context.getResponseWriter();
String symbol = (String)getAttributes().get("value"); // The "value" attribute is used to pass the stock symbol.//get stock priceString stockprice = NetXmethodsServicesStockquoteStockQuotePortClient.getStockPrice(symbol);writer.startElement("p", this);if(symbol != null)writer.writeText("The current price for " + symbol + " is: " + stockprice + ".", null);else

writer.writeText("", null); writer.endElement("p"); }

Now let's move on to the decode() method who's job is to parse the incoming field values and act upon it.public void decode(FacesContext context) {Map requestMap = context.getExternalContext().getRequestParameterMap();String clientId = getClientId(context);try {String string_submit_val = ((String) requestMap.get(clientId+".inputfield")); setSubmittedValue(string_submit_val); setValid(true);}catch(NumberFormatException ex) {// let the converter take care of bad input, but we still have// to set the submitted value, or the converter won't have// any input to deal withsetSubmittedValue((String) requestMap.get(clientId));}
}

Let's review some of the key statements in our decode() method. First our decode() method obtains a requestMap from the JSF Context.

Map requestMap = context.getExternalContext().getRequestParameterMap();The requestMap is a container which allows us to access the values submitted in the http request.
The next statement extracts the clientId which is the unique identifier of the client issuing the request. (i.e. submitting the form)


String clientId = getClientId(context);With the unique client identifier we can obtain the value of the submitted value contained in the requestMap for this client. We can then set the submittedValue to the value submitted in the form. Note: For this example, we are simply setting the value that was submitted as is, but in other cases we may wish to perform a conversion or validation on the submitted value before setting the value as "valid".

try {

String string_submit_val = ((String) requestMap.get(clientId)); setSubmittedValue(string_submit_val);
setValid(true);

}

catch(NumberFormatException ex) {

setSubmittedValue((String) requestMap.get(clientId));
}
That takes care of our new and improved UIComponent rendering (encoding and decoding). I'll leave out the step of registering this component in the faces-config and highlight the remaining trivial code modifications in the tag handler and the TLD.
For the tag handler we have only minor changes. This tag handler as before extends from the same UIComponentTag but will have a bean property of "value" instead of "symbol". The "value" property is the value submitted in the input field and is handled exactly in the same manner before as the symbol. The only other difference from before is that our tag handler is now registered with the StockInput UI Component Class.
public String getComponentType() { return "tss.hello.StockInput"; }
The setProperties method is basically the same as before but operating on the "value" instead "symbol":
protected void setProperties(UIComponent component) {

super.setProperties(component);

if (value != null)
{
if (isValueReference(value))
{
FacesContext context = FacesContext.getCurrentInstance();

Application app = context.getApplication();


ValueBinding vb = app.createValueBinding(value);

component.setValueBinding("value", vb);
}

else

component.getAttributes().put("value", value);

}

Updating the TLD Similar to before, the new TLD tag entry can be as follows:

...

<tag><name>stockinput</name><tag-class>tss.hello.StockInputTag</tag-class>

<attribute> <name>binding</name> <description>A value binding that points to a bean property</description></attribute>

<attribute> <name>id</name> <description>The client id of this component</description></attribute>

<attribute> <name>rendered</name><description>Is this component rendered?</description></attribute><attribute> <name>value</name><description>A value for submitted stock symbol..</description></attribute>

</tag> ....

Running the Stock Input Component

Invoking this component is done in a similar fashion as before where we simply add the tag to the page:

<sf:stockinput id="stockinput" value="" />

Notice that we can leave the value attribute blank but specify it later when we run it. Once the page is running, enter a test stock symbol such as ORCL or AMZN and check out the result!

Summary

As you can see, building custom JSF UI Component is a fairly straightforward process. Once you understand the mechanism detailed in the encode() and decode() methods in the rendering code, the rest is a fairly trivial process of providing the necessary "plumbing" with tag handlers as such to enable usage in a typical client such as a JSP based client.

Future articles on JSF Component development will also build upon these simple examples and show how to build other non visual JSF components such as Validators and Converters.
For More Deatils thepeninsulasedge.com

Sunday, April 5, 2009

ADF Faces RC: Dynamic Table

Example

I have seen a number of posts in the forums concerning “How to create dynamic tables with RCF?”. As such, here is code example that creates an af:table with commandButtons that allow a user to dynamically add both rows and columns to a table, creating the oh so desired Ajax goodness.
Now, there a couple of things to note about this example. Namely, this example does not dynamically create components in a backing bean. Instead, a “best practices” approach is taken that enforces better separation between data and UI manipulation. Thus, the dynamic nature of the table is driven by updates to the model rather directly manipulating UI components.
JSPX File
Managed Bean: DynaTableBean.java
JAVA:
1.package com.thepeninsulasedge.view.dynatable.managed;
2.
3.import java.util.ArrayList;
4.import java.util.Collection;
5.import java.util.HashMap;
6.import java.util.List;
7.
8.import java.util.Map;
9.
10.import javax.faces.event.ActionEvent;
11.
12.import org.apache.myfaces.trinidad.model.CollectionModel;
13.import org.apache.myfaces.trinidad.model.SortableModel;
14.
15.public class DynaTableBean {
16. private SortableModel model;
17. private List columnNames;
18.
19.public DynaTableBean() {
20. columnNames = new ArrayList();
21. }
22.
23.// Add a new row to the model
24. public void addRow(ActionEvent evt){
25.if(!columnNames.isEmpty()){
26. Map newRow = createNewRowMap();
27.((List)model.getWrappedData()).add(newRow);
28.}
29.}
30.
31.// Get table model
32. public CollectionModel getCollectionModel(){
33. if(model == null){
34. model = new SortableModel(new ArrayList());
35. }
36. return model;
37. }
38.
39.// Get Column Names
40.public Collection getColumnNames(){
41. return columnNames;
42. }
43.
44.// Add column
45.public void addColumn(ActionEvent evt){
46. // Create new column name
47.String colName = (columnNames.size()+1) + “”;
48.// Add column name to list of names
49. columnNames.add(colName);
50. // Create new row
51. Map newRow = createNewRowMap();
52. // Add new column name to new row
53. newRow.put(colName,null);
54.// Update existing model
55.addColumnToCurrentModel(colName);
56.}
57.
58.// Add column to existing rows
59. private void addColumnToCurrentModel(String name){
60. List list = (List)model.getWrappedData();
61. for(Map row:list){
62. row.put(name,null);
63. }
64. }
65.
66. private Map createNewRowMap(){
67.Map newRow = new HashMap();
68. for(String colName:columnNames){
69. newRow.put(colName,null);
70. }
71.return newRow;
72.}
73.
74.}
IN BACKING BEAN
In backing I have set ‘DynamicTable’ to instantiate it manually, if the session bean might not be get right.
public void setDocument1(RichDocument document1) {
this.document1 = document1;
FacesContext ctx = FacesContext.getCurrentInstance();
Application app = ctx.getApplication();
ValueBinding bind = app.createValueBinding(”#{DynamicTable}”);//session bean name which has given in adf-config
Object o = bind.getValue(ctx);
DynaTableBeantemp = (DynaTableBean) o;
// temp.setUserName(”Test “);
// temp.setDateAndTime(Calendar.getInstance().getTime().toString());

}