Testing Struts actions with Spring dependencies

July 31st, 2008

The main idea of this post is to explain the way to test Struts actions with service dependencies using StrutsTestCase library. In my case all the actions are handled by Spring and the dependencies are injected just before initializing. That is clear that testing the actions in isolation requires bypassing Spring and letting Struts do the inizializing. But this time we have to inject the dependencies before the action is executed.

I can hear you saying, “Hey no problem at all, mock the service and put it into the action”. Yes but what action instance do you have in your hands prior to execution? Yes you don’t. StrutsTestCase library does not provide you the functionality to get your hands on action instance, you only have the ability to invoke the execution of the action instance that will be created somewhere. –not so mystery, we know where the action is initialized– In this case we have got a couple of ways to achive the objective, that’s enough talk for now, lets get our hands dirty.

We have got an action named LoginAction and this action has a service dependency, UserService, and the implementation of this service is injected into the action via Spring.

public class LoginAction extends Action {

  private UserService userService;

  public void setUserService(UserService userService) {
    this.userService = userService;
  }

  public ActionForward execute(ActionMapping mapping, ActionForm form,
      HttpServletRequest request, HttpServletResponse response)
      throws Exception {
    // some logic using userService
    String username = request.getAttribute("username");
    String password = request.getAttribute("password");
    if(userService.login(username, password)) {
      request.getSession().setAttribute("username", username);
      return mapping.findForward("success");
    }
    return mapping.findForward("error");
  }

}

The action given above is a simple action that checks if the login information is correct or not. According to the result returned from the service, the action decides to forward the request to success or error. Let’s write a unit test for this action using STC.

public class LoginActionTest extends MockStrutsTestCase {

  public static Test suite() {
    return new TestSuite(LoginActionTest.class);
  }

  public void testSuccessfulLogin() {
    setRequestPathInfo("/login");
    addRequestParameter("username", "witt");
    addRequestParameter("password", "eyesony");
    actionPerform();
    verifyForward("success");
    assertEquals("witt", getSession().getAttribute("username"));
  }

}

In order to test this action in isolation it is obvious that we have to mock UserService and put it into the action instead of Spring, because if we depend on Spring for this job then this test will not be a unit test. It is also obvious that we have to make changes to web.xml and struts-config.xml in order to bypass Spring. We dont need Spring for dependency injection, we are going to inject mocked versions of dependencies. It is also possible to let Spring do its job, then afterwards to override the objects injected with the mocked versions but this will cause unnecessary longer test times.

Now how can we access to action instance from within MockStrutsTestCase, unfortunately there is no method or so to get action instance. There is however two ways to achive this objective; one not-so-pretty and other one the aop way. First the not-so-pretty way.

  1. MockStrutsTestCase has a public getter method that returns ActionServlet and as you know from Struts api, ActionServlet has a protected getter method that returns RequestProcessor. Finally RequestProcessor has a protected Hashmap for storing action instances. This means that if we get our hands on that protected Hashmap, then we get our hands on the action instances. If you subclass both the ActionServlet and RequestProcessor, technically you can access the action instances. However the action instances are created just before you make the actionPerform() call from MockStrutsTestCase. So you also have to override the processActionPerform() method of RequestProcessor and have to create your mock in that method and inject into the action. The downside of this method is that you have to subclasses RequestProcessor at least one for every different test class you want to write, because every time you propably need different mocks of different services with different expectations.
  2. Second one is the AOP way, we can intercept the Action.execute call and we can get the action instance just before execution by the help of aop. The only thing we have to do is to define a pointcut to capture the action and a before advice that will let us inject our mock into the action instance. I am not going to go into details of writing aspects, if you are not familiar with aop i suggest you to make a search on google before going on reading. I am going to use AspectJ for implementation, it is possible to use different AOP frameworks.

The following is the source code of our aspect.

import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForward;

aspect StrutsActionPreExecuteNotifier {

  // this pointcut selects the test method's execution join point and
  // exposes the current executing test object instance
  pointcut mockStrutsTest(StrutsActionPreExecuteListener actionTest):
    execution(public void StrutsActionPreExecuteListener+.test*())
    && this(actionTest);

  // this pointcut selects the action execution join point. It is combined
  // with the first pointcut using cflow; means the combined scope is limited
  // to the call flow of the action test method.
  pointcut strutsActionExecute(
      Action action, StrutsActionPreExecuteListener actionTest):
    execution(public ActionForward Action+.execute(..))
    && this(action)
    && cflow(mockStrutsTest(actionTest));

  // the before advice that is bound to the previous point cut provides
  // listener's preActionExecuteOccured method to be called passing the
  // the action instance for mock injection.
  before(Action action, StrutsActionPreExecuteListener actionTest):
    strutsActionExecute(action, actionTest) {

    actionTest.preActionExecuteOccurred(action);
  }

}

The following is the interface that our test classes have to implement in order to have opportunity to inject mocked service objects into the action instance under test. If the test classes do not implement this interface then there will be no matching point cut.

import org.apache.struts.action.Action;

public interface StrutsActionPreExecuteListener {

  public void preActionExecuteOccurred(Action action);

}

The source of the modified version of our test class is given below.

public class LoginActionTest extends MockStrutsTestCase
    implement StrutsActionPreExecuteListener{

  public static Test suite() {
    return new TestSuite(LoginActionTest.class);
  }

  public void testSuccessfulLogin() {
    setRequestPathInfo("/login");
    addRequestParameter("username", "witt");
    addRequestParameter("password", "eyesony");
    actionPerform();
    verifyForward("success");
    assertEquals("witt", getSession().getAttribute("username"));
  }

  public void preActionExecuteOccured(Action action) {
    LoginAction lAction = (LoginAction) action;

    // mock the service and put it into the action
    lAction.setUserService(....);
  }

}

There is nothing special about this code, we simply got the action instance, casted it to LoginAction and put our mocked version of UserService into it. In order to mock the service we can implement the service or we can use a mock library –easymock, jmock– in order to mock and set expectations runtime. If you don’t know how to use mock libraries you can have a look at my post on mocking.

If you implement StrutsActionPreExecuteListener interface in your test class, then before the execution of the methods with names starting with ‘test’, the test class’s preActionExecuteOccured method will be called with the appropriate action instance.

You can do what ever you want with the action instance, the execution flow will wait for the method to return. After your preActionExecuteOccured method’s excution finishes, your test method body will start executing. You can have more than one test method but there will be only one preActionExecuteOccured method, so you have to do all the work for different test scenerios in the same method. But this is not so bad after all you do not have to subclass ActionServlet and RequestProcessor.

Using Spring with Axis2

July 26th, 2008

Using Spring with Axis2 is quite straightforward. Because Axis2 is also a web application you can use Spring like the way you use it with any other web application or you can configure Spring only for a particular aar of yours.

As i mentioned, it is quite straightforward. To make your axis service Spring aware and to initialize application context you have to follow the following steps.

  1. Prepeare your services and other beans as if you are using Spring for dependency injection.
  2. Prepeare your applicationContext.xml and put it into somewhere in the classpath of your aar.
  3. Initialize your application context within a service that implements ServiceLifeCycle and register that service as a load-on-startup service in service.xml.
  4. Finally make necessary changes to services.xml.

You can find the details of the steps following.

Prepeare your services using Spring

public class CodesnippetService implements CodesnippetServiceSkeletonInterface {
    //going to make Spring inject these dependencies
    private CodeSnippetGenerator javaGenerator;
    private CodeSnippetGenerator phpGenerator;
    private CodeSnippetGenerator ccGenerator;

    public CodesnippetService() {

    } 

    public void setJavaGenerator(CodeSnippetGenerator javaGenerator) {
        this.javaGenerator = javaGenerator;
    }

    public void setPhpGenerator(CodeSnippetGenerator phpGenerator) {
        this.phpGenerator = phpGenerator;
    }

    public void setCcGenerator(CodeSnippetGenerator ccGenerator) {
        this.ccGenerator = ccGenerator;
    }

.......

Prepeare applicationContext.xml

To make Axis2 hook into Spring’s applicationContext you have to define the first bean. The second bean is your web service and the other beans following is the beans that our web service is dependent to.

	<!-- For axis2 support -->
	<bean id="applicationContext"
		class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" />

	<bean id="codesnippetService"
		class="org.hoydaa.codesnippet.ws.CodesnippetService">
		<property name="javaGenerator" ref="javaGenerator" />
		<property name="phpGenerator" ref="phpGenerator" />
		<property name="ccGenerator" ref="cGenerator" />
		<!-- <property name="javaGenerator" ref="javaGenerator" /> -->
	</bean>

	<bean id="javaProperties"
		class="org.springframework.beans.factory.config.PropertiesFactoryBean">
		<property name="localOverride" value="true" />
		<property name="location" value="classpath:java.properties" />
		<property name="properties">
			<props>
				<prop key="wrappingFilter.factory">
					org.hoydaa.codesnippet.core.filter.doc.SimpleWrappingFilterFactory
				</prop>
				<prop key="wrappingFilter.tagClass">java-snippet</prop>
			</props>
		</property>
	</bean>

	<bean id="javaConfiguration"
		class="org.hoydaa.codesnippet.core.Configuration">
		<constructor-arg ref="javaProperties" />
	</bean>

	<bean id="javaGenerator"
		class="org.hoydaa.codesnippet.core.CodeSnippetGenerator">
		<constructor-arg ref="javaConfiguration" />
	</bean>

...

</beans>

Initialize your application context within another service that implements ServiceLifeCycle.

package org.hoydaa.codesnippet.ws;

import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.engine.ServiceLifeCycle;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringInit implements ServiceLifeCycle {
    public void startUp(ConfigurationContext ignore, AxisService service) {
        ClassLoader classLoader = service.getClassLoader();
        ClassPathXmlApplicationContext appCtx = new ClassPathXmlApplicationContext(
                new String[] { “applicationContext.xml” }, false);
        appCtx.setClassLoader(classLoader);
        appCtx.refresh();
    }

    public void shutDown(ConfigurationContext arg0, AxisService arg1) {

    }
}

Finally make necessary changes to services.xml.

<?xml version="1.0" encoding="UTF-8"?>
<serviceGroup>
	<service name=”SpringInit”
		class=”org.hoydaa.codesnippet.ws.SpringInit”>
		<description>This web service initializes Spring.</description>
		<parameter name=”ServiceClass”>
			org.hoydaa.codesnippet.ws.SpringInit
		</parameter>
		<parameter name=”ServiceTCCL”>composite</parameter>
		<parameter name=”load-on-startup”>true</parameter>
		<operation name=”springInit”>
			<messageReceiver
				class=”org.apache.axis2.receivers.RawXMLINOutMessageReceiver” />
		</operation>
	</service>
	<service name=”CodesnippetService”>
		<messageReceivers>
			<messageReceiver mep=”http://www.w3.org/ns/wsdl/in-out”
				class=”org.hoydaa.codesnippet.ws.CodesnippetServiceMessageReceiverInOut” />
		</messageReceivers>
		<parameter name=”ServiceClass”>
			org.hoydaa.codesnippet.ws.CodesnippetService
		</parameter>
		<parameter name=”useOriginalwsdl”>false</parameter>
		<parameter name=”modifyUserWSDLPortAddress”>true</parameter>
		<parameter name=”ServiceObjectSupplier” locked=”false”>
			org.apache.axis2.extensions.spring.receivers.SpringAppContextAwareObjectSupplier
		</parameter>
		<parameter name=”SpringBeanName” locked=”false”>
			codesnippetService
		</parameter>
		<operation name=”highlight”
			mep=”http://www.w3.org/ns/wsdl/in-out”
			namespace=”http://www.hoydaa.org/codesnippet”>
			<actionMapping>urn:highlight</actionMapping>
			<outputActionMapping>
				urn:highlightResponse
			</outputActionMapping>
		</operation>
	</service>
</serviceGroup>

Injecting Properties using Spring

July 26th, 2008

Every application needs property files to be configured after packaging and Spring offers a flexible way of doing this by injection. You can load property files or create new Properties using Spring’s PropertiesFactoryBean.

PropertiesFactoryBean supports creating Properties by loading from property file or using local configurations in applicationContext or both. The following is an example configuration that uses both methods to create a custom Properties bean.


<bean id="javaProperties"
        class="org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="localOverride" value="true" />
    <property name="location" value="classpath:java.properties" />
    <property name="properties">
        <props>
            <prop key="wrappingFilter.factory">
                    org.hoydaa.codesnippet.core.filter.doc.SimpleWrappingFilterFactory
            </prop>
            <prop key="wrappingFilter.tagClass">java-snippet</prop>
        </props>
    </property>
</bean>

The snippet above creates a bean with id javaProperties by loading a property file on the classpath named java.properties and then overriding the two properties named wrappingFilter.factory and wrappingFilter.tagClass. The default behavior of PropertiesFactoryBean when there are both a properties file to be loaded and the local properties, is to override the local properties by the properties loaded from properties file. In order to change the overriding you have to set localOverride property of the PropertiesFactoryBean to true.

That’s all, you can inject your bean wherever you want:)

Maven2 site plugin

May 23rd, 2008

After struggling some time to set up a proper site configuration with maven2, i decided to write a detailed post to explain maven2-site-plugin. Although it seems routine to set it up, there are some key points that have to be known. Sadly i could not find useful documents (not very strange when the case is some other maven plugin), I even investigated the source code in order to learn these things.

site:deploy

site:deploy goal is the most useful goal amongst others, so i prefer to start explaining site:deploy. I am going to explain using ssh when deploying your generated site docs to remote server. Actually there are two different methods when using ssh to deploy your site automatically–without password prompt i mean–. Either you can specify connection parameters in settings.xml file under M2_HOME directory or you can use private key authentication.

The pom.xml configuration does not differ in either case. You have to include distributionManagement section into your pom.xml.

<distributionManagement>
  <site>
    <id>myserver</id>
    <name>Production Server</name>
    <url>scp://myserver.com/home/witt/myproject/</url>
  </site>
</distributionManagement>

In the first case you have to include your connection information in settings.xml file with same server id you did use in pom.xml as the following.

<servers>
  <server>
    <id>myserver</id>
    <username>witt</username>
    <password>my_password</password>
  </server>
</servers>

That is all, now you can execute mvn site:deploy. If you do not want to include your password in the settings.xml file or your server does not accept password authentication you can choose to use the second way, using private key authentication. In this case you have to include your public key in the servers .ssh/authorized_keys file under your home directory. You can look at this howto to learn setting up ssh connection using private key authentication. This time you don’t have to make any additional configuration, the configuration you did in the pom.xml will be enough.

Configuring the Site Descriptor

This is also another topic partially described on plugins web page. The site descriptor file is an xml file named site.xml and shold be located under the directory src/site. When you want to override the default navigation tree or the layout of the site, you can create your own site descriptor file. A fully configured site.xml file and the description of the configuration options are given below.

<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Name of your project -->
<project name="Maven">

  <!-- You can change the position and the format of the
       last publish date. -->
  <publishDate position="navigation-bottom" format="MM-dd-yy"/>

  <!-- Left banner banner options -->
  <bannerLeft>
    <name>Maven</name>
    <src>http://maven.apache.org/images/apache-maven-project.png</src>
    <href>http://maven.apache.org/</href>
  </bannerLeft>

  <!-- Right banner options -->
  <bannerRight>
    <src>http://maven.apache.org/images/maven-small.gif</src>
  </bannerRight>

  <!-- Other skins can be used to change the look and
       feel of the site. -->
  <skin>
    <groupId>org.apache.maven.skins</groupId>
    <artifactId>maven-stylus-skin</artifactId>
    <version>1.0.1</version>
  </skin>

  <body>

    <!-- Additional links to be displayed on the top of the page -->
    <links>
      <item name="Apache" href="http://www.apache.org/" />
      <item name="Maven 1.x" href="http://maven.apache.org/maven-1.x/"/>
      <item name="Maven 2" href="http://maven.apache.org/"/>
    </links>

    <!-- A custom menu and the contents as relative urls -->
    <menu name="Maven 2.0">
      <item name="Introduction" href="index.html"/>
      <item name="Download" href="download.html"/>
      <item name="Release Notes" href="release-notes.html" />
      <item name="General Information" href="about.html"/>
      <item name="For Maven 1.x Users" href="maven1.html"/>
      <item name="Road Map" href="roadmap.html" />
    </menu>

    <!-- This is replaced by a menu that contains links to
         the generated reports. Alternatively you could use
         ${reports} instead of the following line. -->
    <menu ref="reports"/>

    <!-- This is replaced by a menu that contains links to
         the sites of the other modules under the project.
         Alternatively you could use ${modules} instead of the
         following line. -->
    <menu ref="modules"/>

    <!-- This is replaced by a link to the parent project
         if there is a parent project. -->
    <menu ref="parent"/>

  </body>
