Wednesday, June 9, 2010

Integrating Subversion with Mantis

It is useful idea to install a web-based bug tracking system. Each member of development team, QA team or even each customer can report about bug, enhancement requirent or just feedback. The other side of the coin is maintance problems. For example customer named Donkey Shon reports about the bug. At this moment, you are few days before next release, so you resolve this bug after two weeks. Another two weeks later, Shon Donkey reports that the issue is still unresolved. At this point of time you already don't remember when you fix a bug, so you don't know what revision is it and if it was in new release or in the old one. Mr. Donkey is angry and he doesn't want your next release. The problem would not been happen if you've remember to label your SVN commit with bug id and to update status of the bug and its notes, but your team was too busy with new release of product.
Everyone who experienced this use-case, wants to synchronize bag tracking system with version control system and you can find some products that aims to do it. However, if you use Subversion and Mantis you can integrate it with 100 lines of script without learning manual and installation instructions of new product, that always met only part of your requirements . There is excellent explanation how to do it, at "alt-tag.com" ( see link at the end). Although the blog mentioned, is short and clear, it has two leaks. First, the scripts code wrote for Linux ( I love Linux, but there are still some Windows servers). Second, it assumes that developer, who commits the changes, always wrote comments in same pattern. The opinion, that developers are robots, is partly true, but they do mistakes, sometimes.
In this article, I'll give you the example of scripts that check commit label before the revision committed, blocks it if it has a error, change bug status after commitment and adds commit label to bug notes at Mantis. There are 6 steps: Mantis definitions, SVN comment template definitions, post-commit svn hook, pre-commit svn hook, post-commit mantis script and pre-commit mantis script.

1. Mantis definitions( config_inc.php ):
<?php
$g_hostname = 'localhost';
$g_db_type = 'mysql';
$g_database_name = 'bugtracker';
$g_db_username = 'root';
$g_db_password = 'rcadminsin';

#User that looks in svn for comments with bug_id
$g_source_control_account = 'svn';
#comments that identifies bug in subversion
$g_source_control_regexp = '/\b(?:bug|issue)\s*[#]{0,1}(\d+)\b/i';
#definition of svn commitements that change bug status in Mantis
$g_source_control_set_status_to = RESOLVED;
$g_source_control_set_resolution_to = FIXED;
$g_source_control_fixed_regexp = '/\bfix(?:ed|es)\s+(?:bug|issue)?\s*[#]{0,1}(\d+)\b/i';
?>

2. SVN comment template: Set property "tsvn:logtemplate" recursively for all files in your project. In this case the property value can be "fixed bug #&quot, so the developer need only add Mantis bug_id.

3. Post-commit SVN hook: Every SVN repository has "hooks" folder( e.g. C:\Subversion\repository\hooks ). An executable or batch file placed in this directory will be called if its name correlates with SVN event. At this stage it is "post-commit.bat". It calls for PHP script in purpose to update bug status at Mantis and to add revision comment as bug note.
@ECHO OFF

SET REPOS=%1
SET REV=%2

SET PHP=C:\AppServ\PHP5\php.exe
SET CHECKIN=C:\AppServ\www\mantisbt-1.2.1\scripts\checkin.php
SET SVNLOOK=C:\Subversion\bin\svnlook.exe

SET LOGFILE=log_post_%REV%.txt
SET AUTHORFILE=author_post_%REV%.txt
SET OUTPUTFILE=output_post_%REV%.txt

%SVNLOOK% log -r %REV% %REPOS% > %LOGFILE%
%SVNLOOK% author -r %REV% %REPOS% > %AUTHORFILE%

ECHO SVN %REPOS% Revision %REV% > %OUTPUTFILE%
TYPE %AUTHORFILE% >> %OUTPUTFILE%
TYPE %LOGFILE% >> %OUTPUTFILE%

TYPE %OUTPUTFILE% | %PHP% %CHECKIN%

CALL DEL %LOGFILE%
CALL DEL %AUTHORFILE%
CALL DEL %OUTPUTFILE%

4. Pre-commit SVN hook: This hook calls other PHP script ( "pre-commit.bat" ):
@ECHO OFF
SET REPOS=%1
SET TX=%2

SET PHP=C:\AppServ\PHP5\php.exe

SET VALIDATOR=C:\AppServ\www\mantisbt-1.2.1\scripts\validate_bug_fix.php
SET SVNLOOK=C:\Subversion\bin\svnlook.exe
SET LOGFILE=log_pre_%TX%.txt
SET OUTPUTFILE=output_pre_%TX%.txt
%SVNLOOK% log -t %TX% %REPOS% > %LOGFILE%
ECHO SVN %REPOS% Transaction %TX% > %OUTPUTFILE%
TYPE %LOGFILE% >> %OUTPUTFILE%
TYPE %OUTPUTFILE% | %PHP% %VALIDATOR% 1>&2
IF %ERRORLEVEL% gtr 0 ( GOTO ERR ) ELSE ( GOTO RM_LOG )
:RM_LOG
CALL DEL %LOGFILE%
CALL DEL %OUTPUTFILE%

exit 0

:ERR
ECHO commit denied >&2
exit 1
The script above prevents from developers to commit revision, that aims to fix already fixed issue. If pre-commit hook has exit code other then zero, SVN will not commit the changes and will display content of STDERR. ">&2" purpose is to copy STDOUT content to STDERR, so developer can see what error prevents his commitment. Most of work are done by PHP script called (see 5 and 6).
5. Post-commit PHP script: This script is already included in Mantis distrubution. It checks if text in STDIN stream is matches the template. If true, its find bug_id changes its status in mantis and add comment as note of the issue. If you need additional functionality you can change it or override default "custom_function_checkin" fuction.

6. Pre-commit PHP script: This script is not part of Mantis, but you can easy create it, because most of it, similar to checkin.php script, included in Mantis( see 5 ). You can use Mantise's "bug_api.php" methods to add other validations.
<?php
# Detect references to issues + concat all lines to have the comment log.
# Called before SVN commits changes to ensure that bug committed is not already resolved

global $g_bypass_headers;
$g_bypass_headers = 1;
require_once( dirname( dirname( __FILE__ ) ) . DIRECTORY_SEPARATOR . 'core.php' );

$t_commit_regexp = config_get( 'source_control_regexp' );
$t_commit_fixed_regexp = config_get( 'source_control_fixed_regexp' );

# Check that the username is set and exists
$t_username = config_get( 'source_control_account' );
if( is_blank( $t_username ) || ( user_get_id_by_name( $t_username ) === false ) ) {
echo "Invalid source control account ('$t_username').\n";
exit( 1 );
}

if( !defined( "STDIN" ) ) {
define( "STDIN", fopen( 'php://stdin', 'r' ) );
}

$t_comment = '';
$t_issues = array();
$t_fixed_issues = array();
while(( $t_line = fgets( STDIN, 1024 ) ) ) {
$t_comment .= $t_line;
if( preg_match_all( $t_commit_regexp, $t_line, $t_matches ) ) {
$t_count = count( $t_matches[0] );
for( $i = 0;$i < $t_count;++$i ) {
$t_issues[] = $t_matches[1][$i];
}
}

if( preg_match_all( $t_commit_fixed_regexp, $t_line, $t_matches ) ) {
$t_count = count( $t_matches[0] );
for( $i = 0;$i < $t_count;++$i ) {
$t_fixed_issues[] = $t_matches[1][$i];
}
}
}

# If no issues found, then no work to do.
if(( count( $t_issues ) == 0 ) && ( count( $t_fixed_issues ) == 0 ) ) {
exit( 0 );
}

# If one of the issues are already resolved it is a error to commit it.
foreach( $t_fixed_issues as $t_issue_id ) {
if( bug_is_resolved( $t_issue_id ) ) {
echo "The bug with id ".$t_issue_id." is already resolved.\n";
exit( 1 );
}
}

#echo "Comment ".$t_comment." OK.\n";
exit( 0 );
?>

That's all. You can add additional functionality to php scripts described, if you need. Link to the article, that used as base:

Monday, June 7, 2010

Tomcat Https and Eclipse

One of requirements in our project is requirement for HTTPS login form. However, bosses don't want to use HTTPS in every page, so I need to do three things: create SSL key, define HTTPS in tomcat and create such definitions in Spring Security XML, that redirects anonymious requests to login form and after that to home page.
Key definition is a step that you need only at development stage. Key is part of certificate that your server needs to send in response to any HTTPS request. The certificate defined by any of free tools you can download, is not trusted by browsers and you will see certificate warning, but you can ignore it, until production stage, where you should buy a real certificate from one of organizations that sell it.
Since we use Apache Tomcat 6, I've decided to use Java keytool to create the key. This utility is supplied with JRE and you don't need to download openSSL engine. After typing
%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA
in command line I've answered several questions and approved the data typed. Last question, about Tomcat Password, is important for next step. In the end of the process, a file named '.keystore' will be created in your user folder.
Default tomcat implementation that you have in eclipse don't support's version 2.2 of EL-expressions, that we use, and I don't want to change definitions when a project will be moved from development environment to production. So I didn't use default eclipse implementation of tomcat, but down loaded fresh Tomcat 6.0.26 from Apache website. It can be used both from eclipse and as standalone webserver, but eclipse overrides Tomcat configuration files with its own each time it noticed the change. Adding Tomcat to eclipse is simple: open Servers view, right click on it and choose 'New -> Server -> Tomcat v6.0 server'. You'll see Server runtime environment row and 'Add' link in the end of it. Click 'Add' and browse to your tomcat installation folder before you click 'Next' in 'New Server' dialog.
Now, you have eclipse project named 'Server' in any eclipse view, that shows list of projects in workspace. Open 'server.xml' file in this project and comment the element below:
<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
The reason of this operation is, that tomcat supports three types of certificates JKS, PKCS11 and PKCS12 and you don't know what certificate will be bought in future. As you can guess from its name, JKS is supported by JAVA and for other types you need openSSL or other external SSL engine. Since I don't use openSSL, I've commented the listener defintion, but didn't remove it, because I don't know what certificate will be used at production stage.
At this moment, I need to define how tomcat will deal with HTTPS connections and what certificate it will use. There is a commented connector element in 'server.xml' that defines SSL for port 8443. You can remove comments and use it as basis, but you should add attributes that define location of key file and its password. In my case It was:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
keystoreFile="${user.home}\.keystore" keystorePass="igor"
clientAuth="false" sslProtocol="TLS" />
The value of keystorePass attribute should be the same value that was entered as 'tomcat password', during key definition.
This is the end of Tomcat definitions. Right-click your server in 'Servers view' and choose 'Clean' command. This, force Eclipse to refresh Tomcat definitions and web applications, including coping updated 'server.xml' into Tomcat folder. Sometimes Eclipse has a bad day and doesn't want to notice that 'server.xml' was changed. In this case you can remove Eclipse's internal copy of it manually. You should remove workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/conf/server.xml
for it. If it also doesn't helps, kill eclipse and go home.
The remaining part is Spring Security configuration. I'll give our example of http element of configuration file:
<http auto-config="false" access-denied-page="/accessDenied.jsf">
<intercept-url pattern="/enter.jsf" requires-channel="https"/>
<intercept-url pattern="/j_spring_security_check"
requires-channel="https"/>
<intercept-url pattern="/**" requires-channel="http"/>
<form-login login-processing-url="/j_spring_security_check"
login-page="/enter.jsf" default-target-url="/home.jsf"
authentication-failure-url="/enter.jsf" />
<session-management session-fixation-protection="none" />
</http>
The configuration above defines 'enter.jsf' as login form and interceptor-url defines that it should use HTTPS. Last 'intercept-url' element defines that all other URLs use HTTP. The 'intercept-url' element in middle, is less obvious. 'j_spring_security_check' is request URL for all Spring Security credentials validations, so it also should use HTTPS.
This configuration only defines the protocol used for each page, but doesn't defines role's access. Roles ans grants are managed by special filter, that also redirects all not authorized request to login form.
More detailed information about HTTPS definitions of Tomcat and Spring Security can be read at these locations:
Tomcat Site:
Spring Security reference, section 2.3.2:

Wednesday, May 26, 2010

Extentending richFaces component with CDK

Lately, we needed new user interface components, as it common in a new
project. Since we use JSF and richFaces, it was natural to use richFaces
CDK. It is promoted, as a technology that allows to create JSF
components in an easy and simple way and most richFaces components were
created with it. I've read the tutorials and started to develop calendar
component. The development was not so simple as in the tutorial example,
but in comparison with the work that I would have done in order to
develop a JSF component from scratch, it is worthwhile. However, the
fact that all tutorials of CDK give one simple example of InputDate
component and there are no articles about the internal structure of
components, there were sone issues that drove me crazy and created a
high network load to richFaces forum in JBoss community. The reason of
most of my issues was that I created components that were similar to the
existing richFaces components, but added some functionalities, without
understanding how these components work.

The way to create component:

Full component creation proccess using richFiaces CDK is described in their tutorial.
Please readhttp://docs.jboss.org/richfaces/latest_3_3_X/en/cdkguide/html_single
before you start. I will just sum-up the tutorial.


1. Maven2: richFaces CDK is in fact a Maven2 plugin and your project should be defined as a Maven project with Maven-cdk-plugin from the beginning. Create Maven project in your IDE, manually or using the archetype mentioned in tutorial. If you use eclipse you need to install m2eclipse plugin. I've experienced a strange issue with it. In the last step before installation I was asked to agree with the licence. However, approving reading the rules, didn't enable the finish button and I couldn't continue installation. When I tried to download it in second time, I installed plugin without problems. Other members of my team that has tried to install the plugin had experienced the same problem.
2. Create or edit an XML file that defines the component: name of the component, name of Java class for component, name of Java class that renders it, tag name in generated tag library, name of JSP like template and component attributes definitions.
3. Create or edit a component class that presents the component in JSF component tree. It should contain setters and getters methods for each of the component attributes and should inheret or override methods to deal with events . Your class should be abstract to allow CDK to do most of the job by creating real component class. For example, if the setter and the getter just set and get values you can define it abstract and CDK will generate the code for it.
4. Create renderer base class. This class is also abstract and it should include encode/decode methods that link between component at client side and its representation in server-side JSF component tree. For example, most components have this piece of code in their doDecode() method:

