using vert.x inside a servlet

530 views
Skip to first unread message

omid pourhadi

unread,
Oct 9, 2016, 7:45:03 AM10/9/16
to vert.x
Hi,

First, I created a vertx http server which simply prints Hello for request localhost:8180/p . it's a verticle.

 @Override
   
public void start() throws Exception
   
{
       
Router router = Router.router(vertx);

       
StaticHandler sh = StaticHandler.create().setEnableRangeSupport(true).setCachingEnabled(false);
        router
.route("/static/*").handler(sh);
       
       
//
        router
.route("/p").handler(h->{
            h
.response().end("Hello");
       
});
        vertx
.createHttpServer().requestHandler(router::accept).listen(8180);
       
System.out.println("server is up and listening to 8180");
   
}



then I'm trying to use vertx inside a servlet as follow, I get following exception and a weird behaviour which is for first request it prints nothing after that it prints Hello.

Servlet.java

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
   
{
       
Vertx vertx = Vertx.factory.vertx();
       
ServletOutputStream os = response.getOutputStream();
       
HttpClientRequest req = vertx.createHttpClient().request(HttpMethod.GET, 8180, "localhost", "/p", res -> {

            res
.bodyHandler(bf -> {
               
System.out.println("body handler");
               
byte[] bytes = bf.getBytes();
               
try
               
{
                   
IOUtils.copy(new ByteArrayInputStream(bytes), os);
               
}
               
catch (Exception e)
               
{
                    e
.printStackTrace();
               
}
           
});
       
});
        req
.end();
        os
.flush();
        os
.close();

   
}

Exception :


body handler
Oct 09, 2016 3:01:01 PM org.apache.catalina.connector.CoyoteAdapter checkRecycled
INFO: Encountered a non-recycled response and recycled it forcedly.
org.apache.catalina.connector.CoyoteAdapter$RecycleRequiredException
    at org.apache.catalina.connector.CoyoteAdapter.checkRecycled(CoyoteAdapter.java:728)
    at org.apache.coyote.http11.AbstractHttp11Processor.recycle(AbstractHttp11Processor.java:1835)

body handler
body handler


Is this the correct way of using vert.x inside a servlet?
 
PS: I'm using tomcat 8.

Alexander Lehmann

unread,
Oct 9, 2016, 8:23:54 AM10/9/16
to vert.x
The request inside the vertx does not block, which means that your servlet will consider the operation finished and close the stream and then the bodyHandler will be called later.

If you want to wait for the vertx operations to finish inside your servlet, you have to use something like CountDownLatch to synchronize the execution.

CountDownLatch latch = new CountDownLatch(1);

then at the end of the bodyHandler

latch.countDown();

and after the req.end();

latch.await();

I think there is are asynchronous operations possible in Servlet 3 with Tomcat 8, but I am not sure how that works together with vertx.

ad...@cs.miami.edu

unread,
Oct 9, 2016, 12:42:23 PM10/9/16
to vert.x
Hi,

As Alexander said, you need to likely use a count down latch or use sesrvlet async. 

Both would work.  But the count down latach would keep the servlet thread tied up until vertx is done.  The better option would be to try to get the async servlet to work.   Let me know if you have any issues and I am happy to explore it.


 Here are some of the steps:

1) make sure you are using the NIO http connector, which you can setup in server.xml (here is my test setup, you don't need to use ssl of course, but mine does so I kept it)

    <Connector
           protocol="org.apache.coyote.http11.Http11NioProtocol"         
           port="443"
            keepAliveTimeout="30000"         
           scheme="https" secure="true" SSLEnabled="true"
           keystoreFile="mykeystore" keystorePass="myPass"
           clientAuth="false" sslProtocol="TLS"/>

2)  Add the async annotation to your servelet.  Here is what mine says for a servlet called CometPust

@WebServlet(name = "CometPush", urlPatterns = {"/CometPush"}, asyncSupported = true)
 
3) in your servlet's GET or processRequest method you may need to add the following (I needed this in tomcat 7 you may not need it in tomcat 8:

request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);

4) add this right afterwards:
AsyncContext aCtx = request.startAsync(request, response);

So this AsyncContext is really the key item.  push it onto a data structure which you then pass down into vertx (or is somehow accessible via your vertx code).    At this point, do not send back any response in your servlet.  Your servlet will finish the handler, but not end the htttp connection/response. When you have the final response that you want to send back to the httpclient, within your vertx code do this:

