org.cometd.server.continuation.ContinuationCometdServlet Maven / Gradle / Ivy
//========================================================================
//Copyright 2007 Mort Bay Consulting Pty. Ltd.
//------------------------------------------------------------------------
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//http://www.apache.org/licenses/LICENSE-2.0
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
//========================================================================
package org.cometd.server.continuation;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.cometd.Bayeux;
import org.cometd.Message;
import org.cometd.server.AbstractBayeux;
import org.cometd.server.AbstractCometdServlet;
import org.cometd.server.ClientImpl;
import org.cometd.server.JSONTransport;
import org.cometd.server.MessageImpl;
import org.cometd.server.Transport;
import org.eclipse.jetty.continuation.Continuation;
import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.util.ArrayQueue;
import org.eclipse.jetty.util.StringUtil;
public class ContinuationCometdServlet extends AbstractCometdServlet
{
public final static int __DEFAULT_REFS_THRESHOLD=0;
protected int _refsThreshold=__DEFAULT_REFS_THRESHOLD;
String _responseBuffer;
@Override
public void init() throws ServletException
{
String refsThreshold=getInitParameter("refsThreshold");
if (refsThreshold != null)
_refsThreshold=Integer.parseInt(refsThreshold);
if (_refsThreshold>0)
{
String server = getServletContext().getServerInfo();
if (server.startsWith("jetty/6"))
_responseBuffer="org.mortbay.jetty.ResponseBuffer";
else if (server.startsWith("jetty/"))
_responseBuffer="org.eclipse.jetty.server.ResponseBuffer";
else
_refsThreshold=0;
}
super.init();
}
/* ------------------------------------------------------------ */
@Override
protected AbstractBayeux newBayeux()
{
return new ContinuationBayeux();
}
/* ------------------------------------------------------------ */
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
// 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)
{
client=(ContinuationClient)_bayeux.getClient((String)message.get(AbstractBayeux.CLIENT_FIELD));
// 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);
// Get messages or wait
synchronized(client)
{
if (!client.hasNonLazyMessages() && initial && received <= 1)
{
// save state and suspend
request.setAttribute(CLIENT_ATTR,client);
request.setAttribute(TRANSPORT_ATTR,transport);
continuation.setTimeout(timeout);
continuation.suspend();
client.setContinuation(continuation);
return;
}
}
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
{
// Send any queued messages.
synchronized(client)
{
client.doDeliverListeners();
final ArrayQueue messages=(ArrayQueue)client.getQueue();
final int size=messages.size();
try
{
for (int i=0; i < size; i++)
{
final Message message=messages.getUnsafe(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(_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: " + Bayeux.JSON_CONTENT_TYPE + "\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(_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();
}
}
finally
{
messages.clear();
}
}
if (metaConnectReply != null)
{
metaConnectReply=_bayeux.extendSendMeta(client,metaConnectReply);
transport.send(metaConnectReply);
if (metaConnectReply instanceof MessageImpl)
((MessageImpl)metaConnectReply).decRef();
}
}
}
if (transport != null)
transport.complete();
}
public void destroy()
{
if (_bayeux != null)
((ContinuationBayeux)_bayeux).destroy();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy