Friday, September 18, 2009

Implementing Direct Web Remoting ( DWR) in Spring Framework

Introduction

Direct web remoting or DWR is like 'AJAX made simple for JAVA'. It is a Java library that helps JavaScript in a browser to interact with Java code on the server.

AJAX VS DWR


In most of the cases, AJAX works in 'pull' mode; pulling data from server by calling server side resource(s), such as jsp, php, servlet, etc... from some browser script/JavaScript code.

In Ajax world, you basically call server resource(s) asynchronously using magical object called 'XMLHTTPRequest' and also define callback method to handle data/message returned from server.

In case of DWR; It can work in both the modes, push as well as pull.

In pull mode DWR library makes java class available to the JavaScript code in the browser. So you can directly call methods on Java class from JavaScript code. Also you may need to define callback method and pass it as parameter to the method of the Java class.

The DWR's push mode is called 'reverse ajax', which pushes data to the browser from the server. There are three methods to implement reverse ajax: Polling, Comet, and Piggyback. Here is a quick definition: (Get more info here : http://directwebremoting.org/dwr/reverse-ajax/index.html)

Polling:

Browser makes call to the server in frequent and regular intervals.

Comet:

This is also called long lived http, server push. In this case http session is open for longer time dictated and scheduled by the server.

Piggyback:

Server keeps update ready and waits for browser for the next http request. Once it receives, it appends its update/message along with response to the current http request.

DWR in Spring


So far what I have discussed above is high level overview and how things works in a nutshell. Let's dive deep and see how DWR can be put to work in Spring MVC. Here is step by step process:

Step 1

First step would to download latest dwr.jar from DWR web site and reference it in your Spring web project
Next a java class/pojo needs to be defined, which would server as class instance to be called from javascript, like this:-


public class AcsDWRUtil {

private volatile SubCategoryDAO subcategoryDAO;

public SubCategoryDAO getSubcategoryDAO() {

return subcategoryDAO;

}

public void setSubcategoryDAO(SubCategoryDAO subcategoryDAO) {

this.subcategoryDAO = subcategoryDAO;

}

public String[] getBusinessSubCategories(int catId) {

List subCatList = this.subcategoryDAO

.getSubCategoriesAsStringList(catId);

if (subCatList.size() > 0) {

String[] subCatStrArr = new String[subCatList.size()];

return subCatList.toArray(subCatStrArr);

} else {

return null;

}

}

}


Step 2

Next step is to add DWR namespace and schema location in your Application context's 'beans' tag. Here is an example:


<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop-2.0.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx-2.0.xsd

http://www.directwebremoting.org/schema/spring-dwr

http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd">


Step 3


Now a configuration tag needs to be added to Application context. This is required even if it does not have data with in it.


<dwr:configuration>dwr:configuration>


Step 4

Configure bean/class (defined in the Step 1) in the Application Context file. It also has dwr tag which basically enables JavaScript to call method on that object instance.


<bean id="dwrService" class="util.AcsDWRUtil" >

<dwr:remote javascript="dwrService">

<dwr:include method="getBusinessSubCategories" />

dwr:remote>

<property name="subcategoryDAO" ref="subcategoryDAO" />

bean>


Tag dwr:remote enables JavaScript to invoke method(s) on dwrService.

Here is an example how jsp page would call DWR. Bur before that few js files (created by DWR engine) needs to be included in the page:


<script type='text/javascript'

src='/abservice/dwr/interface/dwrService.js'>script>

<script type='text/javascript' src='/abservice/dwr/engine.js'>script>

<script type='text/javascript' src='/abservice/dwr/util.js'>script>


Here is the JavaScript code calling Java method using dwrService instance the AcsDWRUtil class:


function callbackDWRGetSubCategories(data) {

var subCatArr = data;

dwr.util.setValue("subcat", subCatArr);

}

function getSubCategories(catId) {

dwrService.getBusinessSubCategories(catId, callbackDWRGetSubCategories);

}


And finally you would be calling above getSubCategories() in your jsp page somewhere. Keep in mind you would need to add one additional parameter to the lava method. It is a js callback method as described above.

That's all. Your Spring app is now DWR enabled and enjoy the power of DWR async communication.

In the next article I am planning of covering DWR "reverse ajax".

Please shoot me an email if you have any suggestions or questions. I would be glad to answer.

Till then,

Sanjay Semwal

J2EE Architect

Saturday, September 12, 2009

Sending mail with Spring mail abstraction Layer

