return;
}
// Look for an existing client and protect from context restarts
Object clientObj=request.getAttribute(CLIENT_ATTR);
Transport transport=null;
int received=-1;
boolean metaConnectDeliveryOnly=false;
boolean pendingResponse=false;
boolean metaConnect=false;
final boolean initial;
// Have we seen this request before
ContinuationClient client=(clientObj instanceof ClientImpl)?(ContinuationClient)clientObj:null;
if (client != null)
{
initial=false;
// yes - extract saved properties
transport=(Transport)request.getAttribute(TRANSPORT_ATTR);
transport.setResponse(response);
metaConnectDeliveryOnly=client.isMetaConnectDeliveryOnly() || transport.isMetaConnectDeliveryOnly();
metaConnect=true;
}
else
{
initial=true;
Message[] messages=getMessages(request);
received=messages.length;
/* check jsonp parameter */
String jsonpParam=request.getParameter("jsonp");
// Handle all received messages
try
{
for (Message message : messages)
{
if (jsonpParam != null)
message.put("jsonp",jsonpParam);
if (client == null)
{
String clientId = (String)message.get(AbstractBayeux.CLIENT_FIELD);
client=(ContinuationClient)_bayeux.getClient(clientId);
// If no client, SHOULD be a handshake, so force a
// transport and handle
if (client == null)
{
// Setup a browser ID
String browser_id=findBrowserId(request);
if (browser_id == null)
browser_id=setBrowserId(request,response);
if (transport == null)
{
transport=_bayeux.newTransport(client,message);
transport.setResponse(response);
metaConnectDeliveryOnly=transport.isMetaConnectDeliveryOnly();
}
_bayeux.handle(null,transport,message);
message=null;
continue;
}
}
String browser_id=findBrowserId(request);
if (browser_id != null && (client.getBrowserId() == null || !client.getBrowserId().equals(browser_id)))
client.setBrowserId(browser_id);
// resolve transport
if (transport == null)
{
transport=_bayeux.newTransport(client,message);
transport.setResponse(response);
metaConnectDeliveryOnly=client.isMetaConnectDeliveryOnly() || transport.isMetaConnectDeliveryOnly();
}
// Tell client to hold messages as a response is likely to
// be sent.
if (!metaConnectDeliveryOnly && !pendingResponse)
{
pendingResponse=true;
client.responsePending();
}
if (Bayeux.META_CONNECT.equals(message.getChannel()))
metaConnect=true;
_bayeux.handle(client,transport,message);
}
}
finally
{
for (Message message : messages)
((MessageImpl)message).decRef();
if (pendingResponse)
{
client.responded();
}
}
}
Message metaConnectReply=null;
// Do we need to wait for messages
if (transport != null)
{
metaConnectReply=transport.getMetaConnectReply();
if (metaConnectReply != null)
{
long timeout=client.getTimeout();
if (timeout < 0)
timeout=_bayeux.getTimeout();
Continuation continuation=ContinuationSupport.getContinuation(request,client);
// Get messages or wait
synchronized(client)
{
if (timeout > 0 && !client.hasNonLazyMessages() && initial && received <= 1)
{
// save state and suspend
request.setAttribute(CLIENT_ATTR,client);
request.setAttribute(TRANSPORT_ATTR,transport);
client.setContinuation(continuation);
continuation.setObject(response);
continuation.suspend(timeout);
}
continuation.reset();
}
client.setContinuation(null);
transport.setMetaConnectReply(null);
}
else if (client != null)
{
client.access();
}
}
if (client != null)
{
if (metaConnectDeliveryOnly && !metaConnect)
{
// wake up any long poll
client.resume();
}
else
{
List<Message> messages;
synchronized (client)
{
client.doDeliverListeners();
ArrayQueue<Message> clientMessages = (ArrayQueue<Message>)client.getQueue();
// Copy the messages to avoid synchronization
messages = new ArrayList<Message>(clientMessages);
// Empty client's queue
clientMessages.clear();
}
final int size=messages.size();
for (int i=0; i < size; i++)
{
final Message message=messages.get(i);
final MessageImpl mesgImpl=(message instanceof MessageImpl)?(MessageImpl)message:null;
// Can we short cut the message?
if (i == 0 && size == 1 && mesgImpl != null && _refsThreshold > 0 && metaConnectReply != null && transport instanceof JSONTransport)
{
// is there a response already prepared
ByteBuffer buffer=mesgImpl.getBuffer();
if (buffer != null)
{
// Send pre-prepared buffer
request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
if (metaConnectReply instanceof MessageImpl)
((MessageImpl)metaConnectReply).decRef();
metaConnectReply=null;
transport=null;
mesgImpl.decRef();
continue;
}
else if (mesgImpl.getRefs() >= _refsThreshold)
{
// create multi-use buffer
byte[] contentBytes=("[" + mesgImpl.getJSON() + ",{\"" + Bayeux.SUCCESSFUL_FIELD + "\":true,\"" + Bayeux.CHANNEL_FIELD
+ "\":\"" + Bayeux.META_CONNECT + "\"}]").getBytes(StringUtil.__UTF8);
int contentLength=contentBytes.length;
String headerString="HTTP/1.1 200 OK\r\n" + "Content-Type: text/json; charset=utf-8\r\n" + "Content-Length: "
+ contentLength + "\r\n" + "\r\n";
byte[] headerBytes=headerString.getBytes(StringUtil.__UTF8);
buffer=ByteBuffer.allocateDirect(headerBytes.length + contentLength);
buffer.put(headerBytes);
buffer.put(contentBytes);
buffer.flip();
mesgImpl.setBuffer(buffer);
request.setAttribute("org.mortbay.jetty.ResponseBuffer",buffer);
metaConnectReply=null;
if (metaConnectReply instanceof MessageImpl)
((MessageImpl)metaConnectReply).decRef();
transport=null;
mesgImpl.decRef();
continue;
}
}
if (message != null)
transport.send(message);
if (mesgImpl != null)
mesgImpl.decRef();
}
if (metaConnectReply != null)
{
metaConnectReply=_bayeux.extendSendMeta(client,metaConnectReply);
transport.send(metaConnectReply);
if (metaConnectReply instanceof MessageImpl)
((MessageImpl)metaConnectReply).decRef();
}
}
}
if (transport != null)
transport.complete();
}