Skip to content

Posts tagged ‘JEE’

25
Apr

Spring Integration RSS Feed Reader

Introduction

This article describes the process for implementing an RSS Feed Reader in your application using the Spring Integration framework in combination with Spring 3.

The Spring Integration framework supports Enterprise Integration Patterns which are a common vocabulary and body of knowledge around asynchronous messaging architectures used to build integration solutions. Spring Integration enables lightweight messaging within Spring-based applications and supports integration with external systems via declarative adapters.

Inbound Channel Adapter

RSS feeds are processed using an Inbound Channel Adapter which is bound to a URL. The channel is configured to poll against the URL on a periodic basis (set as milliseconds) and process incoming messages with a payload in the format of a com.sun.syndication.feed.synd.SyndEntry instance. A service activator is configured to bind the channel to a message handler which implements the org.springframework.integration.core.MessageHandler interface to process the incoming message.

Maven project

I have specified Spring Integration and Rome dependencies in the Maven POM file to support processing of RSS feeds. The Rome dependency contains classes and interfaces in the com.sun.syndication package.

<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>
	<parent>
		<artifactId>feedchannel</artifactId>
		<groupId>net.comdynamics.feedchannel</groupId>
		<version>0.1-SNAPSHOT</version>
	</parent>
	<artifactIdrfeedchannel-core</artifactId>
	<packaging>jar</packaging>
	<name>rssreader Core</name>
	<description>feedchannel - Core Module</description>
    <dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-oxm</artifactId>
			<version>${spring.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-asm</artifactId>
			<version>${spring.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aspects</artifactId>
			<version>${spring.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>${spring.version}</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>2.5</version>
		</dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.0.4</version>
        </dependency>
        <dependency>
            <groupId>rome</groupId>
            <artifactId>rome</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>rome</groupId>
            <artifactId>rome-fetcher</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
			<groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-core</artifactId>
            <version>2.0.3.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-feed</artifactId>
            <version>2.0.3.RELEASE</version>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<artifactId>maven-assembly-plugin</artifactId>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>single</goal>
						</goals>
						<configuration>
							<descriptorRefs>
								<descriptorRef>jar-with-dependencies</descriptorRef>
							</descriptorRefs>
                            <archive>
                                <manifest>
                                    <mainClass>net.comdynamics.feedchannel.RSSReader</mainClass>
                                </manifest>
                            </archive>
						</configuration>
					</execution>
				</executions>
			</plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>net.comdynamics.feedchannel.RSSReader</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.dstovall</groupId>
                <artifactId>onejar-maven-plugin</artifactId>
                <version>1.4.4</version>
                <executions>
                    <execution>
                        <configuration>
                            <!-- Optional -->
                            <onejarVersion>0.97</onejarVersion>
                            <!-- Optional, default is false -->
                            <attachToBuild>true</attachToBuild>
                            <!-- Optional, default is "onejar" -->
                            <classifier>onejar</classifier>
                        </configuration>
                        <goals>
                            <goal>one-jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <pluginRepositories>
        <pluginRepository>
            <id>onejar-maven-plugin.googlecode.com</id>
            <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
        </pluginRepository>
    </pluginRepositories>
</project>

The application will be packaged using One-JAR to create a standalone Java application containing dependent libraries in a single executable JAR file.

Spring Application Context

The Spring application context specifies the Inbound Channel Adapter and a URL to subscribe against, the Service Activator, and a Message Handler for processing incoming RSS message payload.

<?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:context="http://www.springframework.org/schema/context"
	xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:int-feed="http://www.springframework.org/schema/integration/feed"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
		http://www.springframework.org/schema/integration/feed http://www.springframework.org/schema/integration/feed/spring-integration-feed-2.0.xsd">

    <int:channel id="feedChannel" />

    <int-feed:inbound-channel-adapter id="feedAdapter" channel="feedChannel" url="http://www.formula1.com/rss/news/latest.rss">
        <int:poller id="poller" fixed-rate="10000" max-messages-per-poll="100" />
    </int-feed:inbound-channel-adapter>

    <int:service-activator input-channel="feedChannel" ref="messageHandler"/>

    <bean id="messageHandler" class="net.comdynamics.feedchannel.RSSMessageHandler"/>

</beans>

RSS Message Handler

The RSS Message handler is invoked by the poller and the handleMessage is responsible for acting on the incoming message.

package net.comdynamics.feedchannel;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.integration.Message;
import com.sun.syndication.feed.synd.SyndEntryImpl;
import org.springframework.integration.MessagingException;
import org.springframework.integration.core.MessageHandler;

/**
 * Handler for processing incoming RSS message payloads.
 *
 * @author gregsmith
 */
public class RSSMessageHandler implements MessageHandler {

    private static final Log log = LogFactory.getLog(RSSMessageHandler.class);

    public RSSMessageHandler() {
        log.debug("Created RSSMessageHandler");
    }

    /**
     * Handles the message if possible. If the handler cannot deal with the
     * message this will result in a <code>MessageRejectedException</code> e.g.
     * in case of a Selective Consumer. When a consumer tries to handle a
     * message, but fails to do so, a <code>MessageHandlingException</code> is
     * thrown. In the last case it is recommended to treat the message as tainted
     * and go into an error scenario.
     * <p/>
     * When the handling results in a failure of another message being sent
     * (e.g. a "reply" message), that failure  will trigger a
     * <code>MessageDeliveryException</code>.
     *
     * @param message the message to be handled
     * @throws org.springframework.integration.MessageRejectedException
     *          if the handler doesn't accept the message
     * @throws org.springframework.integration.MessageHandlingException
     *          when something fails during the handling
     * @throws org.springframework.integration.MessageDeliveryException
     *          when this handler failed to deliver the
     *          reply related to the handling of the message
     */
    public void handleMessage(Message<?> message) throws MessagingException {
        SyndEntryImpl syndFeed = (SyndEntryImpl)message.getPayload();
        log.debug("Message: " + syndFeed.getTitle() + " created " + syndFeed.getPublishedDate());
    }

}

RSS feed reader bootstrap

This application is invoked from the command line, hence the use of the Spring ClassPathXmlApplicationContext to wire bean dependencies.

package net.comdynamics.feedchannel;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.DirectChannel;

/**
 * Bootstrap class for RSSReader
 *
 * @author gregsmith
 */
public class RSSReader {

    private static final Log log = LogFactory.getLog(RSSReader.class);

	private RSSMessageHandler rssMessageHandler;

    private DirectChannel feedChannel;

    public RSSReader() {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
				new String[] { "applicationContext.xml" });

        log.debug("ApplicationContext is: " + context);
		feedChannel = (DirectChannel) context.getBean("feedChannel");
        rssMessageHandler = (RSSMessageHandler) context.getBean("messageHandler");
        feedChannel.setShouldTrack(true);
        feedChannel.subscribe(rssMessageHandler);
    }

    public static void main(String args[]) {
        log.debug("RSS reader starting...");
        new RSSReader();
        log.debug("RSS reader polling!");
    }

}

Packaging and execution

The application is built using Maven with the following directive:

mvn package

The packaged JAR file will be created using a suffix of one-jar.jar and can then be launched from the /target directory of the Maven project using a syntax of

java -jar application-name.one-jar.jar

Upon startup, incoming RSS messages will be processed by the message handler. In this example which processes the Formula1.com RSS feed, the title and date of publication for the message is displayed.

Message: Qualifying analysis - can McLaren halt Vettel's winning streak? created Sat Apr 16 23:51:00 NZST 2011
Message: Chinese Grand Prix - selected team & driver quotes created Sun Apr 17 21:39:00 NZST 2011
Message: Race - Hamilton takes sensational Shanghai win created Sun Apr 17 21:41:00 NZST 2011
Message: Sebastian Vettel Q&A - an afternoon full of lessons created Mon Apr 18 01:03:00 NZST 2011
Message: FIA post-race press conference - China created Mon Apr 18 01:10:00 NZST 2011
Message: Montezemolo demands rapid improvement at Ferrari created Mon Apr 18 23:59:00 NZST 2011
Message: China analysis - McLaren strike back in Shanghai  created Tue Apr 19 03:41:00 NZST 2011
Message: Shanghai debrief with Williams' Sam Michael created Tue Apr 19 22:29:00 NZST 2011
Message: Massa determined to maintain China momentum created Wed Apr 20 20:46:00 NZST 2011
Message: Lewis Hamilton Q&A: China win just the start of the fight created Thu Apr 21 01:08:00 NZST 2011
Message: Q&A with McLaren's Jenson Button  created Thu Apr 21 02:29:00 NZST 2011
Message: Peter Sauber Q&A: We've reached our first target? created Fri Apr 22 00:53:00 NZST 2011
Message: Robert Kubica Q&A: Fans' response has been overwhelming created Fri Apr 22 02:17:00 NZST 2011
Message: Formula One Fantasy - Mercedes' Nico Rosberg created Mon Apr 25 01:14:00 NZST 2011
Message: Kubica discharged from Italian hospital created Mon Apr 25 08:01:00 NZST 2011

Conclusion

Through minimal coding it is possible to subscribe to an RSS feed using the Spring Integration framework. Since processing RSS feeds is a trivial usage example, the reader is encouraged to explore the framework in more detail if there is a need to support asynchronous, message-driven behavior within a Spring-based application.

17
Jan

Spring 3 and RESTful Services

Introduction

This article describes the process for supporting REST (Representational State Transfer) in your application using Spring 3. For a variety of reasons including scalability, performance, and simplification, REST has gained critical mass as an alternative to SOAP-based Web Services and is now offered as part of JEE 6 in accordance with JSR-311. REST facilitates access to resources in a uniform way independent of the context or caller to promote simplified integration and facilitate re-use across architectural layers.

SpringMVC enhancements

Central to supporting REST in Spring 3 were enhancements made to SpringMVC and annotation driven controllers. In this article I present the hypothetical example of a motor vehicle distributor listing the types of vehicles that they sell. The HTTP GET method will be implemented in the controller for obtaining a list of vehicles or details of a specific vehicle and the output will be presented in the form of an object graph transformed to XML using XStream. XStream has been chosen as it is supported by the org.springframework.oxm.xstream.XStreamMarshaller class in the Spring Object/XML Mapping (OXM) package an does not require custom classes to marshall/unmarshall a payload.

Getting started

The quickest way to create the application structure for this example is with Maven. Here, we will use the web archetype to create an artifact deployable to our Tomcat servlet container.

mvn archetype:generate -DgroupId=net.comdynamics.springrestexample -DartifactId=springrestexample-web -DpackageName=net.comdynamics.springrestexample -Dversion=0.1-SNAPSHOT -DarchetypeArtifactId=maven-archetype-webapp

The directory structure will be similar to the following. You will need to create the Java classes and resources listed in this article as part of the steps listed.

Sample project layout

Maven project

I have specified a property in the Maven POM file to indicate the use of Spring 3.0 Release 3.

<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>net.comdynamics.springrestexample</groupId>
    <artifactId>springrestexample-web</artifactId>
    <packaging>war</packaging>
    <version>0.1-SNAPSHOT</version>
    <name>springrestexample-web Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <repositories>
        <repository>
			<id>maven2-repository.dev.java.net</id>
			<name>Java.net Repository for Maven</name>
			<url>http://download.java.net/maven/2</url>
			<layout>default</layout>
		</repository>
        <repository>
            <id>spring-milestone</id>
            <url>http://maven.springframework.org/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    <properties>
        <spring.version>3.0.3.RELEASE</spring.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-oxm</artifactId>
            <version>${spring.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.2.2</version>
            <optional>false</optional>
        </dependency>
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
        </plugins>
        <finalName>springrestexample</finalName>
    </build>
</project>

JEE deployment descriptor

In the web.xml, the Spring bean configuration is referenced from applicationContext.xml. The Spring MVC DispatcherServlet is responsible for dispatching HTTP requests to our handler which in this scenario is the VehicleController class. Specifying /* with an asterisk ensures all incoming HTTP requests are processed by the Dispatcher.

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

    <display-name>springrestexample</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:/applicationContext.xml
        </param-value>
    </context-param>

    <context-param>
        <param-name>log4jConfigLocation</param-name>
        <param-value>/WEB-INF/classes/log4j.xml</param-value>
    </context-param>

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

    <servlet>
        <servlet-name>springrestexample</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
	        <param-name>contextConfigLocation</param-name>
	        <param-value></param-value>
	    </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>springrestexample</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

Spring Application Context

The Spring application context wires the OXM XStream marshaller and handler. The context:component-scan element triggers annotation-based autowiring against the package specified.

<?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:context="http://www.springframework.org/schema/context"
        xmlns:util="http://www.springframework.org/schema/util"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
	    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

    <context:component-scan base-package="net.comdynamics.springrestexample"/>

    <bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller"/>

    <bean id="marshallingHttpMessageConverter"
          class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
        <property name="marshaller" ref="xstreamMarshaller"/>
        <property name="unmarshaller" ref="xstreamMarshaller"/>
    </bean>

    <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
        <property name="messageConverters">
            <util:list id="beanList">
                <ref bean="marshallingHttpMessageConverter"/>
            </util:list>
        </property>
    </bean>

    <mvc:annotation-driven/>

</beans>

Domain Object

The Vehicle class is an immutable domain object that encapsulates id, make, and model fields.

package net.comdynamics.springrestexample.domain;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class Vehicle {

    private static final Log log = LogFactory.getLog(Vehicle.class);

    private Long id;
    private String make;
    private String model;

    public Vehicle(Long id, String make, String model) {
        this.id = id;
        this.make = make;
        this.model = model;
    }

    public Long getId() {
        return id;
    }

    public String getMake() {
        return make;
    }

    public String getModel() {
        return model;
    }

	@Override
	public boolean equals(Object obj) {
		if (obj == this)
			return true;
		if (this.id == null || !(obj instanceof Vehicle))
			return false;
		Vehicle vehicle = (Vehicle) obj;
		return this.id.equals(vehicle.getId());
	}

	@Override
	public int hashCode() {
		return this.id == null ? 1 : this.id.hashCode();
	}

}

Service Component

There is no reliance on a data tier in this example therefore I have created a service component which uses an in-memory collection of vehicles. The service exposes two methods: getVehicleById() and getAllVehicles(). These methods are called by the Controller class when incoming HTTP GET requests are processed by the Dispatcher.

package net.comdynamics.springrestexample.service;

import net.comdynamics.springrestexample.domain.Vehicle;

import java.util.*;

import javax.inject.Named;

@Named("vehicleService")
public class VehicleService {

    // Dummy list of vehicles
    static final Map<Long, Vehicle> vehicles = new HashMap<Long, Vehicle>();

    // Dummy entry to be returned if not found
    static final Vehicle notFound = new Vehicle(0L, "Vehicle", "Not Found");

    static {
        vehicles.put(1L, new Vehicle(1L, "Audi", "A1"));
        vehicles.put(2L, new Vehicle(2L, "Audi", "S4"));
        vehicles.put(3L, new Vehicle(3L, "Audi", "RS5"));
        vehicles.put(4L, new Vehicle(4L, "BMW", "120i"));
        vehicles.put(5L, new Vehicle(5L, "BMW", "330d"));
        vehicles.put(6L, new Vehicle(6L, "BMW", "M3"));
        vehicles.put(7L, new Vehicle(7L, "Ford", "Focus"));
        vehicles.put(8L, new Vehicle(8L, "Ford", "Mondeo"));
        vehicles.put(9L, new Vehicle(9L, "Volkswagen", "Polo TSI"));
        vehicles.put(10L,new Vehicle(10L, "Volkswagen", "Golf GTI"));
        vehicles.put(11L,new Vehicle(11L, "Volkswagen", "Tiguan"));
    }

    public Vehicle getVehicleById(Long vehicleId) {
        if (vehicleId < vehicles.size() + 1) {
            return vehicles.get(vehicleId);
        } else {
            // Return not found
            return notFound;
        }
    }

    /**
     * Return all vehicles as a List.
     */
    public List<Vehicle> getAllVehicles() {
        return new ArrayList<Vehicle>(vehicles.values());
    }

}

The Controller

The use of the JSR 330 annotation @Named facilitates auto-wiring of dependencies as this controller requires the VehicleService. Here, the annotation @RequestMapping is used to map a URI for a resource and the HTTP method supported which is this instance is GET. An HTTP request to http://server:port/springrestexample/vehicles/ will list all vehicles, and http://server:port/springrestexample/vehicles/3 will return the third vehicle in the motor vehicle distributors inventory. I have chosen to use the plural name (“vehicles”) and not the singular name (“vehicle”) in mappings as this approach is widely adopted for resources accessed using REST.

The @ResponseBody annotation ensures that the return type is written to the response HTTP body which in our case is handled by the XStream OXM class.

package net.comdynamics.springrestexample.rest;

import net.comdynamics.springrestexample.domain.Vehicle;
import net.comdynamics.springrestexample.service.VehicleService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.inject.Inject;
import javax.inject.Named;
import java.util.List;

@Controller
public class VehicleController {

    private static final Log log = LogFactory.getLog(VehicleController.class);

    @Inject
    @Named("vehicleService")
    private VehicleService vehicleService;

    /**
     * Get all vehicles.
     */
    @RequestMapping(value = "/vehicles", method = RequestMethod.GET)
    @ResponseBody
    public List<Vehicle> getAllVehicles() {
        return vehicleService.getAllVehicles();
    }

    /**
     * Get the vehicle matching a specific id.
     *
     * @param vehicleId the identifier of the requested vehicle
     */
    @RequestMapping(value = "/vehicles/{vehicleId}", method = RequestMethod.GET)
    @ResponseBody
    public Vehicle getVehicleById(@PathVariable Long vehicleId) {
        Vehicle vehicle = vehicleService.getVehicleById(vehicleId);
        log.debug("Got request for vehicle " + vehicleId + ", returning " + vehicle);
        return vehicle;
    }

}

Accessing resources via a web brower

Using a browser to get details for vehicle with an identifier of 10 at http://localhost:8080/springrestexample/vehicles/10 will produce the following:

HTTP GET for a single vehicle

When requesting all vehicles at http://localhost:8080/springrestexample/vehicles/ you should see the following:

HTTP GET for all vehicles

Conclusion

Support for REST in Spring 3 is provided using a SpringMVC controller that maps a URI to a resource and HTTP request method type. Future articles will examine the use of Spring URI REST templates and the Content Negotiating View Resolver support for different response types based on the user-agent accessing the resource.