Zach's Blog

Just another WordPress.com weblog

Posts Tagged ‘restful

Jersey + Guice + Scala

with 6 comments

At Pongr, our RESTful web services are built using Jersey, Guice and Scala (among many other technologies). Here’s a quick post that shows how to set up an example project that uses all three. By the end we’ll be able to declare Guice bindings in our own custom module and have them injected into Jersey resource classes.

We’ll manage everything with Maven, so first create your pom.xml. I know it looks like a lot, but only has three Jersey dependencies (and one on the Servlet 2.5 API to make things compile). The rest of this junk is mainly configuring plugins for Scala – don’t worry about it. The upshot is that you can a) run this all using mvn jetty:run, and b) can generate an Eclipse project using mvn eclipse:eclipse.

<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.pongr</groupId>
    <artifactId>jerseyguicescala</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <name>jerseyguicescala</name>
    <properties>
        <jersey-version>1.1.1-ea</jersey-version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>com.sun.jersey</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey.contribs</groupId>
            <artifactId>jersey-guice</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>com.sun.jersey.contribs</groupId>
            <artifactId>jersey-scala</artifactId>
            <version>${jersey-version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- Run with "mvn jetty:run" -->
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.19</version>
                <configuration>
                    <contextPath>/</contextPath>
                </configuration>
            </plugin>
            <!-- Begin scala plugins, inspired by: http://scala-tools.org/mvnsites/maven-scala-plugin/usage_java.html -->
            <plugin>
                <groupId>org.scala-tools</groupId>
                <artifactId>maven-scala-plugin</artifactId>
                <executions>
                    <execution>
                        <id>scala-compile-first</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>add-source</goal>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>scala-test-compile</id>
                        <phase>process-test-resources</phase>
                        <goals>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
                <executions>
                    <execution>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <configuration>
                    <sourceIncludes>
                        <sourceInclude>**/*.scala</sourceInclude>
                    </sourceIncludes>
                    <buildcommands>
                        <buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand>
                    </buildcommands>
                    <additionalProjectnatures>
                        <!-- This nature gets put after org.eclipse.jdt.core.javanature in .project so Eclipse has a J badge on the project instead of an S -->
                        <projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature>
                    </additionalProjectnatures>
                    <classpathContainers>
                        <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer>
                        <classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer>
                    </classpathContainers>
                </configuration>
            </plugin>
            <!-- http://groups.google.com/group/liftweb/browse_thread/thread/3dac7002f9e59546/3918bba2f7a92cd3?pli=1 -->
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>build-helper-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>add-source</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>src/main/scala</source>
                            </sources>
                        </configuration>
                    </execution>
                    <execution>
                        <id>add-test-source</id>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>add-test-source</goal>
                        </goals>
                        <configuration>
                            <sources>
                                <source>src/test/scala</source>
                            </sources>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <!-- End scala plugins -->
        </plugins>
    </build>
</project>

Next up, create the src/main/webapp/WEB-INF/web.xml file. This just registers our special GuiceConfig class that, uh, configures Guice.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd" metadata-complete="false" version="2.5">
    <listener>
        <listener-class>com.pongr.GuiceConfig</listener-class>
    </listener>
    <filter>
        <filter-name>guiceFilter</filter-name>
        <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>guiceFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>

We’ll create an example Guice module in the src/main/java/com/pongr/ExampleModule.java file. It just binds a message String that we’ll inject into our resource classes later.

package com.pongr;

import com.google.inject.*;
import com.google.inject.name.*;

public class ExampleModule extends AbstractModule
{
    @Override
    protected void configure()
    {
        bindConstant().annotatedWith(Names.named("message")).to("Hello, World!");
    }
}

Next up is src/main/java/com/pongr/GuiceConfig.java where we connect Jersey to Guice. This is where we create the Guice Injector using our ExampleModule and configure any Jersey properties, like the package(s) that contain our resource classes.

package com.pongr;

import java.util.*;

import com.google.inject.*;
import com.google.inject.servlet.*;
import com.sun.jersey.api.core.*;
import com.sun.jersey.guice.spi.container.servlet.*;

public class GuiceConfig extends GuiceServletContextListener
{
    @Override
    protected Injector getInjector()
    {
        final Map<String, String> params = new HashMap<String, String>();
        params.put(PackagesResourceConfig.PROPERTY_PACKAGES, "com.pongr");
        return Guice.createInjector(new ExampleModule(), new ServletModule()
        {
            @Override
            protected void configureServlets()
            {
                serve("/*").with(GuiceContainer.class, params);
            }
        });
    }
}

Now for the fun! This src/main/java/com/pongr/JavaResource.java file gets the message String injected and displays it.

package com.pongr;

import javax.ws.rs.*;
import javax.ws.rs.core.*;

import com.google.inject.*;
import com.google.inject.name.*;

@Path("java")
public class JavaResource
{
    private String message;

    @Inject
    public JavaResource(@Named("message") String message)
    {
        this.message = message;
    }

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String get()
    {
        return "From Java: " + message;
    }
}

And for good measure here’s src/main/scala/com/pongr/ScalaResource.scala. Same as JavaResource, except in Scala. The Guice @Inject and @Named annotations can be a bit tricky for constructor injection, so here’s how it’s done.

package com.pongr

import javax.ws.rs._
import javax.ws.rs.core._

import com.google.inject._
import com.google.inject.name._

@Path("scala")
class ScalaResource @Inject() (@Named("message") message: String) {
  @GET
  @Produces(Array(MediaType.TEXT_PLAIN))
  def get(): String = "From Scala: " + message
}

That’s it! Now just run mvn jetty:run on your command line and hit http://localhost:8080/java and http://localhost:8080/scala in your browser to see these resources in action. As always, you can also visit http://localhost:8080/application.wadl to get an overview of the available resources. Enjoy!

Written by Zach Cox

September 22, 2009 at 10:03 pm

Posted in Java, Scala

Tagged with , , , ,

Override the HTTP Request Method in Jersey

with 2 comments

RESTful web services take advantage of all of the HTTP methods including GET, POST, PUT, DELETE, HEAD and OPTIONS.  However, a lot of HTTP libraries (BlackBerry JDE, iPhone SDK, etc) and all browsers only support GET and POST.  There are several ways to get around these deficiencies – in this post I’ll describe two of them and show a Jersey filter for implementing them.

Jersey provides a PostReplaceFilter that looks for the X-HTTP-Method-Override header and changes the request’s method to that header’s value. To use this approach to perform a PUT from your client, just do a POST request and include a “X-HTTP-Method-Override: PUT” header.  The filter will then translate it into a PUT request before handling it.

Ruby on Rails looks for a _method form parameter and changes the request’s method to that parameter’s value.  To use this approach to perform a PUT from your client, just do a POST request and include a “_method=PUT” form parameter.  The Rails version is particularly useful if you’re making the request from an HTML form (updating or deleting a resource, for example).

I combined the two HTTP method overwriting approaches into a new Jersey filter:

import com.sun.jersey.spi.container.*;

/** Clients may override the HTTP method by setting either the X-HTTP-Method-Override header or
 * the _method form or query parameter in a POST request.  If both the X-HTTP-Method-Override
 * header and _method parameter are present in the request then the X-HTTP-Method-Override header
 * will be used.
 *
 * Inspired by https://jersey.dev.java.net/nonav/apidocs/1.1.0-ea/jersey/com/sun/jersey/api/container/filter/PostReplaceFilter.html
 */
public class OverrideHttpMethodFilter implements ContainerRequestFilter
{
    private static final String HEADER = "X-HTTP-Method-Override";
    /** The name of the form or query parameter that overrides the HTTP method. */
    public static final String METHOD = "_method";

    @Override
    public ContainerRequest filter(ContainerRequest request)
    {
        if (request.getMethod().equalsIgnoreCase("POST"))
            if (!override(request.getRequestHeaders().getFirst(HEADER), request))
                if (!override(request.getFormParameters().getFirst(METHOD), request))
                    override(request.getQueryParameters().getFirst(METHOD), request);

        return request;
    }

    private boolean override(String method, ContainerRequest request)
    {
        if (!Strings.isEmpty(method))
        {
            request.setMethod(method);
            return true;
        }

        return false;
    }
}

If you’re creating a web service that uses more than just GET and POST, combining these two approaches will make the unfortunate developers who have to use these flawed HTTP libraries very happy!

Written by Zach Cox

June 17, 2009 at 1:10 pm

Posted in Java

Tagged with , ,

The Top-Level Resource in Jersey

leave a comment »

In RESTful Web Services, the authors define three types of resources exposed by a web service:

  1. Predefined one-off resources for especially important aspects of the application
  2. A resource for every object exposed through the service
  3. Resources representing the results of algorithms applied to the data set

#2 is probably what you think of first when you hear “RESTful web service”.  It’s basic CRUDRuby on Rails was designed to make it super easy to expose these types of resources.  If you have a restaurants table in your databse it gets exposed at http://yourservice.com/restaurants.  Create a new restuarant using POST /restaurants.  View restaurant info at GET /restaurants/{restaurantId}.  Modify a restaurant using PUT /restaurants/{restaurantId}.  Flush a restaurant down the toilet using DELETE /restaurants/{restaurantId}.

#3 is a bit less common but still familiar.  http://google.com/search?q=restful+web+services is Google’s resource for documents about “restful web services”.  It’s the result of using Google’s search algorithms to find relevant documents.

#1 can be used for several different purposes, one of which is to provide a top-level entry point into your web service.  What you choose to put in the representation of the resource at  http://yourservice.com depends on your service.  It could simply provide a way to get to another resource, like http://google.com does (it gives you a search form).  Or it could give you some relevant account info, like https://s3.amazonaws.com (it lists your S3 buckets).  If you’re using XHTML as your representation format, it could provide some documentation about how to use your web service and provide various entry points (ie links) into it.

Using Jersey, it’s incredibly simple to create the top-level resource:

@Path("/")
public class TopLevelResource
{
    @GET
    @Produces(MediaType.APPLICATION_XHTML_XML)
    public String get()
    {
        return "<html><body>This is your top-level resource</body></html>";
    }
}

That’s all there is to it!  The @Path(“/”) annotation makes this resource the top-level resource.  Of course you can add handlers for methods other than GET, but GET should always be used to provide some information about the entire web service.

Written by Zach Cox

June 15, 2009 at 10:55 am

Posted in Java

Tagged with ,

Follow

Get every new post delivered to your Inbox.