Building And Deploying the REST application with Maven

This exercise is to build and deploy the REST application here using MAVEN.
http://cuppajavamattiz.com/2012/11/09/a-simple-restful-service/

Download maven and add it to your PATH environment variable.Create a folder where you want your maven app to be configured. Go to this folder on your command prompt and run the following command:
mvn archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DarchetypeArtifactId=maven-archetype-webapp -DgroupId=com.mattiz.testapp -DartifactId=MavenRest
This will create a maven project structure for a web application within a folder called MavenRest which will also contain a pom.xml
Create a folder src/main/java and copy your java source files to this folder.
The project will have a structure similar to this:

A default pom.xml is created within the MavenRest folder.
Overwrite it with this source:

<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.mattiz.testapp</groupId>
  <artifactId>MavenRest</artifactId>
  <packaging>war</packaging>
  <version>0</version>
  <name>MavenRest Maven Webapp</name>
  <url>http://maven.apache.org</url>
	<properties>
		<org.springframework-version>3.0.2.RELEASE</org.springframework-version>
		<com.springsource-version>3.0.2.RELEASE</com.springsource-version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>com.springsource.org.codehaus.jackson.mapper</artifactId>
			<version>1.4.2</version>
		</dependency>
		<dependency>
			<groupId>org.codehaus.jackson</groupId>
			<artifactId>com.springsource.org.codehaus.jackson</artifactId>
			<version>1.4.2</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>com.springsource.org.apache.commons.beanutils</artifactId>
			<version>1.8.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>com.springsource.org.apache.commons.logging</artifactId>
			<version>1.1.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.aop</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.asm</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.beans</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.context</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.core</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.expression</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.web.servlet</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>org.springframework.web</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>
	<repositories>
		<!--For any snapshot build (Spring 2.5-SNAPSHOT, Spring Web Flow 2.0-SNAPSHOT, etc.) the Maven
		artifacts for that build will be uploaded to the Spring Snapshot repository.-->
		<repository>
            <id>SpringSource Enterprise Bundle Repository - External Bundle Snapshots</id>
            <url>http://repository.springsource.com/maven/bundles/snapshot</url>
        </repository>

        <!-- Required, as Spring JavaConfig has dependencies on released versions of SpringSource products -->
        <repository>
            <id>SpringSource Enterprise Bundle Repository - SpringSource Bundle Releases</id>
            <url>http://repository.springsource.com/maven/bundles/release</url>
        </repository>

        <!-- Required, as Spring JavaConfig has dependencies on External OSGi bundles -->
        <repository>
            <id>SpringSource Enterprise Bundle Repository - External Bundle Releases</id>
            <url>http://repository.springsource.com/maven/bundles/external</url>
        </repository>
		<repository>
            <id>org.springframework.maven.snapshot</id>
            <name>Spring Maven Snapshot Repository</name>
            <url>http://maven.springframework.org/snapshot</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
	</repositories>
	<build>
		<finalName>MavenRest</finalName>
		<!--Property file creation Starts-->
		<resources>
			<resource>
		        <directory>src/main/resources</directory>
		        <filtering>true</filtering>
		     </resource>
		</resources>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>1.5</source>
					<target>1.5</target>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>tomcat-maven-plugin</artifactId>
				<configuration>
					<server>TomcatServer</server>
					<path>/${project.build.finalName}</path>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Points to note
The packaging is declared as war so that maven knows that a WAR file has to be created. The dependencies are mostly declared without any scope so these will be included in the war WEB-INF/lib folder. The jar javax.servlet.jar is declared as “provided” which means it will not be included in the war and will be provided at runtime by the tomcat container. The dependencies for this project are available at the following site:
http://ebr.springsource.com/repository/app/bundle

The repository where these dependencies and the maven plugins are available at the URLs mentioned under repositories. Also the plugins required are declared in the pom. we use two plugins:

  • maven-compiler-plugin
  • tomcat-maven-plugin

The clean, compile, package plugins that we use are available by default with maven. You will need to declare the repositories for the plugins you have explicitly declared in pom.xml.
Copy
applicationContext.xml
cxf-servlet.xml
rest-services-config.xml
web.xml
Place them in /MavenRest/src/main/webapp/WEB-INF/
You need to overwrite the existing web.xml from the older application.
Your app is now ready to build.
Run the following on a command prompt
mvn clean package
You will see that a war file is created under target folder.
You can convert your maven folder structure to a maven Eclipse project. Run this on the command prompt in the folder which contains the pom.
mvn eclipse:eclipse
Import the project created using import existing projects into Eclipse.
Set M2_REPO eclipse variable in Eclipse to your maven repository location to resolve build errors.

You can auto deploy the war created in target folder to a tomcat of your choice using tomcat-maven-plugin declared in the pom.
See this declaration:

			<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>tomcat-maven-plugin</artifactId>
				<configuration>
					<server>TomcatServer</server>
					<path>/${project.build.finalName}</path>
				</configuration>
			</plugin>

