All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.cometd.server.AbstractCometdServlet 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;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.cometd.Bayeux;
import org.cometd.DataFilter;
import org.cometd.Message;
import org.cometd.server.filter.JSONDataFilter;
import org.eclipse.jetty.util.ajax.JSON;
import org.eclipse.jetty.util.log.Log;

/**
 * Cometd Filter Servlet implementing the {@link AbstractBayeux} 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.cometd.server.filter.NoMarkupFilter",
 *      "init"    : {}
 *    }
 *  ]
 * 
* * The following init parameters can be used to configure the servlet: *
*
timeout
*
The server side poll timeout in milliseconds (default 250000). This is * how long the server will hold a reconnect request before responding.
* *
interval
*
The client side poll timeout in milliseconds (default 0). How long a * client will wait between reconnects
* *
maxInterval
*
The max client side poll timeout in milliseconds (default 30000). A * client will be removed if a connection is not received in this time. * *
maxLazyLatency
*
The max time in ms(default 0) that a client with lazy messages will wait before * sending a response. If 0, then the client will wait until the next timeout or * non-lazy message. * *
multiFrameInterval
*
the client side poll timeout if multiple connections are detected from * the same browser (default 1500).
* *
JSONCommented
*
If "true" then the server will accept JSON wrapped in a comment and will * generate JSON wrapped in a comment. This is a defence against Ajax Hijacking. *
* *
filters
*
the location of a JSON file describing {@link DataFilter} instances to be * installed
* *
requestAvailable
*
If true, the current request is made available via the * {@link AbstractBayeux#getCurrentRequest()} method
* *
loglevel
*
0=none, 1=info, 2=debug
* *
refsThreshold
*
The number of message refs at which the a single message response will be * cached instead of being generated for every client delivered to. Done to * optimize a single message being sent to multiple clients.
*
* * @author gregw * @author aabeling: added JSONP transport * * @see {@link AbstractBayeux} * @see {@link ChannelId} */ public abstract class AbstractCometdServlet extends GenericServlet { public static final String CLIENT_ATTR="org.cometd.server.client"; public static final String TRANSPORT_ATTR="org.cometd.server.transport"; public static final String MESSAGE_PARAM="message"; public static final String TUNNEL_INIT_PARAM="tunnelInit"; public static final String HTTP_CLIENT_ID="BAYEUX_HTTP_CLIENT"; public final static String BROWSER_ID="BAYEUX_BROWSER"; protected AbstractBayeux _bayeux; public AbstractBayeux getBayeux() { return _bayeux; } protected abstract AbstractBayeux newBayeux(); @Override public void init() throws ServletException { synchronized(AbstractCometdServlet.class) { _bayeux=(AbstractBayeux)getServletContext().getAttribute(Bayeux.ATTRIBUTE); if (_bayeux == null) { _bayeux=newBayeux(); } } synchronized(_bayeux) { boolean was_initialized=_bayeux.isInitialized(); _bayeux.initialize(getServletContext()); if (!was_initialized) { String filters=getInitParameter("filters"); if (filters != null) { try { InputStream is=getServletContext().getResourceAsStream(filters); if (is == null) throw new FileNotFoundException(filters); Object[] objects=(Object[])JSON.parse(new InputStreamReader(getServletContext().getResourceAsStream(filters),"utf-8")); for (int i=0; objects != null && i < objects.length; i++) { Map filter_def=(Map)objects[i]; String fc=(String)filter_def.get("class"); if (fc != null) Log.warn(filters + " file uses deprecated \"class\" name. Use \"filter\" instead"); else fc=(String)filter_def.get("filter"); Class c=Thread.currentThread().getContextClassLoader().loadClass(fc); DataFilter filter=(DataFilter)c.newInstance(); if (filter instanceof JSONDataFilter) ((JSONDataFilter)filter).init(filter_def.get("init")); _bayeux.getChannel((String)filter_def.get("channels"),true).addDataFilter(filter); } } catch(Exception e) { getServletContext().log("Could not parse: " + filters,e); throw new ServletException(e); } } String timeout=getInitParameter("timeout"); if (timeout != null) _bayeux.setTimeout(Long.parseLong(timeout)); String maxInterval=getInitParameter("maxInterval"); if (maxInterval != null) _bayeux.setMaxInterval(Long.parseLong(maxInterval)); String commentedJSON=getInitParameter("JSONCommented"); _bayeux.setJSONCommented(commentedJSON != null && Boolean.parseBoolean(commentedJSON)); String l=getInitParameter("logLevel"); if (l != null && l.length() > 0) _bayeux.setLogLevel(Integer.parseInt(l)); String interval=getInitParameter("interval"); if (interval != null) _bayeux.setInterval(Long.parseLong(interval)); String maxLazy=getInitParameter("maxLazyLatency"); if (maxLazy != null) _bayeux.setMaxLazyLatency(Integer.parseInt(maxLazy)); String mfInterval=getInitParameter("multiFrameInterval"); if (mfInterval != null) _bayeux.setMultiFrameInterval(Integer.parseInt(mfInterval)); String requestAvailable=getInitParameter("requestAvailable"); _bayeux.setRequestAvailable(requestAvailable != null && Boolean.parseBoolean(requestAvailable)); String async=getInitParameter("asyncDeliver"); if (async != null) getServletContext().log("asyncDeliver no longer supported"); _bayeux.generateAdvice(); if (_bayeux.isLogInfo()) { getServletContext().log("timeout=" + timeout); getServletContext().log("interval=" + interval); getServletContext().log("maxInterval=" + maxInterval); getServletContext().log("multiFrameInterval=" + mfInterval); getServletContext().log("filters=" + filters); } } } getServletContext().setAttribute(Bayeux.ATTRIBUTE,_bayeux); } protected abstract void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException; @Override public void service(ServletRequest req, ServletResponse resp) throws ServletException, IOException { HttpServletRequest request=(HttpServletRequest)req; HttpServletResponse response=(HttpServletResponse)resp; if (_bayeux.isRequestAvailable()) _bayeux.setCurrentRequest(request); try { service(request,response); } finally { if (_bayeux.isRequestAvailable()) _bayeux.setCurrentRequest(null); } } protected String findBrowserId(HttpServletRequest request) { Cookie[] cookies=request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if (BROWSER_ID.equals(cookie.getName())) return cookie.getValue(); } } return null; } protected String setBrowserId(HttpServletRequest request, HttpServletResponse response) { String browser_id=Long.toHexString(request.getRemotePort()) + Long.toString(_bayeux.getRandom(),36) + Long.toString(System.currentTimeMillis(),36) + Long.toString(request.getRemotePort(),36); Cookie cookie=new Cookie(BROWSER_ID,browser_id); cookie.setPath("/"); cookie.setMaxAge(-1); response.addCookie(cookie); return browser_id; } private static Message[] __EMPTY_BATCH=new Message[0]; protected Message[] getMessages(HttpServletRequest request) throws IOException { String fodder=null; try { // Get message batches either as JSON body or as message parameters if (request.getContentType() != null && !request.getContentType().startsWith("application/x-www-form-urlencoded")) { return _bayeux.parse(request.getReader()); } String[] batches=request.getParameterValues(MESSAGE_PARAM); if (batches == null || batches.length == 0) return __EMPTY_BATCH; if (batches.length == 0) { fodder=batches[0]; return _bayeux.parse(fodder); } List messages=new ArrayList(); for (int i=0; i < batches.length; i++) { if (batches[i] == null) continue; fodder=batches[i]; _bayeux.parseTo(fodder,messages); } return messages.toArray(new Message[messages.size()]); } catch(IOException e) { throw e; } catch(Exception e) { throw new Error(fodder,e); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy