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

com.sun.grizzly.messagesbus.MessagesBus Maven / Gradle / Ivy

The newest version!
/*
 * 
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 * 
 * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
 * 
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 */
package com.sun.grizzly.messagesbus;

import java.io.IOException;

import java.io.UnsupportedEncodingException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


import com.sun.grizzly.comet.CometContext;
import com.sun.grizzly.comet.CometEngine;

import com.sun.grizzly.comet.CometHandler;
import com.sun.grizzly.comet.NotificationHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Servlet implementation of the Grizzly Comet Protocol (GCP). The GCP protocol
 * is a very basic protocol that can be used by browser to share data, using the
 * comet technique, between serveral clients without having to poll for it. 
 * 
 * The protocol is very simple. First, a client must subscribe to a topic:
 * 


 * http://host:port/contextPath?
 *    subscribe=[topic name]&cometTechnique=[polling|log-polling|http-streaming]&message[text]
 * 
 * Mandatory: subscribe and cometTechnique.
 * 

* When issuing the URL above, the connection will be automatically suspended * based on the cometTechnique specified. To share data * between application, a browser just need to send the following request: *


 * http://host:port/contextPath?publish=[topic name]&message[text] 
 * 

* The Servlet can be used as it is or extended to add extra features like * filtering messages, security, login, etc. * * To use this Servlet, just add in your web.xml: * *


    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee"
      xmlns:j2ee="http://java.sun.com/xml/ns/j2ee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4"
      xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
      <description>Grizzly Messages Bus Servlet</description>
      <display-name>Grizzly Messages Bus Servlet</display-name>
      <servlet>
        <description>MessagesBus</description>
        <servlet-name>MessagesBus</servlet-name>
        <servlet-class>com.sun.grizzly.messagesbus.MessagesBus</servlet-class>
        <load-on-startup>0</load-on-startup>
      </servlet>
      <servlet-mapping>
        <servlet-name>MessagesBus</servlet-name>
        <url-pattern>/mb</url-pattern>
      </servlet-mapping>
      <session-config>
        <session-timeout>25</session-timeout>
      </session-config>
    </web-app>
 * 

