users@grizzly.java.net

Re: Can't get registerAsyncWrite and CometWriter to work

From: Oleksiy Stashok <Oleksiy.Stashok_at_Sun.COM>
Date: Thu, 28 Jan 2010 17:15:15 +0100

Hi Richard,

> 1) If I call "cometContext.notify(null, handler);" directly from my
> "doGet" method is ignored because in the DefaultNotificationHandler
> there is a line:
>
> if (cometEvent.getCometContext().isActive(cometHandler)){
>
> and the "cometHandler" is not yet active so I have to keep retrying
> until it is active. Is there any way of being notified of the
> handler becoming active? Or can the comet context remember what
> interest ops the handler is interested in until it is active?
I guess you can wait for onInitialize() event.

> 2) When I call "cometContext.registerAsyncWrite(handler)" the
> SelectionKey’s interest ops are updated but the IO selector is not
> woken up. This means I have to wait up to
> "TCPSelectorHandler.selectTimeout" (1000ms by default) before I can
> do the async write which adds extra latency to my app. Shall I raise
> a bug for this?
Yes, and if you can to attach simple test case - would be perfect.

WBR,
Alexey.

>
> From Richard.
>
>
> From: Richard Zschech [mailto:richard_at_zschech.net]
> Sent: Thursday, 21 January 2010 11:37 AM
> To: 'users_at_grizzly.dev.java.net'
> Subject: Can't get registerAsyncWrite and CometWriter to work
>
> Hi All,
>
> I have a small example HttpServlet using Grizzly’s CometEngine (see
> below). Upon receiving a request the test adds a CometHandler,
> spawns a thread which waits for a second and notifies the
> CometHandler using the CometContext.
>
> The CometHandler then receives the notification via its onEvent
> method and then calls registerAsyncWrite. The CometHandler is then
> notified that the async write is possible and tries to write a large
> chunk of data using the CometWriter. The write call returns the
> number of bytes written and if they are not all written the
> CometHandler calls registerAsyncWrite again to be notified when
> another non-blocking write can occur otherwise it calls
> resumesCometHandler to terminate the connection.
>
> My problems are:
>
> 1) If I don’t flush the HttpServletResponse before using the
> CometWriter the HTTP response headers are written when
> resumesCometHandler is called which is after the response data.
>
> 2) On Windows XP the non-blocking CometWriter.write does block and
> writes the large chunk of data in its entirety. I guess this is just
> an OS issue.
>
> 3) The main problem is sometimes after the second call to
> registerAsyncWrite is done the CometHandler never gets another write
> event so the rest of the data is never written and the connection is
> never closed.
>
> I’m using Glassfish v3
>
> Am I doing something wrong?
> Has anyone else had issues using CometWriters?
>
> Thanks for any help,
> From Richard.
>
>
> Example code:
>
> import java.io.IOException;
>
> import javax.servlet.ServletConfig;
> import javax.servlet.ServletException;
> import javax.servlet.http.HttpServlet;
> import javax.servlet.http.HttpServletRequest;
> import javax.servlet.http.HttpServletResponse;
>
> import com.sun.grizzly.comet.CometContext;
> import com.sun.grizzly.comet.CometEngine;
> import com.sun.grizzly.comet.CometEvent;
> import com.sun.grizzly.comet.CometHandler;
> import com.sun.grizzly.comet.CometWriter;
>
> public class GrizzlyServlet extends HttpServlet {
>
> private String topic;
> private CometEngine cometEngine;
> private CometContext cometContext;
>
> @Override
> public void init(ServletConfig config) throws
> ServletException {
> topic =
> config.getServletContext().getContextPath();
> cometEngine = CometEngine.getEngine();
> cometContext =
> cometEngine.register(topic);
> cometContext.setExpirationDelay(-1);
> }
>
> @Override
> public void destroy() {
> cometEngine.unregister(topic);
> }
>
> protected void doGet(HttpServletRequest request,
> HttpServletResponse response) throws ServletException, IOException {
> response.getWriter().append("BOO");
> response.getWriter().flush();
> final CometHandlerImpl handler = new
> CometHandlerImpl();
> handler.attach(response);
> cometContext.addCometHandler(handler);
>
> new Thread() {
> @Override
> public void run() {
> try {
> Thread
> .sleep(100);
> cometContext
> .notify(null, handler);
> }
>
> catch (InterruptedException e) {
> e
> .printStackTrace();
> }
>
> catch (IOException e) {
> e
> .printStackTrace();
> }
> }
> }.start();
> }
>
> private class CometHandlerImpl implements
> CometHandler<HttpServletResponse> {
> private HttpServletResponse response;
>
> volatile int index = 0;
> int size = 1 << 24;
> byte[] bytes = new byte[size];
>
> public CometHandlerImpl() {
> for (int i = 0; i <
> size; i++) {
>
> bytes[i] = (byte) (i % 26 + 'A');
> }
> }
>
> public void
> attach(HttpServletResponse response) {
> this.response =
> response;
> }
>
> public void onInitialize(CometEvent
> event) throws IOException {
>
> System.out.println("onInitialize");
> }
>
> public void onInterrupt(CometEvent
> event) throws IOException {
>
> System.out.println("onInterrupt");
> }
>
> public void onTerminate(CometEvent
> event) throws IOException {
>
> System.out.println("onTerminate");
> }
>
> public void onEvent(CometEvent
> event) throws IOException {
>
> System.out.println("onEvent " + event.getType() + " " +
> event.attachment());
> if (event.getType()
> == CometEvent.NOTIFY) {
>
> cometContext.registerAsyncWrite(this);
> }
> else if
> (event.getType() == CometEvent.WRITE) {
>
> CometWriter writer = (CometWriter) event.attachment();
>
> int
> write = writer.write(bytes, index, bytes.length - index);
>
> System.out.println("Written " + write);
>
> index += write;
> if
> (index == bytes.length) {
> cometContext
> .resumeCometHandler(this);
> }
> else {
> cometContext
> .registerAsyncWrite(this);
> }
> }
> }
> }
> }