Filip Hanik - Dev Lists wrote:
here we go, some examples
http://people.apache.org/~fhanik/tomcat/aio.html#Example%20code%20snippets
and the entire document has been updated to reflect most changes
http://people.apache.org/~fhanik/tomcat/aio.html
Here is an alternative version of the examples using the sandbox API to
give people an idea, along with some comments. No renaming of
sleep/callback, or others at this time. Hopefully, I did not make too
many mistakes.
First example, which can enter a busy loop if all events start returning
false for isWriteable (which is not very likely, of course):
public class ExampleCometStockStreamer implements CometProcessor {
...
public class StockUpdater extends Thread {
public void run() {
...
StockUpdates[] updates = fetchUpdates();
Client[] clients = getClients(updates);
for (int i=0; i<clients.length; i++ ) {
CometEvent event = client.getEvent();
StockUpdates[] clientList = getClientUpdates(client,updates);
client.setAndMergeNextUpdates(clientList);
if (event.isWriteable()) {
byte[] data = getUpdateChunk(client.getNextUpdates());
event.getHttpServletResponse().getOutputStream().write(data);
}
}
...
}
}
...
public void event(CometEvent event) throws IOException,
ServletException {
...
if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
} if ( event.getEventType() == CometEvent.EventType.READ ) {
//read client Id and stock list from client
//and add the event to our list
String clientId = readClientInfo(event,stocks);
clients.add(clientId, event, stocks);
} if ( event.getEventType() == CometEvent.EventType.WRITE ) {
//we can now write
byte[] data = getUpdateChunk(client.getNextUpdates());
event.getHttpServletResponse().getOutputStream().write(data);
} else if (...) {
...
}
...
}
}
What this example should be doing is remove the client from the list
when isWriteable returns false, and add it back when it gets a write event.
I can translate the second example, but it could lead to an abusive
poller use and number of events (all writes are also done synchronously
with blocking IO, which never makes sense to me).
public class ExampleCometStockStreamer implements CometProcessor {
...
public class StockUpdater extends Thread {
public void run() {
...
StockUpdates[] updates = fetchUpdates();
Client[] clients = getClients(updates);
for (int i=0; i<clients.length; i++ ) {
StockUpdates[] clientList = getClientUpdates(client,updates);
client.setAndMergeNextUpdates(clientList);
client.getEvent().callback();
}
...
}
}
...
public void event(CometEvent event) throws IOException,
ServletException {
...
if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
//configure blocking
event.configureBlocking(true);
} if ( event.getEventType() == CometEvent.EventType.READ ) {
//read client Id and stock list from client
//and add the event to our list
String clientId = readClientInfo(event,stocks);
clients.add(clientId, event, stocks);
} if ( event.getEventType() == CometEvent.EventType.CALLBACK ) {
Client client = clients.get(event);
//we can now write
byte[] data = getUpdateChunk(client.getNextUpdates());
event.getHttpServletResponse().getOutputStream().write(data);
} else if (...) {
...
}
...
}
}
I think the third example is wrong: there's no reason for isWriteable or
isReadable to change its result unless they trigger a large amount of
logic and some IO operations. I thought you said it was wrong ;) Also,
it will be very vulnerable to busy loops. I can translate it by wrapping
the content of for (int j=0; j<clients.size(); j++) { into a try/catch,
and removing the calls to isWriteable (which only introduce useless
events, and may cause additional busy loops).
Straight translation (since isWriteable will trigger a write event which
will flush, it will work, but busy loops are pretty much certain; it
also assumes things about the data to read):
public class ExampleAllReadThenWriteComet implements CometProcessor {
...
public class AllWriterThread extends Thread {
byte[] dataChunks = ...;
public void run() {
...
for (int i=0; i<dataChunks.length; i++ ) {
for (int j=0; j<clients.size(); j++) {
boolean done = false;
while (!done) {
//first read the first request
//but only if our previous write was completed
if ( clients[j].getEvent().isWriteable() &&
clients[j].getEvent().isReadable() ) {
done = readClientData(clients[j]); //returns true if all
data has been received for a request
}
}
done = false;
while (!done) {
//write the response
if ( clients[j].getEvent().isWriteable() {
clients[j].getEvent().getHttpServletResponse().write(dataChunks[i]);
done = true;
}
}
}
}
...
}
}
...
public void event(CometEvent event) throws IOException,
ServletException {
...
if ( event.getEventType() == CometEvent.EventType.BEGIN ) {
//add the event to our client list
clients.add(event);
//start our writer if all clients have arrived
if (clients.size()==5) {
AllWriterThread thread = new AllWriterThread();
thread.start();
}
} if ( event.getEventType() == CometEvent.EventType.READ ) {
} if ( event.getEventType() == CometEvent.EventType.WRITE ) {
} else if (...) {
...
}
...
}
}
The last example is quite funny, and I can't translate it (doh), since
there's no opposite API to sleep (once you sleep, you have to callback).
Waiting until you do operations on a number of connections seems weird,
since all would perform as bad as the slowest one (or die if one does
not send the data it was supposed to send). I would like to hear about a
valid use case (by opposition to crazy coder design) which relies on
freely enabling and disabling events.
All of these examples are not very good, I think :( In most of these,
you should not be using Comet I think: CPU usage will skyrocket, killing
off the benefits over regular Servlets with blocking IO.
Rémy
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]