* * By default, a connection will be timed out after a {@link #expirationDelay}. * The default is 30 seconds, but this can be configured by adding, in web.xml: *


   <init-param>
        <param-name>expirationDelay</param-name>
        <param-value>60000</param-value>
   </init-param>
 * 

* * The Grizzly Comet {@link NotificationHandler} can also be replaced by adding: *


   <init-param>
        <param-name>notificationHandler</param-name>
        <param-value>com.foo.bar.ScriptFilterNotificationHandler</param-value>
   </init-param>
 * 

* * A request can also be automatically suspended when the request URI only * contains the publish GCP action. *


   <init-param>
        <param-name>suspendOnTheFly</param-name>
        <param-value>true</param-value>
   </init-param>
 * 

* * * @author Jeanfrancois Arcand */ public class MessagesBus extends HttpServlet { /** * The Comet technique supported. */ public enum CometType { POLLING, LONG_POLLING, HTTP_STREAMING } // 30 seconds by default. private long expirationDelay = 30 * 1000; /** * The specified {@link NotificationHandler}. When not specified, * * */ private NotificationHandler notificationHandler = null; /** * Default Logger. */ private static final Logger logger = Logger.getAnonymousLogger(); /** * true if a connection can be automatically suspended * when the request only contains the GCP message publish * Default is true */ private boolean suspendOnTheFly = true; /** * {@inheritDoc} */ @Override public void init(ServletConfig config) throws ServletException { String ed = config.getInitParameter("expirationDelay"); if (ed != null) { expirationDelay = Long.parseLong(ed); } String nh = config.getInitParameter("notificationHandler"); if (ed != null) { notificationHandler = (NotificationHandler)loadClass(nh); } String stf = config.getInitParameter("suspendOnTheFly"); if (stf != null) { suspendOnTheFly = Boolean.valueOf(stf); } } /** * {@inheritDoc} */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { doPost(req, res); } /** * Basic implementation of the Grizzly Comet Protocol (GCP). * @param req The request * @param res The response * @throws javax.servlet.ServletException * @throws java.io.IOException */ @Override protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { CometType cometType = suspend(req, res); res.setContentType("text/html"); // The connection has been suspended. if (cometType != null && cometType != CometType.POLLING) { res.flushBuffer(); return; } push(req,res); } /** * Inspect the request, looking for the GCP parameters publish * and message. If those parameters are included, the * message will be pushed to all subscriber of the publish's value. * * @param req The http request * @param res The http response. * @throws java.io.IOException */ protected synchronized void push(HttpServletRequest req, HttpServletResponse res) throws IOException { String message = req.getParameter("message"); String topic = req.getParameter("publish"); // Nothing to send if (message == null || topic == null) { return; } CometContext context = CometEngine.getEngine().getCometContext(topic); if (context == null && suspendOnTheFly) { context = createCometContext(topic); CometType cometType = CometType.LONG_POLLING; CometHandler cometHandler = new MessagesBusCometHandler(context, cometType); cometHandler.attach(res); context.addCometHandler(cometHandler); } else if (!suspendOnTheFly) { if (logger.isLoggable(Level.INFO)) { logger.info("Cannot create message topic:" + topic + " on the fly. You first have to " + "subscribe"); } return; } context.notify(message); } /** * Suspend the connection if the request contains the GCP * suscribe and cometTechnique action. * @param req * @param res * @return {@link CometType} used to suspend the connection. * @throws java.io.UnsupportedEncodingException * @throws java.io.IOException */ protected synchronized CometType suspend(HttpServletRequest req, HttpServletResponse res) throws UnsupportedEncodingException, IOException { String cometTechnique = req.getParameter("cometTechnique"); String topic = req.getParameter("subscribe"); String message = req.getParameter("message"); // This is not a request for suspending the connection. if (cometTechnique == null || topic == null) { return CometType.POLLING; } if (logger.isLoggable(Level.FINE)) { logger.fine("CometTechnique: " + cometTechnique + " topic:" + topic); } if (cometTechnique.equals("polling")) { return CometType.POLLING; } CometContext context = CometEngine.getEngine().getCometContext(topic); if (context == null) { context = createCometContext(topic); } CometType cometType = null; if (cometTechnique.equals("long-polling")) { cometType = CometType.LONG_POLLING; } else if (cometTechnique.equals("http-streaming")) { cometType = CometType.HTTP_STREAMING; } CometHandler cometHandler = new MessagesBusCometHandler(context, cometType); cometHandler.attach(res); if (message != null){ context.notify(message); // Echo res.getWriter().write(message); } context.addCometHandler(cometHandler); return cometType; } /** * Create a Grizzly Comet {@link CometContext} * @param topic The name of the {@link CometContext} * @return a cached or newly created {@link CometContext} */ protected final CometContext createCometContext(String topic){ CometContext context = CometEngine.getEngine().register(topic); if (notificationHandler != null){ context.setNotificationHandler(notificationHandler); } context.setExpirationDelay(expirationDelay); context.setBlockingNotification(true); return context; } /** * Util to load classes using reflection. */ private static Object loadClass(String clazzName) { Class className = null; try { className = Class.forName(clazzName, true, Thread.currentThread().getContextClassLoader()); return className.newInstance(); } catch (Throwable t) { logger.log(Level.SEVERE,"Invalid NotificationHandler",t); } return null; } /** * Return the time a connection can stay idle. * @return */ public long getExpirationDelay() { return expirationDelay; } /** * Set the maximum idle time a connection can stay suspended. * @param expirationDelay */ public void setExpirationDelay(long expirationDelay) { this.expirationDelay = expirationDelay; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy