Wednesday, September 14, 2011

Restful webservice (Jersey+ Spring 3.0.X + TestNG+ Jetty)

This is simple hello world example for a restful webservice. This example demonstrates the use of the Jersey as an implementation for restful webservice integrated with the Spring. Jersey has a good support for unit testing with JUnit but there are very few examples of how to test Jersey based application using the TestNG. This example will also explain the use of TestNG with Jersey. For a simplicity we will be using the maven Jetty plugin to run our web application.

Maven Configuration:

Create a simple maven webapp project.

Edit the pom.xml file to include the below content.

<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.ameeth.jersey</groupId>
    <artifactId>JerseySpring</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>Jersey Spring Maven Webapp</name>
    <url>http://maven.apache.org</url>
    <properties>
        <jersey.version>1.5</jersey.version>           <org.springframework.version>3.0.3.RELEASE</org.springframework.version>
        <testng.version>5.12.1</testng.version>

    </properties>
    <dependencies>
        <!-- Jersey dependency -->
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey.contribs</groupId>
            <artifactId>jersey-spring</artifactId>
            <version>${jersey.version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey.jersey-test-framework</groupId>
            <artifactId>jersey-test-framework-grizzly</artifactId>
            <version>${jersey.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testng.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <finalName>JerseySpring</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <target>1.5</target>
                    <source>1.5</source>
                </configuration>
            </plugin>
            <!-- This plugin is for running a web application directly from Maven. -->
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.10</version>
                <configuration>
                    <connectors>
                        <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                            <port>9090</port>
                            <maxIdleTime>60000</maxIdleTime>
                        </connector>
                    </connectors>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Spring based Service:

Now we will create a simple service class. This service class will be configured using the Spring 3.0.X
First we will create a interface named "GreetingService" Which will have a single method declaration
 public String sayHello();


package com.ameeth.jersey.service;


/**
 * <p>
 * GreetingService
 * </p>
 * @version 1.0
 * @author Ameeth Paatil
 * @since Sep 14, 2011
 */
public interface GreetingService {
    public String sayHello();
}

Now we will implement the above interface. We will use spring annotation @Service to mark the "GreetingServiceImpl" as service class. The implementation of sayHello method will return a simple String "Hello World!"

package com.ameeth.jersey.service;

import org.springframework.stereotype.Service;

/**
 * <p>
 * GreetingService
 * </p>
 * @version 1.0
 * @author Ameeth Paatil
 * @since Sep 13, 2011
 */
@Service
public class GreetingServiceImpl
    implements GreetingService {

    /**
     * @see com.ameeth.jersey.service.GreetingService#sayHello()
     */
    @Override
    public String sayHello() {
        return "Hello World!";
    }
}


Jersey based Restfulwebservice

Now we will create a simple Root resource which will consume our service to say Hello. The GreetingsResource class is a very simple Web resource. The URI path of the resource is "/greeting" , it supports the HTTP GET and produces text content.


package com.ameeth.jersey.web;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.ameeth.jersey.service.GreetingService;

/**
 * <p>
 * GreetingsResource
 * </p>
 * @version 1.0
 * @author Ameeth Paatil
 * @since Sep 13, 2011
 */
@Path("/greeting")
@Component
@Scope("request")
public class GreetingsResource {

    @Autowired
    private GreetingService service;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String sayHello() {
        return service.sayHello();
    }
}


Webapp configuration:

So we have created a root resource, we have created a service class. We have configured the pom file. Now we will create the basic spring ApplicationContext.xml file. create this file under resources directory.


<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"
    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-3.0.xsd">
    <context:component-scan base-package="com.ameeth.jersey" />
</beans>

The configuration tells the spring container to scan for the components under "com.ameeth.jersey" package.


Now we have added ApplicationContext.xml now its time to configure web.xml

The web.xml should look like something below where first we will configure the spring contextConfigLocation. Then we will add ContextLoaderListener and RequestContextListener
Then define the SpringServle. with the url pattern. This servlet will be responsible to identify all the spring managed rest resource. Configuration parameter can be set to include the jersey managed resources as well.

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Jersey+Spring+TestNG Demo Web Application</display-name>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:ApplicationContext.xml
        </param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>jerseyspring</servlet-name>
        <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>jerseyspring</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>


Running the Application using Jetty:

Now we have defined the web.xml also its time to run the application.
To run the application simply go to command prompt and run "mvn jetty:run" This will deploy our application on jetty server on port 9090. To check out service enter the below url in the browser
http://localhost:9090/JerseySpring/rest/greeting

This will display the "Hello World!" as output.

To stop the server just hit ctrl+c

Testing the rest resource using TestNG.
Jersey has good integration with the Junit and JerseyTest can be used directly as a base class for all the tests for web resources. To use the JerseyTest wit TestNG below approach can be used.

Create a JerseyTestNGTest class which will be the base class of all the test classes for the webresource


package com.ameeth.jersey.web;

import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.request.RequestContextListener;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.BeforeTest;

import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.spi.spring.container.servlet.SpringServlet;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.WebAppDescriptor;

/**
 * <p>
 * JersyTestNGTest
 * </p>
 * @version 1.0
 * @author Ameeth Paatil
 * @since Sep 13, 2011
 */
public class JerseyTestNGTest {
    private static JerseyTest jersyTest;

    @BeforeSuite()
    public void init() {
        jersyTest = new JerseyTest( new WebAppDescriptor.Builder(
            "com.ameeth.jersy.web" ).contextPath( "rest" )
            .contextParam(
                "contextConfigLocation", "classpath:ApplicationContext.xml" )
            .servletClass( SpringServlet.class )
            .contextListenerClass( ContextLoaderListener.class )
            .requestListenerClass( RequestContextListener.class )
            .build() ) {

        };
    }

    public WebResource resource() {
        return jersyTest.resource();
    }

    public Client client() {
        return jersyTest.client();
    }


    @BeforeTest
    public void setUp()
        throws Exception {
        jersyTest.setUp();
    }

    @AfterTest
    public void tearDown()
        throws Exception {
        jersyTest.tearDown();
    }
}



The init method initializes the container. jersyTest is the instance of JerseyTest. Which will be used the create a WebResource and Client objects. resource() and client() are the utility methods which will be used in the subclasses.


Now we will create a test class for our root resource "GreetingsResource"
package com.ameeth.jersey.web;

import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;

import javax.ws.rs.core.MediaType;

import org.testng.annotations.Test;

import com.sun.jersey.api.client.WebResource;

/**
 * This is a TestNG test for GreetingsResource
 * This test was generated at 09/13/2011
 * @author Ameeth Paatil
 */

public class GreetingsResourceTest
    extends JerseyTestNGTest {

    /**
     * @see com.ameeth.jersy.web.GreetingsResource#sayHello
     */
    @Test
    public void sayHello() {
        WebResource resource = resource();
        String greeting = resource.path( "greeting" )
            .accept( MediaType.TEXT_PLAIN )
            .get( String.class );
        assertNotNull( greeting );
        assertEquals( greeting, "Hello World!" );
    }
}


GreetingsResourceTest extends out generic JerseyTestNGTest class.
sayHello() test will first build the resource for the path "greeting" and media type TextPlain and .get Method will execute the GET call for the "greeting" resource.

Run this test case using "mvn test"

No comments:

Post a Comment