tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Filip Hanik - Dev Lists <devli...@hanik.com>
Subject Re: Proposed simplification of CometEvent
Date Fri, 15 Jun 2007 21:14:34 GMT
Ok, one use case scenario would be AJAX requests with asynchronous 
responses on the server, I can see this be extremely common,
I've tried to add in comments to make the example clear, and I don't see 
this example as stupid, as there are a lot more AJAX client frameworks 
than Comet client frameworks.

So there are two things we are show casing
1. The ability to write asynchronously
2. The ability to pipeline HTTP requests (assumption: only dealing with 
GET requests, no HTTP request body)
3. Difference between Comet non blocking and Comet blocking read and 
writes (note, not related to sockets, API only)

What I'd like to point out is that this example, becomes easier with 
blocking read/writes, so I've added that at the bottom for comparison

Let me know if I've made any mistakes here, so that we can work with a 
correct example.

Non blocking read and writes

public class ExampleDelayedAjaxResponse implements CometProcessor {
  ...
  public class DelayedResponder extends Thread {
    public void run() {
      ...
      Client[] clients = getClients();
      for (int i=0; i<clients.length; i++ ) {
        CometEvent event = client.getEvent();
        byte[] data = getDelayedResponse(event);
        if (data!=null) {
          if (event.isWriteable()) {
            event.getHttpServletResponse().getOutputStream().write(data);
            if (event.isWriteable()) { //did we write it all?
               event.close(); //close the event, in anticipation of the next request
               event.register(OP_CALLBACK); //triggers an END event
            } else { //we didn't write it all, trigger a WRITE event when we are done with
the write 
               event.register(OP_WRITE);
            }
          } else {
            //we are not able to write, let us know when we can
            event.register(OP_WRITE);
          }
          //remove the client from the  async thread
          //since we have received the data for this client.
          clients.remove(event);
        }
      }
      ...
    }
  }
  ...
  public void event(CometEvent event) throws IOException, ServletException {
    ...
    if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
      //configure non blocking
      event.configureBlocking(false);
      //deregister for READ since we want to enable pipe lining on the connection 
      //for the next HTTP request
      event.unregister(OP_READ);
      //add the client to the list
      clients.add(event);
    } if ( event.getEventType() == CometEvent.EventType.READ ) {
      //read client Id and stock list from client
      //and add the event to our list
      assert("this should never happen");
    } if ( event.getEventType() == CometEvent.EventType.WRITE ) {
      //unregister from the write event
      event.unregister(OP_WRITE);
      //we can now write
      byte[] data = getDelayedResponse(event);      
      if ( data != null ) {
        event.getHttpServletResponse().getOutputStream().write(data);
      }
      if( data==null || event.isWriteable() ) {
        event.close();
      }
       
    } if ( event.getEventType() == CometEvent.EventType.END ) {
      clients.remove(event);      
    } else if (...) {
      ...
    }
    ...
  }
}

Blocking read and writes 

public class ExampleDelayedAjaxResponse implements CometProcessor {
  ...
  public class DelayedResponder extends Thread {
    public void run() {
      ...
      Client[] clients = getClients();
      for (int i=0; i<clients.length; i++ ) {
        CometEvent event = client.getEvent();
        byte[] data = getDelayedResponse(event);
        if (data!=null) {
          //register for a write, better do that on a thread pool thread
          //since write is blocking
          event.register(OP_WRITE);
          //remove the client from the  async thread
          clients.remove(event);
        }
      }
      ...
    }
  }
  ...
  public void event(CometEvent event) throws IOException, ServletException {
    ...
    if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
      //configure non blocking
      event.configureBlocking(false);
      //deregister for READ since we want to enable pipe lining on the connection 
      //for the next HTTP request
      event.unregister(OP_READ);
      //add the client to the list
      clients.add(event);
    } if ( event.getEventType() == CometEvent.EventType.READ ) {
      //read client Id and stock list from client
      //and add the event to our list
      assert("this should never happen");
    } if ( event.getEventType() == CometEvent.EventType.WRITE ) {
      //unregister from the write event
      event.unregister(OP_WRITE);
      //we can now write
      byte[] data = getDelayedResponse(event);      
      //note we don't have to check for null data here
      event.getHttpServletResponse().getOutputStream().write(data);
      event.close();
    } if ( event.getEventType() == CometEvent.EventType.END ) {
      clients.remove(event);
    } else if (...) {
      ...
    }
    ...
  }
}
  
I think this makes a good use case of where blocking makes life easier, and less complex code.
Big difference for both the async thread and the Comet processor.
And this is why I think we should support both, please note event.configureBlocking has nothing
to do with the underlying socket, just the inputstream.read/write.
the underlying socket is an implementation detail.

Remy, would you mind showing this example with sandbox API, I think with a real world example,
I can understand your API better, and maybe you mine :)

Filip




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


Mime
View raw message