It tells Maven to deploy the war in the currently running instance of tomcat at the 8080 port. The context path is defined by ${project.build.finalName} which in our case it MavenRest.
You need to make some changes in Maven’s settings.xml too.
Add this to conf/settings.xml under servers.

	<server>
      		<id>TomcatServer</id>
      		<username>admin</username>
      		<password>admin</password>
    	</server>

This is assuming your tomcat manager has the username and password admin/admin
Make this change in the tomcat-users.xml to enable this username and password.

        <role rolename="manager"/>
        <role rolename="admin"/>
        <user username="admin" password="admin" roles="admin,manager"/>

When you run
mvn tomcat:deploy
Maven will deploy the war created by pom.xml to the tomcat’s webapp folder currently running on the 8080 port. You need to have tomcat running on this port in the first place.
Run tomcat:redeploy to redeploy the war after changes.
Check application with the URL
http://localhost:8080/MavenRest/restservices/mattiz
using a REST client.

Short note on Maven
Maven is just a framework of plugins that uses Ant underneath. It stores jar files in a remote repository for easy sharing. Maven is easier to use; there is no need to write large build.xml files since most common tasks are available as plugins.
You have a settings.xml and one or several pom.xml.
settings.xml
The settings.xml is optional and is used to specify the repository location, security and deployment settings. If it is absent default values are used. It may also contain repository authentication informatio and username and passoword for the server on which the generated package is deployed.
Maven Repository
Maven will automatically download artifacts from the online maven repository if the dependencies are not locally available in the repository. The jars are placed in a local maven repository(relative path=.m2/repo).
pom.xml
It contains the following information:

  • the type of packaging,
  • information about the project dependencies(artifacts or dependencies of those artifacts),
  • artifact name
  • artifact version,
  • artifact scope(default scope means the generated package will include this artifact while “provided” means they will be provided by the deployment container),
  • maven plugins that are to be used during the build process(certain plugins such as mvn:clean, mvn:compile, mvn:package are included by default within the maven distribution),
  • dependencies on third party maven repositories

When executing a task or goal, Maven looks for the POM in the current directory. It reads the POM, gets the needed configuration information such as project dependencies, then executes the goal. The goal may be a custom goal or one that is available in a maven plugin or inbuilt into maven.
Maven commands
mvn-test
mvn compile
mvn package
mvn install
are common maven commands.
Advantages
Maven has plugins for all “common” tasks so that all you have to do is add some information to configuration files. These are built over Ant tasks.
Refer this post for the maven download of the REST app http://cuppajavamattiz.com/2012/11/09/a-simple-restful-service/

A simple webservice using Apache CXF

I have modified the previous application in http://cuppajavamattiz.com/2012/11/09/a-simple-restful-service/, to include a webservice using Apache CXF. The jars I included from the CXF distribution were:
httpclient-4.2.1.jar
httpcore-4.2.2.jar
httpcore-nio-4.2.2.jar
jaxb-impl-2.2.5.jar
neethi-3.0.2.jar
cxf-manifest.jar
geronimo-javamail_1.4_spec-1.7.1.jar
geronimo-jaxws_2.2_spec-1.1.jar
geronimo-jms_1.1_spec-1.1.1.jar
geronimo-servlet_3.0_spec-1.0.jar
httpasyncclient-4.0-beta3.jar
xmlschema-core-2.0.3.jar
I modified the web.xml to look this
Remove the REST specific configurations below so that the app only works with REST.

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

<display-name>REST Service</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/rest-services-config.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>restservices</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>restservices</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>
</web-app>

Added applicationContext.xml

Added cxf-servlet.xml

Added two classes:

package com.mattiz.ws.service;

import java.rmi.Remote;
import javax.jws.WebService;

@WebService(targetNamespace = "http:/com.mattiz/wsdl")
public interface MattizWebService extends Remote {
	public String getWelcomeString();
}
package com.mattiz.ws.service;

import javax.annotation.PostConstruct;
import javax.jws.WebMethod;
import javax.jws.WebService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import com.mattiz.rest.service.MattizService;

@Service("mattizWebService")
@WebService(serviceName = "/MattizWebService", portName = "MattizWebServicePort", targetNamespace = "http:/com.mattiz/wsdl", endpointInterface = "com.mattiz.ws.service.MattizWebService")
public class MattizWebServiceImpl implements MattizWebService {

	@Autowired
	private MattizService mattizService;
	@WebMethod(operationName = "getWelcomeString", action = "urn:getWelcomeString")
	public String getWelcomeString() {
		String welcomeString = null;
		try {
			welcomeString = mattizService.getWelcomeString();
			return welcomeString;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	@PostConstruct
	public void init() {
	    SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
	}
	public MattizService getMattizService() {
		return mattizService;
	}
	public void setMattizService(MattizService mattizService) {
		this.mattizService = mattizService;
	}
}

Note that the webservice is not created by Spring, so the mattizService bean is not autowired through spring directly, hence the init method to enable spring autowiring.

The wsdl can be viewed using the following url:

http://localhost:8080/RestServiceExampleWithJson/webservice/mattiz?wsdl

To test the webservice I have modified a client module described elsewhere on this blog http://cuppajavamattiz.com/2011/07/10/an-ejb3-webservice-with-generated-client-code/.

build-client.xml

The test class:

package com.mattiz.ws.client;

import com.mattiz.ws.test.bean.MattizWebService;
import com.mattiz.ws.test.bean._002fMattizWebService;

public class MattizWSClientTest {
	public static void main(String[] args) {
		try {
			MattizWebService port = new _002fMattizWebService().getMattizWebServicePort();
			System.out.println(port.getWelcomeString());
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}

The classes under com.mattiz.ws.test.bean package are automatically generated web service stubs by the build xml.
Run the client class as a standalone to test.
The result is:
Hallo Mattiz World!

A Simple RESTful Service

I am using jars from the spring-framework-3.0.2.RELEASE and spring-framework-3.0.2.RELEASE-dependencies downloads as you can see from the screenshot for this example of a RESTful service integrated with Spring. Spring 3.0.2 inherently supports REST in its packaged dependencies. However it is interesting to note that after the 3.0.2 release of Spring the corresponding dependency jar packages were not shipped, most probably due to the ease of using a maven project and directly downloading these jars from the maven repository. In addition to these I add the servlet-api jar that takes care that spring is configured correctly by the tomcat container. (I am using tomcat 7)

web.xml



	REST Service
	
		contextConfigLocation
		
			/WEB-INF/rest-services-config.xml
		
	
	
		org.springframework.web.context.ContextLoaderListener
	
	
		restservices
		org.springframework.web.servlet.DispatcherServlet
		
			contextConfigLocation
			
		
		1
	
	
		restservices
		/
	

rest-services-config.xml



	
	<!-- Setup spring to pull in @Controller, @RequestMapping, etc Configuration
		scans specified packages for classes configured as Spring managed beans and
		automatically sets up objects annotated with @Controller, @Service etc. -->
	
	<!-- TODO -->
	
	<!-- Configures view for returning JSON to the client -->
	
		
	
	<!-- TODO -->
	
		
			
				
			
		
	
	<!-- Converts JSON to POJO and vice versa -->
	

This is the class that exposes the RESTful methods

package com.mattiz.rest.controller;

import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJacksonJsonView;
import com.mattiz.rest.service.MattizService;

@Controller
@RequestMapping(value = "/restservices")
public class RestServiceController {
	@Autowired
	private MattizService mattizService;
	private static final String DATA_FIELD = "data";
	private static final String ERROR_FIELD = "error";
	@RequestMapping(value = "/mattiz", method = RequestMethod.GET)
	public ModelAndView getWelcomeString(HttpServletRequest request) {
		String msg = null;
		try {
			msg = mattizService.getWelcomeString();
		} catch (Exception e) {
			return createErrorResponse(String.format(
					"Error getting message. [%1$s]", e.toString()));
		}
		return new ModelAndView(new MappingJacksonJsonView(), DATA_FIELD, msg);
	}
	private ModelAndView createErrorResponse(String sMessage) {
		return new ModelAndView(new MappingJacksonJsonView(), ERROR_FIELD,
				sMessage);
	}
}

Service interface

package com.mattiz.rest.service;
public interface MattizService {
	public String getWelcomeString();
}

Service implementation

package com.mattiz.rest.service;

import org.springframework.stereotype.Service;

@Service("mattizService")
public class MattizServiceImpl implements MattizService {
	public String getWelcomeString() {
		return ("Hallo Mattiz World!");
	}
}

This exposes the RESTful service by the URL restservices/mattiz

There are multiple REST clients that can be used to test the application including two plugins to the Chrome browser.
Type the following URL, select GET and hit the SEND button to get the response from the RESTful service.

http://localhost:8080/RestServiceExampleWithJson/restservices/mattiz

You would see something like this:

{“data”:”Hallo Mattiz World!”}

An example of Apache CXF web service and RESTful service can be downloaded here

 

REST is an architecture. REST is not restricted to HTTP alone. It can use any protocol that follows the URI scheme. SOAP on the other hand uses HTTP alone. The consumer need not know a lot about the services exposed by the Rest service provider. In case of SOAP any undocumented change on either server or client side will break the communication. i.e. Web Service client and server are more tightly coupled than REST. The soap client requires detailed previous knowledge of the web service provider. However, once the entry point is known in REST, the resources are supposed to return links that the client can follow. Rest has a much simpler request and can use JSON as well as XML. It does not have the soap envelope and the headers and can be used for protocols that don’t support these. It can use JSON as well as XML or CSV.
REST is almost always going to be faster. The main advantage of SOAP is that it provides a mechanism for services to describe themselves to clients, and to advertise their existence.
REST is much more lightweight and can be implemented using almost any tool, leading to lower bandwidth. However, the clients have to know what to send and what to expect.
So the soap web service client can be thin – service provider has lot of logic and data access and does lot of work while in RESTful web service, the provider is very thin – just provides resources (e.g. data). In general, When you’re publishing an API to the outside world that is either complex or likely to change, SOAP will be more useful. Other than that, REST is usually the better option.

Common HTTP methods for REST

POST – create
GET – read
PUT – update
PATCH – update
DELETE – delete
HEAD – to find what GET will return
Headers provide information about the type of request and the resource requested/ created.