Klaus' Blog

going public

  • Categories

  • Archives

Posts Tagged ‘comet’

Restlet, Grizzly and Async Servlet with Comet

Posted by klauskurz on 23. February 2010

Here is a solution to use Restlet (http://www.restlet.org/) with Grizzly (https://grizzly.dev.java.net/) and a Comet async Servlet.

The App.java is starting a standalone Grizzly Web Server. It is hosting an async Servlet and the Restlet Engine. The Restlet Engine is used as a servlet.

Download Code: AsyncRestlet

App.java

package asyncrestlet;

import com.sun.grizzly.comet.CometAsyncFilter;

import com.sun.grizzly.http.embed.GrizzlyWebServer;
import com.sun.grizzly.http.servlet.ServletAdapter;
import org.restlet.ext.servlet.ServerServlet;

/**
 * The App
 *
 * Demonstration to use the Restlet framework and an async servlet.
 * The async servlet uses the comet package.
 *
 * Starts grizzly standalone servlet container with restlet and comet servlet.
 *
 *
 * Run server:
 *
 *      mvn -Dexec.classpathScope=runtime -Dexec.args="-classpath %classpath asyncrestlet.App" -Dexec.executable=java exec:exec
 *
 * To test:
 *
 * (wget -O - -q "http://localhost:8181/async" &); echo "async GET started"; sleep 2; wget -O - -q "http://localhost:8181/async"
 *
 *  wget -O - -q "http://localhost:8181/restlet/therestlet"
 *
 */
public class App {

    public static void main(String[] args) throws Exception {
        // static content is linked from here
        GrizzlyWebServer gws = new GrizzlyWebServer(8181, "no static content");
        // add the async filter for comet functionality
        gws.addAsyncFilter(new CometAsyncFilter());

        // Adding async servlet
        ServletAdapter simpleServletAdapter = new ServletAdapter();
        simpleServletAdapter.setContextPath("/async");
        simpleServletAdapter.setServletInstance(new AsyncServlet());
        // register above defined adapters
        gws.addGrizzlyAdapter(simpleServletAdapter, new String[]{"/async"});

        // Adding restlet servlet

        ServletAdapter restletServletAdapter = new ServletAdapter();

        restletServletAdapter.setContextPath("/restlet");
        // this is the magic restlet servlet
        restletServletAdapter.setServletInstance(new ServerServlet());
        // let the restlet servlet know which appplication to start
        restletServletAdapter.addContextParameter("org.restlet.application", "asyncrestlet.RestletApplication");
        // register above defined adapters
        gws.addGrizzlyAdapter(restletServletAdapter, new String[]{"/restlet"});

        // let Grizzly run
        gws.start();

        System.out.println("to test async:\n\n    (wget -O - -q \"http://localhost:8181/async\" &); echo \"async GET started\"; sleep 2; wget -O - -q \"http://localhost:8181/async\"\n\n");

        System.out.println("to test restlet:\n\n    wget -O - -q \"http://localhost:8181/restlet/therestlet\"\n\n");
    }
}

AsyncServlet.java

package asyncrestlet;

import com.sun.grizzly.comet.CometContext;
import com.sun.grizzly.comet.CometEngine;
import com.sun.grizzly.comet.CometEvent;
import com.sun.grizzly.comet.CometHandler;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * AsyncServlet
 *
 * uses comet for async http
 *
 * every GET waits 5 seconds. With another GET the wait can be interrupted
 *
 */
public class AsyncServlet extends HttpServlet {

    private class CounterHandler
            implements CometHandler<HttpServletResponse> {

        private HttpServletResponse response;

        @Override
        public void onInitialize(CometEvent event)
                throws IOException {
        }

        @Override
        public void onInterrupt(CometEvent event)
                throws IOException {
            PrintWriter writer = response.getWriter();
            writer.write("timeout from async\n");
            writer.flush();
            removeThisFromContext();
        }

        @Override
        public void onTerminate(CometEvent event)
                throws IOException {
            removeThisFromContext();
        }

        @Override
        public void attach(HttpServletResponse attachment) {
            this.response = attachment;
        }

        private void removeThisFromContext() throws IOException {
            response.getWriter().close();
            CometContext context =
                    CometEngine.getEngine().getCometContext(contextPath);
            context.removeCometHandler(this);
        }

        @Override
        public void onEvent(CometEvent event) throws IOException {
            if (CometEvent.NOTIFY == event.getType()) {
                PrintWriter writer = response.getWriter();
                writer.write("hello from async\n");
                writer.flush();
                event.getCometContext().resumeCometHandler(this);
            }
        }
    }
    private static final long serialVersionUID = 1L;
    private String contextPath;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        contextPath = config.getServletContext().getContextPath() + "/async";
        CometEngine cometEngine = CometEngine.getEngine();
        CometContext context = cometEngine.register(contextPath);
        context.setExpirationDelay(5 * 1000);
    }

    @Override
    protected void doGet(HttpServletRequest req,
            HttpServletResponse res)
            throws ServletException, IOException {

        CounterHandler handler = new CounterHandler();
        handler.attach(res);

        CometEngine engine = CometEngine.getEngine();
        CometContext context = engine.getCometContext(contextPath);
        context.notify(null);
        context.addCometHandler(handler);
    }
}

RestletApplication.java

package asyncrestlet;

import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import org.restlet.routing.Router;

/*
 * RestletApplication
 *
 * The restlet application
 */
public class RestletApplication extends Application {

    /**
     * Creates a root Restlet that will receive all incoming calls.
     */
    @Override
    public synchronized Restlet createInboundRoot() {
        // Create a router Restlet that routes each call to a
        // new instance of HelloWorldResource.
        Router router = new Router(getContext());
        // Defines only one route
        router.attach("/therestlet", RestletResource.class);
        return router;
    }
}

RestletResource.java

package asyncrestlet;

import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class RestletResource extends ServerResource {

    @Get
    public String represent() {
        return "hello from restlet\n";
    }
}

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>AsyncRestlet</groupId>
    <artifactId>AsyncRestlet</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>AsyncRestlet</name>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>maven-restlet</id>
            <name>Maven Restlet Repository</name>
            <url>http://maven.restlet.org</url>
        </repository>
        <repository>
            <id>JavaNet</id>
            <name>Maven JavaNet Repository</name>
            <url>http://download.java.net/maven/2/</url>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.7</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.sun.grizzly</groupId>
            <artifactId>grizzly-comet</artifactId>
            <version>1.9.18b</version>
        </dependency>
        <dependency>
            <groupId>com.sun.grizzly</groupId>
            <artifactId>grizzly-servlet-webserver</artifactId>
            <version>1.9.18b</version>
        </dependency>
        <dependency>
            <groupId>org.restlet.jee</groupId>
            <artifactId>org.restlet</artifactId>
            <version>2.0-M7</version>
            <exclusions>
                <exclusion>
                    <artifactId>org.osgi.core</artifactId>
                    <groupId>org.osgi</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.restlet.jee</groupId>
            <artifactId>org.restlet.ext.servlet</artifactId>
            <version>2.0-M7</version>
            <type>jar</type>
        </dependency>
    </dependencies>
</project>

Resources:
http://blogs.sun.com/msreddy/entry/how_to_make_grizzly_comet
http://www.javaworld.com/javaworld/jw-03-2008/jw-03-asynchhttp.html?page=6
http://blogs.sun.com/japod/entry/jersey_aplication_sharing_grizzly_with

Servlet Communication:
http://docstore.mik.ua/orelly/java-ent/servlet/ch11_03.htm

Posted in java | Tagged: , , , , , | 1 Comment »