You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tomcat.apache.org by Bruce Huang <ma...@gmail.com> on 2016/11/01 09:44:18 UTC

Does Tomcat8 NIO2 connector support Apache CometEvent?

Hi all,

We have a simple servlet which implements Apache CometEvent for long
polling connection on tomcat8. It works well when we used
org.apache.coyote.http11.Http11NioProtocol, however, we have now changed to
using org.apache.coyote.http11.Http11Nio2Protocol and it will not work
properly.

Tomcat: v8.0.23
JDK: v1.8.0_45
OS: Windows server 2008 R2

The connector setting as below:

<Connector port="8443"
protocol="org.apache.coyote.http11.Http11Nio2Protocol"
   maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
   clientAuth="false" sslProtocol="TLS" connectionTimeout="60000"
   keystoreFile="D:\localhost.jks" keystorePass="******" />

The timeout of the event will not work as we have set it to 300 seconds(by
event.setTimeout(300000)), the comet connection will be disconnected after
60 seconds which I believe is the connector connection timeout. And there
will have thrown an exception as below

28-Oct-2016 15:04:33.748 SEVERE [http-nio2-8443-exec-5]
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process Error
reading request, ignored
java.lang.IllegalStateException: Reading not allowed due to timeout or
cancellation
    at
sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:249)
    at
sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297)
    at
org.apache.tomcat.util.net.SecureNio2Channel.read(SecureNio2Channel.java:792)
    at
org.apache.tomcat.util.net.Nio2Endpoint.awaitBytes(Nio2Endpoint.java:871)
    at
org.apache.coyote.http11.Http11Nio2Protocol$Http11ConnectionHandler.release(Http11Nio2Protocol.java:180)
    at
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:722)
    at
org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.doRun(Nio2Endpoint.java:1073)
    at
org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.run(Nio2Endpoint.java:1032)
    at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

If the client makes the comet connection again after this, and the other
client tries to send message. The comet will be END immediately and
connection disconnected.


The Connect servlet as below

public class Connect extends HttpServlet implements CometProcessor {

    ...

    public void event(CometEvent event) throws IOException,
ServletException {
        HttpServletRequest request = event.getHttpServletRequest();
        HttpServletResponse response = event.getHttpServletResponse();
        if (event.getEventType() == CometEvent.EventType.BEGIN) {
            String deviceid = request.getParameter("id");
            MessageSender.getInstance().addConnection(deviceid, event);
            request.setAttribute("org.apache.tomcat.comet.timeout", 300 *
1000);
            event.setTimeout(300 * 1000);
        } else if (event.getEventType() == CometEvent.EventType.ERROR) {
            MessageSender.getInstance().removeConnection(event);
            event.close();
        } else if (event.getEventType() == CometEvent.EventType.END) {
            MessageSender.getInstance().removeConnection(event);
            event.close();
        } else if (event.getEventType() == CometEvent.EventType.READ) {
            throw new UnsupportedOperationException("This servlet does not
accept data");
        }
    }
}

And we have another Trigger servlet for sending message to client:

public class Trigger extends HttpServlet {
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        byte[] receieveByteArray = ByteUtil.getHttpServletRequestBody(req);
        sendTrigger(req, resp, receieveByteArray);
    }

    private void sendTrigger(HttpServletRequest req, HttpServletResponse
resp, byte[] trigger) throws IOException, ServletException
    {
        try
        {
            MessageSender.getInstance().sendTrigger(deviceId, trigger);
        } catch (Exception e)
        {
            logger.error("Send trigger has thrown exception: ", e);
        }
    }
}

And the MessageSender class as below

public class MessageSender
{
    private static final Map<String, CometEvent> connections = new
ConcurrentHashMap<String, CometEvent>();

    public void addConnection(String deviceId, CometEvent event) {
        connections.put(deviceId, event);
    }

    public void removeConnection(CometEvent event) {

        while (connections.values().remove(event)) {
    }

    public static MessageSender getInstance() {
        return instance;
    }

    public void sendTrigger(String deviceId, byte[] triggerMessage) throws
IOException, ConnectionNotFoundException {
        CometEvent comet = connections.get(deviceId);
        HttpServletResponse response = comet.getHttpServletResponse();
        response.addHeader("Content-Length",
Integer.toString(triggerMessage.length));
        response.addHeader("Content-Language", "en-US");

        ServletOutputStream servletOutputStream =
response.getOutputStream();
        servletOutputStream.write(triggerMessage);
        servletOutputStream.flush();
        servletOutputStream.close();

        comet.close(); // add for NIO2
        connections.remove(deviceId);
    }
}


Thanks,
Bruce

Re: Does Tomcat8 NIO2 connector support Apache CometEvent?

Posted by Bruce Huang <ma...@gmail.com>.
Rémy Maucherat <re...@apache.org> 於 2016年11月2日 週三 下午5:28寫道:

> 2016-11-02 5:19 GMT+01:00 Bruce Huang <ma...@gmail.com>:
>
> > Thanks for your suggestion.
> >
> > I have tested on 8.0.38 release, but it even can't close the comet
> > properly. On 8.0.23, after OutputStream.close(), I have to do
> event.close()
> > to make the END event to be fired correctly.
> >
> > ServletOutputStream servletOutputStream =
> > event.getHttpServletResponse().getOutputStream();
> >
> > servletOutputStream.write(triggerMessage);
> > servletOutputStream.flush();
> > servletOutputStream.close();
> >
> > event.close(); // add for NIO2
> >
>
> Why is it "add for NIO2" ? When closing comet, you should use event.close()
> (why do you think this API exists ?) *and* flushing+closing the streams is
> often a problem. Although I understand the systematic stream close (and
> flush, sometimes) comes from java.io, it is useless in Servlets and
> sometimes harmful.


When I used comet in NIO protocol, I only do flush and close the stream.
The END event will be fired after the stream to be closed and I do
event.close() there. In NIO2, however, close stream will not fire the END
event, so I had realized that I must do event.close() after the trigger has
sent.


>
>
>
> > I found that the event.close() won't work from v8.0.27~8.0.38 and I could
> > make the comet to be connected start from v8.0.9 to v8.0.38, but
> > event.setTimeout() are not working on both of them.
> >
> > Since our server is running on Windows platform, we have to switch to
> NIO2
> > for this issue
> > http://tomcat.10.x6.nabble.com/Tomcat-8-uses-high-CPU-td5049333.html
> >
> > What is the error(s) you get with the latest 8.0 build ?
>
>
I have followed your suggestion, not to do flush and close stream, just do
event.close() as below.

HttpServletResponse response = event.getHttpServletResponse();
response.addHeader("Content-Length", Integer.toString(
triggerMessage.length));
response.addHeader("Content-Language", "en-US");
ServletOutputStream servletOutputStream = response.getOutputStream();
servletOutputStream.write(triggerMessage);
event.close();

Before v8.0.26, after event.close(), I will received END event. After
v8.0.27 to v8.0.38(latest build), the END event will be fired about 20
seconds later after event.close() and the below exception will be thrown.

03-Nov-2016 11:39:40.961 SEVERE [http-nio2-8443-exec-5]
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process Error
reading request, ignored
java.lang.IllegalStateException: Reading not allowed due to timeout or
cancellation
    at
sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:249)
    at
sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297)
    at
org.apache.tomcat.util.net.SecureNio2Channel.read(SecureNio2Channel.java:792)
    at
org.apache.tomcat.util.net.Nio2Endpoint.awaitBytes(Nio2Endpoint.java:871)
    at
org.apache.coyote.http11.Http11Nio2Protocol$Http11ConnectionHandler.release(Http11Nio2Protocol.java:180)
    at
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:722)
    at
org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.doRun(Nio2Endpoint.java:1073)
    at
org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.run(Nio2Endpoint.java:1032)
    at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

If I do not send any trigger to Trigger servlet, the comet from client will
be disconnected after 20 seconds, I will received END event and the same
exception as above will be thrown.

Thanks,
Bruce


> Since Comet is removed in 8.5 (deprecated in 8.0) and NIO2 was new in 8.0,
> it's not a very good combo for support of the feature, but we can give it a
> shot.
>
> Rémy
>

Re: Does Tomcat8 NIO2 connector support Apache CometEvent?

Posted by Rémy Maucherat <re...@apache.org>.
2016-11-02 5:19 GMT+01:00 Bruce Huang <ma...@gmail.com>:

> Thanks for your suggestion.
>
> I have tested on 8.0.38 release, but it even can't close the comet
> properly. On 8.0.23, after OutputStream.close(), I have to do event.close()
> to make the END event to be fired correctly.
>
> ServletOutputStream servletOutputStream =
> event.getHttpServletResponse().getOutputStream();
>
> servletOutputStream.write(triggerMessage);
> servletOutputStream.flush();
> servletOutputStream.close();
>
> event.close(); // add for NIO2
>

Why is it "add for NIO2" ? When closing comet, you should use event.close()
(why do you think this API exists ?) *and* flushing+closing the streams is
often a problem. Although I understand the systematic stream close (and
flush, sometimes) comes from java.io, it is useless in Servlets and
sometimes harmful.

