Saturday, May 30, 2009

JavaScript Date Functilons


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


// Author: Vipin K R


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


//


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


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


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


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



//


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


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


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


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


// include it in your javascript
libraries for download.


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


// to the URL instead.


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



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


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





// HISTORY


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


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


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


// March 11, 2003: Added "NNN"

formatting option. Doesn't match up


// perfectly with
SimpleDateFormat formats, but


//
backwards-compatability was required.





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


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


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


// The format string consists of the
following abbreviations:


//



// Field | Full Form |
Short Form


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


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


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


// | NNN (abbr.) |


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


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


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


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



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


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


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


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


// AM/PM | a |


//


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


// Examples:


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



// Dec 1, 1900


// Nov 20, 00


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


// 9/2/00


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



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





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


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


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






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


// isDate ( date_string, format_string
)


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


// is a valid date. Else returns false.


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


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


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


function isDate(val,format) {


var
date=getDateFromFormat(val,format);



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


return true;


}





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


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


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



// Returns:


// 1 if date1 is greater than date2


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


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


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


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


var
d1=getDateFromFormat(date1,dateformat1);


var
d2=getDateFromFormat(date2,dateformat2);



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


return -1;


}


else if (d1 > d2) {


return 1;



}


return 0;


}





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


// formatDate (date_object, format)


// Returns a date in the output format
specified.



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


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


function formatDate(date,format) {


format=format+"";


var result="";


var i_format=0;



var c="";


var token="";


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


var M=date.getMonth()+1;


var d=date.getDate();



var E=date.getDay();


var H=date.getHours();


var m=date.getMinutes();


var s=date.getSeconds();


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


// Convert real date parts into
formatted versions



var value=new Object();


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


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


value["yyyy"]=y;



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


value["M"]=M;


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


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



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


value["d"]=d;


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


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



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


value["H"]=H;


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


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



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


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


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



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


value["k"]=H+1;


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



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


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


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



value["m"]=m;


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


value["s"]=s;


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



while (i_format < format.length)
{


c=format.charAt(i_format);


token="";


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

format.length)) {


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


}


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


else { result=result + token; }


}



return result;


}




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


// Utility functions for parsing in
getDateFromFormat()


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


function _isInteger(val) {


var digits="1234567890";



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


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


}


return true;


}



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


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


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


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


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



}


return null;


}




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


// getDateFromFormat( date_string ,
format_string )


//



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


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


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


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


function getDateFromFormat(val,format)
{


val=val+"";


format=format+"";



var i_val=0;


var i_format=0;


var c="";


var token="";


var token2="";



var x,y;


var now=new Date();


var year=now.getYear();


var month=now.getMonth()+1;


var date=1;


var hh=now.getHours();



var mm=now.getMinutes();


var ss=now.getSeconds();


var ampm="";




while (i_format < format.length)
{



// Get next token from format
string


c=format.charAt(i_format);


token="";


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



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


}


// Extract contents of value
based on format token


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



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


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


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



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



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


i_val += year.length;


if (year.length==2) {


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


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



}


}


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


month=0;


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



var
month_name=MONTH_NAMES[i];


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


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


month=i+1;



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


i_val +=
month_name.length;


break;


}


}


}



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


}


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


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



var
day_name=DAY_NAMES[i];


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


i_val +=
day_name.length;


break;


}


}



}


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



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



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



i_val+=month.length;}


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



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



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



i_val+=date.length;}


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



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



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



i_val+=hh.length;}


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



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



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



i_val+=hh.length;}


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



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



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



i_val+=hh.length;}


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



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



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



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


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



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



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



i_val+=mm.length;}


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



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



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



i_val+=ss.length;}


else if (token=="a")
{


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


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



else {return 0;}


i_val+=2;}


else {


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


else {i_val+=token.length;}


}



}


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


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


// Is date valid for month?


if (month==2) {


// Check for leap year



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


if (date > 29){ return
0; }


}


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



}


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


if (date > 30) { return 0; }


}


// Correct hours value



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


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


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



return newdate.getTime();


}





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


// parseDate( date_string [,
prefer_euro_format] )


//


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


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



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


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


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


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


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


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


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


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


function parseDate(val) {



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


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


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


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


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


var d=null;



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


var l=window[checkList[i]];


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



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


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



}


}


return null;


}

Friday, May 22, 2009

Understanding Application Module Pooling Concepts and Configuration Parameters

Abstract

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

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

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

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

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

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

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

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

Setting Pool Configuration Parameters

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

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

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

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

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

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


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

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

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

java -Dproperty=value -jar yourserver.jar

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

TIP:

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

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


CAVEAT:

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

AM State Snapshots and the Internal Connection

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

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

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

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

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

How Many Pools are Created, and When?

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

Application Module Pools

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

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

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

The basic rule is:

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


NOTE:

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

Database Connection Pools

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

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

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

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

NOTE:

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

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

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

Applying These Rules of Thumb to a Scenario

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

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

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

Single OracleAS Instance, Single OC4J Container, Single JVM

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

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

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

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

NOTE:

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

Multiple OracleAS Instances, Single OC4J Container, Multiple JVMs

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

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

*

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

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

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

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

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

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

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

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

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

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

Application Module Pool Parameters

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

Pool Sizing Parameters

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

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

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

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

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

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

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

Pool Cleanup Parameters

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

TIP:

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

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

The length of time in milliseconds between pool resource cleanup.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

The length of time in milliseconds between pool resource cleanup.

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

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

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

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

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

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

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

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

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

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

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

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

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

Understanding How Database and Application Module Pools Cooperate

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

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

If jbo.doconnectionpooling=false, which is the default, then when an AM instance is created in any pool it acquires a JDBC connection from the appropriate connection pool (based on the JDBC URL in the ADF case, or from the underlying JDBC datasource implementation's pool in the case of a JNDI datasource name). That AM instance holds onto the JDBC connection object that it acquired from the pool until the AM instance is removed from the AM pool. During its lifetime, that AM instance may service many different users, and ADF worries about issuing rollbacks on the database connection so that different users don't end up getting pending database state confused. This provides the best performance in general because, by holding onto the JDBC connection, it allows each AM instance to keep its JDBC PreparedStatements's open and usable across subsequent accesses by clients.

If jbo.doconnectionpooling=true, then each time a user session finishes using an AM (typically at the end of each HTTP request), the AM instance disassociates itself with the JDBC connection it was using on that request and it returns it to the JDBC connection pool. The next time that AM instance is used by a user session, it will reacquire a JDBC connection from the JDBC connection pool and use it for the span of time that that AM is checked out of the AM pool (again, typically the span of one HTTP request). Since the AM instance "unplugs" itself from the JDBC connection object used to create the PreparedStatements it might have used during the servicing of the current HTTP request, those PreparedStatements are no longer usable on the next HTTP request because they are only valid in the context of the Connection object in which they were created. So, using the connection pooling mode turned "on" like this, the tradeoff is a slightly more JDBC setup/overhead each time in return for using a smaller number of overall database connections.
The key difference is seen when many AM pools are all using the same underlying database user for their application connection.

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

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

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

Wednesday, May 20, 2009

JDBC connection pooling ADF BC / Apache Tomcat

* Environment: Apache Tomcat 5.5.23
* ADF / BC 10.1.3.3

Issue:

A web-application *.war file is deployed twice into tomcat container. Every app has its own context-root and JDBC connections for the application modules set. Deployment is successful. But either if you run app1 or app2 as first application, the second application catches the JDBC connection of the the first application.

Solution:

Define the following property in $CATALINA_HOME/conf/catalina.properties

jbo.server.in_oc4j = true

This should cause ADF to partition the caches in Tomcat environment based on ContextClassLoader. Now every app uses its own specified connection and cache.

JDBC Connection Pools in web logic

Click here

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