Techspace

IT happens only in IT

How to configure JCaptcha with your Spring App

Update: 03/17/2009: This code example uses JCaptcha 1.0-RC6 . The latest version released on 02/04/2009 is JCaptcha 1.0. If you use JCaptcha 1.0 then you might have to make some changes to the code given in this example.

This is how I setup JCaptcha in my application. Following code snippet is for the test page I have created to test the JCaptcha and Spring integration

captchademoscreen

1) First create a controller which will generate a new Captcha for each session based on session id

package com.example.web.controller;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;

import com.octo.captcha.service.CaptchaServiceException;
import com.octo.captcha.service.image.ImageCaptchaService;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.example.domain.LoginCommand;
import com.example.logger.LoginLogger;

public class CaptchaController extends LoginBaseController {

    public CaptchaController(){
        setCommandClass(LoginCommand.class);
    }

    @Override
    protected ModelAndView showForm(HttpServletRequest request, HttpServletResponse response, BindException errors,
            Map controlModel) throws Exception {

         byte[] captchaChallengeAsJpeg = null;
           // the output stream to render the captcha image as jpeg into
            ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
            try {
            // get the session id that will identify the generated captcha.
            //the same id must be used to validate the response, the session id is a good candidate!

            String captchaId = request.getSession().getId();
            LoginLogger.debug(this, "Captcha ID which gave the image::" + captchaId);
            // call the ImageCaptchaService getChallenge method
                BufferedImage challenge = ((ImageCaptchaService)getCaptchaService()).getImageChallengeForID(captchaId, request.getLocale());

                // a jpeg encoder
                JPEGImageEncoder jpegEncoder =
                        JPEGCodec.createJPEGEncoder(jpegOutputStream);
                jpegEncoder.encode(challenge);
            } catch (IllegalArgumentException e) {
                response.sendError(HttpServletResponse.SC_NOT_FOUND);
                return null;
            } catch (CaptchaServiceException e) {
                response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                return null;
            }

            captchaChallengeAsJpeg = jpegOutputStream.toByteArray();

            // flush it in the response
            response.setHeader("Cache-Control", "no-store");
            response.setHeader("Pragma", "no-cache");
            response.setDateHeader("Expires", 0);
            //response.setContentType("image/jpeg");
//            response.getOutputStream().write(jpegOutputStream);
            ServletOutputStream responseOutputStream =
                response.getOutputStream();
            responseOutputStream.write(captchaChallengeAsJpeg);
            responseOutputStream.flush();
            responseOutputStream.close();

        return null;
    }

}

Please note that your implementation can vary. The only thing you want is a simple Servlet which will execute the code in showForm method above. In my case I am relying on Spring framework to execute this code because in the JSP where you show Captcha image I have written something like this
<img id=”captchaImage” src=”http://localhost:8080/LoginApplication/captcha.htm”>. In my application the URL captcha.htm is wired to this controller. But you can choose to have a simple servlet mapped instead of a Spring Controller.

2) Make the following entries in your Spring config files to configure JCaptcha

    <!-- Captcha Related Mappings -->
    <bean id="captchaController"
        class="com.example.web.controller.CaptchaController">