</project>

Inversion of Control (IoC) vs Dependency Injection (DI)

May 4th, 2008

When opening this title, my intention was to write a complete article about IoC and DI that clears all the fuss and the confusion about the terms. But i came around a very good article ‘Injection and Inversion‘, about the very same subject that states all the details and the differences between these terms. It is a very-well-written article with good examples, i strongly suggest everyone –who wants to have a clear understanding about the differences between IoC and DI– to read this article.

Sending / Receiving SMS from MIDlets

May 3rd, 2008

Wireless Messaging API is an optional package for Java ME that provides platform-independent access to wireless communication resources like Short Message Service (SMS) and Multimedia Messages (MMS).

With version 1.0 (WMAPI 1.1) of the specification (JSR 120) you can send and receive SMS messages in text or binary format. In version 2.0 (WMAPI 2.0) of the specification (JSR 205) support for multipart messages (MMS) is added.

The Wireless Messaging API (WMAPI) is based on the Generic Connection Framework (GCF). The GCF is defined in the javax.microedition.io package of the Connected Limited Device Configuration (CLDC) 1.0 specification. The package defines an extensible framework for connections and supports input/output and networking functionality in Java Platform Micro Edition profiles.

Since JSR 205, WMAPI supports three type of messages; TextMessage, BinaryMessage and MultipartMessage which are all sub-interfaces of Message. A Message can be thought as an object that has an address and data part.

As defined by the Generic Connection Framework, the message sending and receiving functionality is implemented by a Connection interface, in WMAPI 2.0’s case, MessageConnection. To make a connection, an url is provided for the Connector class, as the Generic Connection Framework offers. In this case the url will be like sms://.

Lets send an SMS now.

//get a reference to the appropriate Connection object using an appropriate url
MessageConnection conn = (MessageConnection) Connector.open("sms://:50001");
//generate a new text message
TextMessage tmsg = (TextMessage) conn.newMessage(MessageConnection.TEXT_MESSAGE);
//set the message text and the address
tmsg.setPayloadText(message);
tmsg.setAddress("sms://" + number);
//finally send our message
conn.send();

Time to receive one;

//get reference to MessageConnection object
MessageConnection conn = (MessageConnection) Connector.open("sms://:50001");
//set message listener
conn.setMessageListener(
new MessageListener() {
public void notifyIncomingMessage(MessageConnection conn) {
Message msg = conn.receive();
//do whatever you want with the message
if(msg instanceof TextMessage) {
TextMessage tmsg = (TextMessage) msg;
System.out.println(tmsg.getPayloadText());
} else if(msg instanceof BinaryMessage) {
.....
} else {
......
}
}
}
);

Now assume that we wrote a full application in order to send and receive SMS, but how can we test. Do we actually deploy it to our phone and test there? It is time to get help from Java Wireless Toolkit. It is possible to send and receive SMS messages when testing our application in the emulator.

  • Create new project using KToolbar utility.
  • Place your source files under src folder in the project directory.
  • Enable Wireless Messaging API under Project->Settings->API Selection.
  • Run your application.
  • Open WMA console under File->Utilities->Open Console(WMA).
  • Both the emulator and your phone will have numbers. Use those numbers to send and receive SMS in order to test your application.

To avoid potential deadlock, operations that may block, such as networking…

May 3rd, 2008

To avoid potential deadlock, operations that may block, such as networking, should be performed in a different thread than the commandAction() handler.

This is an error printed by KToolbar console when you try you run your application. You get this error when you try to execute networking releated operations in the commandAction method of your CommandListener. The same code will execute on your phone without problems, but when you try to run the same code in the emulator, KToolbar will print this warning and emulator will stop running. This is because that the network related operations take some time to operate and may block your current thread’s execution. In order to avoid this situation, you have to run your network related code in another thread. You can use the following code block to run your network related operation.

