2011-10-31 19 views
11

Estoy tratando de implementar el chat simple utilizando Servlet 3.0 y el patrón Comet basado en su compatibilidad asincrónica.Servlet 3 tarea asíncrona en Tomcat 7

Estoy inspirado por este artículo: http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page=3

Mi servlet se parece a esto.

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

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
     AsyncContext aCtx = request.startAsync(request, response); 
     ServletContext appScope = request.getServletContext();  
     List<AsyncContext> watchers = (List<AsyncContext>) appScope.getAttribute("watchers"); 
     watchers.add(aCtx); //register the watcher 
    } 

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 
      AsyncContext aCtx = request.startAsync(request, response); 
      ServletContext appScope = request.getServletContext(); 
      Queue<String> messages = (Queue<String>)appScope.getAttribute("messages"); 
      messages.add(someMessage); 
    } 
} 

ahora mi oyente tiene el siguiente aspecto:

@WebListener 
public class ChatPushService implements ServletContextListener { 

     @Override 
     public void contextInitialized(ServletContextEvent sce) { 
       final List<AsyncContext> watchers = new ArrayList<AsyncContext>(); 
      sce.getServletContext().setAttribute("watchers", watchers); 
       // store new messages not published yet 
      Queue<String> messages = new ConcurrentLinkedQueue<String>(); 
      sce.getServletContext().setAttribute("messages", messages); 
      Executor messageExecutor = Executors.newCachedThreadPool(); 
      final Executor watcherExecutor = Executors.newCachedThreadPool(); 
      while(true) 
       {  

       if(!messages.isEmpty()) 
       { 
        System.out.println("notEmpty"); 
        String message = messages.poll(); 
        messageExecutor.execute(new Runnable(){ 

         @Override 
         public void run() { 
          for(final AsyncContext aCtx : watchers){ 
           watcherExecutor.execute(new Runnable(){ 

            @Override 
             public void run() { 
              try { 
              aCtx.getResponse().getWriter().print("brrrrr"); 
             } catch (IOException e) { 
              // TODO Auto-generated catch block 
              e.printStackTrace(); 
             } 
            } 
           }); 
          } 
         } 
       }); 
       } 
     } 

    } 
    } 

Cuando estoy empezando mi es la congelación durante el inicio del contenedor.

Nov 1, 2011 1:12:09 AM org.apache.catalina.core.AprLifecycleListener init 
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /usr/lib/jvm/java-6-openjdk/jre/lib/amd64/server:/usr/lib/jvm/java-6-openjdk/jre/lib/amd64:/usr/lib/jvm/java-6-openjdk/jre/../lib/amd64:/usr/java/packages/lib/amd64:/usr/lib/jni:/lib:/usr/lib 
Nov 1, 2011 1:12:09 AM org.apache.tomcat.util.digester.SetPropertiesRule begin 
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:Servlet3Comet' did not find a matching property. 
Nov 1, 2011 1:12:09 AM org.apache.coyote.AbstractProtocol init 
INFO: Initializing ProtocolHandler ["http-bio-8080"] 
Nov 1, 2011 1:12:09 AM org.apache.coyote.AbstractProtocol init 
INFO: Initializing ProtocolHandler ["ajp-bio-8009"] 
Nov 1, 2011 1:12:09 AM org.apache.catalina.startup.Catalina load 
INFO: Initialization processed in 624 ms 
Nov 1, 2011 1:12:09 AM org.apache.catalina.core.StandardService startInternal 
INFO: Starting service Catalina 
Nov 1, 2011 1:12:09 AM org.apache.catalina.core.StandardEngine startInternal 
INFO: Starting Servlet Engine: Apache Tomcat/7.0.22 

Parece que public void contextInitialized función no se ejecuta de forma asincrónica en el fondo y es el bloqueo de más de inicialización contenedor.

¿Por qué?

¿Alguien me puede ayudar con este problema?

Respuesta

8

Se está ejecutando el bucle while dentro contextInitialized() método que está mal. contextInitialized() es invocado por Servlet Container como parte del inicio de la aplicación, teniendo while loop bloqueará el inicio de la aplicación.

modificado el código de este tipo la ContextListener se iniciará un hilo de utilidad que publica los mensajes a los observadores de

@WebListener 
public class ChatPushService implements ServletContextListener { 

    @Override 
    public void contextInitialized(ServletContextEvent sce) { 
      final List<AsyncContext> watchers = new ArrayList<AsyncContext>(); 
     sce.getServletContext().setAttribute("watchers", watchers); 
      // store new messages not published yet 
     Queue<String> messages = new ConcurrentLinkedQueue<String>(); 
     sce.getServletContext().setAttribute("messages", messages); 
     new chatManager(sce.getServletContext()).start(); //START DAEMON 

     } 
} 
public class ChatManager implements Runnable 
{ 
ServletContext servletCtx; 
public ChatManager(ServletContext ctx) 
{ 
    this.servletCtx = ctx; 
} 
public void run() 
{ 
     List<AsyncContext> watchers = (List<AsyncContext>) servletCtx.getAttribute("watchers"); 
    Queue<String> messages = (Queue<String>)appScope.getAttribute("messages"); 
    Executor messageExecutor = Executors.newCachedThreadPool(); 
     final Executor watcherExecutor = Executors.newCachedThreadPool(); 
     while(true) 
      {  

      if(!messages.isEmpty()) 
      { 
       System.out.println("notEmpty"); 
       String message = messages.poll(); 
       messageExecutor.execute(new Runnable(){ 

        @Override 
        public void run() { 
         for(final AsyncContext aCtx : watchers){ 
          watcherExecutor.execute(new Runnable(){ 

           @Override 
            public void run() { 
             try { 
             aCtx.getResponse().getWriter().print("brrrrr"); 
            } catch (IOException e) { 
             // TODO Auto-generated catch block 
             e.printStackTrace(); 
            } 
           } 
          }); 
         } 
        } 
      }); 
      } 
    } 

} 

} 
+0

Esa parte también me sorprendió, pero ese código se presentó como tal en el artículo de Javaworld del que OP copió, por lo que OP no tiene la culpa aquí. – BalusC

+0

Estoy tratando de crear un chat donde cada mensaje enviado por POST se entregará a todos los clientes Suscritos allí, Así que tipo de cola creada y mientras (verdadero) el bloque supervisa si este nuevo mensaje ya está en la cola. –

0

que no puedo comentar sobre el código de Ramesh, así que tengo que colocar aquí ... Desde ningún hilo se enrolla alrededor del Runnable de ChatManager, creo que deberías llamar a run() y no a start(). También, bastante obvio, debería ser un nuevo ChatManager() .. no el nuevo chatManager() ... la cuenta de Java ha sido sensible a mayúsculas y minúsculas.

Cuestiones relacionadas