Using Apache Wink, Eclipse, and Maven to develop RESTful Web services

Apache Wink is an open source implementation of the Java™ API for RESTful Web Services (JAX-RS) specification. Learn how to develop, deploy, and run RESTful Web services using Apache Wink along with the Eclipse IDE and the Maven project management tool.

Gabriel Mateescu, Computational Scientist, National Supercomputer Center, Sweden

Gabriel MateescuGabriel Mateescu builds distributed systems for managing and executing data- and compute-intensive applications, such as bioinformatics and high-energy physics simulations. He has worked on several projects, including the LHC Computing Grid, the Distributed European Infrastructure for Supercomputing Applications (DEISA), GridCanada, and NIH MIDAS. You can reach Gabriel at gabriel@vt.edu.



09 February 2010

Also available in Japanese

Apache Wink is an Apache incubator project that enables the creation and consumption of REST Web services. With REST Web services, the interaction between clients and services is constrained to a set of predefined operations, and the complexity of the client-server interactions is limited to the resource representations exchanged between the client and services. This approach allows you to build interoperable, scalable, and reliable REST-based distributed hypermedia systems.

Frequently used acronyms

  • API: Application programming interface
  • HTTP: Hypertext Transfer Protocol
  • IDE: Integrated development environment
  • JSON: JavaScript Object Notation
  • REST: Representational State Transfer
  • URI: Uniform Resource Identifier
  • XML: Extensible Markup Language

This article shows how to develop, deploy, and run RESTful Web services using Apache Wink along with the Eclipse IDE and the Maven project management tool.

The REST approach to Web services

The REST approach to designing Web services constrains the interaction between clients and services to the set of create, read, update, delete (CRUD) operations. These operations map directly to HTTP methods—specifically, to POST, GET, PUT, and DELETE. Although the RESTful style is not tied to the HTTP protocol, this article assumes that HTTP is used for communication between clients and services.

REST Web services perform CRUD operations on resources. Clients exchange with REST services representations of the state of the resources. The data format that the representations use are specified in the header of the HTTP request or response—XML and JSON are widely used formats. Data formats can vary from one operation to another; for example, the data format for creating a resource is different from the format used to read the resources. REST services maintain the state of the resources, but—unlike servlets—do not maintain client session information.

The REST approach enables building interoperable, scalable, and reliable REST-based distributed systems. For example, the GET, PUT, and DELETE methods are idempotent, meaning that the result of executing them multiple times is the same as that of executing them once. Because GET operations do not change the state of the resources, results of GET requests can be cached to accelerate the request-response cycle.

JAX-RS defines an API for RESTful Java Web Services over the HTTP protocol. JAX-RS implementations include Apache Wink, Sun Jersey, and JBoss RESTEasy. This article uses Apache Wink.

JAX-RS harnesses the power of Java annotations, using annotations to perform operations such as:

  • Binding HTTP methods and URIs to methods of a Java class
  • Injecting elements from the URI or the HTTP header as method parameters
  • Converting the body of an HTTP message to and from a Java type
  • Binding URI patterns to Java classes and methods—the @Path annotation
  • Binding HTTP operations to Java methods—the @GET, @POST, @PUT, and @DELETE annotations

JAX-RS also provides a framework for building new functionality. For example, for custom data formats, programmers can develop message readers and writes to marshall Java objects to and unmarshall them from HTTP messages.

In this article, you will download Apache Wink using Eclipse and Maven, run the HelloWorld example included in Apache Wink, and then create your own REST Web service as an Eclipse project.


Getting Apache Wink with Eclipse

Develop skills on this topic

This content is part of a progressive knowledge path for advancing your skills. See Build RESTful web services with Java technology

In this section, you use Eclipse, together with the Maven Integration for Eclipse (known as m2eclipse) and the Subclipse plug-ins, to install Apache Wink. (M2eclipse provides access to Maven from Eclipse; Subclipse provides access to Subversion repositories.) You also use Eclipse as a platform from which to build and run Web services.

Prerequisites

Before getting Apache Wink, download and install the following software packages (see Resources for the download URLs):

  • Java Software Development Kit (JDK) version 6. Set the JAVA_HOME environment variable and add to the path %JAVA_HOME%\bin (in Windows®) or $JAVA_HOME/bin (in Linux®).
  • Apache Tomcat version 6.0. Set the CATALINA_HOME environment variable to point to the installation directory.
  • Eclipse IDE for Java™ Platform, Enterprise Edition (Java EE) developers. The current release at the time of writing is Eclipse Galileo.

Install Subclipse

To manage Maven-aware projects with Eclipse, install the Eclipse plug-ins Subclipse and m2eclipse. To install the Subclipse plug-in, perform these steps:

  1. Start Eclipse.
  2. Click Help in the menu bar, then select Install new software.
  3. In the Available Software window, click Add.
  4. In the Add Site window, type:

         Name:     Subclipse 
         Location: http://subclipse.tigris.org/update_1.6.x/

    and then click OK.

  5. In the Available Software window, select the Subclipse (Required) and SVNKit Client Adapter (Not required) check boxes under Subclipse, as shown in Figure 1, and then click Next.
    Figure 1. Installing the Subclipse plug-in
    Screen shot of Install screen, showing Available software. 'Subclipse' and 'SVNKit Client Adapter' are checked.
  6. In the Install Details window, click Next.
  7. In the Review Licenses window, review the licenses, accept the terms of the license agreement, and click Finish.
  8. Click Yes to restart Eclipse.

Install m2eclipse

To install the m2eclipse plug-in, proceed as for the Subclipse plug-in with these exceptions:

  • In the Add Site window, type:

         Name:     Maven Integration for Eclipse
         Location: http://m2eclipse.sonatype.org/update/

    and then click OK.

  • In the Available Software window, select the Maven Integration for Eclipse (Required) and Maven SCM handler for Subclipse (Optional) check boxes, as shown in Figure 2, and then click Next.
    Figure 2. Installing the m2eclipse plug-in
    Screen shot of install screen showing available software. 'Maven Integration for Eclipse' and 'Maven SCM handler for Subclipse' are checked.

Get Apache Wink

Now, you can use Eclipse to check out the Apache Wink examples from the repository, download the required Java archive (JAR) files (including the Apache Wink JAR files) to a local repository, and build and run the Apache Wink HelloWorld example. To do so, perform these steps:

  1. In Eclipse, select File > Import to launch the Import Wizard.
  2. On the Select wizard page, in the Select and import source box, type maven.
  3. Under Maven, select Materialize Maven Projects, and then click Next.
  4. On the Select Maven artifacts wizard page, click Add.
  5. On the Add Dependency page, type org.apache.wink.example in the Enter groupId, artifactId box.
    Note:Artifact is the term used in Maven to refer to a hierarchical structure of software packages that are versioned and stored in repositories.
  6. In the Search Results area, select org.apache.wink.example apps, as shown in Figure 3, and then click OK.
    Figure 3. The apps artifact in the org.apache.wink.example group
    Screen shot of the 'Add dependency' window. 'org.apache.wink.example apps' is selected.
  7. On the Select Maven artifacts wizard page, click Next, and then click Finish.
  8. On the Maven Projects wizard page, select only the /pom.xml check box, and then click Finish.

Maven resolves all the dependencies of an artifact by downloading them from remote repositories and building a local repository. One of the strengths of Maven is that it handles transitive dependencies; therefore, in the Maven Project Object Model (POM) file, you need to declare only the direct dependencies of an artifact, and Maven will resolve higher-order dependencies for you.

When step 8 above is complete, an Eclipse project is created containing the code in the apps module of the Apache Wink examples. Explore the project files in the Project Explorer view of Eclipse.


The Apache Wink HelloWorld service

Let's examine the HelloWorld Java class in the apps module. In the Project Explorer view, click apps > HelloWorld > src > main, and then open the file HelloWorld.java, whose skeleton is shown in Listing 1.

Listing 1. The HelloWorld.java file
package org.apache.wink.example.helloworld;
...

@Path("/world")
public class HelloWorld {

   public static final String ID = "helloworld:1"; 
   
   @GET
   @Produces(MediaType.APPLICATION_ATOM_XML)
   public SyndEntry getGreeting() {
      SyndEntry synd = new SyndEntry(new SyndText("Hello World!"), ID, new Date());
      return synd;
   }
}

HelloWorld is a JAX-RS resource (or service), as indicated by the @Path("/world") annotation preceding the class definition. The string "/world" is the relative root URI of the resource. JAX-RS routes HTTP requests matching the relative URI "/world" to methods of the HelloWorld class.

The only method of the HelloWorld class—getGreeting—has a @GET annotation, meaning that it will serve HTTP GET requests.

The @Produces(MediaType.APPLICATION_ATOM_XML) annotation indicates the media type of the HTTP response—that is, the value of the Content-Type field in the header of the HTTP response.

The absolute URI associated with the relative root URI "/world" is determined by the settings in the deployment descriptor web.xml, which resides under HelloWorld/src/main/webapp/WEB-INF and is shown in Figure 4.

Figure 4. Deployment descriptor of the HelloWorld application
Screen shot of the web.xml file

Notice that the URI pattern /rest/* is bound to the restSdkService servlet. The context path of this servlet is HelloWorld, which is defined by the <finalName> element in the HelloWorld/pom.xml file. Thus, the absolute URI of the HelloWorld resource is:

     http://host:port/HelloWorld/rest/world

The servlet name restSdkService in Figure 4 refers to the org.apache.wink.server.internal.servlet.RestServlet Apache Wink class, as shown by the <servlet> element in the figure. The RestServlet class is passed the name of the HelloWorld class using the init-parameter applicationConfigLocation, which in turn points to the file application located alongside web.xml in the folder HelloWorld/src/main/webapp/WEB-INF. The application file has only one line, which is the qualified name of the HelloWorld resource:

org.apache.wink.example.helloworld.HelloWorld

The RestServlet servlet can run in a non-JAX-RS-aware servlet container, thereby supporting easy deployment of JAX-RS services to non-JAX-RS-aware containers.

Now, let's build the HelloWorld service, and then deploy and run it in the Tomcat 6.0 servlet container.

Building HelloWorld

From Eclipse, you use the m2eclipse plug-in to build, deploy, and run HelloWorld. First, compile the source code and build the Web archive (WAR) file for the HelloWorld service. To build the service, instruct m2eclipse to perform the install life cycle phase. (Executing a Maven life cycle phase triggers the execution of the previous phases in the project life cycle.) To execute the install phase, right-click HelloWorld in the Project Explorer view, and then click Run As > Maven install, as shown in Figure 5.

Figure 5. Performing the Maven install phase
Screen shot showing the 'Run As --> Maven install' path selected.

Maven downloads all the dependencies (from the central repository http://repo1.maven.org/maven2 or from a mirror repository) and builds the local repository under %HOMEPATH%\.m2\repository in Windows® or $HOME/.m2/repository in Linux®. The actions that Maven takes are logged in the console view of the Eclipse window.

If the install phase finishes successfully, the WAR file HelloWorld.war is built under the target directory and deployed to the local repository, and the Console view displays the message "Build successful."

Deploying HelloWorld to Tomcat

You use Maven's Tomcat plug-in. (Maven, like Eclipse, provides a lot of functionality through plug-ins.) You must tell Maven the location of the Tomcat plug-in by specifying the groupId and artifactId of the plug-in, as shown in Figure 6 (lines 45-46 in pom.xml).

Figure 6. The Tomcat Maven plug-in
Screen shot showing the pom.xml file

You also need to tell Maven the user name and password used to access the Tomcat manager application. Maven uses the manager application to instruct Tomcat to deploy or undeploy a Web application. Tell Maven the authentication information as follows:

  1. Declare a Tomcat server configuration—call it tomcat-localhost—of the tomcat-maven-plugin artifact, as shown in Figure 6 (lines 47-49 in pom.xml).
  2. Define this configuration in the Maven settings file settings.xml (located under %HOMEPATH%\.m2\ in Windows and $HOME/.m2 in Linux), as shown in Listing 2.

    Listing 2. The Maven settings.xml file
    <?xml version="1.0" encoding="UTF-8"?>
    
    <settings 
        xmlns="http://maven.apache.org/SETTINGS/1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 
                            http://maven.apache.org/xsd/settings-1.0.0.xsd">
      <servers>
        <server>
          <id>tomcat-localhost</id>
          <username>admin</username>
          <password>admin</password>
        </server>
      </servers>
    
    </settings>

Now, you're ready to deploy the service to Tomcat. This is done by executing the redeploy goal of the Tomcat plug-in. (Unlike a life cycle phase, whose execution is automatically preceded by the previous phases in the life cycle, a Maven goal is executed by itself.) To execute the redeploy goal, perform these steps:

  1. Insert authentication information in the Tomcat configuration file conf/tomcat-users.xml (located under CATALINA_HOME), as shown in Figure 7, but use a password other than admin.
    Figure 7. Tomcat authentication configuration
    Tomcat authentication configuration
  2. Start Tomcat by running:

    In Windows:   %CATALINA_HOME%\bin\catalina.bat start
    In Linux:     $CATALINA_HOME/bin/catalina.sh start
  3. Execute maven tomcat:redeploy, which deploys HelloWorld.war to Tomcat using the Tomcat manager application. To do so, complete these steps:
    1. In the Project Explorer view, right-click HelloWorld, and then click Run As > Run configurations.
    2. In the Create, manage, and run configurations window, select Maven Build > New_configuration, and then click the Main tab (see Figure 8).
      Figure 8. Running the tomcat:redeploy goal
      Screen shot showing the 'Run Configurations' screen
    3. Click Browse workspace, then select apps > HelloWorld, and then click OK.
    4. In the Goals box, type tomcat:redeploy and then click Run.

      If the redeploy goal executes successfully, the Console view displays the message, "Build successful."

Now, you can invoke the HelloWorld service with an HTTP client such as Curl, as shown in Listing 3.

Listing 3. Invoke the HelloWorld service in Curl
  $ curl -X GET  http://localhost:8080/HelloWorld/rest/world
  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
  <entry xmlns="http://www.w3.org/2005/Atom" 
         xmlns:ns2="http://a9.com/-/spec/opensearch/1.1/" 
         xmlns:ns3="http://www.w3.org/1999/xhtml">
    <id>helloworld:1</id>
    <updated>2010-01-06T13:26:43.924+01:00</updated>
    <title type="text">Hello World!</title>
  </entry>

Developing a REST Web service

In this section, you develop from scratch a REST Web service for managing a collection of book resources. The source code for this REST service is available from the Download table below.

The key steps in developing such a service are:

  1. Define the URIs of the resources, the methods used to manipulate the resources, and the data formats for each method.
  2. Define the Java objects that represent the book resource, and provide the Java code or annotations to marshall and unmarshall the Java objects.
  3. Define the Java service that binds the URIs and HTTP methods to Java methods.
  4. Supply a concrete subclass of the abstract class javax.ws.rs.core.Application.

Let's perform these steps.

Binding paths and HTTP methods to Java methods

This service supports the GET, POST, PUT, and DELETE HTTP methods and maps HTTP requests to Java methods as follows:

  • Map POST /books requests to the Java method with the signature createBook(@Context UriInfo, Book). (The annotation @Context is described in The JAX-RS Web service.) The data format for creating a Book resource is:

         POST /books HTTP/1.1
         Content-Type: application/xml
    
         <book>
              <title> ... </title>
              <isbn> .... </isbn>
         </book>
  • Map GET /books requests to the Java method getBook(). The data format for getting the book resources is:

         GET /books HTTP/1.1
         Content-Type: application/xml
  • Map GET /books/{id} requests to the Java method with the signature getBook(@PathParam("id") int). (The annotation @PathParam is described in The JAX-RS Web service.) The data format for getting the book resource with the URI pattern /books/{id} is:

         GET /books/{id} HTTP/1.1
         Content-Type: application/xml
  • Map PUT /books/{id} requests to the Java method with the signature updateBook(@PathParam("id") int, Book). The data format for updating a book resource with the URI pattern /books/{id} is:

         PUT /books/{id} HTTP/1.1
         Content-Type: application/xml
         
         <book>
             <title> ... </title>
             <isbn> .... </isbn>
         </book>
  • Map DELETE /books/{id} requests to the Java method with the signature deleteBook(@PathParam("id") int). The data format for deleting a book resource with the URI pattern /books/{id} is:

         DELETE /books/{id} HTTP/1.1
         Content-Type: application/xml

The object model of the books

The Java object model used to implement the Book collection has three classes:

Listing 4. The Book class
package com.ibm.devworks.ws.rest.books;
import javax.xml.bind.annotation.*;

@XmlRootElement(name="book")
@XmlAccessorType(XmlAccessType.FIELD)
public class Book {

	@XmlAttribute(name="id")
	private int id;

	@XmlElement(name="title")
	private String title;

	@XmlElement(name="isbn")
	private String ISBN;

	@XmlElement(name = "link")
	private Link link;

	public Book() { }

	public int getId() { return id; }
	public void setId(int id) { this.id = id; }

	public String getTitle() { return title; }
	public void setTitle(String title) { this.title = title; }

	public String getISBN() { return ISBN; }
	public void setISBN(String ISBN) { this.ISBN = ISBN; }
	
	public Link getLink() { return link; }
	public void setLink(String uri) { this.link = new Link(uri); }
}

In the Book class, you use Java Architecture for XML Binding (JAXB) annotations to perform marshalling and unmarshalling of Java objects. Apache Wink automatically marshalls and unmarshalls Java objects that have JAXB annotations, including creating the Marshaller and Unmarshaller instances that perform the work.

You represent the collection of book objects using the BookList class that stores internally the objects in a field of type ArrayList, which is JAXB-annotated for conversion to XML format.

Listing 5. The BookList class
package com.ibm.devworks.ws.rest.books;

import java.util.ArrayList;
import java.util.Map;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlElementRef;

@XmlRootElement(name="books")
public class BookList {

	@XmlElementRef
	ArrayList<Book> books;	

	public BookList() {  }

	public BookList( Map<Integer, Book> bookMap ) {
		books = new ArrayList<Book>( bookMap.values() );
	}	
}

You use the Link class to insert link elements in the XML representation of the book objects (see Listing 6).

Listing 6. The Link class
package com.ibm.devworks.ws.rest.books;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;

@XmlRootElement(name="link")
@XmlAccessorType(XmlAccessType.FIELD)
public class Link {

	@XmlAttribute
	String href = null;
	
	@XmlAttribute
	String rel = "self";
	
	public Link() { }

	public Link( String uri) { 
		this.href = uri; 	
	}
	
	public Link( String href, String rel) { 
		this.href = href; 	
		this.rel = rel; 
	}
}

The JAX-RS Web service

Now, you define the Java service that binds the URIs and HTTP methods to Java methods. You can define the service either as a Java interface or as a class; in the former case, you also define the class implementing the interface. In the interface, you localize the JAX-RS annotations and add a class to implement the interface.

The BookService Java interface is shown in Listing 7. The @javax.ws.rs.Path annotation designates this interface as a JAX-RS service. The value /books of the annotation defines the relative root URI of the service. The annotations @javax.ws.rs.POST, @javax.ws.rs.GET, @javax.ws.rs.PUT, and @javax.ws.rs.DELETE bind the HTTP POST, GET, PUT, and DELETE operations to the Java methods immediately following them.

Listing 7. The BookService interface
package com.ibm.devworks.ws.rest.books;
import javax.ws.rs.*;
import javax.ws.rs.core.*;

@Path("/books")
public interface BookService {
	
	@POST
	@Consumes(MediaType.APPLICATION_XML)
	@Produces(MediaType.APPLICATION_XML)
	public Response createBook(@Context UriInfo uriInfo, Book book);
		
	@GET
	@Produces(MediaType.APPLICATION_XML)
	public BookList getBook();
	
	@Path("{id}")
	@GET
	@Produces(MediaType.APPLICATION_XML)
	public Book getBook(@PathParam("id") int id);
	
	@Path("{id}")
	@PUT
	@Consumes(MediaType.APPLICATION_XML)
	public void updateBook(@PathParam("id") int id, Book book_updated);	
	
	@Path("{id}")
	@DELETE
	public void deleteBook(@PathParam("id") int id);	
}

You attach specific @PATH annotations to the methods whose URI are different from that specified by the @PATH("/books") annotation of the interface. @PATH annotations are cumulative, meaning that a path expression following another path expression is appended to the preceding expression. So, the path pattern that binds to the deleteBook method is /books/{id}.

JAX-RS provides a mechanism to extract information from an HTTP request, cast it to a Java object, and inject it into a Java method parameter. This is called injection. Injections are specified using Java annotations. In the BookService interface, you insert two injection annotations:

  • The @Context annotation extracts the URI information from the HTTP request, converts it to a UriInfo object, and injects the object as the method parameter uriInfo.
  • The @PathParam("id") annotation matches the preceding @Path({"id"}) annotation. This annotation extracts the {id} from the URI pattern /books/{id} and injects it into the value of the parameter id of the getBook method.

Notice that the methods of BookService take as parameters—and return—Java objects such as Book; this is possible, because these objects are JAXB-annotated, so Apache Wink automatically takes care of marshalling and unmarshalling them.

The skeleton of the class implementing the BookService is shown in Listing 8. BookServiceImpl is a singleton class that uses an in-memory map to maintain the collection of book objects. The singleton instance serves concurrent requests using multithreading, so it has to be thread-safe.

Listing 8. The BookService implementation class
package com.ibm.devworks.ws.rest.books;
import javax.ws.rs.*;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Path("/books")
public class BookServiceImpl implements BookService {
	
	private static BookServiceImpl instance = null;
	
	private BookServiceImpl() {  }
	
	public synchronized static BookServiceImpl getInstance() {
		if(instance == null) {
			instance = new BookServiceImpl();
		}
		return instance;
	}
	
	private Map <Integer, Book> bookMap =
		new ConcurrentHashMap <Integer, Book>();
	
	private AtomicInteger seqNumber = new AtomicInteger();

	public Response createBook(@Context UriInfo uriInfo, Book book) 
	throws WebApplicationException {	
	  ...
	}
	
	public BookList getBook() {
	   ...	
	}
	
	public Book getBook(@PathParam("id") int id)
	throws WebApplicationException {
	   ...
	}
		
	public void updateBook(@PathParam("id") int id, Book book_updated) 
	throws WebApplicationException {	
	  ...
	}
	
	public void deleteBook(@PathParam("id") int id) 
	throws WebApplicationException {
	    ...			
	}	
}

You store the collection of book objects in a map. To provide thread-safe access to the map, you use a ConcurrentHashMap. To generate unique book IDs, you use an AtomicInteger that ensures that the incrementation operation is atomic, and thus thread-safe.

Subclassing the Application abstract class

A JAX-RS Web application contains a set of resources (REST Web services). These resources are exposed as subclasses of the JAX-RS abstract class javax.ws.rs.core.Application. The class BookWebApp, shown in Listing 9, extends the Application class.

Listing 9. Concrete subclass of javax.ws.rs.core.Application
package com.ibm.devworks.ws.rest.books;

import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.core.Application;

public class BookWebApp extends Application {

	private Set<Object> svc_singletons = new HashSet<Object>();	
	private Set<Class<?>> svc_classes  = new HashSet<Class<?>>();

	public BookWebApp() {
		svc_singletons.add(BookServiceImpl.getInstance());
	}
	
	@Override
	public Set<Object> getSingletons() {
		return svc_singletons;
	}
	 
	@Override
	public Set<Class<?>> getClasses() {
		return svc_classes;
	}

}

The constructor of BookWebApp gets the singleton instance of the book service implementation object. The getSingletons method returns a set whose only element is this singleton. JAX-RS does not dispose of the singleton after serving a request.


Building and deploying the REST Web service

You use Eclipse to create a dynamic Web project. This project contains the Java classes described in the previous section as well as other resources such as the Web application deployment descriptor and the required JAR files.

Note: An alternative to creating an Eclipse dynamic Web project is creating a Maven project from an archetype such as maven-archetype-webapp or webapp-jee5. (An archetype is a Maven project template.) However, in the current version of Maven, there are some glitches in generating the project metadata that Eclipse uses: to enable automatic code building in the IDE, some Eclipse project files must be manually modified. For this reason, this article uses the Eclipse dynamic Web project.

The Eclipse project for the Web service

The Eclipse dynamic Web project supports developing Web applications that run in a servlet container, so it is a good project template for developing Apache Wink services. To create a dynamic Web project for the Book REST service, complete these steps:

  1. In Eclipse, click File > New > Dynamic Web Project.
  2. In the Dynamic Web Project Wizard, type Books in the Project name box.
  3. Set up a Tomcat run time by clicking New next to the Target runtime box.
  4. On the New Server Runtime Environment wizard page, click Apache > Apache Tomcat v6.0, and then click Next.
  5. On the Tomcat Server wizard page, click Browse, and then navigate to the CATALINA_HOME directory that you defined in the Prerequisites section.
  6. Click OK, and then click Finish.
  7. On the Dynamic Web Project page, click Finish.

Add the Java classes described in the previous section to the Books project that you created. To do so, complete these steps:

  1. In the Project Explorer view, open the Books folder. Right-click Java Resources:src, and then click New > Package.
  2. In the Java Package window, in the Name box, type the name of the package—com.ibm.devworks.ws.rest.books—and then click Finish.
  3. Add the Java classes to the com.ibm.devworks.ws.rest.books package:
    1. In the Project Explorer view, right-click the package, and then click New > Class.
    2. In the Name box, type the name of the class (for example, Book for Book.java), then click Finish.
    3. Use the Eclipse Java editor to create the classes.

Next, add to the project the JAR files needed to build and run an Apache Wink service. Maven downloaded the JAR files to the local repository when you created the apps project. The local repository resides in %HOMEPATH%\.m2\repository in Windows or $HOME/.m2/repository in Linux.

To add the JAR files to the project, complete these steps:

  1. In the Project Explorer view, navigate to Books/Web Content/WEB-INF.
  2. Right-click lib, and then click Import > General > File System, and then click Next.
  3. In the File System window, import the JAR file jsr311-api-1.0.jar from the local Maven repository (which was populated by m2eclipse when you imported the apps Apache Wink module) by navigating to the directory containing the JAR file, and then clicking OK. In the File System window, select the JAR file, and then click Finish.
  4. Repeat steps 2 and 3 for the JAR files wink-server-1.0-incubating.jar, wink-common-1.0-incubating.jar, slf4j-api-1.5.8.jar, and slf4j-simple-1.5.8.jar.

When you have imported all the libraries, the lib directory will contain the JAR files shown in Figure 9.

Figure 9. Libraries needed by an Apache Wink service
Screen shot showing the Project Explorer window open WEB-INF lib folders are expanded, showing a list of Wink JAR files.

You can also create the Eclipse project for the Book service by importing the project from the code sample provided in the Download section below. To do so, download and extract the file. Then, in Eclipse, click File > Import > Existing Project Into Workspace. In the Import Projects Wizard, click Browse, navigate to the Books folder, click OK, and then click Finish.

Deploying the service into Tomcat

In the deployment descriptor file web.xml, shown in Listing 10, you map the URIs with relative root path /* to the Wink servlet org.apache.wink.server.internal.servlet.RestServlet. The RestServlet is passed as init-param the name of the Application subclass that the Book service supplies.

Listing 10. The BookService deployment descriptor 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>Book Web Application</display-name>

  <servlet>
    <servlet-name>restSdkService</servlet-name>
	<servlet-class>org.apache.wink.server.internal.servlet.RestServlet</servlet-class>
	<init-param>
		<param-name>javax.ws.rs.Application</param-name>
		<param-value>com.ibm.devworks.ws.rest.books.BookWebApp</param-value>
	</init-param>
  </servlet>

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

</web-app>

After setting up the deployment descriptor, you can deploy the Books service to Tomcat. For testing, deploy and run the Book service within a Tomcat instance managed by Eclipse. To do so, complete these steps:

  1. In the Project Explorer view, right-click Books, and then click Run As > Run on Server.
  2. In the Run on Server window, click Finish, which deploys the Books service to the Tomcat runtime that was configured when you created the Books project, and starts Tomcat.

When you are done with the testing, you package the Books service in a WAR file for deployment to production environments. To do so, in the Project Explorer view, right-click Books, and then click Export > WAR file. In the WAR Export Wizard, click Browse, select the folder in which to create the WAR file, and then click Save and Finish.


Invoking the REST Web service

You can invoke the Books service using an HTTP client that supports the HTTP operations GET, POST, PUT, and DELETE. Listing 11 shows how you invoke the service with Curl. First, you get the representations of all books (initially, there is no book); then, you create two books using the representations jaxrs.xml and rest.xml. Finally, you get the representations of all the books and of the book with id=2.

Listing 11. Invoking the Book service
$ curl   -X GET  http://localhost:8080/Books/books
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<books/>


$ more Books\xml\jaxrs.xml
<?xml version="1.0" encoding="UTF-8"?>
<book>
   <titleRESTful Java with JAX-RS</title>
   <isbn>978-0-596-15804-0</isbn>
</book>

$ more Books\xml\rest.xml
<?xml version="1.0" encoding="UTF-8"?>
<book>
   <title>RESTful Web Services</title>
   <isbn>978-0-596-52926-0</isbn>
</book>


$  curl -H "Content-Type: application/xml" -T Books\xml\jaxrs.xml \
        -X POST http://localhost:8080/Books/books

$  curl -H "Content-Type: application/xml" -T Books\xml\rest.xml \
        -X POST http://localhost:8080/Books/books


$ curl   -X GET  http://localhost:8080/Books/books
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<books>
  <book id="2">
     <title>RESTful Web Services</title>
     <isbn>978-0-596-52926-0</isbn>
     <link rel="self" href="http://localhost:8080/Books/books/2"/>
  </book>
  <book id="1">
    <title>RESTful Java with JAX-RS</title>
    <isbn>978-0-596-15804-0</isbn>
    <link rel="self" href="http://localhost:8080/Books/books/1"/>
  </book>
</books>

$ curl   -X GET  http://localhost:8080/Books/books/2
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<book id="2">
  <title>RESTful Web Services</title>
  <isbn>978-0-596-52926-0</isbn>
  <link rel="self" href="http://localhost:8080/Books/books/2"/>
</book>

Conclusion

This article showed how a range of technologies can work together to enable the development, building, and deployment of Apache Wink REST Web services. The power of Java annotations simplifies the development.

REST Web services enable applications to exchange linked data. Sir Tim Berners-Lee has predicted that linked data will transform the Web. Bill Burke has noted in his book RESTful Java with JAX-RS that by confining the complexity of service interactions to the data representations, REST Web services support a new level of service composability and reuse.

This article only scratched the surface of developing Apache Wink services. Other important features of Apache Wink include link builders, custom message body readers, and writers for non-supported data formats. To learn more about the Apache Wink framework, be sure to look at the other examples included in Apache Wink.


Download

DescriptionNameSize
Source code for this articlewink_code.zip645KB

Resources

Learn

Get products and technologies

  • Apache Wink framework: Download the framework for building RESTful web services.
  • JDK 6: Download JDK 6 update 17 (jdk-1.6.0_17).
  • Apache Tomcat 6.0: Download Apache Tomcat 6.0.20.
  • Eclipse: Download the Eclipse IDE for Java EE developers.
  • IBM product evaluation versions: Download these versions today and get your hands on application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Web development on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Web development
ArticleID=467065
ArticleTitle=Using Apache Wink, Eclipse, and Maven to develop RESTful Web services
publish-date=02092010