<property name="captchaService" ref="captchaService" />
    </bean>    

    <bean id="imageEngine" class="com.octo.captcha.engine.GenericCaptchaEngine">
        <constructor-arg index="0">
	<list>
                <ref bean="CaptchaFactory"/>
            </list>
        </constructor-arg>
    </bean>

    <bean id="CaptchaFactory" class="com.octo.captcha.image.gimpy.GimpyFactory" >
        <constructor-arg><ref bean="wordgen"/></constructor-arg>
        <constructor-arg><ref bean="wordtoimage"/></constructor-arg>
    </bean>

    <bean id="wordgen" class= "com.octo.captcha.component.word.wordgenerator.DictionaryWordGenerator" >
        <constructor-arg><ref bean="filedict"/></constructor-arg>
    </bean>

    <bean id="filedict" class="com.octo.captcha.component.word.FileDictionary" >
        <constructor-arg index="0"><value>toddlist</value></constructor-arg>
    </bean>

    <bean id="wordtoimage" class="com.octo.captcha.component.image.wordtoimage.ComposedWordToImage" >
        <constructor-arg index="0"><ref bean="fontGenRandom"/></constructor-arg>
        <constructor-arg index="1"><ref bean="backGenUni"/></constructor-arg>
        <constructor-arg index="2"><ref bean="simpleWhitePaster"/></constructor-arg>
    </bean>

    <bean id="fontGenRandom" class="com.octo.captcha.component.image.fontgenerator.RandomFontGenerator" >
        <constructor-arg index="0"><value>40</value></constructor-arg>
        <constructor-arg index="1"><value>50</value></constructor-arg>
        <constructor-arg index="2">
	<list>
                <ref bean="fontArial"/>
            </list>
        </constructor-arg>
    </bean>

    <bean id="fontArial" class="java.awt.Font" >
        <constructor-arg index="0"><value>Arial</value></constructor-arg>
        <constructor-arg index="1"><value>0</value></constructor-arg>
        <constructor-arg index="2"><value>10</value></constructor-arg>
    </bean>

    <bean id="backGenUni" class="com.octo.captcha.component.image.backgroundgenerator.UniColorBackgroundGenerator" >
        <constructor-arg index="0"><value>300</value></constructor-arg>
        <constructor-arg index="1"><value>100</value></constructor-arg>
    </bean>

    <bean id="simpleWhitePaster" class="com.octo.captcha.component.image.textpaster.SimpleTextPaster" >
        <constructor-arg type="java.lang.Integer" index="0">
            <value>3</value>
        </constructor-arg>
        <constructor-arg type="java.lang.Integer" index="1">
            <value>5</value>
        </constructor-arg>
        <constructor-arg type="java.awt.Color" index="2">
            <ref bean="colorBlack"/>
        </constructor-arg>
    </bean>

    <bean id="colorGreen" class="java.awt.Color" >
        <constructor-arg index="0"><value>0</value></constructor-arg>
        <constructor-arg index="1"><value>255</value></constructor-arg>
        <constructor-arg index="2"><value>0</value></constructor-arg>
    </bean>

    <bean id="colorBlack" class="java.awt.Color" >
        <constructor-arg index="0"><value>0</value></constructor-arg>
        <constructor-arg index="1"><value>0</value></constructor-arg>
        <constructor-arg index="2"><value>0</value></constructor-arg>
    </bean>

    <bean id="captchaService" class="com.octo.captcha.service.multitype.GenericManageableCaptchaService">
        <constructor-arg index="0"><ref bean="imageEngine"/></constructor-arg>
        <constructor-arg index="1"><value>180</value></constructor-arg>
        <constructor-arg index="2"><value>180000</value></constructor-arg>
    </bean>
    

For test purpose I have used a Simple Text Captcha.

3) To test create a command,controller and JSP like this

public class LoginCommand implements Serializable {
    private String verificationTextForForgotPass;
    //getter and setter methods
}
package com.example.web.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.validation.BindException;
import org.springframework.web.servlet.ModelAndView;

import com.octo.captcha.service.CaptchaServiceException;
import com.example.domain.LoginCommand;

public class CaptchaDemoController extends LoginBaseController {
	private CaptchaService captchaService;
	//Getter and setter for captchaService

    public CaptchaDemoController() {
        setCommandClass(LoginCommand.class);
    }

    @Override
    protected Object formBackingObject(HttpServletRequest request) throws Exception {
        LoginCommand command = new LoginCommand();

        return command;
    }

    @Override
    protected ModelAndView processFormSubmission(HttpServletRequest request, HttpServletResponse response,
            Object command, BindException errors) throws Exception {
        boolean isResponseCorrect = false;
        String sessionId = request.getSession().getId();
        //retrieve the response
        String verificationText = ((LoginCommand) command).getVerificationTextForForgotPass();

        // Call the Service method
        try {
            isResponseCorrect = getCaptchaService().validateResponseForID(sessionId, verificationText);
        }
        catch (CaptchaServiceException e) {
            //should not happen, may be thrown if the id is not valid
        }

		//You can do whatever you want to based on the response
        response.getWriter().write(String.valueOf(isResponseCorrect));

        return null;
    }
}

<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>

<head>
	<title>Captcha Demo</title>
</head>

<form:form action="captchaDemo.htm">
	<img id="captchaImage" src="http://localhost:8080/LoginApplication/captcha.htm">

	Enter the text here <form:input id="verificationTextForgPassDiv" path="verificationTextForForgotPass" cssErrorClass="errorField"/>

	<input type="submit" name="Submit" value="Submit"/>
</form:form>

As you can see the JSP will just show one Captcha Image and a text box where you can enter the Image text. The controller will verify the entered text and display true or false based on the result. You can implement your logic here for the Captcha verification result.

4) Finally make the following entries in your corresponding spring config file

<beans>
    <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
		<property name="mappings">
			<props>
				<prop key="/captchaDemo.htm">captchaDemoController</prop>
				<prop key="/captcha.htm">captchaController</prop>
            </props>
        </property>
    </bean>
</beans>

   <bean id="captchaDemoView" parent="baseView">
   		<property name="url" value="/WEB-INF/jsp/captchaDemo.jsp"/>
   </bean>
    <bean id="captchaDemoController" class="com.example.web.controller.CaptchaDemoController">
		<property name="formView" value="captchaDemoView"/>
		<property name="successView" value="captchaDemoView"></property>
		<property name="captchaService" ref="captchaService" />
    </bean>

Oops I forgot to mention, you should have JCaptcha jars in your classpath for this example to work ;)
I have written this post using the working code I have. I might have missed some configuration in this post. Let me know if you get any error. I will update the post.

November 11, 2008 Posted by Paras | JCaptcha, Spring | , , | 3 Comments

Test Your Java Knowledge. Chance to Win 1 of 100 books!

Sun Developers network is conducting an easy quiz.

Follow this link to know more details

November 11, 2008 Posted by Paras | News and Announcements | | No Comments Yet

Sorting Hibernate Set using a comparator

Collection mappings in Hibernate can be configured to sort using a specific comparator.

Consider the following mapping

<hibernate-mapping>
<class name="com.example.Person" table="PERSON">
......

<set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="natural">
	<key>
		<column name="BANK_ACCOUNT_ID" precision="29" scale="0" not-null="true" />
	</key>
	<one-to-many class="com.example.BankAccount" />
</set>

......
</class>
</hibernate-mapping>

In the example above Hibernate will order the bankAccounts set according to their natural order. If the BankAccout class implements Comparable interface, compareTo method will be used to sort the Set.

What if you want to sort the set differently? What if you want to use a comparator to sort the set.
The sort attribute can have three possible values

The first option is

 <set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="natural">

which sorts by natural order

the second option is

 <set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="unsorted">

which tells Hibernate that the Set needs not to be sorted

and the third option is

 <set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="comparatorClass">

where you specify what comparator should be used to sort the Set.

Let’s see it through code example. For example suppose class BankAccount is defined as below

package com.example;
//import statements

public class BankAccount implements Comparable<BankAccount>, Serializable{

private String accountName;
private String accountShortName;
//getter and setter methods

    public int compareTo(BankAccount that) {

        final int BEFORE = -1;
        final int AFTER = 1;

        if (that == null) {
            return BEFORE;
        }

        Comparable thisAccountName = this.getAccountName();
        Comparable thatAccountName = that.getAccountName();        

        if(thisAccountName == null) {
        	return AFTER;
        } else if(thatAccountName == null) {
        	return BEFORE;
        } else {
        	return thisAccountName.compareTo(thatAccountName);
        }
    }
}

In this case sort=”natural” will sort using the above compareTo method which compares the accountName to sort.
Now suppose you want that for this specific mapping you want the collection to be sorted by, say, accountShortName. You will define a Comparator like this

package com.example;
//import statements
public class BankAccountShortNameComparator implements Comparator<BankAccount>{
	public int compare(BankAccount o1, BankAccount o2) {
		if(o1!=null && o2!=null && o1.getAccountShortName()!=null && o2.getAccountShortName()!=null) {
			return o1.getAccountShortName().compareTo(o2.getAccountShortName());
		}
		if(o1!=null && o2!=null) {
			return o1.compareTo(o2);
		}

		return 0;
	}
}

Then your mapping will say something like this

	<set name="bankAccounts" lazy="true" cascade="all,delete-orphan" inverse="true" sort="com.example.BankAccountShortNameComparator">

In this way Hibernate will use your custom Comparator to sort the set

November 10, 2008 Posted by Paras | Hibernate | , , | 10 Comments