new Thread(new Runnable(){
public void run() {
// Put your code here
}
});

But more professional and production-ready approach will be to implement a threaded CommandListener object –probably using only one thread to manage all the command calls, in order to preserve cpu– and to use this CommandListener instead of the default CommandListener provided by MIDP.

What is BadgerFish?

May 3rd, 2008

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. Yes i stole this line:)

Yes it is a lightwight data-interchange format, yes it is a replacement for XML where communication speed becomes important –like AJAX calls–, but it has also have some certain limitations when compared to XML.

JSON can represent two things. name-value pairs and arrays. You can think that you can represent an XML document using this two data structures, but in fact you simply CANNOT. What about elements with attributes and text nodes. What about namespaces. Lets have a look at the following samples.

XML: <book>King Lear</book>
JSON: {book: 'King Lear'}

This was easy, what about the following one.

XML: <book country="uk">King Lear</book>
JSON: {book: {'country': 'uk'}

Ok now where will the text node go? And also how do we know afterwards that the country is an attribute not an another element. There is not a notation for this kinda stuations, but Badgerfish JSON notation have some suggestions.

XML: <book country="uk">King Lear</book>
JSON: {book: {'$': 'King Lear', '@country': 'uk'}

As you can see from the notation, attributes have ‘@’ character before label and the text nodes are represented with ‘$’ label.

Generally speaking we can say that, BadgerFish is a convention for translating an XML document into a JSON object.

See Badgerfish site for further information. There is a small list of 9 items that explains all of the conventions.

Floating point operations in CLDC 1.0

May 3rd, 2008

As you all already know there is no float and double data types in CLDC 1.0 because of limited device configurations. If you really need to do floating point calculations then you have to do this calculations using fixed-point arithmetics. Don’t panic, you do not have to do this on your own. There are some open source fixed-point arithmetic libraries for CLDC 1.0.

  • The first one is Nikolay Klimchuk’s henson.midp.Float library. Compiled class is about 14 kilobytes
  • The second one is Roar Lauritzsen’s ral.Real library. Compiled class is about 52 kilobytes

Actually there is not much of a choice here, because the second library, ‘ral.Real’ is much more faster than the first one ‘henson.midp.Float’. The only advantage of the first library is the size, if you really out of space and need a smaller library than maybe it should be your choice. ‘ral.Real’ library have a lot other mathematical and utility functions also have a number formatter and it can be very useful especially bacause we are dealing with CLDC -there is no formatter-.

The following is a detailed runtime comparison results obtained using a nokia e65, the decision is yours.

henson.midp.Float ral.Real
run#1 run#2 run#3 run#4 run#5 avg run#1 run#2 run#3 run#4 run#5 avg
sin(ms) x 100 times 135 129 130 129 122 129 7 6 7 6 7 6,6
cos(ms) x 100 times 144 138 138 138 142 140 8 6 6 7 8 7
tan(ms) x 100 times 244 245 238 245 243 243 12 13 14 14 12 13
add(ms) x 10000 times 151 149 154 149 150 150,6 51 52 47 48 48 49,2
mul(ms) x 10000 times 190 190 186 186 190 188,4 46 51 49 45 45 47,2
div(ms) x 10000 times 619 618 620 621 617 619 40 41 40 44 43 41,6
sqrt(ms) x 1000 times 599 598 595 598 597 597,4 27 26 27 28 27 27
total(ms) 2067,4 191,6
henson/real 10,79

You can download the tester midlet and test on your phone or you can download the WTK project and see the source code of the midlet.

FixedPointTest.jar

FixedPointTest.jad

FixedPointTest WTK Project

Downloading sources of dependencies in maven

May 2nd, 2008

There are two ways for downloading sources of maven dependencies. One way is to pass a command line parameter to maven like the following;

-Declipse.downloadSources=true

The other way is to set this option in the pom.xml under the configuration section of eclipse plug in like the following.

<plugin>
  <artifactid>maven-eclipse-plugin</artifactid>
  <version>2.4</version>
  <configuration>
    <downloadsources>true</downloadsources>
  </configuration>
</plugin>

Also you can set the same options for javadocs, for command line use -Declipse.downloadJavadocs=true, for pom.xml use <downloadjavadocs>true</downloadjavadocs>