ExternalContext external = context.getExternalContext();
Map requestParams = external.getRequestParameterMap();
UIMyComponent component = (UIMyComponent)component;
String clientId = component.getClientId( context );
String submittedValue = (String)requestParams.get( clientId );
if ( submittedValue != null ) {
component.setSubmittedValue( submittedValue );
}
This method is called every time the request submitted by user or by AJAX. The code above takes the value submitted and saves it in component class instance. A doEncode() method should create client side HTML for component, but most of its code is generated by CDK from JSP like jspx file. Other methods that are described in JSF manuals can be created, if you need it.
5. JSPX template. This file aims to be an ultimative advantage of CDK. Instead of implementing encode() method, that adds all client code to StringBuffer line-to-line as in old servlets, you just write JSP like file, that defines how component should look in client side and CDK will do the rest. Component attributes and methods defined in renderer base class can be used. For example, I need to display organizer in my component. I can create getWeekDays() ethod in my renderer class and call it in jspx template to render list of days of the week.

6. Run CDK plugin and enjoy debugging. At this point you can generate the first version of your component with Maven2 and start to debug it. You just include generated jar file into some web project, add taglib to any jsp and use component with the name that you've defined in XML definition, in step 1.


Here are the problems that I confronted in a chronological order:
1. Nested loops: The things look fine, in theory. It is not the first time that I use maven, so I came to step 5 quickly. Ooops, Maven reports that generated class has compiler errors. Ok, I'll go to forum. Another oops, there is a forum for developers that use richFaces components, but there is no forum for those that want to create its own components. The post in richFaces forums has no answer for two days and I start to dig into the problem by myself and find something. I use nested forEach tags in jspx to create table with named rows and columns. CDK converts forEach into java for loops, but use same variable name for both loops. The result is compilation error that I've seen. At this moment I finaly get an answer from forum, that nested loops are not supported by CDK, but such support will be added in next version. Thanks, it is very helpful.
I must indicate that in other cases, when I've added JSF and CDK tags to post and defined it as a question, I've been quickly answered by Nick or Ilya, th members of CDK development team, and I appreciate the help I've received.
Link to forum: http://community.jboss.org/en/richfaces?view=discussions&start=0
Finally my problem was solved by using two different tags for nested loops c:forEach and i:repeat tags. Don't try to use version ofc:forEach with 'begin', 'end' and 'step' attributes if you want to put variables in it. As I'll write below, it will not work. Add another method to renderer and use version of c:forEach, that iterates list returned from it.

You can't do this:

<c:forEach var="trName"
items="#{this:getHoursList( component)}">
#{trName}
<c:set var="hourIndex" value="0"/>
<c:forEach var="item"
items="#{this:getItem(
component, dayIndex, hourIndex )}>
#{item}
<c:set var="hourIndex" value="${hourIndex+1}"/>
</c:forEach>
<c:set var="dayIndex" value="${dayIndex+1}"/>
c:forEach>

You can't do this:
<c:set var="dayIndex" value="0"/>
<c:set var="rows" value="#{this:getHoursC0unt()}"/>
<c:forEach var="trName"
items="#{this:getHoursList( component )}">
#{trName}
<c:forEach var="hourIndex" begin="0" end="rows">
#{this:getItem(component,dayIndex, hourIndex )}
</c:forEach>
<c:set var="dayIndex" value="${dayIndex+1}"/>
<c:forEach>

But you can do this:
<c:forEach var="trName"
items="#{this:getHoursList(component)}">
#{trName}
<ui:repeat var="item"
value="#{this:getNextRow( component )}">
#{item}
</ui:repeat>
</c:forEach>

2. JSPX is not JSP: I tried to escape the
nested loops problem by using different tags for different loops I
confronted another problem that is not only CDK developers' problem, but
everyone that develops with it should be aware of it. You can use some
tags that you used to write in JSP pages or facelets, but not all of
them. JSPX template is not JSP page and not facelet, if you use one of
the tags that are not defined in 'Chapter 10' of richFaces CDK
reference, you will not see any error, and it will be rendered as a
simple test. For example if you use common <h:outputtext
value="foo"/> in template the component, client side will not render
just "foo", but the whole <h:outputtext value="foo"/> token.

3. Next problem - Types Conversion: I used c:set
tag in the template and I had a problem with it. When CDK converts
template to doEncodeEnd() method, the object that is declared with this
tag is stored in variables map as Object and you'll get
compilation error if you try to use it as type different from Object or
String in your java scriplet. You can write ${hourIndex+1} for
such variables and it will work, but you'll have the problem with <c:forEach
var="item" start="0" end="#{hoursCount}">.

This code work only if second parameter of getRowForTime() method has java.lang.Object type:
<c:set var="hourIndex" value="0"/>
<c:forEach var="trName"
items="#{this:getHoursList( component )}">
#{trName}
<ui:repeat var="item"
value="#{this:getRowForTime( component, hourIndex )}">
#{item}
</ui:repeat>
<c:set var="hourIndex" value="${hourIndex+1}"/>
</c:forEach>
There is c:object tag, but you can't use it twice for
the same variable. Using c:setvar another time, redefines
variable, using c:object another type declares variable second
time in generated code and you have a compilation error.

Good news: If you know about variables map you
can use it in java scriplets to refer expressions defined in template
tags.

This code will not work:
<c:object var="hourIndex" value="0" type="java.lang.Integer"/>
<c:forEach var="trName"
items="#{this:getHoursList( component )}">
<c:object var="hourIndex" type="java.lang.Integer"
value="#{hourIndex+1}"/>
#{trName}
<ui:repeat var="item"
value="#{this:getRowForTime(
component, hourIndex )}">
#{item}
</ui:repeat>
</c:forEach>

This code works:
<c:set var="hourIndex" value="1"/>
<c:forEach var="trName" items="#{this:getHoursList( component )}">
<c:set var="hourIndex" value="${hourIndex+1}"/>
<c:object var="hourIndex" type="java.lang.Object"
value="#{hourIndex}"/>
#{trName}
<ui:repeat var="item"
value="#{this:getRowForTime( component, hourIndex )}">
#{item}
</ui:repeat>
</c:forEach>

4. User defined set or get : If you define get method
for any component's attribute, next code should be added at the
beginning:
//Try to read model as EL-expression
ValueExpression ve = getValueExpression( "attrName" );
if( ve != null ) {
try {
_attr = (AttrType) ve.getValue (getFacesContext().getELContext() );
} catch( ELException e ) {
....
}
}
This code retrieves the value of the attribute at the client
side. The problem is not obvious, because in most cases the setters and
getters are abstract and CDK adds this code in the generated code. In my
case, it created a mysterious issue. I had a dataModel attribute in some
component, that should be received only once from a backing bean or an
empty model will be created if no model was received. When I started to
debug component the model was always empty. Debugging showed, that a
setter method was called for each of the component attributes, except
for the dataModel, while the component was created. The problem
disappeared after I had added the above code in the getter. I think that
getDataModel() was called somewhere by the genereated code and created a
new empty model. After that, when setter methods were called, the model
was not null and values from backing bean were not set, because I've
defined that model will be set only once.

5. RichFaces uses Prototype: It is not shown in CDK
tutorial, but all richfaces components have client-side javascript
prototype classes, and you have to extend both server side code and
JS-Prototype, if you want to extend existing component. See richFaces
source codehttp://anonsvn.jboss.org/repos/richfaces/branches/community/3.3.X/
for examples. You can do it in the way below( in my case I am extending
richCalendar, with new control, creating macro variable for the control
to enable its use in any part of component and define this control as
displayed by default in the header) :
//creates richfaces utility class if it doesn't exists yet.
if (!window.Richfaces) window.Richfaces={};
//Defines calendarTypeControl and overrides default header
//to add it.
Object.extend( CalendarView, {
calendarTypeControl: function( context ) {
if( !context.calendar.params.showTypeButton ) {
return "";
}
var text = context.calendar.params.labels[
context.calendar.TYPE_NAMES[ context.calendar.calendarType ] ];
var onclic =
"Richfaces.getComponent('calendar',this).switchToNextType();" +
"return true;"
var markup = new E(
'div',
{'class': 'rich-calendar-tool-btn',
'onclick': onclick,
'id': context.calendar.id + 'TypeText' },
[ new ET(text) ]
);
return markup;
},
header: [ new E( 'table', {'border': '0', 'cellpadding': '0',
'cellspacing': '0', 'width': '100%'},
[ new E('tbody',{},
[ new E('tr',{}, [
new E('td',{'class': 'rich-calendar-tool'},
[ new ET(function (context) { return Richfaces.evalMacro( "previousYearControl",
context ) } )
]),
new E('td',{'class': 'rich-calendar-tool'},
[ new ET(function (context) {
return Richfaces.evalMacro( "previousMonthControl",
context)})
]),
new E('td',{'class': 'rich-calendar-month'},
[ new ET(function (context) {
return Richfaces.evalMacro( "currentMonthControl",
context)})
]),
new E('td',{'class': 'rich-calendar-tool'},
[ new ET(function (context) { return Richfaces.evalMacro(
"nextMonthControl",
context)})
]),
new E('td',{'class': 'rich-calendar-tool'},
[ new ET(function (context) {
return Richfaces.evalMacro(
"nextYearControl",
context)})
]),
new E('td',{'class': 'rich-calendar-tool'},
[ new ET(function (context) {
return Richfaces.evalMacro( "calendarTypeControl",
context)})
]),
new E( 'td', {'class': 'rich-calendar-tool rich-calendar-tool-close',
'style':function(context){
return ( this.isEmpty ?
'display:none;' : '' ); } },
[ new ET(function (context) {
return Richfaces.evalMacro(
"closeControl",
context)})
])
])
])
]
)]
} );
//Defines macro variable for calendar type control
Object.extend( CalendarContext.prototype, {
calendarTypeControl: CalendarView.calendarTypeControl
} );
//Redefines default values for calendar to replace header markup with
//new one that includes calendarType control
Richfaces.Calendar.defaultOptions = {
showWeekDaysBar: true,
showWeeksBar: true,
datePattern: "MMM d, yyyy",
horizontalOffset: 0,
verticalOffset: 0,
dayListMarkup: CalendarView.dayList,
weekNumberMarkup: CalendarView.weekNumber,
weekDayMarkup: CalendarView.weekDay,
headerMarkup: CalendarView.header,
footerMarkup: CalendarView.footer,
isDayEnabled: function (context) {return true;},
dayStyleClass: function (context) {return "";},
showHeader: true,
showFooter: true,
direction: "bottom-right",
jointPoint: "bottom-left",
popup: true,
boundaryDatesMode: "inactive",
todayControlMode: "select",
style: "",
className: "",
disabled: false,
readonly: false,
enableManualInput: false,
showInput: true,
resetTimeOnDateSelect: false,
style: "z-index: 3;",
showApplyButton: false,
selectedDate: null,
currentDate: null,
defaultTime: {hours:12,minutes:0}
};

In template( the code behind ... similar to rich:calendar template ):
...
<f:clientid var="clientId">
<h:scripts>
new org.ajax4jsf.javascript.PrototypeScript(),
new org.ajax4jsf.javascript.AjaxScript(),
/org/richfaces/renderkit/html/scripts/events.js,
/org/richfaces/renderkit/html/scripts/utils.js,
/org/richfaces/renderkit/html/scripts/json/json-dom.js,
/org/richfaces/renderkit/html/scripts/scriptaculous/effects.js,
/org/richfaces/renderkit/html/scripts/jquery/jquery.js,
/org/richfaces/renderkit/html/scripts/JQuerySpinBtn.js,
/org/richfaces/renderkit/html/scripts/calendar.js,
/com/sintecmedia/components/renderkit/html/scripts/sintecCalendar.js
</h:scripts>
...
<c:scriptobject var="options"
base="#{this:getSymbolsMap(context, component)}">
<c:scriptoptionattributes="enableManualInput,disabled,readonly,resetTimeOnDateSelect, showApplyButton, styleClass, minDaysInFirstWeek" />
...
<c:scriptoption name="calendarType"
value="#{this:getCalendarType(component)}"/>
<c:scriptoption name="showTypeButton" value="#{this:isShowTypeButton(component)}" />
<c:scriptoption name="typeNames" value="#{this:getTypeNames(component)}"/>
<c:scriptoption name="firstMonth" value="#{this:getFirstMonth(component)}"/>
...
<script type="text/javascript">
<f:call name="writeDefaultSymbols"/>
new SintecCalendar('#{clientId}',
"#{component.asLocale}",
<c:if test="#{not empty options}">
<f:writeasscript value="#{options}"
</c:if>
<c:if test="#{empty options}">
{}
</c:if>,
<f:call name="writeFacetMarkup"/>
).load(
<jsp:scriptlet>/*<![CDATA[*/
writePreloadBody(context, component);
/*]]>*/</jsp:scriptlet>
);
</script>
...

The code above allows to use calendarTypeControl in newCalendar component in two ways: <my:newcalendar/> will display default header with calendarType control and
<pre name="code" class="Cpp" name="code" class="Cpp">
<my:newcalendar>
<f:facet name="someFacet">
<h:outputtext value="{calendarTypeControl}">
</f:facet>
</my:newcalendar>
</pre>
will display the control in the facet specified.

6. If you want action, you should work hard: richFaces is library
of AJAX components, but richFaces CDK doesn't supports (as of version
3.3.3) AJAX automatically, as it seems. You have JAVA and JS API that do
this work, but you can't just write in a template things like <ajax:request
params="a,b,c" values="1,2,3">. The things are even more complicated. You should create JS event for ajax call and attach it to JS proptotype of component. After that, you should create event observer in doDecode() and getSubmitFunction() and getOnClick() methods in renderer. Finally you should add JS code to create event observer and getOnClick() call where it should be fired. Here is example code that allows to select day of the week:

In renderer:
...
protected void doDecode( FacesContext context, UIComponent component ) {
Map paramMap = getParamMap( context );
String clientId = component.getClientId( context );
//If param is null, then there was no day selected in this
//request and no event should be queued.
String param = (String) paramMap.get( clientId );
if( param == null ) {
return;
}
UIWeekDaysButtons dayButtons = (UIWeekDaysButtons) component;
DaySelectedEvent event =
new DaySelectedEvent( dayButtons, Integer.valueOf( param ) );
event.queue();
}
private Map getParamMap( FacesContext context ) {
return context.getExternalContext().getRequestParameterMap();
}
/**
* @return JS expression what fires day selected event
*/
public String getOnClick(
FacesContext context, UIComponent component, Integer dayIndex ) {
return
"Event.fire(this, 'rich:weekdaysbuttons:ondayselect', {'dayIndex': '"+
dayIndex + "'});changeSelection(this);";
}
/**
* @param context
* @param component
* @return code of Javascript function that submits event through
AJAX request
*/
public String getSubmitFunction(
FacesContext context, UIComponent component ) {
JSFunctionDefinition definition = new JSFunctionDefinition("event");
JSFunction function =
AjaxRendererUtils.buildAjaxFunction( component, context );
Map eventOptions =
AjaxRendererUtils.buildEventOptions( context, component, true );
Map parameters = (Map) eventOptions.get( "parameters" );
Map params = getParameters( context,component );
if(!params.isEmpty()){
parameters.putAll(params);
}
parameters.put(
component.getClientId(context),
new JSLiteral("event.memo.dayIndex") );
function.addParameter(eventOptions);
StringBuffer buffer = new StringBuffer();
function.appendScript(buffer);
buffer.append("; return false;");
definition.addToBody(buffer.toString());
return definition.toScript();
}
//get UIParameter's Map
protected Map getParameters(
FacesContext context, UIComponent component ) {
Map parameters = new HashMap();
if( component instanceof UIWeekDaysButtons ){
UIWeekDaysButtons weekDaysButtons =
(UIWeekDaysButtons)component;
List children = weekDaysButtons.getChildren();
for (Iterator iterator = children.iterator(); iterator.hasNext(); ) {
UIComponent child = (UIComponent) iterator.next();
if(child instanceof UIParameter) {
UIParameter param = (UIParameter)child;
String name = param.getName();
if (name != null) {
parameters.put(name, param.getValue());
}
}
}
}
return parameters;
}
...

In template:
...
<h:scripts>
new org.ajax4jsf.javascript.PrototypeScript(),
new org.ajax4jsf.javascript.AjaxScript(),
/renderkit/html/scripts/weekDaysButtons.js
</h:scripts>
...
<c:forEach var="day" items="#{this:getDaysOfWeek( component )}">
<c:object var="dayName" type="java.lang.Object" value="#{day}"/>
<c:object var="dayIndex" type="java.lang.Integer"
value="#{this:getIndexByDay( component, day )}"/>
<td x:passThruWithExclusions="id,name,type,value,onclick,class"
onclick="#{this:getOnClick( context, component, dayIndex )}"
class="unselected">
#{day}
</td>
<c:forEach/>
...
<script type="text/javascript">
new Richfaces.DaySelector(
'#{clientId}',
#{this:getSubmitFunction(context,component)});
</script>
...

In JS file:
...
if (!window.Richfaces) {
window.Richfaces = {};
}
function changeSelection( element ) {
var selectedDayStyle = /\bselected\b/i;
var unselectedDayStyle = /\bunselected\b/i;
if( element.className.match( selectedDayStyle ) ) {
element.className = element.className.replace(
selectedDayStyle, "unselected" );
} else if( element.className.match( unselectedDayStyle ) ) {
element.className = element.className.replace(
unselectedDayStyle, "selected" );
}
}
Richfaces.DaySelectedEvent = "rich:weekdaysbuttons:ondayselect";
Richfaces.DaySelector = Class.create({
initialize: function(clientId, submitFunction) {
this.element = $(clientId);
this.element.component = this;
this["rich:destructor"] = "destroy";
Event.observe(
this.element,
Richfaces.DaySelectedEvent,
submitFunction );
}
});
...

7. Listeners: another undocumented design pattern. Among rich:calendar
attributes you can see 'dateSelected' and some other attributes that contains
EL-expressions for methods fired, when event occurs. If you want to add listener
attribute to component, simple add of attribute to XML will not work, you need to
define listener element also. Below, I show my version of such attribute:

Component's XML(I don't use facelets so I change taghandler element
to comment):
</component>
...
<property>
<name>daySelectedListener</name>
<classname>javax.el.MethodExpression</classname>
<description>MethodBinding representing an action listener method that will be
notified after day clicked </description>
</property>
</component>