Introduction

Spring framework provides a higher level of abstraction for sending e-mail which hides underlying details of low-level resource handling.

What all is needed for Spring e-mail to work?

Let me try to reveal it with the following step by step process:

STEP 1)
The important package is org.springframework.mail. It contains following two main interfaces:
a) MailSender
--As name states, it is used for sending an email. It declares two overloaded send() methods.
b) MailMessage
--One of the implementations of this interface is SimpleMailMessage, which encapsulates mail properties such as from, to, cc, subject and text.

If you are curious to know more details, please have a look here: http://static.springsource.org/spring/docs/1.2.9/reference/mail.html


STEP 2)
The next step would be to create a mail manager class (say MailManager) which has association/dependency with both the above interfaces. Here is a quick example:



public class MailManager implements Manager {

private MailSender mailSender;

private SimpleMailMessage message;

public void setMailSender(MailSender mailSender) {

this.mailSender = mailSender;

}

public void setMessage(SimpleMailMessage message) {

this.message = message;

}

public void sendPwd(ForgotPwdBean forgotPwd, String pwd) {

//Create a thread safe "sandbox" of the message

SimpleMailMessage msg = new SimpleMailMessage(this.message);

msg.setTo(forgotPwd.getEmail());

msg.setSubject("Information about your account password");

msg.setText("Dear " + forgotPwd.getUid() + ",\n"

+ "You have requested password for your account.\n"

+ "Your password is: " + pwd + "\n" + "Thanks,\n"

+ "www.xyz.com");

try {

mailSender.send(msg);

} catch (MailException ex) {

//log it and go on

System.err.println(ex.getMessage());

}

}

}



STEP 3)

The Third step would be to configure your Application Context file. It should tell IOC container/BeanFactory how dependency will be injected. IOC Container can inject dependency either through 'setter' or 'constructor' Once configured, the container would inject dependency automatically. This is how dependency injection works in Spring:-


<bean id="mailManager" class="service.MailManager">

<property name="mailSender">

<ref bean="mailSender" />

property>

<property name="message">

<ref bean="mailMessage" />

property>

bean>



If you see above xml fragement. service.MailManager class has dependency with two properties ( mailSender and mailMessage) , which are referring to implemented beans (<ref bean="mailSender" />, ). These properties are actually interfaces (declared in class as well) NOT actual classes. Actual implementation classes are defined somewhere in the same application context file like this:



<bean id="mailSender"

class="org.springframework.mail.javamail.JavaMailSenderImpl">

<property name="host" value="smtp.gmail.com" />

<property name="session" ref="mailSession" />

bean>

<bean id="mailMessage"

class="org.springframework.mail.SimpleMailMessage">

<property name="from" value="put email here" />

bean>



STEP 4)
The next step would to setup mail session referenced by mailSession (i.e. ref="mailSession") like this in the same context file:




<bean id="mailSession" class="javax.mail.Session"

factory-method="getInstance">

<constructor-arg>

<props>

<prop key="mail.smtp.auth">trueprop>

<prop key="mail.smtp.socketFactory.port">465prop>

<prop key="mail.smtp.socketFactory.class">

javax.net.ssl.SSLSocketFactory

prop>

<prop key="mail.smtp.socketFactory.fallback">

false

prop>

props>

constructor-arg>

<constructor-arg ref="smtpAuthenticator" />

bean>



The above configuration is required to setup an authenticated session.

STEP 5)

Next step is to define an Authenticator class which is being referenced as constructor arg above ( i.e. ref="smtpAuthenticator" ). Here is the code:




package service.mailauthenticator;

import javax.mail.Authenticator;

import javax.mail.PasswordAuthentication;

public class SmtpAuthenticator extends Authenticator {

private String username;

private String password;

public SmtpAuthenticator(String username, String password) {

super();

this.username = username;

this.password = password;

}

public PasswordAuthentication getPasswordAuthentication() {

return new PasswordAuthentication(username, password);

}

}



STEP 6)
And the final step is to define a bean in application context file and you are good to go!. Here is the xml:



<bean id="smtpAuthenticator"

class="service.mailauthenticator.SmtpAuthenticator">

<constructor-arg value="put email id here" />

<constructor-arg value="put password here" />

bean>


This xml is needed, so that your application automatically will long into your mail account and send mail from there.

That's it!, You are all set now. Please have a look and give a try. I would be happy to hear from any comments, suggestions and/or questions…

Thanks
Sanjay Semwal
J2EE Architect