|Most Shared

Asynchronous REST tech coding rest java tomcat jersey asynch
11 Jul 2014at Atlanta

Sharing a simple code snippet to make a asynchronous REST service with Jersey and embedded Tomcat Gradle plugin.

This is just for a quickstart of the rituals, as I was unlucky in searching for an similar example in StackOverflow and Google.

web.xml

Make sure the jersey servlet spec is 3.0 and it supports asynch

<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">

    <display-name>Tasker</display-name>
    <servlet>
        <servlet-name>Jersey REST Service</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.vijayrc.tasker.api</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>
    ....
</web-app>

    

SearchApi.java

The jersey resource that supposedly does a slow search of key across some imaginary datasources (SearchService), so it must be made asynchronous to free the request thread. The service follows the usual drill of a timeout handler and the forked new thread that callbacks to fill response.

@Component
@Path("search")
public class SearchApi {
    private static Logger log = LogManager.getLogger(SearchApi.class);

    @Autowired
    private SearchService service;

    @GET
    @ManagedAsync
    @Produces("application/json")
    public void fetchFor(@MatrixParam("key") String key, @Suspended final AsyncResponse response){
        log.info("search|"+key);

        response.setTimeoutHandler(r ->  r.resume(Response.status(SERVICE_UNAVAILABLE).entity("search timed out.").build()));
        response.setTimeout(20, SECONDS);
        response.register((CompletionCallback) error -> {
            if( error != null) log.error("search error:|key="+key+"|error="+error);
            else log.info("search complete:|key="+key);
        });

        new Thread(()->{
            List<SearchView> views = service.fetch(key);
            response.resume(views);
        }).start();
    }
}
    

SearchView

The DTO going over the wire as json from the service to client

@XmlRootElement
@ToString
@Bean
public class SearchView {
    private String title;
    private String uri;
}
    

build.gradle

Use a tomcat plugin, plug the below script into your build.gradle, tomcat version should be 7+ to support Servlet 3.0

Run 'gradle tomcatRunWar'

buildscript {
    repositories {
        mavenRepo(url: 'http://jcenter.bintray.com')
    }
    dependencies {
        classpath 'org.gradle.api.plugins:gradle-tomcat-plugin:1.2.4'
    }
}
apply plugin: 'tomcat'

dependencies {
    def tomcatVersion = '7.0.54'
    tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
    "org.apache.tomcat.embed:tomcat-embed-logging-juli:${tomcatVersion}"
    tomcat("org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}") {
        exclude group: 'org.eclipse.jdt.core.compiler', module: 'ecj'
    }
}
tomcat {
    httpPort = 8080
    httpsPort = 8091
    enableSSL = true
}
    

Output

        $ curl http://localhost:8080/tasker/rest/search;key=12
        [{"title":"card-4","uri":"/cards/4"},
        {"title":"card-2","uri":"/cards/2"},
        {"title":"card-4-task-1","uri":"/cards/4/task2/1"},
        {"title":"card-1-task-3","uri":"/cards/1/tasks/3"},
        {"title":"file-2","uri":"/files/2"}]
    
comments powered by Disqus

All content except noted photos and videos copyright © Vijayaraj Chakravarthy. All rights reserved. *Any images or videos not listed as mine are copyright to their respective owners and were used under creative common license or fair use standards. If a photo or video is your material and you do not wish it to be on the site, please email me vijayrc@outlook.com and I will remove it immediately.