Reverse Ajax with Spring and DWR


Ajax is used heavily for web 2.0 applications to provide enhance user experience, which allows a web page to be updated without the need of full refresh. Normally this updated information is pulled from client side.
Javascript call is used to make an Ajax call to the server and received information is updated.
But there are scenarios when server decides to update information on client side e.g. Chat applications, server side processing status, user presence etc.


In these situations server side "PUSH" is required instead of Client side "PULL". There are three techniques used for this purpose:
  • Polling (the browser sends requests at regular interval)
  • Comet (long lived HTTP connection connection is kept open and server keeps replying)
  • Piggyback (server waits for client to make request and sends update with that request data)
Configuration:
1. Enable Reverse Ajax in DWR configuration
There are two ways of going this:

You can enable in DWR.xml
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>

or if you are using DWR name spaces then you can provide entry in [Servlet Name]-servelt.xml
<dwr:controller id="dwrController" debug="true">
<dwr:config-param name="activeReverseAjaxEnabled" value="true" />
</dwr:controller>

2. Enable Reverse Ajax in JSP
dwr.engine.setActiveReverseAjax(true);

3. Now we need to get Browser sessions from server side and push content there:

WebContext wctx = WebContextFactory.get();
String currentPage = wctx.getCurrentPage();

Get current page from webContext

Collection sessions = wctx.getScriptSessionsByPage(currentPage);
Get all other clients session

After getting these sessions you can push data from here using proxy interface
Util utilAll = new Util(sessions);
utilAll.addOptions("chatlog", messages, "text");

Above lines will add messages collection to all the browsers under "chatlog" element

Similarly you can execute scripts on browsers from server side.

ScriptBuffer script = new ScriptBuffer();
script.appendScript("receiveMessages(")
.appendData(messages)
.appendScript(");");

Above snippet will execute receiveMessages() javascript function on client side.

This way you can have full control on client side from server side. Chat application, Stock Ticker control applications, mail client can use this feature effectively.

Logging using Log4j

Logging is an important of any application. There are several APIs available majorly used are:
1. Apache Log4J
2. Java Logging (java.util.logging)

Logging is required to monitor the state of the running application, debug the application, ignorant developers heavily relies on System.out.println(), which is quite expensive in terms of resources and you dont have any way to manage these messages.

To control this we have different API's like mentioned above.

Using Log4J from Apache:
Log4j consists of 3 aspects: logger, appender and, layout relations between three can be expressed as "logger logs to an appender using a layout"

Each class in an application can have seperate logger or a common logger, now this logger should know where to send request for logging. This where are known as appenders which can be:
- FileAppender (flat file)
- JDBCAppender (database )
- Console Appender (Console)
- SMTPAppender (Email)
- JMSAppender (to remote JMS servers)
- SocketAppender (to remote server).
there are few more.

Now we need to decide what and how we want the out out of that log, this is decided by layout

Each class can have a logger as mentioned above similarly each logger should have log level. There are five different log levels (ordered):
- DEBUG
- INFO
- WARN
- ERROR
- FATAL

To configure a class with a logger, appender, layout and log level we need to use an external configuration file (log4j.properties is the default)

Sample configuratiion file is as:
--------------------------------
# Set root logger level to DEBUG and its only appender to CONSOLE.
log4j.rootLogger=INFO, CONSOLE

# A1 is set to be a ConsoleAppender.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender

# A1 uses PatternLayout.
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n

# Change the level of messages for various packages.
log4j.logger.com.tj.cand.controller=WARN
log4j.logger.com.tj.cand.domain=WARN
log4j.logger.com.tj.cand.dao=DEBUG
--------------------------------

Usage:

Logger log = Logger.getLogger(MyController.class);
log.info("This is a logging message);




Why Spring Framework

Last year I had to shift my web application to some latest framework.
I decided to go for Spring Framework, EJB3 was also an option.

The reason why Spring was:

1. Spring was a well established Open Source
2. Spring provides all the configurations into XML where as EJB3.0 relies in annotations, in my scenario I am using WebSphere 6.1 which runs on JDK1.4 which doesn't support annotations.

3. Spring is a loosely coupled Framework You can decide your own stack. Whereas EJB is whole integrated package.

4. One major reason was You are not forced to use any Spring imports or rely on Spring classes. Dependency Injection combined with external meta-data helps to achieve this independence. So you can easily migrate. While in case of EJB 3.0 this is different.

5. One disadvantage of using annotations based EJB 3.0 is you need to change java source to incorporate any configurations whereas in case of spring you need to change XML file.

XML binding using JiBX

JiBX is a XML binding framework which binds XML to your java class.
XML binding is a 2 phase process:
1. JiBX uses binding definition to define the rule how conversion wil happen and modifies byte code of the class.
2. In phase 2 JiBX runtime does marshalling and un-marshalling of java objects to populate XML to java and java 2 XML.

Algorithm
  • Add following jar files to your lib directory from JiBX distribution
    1. bcel.jar (Byte Code Engineering Library used to change bytecode for the class)
    2. jibx-bind.jar (1,2 are used in phase I)
    3. jibx-run.jar
    4. jibx-extras.jar
    5. xpp3.jar (3,4,5 are used in phase II)
  • Modify java class using binding compiler (java -jar ../lib/jibx-bind.jar binding.xml)
  • Write code for marshalling and unmarshalling of java object

Example:



public void XML2Java2XML() {
try {
IBindingFactory bfact = BindingDirectory.getFactory(Customer.class);
IUnmarshallingContext uctx = bfact.createUnmarshallingContext();

Object obj = uctx.unmarshalDocument
(new FileInputStream("customer.xml"), null);
Customer customer = (Customer)obj;
System.out.print(customer.toString());

IMarshallingContext mctx = bfact.createMarshallingContext();
mctx.setIndent(4);
mctx.marshalDocument(obj, "UTF-8", null,
new FileOutputStream("customer2.xml"));

} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (JiBXException e) {
e.printStackTrace();
}
}

Password Strength Meter

Almost every web site provides password strength meter.
To make a strong password it should contain:
  • Sufficient length
  • Mixed case
  • Combination of numbers and Special characters

My password strength meter works on same line:

If password is of minimum length and same case it is a weak passwd

If password is min length mixed case and number normal passwd

if password is min length mixed case number and special char it is medium password

if password is above min length and combination of number and special char, it is strong passwd

Client Side Validation

Validation is a very important aspect of any web application.We can validate user input in client side as well as server side. Client side validation is important since we dont want to send data to server and thenlet user know about the errors. But we can not rely only on client side validation since if Javascript is disabled on client side it will lead to invalid data on server.
So mix approach should be followed: validating data on server as well as client side.


I am using Spring Framework and Spring MVC, I have few options available:


  1. AJAX based validation
  2. Spring VLANG Validation
  3. Apache commons validation (Struts Validator Framework)

I have dropped idea of AJAX based validation since it will require to more Remote calls
Spring VLANG Validation is a good option but dependency is JDK 1.5 and we are still running on JDK 1.4.

Finally decided to go for Commons validator this is well proven and stable one.
I have also read blog from Matt where he appreciated commons validator.
I have used custom validation along with commons standard validation.

Steps followed by me to get commons validator configured with Spring are as follows:
Dependency:
1. Spring-commons-validator (Spring modules 0.8)
2. Commons validator

Step 1: Downloaded dependency jar files
Step 2: Added validation.xml, validation-rules.xml, validation-custom-rules.xml (For custom validators)
Step 3: Added validation specific entries to applicationContext-validation.xml
step 4: Added validator property to form controller entry in [context-root]-servlet.xml

My Validation.xml is as follows:

Validation.xml

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1//EN" "http://jakarta.apache.org/commons/dtds/validator_1_1.dtd;
<form-validation>
<formset>
<form name="registerFormBean">
<field property="user.fname" depends="mask,maxlength">
<arg0 key="register.label.firstname"/>
<arg1 name="maxlength" key="${var:maxlength}" resource="false"/> <var><var-name>maxlength</var-name><var-value>5</var-value>
</var> <var> <var-name>mask</var-name> <var-value>^[a-zA-Z]*$</var-value> </var>
</field> <field property="user.email" depends="required,email">
<arg0 key="register.label.email"/>
</field> <
field property="user.password" depends="required,twofields">
<arg0 key="register.label.password" />
<arg1 key="register.label.verifypassword"/>
<var> <var-name>secondProperty</var-name>
<var-value>verifyPasswd</var-value>
</var> </field> <
field property="verifyPasswd" depends="required">
<arg0 key="register.label.verifypassword" />
</field>
<field property="user.location" depends="selectfield">
<arg0 key="register.label.location" />
<arg1 key="${var:maxsize}" name="selectfield" resource="false"/>
<var><var-name>maxsize</var-name><var-value>3</var-value></var>
</field>
</form>
</formset>
</form-validation>

Validation-rules-custom

My custom validation rules file is as follows:

<!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.3.0//EN" "http://jakarta.apache.org/commons/dtds/validator_1_3_0.dtd; <form-validation>
<global>


<validator name="twofields" classname="com.tj.cand.utils.ValidationUtil" method="validateTwoFields"

methodParams="java.lang.Object,

org.apache.commons.validator.ValidatorAction,

org.apache.commons.validator.Field,

org.springframework.validation.Errors"

depends="required" msg="errors.twofields">

<javascript><!

[CDATA[ function validateTwoFields(form) {

var bValid = true;

var focusField = null;

var i = 0;

var fields = new Array();

oTwoFields = new twofields();

for (x in oTwoFields) {

var field = form[oTwoFields[x][0]];

var secondField = form[oTwoFields[x][2]("secondProperty")];

if (field.type == 'text' field.type == 'textarea' field.type == 'select-one' field.type == 'radio' field.type == 'password') {

var value; var secondValue;

// get field's value

if (field.type == "select-one") { var si = field.selectedIndex; value = field.options[si].value; secondValue = secondField.options[si].value; } else { value = field.value; secondValue = secondField.value; } if (value != secondValue) { if (i == 0) { focusField = field; } fields[i++] = oTwoFields[x][1]; bValid = false; } } } if (fields.length > 0) { focusField.focus(); alert(fields.join('\n')); } return bValid; }]]> </javascript> </validator> <validator name="selectfield" classname="com.tj.cand.utils.ValidationUtil" method="validateSelectField" methodParams="java.lang.Object, org.apache.commons.validator.ValidatorAction, org.apache.commons.validator.Field, org.springframework.validation.Errors" depends="" msg="errors.multiselect"> <javascript><![CDATA[ function validateSelectField(form) { var bValid = true; var focusField = null; var i = 0; var fields = new Array(); oSelectFields = new selectfield(); for (x in oSelectFields) { var field = form[oSelectFields[x][0]]; if (field.type == 'select-multiple') { var iMax = parseInt(oSelectFields[x][2]("maxsize"));
if ((field.options.length == 0) (field.options.length > iMax)) { if (i == 0) { focusField = field; } fields[i++] = oSelectFields[x][1]; bValid = false; } } } if (fields.length > 0) { focusField.focus(); alert(fields.join('\n')); } return bValid; }]]> </javascript> </validator> </global>
</form-validation>

Installing DBD::MySql

I had spent last two days trying to install DBD::MySql version-4.005 for mySql 5.1-22.0 rc.

After a lot of permutation and combination finally able to get it done. I have seen a lot of discussion forums but not able to get the root cause of the problem finally I figured out that it was related with MySql Devel rpm and static linking of My sql Client Library.

This is a known issue with DBD::MySql. It fails if you try linking MySql Client library Dynamically.

The steps I followed after going through DBD::MySql documentation are as follows:

1. Install Mysql-Client rpm
2. Install MySql-Devel Library
3. Install MySql Shared Libraries

  • MySQL-client-community-5.1.22-0.rhel
  • MySQL-devel-5.1.22-0.glibc23
  • MySQL-shared-compat-5.1.22-0.rhel4
Installing DBD::MySql

1. tar xvzf DBD-mysql-.tar.gz
2. cd DBD-mysql-
3. cp /usr/lib/mysql/*.a /tmp/mysql-static (to link libmysql.client.a statically)
4. perl Makefile.PL --libs="-L/tmp/mysql-static -lmysqlclient" --testuser=user --testpassword=pass
5. make
6. make test
7. make install

All tests passed successfully.

Resources: