javarestjax-rsembedded-server

JAX-RS with embedded server


Clarification: this question was about GZIPping an JAX-WS-based REST service, but I've decided to change the topic to make it easier to find

I'm implementing a REST service via JAX-WS Provider <Source>, and publishing it with standard Endpoint (the reason is that I want to avoid using a servlet container or application server).

Is there a way to make server to gzip response content, if Accept-Encoding: gzip is present?


HOW-TO

Samples provided by nicore actually works, and it allows you to make JAX-RS-styled server on top of embedded lightweight server without servlet container, but there are few moments to be considered.

If you prefer to manage classes by yourself (and save a time during startup), you may use the following:

Example

JAX-RS hello world class:

@Path("/helloworld")
public class RestServer {

    @GET
    @Produces("text/html")
    public String getMessage(){
        System.out.println("sayHello()");
        return "Hello, world!";
    }
}

Main method:

For Simple Server:

public static void main(String[] args) throws Exception{
    DefaultResourceConfig resourceConfig = new DefaultResourceConfig(RestServer.class);
    // The following line is to enable GZIP when client accepts it
    resourceConfig.getContainerResponseFilters().add(new GZIPContentEncodingFilter());
    Closeable server = SimpleServerFactory.create("http://0.0.0.0:5555", resourceConfig);
    try {
        System.out.println("Press any key to stop the service...");
        System.in.read();
    } finally {
        server.close();
    }
}

For Grizzly2:

public static void main(String[] args) throws Exception{
    DefaultResourceConfig resourceConfig = new DefaultResourceConfig(RestServer.class);
    // The following line is to enable GZIP when client accepts it
    resourceConfig.getContainerResponseFilters().add(new GZIPContentEncodingFilter());
    HttpServer server = GrizzlyServerFactory.createHttpServer("http://0.0.0.0:5555" , resourceConfig);
    try {
        System.out.println("Press any key to stop the service...");
        System.in.read();
    } finally {
        server.stop();
    }
}

Resolved dependencies:

Simple:

Grizzly:

Jersey:

Notice

Make sure the javax.ws.rs archive didnt get into your classpath, as it conflicts with Jersey's implementation. The worst thing here is a silent 404 error with no logging - only a small note on FINER level is logged.


Solution

  • If you really want to do REST with Java I would suggest you to to use a JAX-RS implementation (RESTeasy, Jersey...).

    If your main concern is the dependency on a servlet container, you could use the JAX-RS RuntimeDelegate to register your application as a JAX-RS endpoint.

    // Using grizzly as the underlaying server
    SelectorThread st = RuntimeDelegate.createEndpoint(new MyApplication(), SelectorThread.class);
    
    st.startEndpoint();
    
    // Wait...
    st.stopEndpoint();
    

    Concerning GZIP encoding, each JAX-RS provider has different approaches. Jersey provides a filter to accomplish the encoding transparently. RESTEasy provides an annotation for that.

    EDIT

    I did some small tests. The following two things will definitely work for you, assuming you are using Maven.

    Using Jersey + SimpleServer:

        public static void main( String[] args ) throws Exception {
    
        java.io.Closeable server = null;
    
        try {
            // Creates a server and listens on the address below.
            // Scans classpath for JAX-RS resources
            server = SimpleServerFactory.create("http://localhost:5555");
            System.out.println("Press any key to stop the service...");
            System.in.read();
        } finally {
            try {
                if (server != null) {
                    server.close();
                }
            } finally {
                ;
            }
        }
    }
    

    with maven dependencies

    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-core</artifactId>
        <version>1.10</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey.contribs</groupId>
        <artifactId>jersey-simple-server</artifactId>
        <version>1.10</version>
    </dependency>
    

    Or using the Jersey + Grizzly2:

    public static void main(String[] args) throws Exception {
    
        HttpServer server = null;
    
        try {
            server = GrizzlyServerFactory.createHttpServer("http://localhost:5555");
            System.out.println("Press any key to stop the service...");
            System.in.read();
        } finally {
            try {
                if (server != null) {
                    server.stop();
                }
            } finally {
                ;
            }
        }
    }
    

    with maven dependencies

    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-core</artifactId>
        <version>1.10</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-grizzly2</artifactId>
        <version>1.10</version>
    </dependency>
    

    Honestly speaking I was not able to get the RuntimeDelegate sample working, too. There certainly is a way to start RESTEasy out of the box, too but I cannot recall it at the moment.