// grab the reference to he AsyncContext;
aCtx = MyStructure.getMyAsyncContext(...);

// the following should be called by your vertx code when it is all done, this is very similar to vertx's response.end(String), just more boilerplate
writer = aCtx.getResponse().getWriter();
writer.println(responseString);
writer.flush();

// if you do want to end the HTTP response (you can keep it open if you want, but it won't end the http response if you do so)
writer.close();       
 aCtx.complete();

ad...@cs.miami.edu

unread,
Oct 9, 2016, 9:42:54 PM10/9/16
to vert.x
Hi,

In case anyone has interest, here is a complete code example of an async servlet making a non blocking call to a JS vertx verticle along the EB, getting the response and passing the response back through the servlet response.  As far as I understanding it, the following template can be used to have non-blocking passing from servlet to vertx and then back through servlet.

-Adam


//------------ Servlet code ---------

@WebServlet(name = "Vertx", urlPatterns = {"/Vertx"}, asyncSupported = true)
public class Vertx extends HttpServlet {

    private static io.vertx.core.Vertx vertx;
    private static EventBus eb;

    // careful here, make this part thread safe!!
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        vertx = io.vertx.core.Vertx.vertx(new VertxOptions());
        String pathToJS = "/home/adam/test/vertx/first/files/servletTest.js";
        vertx.deployVerticle(pathToJS);
        eb = vertx.eventBus();

        System.out.println("finished init");

    }

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        try {
            System.out.println("in servlet");
            request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);

            AsyncContext aCtx = request.startAsync(request, response);

            eb.send("sayHi", "", ar -> {
                if (ar.succeeded()) {
                    try {
                        String s = ar.result().body() + "";
                        PrintWriter writer = aCtx.getResponse().getWriter();
                        writer.println(s);
                        writer.flush();
                        writer.close();
                        aCtx.complete();

                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        System.out.println("sent message");

    }

//------------ Vertx JS code with EB handler ---------

var eb = vertx.eventBus();
eb.consumer("sayHi", function (message) {
    var s = message.body();
    var out = "hi from vertx " + Date.now();
    message.reply(JSON.stringify(out));

});







On Sunday, October 9, 2016 at 7:45:03 AM UTC-4, omid pourhadi wrote:

omid pourhadi

unread,
Oct 10, 2016, 2:21:45 AM10/10/16
to vert.x
Hi,

Thank you Adam for sharing your experience and code,

I will test it in my case and share the result.

I'm just wondering is your code thread-safe ? and what will happen if it is not ?

I mean vertx and eventbus member variables are thread-safe ?

ad...@cs.miami.edu

unread,
Oct 10, 2016, 11:31:28 AM10/10/16
to vert.x
Hi,

There are a few potential problems with the code I posted (it is more of a concept code than a production ready code)

[1]  Make sure that only 1 instance of Vertx and EB is created  I put this in the "init" function.  A servlet is supposed to call the init once on startup, but I don't know if it is a hard requirement for a servlet to call it once and only once.  It takes my laptop about 5 seconds to create an instance of a Vertx object, so I am not sure if the servlet engine will call the init multiple times if it is taking too long.  As a solution, I would recommend wrapping the Vertx and EB object into a thread safe static singleton object using your singleton pattern of choice, which will guarantee that only one Vertx end EB is ever created.

[2]  Another change I would make is the following.  In the call back function, you will find code that actually writes the response back to the servelet response.  Since this is in a call back, this actually gets called on the vertx event loop.  I would create a servlet member static Fixed Thread Pool of a small size (2-4)  and push the following code into a Runnable to have a thread from that pool send the servlet response. This will make sure the vertx event loop stays free.  This is the code that I would run on that thread pool:
                        writer.println(s);
                        writer.flush();
                        writer.close();
                        aCtx.complete();

[3]  Regarding the thread safety of the EB and Vertx objects.  I think for the example I wrote, we only really need to make sure the EB is thread safe, because that is the only object that is called among different servlet requests.  I really don't know about the thread safety of the EB methods like Send.   If I were you, I think we need some vertx pros to answer that I will start a new post later with this question (I think it is a question worthy of a new post, as it is more general purpose than this servlet situation.

Best,
-Adam





On Sunday, October 9, 2016 at 7:45:03 AM UTC-4, omid pourhadi wrote:
Reply all
Reply to author
Forward
0 new messages