<listener>
<name>daySelectedListener</name>
<listenerclass>com.sintecmedia.components.event.DaySelectedListener</listenerclass>
<componentclass>com.sintecmedia.components.component.UIWeekDaysButtons</componentclass>
<eventclass>com.sintecmedia.components.event.DaySelectedEvent</eventclass>
<!-- taghandler generate="true">
<classname>com.sintecmedia.components.taglib.DaySelectedListenerTagHandler</classname>
</taghandler-->
</listener>

Component's class( broadcast() method ):
if( event instanceof DaySelectedEvent ) {
...

//Invoke listener
MethodExpression methodExpression = getDaySelectedListener();
if( methodExpression != null ) {
FacesContext facesContext = getFacesContext();
methodExpression.invoke(
facesContext.getELContext(), new Object[] { event } );
}
}
8. Default attributes: According to CDK reference the developer can
define common HTML attributes with several predefined entities, as
'html_control_events' or 'ajax_component_attributes'. I've assumed that if I
use it, CDK does rest of the job and adds it to component's encode by himself.
It was mistake. If you want that one of this attributes to be rendered in
browser you shoul add to component's template something like this:
onclick="#{component.attributes['onclick']}"

After I've passed these issues, three components that I've
developed started to work. Two last issues forced me to spend the most
time on it. The things are simple, but not documented, so it requires to
study large amounts of richFaces source code, trying to guess what piece
is related to your issue and asking many questions in forum. I assume
that this article describes common isuues and will be useful to people
that begin to use richFaces CDK. I'm not a CDK guru, so I will be glad
to see any suggestings for better solutions of these issues.

The links you need to develop components:
CDK docs:http://docs.jboss.org/richfaces/latest_3_3_X/en/cdkguide/html_single/
richFaces forum:http://community.jboss.org/en/richfaces?view=discussions&start=0
source code:http://anonsvn.jboss.org/repos/richfaces/branches/community/3.3.X/
Book or reference to JSF.

Tuesday, May 25, 2010

LazyInitializationException exceptions in JSF beans

LazyInitializationException exceptions in JSF beans

In our web project we were using a mysql DB. Like in most cases our tables were connected between them: user to company, role to user etc. Foreign keys were created, and the beans were connected to (with suitable annotations:@ManyToOne, @ManyToMany()). After defining all this, we expected that when getting an object of company, let’s say, it will contain all its users, and for every user we could get its roles, and for every role its name etc…

But it wasn’t like this. After getting the company object, while trying to get it’s users:

Set <users>=company.getUsers();

The set was null.

What was happening?

Lazy

To improve the performace, our beans were defined with a lazy annotation above the property getter: @OneToMany(fetch = FetchType.LAZY…), that meant when getting to parent object, in our case the object Company, it saved a reference to the child objects: users. While the session is still open, Hibernate knows where to go and get the data. The story was that after the session was closed, the reference still exited but it did not know to where to indicate.

The solution was to define transactions. Control on opening and closing the sessions, and get all the needed data before the transaction closes, before all the references lose their target!

Transactions

Spring have special annotations, for defining such things. The definition is written above every function: @Transactional. This annotation has a few properties, among them: a boolean property readOnly: true- if this transaction is only for reading data from the DB, or false that means that this transaction is coming to insert or update data too. The main property is propagation. It defines what session to use for this method. Its value is the Propagation enum. Its main values that we used are REQUIRES_NEW, REQUIRED.

REQUIRED means that if there is an open transaction it will join it. If not, it will open a new one.

REQUIRES_NEW means that in any case it will open a new transaction.

The annotation should be written above the method:

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)

This Spring annotations can be recognized only in a class that the spring knows, that were defined in the applicationContext.xml . The definition could be like this:

<bean id="viewDAO" class="com.XXX.infra.daoimpl.GeneralDAOImpl>

</bean>

Using services

As we said, transaction will have an affect only in the spring class. And a class could not be a spring class and a JSF class too. Special classes need to be defined for the hibernate issues.

An interface should be defined with the needed functions. The class defined above should implement it.

In the JSF class you should define an instance of that interface.

private ManageUserService manageUserService= FacesContextUtils.getWebApplicationContext(

FacesContext.getCurrentInstance() ).getBean( name );

The name that’s sent as an argument is the id that defined the implementation in the applicationContext.

The next step is to call the implementation methods from the JSF classes. When first rendering the page, all the data needed from the DB should be taken out all in one transaction. You need to manage the transactions in the Spring class. The main method, the one you call from the your been, should bepropagation = Propagation.REQUIRES_NEW. Any child methods, if there are, should use the same transaction. Its annotation should look propagation = Propagation.REQUIRED, this makes sure that the data will be taken properly before the reference loses its target.

As well, when submitting the page, or every new connection to the DB, should be defined with a new transaction, and that method should end only after you finished doing all what you needed.

If a lot of data needed from that transaction, and methods, we know, return one item only, you could define a class that has the needed properties, and fill it with data in the service.