>
> I found that the event.close() won't work from v8.0.27~8.0.38 and I could
> make the comet to be connected start from v8.0.9 to v8.0.38, but
> event.setTimeout() are not working on both of them.
>
> Since our server is running on Windows platform, we have to switch to NIO2
> for this issue
> http://tomcat.10.x6.nabble.com/Tomcat-8-uses-high-CPU-td5049333.html
>
> What is the error(s) you get with the latest 8.0 build ?

Since Comet is removed in 8.5 (deprecated in 8.0) and NIO2 was new in 8.0,
it's not a very good combo for support of the feature, but we can give it a
shot.

Rémy

Re: Does Tomcat8 NIO2 connector support Apache CometEvent?

Posted by Bruce Huang <ma...@gmail.com>.
Mark Thomas <ma...@apache.org> 於 2016年11月1日 週二 下午6:06寫道:

> On 01/11/2016 09:44, Bruce Huang wrote:
> > Hi all,
> >
> > We have a simple servlet which implements Apache CometEvent for long
> > polling connection on tomcat8. It works well when we used
> > org.apache.coyote.http11.Http11NioProtocol, however, we have now changed
> to
> > using org.apache.coyote.http11.Http11Nio2Protocol and it will not work
> > properly.
> >
> > Tomcat: v8.0.23
> > JDK: v1.8.0_45
> > OS: Windows server 2008 R2
>
> The first thing to do is to test the latest 8.0.x release.
>
> Keep in mind that Comet is deprecated so if there is still a bug in
> 8.0.x, fixing it might not be a priority. Switching back to NIO may be a
> better option.
>
> Mark
>
>
Thanks for your suggestion.

I have tested on 8.0.38 release, but it even can't close the comet
properly. On 8.0.23, after OutputStream.close(), I have to do event.close()
to make the END event to be fired correctly.

ServletOutputStream servletOutputStream =
event.getHttpServletResponse().getOutputStream();

servletOutputStream.write(triggerMessage);
servletOutputStream.flush();
servletOutputStream.close();

event.close(); // add for NIO2

I found that the event.close() won't work from v8.0.27~8.0.38 and I could
make the comet to be connected start from v8.0.9 to v8.0.38, but
event.setTimeout() are not working on both of them.

Since our server is running on Windows platform, we have to switch to NIO2
for this issue
http://tomcat.10.x6.nabble.com/Tomcat-8-uses-high-CPU-td5049333.html

Bruce


> >
> > The connector setting as below:
> >
> > <Connector port="8443"
> > protocol="org.apache.coyote.http11.Http11Nio2Protocol"
> >    maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
> >    clientAuth="false" sslProtocol="TLS" connectionTimeout="60000"
> >    keystoreFile="D:\localhost.jks" keystorePass="******" />
> >
> > The timeout of the event will not work as we have set it to 300
> seconds(by
> > event.setTimeout(300000)), the comet connection will be disconnected
> after
> > 60 seconds which I believe is the connector connection timeout. And there
> > will have thrown an exception as below
> >
> > 28-Oct-2016 15:04:33.748 SEVERE [http-nio2-8443-exec-5]
> > org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process
> Error
> > reading request, ignored
> > java.lang.IllegalStateException: Reading not allowed due to timeout or
> > cancellation
> >     at
> > sun.nio.ch
> .AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:249)
> >     at
> > sun.nio.ch
> .AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297)
> >     at
> > org.apache.tomcat.util.net
> .SecureNio2Channel.read(SecureNio2Channel.java:792)
> >     at
> > org.apache.tomcat.util.net
> .Nio2Endpoint.awaitBytes(Nio2Endpoint.java:871)
> >     at
> >
> org.apache.coyote.http11.Http11Nio2Protocol$Http11ConnectionHandler.release(Http11Nio2Protocol.java:180)
> >     at
> >
> org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:722)
> >     at
> > org.apache.tomcat.util.net
> .Nio2Endpoint$SocketProcessor.doRun(Nio2Endpoint.java:1073)
> >     at
> > org.apache.tomcat.util.net
> .Nio2Endpoint$SocketProcessor.run(Nio2Endpoint.java:1032)
> >     at
> >
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
> >     at
> >
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
> >     at
> >
> org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
> >     at java.lang.Thread.run(Thread.java:745)
> >
> > If the client makes the comet connection again after this, and the other
> > client tries to send message. The comet will be END immediately and
> > connection disconnected.
> >
> >
> > The Connect servlet as below
> >
> > public class Connect extends HttpServlet implements CometProcessor {
> >
> >     ...
> >
> >     public void event(CometEvent event) throws IOException,
> > ServletException {
> >         HttpServletRequest request = event.getHttpServletRequest();
> >         HttpServletResponse response = event.getHttpServletResponse();
> >         if (event.getEventType() == CometEvent.EventType.BEGIN) {
> >             String deviceid = request.getParameter("id");
> >             MessageSender.getInstance().addConnection(deviceid, event);
> >             request.setAttribute("org.apache.tomcat.comet.timeout", 300 *
> > 1000);
> >             event.setTimeout(300 * 1000);
> >         } else if (event.getEventType() == CometEvent.EventType.ERROR) {
> >             MessageSender.getInstance().removeConnection(event);
> >             event.close();
> >         } else if (event.getEventType() == CometEvent.EventType.END) {
> >             MessageSender.getInstance().removeConnection(event);
> >             event.close();
> >         } else if (event.getEventType() == CometEvent.EventType.READ) {
> >             throw new UnsupportedOperationException("This servlet does
> not
> > accept data");
> >         }
> >     }
> > }
> >
> > And we have another Trigger servlet for sending message to client:
> >
> > public class Trigger extends HttpServlet {
> >     protected void doPost(HttpServletRequest req, HttpServletResponse
> resp)
> >             throws ServletException, IOException {
> >         byte[] receieveByteArray =
> ByteUtil.getHttpServletRequestBody(req);
> >         sendTrigger(req, resp, receieveByteArray);
> >     }
> >
> >     private void sendTrigger(HttpServletRequest req, HttpServletResponse
> > resp, byte[] trigger) throws IOException, ServletException
> >     {
> >         try
> >         {
> >             MessageSender.getInstance().sendTrigger(deviceId, trigger);
> >         } catch (Exception e)
> >         {
> >             logger.error("Send trigger has thrown exception: ", e);
> >         }
> >     }
> > }
> >
> > And the MessageSender class as below
> >
> > public class MessageSender
> > {
> >     private static final Map<String, CometEvent> connections = new
> > ConcurrentHashMap<String, CometEvent>();
> >
> >     public void addConnection(String deviceId, CometEvent event) {
> >         connections.put(deviceId, event);
> >     }
> >
> >     public void removeConnection(CometEvent event) {
> >
> >         while (connections.values().remove(event)) {
> >     }
> >
> >     public static MessageSender getInstance() {
> >         return instance;
> >     }
> >
> >     public void sendTrigger(String deviceId, byte[] triggerMessage)
> throws
> > IOException, ConnectionNotFoundException {
> >         CometEvent comet = connections.get(deviceId);
> >         HttpServletResponse response = comet.getHttpServletResponse();
> >         response.addHeader("Content-Length",
> > Integer.toString(triggerMessage.length));
> >         response.addHeader("Content-Language", "en-US");
> >
> >         ServletOutputStream servletOutputStream =
> > response.getOutputStream();
> >         servletOutputStream.write(triggerMessage);
> >         servletOutputStream.flush();
> >         servletOutputStream.close();
> >
> >         comet.close(); // add for NIO2
> >         connections.remove(deviceId);
> >     }
> > }
> >
> >
> > Thanks,
> > Bruce
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
> For additional commands, e-mail: users-help@tomcat.apache.org
>
>

Re: Does Tomcat8 NIO2 connector support Apache CometEvent?

Posted by Mark Thomas <ma...@apache.org>.
On 01/11/2016 09:44, Bruce Huang wrote:
> Hi all,
> 
> We have a simple servlet which implements Apache CometEvent for long
> polling connection on tomcat8. It works well when we used
> org.apache.coyote.http11.Http11NioProtocol, however, we have now changed to
> using org.apache.coyote.http11.Http11Nio2Protocol and it will not work
> properly.
> 
> Tomcat: v8.0.23
> JDK: v1.8.0_45
> OS: Windows server 2008 R2

The first thing to do is to test the latest 8.0.x release.

Keep in mind that Comet is deprecated so if there is still a bug in
8.0.x, fixing it might not be a priority. Switching back to NIO may be a
better option.

Mark


> 
> The connector setting as below:
> 
> <Connector port="8443"
> protocol="org.apache.coyote.http11.Http11Nio2Protocol"
>    maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
>    clientAuth="false" sslProtocol="TLS" connectionTimeout="60000"
>    keystoreFile="D:\localhost.jks" keystorePass="******" />
> 
> The timeout of the event will not work as we have set it to 300 seconds(by
> event.setTimeout(300000)), the comet connection will be disconnected after
> 60 seconds which I believe is the connector connection timeout. And there
> will have thrown an exception as below
> 
> 28-Oct-2016 15:04:33.748 SEVERE [http-nio2-8443-exec-5]
> org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process Error
> reading request, ignored
> java.lang.IllegalStateException: Reading not allowed due to timeout or
> cancellation
>     at
> sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:249)
>     at
> sun.nio.ch.AsynchronousSocketChannelImpl.read(AsynchronousSocketChannelImpl.java:297)
>     at
> org.apache.tomcat.util.net.SecureNio2Channel.read(SecureNio2Channel.java:792)
>     at
> org.apache.tomcat.util.net.Nio2Endpoint.awaitBytes(Nio2Endpoint.java:871)
>     at
> org.apache.coyote.http11.Http11Nio2Protocol$Http11ConnectionHandler.release(Http11Nio2Protocol.java:180)
>     at
> org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:722)
>     at
> org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.doRun(Nio2Endpoint.java:1073)
>     at
> org.apache.tomcat.util.net.Nio2Endpoint$SocketProcessor.run(Nio2Endpoint.java:1032)
>     at
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
>     at
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
>     at
> org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
>     at java.lang.Thread.run(Thread.java:745)
> 
> If the client makes the comet connection again after this, and the other
> client tries to send message. The comet will be END immediately and
> connection disconnected.
> 
> 
> The Connect servlet as below
> 
> public class Connect extends HttpServlet implements CometProcessor {
> 
>     ...
> 
>     public void event(CometEvent event) throws IOException,
> ServletException {
>         HttpServletRequest request = event.getHttpServletRequest();
>         HttpServletResponse response = event.getHttpServletResponse();
>         if (event.getEventType() == CometEvent.EventType.BEGIN) {
>             String deviceid = request.getParameter("id");
>             MessageSender.getInstance().addConnection(deviceid, event);
>             request.setAttribute("org.apache.tomcat.comet.timeout", 300 *
> 1000);
>             event.setTimeout(300 * 1000);
>         } else if (event.getEventType() == CometEvent.EventType.ERROR) {
>             MessageSender.getInstance().removeConnection(event);
>             event.close();
>         } else if (event.getEventType() == CometEvent.EventType.END) {
>             MessageSender.getInstance().removeConnection(event);
>             event.close();
>         } else if (event.getEventType() == CometEvent.EventType.READ) {
>             throw new UnsupportedOperationException("This servlet does not
> accept data");
>         }
>     }
> }
> 
> And we have another Trigger servlet for sending message to client:
> 
> public class Trigger extends HttpServlet {
>     protected void doPost(HttpServletRequest req, HttpServletResponse resp)
>             throws ServletException, IOException {
>         byte[] receieveByteArray = ByteUtil.getHttpServletRequestBody(req);
>         sendTrigger(req, resp, receieveByteArray);
>     }
> 
>     private void sendTrigger(HttpServletRequest req, HttpServletResponse
> resp, byte[] trigger) throws IOException, ServletException
>     {
>         try
>         {
>             MessageSender.getInstance().sendTrigger(deviceId, trigger);
>         } catch (Exception e)
>         {
>             logger.error("Send trigger has thrown exception: ", e);
>         }
>     }
> }
> 
> And the MessageSender class as below
> 
> public class MessageSender
> {
>     private static final Map<String, CometEvent> connections = new
> ConcurrentHashMap<String, CometEvent>();
> 
>     public void addConnection(String deviceId, CometEvent event) {
>         connections.put(deviceId, event);
>     }
> 
>     public void removeConnection(CometEvent event) {
> 
>         while (connections.values().remove(event)) {
>     }
> 
>     public static MessageSender getInstance() {
>         return instance;
>     }
> 
>     public void sendTrigger(String deviceId, byte[] triggerMessage) throws
> IOException, ConnectionNotFoundException {
>         CometEvent comet = connections.get(deviceId);
>         HttpServletResponse response = comet.getHttpServletResponse();
>         response.addHeader("Content-Length",
> Integer.toString(triggerMessage.length));
>         response.addHeader("Content-Language", "en-US");
> 
>         ServletOutputStream servletOutputStream =
> response.getOutputStream();
>         servletOutputStream.write(triggerMessage);
>         servletOutputStream.flush();
>         servletOutputStream.close();
> 
>         comet.close(); // add for NIO2
>         connections.remove(deviceId);
>     }
> }
> 
> 
> Thanks,
> Bruce
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tomcat.apache.org
For additional commands, e-mail: users-help@tomcat.apache.org