Thursday, 22 March 2012

RestTemplate and Spring MVC

This post is a follow up to the Spring MVC and RESTful Web Services post and shows a simple example of using Spring's RestTemplate class for client side access to, in this case, the Spring MVC RESTful web service built in the aforementioned post.

The RestTemplate class is, as it's javadoc describes, "the central class for client-side HTTP access. It simplifies communication with HTTP servers, and enforces RESTful principles. It handles HTTP connections, leaving application code to provide URLs (with possible template variables) and extract results."

In this example, we'll only be using the GET HTTP method (as that is all we have on our MVC example!) but the idea will be pretty much the same for other methods.

First, the Spring config and the XML below lists three beans. The Jaxb2Marshaller bean lists the classes that the JAXBContext needs to be aware of. This bean is then in turn injected into the MarshallingHttpMessageConverter as the marshaller and unmarshaller so Objects can be converted to and from an XML Stream. (Note that by default the MarshallingHttpMessageConverter supports text/xml and application/xml.) For this example, the message converter is the only entry in the list set on the RestTemplate bean. Finally, the RestTemplate bean is injected into the ExampleControllerClient bean.


<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans.xsd">

 <bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
  <property name="classesToBeBound">
   <list>
    <value>com.city81.spring.mvc.rest.domain.Message</value>
   </list>
  </property>
 </bean>

 <bean id="restTemplate" class="org.springframework.web.client.RestTemplate">    
  <property name="messageConverters">    
   <list>      
    <bean id="messageConverter"            
     class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">        
     <property name="marshaller" ref="jaxbMarshaller" />        
     <property name="unmarshaller" ref="jaxbMarshaller" />    
    </bean>    
   </list>    
  </property>  
 </bean>

 <bean id="exampleControllerClient" class="com.city81.spring.mvc.rest.ExampleControllerClient">
  <constructor-arg ref="restTemplate" />
 </bean>

</beans> 


The ExampleControllerClient class below shows how simple it is to make a RESTful web service call:

package com.city81.spring.mvc.rest;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.client.RestTemplate;
import com.city81.spring.mvc.rest.domain.Message;

public class ExampleControllerClient {

 private RestTemplate restTemplate;

 public ExampleControllerClient(RestTemplate restTemplate) {
  this.restTemplate = restTemplate;
 }

 public void getMessage() {

  Message message = restTemplate.getForObject(
   "http://localhost:8080/spring-rest-0.0.1-SNAPSHOT/example/controller/message", 
   Message.class); 
  System.out.println(message.getMessageString());
 }

 public static void main(String[] args) {

  ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
          new String[] {"applicationContext.xml"});
  BeanFactory factory = (BeanFactory) appContext;
  ExampleControllerClient client = (ExampleControllerClient) factory
    .getBean("exampleControllerClient");
  client.getMessage();

 }

}


The getForObject method takes a URL and the type of the response object and retrieves a representation by doing a GET on the URL arg. This method is overloaded and can be used for different URLs. For example, if there are URI templates in the URL, then these can be populated by a third arg of a Map containing a collection of name value pairs or by using varargs.


public  T getForObject(String url,
                          Class responseType,
                          Object... urlVariables)
               throws RestClientException

public  T getForObject(String url,
                          Class responseType,
                          Map urlVariables)
               throws RestClientException


Back to the example and when the getForObject call is invoked, the JAXB marshaller behind the scenes will convert the XML into a Message object. An alternative to using the Jaxb2Marshaller  is the XStreamMarshaller. To swap JAXB for XStream would just be a Spring XML change as shown below:


<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">    
   <property name="aliases">    
    <props>      
     <prop key="message">com.city81.spring.mvc.rest.domain.Message</prop>    
    </props>    
   </property>  
  </bean>

...
     <property name="marshaller" ref="xstreamMarshaller" />        
     <property name="unmarshaller" ref="xstreamMarshaller" /> 
...


There are many different marshallers to achieve the same goal, and indeed many different media types with different marshallers. This post barely scratches the surface but just shows how simple it is to create client side code for calling a RESTful web service.

Tuesday, 31 January 2012

Parallel Processing with ForkJoinPool

With the release of Java 7 came the new Executor Service, ForkJoinPool. The class uses the notion of work-stealing threads which execute tasks which have been created by other tasks. Ultimately, this division of work will result in large problems becoming a series of smaller ones which will eventually result in one answer when all the tasks have completed their processing.

This post will demonstrate this new threading feature by an interpolation example. In this case, for two numbers with a given number of steps, the code will attempt to construct new points between those numbers using linear interpolation, and for simplicity using only a number of steps divisible by 2. eg for the numbers 5 and 25 with a step number of 4, the generated sequence would be:

[5.0, 10.0, 15.0, 20.0, 25.0]

The InterpolationService class below will contain an instance of the ForkJoinPool class. A ForkJoinPool instance can be created with an argument representing a target parallelism. This can either be supplied or left as the default which will be the number of processors ie  Runtime.availableProcessors()

package com.city81.forkjoin;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;

public class InterpolateService {

    private final ForkJoinPool forkJoinPool;

    public InterpolateService() {
        forkJoinPool = new ForkJoinPool();
    }

    public List<Double> interpolate(double valueOne, double valueTwo, int steps) {
        
        ForkJoinTask<List<Double>> job = forkJoinPool.submit(
            new InterpolateTask(valueOne, valueTwo, steps));
        return job.join();
    }

    private static class InterpolateTask 
        extends RecursiveTask<List<Double>> {

        private final double valueOne;
        private final double valueTwo;
        private final int steps;
        private static final int LOWEST_STEP = 2;

        protected InterpolateTask(double valueOne, double valueTwo, int steps) {

            this.valueOne = valueOne;
            this.valueTwo = valueTwo;
            this.steps = steps;
        }

        @Override
        protected List<Double> compute() {
    
            List<Double> interpolatedArray = new ArrayList<Double>();
            double interpolatedValue = interpolate(valueOne, valueTwo);
    
            if (this.steps == LOWEST_STEP) {
                interpolatedArray.add(valueOne);
                interpolatedArray.add(interpolatedValue);
                interpolatedArray.add(valueTwo);
            } else {
                InterpolateTask interpolateTask1 = 
                    new InterpolateTask(valueOne, interpolatedValue, (steps/2));
                interpolateTask1.fork();
                InterpolateTask interpolateTask2 = 
                    new InterpolateTask(interpolatedValue, valueTwo, (steps/2));
                List<Double> interpolatedArrayTask2 = 
                    interpolateTask2.compute();
                List<Double> interpolatedArrayTask1 = 
                    interpolateTask1.join();
                interpolatedArray.addAll(
                    interpolatedArrayTask1.subList(0, interpolatedArrayTask1.size() - 1));
                interpolatedArray.addAll(interpolatedArrayTask2);
            }
            // System.out.println(interpolatedArray);
            return interpolatedArray;
        }

        private double interpolate(
            double valueOne, double valueTwo) {
   
            return ((valueTwo - valueOne) / 2.0) + valueOne;
        }

    }

    public static void main(String[] args) {
        InterpolateService interpolateService = new InterpolateService();
        List<Double> interpolatedArray = interpolateService.interpolate(5,25,4);
        System.out.println(interpolatedArray);
    }

}

The InterpolationService 's only public method interpolate, takes two numbers and the number of steps. These are the parameters to construct an instance of our private static class InterpolateTask. This class implements RecursiveTask which can return a result when the compute method is called on the task. An alternative implementation (but not suitable for this example) would be RecursiveAction whose compute method returns nothing.

The constructed task is submitted to the ForkJoinPool.

The compute method is where the logic for subdividing the task resides. It decides whether the work it has to process is small enough to process now or whether it needs further division. In the case of our example, the task will determine a task small enough when the step size is 2. If not, it will create two sub tasks, dividing the step size each time.

Eventually, all tasks will be of a small enough size to be completed. This will result in the arrays being added together as the recursive task tree is traversed back up to the original task.

This is not example of how to efficiently perform linear interpolation on a set of numbers but is just one example implementation of how to use the ForkJoinPool and its associated Task classes. Over time, hopefully this post can be updated to make the above code more efficient as well gathering metrics and benchmarking against other implementations.

Friday, 27 January 2012

Spring MVC and RESTful Web Services

This post is a follow up to the Spring MVC Bare Essentials post and shows how a simple RESTful web service can be implemented using Spring MVC. It'll also show the different ways in which the controller services can be implemented and how the model can be rendered.

The post will use the same classes and XML files as in the Bare Essentials post but change them to make the methods expoed by the controller RESTful.

First of all, the ExampleController class will change to use web bind annotations which will mark the class and the methods within it with URL paths.

@Controller
@RequestMapping("/controller")
public class ExampleController {

    @RequestMapping(value="message", method=RequestMethod.GET)

    public ModelAndView getMessage() {
        Message message = new Message("Spring MVC Rest Example");
        ModelAndView modelAndView = new ModelAndView(
            "example", "message", message);
        return modelAndView;
    }

}


The web.xml below shows the changes to the servlet mapping tag and in particular the url-pattern. This means our URLs will be:

http://<ip>:<port>/<app name>/example/<request mapping>

<servlet-mapping>
    <servlet-name>springMVCRESTExample</servlet-name>
    <url-pattern>/example/*</url-pattern>
</servlet-mapping>


In the servlet's context XML file, we'll auto detect the ExampleController bean by using context:component-scan and then add the BeanNameViewResolver to interpret a view name as a bean name. Finally, add a MarshallingView which will use JAX-B to marshall and unmarshall the com.city81.spring.mvc.rest.domain.Message class.

<context:component-scan base-package="com.city81.spring.mvc.rest" /> 

<bean class="org.springframework.web.servlet.view.BeanNameViewResolver" />

<bean id="example" class="org.springframework.web.servlet.view.xml.MarshallingView">
    <constructor-arg>
        <bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
            <property name="classesToBeBound">
                <list>
                    <value>com.city81.spring.mvc.rest.domain.Message</value>
                </list>
            </property>
        </bean>
    </constructor-arg>
</bean>


Building a WAR and deploying to a container such as Tomcat would then enable you call the getMessage method of the ExampleController class with the URL:

http://<ip>:<port>/<app name>/example/controller/message

An alternative to implementing the getMessage method is to use the @ModelAttribute instead the the ModelView class as shown below:

@RequestMapping(value = "message", method = RequestMethod.GET)
public @ModelAttribute("example") Message getMessage() {
    Message message = new Message("Spring MVC Rest Example");
    return message;
}


Another alternative is to use <mvc:annotation-driven /> which was introduced in Spring 3. By adding it to the servlet's context XML file (in place of the beans BeanNameViewResolver and MarshallingView), the getMessage method can then be implemented as show below:

@RequestMapping(value="message", method = RequestMethod.GET)
public @ResponseBody Message getMessage() {
    Message message = new Message("Spring MVC Rest Example");
    return message;
}


This is a very simple example that can be built upon to use different RESTful methods. There are also different ways in which XML can be rendered in the view and also different types that can be rendered eg text. It is also worth considering Spring Roo if wanting to implement a RESTful web service. These will hopefully be covered in further posts.

Thursday, 19 January 2012

Using Maven to Generate Wrapped or Non-Wrapped SOAP Bindings

For a given WSDL, there are several different ways to generate Java web service code (CXF, Axis2, etc..). And depending on certain settings within the WSDL file and settings used by the relevant build tool, there are different ways of exposing those services described in the WSDL.

This post will briefly document the generating of Java code for a WSDL using Maven and the jaxws wsimport plugin. It will also show the difference in the services exposed when using wrapped and non-wrapped bindings.

Below is an extract from a pom.xml to generate the Java code:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxws-maven-plugin</artifactId>
    <version>1.10</version>
    <executions>
        <execution>
            <goals>
                <goal>wsimport</goal>
            </goals>
            <configuration>
                <wsdlFiles>
                    <wsdlFile>City81SOAPService.wsdl</wsdlFile>
                </wsdlFiles>
                <bindingDirectory>${basedir}/src/wsdl</bindingDirectory>
            </configuration>
            <id>generate-sources</id>
            <phase>generate-sources</phase>
        </execution>
    </executions>
    <dependencies>
         .........            
    </dependencies>
    <configuration>
        <sourceDestDir>
            ${project.build.directory}/generated-sources/jaxws-wsimport
        </sourceDestDir>
        <xnocompile>true</xnocompile>
        <verbose>true</verbose>
        <extension>true</extension>
        <catalog>${basedir}/src/jax-ws-catalog.xml</catalog>                  
    </configuration>
</plugin>


For the below WSDL file, the wsimport plugin will generate the following classes:

com\city81\soap\Balance.java
com\city81\soap\City81SOAP.java
com\city81\soap\City81SOAPImplService.java
com\city81\soap\CreateCustomer.java
com\city81\soap\CreateCustomerResponse.java
com\city81\soap\CreateCustomerResponseType.java
com\city81\soap\CreateStatus.java
com\city81\soap\ObjectFactory.java
com\city81\soap\package-info.java


<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions name="City81SOAPService" targetNamespace=http://soap.city81.com/ xmlns:ns1=http://schemas.xmlsoap.org/wsdl/soap/http
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://soap.city81.com/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <wsdl:types>
        <xsd:schema>
            <xsd:import namespace="http://soap.city81.com/" schemaLocation="City81SOAPService.xsd" />
        </xsd:schema>
    </wsdl:types>

    <wsdl:message name="createCustomer">
        <wsdl:part name="params" element="tns:createCustomer"></wsdl:part>
    </wsdl:message>
    <wsdl:message name="createCustomerResponse">
        <wsdl:part name="params" element="tns:createCustomerResponse"></wsdl:part>
    </wsdl:message>

    <wsdl:portType name="City81SOAP">
        <wsdl:operation name="createCustomer">
            <wsdl:input message="tns:createCustomer"></wsdl:input>
            <wsdl:output message="tns:createCustomerResponse"></wsdl:output>
        </wsdl:operation>
    </wsdl:portType>

    <wsdl:binding name="City81SOAPImplServiceSoapBinding" type="tns:City81SOAP">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
        <wsdl:operation name="createCustomer">
            <soap:operation soapAction="http://soap.city81.com/createCustomer" />
            <wsdl:input>
                <soap:body use="literal" />
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal" />
            </wsdl:output>
        </wsdl:operation>
    </wsdl:binding>

    <wsdl:service name="City81SOAPImplService">
        <wsdl:port binding="tns:City81SOAPImplServiceSoapBinding" name="City81SOAPImplPort">
            <soap:address location=http://localhost:8080/city81-soap/soap />
        </wsdl:port>
    </wsdl:service>

</wsdl:definitions>


For the above settings, the generated City81SOAP class will be as below:

@WebService(name = "City81SOAP", targetNamespace = "http://soap.city81.com/")
@SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
@XmlSeeAlso({
    ObjectFactory.class
})
public interface City81SOAP {

    @WebMethod(action = "http://soap.city81.com/createCustomer")
    @WebResult(name = "createCustomerResponse", targetNamespace = "http://soap.city81.com/", partName = "params")
    public CreateCustomerResponse createCustomer(@WebParam(name = "createCustomer", targetNamespace = "http://soap.city81.com/", partName = "params") CreateCustomer params);

}


The binding style as can be seen from the @SOAPBinding annotation  at the head of the class is BARE ie non-wrapped. The method's args and return parameters are in each case represented as a single Java object. CreateCustomer and CreateCustomerResponse.

This has happened because in the pom.xml file, there is a bindingDirectory tag which points to a folder containing a binding.xml file. This file, shown below, has an enableWrapperStyle tag and the boolean value of false.

<bindings
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    wsdlLocation="City81SOAPService.wsdl"
    xmlns="http://java.sun.com/xml/ns/jaxws">
        <!-- Disable default wrapper style -->
        <enableWrapperStyle>false</enableWrapperStyle>        
</bindings>


If the boolean was true, or if there was no bindingDirectory tag in the pom.xml file, then the default SOAP binding style would be used ie WRAPPED. This would then result in the below generated City81SOAP class:

@WebService(name = "City81SOAP", targetNamespace = "http://soap.city81.com/")
@XmlSeeAlso({
    ObjectFactory.class
})
public interface City81SOAP {

    @WebMethod(action = "http://soap.city81.com/createCustomer")
    @RequestWrapper(localName = "createCustomer", targetNamespace = "http://soap.city81.com/", className = "com.city81.soap.CreateCustomer")
    @ResponseWrapper(localName = "createCustomerResponse", targetNamespace = "http://soap.city81.com/", className = "com.city81.soap.CreateCustomerResponse")
    public void createCustomer(

        @WebParam(name = "surname", targetNamespace = "")
        String surname,
        @WebParam(name = "firstName", targetNamespace = "")
        String firstName,
        @WebParam(name = "balance", targetNamespace = "")
        Balance balance,
        @WebParam(name = "customerId", targetNamespace = "", mode = WebParam.Mode.OUT)
        Holder<String> customerId,
        @WebParam(name = "status", targetNamespace = "", mode = WebParam.Mode.OUT)
        Holder<CreateStatus> status);

}


The method's args are now individual Java objects and the return parameters are each represented as Holder objects with a WebParam.Mode.OUT value denoting they are return objects. This means that return objects are set as opposed to actually being returned in the method's signature.

Another way to specify bindings other than using the binding.xml file is to embed the enableWrapperStyle as a child of the portType but if a WSDL is from a third party, then having to change it every time a new version of the WSDL is released is open to errors.

<wsdl:portType name="City81SOAPImplService">
    <jaxws:bindings xmlns:jaxws="http://java.sun.com/xml/ns/jaxws">
        <jaxws:enableWrapperStyle>false</jaxws:enableWrapperStyle>
    </jaxws:bindings>
    ...
</wsdl:portType>


Back to the generated interfaces, and these of course need to be implemented. For an interface with a binding type of BARE, the implemented class would look like below:

@WebService(targetNamespace = "http://soap.city81.com/", name = "City81SOAP", portName = "City81SOAPImplPort", serviceName = "City81SOAPImplService")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL, parameterStyle = SOAPBinding.ParameterStyle.BARE)
public class City81SOAPImpl implements City81SOAP {    

    @Override   
    public CreateCustomerResponse createCustomer(CreateCustomer createCustomer) {      
        CreateCustomerResponse createCustomerResponse = 
            new CreateCustomerResponse();     
         .....
        return createCustomerResponse;  
    } 
}


In the case of WRAPPED binding style, the SOAPBinding annotation would include parameterStyle = SOAPBinding.ParameterStyle.WRAPPED and the createCustomer method would be as below:
 

    public void createCustomer(
        String surname,
        String firstName,
        Balance balance,
        Holder<String> customerId,
        Holder<CreateStatus> status) {
    
        customerId= new Holder<String>("1");
        status = new Holder<CreateStatus>(CreateStatus.CREATE_PENDING);
    }   


This post shows that there are different ways to ultimately achieve the same result.
 

Tuesday, 29 November 2011

JAX-WS, JAXB and Generics

When  JAXB 2.1 came along it introduced a new annotation namely @XmlSeeAlso. It resolved the problem where at runtime, JAX-WS would only know about classes bound by JAXB and not sub classes of those which have been bound.

By using @XmlSeeAlso on a class, sub types of the bound class can be listed thereby allowing them to be bound also and therefore reachable by JAX-WS when marshalling and unmarshalling.

It can also be used to overcome the problem of using generics in a JAXB annotated class as the following simple example will describe. Given the below LogFile class, it will only be marshalled/unmarshalled if the T at runtime is bound.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class LogFile<T> {

    @XmlElement(name="logFileLine")
    private List<T> logFileLines;

    public LogFile() {
        logFileLines = new ArrayList<T>();
    }

    public LogFile(List<T> logFileLines) {
        this.logFileLines = logFileLines;
    }

    public List<T> getLogFileLines() {
        return logFileLines;
    }

    public void setLogFileLines(List<T> logFileLines) {
        this.logFileLines = logFileLines;
    }

    public void addLogFileLine(T logFileLine) {
        this.logFileLines.add(logFileLine);
    }

}


If LogFile contains a collection of eg Strings then this will work fine but if T is a class not bound, eg com.city81.domain.LogLine then an error similar to below will be thrown:

javax.xml.bind.MarshalException - with linked exception: [javax.xml.bind.JAXBException: class com.city81.domain.LogLine nor any of its super class is known to this context.]

To resolve this, the class LogLine needs to be included the @XmlSeeAlso annotation.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso(LogLine.class)
public class LogFile<T> {

    ....

}


This does of course mean you need to know what potential classes can be T before runtime but at least it means you can use Generics on JAXB annotated classes.

Thursday, 17 November 2011

Using Spring Expression Language for Server Specific Properties

Spring 3.0 introduced Spring Expression Language (SpEL). This post will describe how to use SpEL to load property files which are different for each server your application runs on. It also describes how server specific properties can used without having to use -D.

The problem solved was how can a WAR be deployed onto different servers without having to package up a server specific property file in each archive (or indeed bundle them all in the same WAR file.) Ideally, you would want to drop the WAR file into any environment without having to configure the container or amend the WAR, and if you wanted to change a property, you would change the property file on the server and redeploy the app (or dynamically refresh the cache of properties.)

In this example, our application needs to access a different remote server registry for each env: Dev, Test and Prod. (For ease in this example, our server names are the same as our envionments!)

Therefore we have a properties file for each env/server (dev.properties, test.properties and prod.properties). Could have a local.properties file on each server but prefixing them with a server name helps distinguish them. An example property file is shown below:

rmiRegistryHost=10.11.12.13
rmiRegistryPort=1099

We have a bean which requires these properties, so it's constructor args contain property placeholders:

<bean id="lookupService" class="com.city81.rmi.LookupService" scope="prototype">
  <constructor-arg index="0" value="${rmiRegistryHost}" /> 
  <constructor-arg index="1" value="${rmiRegistryPort}" />
</bean>


For the above bean to be loaded, the properties need to be loaded themselves and this is done via the PropertyPlaceholderConfigurer class. The location and name of the server specific property file is added as one of the locations the configurer uses to search for properties.

The file is in the same location on each server but in order to know what the name is, SpEL is used. By creating a java.net.InetAddress bean, we can access the hostName of the server the application is running on by using SpEL ie #{inetAddress.hostName}. Therefore, this config doesn't have to change between environments.

<bean id="inetAddress" class="java.net.InetAddress" factory-method="getLocalHost">
</bean>
    
<bean id="propertyBean" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="ignoreResourceNotFound" value="false"/>
    <property name="ignoreUnresolvablePlaceholders" value="false"/>
    <property name="locations">
        <list>
            <value>file:/home/city81/resources/#{inetAddress.hostName}.properties</value>
        </list>
    </property>
</bean>


This is a very specific example where the property files are prefixed with the server names but it shows how SpEL can be used to solve a problem which would have taken a lot more work pre Spring 3.0.

Wednesday, 16 November 2011

Spring MVC - A Bare Essentials Example Using Maven

Spring's MVC is a request based framework like Struts but it clearly separates the presentation, request handling and model layers.

In this post, I'll describe how to get the most simple of examples up and running using Maven, therefore providing a basis upon which to add more features of Spring MVC like handler mappings, complex controllers, commons validator etc..

Let's start with the pom.xml file. This will package up the project as a war file and only requires three dependencies namely the artifacts spring-webmvc, servlet-api and jstl. The spring-webmvc artifact will pull in all the other required spring jars like core, web, etc.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.city81</groupId>
    <artifactId>spring-mvc</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>2.1-beta-1</version>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>3.0.5.RELEASE</version>
            <optional>false</optional>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>
</project> 


Note that the scope of the servlet-api is provided and therefore excluded from the war file. If deployed as part of the war, there'll be conflict with the servlet jar of the container, and there'll be an error similar to the one below when deploying to Tomcat:

INFO: Deploying web application archive spring-mvc-0.0.1-SNAPSHOT.war
15-Nov-2011 16:05:27 org.apache.catalina.loader.WebappClassLoader validateJarFile
INFO: validateJarFile(C:\apache-tomcat-6.0.33\webapps\spring-mvc-0.0.1-SNAPSHOT\WEB-INF\lib\servlet-api-2.5.jar) - jar not loaded. See Servlet Spec 2.3, section
 9.7.2. Offending class: javax/servlet/Servlet.class


Next the web.xml located in the /webapp/WEB-INF folder:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 version="2.5">

    <display-name>Spring MVC Example</display-name>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>springMVCExample</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>springMVCExample</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>home.jsp</welcome-file>
    </welcome-file-list>

</web-app>

The context loader is a listener class called ContextLoaderListener. By default this will load the config in the /WEB-INF/applicationContext.xml but you can specify more files by adding a contextConfigLocation param and list one or more xml files. For example,


    contextConfigLocation    /WEB-INF/example-persistence.xml
        /WEB-INF/example-security.xml


If an applicationContext.xml file isn't present when not using a context param list, then the WAR won't deploy properly. An example empty applicationContext.xml is below:

<?xml version="1.0" encoding="UTF-8"?>
<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"
 xsi:schemaLocation="http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/util 
    http://www.springframework.org/schema/util/spring-util.xsd
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/aop    
    http://www.springframework.org/schema/aop/spring-aop.xsd">

</beans>


The servlet's configuration does not need to be explicitly specified as it can be loaded by following the same naming convention of the servlet, in this case springMVCExample-servlet.xml. The servlet is the front controller which delegates requests to other parts of the system.

The servlet-mapping tags in the web.xml denote what URLs the DispatcherServlet will handle. In this example HTML.

Also included in the web.xml by way of the welcome-file, is a default home page. This doesn't have to be included but the page can be used to forward a request as can be seen later in the post.

As mentioned previously, the servlet's config is in it's own XML file. This describes the mapping between the a URL and the Controller which will handle the request. It also contains the a ViewResolver which maps the view name in the ModelAndView to an actual view. The springMVCExample-servlet.xml is shown below:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean name="/example.htm" class="com.city81.spring.mvc.ExampleController">
    </bean>

    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/jsp/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property> 
    </bean>

</beans>


The ExampleController class is shown below. It extends AbstractController therefore must implement the method handleRequestInternal(HttpServletRequest request, HttpServletResponse response). The return value of this method is a ModelAndView object. This object is constructed by passing in the view name (example), the model name (message) and the model object (in this case a String)

package com.city81.spring.mvc;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

public class ExampleController extends AbstractController {
  
    protected ModelAndView handleRequestInternal(
        HttpServletRequest request, HttpServletResponse response) 
            throws Exception {
        ModelAndView modelAndView = new ModelAndView("example", "message", "Spring MVC Example");

        return modelAndView;
    }

}


The view jsp will then have the ${message} value populated by the model object from the ModelAndView. The example.jsp is below and resides in the /webapp/WEB-INF/jsp folder:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
    <head>
        <title>Spring MVC Example</title>
    </head>
    <body>
        <h2>Welcome to the Example Spring MVC page</h2>
        <h3>The message text is:</h3>
        <p>${message}</p>
    </body>
</html>


As mentioned previously, a default home page can included in the web.xml and instead of displaying html etc., it can be used to redirect requests to another URL. The below home.jsp redirects requests to example.htm:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:redirect url="/example.htm"/>


Deploying the above to a container like Tomcat should result in a page like the following:



This is just the very basics of Spring MVC but later posts, will expand on the framework and show how it can be used with, for example, web services like REST.