Posts Tagged ‘RESTlet

02
Mar
11

Spring Framework based RESTful Web Service

This page shows you how to quickly and easily create a read-only Spring based RESTful Web Service / Application.

To keep things simple I will not be covering the “front-end” view technologies. Please see one of my other pages on how to get Spring MVC, JSF, extJS or even standard Servlets/JSP’s running with the application discussed here.

You can drop in any “view technologies” once you have the below application running.

The application will retrieve a list of cities from a “mock” datamanager and display them in JSON format in a browser.

The page should take 10-15 minutes to implement.

Requirements

  • Basic understanding of Spring
  • Basic understanding of REST
  • Java 5
  • Maven 2

Procedure

Configure the project

Create a project using Maven archetype. Open up the command prompt and navigate to an empty directory.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

groupId: com.test
artifactId: springRestWeb

Answer the rest of the questions with defaults “Just hit the enter key”,

Cd to the project base folder.

cd springRestWeb

Since this is a web project maven does not create the java source foldder.

Create missing directory
mkdir -p src/main/java/com/test

Modify the project configuration file

Open up the pom.xml file and make sure it looks like the one below. In most cases you can just copy and paste the one below into your own.

pom.xml

<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.test</groupId>
  <artifactId>springRestWeb</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>springRestWeb</name>
  <url>http://maven.apache.org</url>
    <repositories>
        <repository>
           <id>maven-restlet</id>
           <name>Public online Restlet repository</name>
           <url>http://maven.restlet.org</url>
        </repository>
    </repositories>
 
  <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

    <dependency>
        <groupId>org.json</groupId>
        <artifactId>json</artifactId>
        <version>20090211</version>
    </dependency>        
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib</artifactId>
      <version>2.2</version>
    </dependency>
        
    <dependency>
       <groupId>org.restlet.jee</groupId>
       <artifactId>org.restlet</artifactId>
       <version>2.0.5</version>
    </dependency>
    <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet.ext.simple</artifactId>
       <version>2.0.5</version>
    </dependency>
    <dependency>
       <groupId>org.restlet.jee</groupId>
       <artifactId>org.restlet.ext.spring</artifactId>
       <version>2.0.5</version>
    </dependency>
    
    <dependency>
       <groupId>org.restlet.jee</groupId>
       <artifactId>org.restlet.ext.servlet</artifactId>
       <version>2.0.5</version>
    </dependency>
    
    <!-- spring framework -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>3.0.1.RELEASE</version>
    </dependency>
        
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-servlet_2.5_spec</artifactId>
            <version>1.2</version>
            <scope>provided</scope>
        </dependency>
  </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
				<version>7.0.0.v20091005</version>
                <configuration>
                    <scanIntervalSeconds>2</scanIntervalSeconds>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Web Application Configuration

The application uses the “org.restlet.ext.spring.SpringServerServlet” to respond to HTTP Requests. This servlet responds to URL’s that begin with “/app/*” and delegates the handling of the requests to the Resources based on the routing logic specified in the ApplicationContext.xml.

src/main/webapp/WEB-INF/web.xml

<?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>Archetype Created Web Application</display-name>

<!-- The following is  used to initialize the spring framework when the web app starts. -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
 
     <servlet>
        <servlet-name>stateApplication</servlet-name>
        <servlet-class>
             org.restlet.ext.spring.SpringServerServlet
        </servlet-class>
        <init-param>
			<param-name>org.restlet.application</param-name>
			<param-value>stateApplication</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>stateApplication</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
 
 
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
 
</web-app>

Spring Configuration

The stateApplication uses a router that further checks the URL and calls the proper “Resource” based on the mappings. The routing logic consists of a “url pattern” that will cause the specified “Resource” to be called upon to respond to the request.

Each map entry uses a “SpringFinder” to create an instance of the Resource. The instance of the resource can have any number of beans injected into it (based on spring configuration).

src/main/webapp/WEB-INF/applicationContext.xml

<?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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
 
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
 
http://www.springframework.org/schema/context
 
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
 
	<bean id="stateDataManager" class="com.test.StateDataManager"/>

	<bean id="stateApplication" class="org.restlet.Application" scope="singleton">
		<property name="root">
			<bean class="org.restlet.ext.spring.SpringRouter">
				<property name="attachments">
					<map>
						<entry key="/state/{name}">
							<bean class="org.restlet.ext.spring.SpringFinder">
								<lookup-method name="create" bean="stateResource" />
							</bean>
						</entry>
					</map>
				</property>
			</bean>
		</property>
	</bean>

	<bean id="stateResource" class="com.test.StateResource" scope="prototype">
		<property name="stateDataManager" ref="stateDataManager"/>
    </bean>
		
</beans>

Create the Resource

The “Resource” is called upon to respond to requests. The “stateDataManager” member will be injected using the spring configuration seen above.

src/main/java/com/test/StateResource.java

package com.test;

import org.json.JSONArray;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ResourceException;
import org.restlet.resource.ServerResource;
import org.springframework.beans.factory.annotation.Required;

public class StateResource extends ServerResource {
	// the stateDataManager is injected using Spring
	private StateDataManager stateDataManager;
	
	// ServerResources are thread safe (spring "prototype")
	private String state;
	
    public StateResource() {
        super();
    }
    @Override
    protected void doInit() throws ResourceException {
    	super.doInit();
    	state = (String)getRequestAttributes().get("name");
    }
    @Override
    protected Representation get() throws ResourceException {
    	
        JSONArray jsonArray = new JSONArray(stateDataManager.getCities(state));
        StringBuffer out = new StringBuffer();
        String cb = getQuery().getFirstValue("callback");
        out.append(cb + "(");
        out.append("{ \"totalCount\" : \"" + jsonArray.length() + "\",");
        out.append("\"records\" : ");
        out.append(jsonArray.toString());
        out.append("}");
        out.append(");");
        
        return new StringRepresentation(out.toString());
    }
    @Required
	public void setStateDataManager(StateDataManager stateDataManager) {
		this.stateDataManager = stateDataManager;
	}
	public StateDataManager getStateDataManager() {
		return stateDataManager;
	}
}

Data Manager

This is the dummy data manager. In your situation you would replace the hard coding with a connection to a real database. I have many examples where Spring is used to connect to a mySQL database. Please search for “SimpleJDBC” on the top right corner.

src/main/java/com/test/StateDataManager.java

package com.test;

import java.util.ArrayList;
import java.util.List;

/**
 * This is a test data manager that returns dummy data.
 */
public class StateDataManager {
	public List<String> getCities(String state) {
		// return the list of cities given a state		
		List<String> cityList = new ArrayList<String>();		
		if("TX".equals(state)) {
			cityList.add("Houston");
			cityList.add("San Antonio");
			cityList.add("Dallas");
			cityList.add("Austin");
			cityList.add("El Paso");
			cityList.add("Fort Worth");			
		} else if("NY".equals(state)) {
			cityList.add("New York City");
			cityList.add("Buffalo");
			cityList.add("Rochester");
			cityList.add("Yonkers");
			cityList.add("Syracuse");
		} else if("CA".equals(state)) {
			cityList.add("Los Angeles");
			cityList.add("San Diego");
			cityList.add("San Jose");
			cityList.add("San Francisco");
			cityList.add("Fresno");
		} else {
			// don't add any cities
		}
		return cityList;
	}
}

Test the Application

mvn clean compile jetty:run

Use your browser to navigate to the following URLs:
http://localhost:8080/app/state/CA
http://localhost:8080/app/state/NY
http://localhost:8080/app/state/TX

You should see something like this in your browser:

null({ "totalCount" : "5","records" : ["Los Angeles","San Diego","San Jose","San Francisco","Fresno"]});

The above format is designed to work with the extJS “Ext.data.ScriptTagProxy”. But you can use any number of view technologies to parse and display the data.

Creating a WAR file

If you want to run the application in another environment you can create a war file and drop it into a server of your choice. This method will also package up any runtime dependencies and put them in the /WEB-INF/lib folder of the WAR file.

mvn clean compile package

The war file should appear in the following location…

springRestWeb/target/springRestWeb-1.0-SNAPSHOT.war

24
Feb
11

extJS GridPanel using data from RESTlet Invocation

This page will describe an implementation of an extJS grid panel component being fed data in JSON format from a server side resource. In this case it will be the RESTlet however you can always use a standard Java Servlet as well. This page introduces you to ExtJS, JSON, and RESTlet technologies.

Requirements

  • Maven 2 – see my maven tutorial
  • Java 5
  • Basic understanding of extJS
  • Basic understanding of RESTlet framework
  • Basic understanding of JSON

Background

The data coming from the RESTlet looks like the following.

callbackName({ "totalCount" : "4","records" : [
	{"state":"NY","fullName":"John Allen"},
	{"state":"NJ","fullName":"Bob Smith"},
	{"state":"NY","fullName":"John Adams"},
	{"state":"CA","fullName":"John Doe"}
]});

Procedure

We will start by creating a new project using maven 2.

mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

For the group id enter: com.test
For the artifactId enter: extJSWeb

Answer the rest of the questions using defaults [Hit Enter].

cd to the project’s folder

Edit the pom.xml file to look like the following…

pom.xml

<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.test</groupId>
  <artifactId>extjsWeb</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>extjsWeb Maven Webapp</name>
  <url>http://maven.apache.org</url>
    <repositories>
        <repository>
           <id>maven-restlet</id>
           <name>Public online Restlet repository</name>
           <url>http://maven.restlet.org</url>
        </repository>
    </repositories>  
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
	<dependency>
	    <groupId>org.json</groupId>
	    <artifactId>json</artifactId>
	    <version>20090211</version>
	</dependency>    
    <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet</artifactId>
       <version>2.0.0</version>
    </dependency>
    <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet.ext.simple</artifactId>
       <version>2.0.0</version>
    </dependency>
    <dependency>
       <groupId>org.restlet.jse</groupId>
       <artifactId>org.restlet.ext.json</artifactId>
       <version>2.0.0</version>
    </dependency>
    <dependency>
       <groupId>org.restlet.jee</groupId>
       <artifactId>org.restlet.ext.servlet</artifactId>
       <version>2.0.0</version>
    </dependency>
        <dependency>
            <groupId>org.apache.geronimo.specs</groupId>
            <artifactId>geronimo-servlet_2.5_spec</artifactId>
            <version>1.2</version>
            <scope>provided</scope>
        </dependency>

  </dependencies>
  <build>
    <finalName>extjsWeb</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
				<version>7.0.0.v20091005</version>
                <configuration>
                    <scanIntervalSeconds>2</scanIntervalSeconds>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-eclipse-plugin</artifactId>
                <configuration>
                    <wtpapplicationxml>true</wtpapplicationxml>
                    <wtpversion>1.5</wtpversion>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                    <classpathContainers>
                        <classpathContainer>org.eclipse.jst.j2ee.internal.web.container</classpathContainer>
                        <classpathContainer>org.eclipse.jst.j2ee.internal.module.container</classpathContainer>
                    </classpathContainers>
                    <additionalProjectFacets>
                        <jst.web>2.5</jst.web>
                        <jst.jsf>1.2</jst.jsf>
                    </additionalProjectFacets>
                </configuration>
            </plugin>
        </plugins>
  </build>
</project>

JSP Page

The following page contains the “gridPanelRestletExample.js” file responsible for rendering the grid panel component. For the sake of simplicity I will link to the extJS css and js files directly from the Sencha site. This is not recommended for production code. In production the extJS library should be downloaded and installed onto your web or App server.

src/main/webapp/gridPanelRestlet.jsp

<html>
<head>
	<link rel="stylesheet" type="text/css"
		href="http://dev.sencha.com/deploy/ext-3.3.1/resources/css/ext-all.css"/>
		
	<script type="text/javascript"
		src="http://dev.sencha.com/deploy/ext-3.3.1/adapter/ext/ext-base-debug.js">
	</script>
	<script type="text/javascript"
		src="http://dev.sencha.com/deploy/ext-3.3.1/ext-all-debug.js">
	</script>
	
	<script type="text/javascript" src='gridPanelRestletExample.js'>
	</script>
	
</head>

<body>
</body>
</html>

Finally the javascript for the component.

src/main/webapp/gridPanelRestletExample.js

function buildWindow() {

	// The following calls the restlet to get the data
	var remoteProxy = new Ext.data.ScriptTagProxy( {
		url : 'app/addresses'
	});

	var recordFields = [ 'fullName', 'state' ];

	var store2 = new Ext.data.JsonStore( {
		proxy : remoteProxy,
		id : 'ourRemoteStore',
		root : 'records',
		autoLoad : true,
		totalProperty : 'totalCount',
		remoteSort : false,
		fields : recordFields
	});

	var cm = new Ext.grid.ColumnModel( [ {
		header : 'Full Name',
		sortable : true,
		dataIndex : 'fullName'
	}, {
		header : 'State',
		dataIndex : 'state'
	} ]);

	var gridView = new Ext.grid.GridView();
	var selModel = new Ext.grid.RowSelectionModel( {
		singleSelect : true
	});

	var grid = new Ext.grid.GridPanel( {
		title : 'Our first grid',
		renderTo : Ext.getBody(),
		autoHeight : true,
		width : 250,
		store : store2,
		view : gridView,
		colModel : cm,
		selModel : selModel
	});

}

Ext.onReady(buildWindow);

The following is a Plain Old Java Object that represents an Address. It will be used to generate the JSON response by the RESTlet.

src/main/java/com/test/Address.java

package com.test;
 
public class Address {
	private String fullName;
    private String state;

    public Address() {
    	super();
    }
    
    public Address(String fullName, String state) {
    	this.fullName = fullName;
    	this.state = state;    	
    }
    
    public String getState() {
        return state;
    }

	public void setFullName(String fullName) {
		this.fullName = fullName;
	}

	public String getFullName() {
		return fullName;
	}
}

The following is the RESTlet that will be performing all the work.

src/main/java/com/test/AddressResource.java

package com.test;

import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONObject;
import org.restlet.Context;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.MediaType;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.representation.Variant;
import org.restlet.resource.ResourceException;
import org.restlet.resource.ServerResource;

public class AddressResource extends ServerResource {

	public AddressResource() {
		super();
	}

	public AddressResource(Context context, Request request, Response response) {
		getVariants().add(new Variant(MediaType.TEXT_HTML));
	}

	@Override
	protected Representation get() throws ResourceException {
		List<JSONObject> addressList = new ArrayList<JSONObject>();

		addressList.add(new JSONObject(new Address("John Allen", "NY")));
		addressList.add(new JSONObject(new Address("Bob Smith", "NJ")));
		addressList.add(new JSONObject(new Address("John Adams", "NY")));
		addressList.add(new JSONObject(new Address("John Doe", "CA")));

		JSONArray jsonArray = new JSONArray(addressList);
		StringBuffer out = new StringBuffer();
		String cb = getQuery().getFirstValue("callback");
		out.append(cb + "(");
		out.append("{ \"totalCount\" : \"" + jsonArray.length() + "\",");
		out.append("\"records\" : ");

		out.append(jsonArray.toString());

		out.append("}");

		out.append(");");

		return new StringRepresentation(out.toString());
	}
}

The following is the RESTful Web Service that manages the Address Resource.

src/main/java/com/test/DemoApplication.java

package com.test;

import org.restlet.Application;
import org.restlet.Context;
import org.restlet.Restlet;
import org.restlet.routing.Router;

public class DemoApplication extends Application {

	public DemoApplication() {
		super();
	}

	public DemoApplication(Context parentContext) {
		super(parentContext);
	}

	public Restlet createRoot() {
		Router router = new Router(getContext());
		router.attach("/addresses", AddressResource.class);
		return router;
	}

}

src/main/webapp/WEB-INF/web.xml

<?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>Archetype Created Web Application</display-name>
 
         <servlet>
                 <servlet-name>Restlet</servlet-name>
                 <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
                 <init-param>
                         <param-name>org.restlet.application</param-name>
                         <param-value>com.test.DemoApplication</param-value>
                 </init-param>
         </servlet>
 
    <servlet-mapping>
        <servlet-name>Restlet</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
 
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
 
</web-app>

Test the application

mvn jetty:run

Test the RESTlet:
Start up jetty and navigate to the following URL:

http://localhost:8080/app/addresses?callback=callbackName
Test the Page:
http://localhost:8080/gridPanelRestlet.jsp




Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 77 other followers

February 2017
S M T W T F S
« Mar    
 1234
567891011
12131415161718
19202122232425
262728  

Blog Stats

  • 795,599 hits