<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Hari Gangadharan's Blog &#187; Java</title>
	<atom:link href="http://www.harinair.com/category/technology/java/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.harinair.com</link>
	<description>From the desk of a gadget lover</description>
	<lastBuildDate>Mon, 09 May 2011 20:14:35 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Spring (Acegi) Security Account Lockout</title>
		<link>http://www.harinair.com/2010/02/spring-acegi-security-account-lockout/</link>
		<comments>http://www.harinair.com/2010/02/spring-acegi-security-account-lockout/#comments</comments>
		<pubDate>Sun, 28 Feb 2010 07:28:22 +0000</pubDate>
		<dc:creator>Hari Gangadharan</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.harinair.com/?p=167</guid>
		<description><![CDATA[Due to my previous articles in Spring Security, some has asked me how to implement the Account Lockout on too many failed login attempts. The best way to do this is to listen for Spring events and update your User object on a failed login.  Let us start with your User object. It must be [...]]]></description>
			<content:encoded><![CDATA[<p>Due to my previous articles in Spring Security, some has asked me how to implement the Account Lockout on too many failed login attempts. The best way to do this is to listen for Spring events and update your User object on a failed login.  Let us start with your User object. It must be implementing the UserDetails interface and you might have already noticed that it has a method isAccountNonLocked(). You might be currently returning true in the implementation. Now we have to change the logic here to implement locked status.<br />
<span id="more-167"></span></p>
<pre name="code" class="java">
// User.java
public class User implements Serializable,
     org.springframework.security.userdetails.UserDetails {
    // let us put max failed login attempts at 5
    public static final short MAX_FAILED_LOGIN_ATTEMPTS = 5;

    /**
     * An attribute to track the number of failed login attempts
     */
    private int failedLoginAttempts;

    // all other attributes and the getters and setters.

    /**
     * Implementation for the UserDetails interface. Verifies that
     * the account is not locked. Returns true if account is not
     * locked. Otherwise returns false.
     */
    public boolean isAccountNonLocked() {
        if (this.getFailedLoginAttempts()
                   >= MAX_FAILED_LOGIN_ATTEMPTS) {
            return false;
        }
        return true;
    }
}
</pre>
<p>That takes care of the actual locking of the account. Now we have to increment the failedLoginAttempts every time an user enters the wrong credentials. Luckily, Spring Security creates an AuthenticationFailureBadCredentialsEvent every time a user tries to login with wrong credentials. Now we have to implement an ApplicationListener to listen for this event. This class shall implement the Spring ApplicationListener interface.  Actually you need only one application listener for your whole application:</p>
<pre name="code" class="java">
public class ApplicationEventListener implements
    org.springframework.context.ApplicationListener {
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof AuthenticationFailureBadCredentialsEvent){
            // do everything for bad login
            // (increment failedLoginAttempts)
        else if (event instanceof SomeOtherEvent) {
            // handle the "some other event"!
        }
    }
}
</pre>
<p>However somebody with a little bit of Object Oriented Programming knowledge can tell that this is a bad design. The reason is this class handles too many events and this class has to be modified whenever your application has to listen for a new event. Hence we will refactor the code in an Object Oriented way. We will modify this class to listen for the application events and to dispatch it to an appropriate listener. We will then create one listener for every Event we have to handle. To begin, an abstract class EventListener is created. All event listeners extend this class and implement the abstract methods. This could have been an interface but it has been created as an abstract class so that I can add the code to automatically register the listener with the main application event dispatcher.</p>
<pre name="code" class="java">
// EventListener.java
package wisdom.web.event;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * An abstract class that is the parent for event listeners
 * in this application. Any event listener should extend
 * this class.
 *
 * @author Hari Gangadharan
 */
public abstract class EventListener implements InitializingBean {

    Log log = LogFactory.getLog(this.getClass());

   // the instance of the event dispatcher will be
   // auto-wired by spring
   @Autowired
   EventDispatcher eventDispatcher;

   // Spring will call this method after auto-
   // wiring is complete.
   public void afterPropertiesSet() throws Exception {
       // let us register this instance with
       // event dispatcher
       eventDispatcher.registerListener(this);
   }

   /**
    * Implementation of this method checks whether the given event can
    * be handled in this class. This method will be called by the event
    * dispatcher.
    *
    * @param event the event to handle
    * @return true if the implementing subclass can handle the event
    */
   public abstract boolean canHandle(Object event);

   /**
    * This method is executed by the event dispatcher with the
    * event object.
    *
    * @param event the event to handle
    */
   public abstract void handle(Object event);
}
</pre>
<p>Here you will see that this bean auto-wires the EventDispatcher (which we have not written yet). Also we register this instance to the EventDispatcher after the properties are set. Now we will write an Event Dispatcher that receives Spring Events and dispatches it to the appropriate Listener.</p>
<pre name="code" class="java">
// EventDispatcher.java
package wisdom.web.event;

import java.util.ArrayList;
import java.util.List;
import org.springframework.context.ApplicationEvent;
import org.springframework.stereotype.Component;

/**
 * This class implements the Spring ApplicationListener interface and
 * hence it receives application event notifications. This in turn
 * dispatches the events to listeners that have registered with
 * this object.
 *
 * @author Hari Gangadharan
 */
@Component("eventDispatcher")
public class EventDispatcher implements
     org.springframework.context.ApplicationListener {

    List&lt;EventListener&gt; listeners = new ArrayList&lt;EventListener&gt;();

    /**
     * Method that allows registering of an Event Listener.
     */
    public void registerListener(EventListener listener) {
        listeners.add(listener);
    }

    /**
     * Spring executes this method with the event object.
     * This method iterates though the list of registered
     * Listeners and checks whether any listener can
     * handle the event. Calls handle method of the
     * Listener if it can handle the event.
     */
    public void onApplicationEvent(ApplicationEvent event) {
        for (EventListener listener: listeners) {
            if (listener.canHandle(event)) {
                listener.handle(event);
            }
        }
    }
</pre>
<p>Now we are ready to write the code that will listen for the login failures. As you know this code will increment the failedLoginAttempt of User object.</p>
<pre name="code" class="java">
// LoginFailureEventListener.java
package wisdom.web.event;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.event.authentication
      .AuthenticationFailureBadCredentialsEvent;
import org.springframework.stereotype.Component;
import wisdom.api.model.User;
import wisdom.api.service.UserManager;

/**
 * A listener that listens for the Login Failure Event. This listener
 * updates the failed login attempt count which in turn locks out
 * the user.
 *
 * @author Hari Gangadharan
 */
@Component("loginFailureEventListener")
public class LoginFailureEventListener extends EventListener {
    // this is your User Service. We call a method
    // in this to update the User object.
    @Autowired
    UserManager userManager;

    @Override
    public boolean canHandle(Object event) {
        return event instanceof
             AuthenticationFailureBadCredentialsEvent;
    }

    @Override
    public void handle(Object event) {
        AuthenticationFailureBadCredentialsEvent loginFailureEvent
             = (AuthenticationFailureBadCredentialsEvent) event;
        Object name = loginFailureEvent.getAuthentication()
                  .getPrincipal();
        User user = userManager.getUser((String) name);
        if (user != null) {
            // update the failed login count
            short failedLoginAttempts = user.getFailedLoginAttempts();
            user.setFailedLoginAttempts(++failedLoginAttempts);
            // update user
            userManager.updateUser(user);
        }
    }
}
</pre>
<p>We are almost there&#8230; Now the we have to do two more things. Can you guess? The first one is to create another listener for successful authentication event. If the user is successful in logging in and if the failedLoginAttempts count is greater than 0 then we have reset the count (to 0). Otherwise the failedLoginAttempts may get accumulated over time with occasional login failures and finally the account may become locked. The second  thing to do is to alert the user if the account is locked. Let us do the first thing viz. the listener now:</p>
<pre name="code" class="java">
// LoginSuccessEventListener.java
package wisdom.web.event;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.event.authorization.AuthorizedEvent;
import org.springframework.stereotype.Component;
import wisdom.api.model.User;
import wisdom.api.service.UserManager;

/**
 * Listens for the Login Success.
 * This class resets the failed login count.
 *
 * @author Hari Gangadharan
 */
@Component("loginSuccessEventListener")
public class LoginSuccessEventListener extends EventListener {

    @Autowired
    UserManager userManager;
    /**
     * A private method that gets the User object
     * from the event if it is an AuthorizedEvent.
     * Otherwise returns null.
     */
    private User getPrincipal(Object event) {
        if (event instanceof AuthorizedEvent) {
            AuthorizedEvent authorizedEvent = (AuthorizedEvent) event;
            Object principal = authorizedEvent.getAuthentication()
                     .getPrincipal();
            if (principal instanceof User) {
                return (User) principal;
            }
        }
        return null;
    }

    @Override
    public boolean canHandle(Object event) {
        User principal = this.getPrincipal(event);
        return (principal != null);
    }

    @Override
    public void handle(Object event) {
        User user = this.getPrincipal(event);
        try {
            if (user.getFailedLoginAttempts() > 0) {
                // reset failed login count to zero
                // on a successful login
                user.setFailedLoginAttempts((short) 0);
                // update user
                userManager.updateUser(user);
            }
        } catch (Exception ex) {
            // just log the exception
            log.error("Failure in login success event handling", ex);
        }
    }
}
</pre>
<p>That completes the listener. Now we have to do the last thing &#8211; alert the user that the account is locked and direct the user to further actions like contacting customer care or verifying account. Depending on the framework used, you may have to figure out where the code is to be added:</p>
<pre name="code" class="java">
ExternalContext externalContext = FacesUtils.getExternalContext();
Exception e = (Exception) externalContext.getSessionMap().get(
         AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY);
// check if there is a Bad Cred Exception
if (e instanceof BadCredentialsException) {
    // add code to show the Login Invalid Error Message
// check if it is Account Locked
} else if (e instanceof LockedException) {
    // add code to show Account Locked Error Message
}
// reset the last exception key
externalContext.getSessionMap().put(
     AbstractProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY, null);
</pre>
<p>If the framework used is JSF the above code can go into the Phase Listener or on the the form binding variable setter for the login form.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.harinair.com/2010/02/spring-acegi-security-account-lockout/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Back in US!</title>
		<link>http://www.harinair.com/2009/07/back-in-us/</link>
		<comments>http://www.harinair.com/2009/07/back-in-us/#comments</comments>
		<pubDate>Thu, 09 Jul 2009 19:40:22 +0000</pubDate>
		<dc:creator>Hari Gangadharan</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.harinair.com/?p=140</guid>
		<description><![CDATA[After a month long journey and two kids with dysentery, I am happy to be back home in California. I am still recovering from my jet-lag. These days I am sleeping very early, probably by 8:30 PM because of the jet-lag. Hopefully I will over with that by the end of this week.
On my way [...]]]></description>
			<content:encoded><![CDATA[<p>After a month long journey and two kids with dysentery, I am happy to be back home in California. I am still recovering from my jet-lag. These days I am sleeping very early, probably by 8:30 PM because of the jet-lag. Hopefully I will over with that by the end of this week.</p>
<p>On my way back from India we stayed 4 days in Dubai, UAE. It is amazing how they have constructed that huge city in the middle of a desert. The Burj Dubai, Burj Al Arab and the Palm Jumeriah are impressive. Dubai seemed to be an extension of Kerala since we could go into any store and start talking in Malayalam. Probably half of Dubai residents are people from Kerala, India. The food there is cheap and good. The third day, we went on a desert safari which we all enjoyed. My kids had a blast riding ATV on desert.</p>
<p>However I am amazed by the lack of the concept of a family (at least in the public), especially among local population. It is hard to find a family go together to a mall or a restaurant. You can see groups of men and groups of ladies roaming separately which is hard to see in US or any other western country.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.harinair.com/2009/07/back-in-us/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Look what I was working on!</title>
		<link>http://www.harinair.com/2009/05/look-what-i-was-working-on/</link>
		<comments>http://www.harinair.com/2009/05/look-what-i-was-working-on/#comments</comments>
		<pubDate>Tue, 05 May 2009 18:41:54 +0000</pubDate>
		<dc:creator>Hari Gangadharan</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.harinair.com/?p=97</guid>
		<description><![CDATA[We recently created a SPOT Live Widget that can be embedded in your blog or your web page. Here is my SPOT Live widget and it tells me where I am:

div#ext-gen76 {
    display: none;
}





If you are a SPOT User, you can easily get the SPOT Widget running on your site.

First create a [...]]]></description>
			<content:encoded><![CDATA[<p>We recently created a SPOT Live Widget that can be embedded in your blog or your web page. Here is my SPOT Live widget and it tells me where I am:</p>
<style class="text/css">
div#ext-gen76 {
    display: none;
}
</style>
<p><script src="http://maps.google.com/maps?oe=utf-8&amp;file=api&amp;v=2&amp;key=ABQIAAAAr8rJyh2fK15gFa0tbS4cphS3Zeu2Vh4_6NEAQ7nj21r4XYWguxRI41KD_TWtHEFOvfIGsm1quk9DuA" type="text/javascript"></script><br />
<script type="text/javascript" src="http://static.findmespot.com/live-widget/1.1/js/SpotMain.js"></script><br />
<script type="text/javascript"><!--
 var widget = new Spot.Ui.LiveWidget({ renderTo: "spot-live-widget",
   feeds: [ "0o0VYWuQkoUvs9dj04qhOxFOgavQXdAEP","0078jGJ3hemqDkELgNQ1bcT3Kv7OuNTN3" ],
   height: 500,
   width: 570
 });
// --></script></p>
<div id="spot-live-widget"></div>
<p>If you are a SPOT User, you can easily get the SPOT Widget running on your site.</p>
<ol>
<li>First create a share page by logging into your SPOT Account and then clicking the &#8220;Share&#8221; tab.</li>
<li>Now note the glId of the share link created (share links are of the format http://share.findmespot.com/shared/faces/gogl.jsp?glId=xxxxx &#8211; here xxxxx is your glId or guest link Id).</li>
<li>Sign up for a <a href="http://code.google.com/apis/maps/signup.html" target="_blank">Google Maps API key</a>. You need to provide the URL of your site.</li>
<li>Return to this page and click on the &#8220;Share this&#8221; button on the bottom of this widget and copy the code from that and paste it to your blog or webpage. Make sure you are pasting the code in HTML mode (not visual mode).</li>
<li>Replace the <strong>feeds: [ "0o0VYWuQkoUvs9dj04qhOxFOgavQXdAEP" ]</strong> in the copied code with<strong> feeds: [ "xxxxx" ]</strong> where <strong>xxxx </strong>is the glId obtained from step 2.</li>
<li>Replace <strong>your-gmap-key</strong> in the copied code with the key obtained in Step 3.</li>
</ol>
<p>Sure, it sounds complicated since I explained it too much <img src='http://www.harinair.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . For people with some knowlege of HTML it is quick and easy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.harinair.com/2009/05/look-what-i-was-working-on/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>My Kindle 2 Finally Arrived!</title>
		<link>http://www.harinair.com/2009/03/my-kindle-2-finally-arrived/</link>
		<comments>http://www.harinair.com/2009/03/my-kindle-2-finally-arrived/#comments</comments>
		<pubDate>Tue, 03 Mar 2009 08:06:26 +0000</pubDate>
		<dc:creator>Hari Gangadharan</dc:creator>
				<category><![CDATA[Java]]></category>

		<guid isPermaLink="false">http://www.harinair.com/?p=56</guid>
		<description><![CDATA[From late December, I was planning to order Kindle but I put it off just because of the rumors of Kindle 2 being out. I also noticed the huge waiting period for Kindle last month (almost 13 weeks). From that I was pretty sure Kindle 2 is on the way. Finally the day they announced, [...]]]></description>
			<content:encoded><![CDATA[<p>From late December, I was planning to order Kindle but I put it off just because of the rumors of Kindle 2 being out. I also noticed the huge waiting period for Kindle last month (almost 13 weeks). From that I was pretty sure Kindle 2 is on the way. Finally the day they announced, I ordered my Kindle 2. I have seen Kindle 1 and I liked it too but I heard that the major flaws with Kindle 1 is resolved in this version.</p>
<p><img style="float: left; padding: 10px;" title="Kindle - in the package" src="http://www.harinair.com/wp-content/uploads/2009/03/074.jpg" alt="Kindle - in the package" width="440" height="332" />Kindle 2 came in a very nice packing. After opening, I was surprised by the iPhone like thin look and its tiny bright keys. The keys actually fits nicely compared to the Kindle 1.It came powered on and the screen had instruction on how to start using Kindle! I initially thought that it was plastic paper stuck on the screen of Kindle!</p>
<p>The shorter paging button is much better and it does not accidentally turn a page. The kindle 2 feels like it is marginally faster&#8230; the page rendering seems to be faster and the accidental page flip is not as annoying since we can flip back fairly quickly.</p>
<p>I understand that with today&#8217;s thin devices the possibility of replacing batteries is even more difficult. However I am not happy that the Kindle 2 does not have a replaceable battery. The other biggest drawback and is a downgrade from the version 1 is the missing expansion slots. The Kindle 1 had a SD slot. I hoped that Kindle 2 had at least the micro-SD slot. But without the expansion slot your Kindle is stuck with 1.5 GB capacity. Right now with around 30 books and manuals stored in Kindle, I have not even used 20 MB. But someday you have to swap some stuff out to make room for other books. I am also unhappy that I cannot organize books in folders &#8211; I am too used to folders. Even if I create folders in the Kindle internal disk everything shows up flat in the Home screen.</p>
<p><span id="more-56"></span></p>
<p><img style="float: left; padding: 10px;" title="Kindle - unpacked" src="http://www.harinair.com/wp-content/uploads/2009/03/075.jpg" alt="Kindle - unpacked" width="444" height="341" />Kindle 2 has put a small joystick on the bottom for you to move your cursor. Not being a big fan of joysticks or buttons, I would have liked a thumb wheel or a roller instead. Similarly for $359, I would expect a little more bigger screen. The current screen is sufficient but it would have been much better if it were as big as the device itself. Personally the 16-shade gray scale is fine for me and I did not have difficulty reading figures in my manuals. The electronic ink is completely strain free and you could read for hours without straining your eyes. One of the features, non-native English readers like me and the young reader appreciate is the instant dictionary lookup. As soon as you place the cursor before a word you are unsure, the definition from the dictionary will be shown in the bottom. You can press enter key to see the full definition. However, I would have liked a few more lines for that popup (for the lack of a better word) that shows the definition. Many cases the definition shown is not complete and I had to press enter and see the full definition.</p>
<p><img style="float: left; padding: 10px;" title="Kindle - Charger amd micro-USB cable" src="http://www.harinair.com/wp-content/uploads/2009/03/111.jpg" alt="Kindle - Charger amd micro-USB cable" width="480" height="360" />Connecting the Kindle to the computer is very easy &#8211; just like any thumb drives. I initially was disappointed to see that Amazon was not using the mini-USB for the sync cable. I am not a fan of proprietary interfaces and hate carrying a bunch of cables when I travel. Soon I realized that the cable Amazon was using is the micro-USB the new USB interface for small devices like phones. The Kindle&#8217;s charger is the best I have seen. My guess is I can use that for charging all my USB devices. It is a plug with a USB slot. You can connect the Kindle USB cable into that plug to start the charging.</p>
<p><img class="alignnone size-full wp-image-64" style="float: left; padding: 10px;" title="Kindle" src="http://www.harinair.com/wp-content/uploads/2009/03/077.jpg" alt="Kindle" width="360" height="480" />Kindle does not have native PDF support but your PDF books and manuals can be sent to name@kindle.com or name@free.kindle.com (where name is the Kindle id you have chosen) and the Amazon Kindle service will convert it to Kindle format. The first email address will sent the converted book directly to your Kindle using Whispernet and they charge 10 cents per book. In the other case it will be converted and sent to the primary email address in the Amazon account. You can download it and manually transfer it to your Kindle. I have converted a bunch of technical books in PDF format using this service and all of them looked OK in Kindle. Conversion service took an average of 2 minutes to convert each book. The cool thing is you can even send a zip file of all the documents you have to convert. The Amazon service will unzip, convert the documents and send them to you.</p>
<p>Overall I am satisfied by this product. The price is a little too steep but I am OK with it since it comes with lifetime subscription to Whispernet. I even can browse the internet using the Whispernet. However I can give only a 70% approval rating just because of the following three annoyances:</p>
<ul>
<li>Screen not big enough to hold a full page of a manual or text book</li>
<li>Lack of expansion slots</li>
<li>Lack of replaceable battery</li>
</ul>
<p>According to me the following are the pros:</p>
<ul>
<li>Thin, sleek device &#8211; fits everywhere</li>
<li>Better page flip and handles easily</li>
<li>Sufficient internal memory</li>
<li>Great compact charger &#8211; all other devices should use make use of this compact charger</li>
<li>Whispernet and Internet connection</li>
<li>Read to Me feature</li>
<li>The instant dictionary lookup</li>
<li>Saves Trees</li>
</ul>
<p><strong>And now the cons:</strong></p>
<ul>
<li>No expansion slot! What was Amazon thinking?</li>
<li>Battery cannot be replaced (by the end user)</li>
<li>Screen not big enough to hold a full page</li>
<li>What my Lexus don&#8217;t come with floor mats? They sell the Kindle cover for $30? That&#8217;s unreasonable. I already paid $360</li>
<li>Could be a little more elegant</li>
<li>No privacy settings &#8211; password protection, password protecting books, or hiding books you don&#8217;t want others to see.</li>
</ul>
<p><strong>Nice to have:</strong></p>
<ul>
<li>Touch screen</li>
<li>Color screen</li>
<li>Native PDF support</li>
<li>Blackberry like Roller or a track ball instead of the Joystick</li>
<li>More lines in the dictionary lookup popup</li>
</ul>
<p><img style="float: left; padding: 10px;" title="Kindle - connected" src="http://www.harinair.com/wp-content/uploads/2009/03/083.jpg" alt="Kindle - connected" width="480" height="360" /><br />
<img class="alignnone size-full wp-image-66" title="Kindle" src="http://www.harinair.com/wp-content/uploads/2009/03/079.jpg" alt="Kindle" width="480" height="360" /></p>
<p><img class="alignnone size-full wp-image-65" title="Kindle - keyboard" src="http://www.harinair.com/wp-content/uploads/2009/03/078.jpg" alt="Kindle - keyboard" width="480" height="360" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.harinair.com/2009/03/my-kindle-2-finally-arrived/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Spring, Quartz and Auto-wiring of Quartz jobs</title>
		<link>http://www.harinair.com/2008/01/spring-quartz-and-auto-wiring-of-quartz-jobs/</link>
		<comments>http://www.harinair.com/2008/01/spring-quartz-and-auto-wiring-of-quartz-jobs/#comments</comments>
		<pubDate>Wed, 16 Jan 2008 00:06:35 +0000</pubDate>
		<dc:creator>Hari Gangadharan</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[quartz]]></category>
		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://www.harinair.com/?p=13</guid>
		<description><![CDATA[Facing Null Pointer Exceptions in Quartz jobs? This is an example on how to do Spring Quartz Integration with Auto-wiring. 
Quartz Enterprise scheduler is a neat application that lets you setup periodic jobs within a J2EE or J2SE environment. Quartz is not as powerful as other commercial enterprise job schedulers like Autosys but its ability [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Facing Null Pointer Exceptions in Quartz jobs? This is an example on how to do Spring Quartz Integration with Auto-wiring. </strong></p>
<p>Quartz Enterprise scheduler is a neat application that lets you setup periodic jobs within a J2EE or J2SE environment. Quartz is not as powerful as other commercial enterprise job schedulers like Autosys but its ability to run simple cron-like jobs within an Application server environment is commendable.  Above all Quartz and Spring integrates very nicely with a little effort.</p>
<p><span id="more-13"></span>I have seen that many people complain about Null Pointer Exception in the Quartz jobs. It is due to the inability of Quartz to auto-wire Spring beans since the job bean is instantiated by Quartz. One option people talk about is to use the <span style="background-color: #ffffff; font-family: courier new,courier,monospace; color: #3333ff;">MethodInvokingJobDetailFactoryBean</span> of Spring to invoke a method in your spring bean. The disadvantage is that you would not have access to the JobExcecutionContext which I think is important in many advanced jobs. Here is a document that explains this method:<br />
<a href="http://www.zabada.com/technology/Wiki.jsp?page=SpringAndQuartz">http://www.zabada.com/technology/Wiki.jsp?page=SpringAndQuartz</a></p>
<p>I have successfully instantiated Job beans will full auto-wiring using the technique explained below. In this technique I pass the actual job bean name to a delegating job bean through the job data map.  Now the delegating job bean instantiates the actual job bean based on name retrieved from the job data map. After instantiating the job bean, the delegating job bean invokes methods in it as defined by the contract, JobInterface.</p>
<p>First you define an interface (or a contract) for your jobs. Let us call it JobInterface:</p>
<pre name="code" class="java">
// JobInterface.java
package com.harinair.jobs;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public interface JobInterface {
public void init(JobExecutionContext jobExecutionContext)
      throws JobExecutionException
public void execute() throws JobExecutionException;
public void destroy();
}</pre>
<p>Now write the job bean that implements this interface:</p>
<pre name="code" class="java">
package com.harinair.jobs;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
 * @author hari.gangadharan
 * @spring.bean id="checkMailJobBean" autowire="byName"
 */
public class CheckMailJobBean implements JobInterface {
    public void init (JobExecutionContext jobExecutionContext)
        throws JobExecutionException {
        // Do your job initialization
    }
    public void execute() throws JobExecutionException {
        // Write your job logic
    }
    public void destroy() {
        // Do the cleanup
    }
// Add all others setters and getters for your
// Spring auto-wiring
}
</pre>
<p>It is time to write a delegating job bean that can execute the above job bean:</p>
<pre name="code" class="java">
package com.harinair.jobs;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerContext;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
/**
 * @author hari.gangadharan
 */
public class DelegatingJobBean extends QuartzJobBean {
    private static final String APPLICATION_CONTEXT_KEY
        = "applicationContext";
    private static final String JOB_BEAN_NAME_KEY
        = "job.bean.name";
    protected Log log = LogFactory.getLog(getClass());

    @Override
    protected final void executeInternal(JobExecutionContext
              jobExecutionContext) throws JobExecutionException {
        SchedulerContext schedulerContext = null;
        try {
            schedulerContext = jobExecutionContext.getScheduler()
                 .getContext();
        } catch(SchedulerException e) {
            throw new JobExecutionException(
                "Failure accessing scheduler context", e);
        }
        ApplicationContext appContext = (ApplicationContext)
             schedulerContext.get(APPLICATION_CONTEXT_KEY);
        String jobBeanName = (String) jobExecutionContext
                  .getJobDetail()
                  .getJobDataMap().get(JOB_BEAN_NAME_KEY);
        log.info("Starting job: " + jobBeanName);
        JobInterface jobBean = (JobInterface) appContext
               .getBean(jobBeanName);
        try {
            jobBean.init(jobExecutionContext);
            jobBean.execute();
        } finally {
            jobBean.destroy();
        }
    }
}
</pre>
<p>Now you are ready to make the application context changes:</p>
<p>Spring Context (I have also attached it here):<a href="http://shared-files.s3.amazonaws.com/springContext.xml"><br />
http://shared-files.s3.amazonaws.com/springContext.xml</a></p>
<pre name="code" class="xml">
< !DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
      "http://www.springframework.org/dtd/spring-beans.dtd"> 

<beans>
<!-- This is your job bean-->
<bean id="checkMailJobBean"
    class="com.harinair.jobs.CheckMailJobBean"
    autowire="byName" >
  <!-- Ref to other beans. Add more if needed --> 
<property name="serviceLocator">
    <ref bean="serviceLocator" />
  </property>
</bean>
<!-- Define the bean that delegates the work to the real job bean -->
<bean name="checkMailJob"
    class="org.springframework.scheduling.quartz.JobDetailBean"> 
<property name="jobClass"
       value="com.harinair.jobs.DelegatingJobBean"/>
<property name="jobDataAsMap">
<map>
      <!-- This specifies the actual job bean name -->
      <entry key="job.bean.name" value="checkMailJobBean"/>
      <!-- Any other job data map entries required by your job -->
      <entry key="sdtl.file.prefix" value="sdtl_"/>
    </map>
</property>
</bean>
<!-- Associate the delegating job bean with a trigger -->
<bean id="checkMailTrigger"
    class="org.springframework.scheduling.quartz.CronTriggerBean"> 
<property name="jobDetail" ref="checkMailJob"/>
  <!-- run every morning at 6:30 AM --> 
<property name="cronExpression" value="0 30 6 * * ?"/>
</bean> 

  <!-- Define the scheduler with the list of triggers -->
  <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 
<property name="triggers">
<list>
      <ref bean="checkMailTrigger"/>
    </list>
  </property>
  <!-- Scheduler context key we use this in delegating job bean --> 
<property name="applicationContextSchedulerContextKey">
      <value>applicationContext</value>
  </property>
</bean>
</beans>
</pre>
<p>Now fire up your application. Your job will run daily at 6:30 AM.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.harinair.com/2008/01/spring-quartz-and-auto-wiring-of-quartz-jobs/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
	</channel>
</rss>

