2011-10-31 10 views
11

Sto cercando di implementare la chat semplice utilizzando Servlet 3.0 e il modello Comet in base al relativo supporto asincrono.Servlet 3 Task asincrono su Tomcat 7

Sono ispirato da questo articolo: http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page=3

mio servlet assomiglia a questo.

@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); 
    } 
} 

ora il mio ascoltatore si presenta così:

@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(); 
             } 
            } 
           }); 
          } 
         } 
       }); 
       } 
     } 

    } 
    } 

Quando sto iniziando il mio si gela durante contenitore iniziazione.

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 

Sembra public void contextInitialized funzione non è in esecuzione in modo asincrono su sfondo e sta bloccando ulteriormente l'inizializzazione del contenitore.

Perché?

qualcuno può aiutarmi su questo problema?

risposta

8

Si esegue ciclo while all'interno contextInitialized() metodo che è sbagliato. contesto contextInitialized() viene richiamato da Servlet Container come parte dell'avvio dell'applicazione, mentre il ciclo while blocca l'avvio dell'app.

modificato il codice come il ContextListener inizierà un thread demone che pubblica i messaggi agli osservatori

@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

Anche questa parte mi ha sorpreso, ma quel codice è stato presentato come tale nell'articolo di Javaworld da cui l'OP ha copiato, quindi l'OP non è da biasimare qui. – BalusC

+0

Sto provando a creare una chat in cui ogni messaggio inviato da POST verrà consegnato a tutti i client iscritti lì, quindi tipo di coda creata e mentre (true) monitor di blocco se questo nuovo messaggio è già in coda. –

0

non posso commentare sul codice di Ramesh, quindi devo metterlo qui ... Dal nessun thread si avvolge attorno al runner di ChatManager, credo che dovresti chiamare run() su di esso e non start(). Inoltre, abbastanza ovvio, dovrebbe essere il nuovo ChatManager() .. non nuovo chatManager() ... l'account di Java è stato case-sensitive.