org.mortbay.cometd.CometdServlet Maven / Gradle / Ivy
// ========================================================================
// Copyright 2006 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.mortbay.cometd;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mortbay.util.TypeUtil;
import org.mortbay.util.ajax.Continuation;
import org.mortbay.util.ajax.ContinuationSupport;
/** Cometd Filter
* Servlet implementing the {@link Bayeux} protocol.
*
* The Servlet can be initialized with a json file mapping channels to {@link DataFilter} definitions.
* The servlet init parameter "filters" should point to a webapplication resource containing a JSON
* array of filter definitions. For example:
* [
* {
* "channels": "/**",
* "class" : "org.mortbay.cometd.filter.NoMarkupFilter",
* "init" : {}
* }
* ]
*
*
* The init parameter "timeout" specifies the poll timeout in milliseconds (default 45000).
* The init parameter "multiTimeout" specifies the poll timeout if multiple polls are detected from the
* same browser (default 0 - disable browser detection).
*
* @author gregw
* @see {@link Bayeux}
* @see {@link ChannelPattern}
*/
public class CometdServlet extends HttpServlet
{
public static final String ORG_MORTBAY_BAYEUX="org.mortbay.bayeux";
public static final String CLIENT_ATTR="org.mortbay.cometd.client";
public static final String MESSAGE_PARAM="message";
public static final String TUNNEL_INIT_PARAM="tunnelInit";
public static final String BROWSER_ID="bayeuxBID";
private Bayeux _bayeux;
private long _timeout=45000;
private long _multiTimeout=0;
private Object _multiAdvice=null;
private Map _bidCount=new HashMap();
private boolean _verbose;
public void init() throws ServletException
{
synchronized (CometdServlet.class)
{
_bayeux=(Bayeux)getServletContext().getAttribute(ORG_MORTBAY_BAYEUX);
if (_bayeux==null)
{
_bayeux=new Bayeux(getServletContext());
getServletContext().setAttribute(ORG_MORTBAY_BAYEUX,_bayeux);
}
}
String filters=getInitParameter("filters");
if (filters!=null)
{
try
{
Object[] objects = (Object[])JSON.parse(getServletContext().getResourceAsStream(filters));
for (int i=0;objects!=null && i Init Tunnel - IFRAME CURRENTLY BROKEN!!!!!!!");
Transport transport=new IFrameTransport();
((IFrameTransport)transport).initTunnel(resp);
if (_verbose) System.err.println("<-- Tunnel Over");
}
else
{
super.service(req,resp);
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
// Look for an existing client and protect from context restarts
Object clientObj=req.getAttribute(CLIENT_ATTR);
Client client=(clientObj instanceof Client)?(Client)clientObj:null;
Transport transport=null;
Continuation continuation=null;
String bid=null;
// Have we seen this request before?
if (client!=null)
{
// yes - extract saved properties
transport =(Transport)req.getAttribute(Bayeux.TRANSPORT_ATTR);
transport.setResponse(resp);
bid=(String)req.getAttribute(BROWSER_ID);
// Reduce browser ID counter
// TODO protect from exceptions
if (_multiTimeout>0 && decBID(bid)==0)
{
/*
if (false) // TODO only reset if advised previously
_bayeux.advise(client,transport,null);
*/
}
}
else
{
// No - process messages
// Look for a browser ID
if (_multiTimeout>0)
{
Cookie[] cookies=req.getCookies();
for (int i=0;cookies!=null && i"+batches[batch_index]);
index=0;
batch=JSON.parse(batches[batch_index++]);
}
if (batch==null)
continue;
if (batch.getClass().isArray())
{
message=(Map)Array.get(batch,index++);
if (index>=Array.getLength(batch))
batch=null;
}
else
{
message=(Map)batch;
batch=null;
}
message_count++;
client=_bayeux.getClient((String)message.get(Bayeux.CLIENT_ATTR));
// If no client, this is a handshake
if (client==null)
{
// handshake!
transport=_bayeux.newTransport(client,message);
transport.setResponse(resp);
_bayeux.handle(null,transport,message);
message=null;
}
break;
}
// Handle all client messages
if (client!=null)
{
// resolve transport
transport=_bayeux.newTransport(client,message);
transport.setResponse(resp);
if (_verbose && transport instanceof PlainTextJSONTransport)
((PlainTextJSONTransport)transport).setVerbose(_verbose);
// continue handling messages with a known client and transport!
try
{
// Tell client to hold messages as a response is likely to be sent.
client.responsePending();
// handle any message left over from client loop above
if (message!=null)
_bayeux.handle(client,transport,message);
message=null;
// handle all other messages
while (batch_index"+batches[batch_index]);
index=0;
batch=JSON.parse(batches[batch_index++]);
}
if (batch==null)
continue;
// get the next message
if (batch.getClass().isArray())
{
message=(Map)Array.get(batch,index++);
if (index>=Array.getLength(batch))
batch=null;
}
else
{
message=(Map)batch;
batch=null;
}
// handle message
if (message!=null)
_bayeux.handle(client,transport,message);
message=null;
}
}
finally
{
client.responded();
}
}
}
// Do we need to wait for messages or are we streaming?
while (transport.isPolling())
{
long timeout=_timeout;
continuation=ContinuationSupport.getContinuation(req,client);
// Get messages or wait
List messages = null;
synchronized(client)
{
messages = client.takeMessages();
if (messages==null && !continuation.isPending())
{
//check that only 1 request per browser is waiting
if (_multiTimeout>0 && incBID(bid)>1)
{
// Advise that there are multiple windows waiting
// fall back to traditional polling
timeout=_multiTimeout;
_bayeux.advise(client,transport,_multiAdvice);
}
// save state and suspend
client.addContinuation(continuation);
req.setAttribute(CLIENT_ATTR,client);
req.setAttribute(BROWSER_ID,bid);
req.setAttribute(Bayeux.TRANSPORT_ATTR,transport);
continuation.suspend(timeout);
client.removeContinuation(continuation);
messages=client.takeMessages();
}
continuation.reset();
client.removeContinuation(continuation);
if (messages==null) // timeout
transport.setPolling(false);
}
// Send the messages
if (messages!=null)
{
transport.send(messages);
}
// Only a simple poll if the transport does not flush
if (!transport.keepAlive())
transport.setPolling(false);
}
// Send any left over messages.
if (client!=null)
{
List messages = client.takeMessages();
if (messages!=null)
transport.send(messages);
}
transport.complete();
}
private int incBID(String bid)
{
synchronized (_bidCount)
{
Integer count = (Integer)_bidCount.get(bid);
count=TypeUtil.newInteger(count==null?1:count.intValue()+1);
_bidCount.put(bid,count);
return count.intValue();
}
}
private int decBID(String bid)
{
synchronized (_bidCount)
{
Integer count = (Integer)_bidCount.get(bid);
count=(count==null || count.intValue()<=1)?null:TypeUtil.newInteger(count.intValue()-1);
if (count==null)
{
_bidCount.remove(bid);
return 0;
}
_bidCount.put(bid,count);
return count.intValue();
}
}
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
doPost(req,resp);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy