Move the bayeux to a separate module
authorfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Tue, 11 Nov 2008 15:58:23 +0000 (15:58 +0000)
committerfhanik <fhanik@13f79535-47bb-0310-9956-ffa450edef68>
Tue, 11 Nov 2008 15:58:23 +0000 (15:58 +0000)
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@713070 13f79535-47bb-0310-9956-ffa450edef68

63 files changed:
.classpath
extras.xml
java/org/apache/cometd/bayeux/Bayeux.java [deleted file]
java/org/apache/cometd/bayeux/Channel.java [deleted file]
java/org/apache/cometd/bayeux/Client.java [deleted file]
java/org/apache/cometd/bayeux/DataFilter.java [deleted file]
java/org/apache/cometd/bayeux/Listener.java [deleted file]
java/org/apache/cometd/bayeux/Message.java [deleted file]
java/org/apache/cometd/bayeux/SecurityPolicy.java [deleted file]
java/org/apache/tomcat/bayeux/BayeuxException.java [deleted file]
java/org/apache/tomcat/bayeux/BayeuxRequest.java [deleted file]
java/org/apache/tomcat/bayeux/BayeuxServlet.java [deleted file]
java/org/apache/tomcat/bayeux/ChannelImpl.java [deleted file]
java/org/apache/tomcat/bayeux/ClientImpl.java [deleted file]
java/org/apache/tomcat/bayeux/HttpError.java [deleted file]
java/org/apache/tomcat/bayeux/MessageImpl.java [deleted file]
java/org/apache/tomcat/bayeux/RequestBase.java [deleted file]
java/org/apache/tomcat/bayeux/RequestFactory.java [deleted file]
java/org/apache/tomcat/bayeux/TomcatBayeux.java [deleted file]
java/org/apache/tomcat/bayeux/request/MetaConnectRequest.java [deleted file]
java/org/apache/tomcat/bayeux/request/MetaDisconnectRequest.java [deleted file]
java/org/apache/tomcat/bayeux/request/MetaHandshakeRequest.java [deleted file]
java/org/apache/tomcat/bayeux/request/MetaSubscribeRequest.java [deleted file]
java/org/apache/tomcat/bayeux/request/MetaUnsubscribeRequest.java [deleted file]
java/org/apache/tomcat/bayeux/request/PublishRequest.java [deleted file]
modules/bayeux/.classpath [new file with mode: 0644]
modules/bayeux/.project [new file with mode: 0644]
modules/bayeux/build.xml [new file with mode: 0644]
modules/bayeux/java/org/apache/cometd/bayeux/Bayeux.java [new file with mode: 0644]
modules/bayeux/java/org/apache/cometd/bayeux/Channel.java [new file with mode: 0644]
modules/bayeux/java/org/apache/cometd/bayeux/Client.java [new file with mode: 0644]
modules/bayeux/java/org/apache/cometd/bayeux/DataFilter.java [new file with mode: 0644]
modules/bayeux/java/org/apache/cometd/bayeux/Listener.java [new file with mode: 0644]
modules/bayeux/java/org/apache/cometd/bayeux/Message.java [new file with mode: 0644]
modules/bayeux/java/org/apache/cometd/bayeux/SecurityPolicy.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/BayeuxException.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/BayeuxRequest.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/BayeuxServlet.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/ChannelImpl.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/ClientImpl.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/HttpError.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/MessageImpl.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/RequestBase.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/RequestFactory.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/TomcatBayeux.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaConnectRequest.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaDisconnectRequest.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaHandshakeRequest.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaSubscribeRequest.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaUnsubscribeRequest.java [new file with mode: 0644]
modules/bayeux/java/org/apache/tomcat/bayeux/request/PublishRequest.java [new file with mode: 0644]
modules/bayeux/test/org/apache/cometd/bayeux/samples/BayeuxStockTicker.java [new file with mode: 0644]
modules/bayeux/test/org/apache/cometd/bayeux/samples/EchoChatClient.java [new file with mode: 0644]
modules/bayeux/webapps/cometd/WEB-INF/web.xml [new file with mode: 0644]
modules/bayeux/webapps/cometd/examples/simplechat/cometdchat.htm [new file with mode: 0644]
modules/bayeux/webapps/cometd/examples/simplechat/ticker.html [new file with mode: 0644]
modules/bayeux/webapps/cometd/index.html [new file with mode: 0644]
test/org/apache/cometd/bayeux/samples/BayeuxStockTicker.java [deleted file]
test/org/apache/cometd/bayeux/samples/EchoChatClient.java [deleted file]
webapps/cometd/WEB-INF/web.xml [deleted file]
webapps/cometd/examples/simplechat/cometdchat.htm [deleted file]
webapps/cometd/examples/simplechat/ticker.html [deleted file]
webapps/cometd/index.html [deleted file]

index 071456f..1cddfd1 100644 (file)
@@ -1,20 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one or more
-  contributor license agreements.  See the NOTICE file distributed with
-  this work for additional information regarding copyright ownership.
-  The ASF licenses this file to You 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.
--->
 <classpath>
         <classpathentry excluding="**/.svn/**|org/apache/naming/factory/webservices/" kind="src" path="java"/>
        <classpathentry kind="src" path="test"/>
@@ -24,5 +8,7 @@
         <classpathentry kind="var" path="TOMCAT_LIBS_BASE/json-20080701/json.jar"/>
        <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
        <classpathentry kind="var" path="ANT_HOME/lib/ant.jar"/>
+       <classpathentry kind="lib" path="output/extras/webservices/jaxrpc.jar"/>
+       <classpathentry kind="lib" path="output/extras/webservices/wsdl4j.jar"/>
        <classpathentry kind="output" path=".settings/output"/>
 </classpath>
index 844531e..f1dc132 100644 (file)
@@ -15,7 +15,7 @@
   See the License for the specific language governing permissions and
   limitations under the License.
 -->
-<project name="Tomcat 6.0" default="extras" basedir=".">
+<project name="Tomcat 6.0" default="extras" basedir="../..">
 
 
   <!-- ===================== Initialize Property Values =================== -->
   <property name="tomcat-juli-adapters.jar" value="${tomcat.extras}/tomcat-juli-adapters.jar"/>
   <property name="catalina-ws.jar" value="${tomcat.extras}/catalina-ws.jar"/>
 
-  <property name="cometd-api.jar" value="${tomcat.extras}/cometd-api.jar"/>
-  <property name="tomcat-bayeux.jar" value="${tomcat.extras}/tomcat-bayeux.jar"/>
-  <property name="cometd.war" value="${tomcat.extras}/cometd.war"/>
-  <property name="tomcat-bayeux-samples.jar" value="${tomcat.extras}/tomcat-bayeux-samples.jar"/>
-
   <property name="catalina-jmx-remote.jar" value="${tomcat.extras}/catalina-jmx-remote.jar"/>
        
   <!-- Classpath -->
        
   </target>
 
-  <target name="bayeux">
-    <mkdir dir="${tomcat.extras}"/>
-
-    <antcall target="downloadgz">
-      <param name="sourcefile" value="${dojo-js.loc}"/>
-      <param name="destfile" value="${dojo-js.jar}"/>
-    </antcall>
-       
-    <copy todir="${tomcat.extras}" file="${json-lib.home}/${json-lib.jar}"/>
-    <!-- Classpath -->
-    <path id="tomcat.bayeux.classpath">
-      <pathelement path="${tomcat.classpath}"/>
-      <pathelement path="${json-lib.home}/${json-lib.jar}"/>
-    </path>
-
-    <!-- compile org.apache.tomcat.bayeux -->
-    <!-- compile org.apache.cometd -->
-    <javac srcdir="java" destdir="${tomcat.classes}"
-           debug="${compile.debug}"
-           deprecation="${compile.deprecation}"
-           source="${compile.source}"
-           optimize="${compile.optimize}">
-      <classpath refid="tomcat.bayeux.classpath" />
-      <include name="org/apache/tomcat/bayeux/**" />
-      <include name="org/apache/cometd/**" />
-    </javac>
-    
-    <!-- Cometd API JAR File -->
-    <jar jarfile="${cometd-api.jar}">
-      <fileset dir="${tomcat.classes}">
-        <exclude name="**/package.html" />
-        <exclude name="**/LocalStrings_*" />
-        <include name="org/apache/cometd/**" />
-      </fileset>
-    </jar>
-    <!-- Cometd API JAR File -->
-    <jar jarfile="${tomcat-bayeux.jar}">
-      <fileset dir="${tomcat.classes}">
-        <exclude name="**/package.html" />
-        <exclude name="**/LocalStrings_*" />
-        <include name="org/apache/tomcat/bayeux/**" />
-      </fileset>
-    </jar>
-
-    <!-- cometd samples application -->
-    <javac srcdir="test" destdir="${tomcat.classes}"
-           debug="${compile.debug}"
-           deprecation="${compile.deprecation}"
-           source="${compile.source}"
-           optimize="${compile.optimize}">
-      <classpath refid="tomcat.bayeux.classpath" />
-      <include name="org/apache/tomcat/bayeux/**" />
-      <include name="org/apache/cometd/**" />
-    </javac>
-    
-    <!-- Cometd samples JAR File -->
-    <jar jarfile="${tomcat-bayeux-samples.jar}">
-      <fileset dir="${tomcat.classes}">
-        <exclude name="**/package.html" />
-        <exclude name="**/LocalStrings_*" />
-        <include name="org/apache/cometd/bayeux/samples/**" />
-      </fileset>
-    </jar>
-    
-    <!-- build samples webapplication /cometd -->
-       <property name="cometd-app" value="${base.path}/cometd"/>
-       <mkdir dir="${cometd-app}"/>
-       
-       <copy todir="${cometd-app}">
-         <fileset dir="${basedir}/webapps/cometd">
-               <include name="**/**"/>
-         </fileset>
-      <fileset dir="${dojo-js.home}">
-       <include name="dojo/**"/>
-       <include name="dojox/**"/>
-      </fileset>       
-       </copy>
-    <mkdir dir="${cometd-app}/WEB-INF/lib"/>
-    <copy todir="${cometd-app}/WEB-INF/lib" file="${tomcat-bayeux-samples.jar}"/>
-       
-    <zip zipfile="${cometd.war}">
-      <fileset dir="${cometd-app}">
-        <include name="**/**"/>
-      </fileset>
-    </zip>
-       
-       <delete dir="${cometd-app}"/>
-       
-       <!-- create checksums -->
-    <checksum file="${cometd-api.jar}" forceOverwrite="yes" fileext=".md5" />
-    <checksum file="${tomcat-bayeux.jar}" forceOverwrite="yes" fileext=".md5" />
-    <checksum file="${cometd.war}" forceOverwrite="yes" fileext=".md5" />
-    <checksum file="${tomcat.extras}/${json-lib.jar}" forceOverwrite="yes" fileext=".md5" />
-       
-       <!-- print out how to --> 
-    <echo>You've built the Tomcat Bayeux libraries, simply add the following libraries to your CATALINA_HOME/lib directory:
-          ${cometd-api.jar}
-          ${tomcat-bayeux.jar} 
-          ${tomcat.extras}/${json-lib.jar}
-To run the sample application, copy the following applications into your CATALINA_BASE/webapps directory
-          ${cometd.war}
-    </echo>
-  </target>
-
-
-
   <target name="jmx-remote" >
     <!-- Create the JAR file -->
     <jar jarfile="${catalina-jmx-remote.jar}">
@@ -349,7 +238,7 @@ To run the sample application, copy the following applications into your CATALIN
          
   </target>
   
-  <target name="extras" depends="prepare,commons-logging,webservices,bayeux,jmx-remote">
+  <target name="extras" depends="prepare,commons-logging,webservices,jmx-remote">
   </target>
 
   <!-- Download and dependency building -->
diff --git a/java/org/apache/cometd/bayeux/Bayeux.java b/java/org/apache/cometd/bayeux/Bayeux.java
deleted file mode 100644 (file)
index 5385d32..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.cometd.bayeux;\r
-\r
-import java.util.List;\r
-\r
-/** Bayeux Interface.<br/>\r
- * This interface represents the server side API for the Bayeux messaging protocol.\r
- * Bayeux is a simple subscribe/publish/receive methodology, not far from JMS, but much simplified.<br/>\r
- * It is used both by the actual implementation and by server side clients.<br/>\r
- * Server side clients use this to create, retrieve and subscribe to channels.\r
- * Server side clients are represented, just like remote clients, through the Client interface.\r
- * <br/>\r
- * The Bayeux implementations is intended to be thread safe and multiple threads may simultaneously call Bayeux methods.\r
- * <br/>\r
- * The Bayeux object, is the starting point for any cometd application relying on the Bayeux object.\r
- * Dependent on the container, the Bayeux object will be stored in the <code>javax.servlet.ServletContext</code> object\r
- * as an attribute under the name <code>Bayeux.DOJOX_COMETD_BAYEUX</code><br/>\r
- * To retrieve this object, one would simply call<br/>\r
- * <code>Bayeux bx = (Bayeux)getServletContext().getAttribute(Bayeux.DOJOX_COMETD_BAYEUX);\r
- * <br/><br/>\r
- * The Bayeux protocol is pretty straight forward and includes a bunch of messaging that is not needed to be known to clients,\r
- * both server side and remote clients.\r
- * This object gets initialized by a container dependent servlet, and the servlet then handles all Bayeux communication from the client.\r
- * Remote messsages are delivered to channels, and to server side clients using the <code>Listener</code> interface.<br/>\r
- * <br/>\r
- * A <code>Bayeux session</code> is active as long as the webapp hosting the Bayeux object is active.<br/>\r
- * When the webapplication shuts down, the Bayeux object will unsubscribe all clients and remove all the active channels.\r
- * \r
- * @author Greg Wilkins\r
- * @author Filip Hanik\r
- */\r
-public interface Bayeux {\r
-    \r
-    /**Meta definitions for channels*/\r
-    public static final String META="/meta";\r
-    /**Meta definitions for channels*/\r
-    public static final String META_SLASH="/meta/";\r
-    /**Meta definitions for channels - connect message*/\r
-    public static final String META_CONNECT="/meta/connect";\r
-    /**Meta definitions for channels - client messsage*/\r
-    public static final String META_CLIENT="/meta/client";\r
-    /**Meta definitions for channels - disconnect messsage*/\r
-    public static final String META_DISCONNECT="/meta/disconnect";\r
-    /**Meta definitions for channels - handshake messsage*/\r
-    public static final String META_HANDSHAKE="/meta/handshake";\r
-    /**Meta definitions for channels - ping messsage*/\r
-    public static final String META_PING="/meta/ping";\r
-    /**Meta definitions for channels - reconnect messsage\r
-     * @deprecated\r
-     */\r
-    public static final String META_RECONNECT="/meta/reconnect";\r
-    /**Meta definitions for channels - status messsage*/\r
-    public static final String META_STATUS="/meta/status";\r
-    /**Meta definitions for channels - subscribe messsage*/\r
-    public static final String META_SUBSCRIBE="/meta/subscribe";\r
-    /**Meta definitions for channels - unsubscribe messsage*/\r
-    public static final String META_UNSUBSCRIBE="/meta/unsubscribe";\r
-    /*Field names inside Bayeux messages*/\r
-    /**Field names inside Bayeux messages - clientId field*/\r
-    public static final String CLIENT_FIELD="clientId";\r
-    /**Field names inside Bayeux messages - data field*/\r
-    public static final String DATA_FIELD="data";\r
-    /**Field names inside Bayeux messages - channel field*/\r
-    public static final String CHANNEL_FIELD="channel";\r
-    /**Field names inside Bayeux messages - id field*/\r
-    public static final String ID_FIELD="id";\r
-    /**Field names inside Bayeux messages - error field*/\r
-    public static final String ERROR_FIELD="error";\r
-    /**Field names inside Bayeux messages - timestamp field*/\r
-    public static final String TIMESTAMP_FIELD="timestamp";\r
-    /**Field names inside Bayeux messages - transport field*/\r
-    public static final String TRANSPORT_FIELD="transport";\r
-    /**Field names inside Bayeux messages - advice field*/\r
-    public static final String ADVICE_FIELD="advice";\r
-    /**Field names inside Bayeux messages - successful field*/\r
-    public static final String SUCCESSFUL_FIELD="successful";\r
-    /**Field names inside Bayeux messages - subscription field*/\r
-    public static final String SUBSCRIPTION_FIELD="subscription";\r
-    /**Field names inside Bayeux messages - ext field*/\r
-    public static final String EXT_FIELD="ext";\r
-    /**Field names inside Bayeux messages - connectionType field*/\r
-    public static final String CONNECTION_TYPE_FIELD="connectionType";\r
-    /**Field names inside Bayeux messages - version field*/\r
-    public static final String VERSION_FIELD="version";\r
-    /**Field names inside Bayeux messages - minimumVersion field*/\r
-    public static final String MIN_VERSION_FIELD="minimumVersion";\r
-    /**Field names inside Bayeux messages - supportedConnectionTypes field*/\r
-    public static final String SUPP_CONNECTION_TYPE_FIELD="supportedConnectionTypes";\r
-    /**Field names inside Bayeux messages - json-comment-filtered field*/\r
-    public static final String JSON_COMMENT_FILTERED_FIELD="json-comment-filtered";\r
-    /**Field names inside Bayeux messages - reconnect field*/\r
-    public static final String RECONNECT_FIELD = "reconnect";\r
-    /**Field names inside Bayeux messages - interval field*/\r
-    public static final String INTERVAL_FIELD = "interval";\r
-    /**Field values inside Bayeux messages - retry response*/\r
-    public static final String RETRY_RESPONSE = "retry";\r
-    /**Field values inside Bayeux messages - handshake response*/\r
-    public static final String HANDSHAKE_RESPONSE = "handshake";\r
-    /**Field values inside Bayeux messages - none response*/\r
-    public static final String NONE_RESPONSE = "none";\r
-    /**Service channel names-starts with*/\r
-    public static final String SERVICE="/service";\r
-    /**Service channel names-trailing slash*/\r
-    public static final String SERVICE_SLASH="/service/";\r
-    /*Transport types*/\r
-    /**Transport types - long polling*/\r
-    public static final String TRANSPORT_LONG_POLL="long-polling";\r
-    /**Transport types - callback polling*/\r
-    public static final String TRANSPORT_CALLBACK_POLL="callback-polling";\r
-    /**Transport types - iframe*/\r
-    public static final String TRANSPORT_IFRAME="iframe";\r
-    /**Transport types - flash*/\r
-    public static final String TRANSPORT_FLASH="flash";\r
-    /** ServletContext attribute name used to obtain the Bayeux object */\r
-    public static final String DOJOX_COMETD_BAYEUX="dojox.cometd.bayeux";\r
-    /*http field names*/\r
-    /**http helpers - text/json content type*/\r
-    public static final String JSON_CONTENT_TYPE="text/json";\r
-    /**http helpers - parameter name for json message*/\r
-    public static final String MESSAGE_PARAMETER="message";\r
-    /**http helpers - name of the jsonp parameter*/\r
-    public static final String JSONP_PARAMETER="jsonp";\r
-    /**http helpers - default name of the jsonp callback function*/\r
-    public static final String JSONP_DEFAULT_NAME="jsonpcallback";\r
-\r
-    /*--Client----------------------------------------------------------- */\r
-    /**\r
-     * Creates a new server side client. This method is to be invoked\r
-     * by server side objects only. You cannot create a remote client by using this method.\r
-     * A client represents an entity that can subscribe to channels and publish and receive messages\r
-     * through these channels\r
-     * @param idprefix String - the prefix string for the id generated, can be null\r
-     * @param listener Listener - a callback object to be called when messages are to be delivered to the new client\r
-     * @return Client - returns an implementation of the client interface.\r
-     */\r
-    public Client newClient(String idprefix, Listener listener);\r
-\r
-    /**\r
-     * retrieve a client based on an ID. Will return null if the client doesn't exist.\r
-     * @param clientid String\r
-     * @return Client-null if the client doesn't exist.returns the client if it does.\r
-     */\r
-    public Client getClient(String clientid);\r
-    \r
-    /**\r
-     * Returns a non modifiable list of all the clients that are currently active\r
-     * in this Bayeux session\r
-     * @return List<Client> - a list containing all clients. The List can not be modified.\r
-     */\r
-    public List<Client> getClients();\r
-    \r
-    /**\r
-     * Returns true if a client with the given id exists.<br/>\r
-     * Same as executing <code>getClient(id)!=null</code>.\r
-     * @param clientId String\r
-     * @return boolean - true if the client exists\r
-     */\r
-    public boolean hasClient(String clientId);\r
-    \r
-    /**\r
-     * Removes the client all together.\r
-     * This will unsubscribe the client to any channels it may be subscribed to\r
-     * and remove it from the list.\r
-     * @param client Client\r
-     * @return Client - returns the client that was removed, or null if no client was removed.\r
-     */\r
-    public Client remove(Client client);\r
-\r
-    \r
-    /*--Channel---------------------------------------------------------- */\r
-    /**\r
-     * Returns the channel for a given channel id.\r
-     * If the channel doesn't exist, and the <code>create</code> parameter is set to true,\r
-     * the channel will be created and added to the list of active channels.<br/>\r
-     * if <code>create</code> is set to false, and the channel doesn't exist, null will be returned.\r
-     * @param channelId String - the id of the channel to be retrieved or created\r
-     * @param create boolean - true if the Bayeux impl should create the channel\r
-     * @return Channel - null if <code>create</code> is set to false and the channel doesn't exist, \r
-     * otherwise it returns a channel object.\r
-     */\r
-    public Channel getChannel(String channelId, boolean create);\r
-    \r
-    /**\r
-     * Returns a list of currently active channels in this Bayeux session.\r
-     * @return List<Channel>\r
-     */\r
-    public List<Channel> getChannels();\r
-\r
-    /**\r
-     * Removes a channel from the Bayeux object.\r
-     * This will also unsubscribe all the clients currently subscribed to the\r
-     * the channel.\r
-     * @param channel Channel - the channel to be removed\r
-     * @return Channel - returns the channel that was removed, or null if no channel was removed.\r
-     */\r
-    public Channel remove(Channel channel);\r
-\r
-    /**\r
-     * returns true if a channel with the given channelId exists.\r
-     * <br/>Same as executing <code>Bayeux.getChannel(channelId,false)!=null</code>\r
-     * @param channelId String\r
-     * @return boolean - true if the channel exists.\r
-     */\r
-    public boolean hasChannel(String channelId);\r
-\r
-    /* --Message---------------------------------------------------------- */\r
-    /**\r
-     * Creates a new message to be sent by a server side client.\r
-     * @return Message - returns a new Message object, that has a unique id.\r
-     */\r
-    public Message newMessage(Client from);\r
-\r
-\r
-    /*--Security policy----------------------------------------------------------- */\r
-    /**\r
-     * Returns the security policy associated with this Bayeux session\r
-     * @return SecurityPolicy\r
-     */\r
-    public SecurityPolicy getSecurityPolicy();\r
-   \r
-    /**\r
-     * Sets the security policy to be used in this Bayeux session\r
-     * @param securityPolicy SecurityPolicy\r
-     */\r
-    public void setSecurityPolicy(SecurityPolicy securityPolicy);\r
-\r
-}
\ No newline at end of file
diff --git a/java/org/apache/cometd/bayeux/Channel.java b/java/org/apache/cometd/bayeux/Channel.java
deleted file mode 100644 (file)
index 34af328..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.cometd.bayeux;\r
-\r
-import java.util.List;\r
-\r
-/** \r
- * A Bayeux Channel represents a channel used to receive messages from and to publish messages to.\r
- * In order to publish messages to or receive messages from, one must subscribe to the channel.\r
- * This is easily done by invoking the <code>subscribe</code> method.\r
- * A channel is created by calling the <code>Bayeux.getChannel(channelId,true)</code> method.\r
- * A channel can be created either server side by invoking the getChannel, or client side\r
- * by using the /meta/subscribe message without a wildcard.\r
- * @author Greg Wilkins\r
- * @author Filip Hanik\r
- */\r
-public interface Channel\r
-{\r
-    /**\r
-     * Returns the id for this channel. The id is unique within bayeux session.\r
-     * @return String - will never be null.\r
-     */\r
-    public String getId();\r
-\r
-    /** \r
-     * Publishes a message to all the subscribers of this channel.\r
-     * The <code>from</code> is contained within the message, by calling\r
-     * <code>msg.getClient()</code>\r
-     * @param data - the message to be published, can not be null.\r
-     */\r
-    public void publish(Message msg);\r
-    \r
-    /** \r
-     * Publishes more than one message to all the subscribers of this channel.\r
-     * The <code>from</code> is contained within the message, by calling\r
-     * <code>msg[x].getClient()</code>\r
-     * @param data - the message to be published, can not be null.\r
-     */\r
-    public void publish(Message[] msgs);\r
-\r
-    /** \r
-     * Non persistent channels are removed when the last subscription is\r
-     * removed. Persistent channels survive periods without any subscribers.\r
-     * @return true if the Channel will persist without any subscription.\r
-     */\r
-    public boolean isPersistent();\r
-    \r
-    /**\r
-     * @param persistent true if the Channel will persist without any subscription.\r
-     * @see isPersistent\r
-     */\r
-    public void setPersistent(boolean persistent);\r
-    \r
-    /** \r
-     * Subscribes a client to a channel.\r
-     * @param subscriber - the client to be subscribed. If the client\r
-     * already is subscribed, this call will not create a duplicate subscription.\r
-     */\r
-    public void subscribe(Client subscriber);\r
-\r
-    /** \r
-     * Unsubscribes a client from a channel\r
-     * @param subscriber - the client to be subscribed.\r
-     * @return - returns the client that was unsubscribed, or null if the client wasn't subscribed.\r
-     */\r
-    public Client unsubscribe(Client subscriber);\r
-\r
-    /**\r
-     * returns a non modifiable list of all the subscribers to this \r
-     * channel.\r
-     * @return a list of subscribers\r
-     */\r
-    public List<Client> getSubscribers();\r
-    \r
-    /**\r
-     * Adds a data filter to this channel. All messages received by this channel \r
-     * will run through this filter.\r
-     * @param filter Filter\r
-     */\r
-    public void addFilter(DataFilter filter);\r
-    \r
-    /**\r
-     * Removes a filter from this channel.\r
-     * returns the filter that was removed, or null if the filter wasn't in the channel.\r
-     * @param filter Filter\r
-     * @return Filter - null if no filter was removed otherwise it returns the filter that was removed.\r
-     */\r
-    public DataFilter removeFilter(DataFilter filter);\r
-}
\ No newline at end of file
diff --git a/java/org/apache/cometd/bayeux/Client.java b/java/org/apache/cometd/bayeux/Client.java
deleted file mode 100644 (file)
index 3d6a8d8..0000000
+++ /dev/null
@@ -1,91 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-package org.apache.cometd.bayeux;\r
-\r
-\r
-\r
-/** A Bayeux Client.\r
- * <p>\r
- * A client may subscribe to channels and publish messages to channels.\r
- * Client instances should not be directly created by uses, but should \r
- * be obtained via the {@link Bayeux#getClient(String)} or {@link Bayeux#newClient(String, Listener)}\r
- * methods.\r
- * </p>\r
- * <p>\r
- * Three types of client may be represented by this interface:<nl>\r
- * <li>The server representation of a remote client connected via HTTP, \r
- *     automatically created by the Bayeux server when a connect message comes in</li>\r
- * <li>A server side client, created by the application using the {@link Bayeux#newClient(String, Listener)} method</li>\r
- * <li>A java client connected to a remote Bayeux server - not implemented</li>\r
- * </nl>\r
- * @author Greg Wilkins\r
- * @author Filip Hanik\r
- */\r
-public interface Client\r
-{\r
-    /**\r
-     * Returns a unique id for this client. The id is unique within this Bayeux session.\r
-     * @return String - will not be null\r
-     */\r
-    public String getId();\r
-\r
-    /**\r
-     * Returns true if this client is holding messages to be delivered to the remote client.\r
-     * This method always returns false for local clients, since messages are delivered instantly using the \r
-     * Listener(callback) object\r
-     * @return boolean\r
-     */\r
-    public boolean hasMessages();\r
-\r
-    /** \r
-     * Deliver a message to this client only\r
-     * Deliver a message directly to the client. The message is not \r
-     * filtered or published to a channel.\r
-     * @param message\r
-     */\r
-    public void deliver(Message message);\r
-\r
-    /** \r
-     * Deliver a batch of messages to this client only\r
-     * Deliver a batch messages directly to the client. The messages are not \r
-     * filtered or published to a channel.\r
-     * @param message\r
-     */\r
-    public void deliver(Message[] message);\r
-\r
-    /**\r
-     * @return True if the client is local. False if this client is either a remote HTTP client or\r
-     * a java client to a remote server. \r
-     */\r
-    public boolean isLocal();\r
-    \r
-    /**\r
-     * Starts a batch, no messages will be delivered until endBatch is called.\r
-     * Batches can be nested, and messages will only be delivered after\r
-     * the last endBatch has been called.\r
-     */\r
-    public void startBatch();\r
-    \r
-    /**\r
-     * Ends a batch. since batches can be nested, messages will only be delivered\r
-     * after the endBatch has been called as many times as startBatch has.\r
-     */\r
-    public void endBatch();\r
-    \r
-    \r
-}
\ No newline at end of file
diff --git a/java/org/apache/cometd/bayeux/DataFilter.java b/java/org/apache/cometd/bayeux/DataFilter.java
deleted file mode 100644 (file)
index d632aec..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.cometd.bayeux;\r
-\r
-/** \r
- * Data Filter<br/>\r
- * Data filters are used to transform data as it is sent to a Channel.\r
- * Messages are filtered as the message is published to a channel, invoking the \r
- * {@link Channel#publish(Message)} method.<br/>\r
- * This method gets invoked in two different scenarios, the first being when a message is received from\r
- * a remote client, and the Bayeux implementation invokes the publish method directly.\r
- * The second scenario is when a local client invokes {@link Channel#publish(Message)} directly in the local JVM.\r
- * @author Greg Wilkins\r
- * @author Filip Hanik\r
- *\r
- */\r
-public interface DataFilter\r
-{\r
-    /**\r
-     * Runs a message through the filter. Filtering can only modify an existing object, it can not replace it.\r
-     * @param data Message - the message to be filtered, may not be null\r
-     */\r
-    public void filter(Message data);\r
-}\r
diff --git a/java/org/apache/cometd/bayeux/Listener.java b/java/org/apache/cometd/bayeux/Listener.java
deleted file mode 100644 (file)
index cce2018..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.cometd.bayeux;\r
-\r
-/** \r
- * Cometd Listener interface.<br/>\r
- * For local clients, in order to receive messages, they pass in a callback object\r
- * when the local client is created using the {@link Bayeux#newClient(String,Listener)} method.\r
- * This callback object, implementing the Listener interface, is used to deliver messages to local, in JVM, clients.\r
- * @author Greg Wilkins\r
- * @author Filip Hanik\r
- *\r
- */\r
-public interface Listener\r
-{\r
-    /**\r
-     * This method is called when the client is removed (explicitly or from a timeout)\r
-     * @param timeout - true if the client was removed from a timeout\r
-     * false if it was removed explicitly.\r
-     */\r
-    public void removed(boolean timeout);\r
-    \r
-    /**\r
-     * Invoked when a message is delivered to the client.\r
-     * The message contains the message itself, as well as what channel this message came through\r
-     * and who the sender is. If someone invoked {@link Client#deliver(Message)} then the channel reference will\r
-     * be null.\r
-     * @param msg \r
-     */\r
-    public void deliver(Message[] msg);\r
-}\r
diff --git a/java/org/apache/cometd/bayeux/Message.java b/java/org/apache/cometd/bayeux/Message.java
deleted file mode 100644 (file)
index 26ba640..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.cometd.bayeux;\r
-\r
-import java.util.Map;\r
-\r
-/** \r
- * A Bayeux Message<br/>\r
- * A Bayeux message is a Map of String/Object key value pairs representing the data in the message.\r
- * The message contains information about the channel it was published through and who the sender was\r
- * \r
- * @author Greg Wilkins\r
- * @author Filip Hanik\r
- */\r
-public interface Message extends Map<String,Object>\r
-{\r
-    /**\r
-     * Returns a reference to the client that sent this message\r
-     * @return Client - may be null\r
-     */\r
-    public Client getClient();\r
-    /**\r
-     * Returns a reference to the channel that this message was published throuhg\r
-     * @return Channel - may be null\r
-     */\r
-    public Channel getChannel();\r
-    /**\r
-     * Returns the unique id of this message\r
-     * @return String\r
-     */\r
-    public String getId();\r
-    \r
-    /**\r
-     * Sets the time to live in milliseconds. If the message hasn't been delivered \r
-     * when the time passed after the creation time is longer than the TTL the message will\r
-     * expire and removed from any delivery queues.\r
-     * @param ttl long\r
-     */\r
-    public void setTTL(long ttl);\r
-    \r
-    /**\r
-     * Returns the time to live (in milliseconds) for this message\r
-     * @return long\r
-     */\r
-    public long getTTL();\r
-    \r
-    /**\r
-     * returns the timestamp in milliseconds(System.currentTimeMillis()) of when this message was created.\r
-     * @return long\r
-     */\r
-    public long getCreationTime();\r
-}\r
-\r
-\r
diff --git a/java/org/apache/cometd/bayeux/SecurityPolicy.java b/java/org/apache/cometd/bayeux/SecurityPolicy.java
deleted file mode 100644 (file)
index 930f605..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.cometd.bayeux;\r
-\r
-/**\r
- * @author Greg Wilkins\r
- */\r
-public interface SecurityPolicy\r
-{\r
-    boolean canHandshake(Message message);\r
-    boolean canCreate(Client client,String channel,Message message);\r
-    boolean canSubscribe(Client client,String channel,Message messsage);\r
-    boolean canPublish(Client client,String channel,Message messsage);\r
-}\r
diff --git a/java/org/apache/tomcat/bayeux/BayeuxException.java b/java/org/apache/tomcat/bayeux/BayeuxException.java
deleted file mode 100644 (file)
index d201c5e..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux;\r
-/**\r
- * \r
- * @author Filip Hanik\r
- * @version 1.0\r
- */\r
-public class BayeuxException extends Exception {\r
-    public BayeuxException() {\r
-        super();\r
-    }\r
-\r
-    public BayeuxException(String message) {\r
-        super(message);\r
-    }\r
-\r
-    public BayeuxException(String message, Throwable cause) {\r
-        super(message, cause);\r
-    }\r
-\r
-    public BayeuxException(Throwable cause) {\r
-        super(cause);\r
-    }\r
-}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/bayeux/BayeuxRequest.java b/java/org/apache/tomcat/bayeux/BayeuxRequest.java
deleted file mode 100644 (file)
index 6e93c99..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux;\r
-\r
-import org.apache.tomcat.bayeux.HttpError;\r
-\r
-/**\r
- * An interface that defines methods for managing Bayeux request meta \r
- * messages.\r
- *\r
- * @author Guy A. Molinari\r
- * @author Filip Hanik\r
- * @version 0.9\r
- */\r
-public interface BayeuxRequest {\r
-\r
-    public static final String LAST_REQ_ATTR = "org.apache.cometd.bayeux.last_request";\r
-    public static final String CURRENT_REQ_ATTR = "org.apache.cometd.bayeux.current_request";\r
-    public static final String JSON_MSG_ARRAY = "org.apache.cometd.bayeux.json_msg_array";\r
-\r
-    /**\r
-     * Validates a specific request. \r
-     * This method must be called prior to process()\r
-     * as a request can do pre processing in the validate method.\r
-     * <br/>\r
-     * Should the validation fail, an error object is returned \r
-     * containing an error message, and potentially a stack trace\r
-     * if an exception was generated\r
-     * @return HttpError - null if no error was detected, an HttpError object containing information about the error.\r
-     */\r
-    public HttpError validate();\r
-    \r
-    /**\r
-     * processes a remote client Bayeux message\r
-     * @param prevops - the operation requested by the previous request, in case of chained requests.\r
-     * @return int - returns the interest operation for a CometEvent. Currently not used\r
-     * @throws BayeuxException - if an error was detected, and the appropriate error response couldn't be delivered to the client. \r
-     */\r
-    public int process(int prevops) throws BayeuxException;\r
-}\r
diff --git a/java/org/apache/tomcat/bayeux/BayeuxServlet.java b/java/org/apache/tomcat/bayeux/BayeuxServlet.java
deleted file mode 100644 (file)
index 837086d..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- *\r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux;\r
-\r
-import java.io.IOException;\r
-import javax.servlet.ServletConfig;\r
-import javax.servlet.ServletContext;\r
-import javax.servlet.ServletException;\r
-import javax.servlet.ServletRequest;\r
-import javax.servlet.ServletResponse;\r
-import javax.servlet.http.HttpServletResponse;\r
-\r
-import org.apache.catalina.CometEvent;\r
-import org.apache.catalina.CometProcessor;\r
-import org.apache.juli.logging.Log;\r
-import org.apache.juli.logging.LogFactory;\r
-import org.json.JSONArray;\r
-import org.json.JSONException;\r
-import org.json.JSONObject;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-\r
-/**\r
- * \r
- * @author Filip Hanik\r
- * @author Guy Molinari\r
- * @version 1.0\r
- */\r
-public class BayeuxServlet implements CometProcessor {\r
-\r
-    /**\r
-     * Attribute to hold the TomcatBayeux object in the servlet context\r
-     */\r
-    public static final String TOMCAT_BAYEUX_ATTR = Bayeux.DOJOX_COMETD_BAYEUX;\r
-    \r
-    /**\r
-     * Logger object\r
-     */\r
-    protected static Log log = LogFactory.getLog(BayeuxServlet.class);\r
-\r
-    /**\r
-     * Servlet config - for future use\r
-     */\r
-    protected ServletConfig servletConfig;\r
-    \r
-    /**\r
-     * Reference to the global TomcatBayeux object\r
-     */\r
-    protected TomcatBayeux tb;\r
-    \r
-    /**\r
-     * Upon servlet destruction, the servlet will clean up the \r
-     * TomcatBayeux object and terminate any outstanding events.\r
-     */\r
-    public void destroy() {\r
-        servletConfig = null;\r
-        //to do, close all outstanding comet events\r
-        //tb.destroy();\r
-        tb = null;//TO DO, close everything down\r
-        \r
-    }\r
-    \r
-    /**\r
-     * Returns the preconfigured connection timeout.\r
-     * If no timeout has been configured as a servlet init parameter named <code>timeout</code>\r
-     * then the default of 2min will be used.\r
-     * @return int - the timeout for a connection in milliseconds\r
-     */\r
-    protected int getTimeout() {\r
-        String timeoutS = servletConfig.getInitParameter("timeout");\r
-        int timeout = 120*1000; //2 min\r
-        try {\r
-            timeout = Integer.parseInt(timeoutS);\r
-        }catch (NumberFormatException nfe) {\r
-            //ignore, we have a default value\r
-        }\r
-        return timeout;\r
-    }\r
-    \r
-    protected int getReconnectInterval() {\r
-        String rs = servletConfig.getInitParameter("reconnectInterval");\r
-        int rct = 1000; //1 seconds\r
-        try {\r
-            rct = Integer.parseInt(rs);\r
-        }catch (NumberFormatException nfe) {\r
-            //ignore, we have a default value\r
-        }\r
-        return rct;\r
-    }\r
-\r
-\r
-    public void event(CometEvent cometEvent) throws IOException, ServletException {\r
-        CometEvent.EventType type = cometEvent.getEventType();\r
-        if (log.isDebugEnabled()) {\r
-            log.debug("["+Thread.currentThread().getName()+"] Received Comet Event type="+type+" subtype:"+cometEvent.getEventSubType());\r
-        }\r
-        synchronized (cometEvent) {\r
-            if (type==CometEvent.EventType.BEGIN) {\r
-                //begin event, set the timeout\r
-                cometEvent.setTimeout(getTimeout());\r
-                //checkBayeux(cometEvent); - READ event should always come\r
-            } else if (type==CometEvent.EventType.READ) {\r
-                checkBayeux(cometEvent);\r
-            } else if (type==CometEvent.EventType.ERROR) {\r
-                tb.remove(cometEvent);\r
-                cometEvent.close();\r
-            } else if (type==CometEvent.EventType.END) {\r
-                tb.remove(cometEvent);\r
-                cometEvent.close();\r
-            }//end if\r
-            \r
-        }//synchronized\r
-    }//event\r
-\r
-    /**\r
-     * \r
-     * @param cometEvent CometEvent\r
-     * @return boolean - true if we comet event stays open\r
-     * @throws IOException\r
-     * @throws UnsupportedOperationException\r
-     */\r
-    protected void checkBayeux(CometEvent cometEvent) throws IOException, UnsupportedOperationException {\r
-        //we actually have data.\r
-        //data can be text/json or \r
-        if (Bayeux.JSON_CONTENT_TYPE.equals(cometEvent.getHttpServletRequest().getContentType())) {\r
-            //read and decode the bytes according to content length\r
-            log.warn("["+Thread.currentThread().getName()+"] JSON encoding not supported, will throw an exception and abort the request.");\r
-            int contentlength = cometEvent.getHttpServletRequest().getContentLength();\r
-            throw new UnsupportedOperationException("Decoding "+Bayeux.JSON_CONTENT_TYPE+" not yet implemented.");\r
-        } else { //GET method or application/x-www-form-urlencoded\r
-            String message = cometEvent.getHttpServletRequest().getParameter(Bayeux.MESSAGE_PARAMETER);\r
-            if (log.isTraceEnabled()) {\r
-                log.trace("["+Thread.currentThread().getName()+"] Received JSON message:"+message);\r
-            }\r
-            try {\r
-                int action = handleBayeux(message, cometEvent);\r
-                if (log.isDebugEnabled()) {\r
-                    log.debug("["+Thread.currentThread().getName()+"] Bayeux handling complete, action result="+action);\r
-                }\r
-                if (action<=0) {\r
-                    cometEvent.close();\r
-                }\r
-            }catch (Exception x) {\r
-                x.printStackTrace();\r
-                tb.remove(cometEvent);\r
-                log.error(x);\r
-                cometEvent.close();\r
-            }\r
-        }\r
-    }\r
-    \r
-    protected int handleBayeux(String message, CometEvent event) throws IOException, ServletException {\r
-        int result = 0;\r
-        if (message==null || message.length()==0) return result;\r
-        try {\r
-            BayeuxRequest request = null;\r
-            //a message can be an array of messages\r
-            JSONArray jsArray = new JSONArray(message);\r
-            for (int i = 0; i < jsArray.length(); i++) {\r
-                JSONObject msg = jsArray.getJSONObject(i);\r
-                \r
-                if (log.isDebugEnabled()) {\r
-                    log.debug("["+Thread.currentThread().getName()+"] Processing bayeux message:"+msg);\r
-                }\r
-                request = RequestFactory.getRequest(tb,event,msg);\r
-                if (log.isDebugEnabled()) {\r
-                    log.debug("["+Thread.currentThread().getName()+"] Processing bayeux message using request:"+request);\r
-                }\r
-                result = request.process(result);\r
-                if (log.isDebugEnabled()) {\r
-                    log.debug("["+Thread.currentThread().getName()+"] Processing bayeux message result:"+result);\r
-                }\r
-            }\r
-            if (result>0 && request!=null) {\r
-                event.getHttpServletRequest().setAttribute(BayeuxRequest.LAST_REQ_ATTR, request);\r
-                ClientImpl ci = (ClientImpl)tb.getClient(((RequestBase)request).getClientId());\r
-                ci.addCometEvent(event);\r
-                if (log.isDebugEnabled()) {\r
-                    log.debug("["+Thread.currentThread().getName()+"] Done bayeux message added to request attribute");\r
-                }\r
-            } else if (result == 0 && request!=null) {\r
-                RequestBase.deliver(event,(ClientImpl)tb.getClient(((RequestBase)request).getClientId()));\r
-                if (log.isDebugEnabled()) {\r
-                    log.debug("["+Thread.currentThread().getName()+"] Done bayeux message, delivered to client");\r
-                }\r
-            }\r
-            \r
-        }catch (JSONException x) {\r
-            log.error(x);//to do impl error handling\r
-            result = -1;\r
-        }catch (BayeuxException x) {\r
-            log.error(x); //to do impl error handling\r
-            result = -1;\r
-        }\r
-        return result;\r
-    }\r
-\r
-    public ServletConfig getServletConfig() {\r
-        return servletConfig;\r
-    }\r
-\r
-    public String getServletInfo() {\r
-        return "Tomcat/BayeuxServlet/1.0";\r
-    }\r
-\r
-    public void init(ServletConfig servletConfig) throws ServletException {\r
-        \r
-        this.servletConfig = servletConfig;\r
-        ServletContext ctx = servletConfig.getServletContext();\r
-        if (ctx.getAttribute(TOMCAT_BAYEUX_ATTR)==null)\r
-            ctx.setAttribute(TOMCAT_BAYEUX_ATTR,new TomcatBayeux());\r
-        this.tb = (TomcatBayeux)ctx.getAttribute(TOMCAT_BAYEUX_ATTR);\r
-        tb.setReconnectInterval(getReconnectInterval());\r
-    }\r
-\r
-    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {\r
-        if (servletResponse instanceof HttpServletResponse) {\r
-            ( (HttpServletResponse) servletResponse).sendError(500, "Misconfigured Tomcat server, must be configured to support Comet operations.");\r
-        } else {\r
-            throw new ServletException("Misconfigured Tomcat server, must be configured to support Comet operations for the Bayeux protocol.");\r
-        }\r
-    }\r
-}\r
diff --git a/java/org/apache/tomcat/bayeux/ChannelImpl.java b/java/org/apache/tomcat/bayeux/ChannelImpl.java
deleted file mode 100644 (file)
index e1e08a8..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux;\r
-\r
-import java.util.LinkedList;\r
-\r
-import org.apache.cometd.bayeux.Channel;\r
-import org.apache.cometd.bayeux.Client;\r
-import org.apache.cometd.bayeux.DataFilter;\r
-import java.util.Collections;\r
-import java.util.List;\r
-import org.apache.cometd.bayeux.Message;\r
-import java.util.Iterator;\r
-import org.apache.juli.logging.Log;\r
-import org.apache.juli.logging.LogFactory;\r
-/**\r
- * \r
- * @author Filip Hanik\r
- * @version 1.0\r
- */\r
-public class ChannelImpl implements Channel {\r
-    \r
-    protected static Log log = LogFactory.getLog(ChannelImpl.class);\r
-    \r
-    /**\r
-     * The unique id of this channel\r
-     */\r
-    protected String id = null;\r
-    \r
-    /**\r
-     * A list of the current subscribers\r
-     */\r
-    protected LinkedList<Client> subscribers = new LinkedList<Client>();\r
-    \r
-    /**\r
-     * A list of the current filters\r
-     */\r
-    protected LinkedList<DataFilter> filters = new LinkedList<DataFilter>();\r
-    \r
-    /**\r
-     * Is this channel persistent, default value is true\r
-     */\r
-    protected boolean persistent = true; \r
-    \r
-    /**\r
-     * Creates a new channel\r
-     * @param id String - the id of the channel, can not be null\r
-     */\r
-    protected ChannelImpl(String id) {\r
-        assert id != null;\r
-        this.id = id;\r
-    }\r
-\r
-    /**\r
-     * returns the id of this channel\r
-     * @return String\r
-     */\r
-    public String getId() {\r
-        return id;\r
-    }\r
-    \r
-    /**\r
-     * Returns true if this channel matches the pattern to its id.\r
-     * The channel pattern can be a complete name like <code>/service/mychannel</code>\r
-     * or it can be a wild card pattern like <code>/service/app2/**</code>\r
-     * @param pattern String according to the Bayeux specification section 2.2.1 Channel Globbing, can not be null.\r
-     * @return boolean true if the id of this channel matches the pattern\r
-     */\r
-    public boolean matches(String pattern) {\r
-        if (pattern == null)\r
-            throw new NullPointerException("Channel pattern must not be null.");\r
-        if (getId().equals(pattern))\r
-            return true;\r
-        int wildcardPos = pattern.indexOf("/*");\r
-        if (wildcardPos == -1)\r
-            return false;\r
-        boolean multiSegment = pattern.indexOf("**") != -1;\r
-        String leadSubstring = pattern.substring(0, wildcardPos);\r
-        if (leadSubstring == null)\r
-            return false;\r
-        if (multiSegment) \r
-            return getId().startsWith(leadSubstring);\r
-        else {\r
-            if (getId().length() <= wildcardPos + 2)\r
-                return false;\r
-            return !(getId().substring(wildcardPos + 2).contains("/"));\r
-        }\r
-    }\r
-\r
-\r
-\r
-    /**\r
-     * @return returns a non modifiable list of the subscribers for this channel.\r
-     */\r
-    public List<Client> getSubscribers() {\r
-        return Collections.unmodifiableList(subscribers);\r
-    }\r
-\r
-    /**\r
-     * @return true if the Channel will persist without any subscription.\r
-     */\r
-    public boolean isPersistent() {\r
-        return persistent;\r
-    }\r
-    \r
-    public void publish(Message msg) {\r
-        publish(new Message[] {msg});\r
-    }\r
-\r
-    public void publish(Message[] msgs) {\r
-        if (msgs==null) return;\r
-        MessageImpl[] imsgs = new MessageImpl[msgs.length];\r
-        for (int i=0; msgs!=null && i<msgs.length; i++) {\r
-            Message data = msgs[i];\r
-\r
-            if (!(data instanceof MessageImpl)) \r
-                throw new IllegalArgumentException("Invalid message class, you can only publish messages "+\r
-                                                   "created through the Bayeux.newMessage() method");\r
-            if (log.isDebugEnabled()) {\r
-                log.debug("Publishing message:"+data+" to channel:"+this);\r
-            }\r
-            //clone it so that we can set this channel as a reference\r
-            MessageImpl msg = (MessageImpl)((MessageImpl)data).clone();\r
-            //this is the channel it was delivered through\r
-            msg.setChannel(this);\r
-            //pass through filters\r
-            for (Iterator<DataFilter> it = filters.iterator(); it.hasNext(); ) {\r
-                it.next().filter(msg);\r
-            }\r
-            imsgs[i] = msg;\r
-        }\r
-        //deliver it to the clients\r
-        for (Iterator<Client> it = subscribers.iterator(); it.hasNext(); ) {\r
-            ClientImpl c = (ClientImpl)it.next();\r
-            c.deliverInternal(this,imsgs);\r
-        }\r
-        \r
-    }\r
-\r
-    public void setPersistent(boolean persistent) {\r
-        this.persistent = persistent;\r
-    }\r
-\r
-    public void subscribe(Client subscriber) {\r
-        if (!subscribers.contains((subscriber))) { \r
-            subscribers.addLast(subscriber);\r
-            ((ClientImpl)subscriber).subscribed(this);\r
-        }\r
-    }\r
-\r
-    public Client unsubscribe(Client subscriber) {\r
-        if (subscribers.remove(subscriber)) {\r
-            ((ClientImpl)subscriber).unsubscribed(this);\r
-            return subscriber;\r
-        } else\r
-            return null;\r
-    }\r
-    \r
-    public void addFilter(DataFilter filter) {\r
-        if (!filters.contains(filter)) \r
-            filters.addLast(filter);\r
-    }\r
-\r
-    public DataFilter removeFilter(DataFilter filter) {\r
-        if ( filters.remove(filter) ) return filter;\r
-        else return null;\r
-    }\r
-    \r
-    public String toString() {\r
-        StringBuffer buf = new StringBuffer(super.toString());\r
-        buf.append("; channelId=").append(getId());\r
-        return buf.toString();\r
-    }\r
-\r
-}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/bayeux/ClientImpl.java b/java/org/apache/tomcat/bayeux/ClientImpl.java
deleted file mode 100644 (file)
index 894f9ef..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux;\r
-\r
-import java.util.LinkedList;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Queue;\r
-import java.util.concurrent.ConcurrentLinkedQueue;\r
-\r
-import org.apache.catalina.CometEvent;\r
-import org.json.JSONObject;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-import org.apache.cometd.bayeux.Client;\r
-import org.apache.cometd.bayeux.Listener;\r
-import org.apache.cometd.bayeux.Message;\r
-import org.apache.juli.logging.Log;\r
-import org.apache.juli.logging.LogFactory;\r
-import java.util.concurrent.atomic.AtomicInteger;\r
-import java.util.HashMap;\r
-import java.util.ArrayList;\r
-\r
-public class ClientImpl implements Client {\r
-    \r
-    public static final int SUPPORT_CALLBACK_POLL = 0x1;\r
-    public static final int SUPPORT_LONG_POLL = 0x2; \r
-\r
-    public static final String COMET_EVENT_ATTR = "org.apache.cometd.bayeux.client";\r
-    \r
-    protected static Log log = LogFactory.getLog(ClientImpl.class);\r
-\r
-    protected static LinkedList<Message> EMPTY_LIST = new LinkedList<Message>();\r
-    /**\r
-     * queued message for remote clients.\r
-     */\r
-    protected LinkedList<Message> messages = null;\r
-    \r
-    /**\r
-     * \r
-     */\r
-    protected Queue<CometEvent> events = new LinkedList<CometEvent>();\r
-    \r
-    /**\r
-     * Unique id representing this client\r
-     */\r
-    protected String id;\r
-    \r
-    /**\r
-     * supported connection types, defaults to long-polling\r
-     */\r
-    protected int supportedConnTypes = SUPPORT_LONG_POLL | SUPPORT_CALLBACK_POLL;\r
-    \r
-    /**\r
-     * The desired connection type\r
-     */\r
-    protected int desirectConnType = SUPPORT_LONG_POLL;\r
-    \r
-    /**\r
-     * Does this client use json-comment-filtered messages\r
-     */\r
-    protected boolean useJsonFiltered = false;\r
-    \r
-    /**\r
-     * Same JVM clients, get local=true\r
-     */\r
-    protected boolean local;\r
-    \r
-    /**\r
-     * The callback object for local clients\r
-     */\r
-    protected Listener listener;\r
-    \r
-    protected AtomicInteger nrofsubscriptions = new AtomicInteger(0);\r
-    \r
-    protected ClientImpl(String id, boolean local) {\r
-        this.id = id;\r
-        this.local = local;\r
-        if (!local) messages = new LinkedList<Message>();\r
-    }\r
-    \r
-    protected ClientImpl(String id, CometEvent event) {\r
-        this(id,false);\r
-        events = new ConcurrentLinkedQueue<CometEvent>();\r
-        addCometEvent(event);\r
-    }\r
-\r
-    public synchronized void deliver(Message message) {\r
-        deliverInternal(null,new MessageImpl[] {(MessageImpl)message});\r
-    }\r
-    \r
-    public synchronized void deliver(Message[] message) {\r
-        deliverInternal(null,message);\r
-    }\r
-\r
-    protected synchronized void deliverInternal(ChannelImpl channel, MessageImpl message) {\r
-        deliverInternal(channel,new MessageImpl[] {message});\r
-    }\r
-\r
-    protected synchronized void deliverInternal(ChannelImpl channel, Message[] msgs) {\r
-        if (isLocal()) {\r
-            //local clients must have a listener\r
-            ArrayList<Message> list = new ArrayList<Message>();\r
-            for (int i=0; msgs!=null && i<msgs.length; i++) {\r
-                //dont deliver to ourselves\r
-                if (this!=msgs[i].getClient()) list.add(msgs[i]);\r
-            }\r
-            if (getListener() != null && list.size()>0) {\r
-                getListener().deliver(list.toArray(new Message[0]));\r
-            }\r
-        } else {\r
-            for (int i=0; msgs!=null && i<msgs.length; i++) {\r
-                MessageImpl message = (MessageImpl)msgs[i];\r
-                if (this==message.getClient()) { \r
-                    //dont deliver to ourself\r
-                    continue;\r
-                }\r
-                //we are not implementing forever responses, if the client is connected\r
-                //then we will fire off the message\r
-                //first we check to see if we have any existing connections we can piggy back on\r
-                CometEvent event = events.poll();\r
-                boolean delivered = false;\r
-                //TODO TODO - check on thread safety, for writing and for getting last request.\r
-                if (event!=null) {\r
-                    synchronized (event) {\r
-                        RequestBase rq = (RequestBase)event.getHttpServletRequest().getAttribute(RequestBase.LAST_REQ_ATTR);\r
-                        if (rq!=null) {\r
-                            Map map = new HashMap();\r
-                            try {\r
-                                map.put(Bayeux.CHANNEL_FIELD,message.getChannel().getId());\r
-                                map.put(Bayeux.DATA_FIELD,message);\r
-                                JSONObject json = new JSONObject(map);\r
-                                if (log.isDebugEnabled()) {\r
-                                    log.debug("Message instantly delivered to remote client["+this+"] message:"+json);\r
-                                }\r
-                                rq.addToDeliveryQueue(this, json);\r
-                                //deliver the batch\r
-                                if (i==(msgs.length-1)) {\r
-                                    rq.deliver(event, this);\r
-                                    event.close(); //todo, figure out a better way, this means only one message gets delivered\r
-                                    removeCometEvent(event); //and delivered instantly\r
-                                }\r
-                                delivered = true;\r
-                            } catch (Exception x) {\r
-                                log.error(x);\r
-                            }\r
-                        }\r
-                    }\r
-                } \r
-                if (!delivered) {\r
-                    if (log.isDebugEnabled()) {\r
-                        log.debug("Message added to queue for remote client["+this+"] message:"+message);\r
-                    }\r
-                    //queue the message for the next round\r
-                    messages.add(message);\r
-                }\r
-            }\r
-        }\r
-    }\r
-\r
-    public String getId() {\r
-        return this.id;\r
-    }\r
-\r
-    protected Listener getListener() {\r
-        return listener;\r
-    }\r
-\r
-    public boolean hasMessages() {\r
-        if (isLocal()) return false;\r
-        else {\r
-            return messages.size() > 0;\r
-        }\r
-    }\r
-\r
-    public boolean isLocal() {\r
-        return local;\r
-    }\r
-\r
-    public int getSupportedConnTypes() {\r
-        return supportedConnTypes;\r
-    }\r
-\r
-    public int getDesirectConnType() {\r
-        return desirectConnType;\r
-    }\r
-\r
-    public boolean useJsonFiltered() {\r
-        return useJsonFiltered;\r
-    }\r
-\r
-    public void setListener(Listener listener) {\r
-        this.listener = listener;\r
-    }\r
-\r
-    public void setSupportedConnTypes(int supportedConnTypes) {\r
-        this.supportedConnTypes = supportedConnTypes;\r
-    }\r
-\r
-    public void setUseJsonFiltered(boolean useJsonFiltered) {\r
-        this.useJsonFiltered = useJsonFiltered;\r
-    }\r
-\r
-    public void setDesirectConnType(int desirectConnType) {\r
-        this.desirectConnType = desirectConnType;\r
-    }\r
-\r
-    public boolean supportsCallbackPoll() {\r
-        return (supportedConnTypes & SUPPORT_CALLBACK_POLL) == SUPPORT_CALLBACK_POLL;\r
-    }\r
-\r
-    public boolean supportsLongPoll() {\r
-        return (supportedConnTypes & SUPPORT_LONG_POLL) == SUPPORT_LONG_POLL;\r
-    }\r
-\r
-    public synchronized List<Message> takeMessages() {\r
-        if (isLocal()) return null;\r
-        if (messages.size()==0) return EMPTY_LIST;\r
-        List result = new LinkedList(messages);\r
-        messages.clear();\r
-        return result;\r
-    }\r
-    \r
-    public String toString() {\r
-        StringBuffer buf = new StringBuffer(super.toString());\r
-        buf.append(" id=").append(getId());\r
-        return buf.toString();\r
-    }\r
-    \r
-    public boolean isSubscribed() {\r
-        return nrofsubscriptions.get()>0;\r
-    }\r
-    \r
-    protected synchronized boolean addCometEvent(CometEvent event) {\r
-        boolean result = false;\r
-        if (!events.contains(event)) {\r
-            events.add(event);\r
-            result = true;\r
-        }\r
-        event.getHttpServletRequest().setAttribute(COMET_EVENT_ATTR,this);\r
-        return result;\r
-    }\r
-    \r
-    protected synchronized boolean removeCometEvent(CometEvent event) {\r
-        boolean result = events.remove(event);\r
-        event.getHttpServletRequest().removeAttribute(COMET_EVENT_ATTR);\r
-        return result;\r
-    }\r
-    \r
-    \r
-    protected void subscribed(ChannelImpl ch) {\r
-        nrofsubscriptions.addAndGet(1);\r
-    }\r
-    \r
-    protected void unsubscribed(ChannelImpl ch) {\r
-        nrofsubscriptions.addAndGet(-1);\r
-    }\r
-    \r
-    public void startBatch(){\r
-        //noop until improved\r
-    }\r
-    public void endBatch() {\r
-        //noop until improved\r
-    }\r
-        \r
-}\r
diff --git a/java/org/apache/tomcat/bayeux/HttpError.java b/java/org/apache/tomcat/bayeux/HttpError.java
deleted file mode 100644 (file)
index 55ff2c7..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.apache.tomcat.bayeux;\r
-\r
-public class HttpError {\r
-    private int code;\r
-    private String status;\r
-    private Throwable cause;\r
-    public HttpError(int code, String status, Throwable cause) {\r
-        this.code = code;\r
-        this.status = status;\r
-        this.cause = cause;\r
-    }\r
-\r
-    public void setCode(int code) {\r
-        this.code = code;\r
-    }\r
-\r
-    public void setStatus(String status) {\r
-        this.status = status;\r
-    }\r
-\r
-    public void setCause(Throwable exception) {\r
-        this.cause = exception;\r
-    }\r
-\r
-    public int getCode() {\r
-        return code;\r
-    }\r
-\r
-    public String getStatus() {\r
-        return status;\r
-    }\r
-\r
-    public Throwable getCause() {\r
-        return cause;\r
-    }\r
-\r
-    public String toString() {\r
-        if (cause != null)\r
-            return code + ":" + status + " - [" + cause + "]";\r
-        else\r
-            return code + ":" + status;\r
-    }\r
-}\r
diff --git a/java/org/apache/tomcat/bayeux/MessageImpl.java b/java/org/apache/tomcat/bayeux/MessageImpl.java
deleted file mode 100644 (file)
index 53d5342..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux;\r
-\r
-import java.util.HashMap;\r
-\r
-import org.apache.cometd.bayeux.Channel;\r
-import org.apache.cometd.bayeux.Client;\r
-import org.apache.cometd.bayeux.Message;\r
-\r
-public class MessageImpl extends HashMap<String,Object> implements Message {\r
-    \r
-    protected Channel channel;\r
-    protected Client client;\r
-    protected String id;\r
-    private long TTL = 1000*60*5; //5min is the default TTL for a message\r
-    protected long creationTime = System.currentTimeMillis();\r
-\r
-    public Object clone() {\r
-        MessageImpl copy = new MessageImpl(id);\r
-        copy.putAll(this);\r
-        copy.channel = channel;\r
-        copy.client = client;\r
-        copy.id = id;\r
-        copy.creationTime = creationTime;\r
-        copy.TTL = TTL;\r
-        return copy;\r
-    }\r
-\r
-    protected MessageImpl(String id) {\r
-        assert id != null;\r
-        this.id = id;\r
-    }\r
-\r
-    public Channel getChannel() {\r
-        return channel;\r
-    }\r
-\r
-    public Client getClient() {\r
-        return client;\r
-    }\r
-\r
-    public long getCreationTime() {\r
-        return creationTime;\r
-    }\r
-\r
-    public long getTTL() {\r
-        return TTL;\r
-    }\r
-\r
-    public String getId() {\r
-        return id;\r
-    }\r
-\r
-    protected void setChannel(Channel channel) {\r
-        this.channel = channel;\r
-    }\r
-\r
-    protected void setClient(Client client) {\r
-        this.client = client;\r
-    }\r
-\r
-    public void setTTL(long TTL) {\r
-        this.TTL = TTL;\r
-    }\r
-}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/bayeux/RequestBase.java b/java/org/apache/tomcat/bayeux/RequestBase.java
deleted file mode 100644 (file)
index e3c4000..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- *\r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux;\r
-\r
-import java.io.IOException;\r
-import java.io.PrintWriter;\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.LinkedHashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.TimeZone;\r
-import java.util.Date;\r
-import java.text.SimpleDateFormat;\r
-import javax.servlet.ServletException;\r
-\r
-import org.apache.catalina.CometEvent;\r
-import org.apache.tomcat.bayeux.HttpError;\r
-\r
-import org.apache.juli.logging.Log;\r
-import org.apache.juli.logging.LogFactory;\r
-import org.json.JSONArray;\r
-import org.json.JSONException;\r
-import org.json.JSONObject;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-import org.apache.cometd.bayeux.Message;\r
-\r
-/**\r
- * Common functionality and member variables for all Bayeux requests.\r
- *\r
- * @author Guy A. Molinari\r
- * @author Filip Hanik\r
- * @version 0.9\r
- *\r
- */\r
-public abstract class RequestBase implements BayeuxRequest {\r
-    \r
-    protected static final SimpleDateFormat timestampFmt =\r
-        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");\r
-    static {\r
-        timestampFmt.setTimeZone(TimeZone.getTimeZone("GMT"));\r
-    }\r
-    //message properties, combined for all messages\r
-    protected TomcatBayeux tomcatBayeux;\r
-    protected String channel;\r
-    protected String id;\r
-    protected String clientId;\r
-    protected String version = null;\r
-    protected String[] suppConnTypes = null;\r
-    protected int suppConnTypesFlag = 0;\r
-    protected int desiredConnTypeFlag = 0;\r
-    protected String minVersion = null;\r
-    protected String subscription = null;\r
-    protected String data = null;\r
-    protected String conType = null;\r
-    protected LinkedHashMap<String, Object> ext = new LinkedHashMap<String, Object> ();\r
-\r
-    \r
-    protected CometEvent event;\r
-    \r
-    protected HashMap<String, Object> response = null;\r
-    \r
-    protected static Log log = LogFactory.getLog(RequestBase.class);\r
-    \r
-    protected int reconnectInterval = 1000;\r
-    \r
-    protected RequestBase(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
-        this.tomcatBayeux = tb;\r
-        this.event = event;\r
-        channel = jsReq.optString(Bayeux.CHANNEL_FIELD);\r
-        id = jsReq.optString(Bayeux.ID_FIELD);\r
-        clientId = jsReq.optString(Bayeux.CLIENT_FIELD);\r
-        version = jsReq.optString(Bayeux.VERSION_FIELD);\r
-        minVersion = jsReq.optString(Bayeux.MIN_VERSION_FIELD);\r
-        conType = jsReq.optString(Bayeux.CONNECTION_TYPE_FIELD);\r
-        subscription = jsReq.optString(Bayeux.SUBSCRIPTION_FIELD);\r
-        data = jsReq.optString(Bayeux.DATA_FIELD);\r
-        reconnectInterval = tb.getReconnectInterval();\r
-        if (jsReq.has(Bayeux.EXT_FIELD)) {\r
-            JSONObject jext = jsReq.getJSONObject(Bayeux.EXT_FIELD);\r
-            for (Iterator<String> i = jext.keys(); i.hasNext(); ) {\r
-                String key = i.next();\r
-                ext.put(key, jext.get(key));\r
-            }//for\r
-        }//end if\r
-        \r
-        if (jsReq.has(Bayeux.SUPP_CONNECTION_TYPE_FIELD)) {\r
-            JSONArray types = jsReq.getJSONArray(Bayeux.SUPP_CONNECTION_TYPE_FIELD);\r
-            suppConnTypes = new String[types.length()];\r
-            for (int i = 0; i < types.length(); i++) {\r
-                suppConnTypes[i] = types.getString(i);\r
-                if (Bayeux.TRANSPORT_CALLBACK_POLL.equals(suppConnTypes[i]))\r
-                    suppConnTypesFlag = suppConnTypesFlag|ClientImpl.SUPPORT_CALLBACK_POLL;\r
-                else if (Bayeux.TRANSPORT_LONG_POLL.equals(suppConnTypes[i]))\r
-                    suppConnTypesFlag = suppConnTypesFlag|ClientImpl.SUPPORT_LONG_POLL;\r
-            }//for\r
-        }//end if\r
-\r
-        if (conType!=null) {\r
-            if (Bayeux.TRANSPORT_CALLBACK_POLL.equals(conType))\r
-                desiredConnTypeFlag = ClientImpl.SUPPORT_CALLBACK_POLL;\r
-            else if (Bayeux.TRANSPORT_LONG_POLL.equals(conType))\r
-                desiredConnTypeFlag = ClientImpl.SUPPORT_LONG_POLL;\r
-        }//end if\r
-        \r
-        //due to the fact that the javascript doesn't send up a required field\r
-        //we have to fake it\r
-        suppConnTypesFlag = ClientImpl.SUPPORT_CALLBACK_POLL | ClientImpl.SUPPORT_LONG_POLL;\r
-\r
-    }\r
-\r
-    public HttpError validate() {\r
-        HttpError result = null;\r
-//        if (clientId == null) {\r
-//            result = new HttpError(401,"No Client ID.", null);\r
-//        }\r
-        return result;\r
-    }\r
-\r
-    public TomcatBayeux getTomcatBayeux() {\r
-        return tomcatBayeux;\r
-    }\r
-\r
-    public String getChannel() {\r
-        return channel;\r
-    }\r
-\r
-    public String getId() {\r
-        return id;\r
-    }\r
-\r
-    public String getClientId() {\r
-        return clientId;\r
-    }\r
-\r
-    public LinkedHashMap getExt() {\r
-        return ext;\r
-    }\r
-\r
-    public CometEvent getEvent() {\r
-        return event;\r
-    }\r
-    \r
-    protected static void deliver(CometEvent event, ClientImpl to) throws IOException, ServletException, BayeuxException {\r
-        JSONArray jarray = getJSONArray(event,true);\r
-        if ( jarray == null ) throw new BayeuxException("No message to send!");\r
-        String jsonstring = jarray.toString();\r
-        if (log.isDebugEnabled()) {\r
-            log.debug("["+Thread.currentThread().getName()+"] Delivering message to[" + to + "] message:" + jsonstring);\r
-        }\r
-\r
-        if (to!=null) {\r
-            if (to.useJsonFiltered()) {\r
-                if (!event.getHttpServletResponse().isCommitted()) event.getHttpServletResponse().setContentType("text/json-comment-filtered");\r
-            }else {    \r
-                if (!event.getHttpServletResponse().isCommitted()) event.getHttpServletResponse().setContentType("text/json");\r
-            }\r
-        }\r
-\r
-        PrintWriter out = event.getHttpServletResponse().getWriter();\r
-        if (to==null) {\r
-            //do nothing\r
-        }else if ( (to.getDesirectConnType() == 0 && to.supportsLongPoll()) || to.getDesirectConnType() == ClientImpl.SUPPORT_LONG_POLL) {\r
-            if (to.useJsonFiltered())\r
-                out.print("/*");\r
-        } else if ( (to.getDesirectConnType() == 0 && to.supportsCallbackPoll()) || to.getDesirectConnType() == ClientImpl.SUPPORT_CALLBACK_POLL) {\r
-            String jsonp = event.getHttpServletRequest().getParameter(Bayeux.JSONP_PARAMETER);\r
-            if (jsonp == null)\r
-                jsonp = Bayeux.JSONP_DEFAULT_NAME;\r
-            out.print(jsonp);\r
-            out.print('(');\r
-        } else {\r
-            throw new BayeuxException("Client doesn't support any appropriate connection type.");\r
-        }\r
-        out.print(jsonstring);\r
-        if ( to == null ) {\r
-            //do nothing\r
-        } else if ( (to.getDesirectConnType() == 0 && to.supportsLongPoll()) || to.getDesirectConnType() == ClientImpl.SUPPORT_LONG_POLL) {\r
-            if (to.useJsonFiltered())\r
-                out.print("*/");\r
-        } else if ( (to.getDesirectConnType() == 0 && to.supportsCallbackPoll()) || to.getDesirectConnType() == ClientImpl.SUPPORT_CALLBACK_POLL) {\r
-            out.print(");");\r
-        } \r
-        out.flush();\r
-        event.getHttpServletResponse().flushBuffer();\r
-\r
-        \r
-    }\r
-\r
-    protected static JSONArray getJSONArray(CometEvent event, boolean nullok) {\r
-        synchronized(event) {\r
-            JSONArray jarray = (JSONArray) event.getHttpServletRequest().getAttribute(JSON_MSG_ARRAY);\r
-            if (jarray == null && (!nullok)) {\r
-                jarray = new JSONArray();\r
-                event.getHttpServletRequest().setAttribute(JSON_MSG_ARRAY, jarray);\r
-            }\r
-            return jarray;\r
-        }\r
-    }\r
-\r
-    protected JSONArray getJSONArray() {\r
-        return getJSONArray(event,false);\r
-    }\r
-\r
-    protected void addToDeliveryQueue(ClientImpl to, JSONObject msg) throws IOException, ServletException, BayeuxException {\r
-        synchronized (event) {\r
-            getJSONArray().put(msg);\r
-        }\r
-    }\r
-    \r
-    protected void flushMessages(ClientImpl client) throws BayeuxException {\r
-        List<Message> msgs = client.takeMessages();\r
-        synchronized (event) {\r
-            try {\r
-                for (Iterator<Message> it = msgs.iterator(); it.hasNext(); ){\r
-                    MessageImpl msg = (MessageImpl)it.next();\r
-                    Map map = new HashMap();\r
-                    map.put(Bayeux.CHANNEL_FIELD,msg.getChannel().getId());\r
-                    if (msg.getClient()!=null) map.put(Bayeux.CLIENT_FIELD,msg.getClient().getId());\r
-                    map.put(Bayeux.DATA_FIELD,msg);\r
-                    JSONObject obj = new JSONObject(map);\r
-                    addToDeliveryQueue(client, obj);\r
-                }\r
-            } catch (ServletException x) {\r
-                throw new BayeuxException(x);\r
-            } catch (IOException x) {\r
-                throw new BayeuxException(x);\r
-            }\r
-        }\r
-    }\r
-    \r
-    public int process(int prevops) throws BayeuxException {\r
-        event.getHttpServletRequest().setAttribute(CURRENT_REQ_ATTR,this);\r
-        return prevops;\r
-    }\r
-    \r
-    public int getReconnectInterval() {\r
-        return reconnectInterval;\r
-    }\r
-\r
-    public String getTimeStamp() {\r
-        return timestampFmt.format(new Date(System.currentTimeMillis()));\r
-    }\r
-\r
-}\r
diff --git a/java/org/apache/tomcat/bayeux/RequestFactory.java b/java/org/apache/tomcat/bayeux/RequestFactory.java
deleted file mode 100644 (file)
index f2765e6..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux;\r
-\r
-import org.json.JSONObject;\r
-import org.apache.tomcat.bayeux.request.MetaHandshakeRequest;\r
-import org.apache.catalina.CometEvent;\r
-import org.json.JSONException;\r
-import org.apache.tomcat.bayeux.request.MetaConnectRequest;\r
-import org.apache.tomcat.bayeux.request.MetaDisconnectRequest;\r
-import org.apache.tomcat.bayeux.request.MetaSubscribeRequest;\r
-import org.apache.tomcat.bayeux.request.MetaUnsubscribeRequest;\r
-import org.apache.tomcat.bayeux.request.PublishRequest;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-\r
-public class RequestFactory {\r
-\r
-    public static BayeuxRequest getRequest(TomcatBayeux tomcatBayeux, CometEvent event, JSONObject msg) throws JSONException {\r
-        String channel = msg.optString(Bayeux.CHANNEL_FIELD);\r
-        if (Bayeux.META_HANDSHAKE.equals(channel)) {\r
-            return new MetaHandshakeRequest(tomcatBayeux,event,msg);\r
-        }else if (Bayeux.META_CONNECT.equals(channel)) {\r
-            return new MetaConnectRequest(tomcatBayeux,event,msg);\r
-        }else if (Bayeux.META_DISCONNECT.equals(channel)) {\r
-            return new MetaDisconnectRequest(tomcatBayeux,event,msg);\r
-        }else if (Bayeux.META_SUBSCRIBE.equals(channel)) {\r
-            return new MetaSubscribeRequest(tomcatBayeux,event,msg);\r
-        }else if (Bayeux.META_UNSUBSCRIBE.equals(channel)) {\r
-            return new MetaUnsubscribeRequest(tomcatBayeux,event,msg);\r
-        } else {\r
-            return new PublishRequest(tomcatBayeux,event,msg);\r
-        }\r
-    }\r
-}
\ No newline at end of file
diff --git a/java/org/apache/tomcat/bayeux/TomcatBayeux.java b/java/org/apache/tomcat/bayeux/TomcatBayeux.java
deleted file mode 100644 (file)
index efe2264..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux;\r
-\r
-import java.util.HashMap;\r
-import java.util.LinkedHashMap;\r
-import java.util.List;\r
-\r
-import org.apache.catalina.CometEvent;\r
-import org.apache.catalina.tribes.util.Arrays;\r
-import org.apache.catalina.tribes.util.UUIDGenerator;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-import org.apache.cometd.bayeux.Channel;\r
-import org.apache.cometd.bayeux.Client;\r
-import org.apache.cometd.bayeux.Listener;\r
-import org.apache.cometd.bayeux.Message;\r
-import org.apache.cometd.bayeux.SecurityPolicy;\r
-/**\r
- * \r
- * @author Filip Hanik\r
- * @version 1.0\r
- */\r
-public class TomcatBayeux implements Bayeux {\r
-    \r
-\r
-    protected int reconnectInterval = 5000;\r
-    /**\r
-     * a list of all active clients\r
-     */\r
-    protected HashMap<String,Client> clients = new HashMap<String,Client>();\r
-    \r
-    /**\r
-     * a list of all active channels\r
-     */\r
-    protected LinkedHashMap<String, Channel> channels = new LinkedHashMap<String,Channel>();\r
-    \r
-    /**\r
-     * security policy to be used.\r
-     */\r
-    protected SecurityPolicy securityPolicy = null;\r
-    /**\r
-     * default client to use when we need to send an error message but don't have a client valid reference\r
-     */\r
-    protected static ClientImpl errorClient = new ClientImpl("error-no-client",false);\r
-    \r
-    /**\r
-     * returns the default error client\r
-     * @return ClientImpl\r
-     */\r
-    public static ClientImpl getErrorClient() {\r
-        return errorClient;\r
-    }\r
-    \r
-    protected TomcatBayeux() {\r
-    }\r
-    \r
-    /**\r
-     * should be invoked when the servlet is destroyed or when the context shuts down\r
-     */\r
-    public void destroy() {\r
-        throw new UnsupportedOperationException("TomcatBayeux.destroy() not yet implemented");\r
-    }\r
-\r
-    public Channel getChannel(String channelId, boolean create) {\r
-        Channel result = channels.get(channelId);\r
-        if (result==null && create) {\r
-            result = new ChannelImpl(channelId);\r
-            channels.put(channelId,result);\r
-        }\r
-        return result;\r
-    }\r
-    \r
-    public Channel remove(Channel channel) {\r
-        return channels.remove(channel.getId());\r
-    }\r
-    \r
-    public Client remove(Client client) {\r
-        if (client==null) return null;\r
-        for (Channel ch : getChannels()) {\r
-            ch.unsubscribe(client);\r
-        }\r
-        return clients.remove(client.getId());\r
-    }\r
-\r
-    public Client getClient(String clientId) {\r
-        return clients.get(clientId);\r
-    }\r
-    \r
-    public boolean hasClient(String clientId) {\r
-        return clients.containsKey(clientId);\r
-    }\r
-    \r
-    public List<Client> getClients() {\r
-        return java.util.Arrays.asList(clients.entrySet().toArray(new Client[0]));\r
-    }\r
-\r
-    public SecurityPolicy getSecurityPolicy() {\r
-        return securityPolicy;\r
-    }\r
-\r
-    public int getReconnectInterval() { \r
-        return reconnectInterval;\r
-    }\r
-\r
-    public boolean hasChannel(String channel) {\r
-        return channels.containsKey(channel);\r
-    }\r
-\r
-    public Client newClient(String idprefix, Listener listener, boolean local, CometEvent event) {\r
-        String id = createUUID(idprefix);\r
-        ClientImpl client = new ClientImpl(id, local);\r
-        client.setListener(listener);\r
-        clients.put(id, client);\r
-        return client;\r
-    }\r
-\r
-    public Client newClient(String idprefix, Listener listener) {\r
-        assert listener!=null;\r
-        //if this method gets called, someone is using the API inside\r
-        //the JVM, this is a local client\r
-        return newClient(idprefix,listener,true, null);\r
-    }\r
-    \r
-    protected ClientImpl getClientImpl(CometEvent event) {\r
-        return (ClientImpl)event.getHttpServletRequest().getAttribute(ClientImpl.COMET_EVENT_ATTR);\r
-    }\r
-    \r
-    protected void remove(CometEvent event) {\r
-        ClientImpl client = getClientImpl(event);\r
-        if (client!=null) {\r
-            client.removeCometEvent(event);\r
-        }\r
-    }\r
-\r
-    public String createUUID(String idprefix) {\r
-        if (idprefix==null) idprefix="";\r
-        return idprefix + Arrays.toString(UUIDGenerator.randomUUID(false));\r
-    }\r
-    \r
-    public List<Channel> getChannels() {\r
-        return java.util.Arrays.asList(channels.entrySet().toArray(new Channel[0]));\r
-    }\r
-\r
-    protected Message newMessage() {\r
-        String id = createUUID("msg-");\r
-        return new MessageImpl(id);\r
-    }\r
-\r
-    public Message newMessage(Client from) {\r
-        MessageImpl msg = (MessageImpl)newMessage();\r
-        msg.setClient(from);\r
-        return msg;\r
-    }\r
-    public void setSecurityPolicy(SecurityPolicy securityPolicy) {\r
-        this.securityPolicy = securityPolicy;\r
-    }\r
-\r
-    public void setReconnectInterval(int reconnectTimeout) {\r
-        this.reconnectInterval = reconnectTimeout;\r
-    }\r
-\r
-}\r
diff --git a/java/org/apache/tomcat/bayeux/request/MetaConnectRequest.java b/java/org/apache/tomcat/bayeux/request/MetaConnectRequest.java
deleted file mode 100644 (file)
index baa4e8f..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux.request;\r
-\r
-import java.io.IOException;\r
-import java.util.HashMap;\r
-import javax.servlet.ServletException;\r
-\r
-import org.apache.catalina.CometEvent;\r
-import org.apache.tomcat.bayeux.HttpError;\r
-import org.apache.tomcat.bayeux.BayeuxException;\r
-import org.apache.tomcat.bayeux.BayeuxRequest;\r
-import org.apache.tomcat.bayeux.ClientImpl;\r
-import org.apache.tomcat.bayeux.TomcatBayeux;\r
-import org.json.JSONException;\r
-import org.json.JSONObject;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-import org.apache.tomcat.bayeux.*;\r
-\r
-/******************************************************************************\r
- * Handshake request Bayeux message.\r
- *\r
- * @author Guy A. Molinari\r
- * @author Filip Hanik\r
- * @version 1.0\r
- *\r
- */\r
-public class MetaConnectRequest extends RequestBase implements BayeuxRequest {\r
-    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
-\r
-    static {\r
-        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_CONNECT);\r
-        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
-        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
-    }\r
-\r
-    public MetaConnectRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
-        super(tb, event, jsReq);\r
-        if (clientId!=null && getTomcatBayeux().hasClient(clientId)) {\r
-            event.getHttpServletRequest().setAttribute("client",getTomcatBayeux().getClient(clientId));\r
-        }\r
-    }\r
-\r
-\r
-    /**\r
-     * Check client request for validity.\r
-     *\r
-     * Per section 4.2.1 of the Bayuex spec a connect request must contain:\r
-     *  1) The "/meta/connect" channel identifier.\r
-     *  2) The clientId returned by the server after handshake.\r
-     *  3) The desired connectionType (must be one of the server's supported\r
-     *     types returned by handshake response.\r
-     *  \r
-     * @return HttpError This method returns null if no errors were found\r
-     */\r
-    public HttpError validate() {\r
-        if(clientId==null|| (!getTomcatBayeux().hasClient(clientId)))\r
-            return new HttpError(400,"Client Id not valid.", null);\r
-        if (! (Bayeux.TRANSPORT_LONG_POLL.equals(conType) || Bayeux.TRANSPORT_CALLBACK_POLL.equals(conType)))\r
-            return new HttpError(400,"Unsupported connection type.",null);\r
-        return null;//no error\r
-    }\r
-\r
-    /**\r
-     * Transition to connected state, flushing pending messages if\r
-     * available.  If there are pending subscriptions and no messages to\r
-     * flush then the connection is held until there is a pending publish\r
-     * event to be delivered to this client (Section 4.2.2 of spec).\r
-     */\r
-    public int process(int prevops) throws BayeuxException {\r
-        super.process(prevops);\r
-        response = (HashMap<String, Object>)responseTemplate.clone();\r
-        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);\r
-        boolean success = false;\r
-        HttpError error = validate();\r
-        if (error == null) {\r
-            client.setDesirectConnType(desiredConnTypeFlag);\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.RETRY_RESPONSE);\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.INTERVAL_FIELD, getReconnectInterval());\r
-            success = true;\r
-        }else {\r
-            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
-            response.put(Bayeux.ERROR_FIELD, error.toString());\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.HANDSHAKE_RESPONSE);\r
-            if (client==null) client = TomcatBayeux.getErrorClient();\r
-        }\r
-        response.put(Bayeux.CLIENT_FIELD, client.getId());\r
-        response.put(Bayeux.TIMESTAMP_FIELD,getTimeStamp());\r
-        try {\r
-            JSONObject obj = new JSONObject(response);\r
-            addToDeliveryQueue(client, obj);\r
-        } catch (ServletException x) {\r
-            throw new BayeuxException(x);\r
-        } catch (IOException x) {\r
-            throw new BayeuxException(x);\r
-        }\r
-        \r
-        //return immediately if there is no subscriptions\r
-        //so that we can process the next message\r
-        int result = client.isSubscribed()?1:0; \r
-\r
-        if (success && client!=null && client.hasMessages()) {\r
-            //send out messages \r
-            flushMessages(client);\r
-            result = 0; //flush out the messages\r
-        }\r
-\r
-        return result;\r
-    }\r
-}\r
-\r
diff --git a/java/org/apache/tomcat/bayeux/request/MetaDisconnectRequest.java b/java/org/apache/tomcat/bayeux/request/MetaDisconnectRequest.java
deleted file mode 100644 (file)
index be840e9..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux.request;\r
-\r
-import java.io.IOException;\r
-import java.util.HashMap;\r
-import javax.servlet.ServletException;\r
-\r
-import org.apache.catalina.CometEvent;\r
-import org.apache.tomcat.bayeux.HttpError;\r
-import org.apache.tomcat.bayeux.BayeuxException;\r
-import org.apache.tomcat.bayeux.BayeuxRequest;\r
-import org.apache.tomcat.bayeux.ClientImpl;\r
-import org.apache.tomcat.bayeux.TomcatBayeux;\r
-import org.json.JSONException;\r
-import org.json.JSONObject;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-import org.apache.tomcat.bayeux.*;\r
-import org.apache.cometd.bayeux.Channel;\r
-\r
-/******************************************************************************\r
- * Handshake request Bayeux message.\r
- *\r
- * @author Guy A. Molinari\r
- * @author Filip Hanik\r
- * @version 1.0\r
- *\r
- */\r
-public class MetaDisconnectRequest extends RequestBase implements BayeuxRequest {\r
-\r
-    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
-\r
-    static {\r
-        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_DISCONNECT);\r
-        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
-        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
-    }\r
-\r
-    public MetaDisconnectRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
-        super(tb, event, jsReq);\r
-    }\r
-\r
-\r
-    /**\r
-     * Check client request for validity.\r
-     *\r
-     * Per section 4.4.1 of the Bayuex spec a connect request must contain:\r
-     *  1) The "/meta/disconnect" channel identifier.\r
-     *  2) The clientId.\r
-     *  \r
-     * @return HttpError This method returns null if no errors were found\r
-     */\r
-    public HttpError validate() {\r
-        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))\r
-            return new HttpError(400,"Client Id not valid.", null);\r
-//        if (! (Bayeux.TRANSPORT_LONG_POLL.equals(conType) || Bayeux.TRANSPORT_CALLBACK_POLL.equals(conType)))\r
-//            return new HttpError(400,"Unsupported connection type.",null);\r
-        return null;//no error\r
-    }\r
-\r
-    /**\r
-     * Disconnect a client session.\r
-     */\r
-    public int process(int prevops) throws BayeuxException {\r
-        super.process(prevops);\r
-        response = (HashMap<String, Object>)responseTemplate.clone();\r
-        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);\r
-        HttpError error = validate();\r
-        if (error == null) {\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "retry");\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("interval", getReconnectInterval());\r
-        }else {\r
-            getTomcatBayeux().remove(client);\r
-            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
-            response.put(Bayeux.ERROR_FIELD, error.toString());\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "none");\r
-            if (client==null) client = TomcatBayeux.getErrorClient();\r
-        }\r
-        response.put(Bayeux.CLIENT_FIELD, client.getId());\r
-        try {\r
-            JSONObject obj = new JSONObject(response);\r
-            addToDeliveryQueue(client, obj);\r
-        } catch (ServletException x) {\r
-            throw new BayeuxException(x);\r
-        } catch (IOException x) {\r
-            throw new BayeuxException(x);\r
-        }\r
-        return 0;\r
-    }\r
-}\r
-\r
diff --git a/java/org/apache/tomcat/bayeux/request/MetaHandshakeRequest.java b/java/org/apache/tomcat/bayeux/request/MetaHandshakeRequest.java
deleted file mode 100644 (file)
index bd38b9e..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux.request;\r
-\r
-import java.io.IOException;\r
-import java.util.HashMap;\r
-import javax.servlet.ServletException;\r
-\r
-import org.apache.catalina.CometEvent;\r
-import org.apache.tomcat.bayeux.HttpError;\r
-import org.apache.tomcat.bayeux.BayeuxException;\r
-import org.apache.tomcat.bayeux.BayeuxRequest;\r
-import org.apache.tomcat.bayeux.ClientImpl;\r
-import org.apache.tomcat.bayeux.TomcatBayeux;\r
-import org.json.JSONException;\r
-import org.json.JSONObject;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-import org.apache.tomcat.bayeux.*;\r
-\r
-/******************************************************************************\r
- * Handshake request Bayeux message.\r
- *\r
- * @author Guy A. Molinari\r
- * @author Filip Hanik\r
- * @version 1.0\r
- *\r
- */\r
-public class MetaHandshakeRequest extends RequestBase implements BayeuxRequest {\r
-\r
-    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
-    \r
-    static {\r
-        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_HANDSHAKE);\r
-        responseTemplate.put(Bayeux.VERSION_FIELD,"1.0");\r
-        responseTemplate.put(Bayeux.SUPP_CONNECTION_TYPE_FIELD,new String[] { Bayeux.TRANSPORT_LONG_POLL, Bayeux.TRANSPORT_CALLBACK_POLL });\r
-        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
-        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
-    }\r
-\r
-    public MetaHandshakeRequest(TomcatBayeux tomcatBayeux, CometEvent event, JSONObject jsReq) throws JSONException {\r
-        super(tomcatBayeux, event, jsReq);\r
-    }\r
-    \r
-\r
-    public String getVersion() { return version; }\r
-    public String getMinimumVersion() { return minVersion; }\r
-\r
-\r
-    /**\r
-     * Check client request for validity.\r
-     *\r
-     * Per section 4.1.1 of the Bayuex spec a handshake request must contain:\r
-     *  1) The "/meta/handshake" channel identifier.\r
-     *  2) The version of the protocol supported by the client\r
-     *  3) The client's supported connection types.\r
-     *  \r
-     * @return HttpError This method returns null if no errors were found\r
-     */\r
-    public HttpError validate() {\r
-        boolean error = (version==null || version.length()==0);\r
-        if (!error) error = suppConnTypesFlag==0;\r
-        if (error) return new HttpError(400,"Invalid handshake request, supportedConnectionType field missing.",null);\r
-        else return null;\r
-    }\r
-\r
-    /**\r
-     * Generate and return a client identifier.  Return a list of\r
-     * supported connection types.  Must be a subset of or identical to\r
-     * the list of types supported by the client.  See section 4.1.2 of\r
-     * the Bayuex specification.\r
-     */\r
-    public int process(int prevops) throws BayeuxException {\r
-        super.process(prevops);\r
-        response = (HashMap<String, Object>)responseTemplate.clone();\r
-        ClientImpl client = null;\r
-        HttpError error = validate();\r
-        if (error == null) {\r
-            client = (ClientImpl) getTomcatBayeux().newClient("http-", null, false,getEvent());\r
-            clientId = client.getId();\r
-            client.setSupportedConnTypes(suppConnTypesFlag);\r
-            client.setUseJsonFiltered(getExt().get(Bayeux.JSON_COMMENT_FILTERED_FIELD) != null);\r
-            response.put(Bayeux.CLIENT_FIELD, client.getId());\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.RETRY_RESPONSE);\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.INTERVAL_FIELD, getReconnectInterval());\r
-        }else {\r
-            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
-            response.put(Bayeux.ERROR_FIELD, error.toString());\r
-            client = TomcatBayeux.getErrorClient();\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.NONE_RESPONSE);\r
-        }\r
-        try {\r
-            JSONObject obj = new JSONObject(response);\r
-            addToDeliveryQueue(client, obj);\r
-        } catch (ServletException x) {\r
-            throw new BayeuxException(x);\r
-        } catch (IOException x) {\r
-            throw new BayeuxException(x);\r
-        }\r
-        return 0;\r
-    }\r
-}\r
-\r
diff --git a/java/org/apache/tomcat/bayeux/request/MetaSubscribeRequest.java b/java/org/apache/tomcat/bayeux/request/MetaSubscribeRequest.java
deleted file mode 100644 (file)
index 31994f3..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux.request;\r
-\r
-import java.io.IOException;\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import javax.servlet.ServletException;\r
-\r
-import org.apache.catalina.CometEvent;\r
-import org.apache.tomcat.bayeux.HttpError;\r
-import org.apache.tomcat.bayeux.BayeuxException;\r
-import org.apache.tomcat.bayeux.BayeuxRequest;\r
-import org.apache.tomcat.bayeux.ChannelImpl;\r
-import org.apache.tomcat.bayeux.ClientImpl;\r
-import org.apache.tomcat.bayeux.TomcatBayeux;\r
-import org.json.JSONException;\r
-import org.json.JSONObject;\r
-import org.apache.cometd.bayeux.Channel;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-import org.apache.tomcat.bayeux.*;\r
-\r
-/******************************************************************************\r
- * Handshake request Bayeux message.\r
- *\r
- * @author Guy A. Molinari\r
- * @author Filip Hanik\r
- * @version 1.0\r
- */\r
-public class MetaSubscribeRequest extends RequestBase implements BayeuxRequest {\r
-\r
-    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
-\r
-    static {\r
-        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_SUBSCRIBE);\r
-        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
-        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
-    }\r
-\r
-    public MetaSubscribeRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
-        super(tb, event, jsReq);\r
-    }\r
-\r
-\r
-    /**\r
-     * Check client request for validity.\r
-     *\r
-     * Per section 4.5.1 of the Bayuex spec a connect request must contain:\r
-     *  1) The "/meta/subscribe" channel identifier.\r
-     *  2) The clientId.\r
-     *  3) The subscription.  This is the name of the channel of interest,\r
-     *     or a pattern.\r
-     *  \r
-     * @return HttpError This method returns null if no errors were found\r
-     */\r
-    public HttpError validate() {\r
-        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))\r
-            return new HttpError(400,"Client Id not valid.", null);\r
-        if (subscription==null||subscription.length()==0)\r
-            return new HttpError(400,"Subscription missing.",null);\r
-        return null;//no error\r
-    }\r
-\r
-    /**\r
-     * Register interest for one or more channels.  Per section 2.2.1 of the\r
-     * Bayeux spec, a pattern may be specified.  Assign client to matching\r
-     * channels and inverse client to channel reference.\r
-     */\r
-    public int process(int prevops) throws BayeuxException {\r
-        super.process(prevops);\r
-        response = (HashMap<String, Object>)this.responseTemplate.clone();\r
-        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);\r
-        HttpError error = validate();\r
-        if (error == null) {\r
-            boolean wildcard = subscription.indexOf('*')!=-1;\r
-            boolean subscribed = false;\r
-            if (wildcard) {\r
-                List<Channel> channels = getTomcatBayeux().getChannels();\r
-                Iterator<Channel> it = channels.iterator();\r
-                while (it.hasNext()) {\r
-                    ChannelImpl ch = (ChannelImpl)it.next();\r
-                    if (ch.matches(subscription)) {\r
-                        ch.subscribe(client);\r
-                        subscribed = true;\r
-                    }\r
-                }\r
-            }else {\r
-                ChannelImpl ch = (ChannelImpl)getTomcatBayeux().getChannel(subscription,true);\r
-                ch.subscribe(client);\r
-                subscribed = true;\r
-            }\r
-            response.put(Bayeux.SUCCESSFUL_FIELD, Boolean.valueOf(subscribed));\r
-            response.put(Bayeux.SUBSCRIPTION_FIELD,subscription);\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "retry");\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("interval", getReconnectInterval());\r
-        }else {\r
-            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
-            response.put(Bayeux.ERROR_FIELD, error.toString());\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "handshake");\r
-            if (client==null) client = TomcatBayeux.getErrorClient();\r
-        }\r
-        response.put(Bayeux.CLIENT_FIELD, client.getId());\r
-        response.put(Bayeux.TIMESTAMP_FIELD,getTimeStamp());\r
-        try {\r
-            JSONObject obj = new JSONObject(response);\r
-            addToDeliveryQueue(client, obj);\r
-        } catch (ServletException x) {\r
-            throw new BayeuxException(x);\r
-        } catch (IOException x) {\r
-            throw new BayeuxException(x);\r
-        }\r
-        return 0;\r
-    }\r
-}\r
-\r
diff --git a/java/org/apache/tomcat/bayeux/request/MetaUnsubscribeRequest.java b/java/org/apache/tomcat/bayeux/request/MetaUnsubscribeRequest.java
deleted file mode 100644 (file)
index 69a57cd..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux.request;\r
-\r
-import java.io.IOException;\r
-import java.util.HashMap;\r
-import java.util.Iterator;\r
-import java.util.List;\r
-import javax.servlet.ServletException;\r
-\r
-import org.apache.catalina.CometEvent;\r
-import org.apache.tomcat.bayeux.HttpError;\r
-import org.apache.tomcat.bayeux.BayeuxException;\r
-import org.apache.tomcat.bayeux.BayeuxRequest;\r
-import org.apache.tomcat.bayeux.ChannelImpl;\r
-import org.apache.tomcat.bayeux.ClientImpl;\r
-import org.apache.tomcat.bayeux.TomcatBayeux;\r
-import org.json.JSONException;\r
-import org.json.JSONObject;\r
-import org.apache.cometd.bayeux.Channel;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-import org.apache.tomcat.bayeux.*;\r
-\r
-/******************************************************************************\r
- * Handshake request Bayeux message.\r
- *\r
- * @author Guy A. Molinari\r
- * @author Filip Hanik\r
- * @version 1.0\r
- *\r
- */\r
-public class MetaUnsubscribeRequest extends RequestBase implements BayeuxRequest {\r
-\r
-    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
-\r
-    static {\r
-        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_UNSUBSCRIBE);\r
-        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
-        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
-    }\r
-\r
-    public MetaUnsubscribeRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
-        super(tb, event, jsReq);\r
-    }\r
-\r
-\r
-    /**\r
-     * Check client request for validity.\r
-     *\r
-     * Per section 4.6.1 of the Bayuex spec a connect request must contain:\r
-     *  1) The "/meta/unsubscribe" channel identifier.\r
-     *  2) The clientId.\r
-     *  3) The subscription.  This is the name of the channel of interest,\r
-     *     or a pattern.\r
-     *  \r
-     * @return HttpError This method returns null if no errors were found\r
-     */\r
-    public HttpError validate() {\r
-        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))\r
-            return new HttpError(400,"Client Id not valid.", null);\r
-        if (subscription==null||subscription.length()==0)\r
-            return new HttpError(400,"Subscription missing.",null);\r
-        return null;//no error\r
-    }\r
-\r
-    /**\r
-     * De-register interest for one or more channels.  Per section 2.2.1 of the\r
-     * Bayeux spec, a pattern may be specified.  Sever relationships.\r
-     */\r
-    public int process(int prevops) throws BayeuxException {\r
-        super.process(prevops);\r
-        response = (HashMap<String, Object>)responseTemplate.clone();\r
-        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);\r
-        HttpError error = validate();\r
-        if (error == null) {\r
-            boolean wildcard = subscription.indexOf('*')!=-1;\r
-            boolean unsubscribed = false;\r
-            if (wildcard) {\r
-                List<Channel> channels = getTomcatBayeux().getChannels();\r
-                Iterator<Channel> it = channels.iterator();\r
-                while (it.hasNext()) {\r
-                    ChannelImpl ch = (ChannelImpl)it.next();\r
-                    if (ch.matches(subscription)) {\r
-                        ch.unsubscribe(client);\r
-                        unsubscribed = true;\r
-                    }\r
-                }\r
-            }else {\r
-                ChannelImpl ch = (ChannelImpl)getTomcatBayeux().getChannel(subscription,true);\r
-                ch.unsubscribe(client);\r
-                unsubscribed = true;\r
-            }\r
-            response.put(Bayeux.SUCCESSFUL_FIELD, Boolean.valueOf(unsubscribed));\r
-            response.put(Bayeux.SUBSCRIPTION_FIELD,subscription);\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "retry");\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("interval", getReconnectInterval());\r
-        }else {\r
-            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
-            response.put(Bayeux.ERROR_FIELD, error.toString());\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "handshake");\r
-            if (client==null) client = TomcatBayeux.getErrorClient();\r
-        }\r
-        response.put(Bayeux.CLIENT_FIELD, client.getId());\r
-        response.put(Bayeux.TIMESTAMP_FIELD,getTimeStamp());\r
-        try {\r
-            JSONObject obj = new JSONObject(response);\r
-            addToDeliveryQueue(client, obj);\r
-        } catch (ServletException x) {\r
-            throw new BayeuxException(x);\r
-        } catch (IOException x) {\r
-            throw new BayeuxException(x);\r
-        }\r
-        return 0;\r
-    }\r
-}\r
-\r
diff --git a/java/org/apache/tomcat/bayeux/request/PublishRequest.java b/java/org/apache/tomcat/bayeux/request/PublishRequest.java
deleted file mode 100644 (file)
index fcf956c..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to You under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- * \r
- *      http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.tomcat.bayeux.request;\r
-\r
-import java.io.IOException;\r
-import java.util.HashMap;\r
-import javax.servlet.ServletException;\r
-\r
-import org.apache.catalina.CometEvent;\r
-import org.apache.tomcat.bayeux.HttpError;\r
-import org.apache.tomcat.bayeux.BayeuxException;\r
-import org.apache.tomcat.bayeux.BayeuxRequest;\r
-import org.apache.tomcat.bayeux.ChannelImpl;\r
-import org.apache.tomcat.bayeux.ClientImpl;\r
-import org.apache.tomcat.bayeux.MessageImpl;\r
-import org.apache.tomcat.bayeux.TomcatBayeux;\r
-import org.json.JSONException;\r
-import org.json.JSONObject;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-import java.util.List;\r
-import org.apache.cometd.bayeux.Message;\r
-import java.util.Iterator;\r
-import org.apache.tomcat.bayeux.*;\r
-\r
-/******************************************************************************\r
- * Handshake request Bayeux message.\r
- *\r
- * @author Guy A. Molinari\r
- * @author Filip Hanik\r
- * @version 1.0\r
- *\r
- */\r
-public class PublishRequest extends RequestBase implements BayeuxRequest {\r
-\r
-    JSONObject msgData = null;\r
-\r
-    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
-\r
-    static {\r
-        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
-        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
-    }\r
-\r
-    public PublishRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
-        super(tb, event, jsReq);\r
-    }\r
-\r
-\r
-    /**\r
-     * Check client request for validity.\r
-     *\r
-     * Per section 5.1.1 of the Bayuex spec a connect request must contain:\r
-     *  1) The channel identifier of the channel for publication.\r
-     *  2) The data to send.\r
-     *  \r
-     * @return HttpError This method returns null if no errors were found\r
-     */\r
-    public HttpError validate() {\r
-        if(channel==null|| (!this.getTomcatBayeux().hasChannel(channel)))\r
-            return new HttpError(400,"Channel Id not valid.", null);\r
-        if(data==null || data.length()==0)\r
-            return new HttpError(400,"Message data missing.", null);\r
-        try {\r
-            this.msgData = new JSONObject(data);\r
-        }catch (JSONException x) {\r
-            return new HttpError(400,"Invalid JSON object in data attribute.",x);\r
-        }\r
-        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))\r
-            return new HttpError(400,"Client Id not valid.", null);\r
-        return null;//no error\r
-    }\r
-\r
-    /**\r
-     *  Send the event message to all registered subscribers.\r
-     */\r
-    public int process(int prevops) throws BayeuxException {\r
-        super.process(prevops);\r
-        response = (HashMap<String, Object>)responseTemplate.clone();\r
-        ClientImpl client = clientId!=null?(ClientImpl)getTomcatBayeux().getClient(clientId):\r
-                                           (ClientImpl)event.getHttpServletRequest().getAttribute("client");\r
-        boolean success = false;\r
-        HttpError error = validate();\r
-        if (error == null) {\r
-            ChannelImpl chimpl = (ChannelImpl)getTomcatBayeux().getChannel(channel,false);\r
-            MessageImpl mimpl = (MessageImpl)getTomcatBayeux().newMessage(client);\r
-            \r
-            try {\r
-                String[] keys = JSONObject.getNames(msgData);\r
-                for (int i = 0; i < keys.length; i++) {\r
-                    mimpl.put(keys[i], msgData.get(keys[i]));\r
-                }\r
-                success = true;\r
-                ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.RETRY_RESPONSE);\r
-                ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.INTERVAL_FIELD, getReconnectInterval());\r
-            }catch (JSONException x) {\r
-                if (log.isErrorEnabled()) log.error("Unable to parse:"+msgData,x);\r
-                throw new BayeuxException(x);\r
-            }\r
-            chimpl.publish(mimpl);\r
-        }\r
-        if(!success) {\r
-            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
-            response.put(Bayeux.ERROR_FIELD, error.toString());\r
-            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.HANDSHAKE_RESPONSE);\r
-            if (client==null) client = TomcatBayeux.getErrorClient();\r
-        }\r
-        response.put(Bayeux.CHANNEL_FIELD,channel);\r
-        response.put(Bayeux.CLIENT_FIELD, client.getId());\r
-        try {\r
-            JSONObject obj = new JSONObject(response);\r
-            addToDeliveryQueue(client, obj);\r
-        } catch (ServletException x) {\r
-            throw new BayeuxException(x);\r
-        } catch (IOException x) {\r
-            throw new BayeuxException(x);\r
-        }\r
-        \r
-        if (success && client!=null && client.hasMessages()) {\r
-            //send out messages \r
-            flushMessages(client);\r
-        }\r
-\r
-        return 0;\r
-    }\r
-}\r
-\r
diff --git a/modules/bayeux/.classpath b/modules/bayeux/.classpath
new file mode 100644 (file)
index 0000000..889b127
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry kind="src" path="java"/>
+       <classpathentry kind="src" path="test"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+       <classpathentry combineaccessrules="false" kind="src" path="/tomcat-trunk"/>
+       <classpathentry kind="var" path="TOMCAT_LIBS_BASE/json-20080701/json.jar"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/modules/bayeux/.project b/modules/bayeux/.project
new file mode 100644 (file)
index 0000000..872599e
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>tomcat-bayeux</name>
+       <comment></comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+       </natures>
+</projectDescription>
diff --git a/modules/bayeux/build.xml b/modules/bayeux/build.xml
new file mode 100644 (file)
index 0000000..2ac3073
--- /dev/null
@@ -0,0 +1,222 @@
+<?xml version="1.0"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+-->
+<project name="Tomcat 6.0" default="bayeux" basedir="../..">
+
+
+  <!-- ===================== Initialize Property Values =================== -->
+
+  <!-- See "build.properties.sample" in the top level directory for all     -->
+  <!-- property values you must customize for successful building!!!        -->
+  <property file="${user.home}/build.properties"/>
+  <property file="${basedir}/build.properties"/>
+  <property file="${basedir}/build.properties.default"/>
+
+  <!-- Project Properties -->
+  <property name="project"               value="apache-tomcat" />
+  <property name="name"                  value="Apache Tomcat" />
+  <property name="year"                  value="2008" />
+  <property name="version.major"         value="6" />
+  <property name="version.minor"         value="0" />
+  <property name="version.build"         value="0" />
+  <property name="version.patch"         value="0" />
+  <property name="version.suffix"        value="-dev" />
+
+  <property name="version"               value="${version.major}.${version.minor}.${version.build}${version.suffix}" />
+  <property name="version.number"        value="${version.major}.${version.minor}.${version.build}.${version.patch}" />
+  <property name="version.major.minor"   value="${version.major}.${version.minor}" />
+
+  <property name="final.name"            value="${project}-${version}" />
+  <property name="final-src.name"        value="${project}-${version}-src" />
+
+  <!-- Build Defaults -->
+  <property name="tomcat.build"      value="${basedir}/output/build"/>
+  <property name="tomcat.classes"    value="${basedir}/output/classes"/>
+  <property name="tomcat.dist"       value="${basedir}/output/dist"/>
+  <property name="tomcat.extras"     value="${basedir}/output/extras"/>
+  <property name="tomcat.deployer"   value="${basedir}/output/deployer"/>
+  <property name="tomcat.release"    value="${basedir}/output/release"/>
+  <property name="test.failonerror"  value="true"/>
+  <property name="test.runner"       value="junit.textui.TestRunner"/>
+
+  <!-- Can't be lower - jsp uses templates -->
+  <property name="compile.source" value="1.5"/>
+
+  <!-- JAR artifacts -->
+  <property name="cometd-api.jar" value="${tomcat.extras}/cometd-api.jar"/>
+  <property name="tomcat-bayeux.jar" value="${tomcat.extras}/tomcat-bayeux.jar"/>
+  <property name="cometd.war" value="${tomcat.extras}/cometd.war"/>
+  <property name="tomcat-bayeux-samples.jar" value="${tomcat.extras}/tomcat-bayeux-samples.jar"/>
+
+       <!-- Classpath -->
+  <path id="tomcat.classpath">
+    <pathelement location="${tomcat.classes}"/>
+  </path>
+
+  <target name="prepare">
+    <mkdir dir="${tomcat.extras}"/>
+  </target>
+
+  <target name="clean">
+       <delete dir="${tomcat.extras}"/>
+  </target>
+
+
+       <target name="bayeux">
+    <mkdir dir="${tomcat.extras}"/>
+
+    <antcall target="downloadgz">
+      <param name="sourcefile" value="${dojo-js.loc}"/>
+      <param name="destfile" value="${dojo-js.jar}"/>
+    </antcall>
+       
+    <copy todir="${tomcat.extras}" file="${json-lib.home}/${json-lib.jar}"/>
+    <!-- Classpath -->
+    <path id="tomcat.bayeux.classpath">
+      <pathelement path="${tomcat.classpath}"/>
+      <pathelement path="${json-lib.home}/${json-lib.jar}"/>
+    </path>
+
+    <!-- compile org.apache.tomcat.bayeux -->
+    <!-- compile org.apache.cometd -->
+    <javac srcdir="java" destdir="${tomcat.classes}"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           optimize="${compile.optimize}">
+      <classpath refid="tomcat.bayeux.classpath" />
+      <include name="org/apache/tomcat/bayeux/**" />
+      <include name="org/apache/cometd/**" />
+    </javac>
+    
+    <!-- Cometd API JAR File -->
+    <jar jarfile="${cometd-api.jar}">
+      <fileset dir="${tomcat.classes}">
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+        <include name="org/apache/cometd/**" />
+      </fileset>
+    </jar>
+    <!-- Cometd API JAR File -->
+    <jar jarfile="${tomcat-bayeux.jar}">
+      <fileset dir="${tomcat.classes}">
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+        <include name="org/apache/tomcat/bayeux/**" />
+      </fileset>
+    </jar>
+
+    <!-- cometd samples application -->
+    <javac srcdir="test" destdir="${tomcat.classes}"
+           debug="${compile.debug}"
+           deprecation="${compile.deprecation}"
+           source="${compile.source}"
+           optimize="${compile.optimize}">
+      <classpath refid="tomcat.bayeux.classpath" />
+      <include name="org/apache/tomcat/bayeux/**" />
+      <include name="org/apache/cometd/**" />
+    </javac>
+    
+    <!-- Cometd samples JAR File -->
+    <jar jarfile="${tomcat-bayeux-samples.jar}">
+      <fileset dir="${tomcat.classes}">
+        <exclude name="**/package.html" />
+        <exclude name="**/LocalStrings_*" />
+        <include name="org/apache/cometd/bayeux/samples/**" />
+      </fileset>
+    </jar>
+    
+    <!-- build samples webapplication /cometd -->
+       <property name="cometd-app" value="${base.path}/cometd"/>
+       <mkdir dir="${cometd-app}"/>
+       
+       <copy todir="${cometd-app}">
+         <fileset dir="${basedir}/webapps/cometd">
+               <include name="**/**"/>
+         </fileset>
+      <fileset dir="${dojo-js.home}">
+       <include name="dojo/**"/>
+       <include name="dojox/**"/>
+      </fileset>       
+       </copy>
+    <mkdir dir="${cometd-app}/WEB-INF/lib"/>
+    <copy todir="${cometd-app}/WEB-INF/lib" file="${tomcat-bayeux-samples.jar}"/>
+       
+    <zip zipfile="${cometd.war}">
+      <fileset dir="${cometd-app}">
+        <include name="**/**"/>
+      </fileset>
+    </zip>
+       
+       <delete dir="${cometd-app}"/>
+       
+       <!-- create checksums -->
+    <checksum file="${cometd-api.jar}" forceOverwrite="yes" fileext=".md5" />
+    <checksum file="${tomcat-bayeux.jar}" forceOverwrite="yes" fileext=".md5" />
+    <checksum file="${cometd.war}" forceOverwrite="yes" fileext=".md5" />
+    <checksum file="${tomcat.extras}/${json-lib.jar}" forceOverwrite="yes" fileext=".md5" />
+       
+       <!-- print out how to --> 
+    <echo>You've built the Tomcat Bayeux libraries, simply add the following libraries to your CATALINA_HOME/lib directory:
+          ${cometd-api.jar}
+          ${tomcat-bayeux.jar} 
+          ${tomcat.extras}/${json-lib.jar}
+To run the sample application, copy the following applications into your CATALINA_BASE/webapps directory
+          ${cometd.war}
+    </echo>
+  </target>
+
+
+
+  <!-- Download and dependency building -->
+  <target name="proxyflags">
+    <!-- check proxy parameters. -->
+    <condition property="useproxy">
+      <equals arg1="${proxy.use}" arg2="on" />
+    </condition>
+  </target>
+
+  <target name="setproxy" depends="proxyflags" if="useproxy">
+    <taskdef name="setproxy"
+            classname="org.apache.tools.ant.taskdefs.optional.net.SetProxy" />
+    <setproxy proxyhost="${proxy.host}" proxyport="${proxy.port}"
+              proxyuser="${proxy.user}" proxypassword="${proxy.password}" />
+    <echo message="Using ${proxy.host}:${proxy.port} to download ${sourcefile}"/>
+  </target>
+
+  <target name="testexist">
+    <echo message="Testing  for ${destfile}"/>
+    <available file="${destfile}" property="exist"/>
+  </target>
+
+  <target name="downloadfile" unless="exist" depends="setproxy,testexist">
+    <!-- Download extract the file -->
+    <mkdir dir="${destdir}" />
+    <get src="${sourcefile}" dest="${destfile}" />
+  </target>
+       
+  <target name="downloadgz" unless="exist" depends="setproxy,testexist">
+    <!-- Download and extract the package -->
+    <get src="${sourcefile}" dest="${base.path}/file.tar.gz" />
+    <gunzip src="${base.path}/file.tar.gz" dest="${base.path}/file.tar"/>
+    <untar src="${base.path}/file.tar" dest="${base.path}"/>
+    <delete file="${base.path}/file.tar"/>
+    <delete file="${base.path}/file.tar.gz"/>
+  </target>
+
+
+</project>
diff --git a/modules/bayeux/java/org/apache/cometd/bayeux/Bayeux.java b/modules/bayeux/java/org/apache/cometd/bayeux/Bayeux.java
new file mode 100644 (file)
index 0000000..5385d32
--- /dev/null
@@ -0,0 +1,242 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.cometd.bayeux;\r
+\r
+import java.util.List;\r
+\r
+/** Bayeux Interface.<br/>\r
+ * This interface represents the server side API for the Bayeux messaging protocol.\r
+ * Bayeux is a simple subscribe/publish/receive methodology, not far from JMS, but much simplified.<br/>\r
+ * It is used both by the actual implementation and by server side clients.<br/>\r
+ * Server side clients use this to create, retrieve and subscribe to channels.\r
+ * Server side clients are represented, just like remote clients, through the Client interface.\r
+ * <br/>\r
+ * The Bayeux implementations is intended to be thread safe and multiple threads may simultaneously call Bayeux methods.\r
+ * <br/>\r
+ * The Bayeux object, is the starting point for any cometd application relying on the Bayeux object.\r
+ * Dependent on the container, the Bayeux object will be stored in the <code>javax.servlet.ServletContext</code> object\r
+ * as an attribute under the name <code>Bayeux.DOJOX_COMETD_BAYEUX</code><br/>\r
+ * To retrieve this object, one would simply call<br/>\r
+ * <code>Bayeux bx = (Bayeux)getServletContext().getAttribute(Bayeux.DOJOX_COMETD_BAYEUX);\r
+ * <br/><br/>\r
+ * The Bayeux protocol is pretty straight forward and includes a bunch of messaging that is not needed to be known to clients,\r
+ * both server side and remote clients.\r
+ * This object gets initialized by a container dependent servlet, and the servlet then handles all Bayeux communication from the client.\r
+ * Remote messsages are delivered to channels, and to server side clients using the <code>Listener</code> interface.<br/>\r
+ * <br/>\r
+ * A <code>Bayeux session</code> is active as long as the webapp hosting the Bayeux object is active.<br/>\r
+ * When the webapplication shuts down, the Bayeux object will unsubscribe all clients and remove all the active channels.\r
+ * \r
+ * @author Greg Wilkins\r
+ * @author Filip Hanik\r
+ */\r
+public interface Bayeux {\r
+    \r
+    /**Meta definitions for channels*/\r
+    public static final String META="/meta";\r
+    /**Meta definitions for channels*/\r
+    public static final String META_SLASH="/meta/";\r
+    /**Meta definitions for channels - connect message*/\r
+    public static final String META_CONNECT="/meta/connect";\r
+    /**Meta definitions for channels - client messsage*/\r
+    public static final String META_CLIENT="/meta/client";\r
+    /**Meta definitions for channels - disconnect messsage*/\r
+    public static final String META_DISCONNECT="/meta/disconnect";\r
+    /**Meta definitions for channels - handshake messsage*/\r
+    public static final String META_HANDSHAKE="/meta/handshake";\r
+    /**Meta definitions for channels - ping messsage*/\r
+    public static final String META_PING="/meta/ping";\r
+    /**Meta definitions for channels - reconnect messsage\r
+     * @deprecated\r
+     */\r
+    public static final String META_RECONNECT="/meta/reconnect";\r
+    /**Meta definitions for channels - status messsage*/\r
+    public static final String META_STATUS="/meta/status";\r
+    /**Meta definitions for channels - subscribe messsage*/\r
+    public static final String META_SUBSCRIBE="/meta/subscribe";\r
+    /**Meta definitions for channels - unsubscribe messsage*/\r
+    public static final String META_UNSUBSCRIBE="/meta/unsubscribe";\r
+    /*Field names inside Bayeux messages*/\r
+    /**Field names inside Bayeux messages - clientId field*/\r
+    public static final String CLIENT_FIELD="clientId";\r
+    /**Field names inside Bayeux messages - data field*/\r
+    public static final String DATA_FIELD="data";\r
+    /**Field names inside Bayeux messages - channel field*/\r
+    public static final String CHANNEL_FIELD="channel";\r
+    /**Field names inside Bayeux messages - id field*/\r
+    public static final String ID_FIELD="id";\r
+    /**Field names inside Bayeux messages - error field*/\r
+    public static final String ERROR_FIELD="error";\r
+    /**Field names inside Bayeux messages - timestamp field*/\r
+    public static final String TIMESTAMP_FIELD="timestamp";\r
+    /**Field names inside Bayeux messages - transport field*/\r
+    public static final String TRANSPORT_FIELD="transport";\r
+    /**Field names inside Bayeux messages - advice field*/\r
+    public static final String ADVICE_FIELD="advice";\r
+    /**Field names inside Bayeux messages - successful field*/\r
+    public static final String SUCCESSFUL_FIELD="successful";\r
+    /**Field names inside Bayeux messages - subscription field*/\r
+    public static final String SUBSCRIPTION_FIELD="subscription";\r
+    /**Field names inside Bayeux messages - ext field*/\r
+    public static final String EXT_FIELD="ext";\r
+    /**Field names inside Bayeux messages - connectionType field*/\r
+    public static final String CONNECTION_TYPE_FIELD="connectionType";\r
+    /**Field names inside Bayeux messages - version field*/\r
+    public static final String VERSION_FIELD="version";\r
+    /**Field names inside Bayeux messages - minimumVersion field*/\r
+    public static final String MIN_VERSION_FIELD="minimumVersion";\r
+    /**Field names inside Bayeux messages - supportedConnectionTypes field*/\r
+    public static final String SUPP_CONNECTION_TYPE_FIELD="supportedConnectionTypes";\r
+    /**Field names inside Bayeux messages - json-comment-filtered field*/\r
+    public static final String JSON_COMMENT_FILTERED_FIELD="json-comment-filtered";\r
+    /**Field names inside Bayeux messages - reconnect field*/\r
+    public static final String RECONNECT_FIELD = "reconnect";\r
+    /**Field names inside Bayeux messages - interval field*/\r
+    public static final String INTERVAL_FIELD = "interval";\r
+    /**Field values inside Bayeux messages - retry response*/\r
+    public static final String RETRY_RESPONSE = "retry";\r
+    /**Field values inside Bayeux messages - handshake response*/\r
+    public static final String HANDSHAKE_RESPONSE = "handshake";\r
+    /**Field values inside Bayeux messages - none response*/\r
+    public static final String NONE_RESPONSE = "none";\r
+    /**Service channel names-starts with*/\r
+    public static final String SERVICE="/service";\r
+    /**Service channel names-trailing slash*/\r
+    public static final String SERVICE_SLASH="/service/";\r
+    /*Transport types*/\r
+    /**Transport types - long polling*/\r
+    public static final String TRANSPORT_LONG_POLL="long-polling";\r
+    /**Transport types - callback polling*/\r
+    public static final String TRANSPORT_CALLBACK_POLL="callback-polling";\r
+    /**Transport types - iframe*/\r
+    public static final String TRANSPORT_IFRAME="iframe";\r
+    /**Transport types - flash*/\r
+    public static final String TRANSPORT_FLASH="flash";\r
+    /** ServletContext attribute name used to obtain the Bayeux object */\r
+    public static final String DOJOX_COMETD_BAYEUX="dojox.cometd.bayeux";\r
+    /*http field names*/\r
+    /**http helpers - text/json content type*/\r
+    public static final String JSON_CONTENT_TYPE="text/json";\r
+    /**http helpers - parameter name for json message*/\r
+    public static final String MESSAGE_PARAMETER="message";\r
+    /**http helpers - name of the jsonp parameter*/\r
+    public static final String JSONP_PARAMETER="jsonp";\r
+    /**http helpers - default name of the jsonp callback function*/\r
+    public static final String JSONP_DEFAULT_NAME="jsonpcallback";\r
+\r
+    /*--Client----------------------------------------------------------- */\r
+    /**\r
+     * Creates a new server side client. This method is to be invoked\r
+     * by server side objects only. You cannot create a remote client by using this method.\r
+     * A client represents an entity that can subscribe to channels and publish and receive messages\r
+     * through these channels\r
+     * @param idprefix String - the prefix string for the id generated, can be null\r
+     * @param listener Listener - a callback object to be called when messages are to be delivered to the new client\r
+     * @return Client - returns an implementation of the client interface.\r
+     */\r
+    public Client newClient(String idprefix, Listener listener);\r
+\r
+    /**\r
+     * retrieve a client based on an ID. Will return null if the client doesn't exist.\r
+     * @param clientid String\r
+     * @return Client-null if the client doesn't exist.returns the client if it does.\r
+     */\r
+    public Client getClient(String clientid);\r
+    \r
+    /**\r
+     * Returns a non modifiable list of all the clients that are currently active\r
+     * in this Bayeux session\r
+     * @return List<Client> - a list containing all clients. The List can not be modified.\r
+     */\r
+    public List<Client> getClients();\r
+    \r
+    /**\r
+     * Returns true if a client with the given id exists.<br/>\r
+     * Same as executing <code>getClient(id)!=null</code>.\r
+     * @param clientId String\r
+     * @return boolean - true if the client exists\r
+     */\r
+    public boolean hasClient(String clientId);\r
+    \r
+    /**\r
+     * Removes the client all together.\r
+     * This will unsubscribe the client to any channels it may be subscribed to\r
+     * and remove it from the list.\r
+     * @param client Client\r
+     * @return Client - returns the client that was removed, or null if no client was removed.\r
+     */\r
+    public Client remove(Client client);\r
+\r
+    \r
+    /*--Channel---------------------------------------------------------- */\r
+    /**\r
+     * Returns the channel for a given channel id.\r
+     * If the channel doesn't exist, and the <code>create</code> parameter is set to true,\r
+     * the channel will be created and added to the list of active channels.<br/>\r
+     * if <code>create</code> is set to false, and the channel doesn't exist, null will be returned.\r
+     * @param channelId String - the id of the channel to be retrieved or created\r
+     * @param create boolean - true if the Bayeux impl should create the channel\r
+     * @return Channel - null if <code>create</code> is set to false and the channel doesn't exist, \r
+     * otherwise it returns a channel object.\r
+     */\r
+    public Channel getChannel(String channelId, boolean create);\r
+    \r
+    /**\r
+     * Returns a list of currently active channels in this Bayeux session.\r
+     * @return List<Channel>\r
+     */\r
+    public List<Channel> getChannels();\r
+\r
+    /**\r
+     * Removes a channel from the Bayeux object.\r
+     * This will also unsubscribe all the clients currently subscribed to the\r
+     * the channel.\r
+     * @param channel Channel - the channel to be removed\r
+     * @return Channel - returns the channel that was removed, or null if no channel was removed.\r
+     */\r
+    public Channel remove(Channel channel);\r
+\r
+    /**\r
+     * returns true if a channel with the given channelId exists.\r
+     * <br/>Same as executing <code>Bayeux.getChannel(channelId,false)!=null</code>\r
+     * @param channelId String\r
+     * @return boolean - true if the channel exists.\r
+     */\r
+    public boolean hasChannel(String channelId);\r
+\r
+    /* --Message---------------------------------------------------------- */\r
+    /**\r
+     * Creates a new message to be sent by a server side client.\r
+     * @return Message - returns a new Message object, that has a unique id.\r
+     */\r
+    public Message newMessage(Client from);\r
+\r
+\r
+    /*--Security policy----------------------------------------------------------- */\r
+    /**\r
+     * Returns the security policy associated with this Bayeux session\r
+     * @return SecurityPolicy\r
+     */\r
+    public SecurityPolicy getSecurityPolicy();\r
+   \r
+    /**\r
+     * Sets the security policy to be used in this Bayeux session\r
+     * @param securityPolicy SecurityPolicy\r
+     */\r
+    public void setSecurityPolicy(SecurityPolicy securityPolicy);\r
+\r
+}
\ No newline at end of file
diff --git a/modules/bayeux/java/org/apache/cometd/bayeux/Channel.java b/modules/bayeux/java/org/apache/cometd/bayeux/Channel.java
new file mode 100644 (file)
index 0000000..34af328
--- /dev/null
@@ -0,0 +1,103 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.cometd.bayeux;\r
+\r
+import java.util.List;\r
+\r
+/** \r
+ * A Bayeux Channel represents a channel used to receive messages from and to publish messages to.\r
+ * In order to publish messages to or receive messages from, one must subscribe to the channel.\r
+ * This is easily done by invoking the <code>subscribe</code> method.\r
+ * A channel is created by calling the <code>Bayeux.getChannel(channelId,true)</code> method.\r
+ * A channel can be created either server side by invoking the getChannel, or client side\r
+ * by using the /meta/subscribe message without a wildcard.\r
+ * @author Greg Wilkins\r
+ * @author Filip Hanik\r
+ */\r
+public interface Channel\r
+{\r
+    /**\r
+     * Returns the id for this channel. The id is unique within bayeux session.\r
+     * @return String - will never be null.\r
+     */\r
+    public String getId();\r
+\r
+    /** \r
+     * Publishes a message to all the subscribers of this channel.\r
+     * The <code>from</code> is contained within the message, by calling\r
+     * <code>msg.getClient()</code>\r
+     * @param data - the message to be published, can not be null.\r
+     */\r
+    public void publish(Message msg);\r
+    \r
+    /** \r
+     * Publishes more than one message to all the subscribers of this channel.\r
+     * The <code>from</code> is contained within the message, by calling\r
+     * <code>msg[x].getClient()</code>\r
+     * @param data - the message to be published, can not be null.\r
+     */\r
+    public void publish(Message[] msgs);\r
+\r
+    /** \r
+     * Non persistent channels are removed when the last subscription is\r
+     * removed. Persistent channels survive periods without any subscribers.\r
+     * @return true if the Channel will persist without any subscription.\r
+     */\r
+    public boolean isPersistent();\r
+    \r
+    /**\r
+     * @param persistent true if the Channel will persist without any subscription.\r
+     * @see isPersistent\r
+     */\r
+    public void setPersistent(boolean persistent);\r
+    \r
+    /** \r
+     * Subscribes a client to a channel.\r
+     * @param subscriber - the client to be subscribed. If the client\r
+     * already is subscribed, this call will not create a duplicate subscription.\r
+     */\r
+    public void subscribe(Client subscriber);\r
+\r
+    /** \r
+     * Unsubscribes a client from a channel\r
+     * @param subscriber - the client to be subscribed.\r
+     * @return - returns the client that was unsubscribed, or null if the client wasn't subscribed.\r
+     */\r
+    public Client unsubscribe(Client subscriber);\r
+\r
+    /**\r
+     * returns a non modifiable list of all the subscribers to this \r
+     * channel.\r
+     * @return a list of subscribers\r
+     */\r
+    public List<Client> getSubscribers();\r
+    \r
+    /**\r
+     * Adds a data filter to this channel. All messages received by this channel \r
+     * will run through this filter.\r
+     * @param filter Filter\r
+     */\r
+    public void addFilter(DataFilter filter);\r
+    \r
+    /**\r
+     * Removes a filter from this channel.\r
+     * returns the filter that was removed, or null if the filter wasn't in the channel.\r
+     * @param filter Filter\r
+     * @return Filter - null if no filter was removed otherwise it returns the filter that was removed.\r
+     */\r
+    public DataFilter removeFilter(DataFilter filter);\r
+}
\ No newline at end of file
diff --git a/modules/bayeux/java/org/apache/cometd/bayeux/Client.java b/modules/bayeux/java/org/apache/cometd/bayeux/Client.java
new file mode 100644 (file)
index 0000000..3d6a8d8
--- /dev/null
@@ -0,0 +1,91 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package org.apache.cometd.bayeux;\r
+\r
+\r
+\r
+/** A Bayeux Client.\r
+ * <p>\r
+ * A client may subscribe to channels and publish messages to channels.\r
+ * Client instances should not be directly created by uses, but should \r
+ * be obtained via the {@link Bayeux#getClient(String)} or {@link Bayeux#newClient(String, Listener)}\r
+ * methods.\r
+ * </p>\r
+ * <p>\r
+ * Three types of client may be represented by this interface:<nl>\r
+ * <li>The server representation of a remote client connected via HTTP, \r
+ *     automatically created by the Bayeux server when a connect message comes in</li>\r
+ * <li>A server side client, created by the application using the {@link Bayeux#newClient(String, Listener)} method</li>\r
+ * <li>A java client connected to a remote Bayeux server - not implemented</li>\r
+ * </nl>\r
+ * @author Greg Wilkins\r
+ * @author Filip Hanik\r
+ */\r
+public interface Client\r
+{\r
+    /**\r
+     * Returns a unique id for this client. The id is unique within this Bayeux session.\r
+     * @return String - will not be null\r
+     */\r
+    public String getId();\r
+\r
+    /**\r
+     * Returns true if this client is holding messages to be delivered to the remote client.\r
+     * This method always returns false for local clients, since messages are delivered instantly using the \r
+     * Listener(callback) object\r
+     * @return boolean\r
+     */\r
+    public boolean hasMessages();\r
+\r
+    /** \r
+     * Deliver a message to this client only\r
+     * Deliver a message directly to the client. The message is not \r
+     * filtered or published to a channel.\r
+     * @param message\r
+     */\r
+    public void deliver(Message message);\r
+\r
+    /** \r
+     * Deliver a batch of messages to this client only\r
+     * Deliver a batch messages directly to the client. The messages are not \r
+     * filtered or published to a channel.\r
+     * @param message\r
+     */\r
+    public void deliver(Message[] message);\r
+\r
+    /**\r
+     * @return True if the client is local. False if this client is either a remote HTTP client or\r
+     * a java client to a remote server. \r
+     */\r
+    public boolean isLocal();\r
+    \r
+    /**\r
+     * Starts a batch, no messages will be delivered until endBatch is called.\r
+     * Batches can be nested, and messages will only be delivered after\r
+     * the last endBatch has been called.\r
+     */\r
+    public void startBatch();\r
+    \r
+    /**\r
+     * Ends a batch. since batches can be nested, messages will only be delivered\r
+     * after the endBatch has been called as many times as startBatch has.\r
+     */\r
+    public void endBatch();\r
+    \r
+    \r
+}
\ No newline at end of file
diff --git a/modules/bayeux/java/org/apache/cometd/bayeux/DataFilter.java b/modules/bayeux/java/org/apache/cometd/bayeux/DataFilter.java
new file mode 100644 (file)
index 0000000..d632aec
--- /dev/null
@@ -0,0 +1,38 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.cometd.bayeux;\r
+\r
+/** \r
+ * Data Filter<br/>\r
+ * Data filters are used to transform data as it is sent to a Channel.\r
+ * Messages are filtered as the message is published to a channel, invoking the \r
+ * {@link Channel#publish(Message)} method.<br/>\r
+ * This method gets invoked in two different scenarios, the first being when a message is received from\r
+ * a remote client, and the Bayeux implementation invokes the publish method directly.\r
+ * The second scenario is when a local client invokes {@link Channel#publish(Message)} directly in the local JVM.\r
+ * @author Greg Wilkins\r
+ * @author Filip Hanik\r
+ *\r
+ */\r
+public interface DataFilter\r
+{\r
+    /**\r
+     * Runs a message through the filter. Filtering can only modify an existing object, it can not replace it.\r
+     * @param data Message - the message to be filtered, may not be null\r
+     */\r
+    public void filter(Message data);\r
+}\r
diff --git a/modules/bayeux/java/org/apache/cometd/bayeux/Listener.java b/modules/bayeux/java/org/apache/cometd/bayeux/Listener.java
new file mode 100644 (file)
index 0000000..cce2018
--- /dev/null
@@ -0,0 +1,45 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.cometd.bayeux;\r
+\r
+/** \r
+ * Cometd Listener interface.<br/>\r
+ * For local clients, in order to receive messages, they pass in a callback object\r
+ * when the local client is created using the {@link Bayeux#newClient(String,Listener)} method.\r
+ * This callback object, implementing the Listener interface, is used to deliver messages to local, in JVM, clients.\r
+ * @author Greg Wilkins\r
+ * @author Filip Hanik\r
+ *\r
+ */\r
+public interface Listener\r
+{\r
+    /**\r
+     * This method is called when the client is removed (explicitly or from a timeout)\r
+     * @param timeout - true if the client was removed from a timeout\r
+     * false if it was removed explicitly.\r
+     */\r
+    public void removed(boolean timeout);\r
+    \r
+    /**\r
+     * Invoked when a message is delivered to the client.\r
+     * The message contains the message itself, as well as what channel this message came through\r
+     * and who the sender is. If someone invoked {@link Client#deliver(Message)} then the channel reference will\r
+     * be null.\r
+     * @param msg \r
+     */\r
+    public void deliver(Message[] msg);\r
+}\r
diff --git a/modules/bayeux/java/org/apache/cometd/bayeux/Message.java b/modules/bayeux/java/org/apache/cometd/bayeux/Message.java
new file mode 100644 (file)
index 0000000..26ba640
--- /dev/null
@@ -0,0 +1,68 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.cometd.bayeux;\r
+\r
+import java.util.Map;\r
+\r
+/** \r
+ * A Bayeux Message<br/>\r
+ * A Bayeux message is a Map of String/Object key value pairs representing the data in the message.\r
+ * The message contains information about the channel it was published through and who the sender was\r
+ * \r
+ * @author Greg Wilkins\r
+ * @author Filip Hanik\r
+ */\r
+public interface Message extends Map<String,Object>\r
+{\r
+    /**\r
+     * Returns a reference to the client that sent this message\r
+     * @return Client - may be null\r
+     */\r
+    public Client getClient();\r
+    /**\r
+     * Returns a reference to the channel that this message was published throuhg\r
+     * @return Channel - may be null\r
+     */\r
+    public Channel getChannel();\r
+    /**\r
+     * Returns the unique id of this message\r
+     * @return String\r
+     */\r
+    public String getId();\r
+    \r
+    /**\r
+     * Sets the time to live in milliseconds. If the message hasn't been delivered \r
+     * when the time passed after the creation time is longer than the TTL the message will\r
+     * expire and removed from any delivery queues.\r
+     * @param ttl long\r
+     */\r
+    public void setTTL(long ttl);\r
+    \r
+    /**\r
+     * Returns the time to live (in milliseconds) for this message\r
+     * @return long\r
+     */\r
+    public long getTTL();\r
+    \r
+    /**\r
+     * returns the timestamp in milliseconds(System.currentTimeMillis()) of when this message was created.\r
+     * @return long\r
+     */\r
+    public long getCreationTime();\r
+}\r
+\r
+\r
diff --git a/modules/bayeux/java/org/apache/cometd/bayeux/SecurityPolicy.java b/modules/bayeux/java/org/apache/cometd/bayeux/SecurityPolicy.java
new file mode 100644 (file)
index 0000000..930f605
--- /dev/null
@@ -0,0 +1,28 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.cometd.bayeux;\r
+\r
+/**\r
+ * @author Greg Wilkins\r
+ */\r
+public interface SecurityPolicy\r
+{\r
+    boolean canHandshake(Message message);\r
+    boolean canCreate(Client client,String channel,Message message);\r
+    boolean canSubscribe(Client client,String channel,Message messsage);\r
+    boolean canPublish(Client client,String channel,Message messsage);\r
+}\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/BayeuxException.java b/modules/bayeux/java/org/apache/tomcat/bayeux/BayeuxException.java
new file mode 100644 (file)
index 0000000..d201c5e
--- /dev/null
@@ -0,0 +1,39 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux;\r
+/**\r
+ * \r
+ * @author Filip Hanik\r
+ * @version 1.0\r
+ */\r
+public class BayeuxException extends Exception {\r
+    public BayeuxException() {\r
+        super();\r
+    }\r
+\r
+    public BayeuxException(String message) {\r
+        super(message);\r
+    }\r
+\r
+    public BayeuxException(String message, Throwable cause) {\r
+        super(message, cause);\r
+    }\r
+\r
+    public BayeuxException(Throwable cause) {\r
+        super(cause);\r
+    }\r
+}
\ No newline at end of file
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/BayeuxRequest.java b/modules/bayeux/java/org/apache/tomcat/bayeux/BayeuxRequest.java
new file mode 100644 (file)
index 0000000..6e93c99
--- /dev/null
@@ -0,0 +1,54 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux;\r
+\r
+import org.apache.tomcat.bayeux.HttpError;\r
+\r
+/**\r
+ * An interface that defines methods for managing Bayeux request meta \r
+ * messages.\r
+ *\r
+ * @author Guy A. Molinari\r
+ * @author Filip Hanik\r
+ * @version 0.9\r
+ */\r
+public interface BayeuxRequest {\r
+\r
+    public static final String LAST_REQ_ATTR = "org.apache.cometd.bayeux.last_request";\r
+    public static final String CURRENT_REQ_ATTR = "org.apache.cometd.bayeux.current_request";\r
+    public static final String JSON_MSG_ARRAY = "org.apache.cometd.bayeux.json_msg_array";\r
+\r
+    /**\r
+     * Validates a specific request. \r
+     * This method must be called prior to process()\r
+     * as a request can do pre processing in the validate method.\r
+     * <br/>\r
+     * Should the validation fail, an error object is returned \r
+     * containing an error message, and potentially a stack trace\r
+     * if an exception was generated\r
+     * @return HttpError - null if no error was detected, an HttpError object containing information about the error.\r
+     */\r
+    public HttpError validate();\r
+    \r
+    /**\r
+     * processes a remote client Bayeux message\r
+     * @param prevops - the operation requested by the previous request, in case of chained requests.\r
+     * @return int - returns the interest operation for a CometEvent. Currently not used\r
+     * @throws BayeuxException - if an error was detected, and the appropriate error response couldn't be delivered to the client. \r
+     */\r
+    public int process(int prevops) throws BayeuxException;\r
+}\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/BayeuxServlet.java b/modules/bayeux/java/org/apache/tomcat/bayeux/BayeuxServlet.java
new file mode 100644 (file)
index 0000000..837086d
--- /dev/null
@@ -0,0 +1,236 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux;\r
+\r
+import java.io.IOException;\r
+import javax.servlet.ServletConfig;\r
+import javax.servlet.ServletContext;\r
+import javax.servlet.ServletException;\r
+import javax.servlet.ServletRequest;\r
+import javax.servlet.ServletResponse;\r
+import javax.servlet.http.HttpServletResponse;\r
+\r
+import org.apache.catalina.CometEvent;\r
+import org.apache.catalina.CometProcessor;\r
+import org.apache.juli.logging.Log;\r
+import org.apache.juli.logging.LogFactory;\r
+import org.json.JSONArray;\r
+import org.json.JSONException;\r
+import org.json.JSONObject;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+\r
+/**\r
+ * \r
+ * @author Filip Hanik\r
+ * @author Guy Molinari\r
+ * @version 1.0\r
+ */\r
+public class BayeuxServlet implements CometProcessor {\r
+\r
+    /**\r
+     * Attribute to hold the TomcatBayeux object in the servlet context\r
+     */\r
+    public static final String TOMCAT_BAYEUX_ATTR = Bayeux.DOJOX_COMETD_BAYEUX;\r
+    \r
+    /**\r
+     * Logger object\r
+     */\r
+    protected static Log log = LogFactory.getLog(BayeuxServlet.class);\r
+\r
+    /**\r
+     * Servlet config - for future use\r
+     */\r
+    protected ServletConfig servletConfig;\r
+    \r
+    /**\r
+     * Reference to the global TomcatBayeux object\r
+     */\r
+    protected TomcatBayeux tb;\r
+    \r
+    /**\r
+     * Upon servlet destruction, the servlet will clean up the \r
+     * TomcatBayeux object and terminate any outstanding events.\r
+     */\r
+    public void destroy() {\r
+        servletConfig = null;\r
+        //to do, close all outstanding comet events\r
+        //tb.destroy();\r
+        tb = null;//TO DO, close everything down\r
+        \r
+    }\r
+    \r
+    /**\r
+     * Returns the preconfigured connection timeout.\r
+     * If no timeout has been configured as a servlet init parameter named <code>timeout</code>\r
+     * then the default of 2min will be used.\r
+     * @return int - the timeout for a connection in milliseconds\r
+     */\r
+    protected int getTimeout() {\r
+        String timeoutS = servletConfig.getInitParameter("timeout");\r
+        int timeout = 120*1000; //2 min\r
+        try {\r
+            timeout = Integer.parseInt(timeoutS);\r
+        }catch (NumberFormatException nfe) {\r
+            //ignore, we have a default value\r
+        }\r
+        return timeout;\r
+    }\r
+    \r
+    protected int getReconnectInterval() {\r
+        String rs = servletConfig.getInitParameter("reconnectInterval");\r
+        int rct = 1000; //1 seconds\r
+        try {\r
+            rct = Integer.parseInt(rs);\r
+        }catch (NumberFormatException nfe) {\r
+            //ignore, we have a default value\r
+        }\r
+        return rct;\r
+    }\r
+\r
+\r
+    public void event(CometEvent cometEvent) throws IOException, ServletException {\r
+        CometEvent.EventType type = cometEvent.getEventType();\r
+        if (log.isDebugEnabled()) {\r
+            log.debug("["+Thread.currentThread().getName()+"] Received Comet Event type="+type+" subtype:"+cometEvent.getEventSubType());\r
+        }\r
+        synchronized (cometEvent) {\r
+            if (type==CometEvent.EventType.BEGIN) {\r
+                //begin event, set the timeout\r
+                cometEvent.setTimeout(getTimeout());\r
+                //checkBayeux(cometEvent); - READ event should always come\r
+            } else if (type==CometEvent.EventType.READ) {\r
+                checkBayeux(cometEvent);\r
+            } else if (type==CometEvent.EventType.ERROR) {\r
+                tb.remove(cometEvent);\r
+                cometEvent.close();\r
+            } else if (type==CometEvent.EventType.END) {\r
+                tb.remove(cometEvent);\r
+                cometEvent.close();\r
+            }//end if\r
+            \r
+        }//synchronized\r
+    }//event\r
+\r
+    /**\r
+     * \r
+     * @param cometEvent CometEvent\r
+     * @return boolean - true if we comet event stays open\r
+     * @throws IOException\r
+     * @throws UnsupportedOperationException\r
+     */\r
+    protected void checkBayeux(CometEvent cometEvent) throws IOException, UnsupportedOperationException {\r
+        //we actually have data.\r
+        //data can be text/json or \r
+        if (Bayeux.JSON_CONTENT_TYPE.equals(cometEvent.getHttpServletRequest().getContentType())) {\r
+            //read and decode the bytes according to content length\r
+            log.warn("["+Thread.currentThread().getName()+"] JSON encoding not supported, will throw an exception and abort the request.");\r
+            int contentlength = cometEvent.getHttpServletRequest().getContentLength();\r
+            throw new UnsupportedOperationException("Decoding "+Bayeux.JSON_CONTENT_TYPE+" not yet implemented.");\r
+        } else { //GET method or application/x-www-form-urlencoded\r
+            String message = cometEvent.getHttpServletRequest().getParameter(Bayeux.MESSAGE_PARAMETER);\r
+            if (log.isTraceEnabled()) {\r
+                log.trace("["+Thread.currentThread().getName()+"] Received JSON message:"+message);\r
+            }\r
+            try {\r
+                int action = handleBayeux(message, cometEvent);\r
+                if (log.isDebugEnabled()) {\r
+                    log.debug("["+Thread.currentThread().getName()+"] Bayeux handling complete, action result="+action);\r
+                }\r
+                if (action<=0) {\r
+                    cometEvent.close();\r
+                }\r
+            }catch (Exception x) {\r
+                x.printStackTrace();\r
+                tb.remove(cometEvent);\r
+                log.error(x);\r
+                cometEvent.close();\r
+            }\r
+        }\r
+    }\r
+    \r
+    protected int handleBayeux(String message, CometEvent event) throws IOException, ServletException {\r
+        int result = 0;\r
+        if (message==null || message.length()==0) return result;\r
+        try {\r
+            BayeuxRequest request = null;\r
+            //a message can be an array of messages\r
+            JSONArray jsArray = new JSONArray(message);\r
+            for (int i = 0; i < jsArray.length(); i++) {\r
+                JSONObject msg = jsArray.getJSONObject(i);\r
+                \r
+                if (log.isDebugEnabled()) {\r
+                    log.debug("["+Thread.currentThread().getName()+"] Processing bayeux message:"+msg);\r
+                }\r
+                request = RequestFactory.getRequest(tb,event,msg);\r
+                if (log.isDebugEnabled()) {\r
+                    log.debug("["+Thread.currentThread().getName()+"] Processing bayeux message using request:"+request);\r
+                }\r
+                result = request.process(result);\r
+                if (log.isDebugEnabled()) {\r
+                    log.debug("["+Thread.currentThread().getName()+"] Processing bayeux message result:"+result);\r
+                }\r
+            }\r
+            if (result>0 && request!=null) {\r
+                event.getHttpServletRequest().setAttribute(BayeuxRequest.LAST_REQ_ATTR, request);\r
+                ClientImpl ci = (ClientImpl)tb.getClient(((RequestBase)request).getClientId());\r
+                ci.addCometEvent(event);\r
+                if (log.isDebugEnabled()) {\r
+                    log.debug("["+Thread.currentThread().getName()+"] Done bayeux message added to request attribute");\r
+                }\r
+            } else if (result == 0 && request!=null) {\r
+                RequestBase.deliver(event,(ClientImpl)tb.getClient(((RequestBase)request).getClientId()));\r
+                if (log.isDebugEnabled()) {\r
+                    log.debug("["+Thread.currentThread().getName()+"] Done bayeux message, delivered to client");\r
+                }\r
+            }\r
+            \r
+        }catch (JSONException x) {\r
+            log.error(x);//to do impl error handling\r
+            result = -1;\r
+        }catch (BayeuxException x) {\r
+            log.error(x); //to do impl error handling\r
+            result = -1;\r
+        }\r
+        return result;\r
+    }\r
+\r
+    public ServletConfig getServletConfig() {\r
+        return servletConfig;\r
+    }\r
+\r
+    public String getServletInfo() {\r
+        return "Tomcat/BayeuxServlet/1.0";\r
+    }\r
+\r
+    public void init(ServletConfig servletConfig) throws ServletException {\r
+        \r
+        this.servletConfig = servletConfig;\r
+        ServletContext ctx = servletConfig.getServletContext();\r
+        if (ctx.getAttribute(TOMCAT_BAYEUX_ATTR)==null)\r
+            ctx.setAttribute(TOMCAT_BAYEUX_ATTR,new TomcatBayeux());\r
+        this.tb = (TomcatBayeux)ctx.getAttribute(TOMCAT_BAYEUX_ATTR);\r
+        tb.setReconnectInterval(getReconnectInterval());\r
+    }\r
+\r
+    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {\r
+        if (servletResponse instanceof HttpServletResponse) {\r
+            ( (HttpServletResponse) servletResponse).sendError(500, "Misconfigured Tomcat server, must be configured to support Comet operations.");\r
+        } else {\r
+            throw new ServletException("Misconfigured Tomcat server, must be configured to support Comet operations for the Bayeux protocol.");\r
+        }\r
+    }\r
+}\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/ChannelImpl.java b/modules/bayeux/java/org/apache/tomcat/bayeux/ChannelImpl.java
new file mode 100644 (file)
index 0000000..e1e08a8
--- /dev/null
@@ -0,0 +1,189 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux;\r
+\r
+import java.util.LinkedList;\r
+\r
+import org.apache.cometd.bayeux.Channel;\r
+import org.apache.cometd.bayeux.Client;\r
+import org.apache.cometd.bayeux.DataFilter;\r
+import java.util.Collections;\r
+import java.util.List;\r
+import org.apache.cometd.bayeux.Message;\r
+import java.util.Iterator;\r
+import org.apache.juli.logging.Log;\r
+import org.apache.juli.logging.LogFactory;\r
+/**\r
+ * \r
+ * @author Filip Hanik\r
+ * @version 1.0\r
+ */\r
+public class ChannelImpl implements Channel {\r
+    \r
+    protected static Log log = LogFactory.getLog(ChannelImpl.class);\r
+    \r
+    /**\r
+     * The unique id of this channel\r
+     */\r
+    protected String id = null;\r
+    \r
+    /**\r
+     * A list of the current subscribers\r
+     */\r
+    protected LinkedList<Client> subscribers = new LinkedList<Client>();\r
+    \r
+    /**\r
+     * A list of the current filters\r
+     */\r
+    protected LinkedList<DataFilter> filters = new LinkedList<DataFilter>();\r
+    \r
+    /**\r
+     * Is this channel persistent, default value is true\r
+     */\r
+    protected boolean persistent = true; \r
+    \r
+    /**\r
+     * Creates a new channel\r
+     * @param id String - the id of the channel, can not be null\r
+     */\r
+    protected ChannelImpl(String id) {\r
+        assert id != null;\r
+        this.id = id;\r
+    }\r
+\r
+    /**\r
+     * returns the id of this channel\r
+     * @return String\r
+     */\r
+    public String getId() {\r
+        return id;\r
+    }\r
+    \r
+    /**\r
+     * Returns true if this channel matches the pattern to its id.\r
+     * The channel pattern can be a complete name like <code>/service/mychannel</code>\r
+     * or it can be a wild card pattern like <code>/service/app2/**</code>\r
+     * @param pattern String according to the Bayeux specification section 2.2.1 Channel Globbing, can not be null.\r
+     * @return boolean true if the id of this channel matches the pattern\r
+     */\r
+    public boolean matches(String pattern) {\r
+        if (pattern == null)\r
+            throw new NullPointerException("Channel pattern must not be null.");\r
+        if (getId().equals(pattern))\r
+            return true;\r
+        int wildcardPos = pattern.indexOf("/*");\r
+        if (wildcardPos == -1)\r
+            return false;\r
+        boolean multiSegment = pattern.indexOf("**") != -1;\r
+        String leadSubstring = pattern.substring(0, wildcardPos);\r
+        if (leadSubstring == null)\r
+            return false;\r
+        if (multiSegment) \r
+            return getId().startsWith(leadSubstring);\r
+        else {\r
+            if (getId().length() <= wildcardPos + 2)\r
+                return false;\r
+            return !(getId().substring(wildcardPos + 2).contains("/"));\r
+        }\r
+    }\r
+\r
+\r
+\r
+    /**\r
+     * @return returns a non modifiable list of the subscribers for this channel.\r
+     */\r
+    public List<Client> getSubscribers() {\r
+        return Collections.unmodifiableList(subscribers);\r
+    }\r
+\r
+    /**\r
+     * @return true if the Channel will persist without any subscription.\r
+     */\r
+    public boolean isPersistent() {\r
+        return persistent;\r
+    }\r
+    \r
+    public void publish(Message msg) {\r
+        publish(new Message[] {msg});\r
+    }\r
+\r
+    public void publish(Message[] msgs) {\r
+        if (msgs==null) return;\r
+        MessageImpl[] imsgs = new MessageImpl[msgs.length];\r
+        for (int i=0; msgs!=null && i<msgs.length; i++) {\r
+            Message data = msgs[i];\r
+\r
+            if (!(data instanceof MessageImpl)) \r
+                throw new IllegalArgumentException("Invalid message class, you can only publish messages "+\r
+                                                   "created through the Bayeux.newMessage() method");\r
+            if (log.isDebugEnabled()) {\r
+                log.debug("Publishing message:"+data+" to channel:"+this);\r
+            }\r
+            //clone it so that we can set this channel as a reference\r
+            MessageImpl msg = (MessageImpl)((MessageImpl)data).clone();\r
+            //this is the channel it was delivered through\r
+            msg.setChannel(this);\r
+            //pass through filters\r
+            for (Iterator<DataFilter> it = filters.iterator(); it.hasNext(); ) {\r
+                it.next().filter(msg);\r
+            }\r
+            imsgs[i] = msg;\r
+        }\r
+        //deliver it to the clients\r
+        for (Iterator<Client> it = subscribers.iterator(); it.hasNext(); ) {\r
+            ClientImpl c = (ClientImpl)it.next();\r
+            c.deliverInternal(this,imsgs);\r
+        }\r
+        \r
+    }\r
+\r
+    public void setPersistent(boolean persistent) {\r
+        this.persistent = persistent;\r
+    }\r
+\r
+    public void subscribe(Client subscriber) {\r
+        if (!subscribers.contains((subscriber))) { \r
+            subscribers.addLast(subscriber);\r
+            ((ClientImpl)subscriber).subscribed(this);\r
+        }\r
+    }\r
+\r
+    public Client unsubscribe(Client subscriber) {\r
+        if (subscribers.remove(subscriber)) {\r
+            ((ClientImpl)subscriber).unsubscribed(this);\r
+            return subscriber;\r
+        } else\r
+            return null;\r
+    }\r
+    \r
+    public void addFilter(DataFilter filter) {\r
+        if (!filters.contains(filter)) \r
+            filters.addLast(filter);\r
+    }\r
+\r
+    public DataFilter removeFilter(DataFilter filter) {\r
+        if ( filters.remove(filter) ) return filter;\r
+        else return null;\r
+    }\r
+    \r
+    public String toString() {\r
+        StringBuffer buf = new StringBuffer(super.toString());\r
+        buf.append("; channelId=").append(getId());\r
+        return buf.toString();\r
+    }\r
+\r
+}
\ No newline at end of file
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/ClientImpl.java b/modules/bayeux/java/org/apache/tomcat/bayeux/ClientImpl.java
new file mode 100644 (file)
index 0000000..894f9ef
--- /dev/null
@@ -0,0 +1,279 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux;\r
+\r
+import java.util.LinkedList;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Queue;\r
+import java.util.concurrent.ConcurrentLinkedQueue;\r
+\r
+import org.apache.catalina.CometEvent;\r
+import org.json.JSONObject;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+import org.apache.cometd.bayeux.Client;\r
+import org.apache.cometd.bayeux.Listener;\r
+import org.apache.cometd.bayeux.Message;\r
+import org.apache.juli.logging.Log;\r
+import org.apache.juli.logging.LogFactory;\r
+import java.util.concurrent.atomic.AtomicInteger;\r
+import java.util.HashMap;\r
+import java.util.ArrayList;\r
+\r
+public class ClientImpl implements Client {\r
+    \r
+    public static final int SUPPORT_CALLBACK_POLL = 0x1;\r
+    public static final int SUPPORT_LONG_POLL = 0x2; \r
+\r
+    public static final String COMET_EVENT_ATTR = "org.apache.cometd.bayeux.client";\r
+    \r
+    protected static Log log = LogFactory.getLog(ClientImpl.class);\r
+\r
+    protected static LinkedList<Message> EMPTY_LIST = new LinkedList<Message>();\r
+    /**\r
+     * queued message for remote clients.\r
+     */\r
+    protected LinkedList<Message> messages = null;\r
+    \r
+    /**\r
+     * \r
+     */\r
+    protected Queue<CometEvent> events = new LinkedList<CometEvent>();\r
+    \r
+    /**\r
+     * Unique id representing this client\r
+     */\r
+    protected String id;\r
+    \r
+    /**\r
+     * supported connection types, defaults to long-polling\r
+     */\r
+    protected int supportedConnTypes = SUPPORT_LONG_POLL | SUPPORT_CALLBACK_POLL;\r
+    \r
+    /**\r
+     * The desired connection type\r
+     */\r
+    protected int desirectConnType = SUPPORT_LONG_POLL;\r
+    \r
+    /**\r
+     * Does this client use json-comment-filtered messages\r
+     */\r
+    protected boolean useJsonFiltered = false;\r
+    \r
+    /**\r
+     * Same JVM clients, get local=true\r
+     */\r
+    protected boolean local;\r
+    \r
+    /**\r
+     * The callback object for local clients\r
+     */\r
+    protected Listener listener;\r
+    \r
+    protected AtomicInteger nrofsubscriptions = new AtomicInteger(0);\r
+    \r
+    protected ClientImpl(String id, boolean local) {\r
+        this.id = id;\r
+        this.local = local;\r
+        if (!local) messages = new LinkedList<Message>();\r
+    }\r
+    \r
+    protected ClientImpl(String id, CometEvent event) {\r
+        this(id,false);\r
+        events = new ConcurrentLinkedQueue<CometEvent>();\r
+        addCometEvent(event);\r
+    }\r
+\r
+    public synchronized void deliver(Message message) {\r
+        deliverInternal(null,new MessageImpl[] {(MessageImpl)message});\r
+    }\r
+    \r
+    public synchronized void deliver(Message[] message) {\r
+        deliverInternal(null,message);\r
+    }\r
+\r
+    protected synchronized void deliverInternal(ChannelImpl channel, MessageImpl message) {\r
+        deliverInternal(channel,new MessageImpl[] {message});\r
+    }\r
+\r
+    protected synchronized void deliverInternal(ChannelImpl channel, Message[] msgs) {\r
+        if (isLocal()) {\r
+            //local clients must have a listener\r
+            ArrayList<Message> list = new ArrayList<Message>();\r
+            for (int i=0; msgs!=null && i<msgs.length; i++) {\r
+                //dont deliver to ourselves\r
+                if (this!=msgs[i].getClient()) list.add(msgs[i]);\r
+            }\r
+            if (getListener() != null && list.size()>0) {\r
+                getListener().deliver(list.toArray(new Message[0]));\r
+            }\r
+        } else {\r
+            for (int i=0; msgs!=null && i<msgs.length; i++) {\r
+                MessageImpl message = (MessageImpl)msgs[i];\r
+                if (this==message.getClient()) { \r
+                    //dont deliver to ourself\r
+                    continue;\r
+                }\r
+                //we are not implementing forever responses, if the client is connected\r
+                //then we will fire off the message\r
+                //first we check to see if we have any existing connections we can piggy back on\r
+                CometEvent event = events.poll();\r
+                boolean delivered = false;\r
+                //TODO TODO - check on thread safety, for writing and for getting last request.\r
+                if (event!=null) {\r
+                    synchronized (event) {\r
+                        RequestBase rq = (RequestBase)event.getHttpServletRequest().getAttribute(RequestBase.LAST_REQ_ATTR);\r
+                        if (rq!=null) {\r
+                            Map map = new HashMap();\r
+                            try {\r
+                                map.put(Bayeux.CHANNEL_FIELD,message.getChannel().getId());\r
+                                map.put(Bayeux.DATA_FIELD,message);\r
+                                JSONObject json = new JSONObject(map);\r
+                                if (log.isDebugEnabled()) {\r
+                                    log.debug("Message instantly delivered to remote client["+this+"] message:"+json);\r
+                                }\r
+                                rq.addToDeliveryQueue(this, json);\r
+                                //deliver the batch\r
+                                if (i==(msgs.length-1)) {\r
+                                    rq.deliver(event, this);\r
+                                    event.close(); //todo, figure out a better way, this means only one message gets delivered\r
+                                    removeCometEvent(event); //and delivered instantly\r
+                                }\r
+                                delivered = true;\r
+                            } catch (Exception x) {\r
+                                log.error(x);\r
+                            }\r
+                        }\r
+                    }\r
+                } \r
+                if (!delivered) {\r
+                    if (log.isDebugEnabled()) {\r
+                        log.debug("Message added to queue for remote client["+this+"] message:"+message);\r
+                    }\r
+                    //queue the message for the next round\r
+                    messages.add(message);\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    public String getId() {\r
+        return this.id;\r
+    }\r
+\r
+    protected Listener getListener() {\r
+        return listener;\r
+    }\r
+\r
+    public boolean hasMessages() {\r
+        if (isLocal()) return false;\r
+        else {\r
+            return messages.size() > 0;\r
+        }\r
+    }\r
+\r
+    public boolean isLocal() {\r
+        return local;\r
+    }\r
+\r
+    public int getSupportedConnTypes() {\r
+        return supportedConnTypes;\r
+    }\r
+\r
+    public int getDesirectConnType() {\r
+        return desirectConnType;\r
+    }\r
+\r
+    public boolean useJsonFiltered() {\r
+        return useJsonFiltered;\r
+    }\r
+\r
+    public void setListener(Listener listener) {\r
+        this.listener = listener;\r
+    }\r
+\r
+    public void setSupportedConnTypes(int supportedConnTypes) {\r
+        this.supportedConnTypes = supportedConnTypes;\r
+    }\r
+\r
+    public void setUseJsonFiltered(boolean useJsonFiltered) {\r
+        this.useJsonFiltered = useJsonFiltered;\r
+    }\r
+\r
+    public void setDesirectConnType(int desirectConnType) {\r
+        this.desirectConnType = desirectConnType;\r
+    }\r
+\r
+    public boolean supportsCallbackPoll() {\r
+        return (supportedConnTypes & SUPPORT_CALLBACK_POLL) == SUPPORT_CALLBACK_POLL;\r
+    }\r
+\r
+    public boolean supportsLongPoll() {\r
+        return (supportedConnTypes & SUPPORT_LONG_POLL) == SUPPORT_LONG_POLL;\r
+    }\r
+\r
+    public synchronized List<Message> takeMessages() {\r
+        if (isLocal()) return null;\r
+        if (messages.size()==0) return EMPTY_LIST;\r
+        List result = new LinkedList(messages);\r
+        messages.clear();\r
+        return result;\r
+    }\r
+    \r
+    public String toString() {\r
+        StringBuffer buf = new StringBuffer(super.toString());\r
+        buf.append(" id=").append(getId());\r
+        return buf.toString();\r
+    }\r
+    \r
+    public boolean isSubscribed() {\r
+        return nrofsubscriptions.get()>0;\r
+    }\r
+    \r
+    protected synchronized boolean addCometEvent(CometEvent event) {\r
+        boolean result = false;\r
+        if (!events.contains(event)) {\r
+            events.add(event);\r
+            result = true;\r
+        }\r
+        event.getHttpServletRequest().setAttribute(COMET_EVENT_ATTR,this);\r
+        return result;\r
+    }\r
+    \r
+    protected synchronized boolean removeCometEvent(CometEvent event) {\r
+        boolean result = events.remove(event);\r
+        event.getHttpServletRequest().removeAttribute(COMET_EVENT_ATTR);\r
+        return result;\r
+    }\r
+    \r
+    \r
+    protected void subscribed(ChannelImpl ch) {\r
+        nrofsubscriptions.addAndGet(1);\r
+    }\r
+    \r
+    protected void unsubscribed(ChannelImpl ch) {\r
+        nrofsubscriptions.addAndGet(-1);\r
+    }\r
+    \r
+    public void startBatch(){\r
+        //noop until improved\r
+    }\r
+    public void endBatch() {\r
+        //noop until improved\r
+    }\r
+        \r
+}\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/HttpError.java b/modules/bayeux/java/org/apache/tomcat/bayeux/HttpError.java
new file mode 100644 (file)
index 0000000..55ff2c7
--- /dev/null
@@ -0,0 +1,43 @@
+package org.apache.tomcat.bayeux;\r
+\r
+public class HttpError {\r
+    private int code;\r
+    private String status;\r
+    private Throwable cause;\r
+    public HttpError(int code, String status, Throwable cause) {\r
+        this.code = code;\r
+        this.status = status;\r
+        this.cause = cause;\r
+    }\r
+\r
+    public void setCode(int code) {\r
+        this.code = code;\r
+    }\r
+\r
+    public void setStatus(String status) {\r
+        this.status = status;\r
+    }\r
+\r
+    public void setCause(Throwable exception) {\r
+        this.cause = exception;\r
+    }\r
+\r
+    public int getCode() {\r
+        return code;\r
+    }\r
+\r
+    public String getStatus() {\r
+        return status;\r
+    }\r
+\r
+    public Throwable getCause() {\r
+        return cause;\r
+    }\r
+\r
+    public String toString() {\r
+        if (cause != null)\r
+            return code + ":" + status + " - [" + cause + "]";\r
+        else\r
+            return code + ":" + status;\r
+    }\r
+}\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/MessageImpl.java b/modules/bayeux/java/org/apache/tomcat/bayeux/MessageImpl.java
new file mode 100644 (file)
index 0000000..53d5342
--- /dev/null
@@ -0,0 +1,80 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux;\r
+\r
+import java.util.HashMap;\r
+\r
+import org.apache.cometd.bayeux.Channel;\r
+import org.apache.cometd.bayeux.Client;\r
+import org.apache.cometd.bayeux.Message;\r
+\r
+public class MessageImpl extends HashMap<String,Object> implements Message {\r
+    \r
+    protected Channel channel;\r
+    protected Client client;\r
+    protected String id;\r
+    private long TTL = 1000*60*5; //5min is the default TTL for a message\r
+    protected long creationTime = System.currentTimeMillis();\r
+\r
+    public Object clone() {\r
+        MessageImpl copy = new MessageImpl(id);\r
+        copy.putAll(this);\r
+        copy.channel = channel;\r
+        copy.client = client;\r
+        copy.id = id;\r
+        copy.creationTime = creationTime;\r
+        copy.TTL = TTL;\r
+        return copy;\r
+    }\r
+\r
+    protected MessageImpl(String id) {\r
+        assert id != null;\r
+        this.id = id;\r
+    }\r
+\r
+    public Channel getChannel() {\r
+        return channel;\r
+    }\r
+\r
+    public Client getClient() {\r
+        return client;\r
+    }\r
+\r
+    public long getCreationTime() {\r
+        return creationTime;\r
+    }\r
+\r
+    public long getTTL() {\r
+        return TTL;\r
+    }\r
+\r
+    public String getId() {\r
+        return id;\r
+    }\r
+\r
+    protected void setChannel(Channel channel) {\r
+        this.channel = channel;\r
+    }\r
+\r
+    protected void setClient(Client client) {\r
+        this.client = client;\r
+    }\r
+\r
+    public void setTTL(long TTL) {\r
+        this.TTL = TTL;\r
+    }\r
+}
\ No newline at end of file
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/RequestBase.java b/modules/bayeux/java/org/apache/tomcat/bayeux/RequestBase.java
new file mode 100644 (file)
index 0000000..e3c4000
--- /dev/null
@@ -0,0 +1,259 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux;\r
+\r
+import java.io.IOException;\r
+import java.io.PrintWriter;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.LinkedHashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.TimeZone;\r
+import java.util.Date;\r
+import java.text.SimpleDateFormat;\r
+import javax.servlet.ServletException;\r
+\r
+import org.apache.catalina.CometEvent;\r
+import org.apache.tomcat.bayeux.HttpError;\r
+\r
+import org.apache.juli.logging.Log;\r
+import org.apache.juli.logging.LogFactory;\r
+import org.json.JSONArray;\r
+import org.json.JSONException;\r
+import org.json.JSONObject;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+import org.apache.cometd.bayeux.Message;\r
+\r
+/**\r
+ * Common functionality and member variables for all Bayeux requests.\r
+ *\r
+ * @author Guy A. Molinari\r
+ * @author Filip Hanik\r
+ * @version 0.9\r
+ *\r
+ */\r
+public abstract class RequestBase implements BayeuxRequest {\r
+    \r
+    protected static final SimpleDateFormat timestampFmt =\r
+        new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");\r
+    static {\r
+        timestampFmt.setTimeZone(TimeZone.getTimeZone("GMT"));\r
+    }\r
+    //message properties, combined for all messages\r
+    protected TomcatBayeux tomcatBayeux;\r
+    protected String channel;\r
+    protected String id;\r
+    protected String clientId;\r
+    protected String version = null;\r
+    protected String[] suppConnTypes = null;\r
+    protected int suppConnTypesFlag = 0;\r
+    protected int desiredConnTypeFlag = 0;\r
+    protected String minVersion = null;\r
+    protected String subscription = null;\r
+    protected String data = null;\r
+    protected String conType = null;\r
+    protected LinkedHashMap<String, Object> ext = new LinkedHashMap<String, Object> ();\r
+\r
+    \r
+    protected CometEvent event;\r
+    \r
+    protected HashMap<String, Object> response = null;\r
+    \r
+    protected static Log log = LogFactory.getLog(RequestBase.class);\r
+    \r
+    protected int reconnectInterval = 1000;\r
+    \r
+    protected RequestBase(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
+        this.tomcatBayeux = tb;\r
+        this.event = event;\r
+        channel = jsReq.optString(Bayeux.CHANNEL_FIELD);\r
+        id = jsReq.optString(Bayeux.ID_FIELD);\r
+        clientId = jsReq.optString(Bayeux.CLIENT_FIELD);\r
+        version = jsReq.optString(Bayeux.VERSION_FIELD);\r
+        minVersion = jsReq.optString(Bayeux.MIN_VERSION_FIELD);\r
+        conType = jsReq.optString(Bayeux.CONNECTION_TYPE_FIELD);\r
+        subscription = jsReq.optString(Bayeux.SUBSCRIPTION_FIELD);\r
+        data = jsReq.optString(Bayeux.DATA_FIELD);\r
+        reconnectInterval = tb.getReconnectInterval();\r
+        if (jsReq.has(Bayeux.EXT_FIELD)) {\r
+            JSONObject jext = jsReq.getJSONObject(Bayeux.EXT_FIELD);\r
+            for (Iterator<String> i = jext.keys(); i.hasNext(); ) {\r
+                String key = i.next();\r
+                ext.put(key, jext.get(key));\r
+            }//for\r
+        }//end if\r
+        \r
+        if (jsReq.has(Bayeux.SUPP_CONNECTION_TYPE_FIELD)) {\r
+            JSONArray types = jsReq.getJSONArray(Bayeux.SUPP_CONNECTION_TYPE_FIELD);\r
+            suppConnTypes = new String[types.length()];\r
+            for (int i = 0; i < types.length(); i++) {\r
+                suppConnTypes[i] = types.getString(i);\r
+                if (Bayeux.TRANSPORT_CALLBACK_POLL.equals(suppConnTypes[i]))\r
+                    suppConnTypesFlag = suppConnTypesFlag|ClientImpl.SUPPORT_CALLBACK_POLL;\r
+                else if (Bayeux.TRANSPORT_LONG_POLL.equals(suppConnTypes[i]))\r
+                    suppConnTypesFlag = suppConnTypesFlag|ClientImpl.SUPPORT_LONG_POLL;\r
+            }//for\r
+        }//end if\r
+\r
+        if (conType!=null) {\r
+            if (Bayeux.TRANSPORT_CALLBACK_POLL.equals(conType))\r
+                desiredConnTypeFlag = ClientImpl.SUPPORT_CALLBACK_POLL;\r
+            else if (Bayeux.TRANSPORT_LONG_POLL.equals(conType))\r
+                desiredConnTypeFlag = ClientImpl.SUPPORT_LONG_POLL;\r
+        }//end if\r
+        \r
+        //due to the fact that the javascript doesn't send up a required field\r
+        //we have to fake it\r
+        suppConnTypesFlag = ClientImpl.SUPPORT_CALLBACK_POLL | ClientImpl.SUPPORT_LONG_POLL;\r
+\r
+    }\r
+\r
+    public HttpError validate() {\r
+        HttpError result = null;\r
+//        if (clientId == null) {\r
+//            result = new HttpError(401,"No Client ID.", null);\r
+//        }\r
+        return result;\r
+    }\r
+\r
+    public TomcatBayeux getTomcatBayeux() {\r
+        return tomcatBayeux;\r
+    }\r
+\r
+    public String getChannel() {\r
+        return channel;\r
+    }\r
+\r
+    public String getId() {\r
+        return id;\r
+    }\r
+\r
+    public String getClientId() {\r
+        return clientId;\r
+    }\r
+\r
+    public LinkedHashMap getExt() {\r
+        return ext;\r
+    }\r
+\r
+    public CometEvent getEvent() {\r
+        return event;\r
+    }\r
+    \r
+    protected static void deliver(CometEvent event, ClientImpl to) throws IOException, ServletException, BayeuxException {\r
+        JSONArray jarray = getJSONArray(event,true);\r
+        if ( jarray == null ) throw new BayeuxException("No message to send!");\r
+        String jsonstring = jarray.toString();\r
+        if (log.isDebugEnabled()) {\r
+            log.debug("["+Thread.currentThread().getName()+"] Delivering message to[" + to + "] message:" + jsonstring);\r
+        }\r
+\r
+        if (to!=null) {\r
+            if (to.useJsonFiltered()) {\r
+                if (!event.getHttpServletResponse().isCommitted()) event.getHttpServletResponse().setContentType("text/json-comment-filtered");\r
+            }else {    \r
+                if (!event.getHttpServletResponse().isCommitted()) event.getHttpServletResponse().setContentType("text/json");\r
+            }\r
+        }\r
+\r
+        PrintWriter out = event.getHttpServletResponse().getWriter();\r
+        if (to==null) {\r
+            //do nothing\r
+        }else if ( (to.getDesirectConnType() == 0 && to.supportsLongPoll()) || to.getDesirectConnType() == ClientImpl.SUPPORT_LONG_POLL) {\r
+            if (to.useJsonFiltered())\r
+                out.print("/*");\r
+        } else if ( (to.getDesirectConnType() == 0 && to.supportsCallbackPoll()) || to.getDesirectConnType() == ClientImpl.SUPPORT_CALLBACK_POLL) {\r
+            String jsonp = event.getHttpServletRequest().getParameter(Bayeux.JSONP_PARAMETER);\r
+            if (jsonp == null)\r
+                jsonp = Bayeux.JSONP_DEFAULT_NAME;\r
+            out.print(jsonp);\r
+            out.print('(');\r
+        } else {\r
+            throw new BayeuxException("Client doesn't support any appropriate connection type.");\r
+        }\r
+        out.print(jsonstring);\r
+        if ( to == null ) {\r
+            //do nothing\r
+        } else if ( (to.getDesirectConnType() == 0 && to.supportsLongPoll()) || to.getDesirectConnType() == ClientImpl.SUPPORT_LONG_POLL) {\r
+            if (to.useJsonFiltered())\r
+                out.print("*/");\r
+        } else if ( (to.getDesirectConnType() == 0 && to.supportsCallbackPoll()) || to.getDesirectConnType() == ClientImpl.SUPPORT_CALLBACK_POLL) {\r
+            out.print(");");\r
+        } \r
+        out.flush();\r
+        event.getHttpServletResponse().flushBuffer();\r
+\r
+        \r
+    }\r
+\r
+    protected static JSONArray getJSONArray(CometEvent event, boolean nullok) {\r
+        synchronized(event) {\r
+            JSONArray jarray = (JSONArray) event.getHttpServletRequest().getAttribute(JSON_MSG_ARRAY);\r
+            if (jarray == null && (!nullok)) {\r
+                jarray = new JSONArray();\r
+                event.getHttpServletRequest().setAttribute(JSON_MSG_ARRAY, jarray);\r
+            }\r
+            return jarray;\r
+        }\r
+    }\r
+\r
+    protected JSONArray getJSONArray() {\r
+        return getJSONArray(event,false);\r
+    }\r
+\r
+    protected void addToDeliveryQueue(ClientImpl to, JSONObject msg) throws IOException, ServletException, BayeuxException {\r
+        synchronized (event) {\r
+            getJSONArray().put(msg);\r
+        }\r
+    }\r
+    \r
+    protected void flushMessages(ClientImpl client) throws BayeuxException {\r
+        List<Message> msgs = client.takeMessages();\r
+        synchronized (event) {\r
+            try {\r
+                for (Iterator<Message> it = msgs.iterator(); it.hasNext(); ){\r
+                    MessageImpl msg = (MessageImpl)it.next();\r
+                    Map map = new HashMap();\r
+                    map.put(Bayeux.CHANNEL_FIELD,msg.getChannel().getId());\r
+                    if (msg.getClient()!=null) map.put(Bayeux.CLIENT_FIELD,msg.getClient().getId());\r
+                    map.put(Bayeux.DATA_FIELD,msg);\r
+                    JSONObject obj = new JSONObject(map);\r
+                    addToDeliveryQueue(client, obj);\r
+                }\r
+            } catch (ServletException x) {\r
+                throw new BayeuxException(x);\r
+            } catch (IOException x) {\r
+                throw new BayeuxException(x);\r
+            }\r
+        }\r
+    }\r
+    \r
+    public int process(int prevops) throws BayeuxException {\r
+        event.getHttpServletRequest().setAttribute(CURRENT_REQ_ATTR,this);\r
+        return prevops;\r
+    }\r
+    \r
+    public int getReconnectInterval() {\r
+        return reconnectInterval;\r
+    }\r
+\r
+    public String getTimeStamp() {\r
+        return timestampFmt.format(new Date(System.currentTimeMillis()));\r
+    }\r
+\r
+}\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/RequestFactory.java b/modules/bayeux/java/org/apache/tomcat/bayeux/RequestFactory.java
new file mode 100644 (file)
index 0000000..f2765e6
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux;\r
+\r
+import org.json.JSONObject;\r
+import org.apache.tomcat.bayeux.request.MetaHandshakeRequest;\r
+import org.apache.catalina.CometEvent;\r
+import org.json.JSONException;\r
+import org.apache.tomcat.bayeux.request.MetaConnectRequest;\r
+import org.apache.tomcat.bayeux.request.MetaDisconnectRequest;\r
+import org.apache.tomcat.bayeux.request.MetaSubscribeRequest;\r
+import org.apache.tomcat.bayeux.request.MetaUnsubscribeRequest;\r
+import org.apache.tomcat.bayeux.request.PublishRequest;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+\r
+public class RequestFactory {\r
+\r
+    public static BayeuxRequest getRequest(TomcatBayeux tomcatBayeux, CometEvent event, JSONObject msg) throws JSONException {\r
+        String channel = msg.optString(Bayeux.CHANNEL_FIELD);\r
+        if (Bayeux.META_HANDSHAKE.equals(channel)) {\r
+            return new MetaHandshakeRequest(tomcatBayeux,event,msg);\r
+        }else if (Bayeux.META_CONNECT.equals(channel)) {\r
+            return new MetaConnectRequest(tomcatBayeux,event,msg);\r
+        }else if (Bayeux.META_DISCONNECT.equals(channel)) {\r
+            return new MetaDisconnectRequest(tomcatBayeux,event,msg);\r
+        }else if (Bayeux.META_SUBSCRIBE.equals(channel)) {\r
+            return new MetaSubscribeRequest(tomcatBayeux,event,msg);\r
+        }else if (Bayeux.META_UNSUBSCRIBE.equals(channel)) {\r
+            return new MetaUnsubscribeRequest(tomcatBayeux,event,msg);\r
+        } else {\r
+            return new PublishRequest(tomcatBayeux,event,msg);\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/TomcatBayeux.java b/modules/bayeux/java/org/apache/tomcat/bayeux/TomcatBayeux.java
new file mode 100644 (file)
index 0000000..efe2264
--- /dev/null
@@ -0,0 +1,176 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux;\r
+\r
+import java.util.HashMap;\r
+import java.util.LinkedHashMap;\r
+import java.util.List;\r
+\r
+import org.apache.catalina.CometEvent;\r
+import org.apache.catalina.tribes.util.Arrays;\r
+import org.apache.catalina.tribes.util.UUIDGenerator;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+import org.apache.cometd.bayeux.Channel;\r
+import org.apache.cometd.bayeux.Client;\r
+import org.apache.cometd.bayeux.Listener;\r
+import org.apache.cometd.bayeux.Message;\r
+import org.apache.cometd.bayeux.SecurityPolicy;\r
+/**\r
+ * \r
+ * @author Filip Hanik\r
+ * @version 1.0\r
+ */\r
+public class TomcatBayeux implements Bayeux {\r
+    \r
+\r
+    protected int reconnectInterval = 5000;\r
+    /**\r
+     * a list of all active clients\r
+     */\r
+    protected HashMap<String,Client> clients = new HashMap<String,Client>();\r
+    \r
+    /**\r
+     * a list of all active channels\r
+     */\r
+    protected LinkedHashMap<String, Channel> channels = new LinkedHashMap<String,Channel>();\r
+    \r
+    /**\r
+     * security policy to be used.\r
+     */\r
+    protected SecurityPolicy securityPolicy = null;\r
+    /**\r
+     * default client to use when we need to send an error message but don't have a client valid reference\r
+     */\r
+    protected static ClientImpl errorClient = new ClientImpl("error-no-client",false);\r
+    \r
+    /**\r
+     * returns the default error client\r
+     * @return ClientImpl\r
+     */\r
+    public static ClientImpl getErrorClient() {\r
+        return errorClient;\r
+    }\r
+    \r
+    protected TomcatBayeux() {\r
+    }\r
+    \r
+    /**\r
+     * should be invoked when the servlet is destroyed or when the context shuts down\r
+     */\r
+    public void destroy() {\r
+        throw new UnsupportedOperationException("TomcatBayeux.destroy() not yet implemented");\r
+    }\r
+\r
+    public Channel getChannel(String channelId, boolean create) {\r
+        Channel result = channels.get(channelId);\r
+        if (result==null && create) {\r
+            result = new ChannelImpl(channelId);\r
+            channels.put(channelId,result);\r
+        }\r
+        return result;\r
+    }\r
+    \r
+    public Channel remove(Channel channel) {\r
+        return channels.remove(channel.getId());\r
+    }\r
+    \r
+    public Client remove(Client client) {\r
+        if (client==null) return null;\r
+        for (Channel ch : getChannels()) {\r
+            ch.unsubscribe(client);\r
+        }\r
+        return clients.remove(client.getId());\r
+    }\r
+\r
+    public Client getClient(String clientId) {\r
+        return clients.get(clientId);\r
+    }\r
+    \r
+    public boolean hasClient(String clientId) {\r
+        return clients.containsKey(clientId);\r
+    }\r
+    \r
+    public List<Client> getClients() {\r
+        return java.util.Arrays.asList(clients.entrySet().toArray(new Client[0]));\r
+    }\r
+\r
+    public SecurityPolicy getSecurityPolicy() {\r
+        return securityPolicy;\r
+    }\r
+\r
+    public int getReconnectInterval() { \r
+        return reconnectInterval;\r
+    }\r
+\r
+    public boolean hasChannel(String channel) {\r
+        return channels.containsKey(channel);\r
+    }\r
+\r
+    public Client newClient(String idprefix, Listener listener, boolean local, CometEvent event) {\r
+        String id = createUUID(idprefix);\r
+        ClientImpl client = new ClientImpl(id, local);\r
+        client.setListener(listener);\r
+        clients.put(id, client);\r
+        return client;\r
+    }\r
+\r
+    public Client newClient(String idprefix, Listener listener) {\r
+        assert listener!=null;\r
+        //if this method gets called, someone is using the API inside\r
+        //the JVM, this is a local client\r
+        return newClient(idprefix,listener,true, null);\r
+    }\r
+    \r
+    protected ClientImpl getClientImpl(CometEvent event) {\r
+        return (ClientImpl)event.getHttpServletRequest().getAttribute(ClientImpl.COMET_EVENT_ATTR);\r
+    }\r
+    \r
+    protected void remove(CometEvent event) {\r
+        ClientImpl client = getClientImpl(event);\r
+        if (client!=null) {\r
+            client.removeCometEvent(event);\r
+        }\r
+    }\r
+\r
+    public String createUUID(String idprefix) {\r
+        if (idprefix==null) idprefix="";\r
+        return idprefix + Arrays.toString(UUIDGenerator.randomUUID(false));\r
+    }\r
+    \r
+    public List<Channel> getChannels() {\r
+        return java.util.Arrays.asList(channels.entrySet().toArray(new Channel[0]));\r
+    }\r
+\r
+    protected Message newMessage() {\r
+        String id = createUUID("msg-");\r
+        return new MessageImpl(id);\r
+    }\r
+\r
+    public Message newMessage(Client from) {\r
+        MessageImpl msg = (MessageImpl)newMessage();\r
+        msg.setClient(from);\r
+        return msg;\r
+    }\r
+    public void setSecurityPolicy(SecurityPolicy securityPolicy) {\r
+        this.securityPolicy = securityPolicy;\r
+    }\r
+\r
+    public void setReconnectInterval(int reconnectTimeout) {\r
+        this.reconnectInterval = reconnectTimeout;\r
+    }\r
+\r
+}\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaConnectRequest.java b/modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaConnectRequest.java
new file mode 100644 (file)
index 0000000..baa4e8f
--- /dev/null
@@ -0,0 +1,125 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux.request;\r
+\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import javax.servlet.ServletException;\r
+\r
+import org.apache.catalina.CometEvent;\r
+import org.apache.tomcat.bayeux.HttpError;\r
+import org.apache.tomcat.bayeux.BayeuxException;\r
+import org.apache.tomcat.bayeux.BayeuxRequest;\r
+import org.apache.tomcat.bayeux.ClientImpl;\r
+import org.apache.tomcat.bayeux.TomcatBayeux;\r
+import org.json.JSONException;\r
+import org.json.JSONObject;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+import org.apache.tomcat.bayeux.*;\r
+\r
+/******************************************************************************\r
+ * Handshake request Bayeux message.\r
+ *\r
+ * @author Guy A. Molinari\r
+ * @author Filip Hanik\r
+ * @version 1.0\r
+ *\r
+ */\r
+public class MetaConnectRequest extends RequestBase implements BayeuxRequest {\r
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
+\r
+    static {\r
+        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_CONNECT);\r
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
+    }\r
+\r
+    public MetaConnectRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
+        super(tb, event, jsReq);\r
+        if (clientId!=null && getTomcatBayeux().hasClient(clientId)) {\r
+            event.getHttpServletRequest().setAttribute("client",getTomcatBayeux().getClient(clientId));\r
+        }\r
+    }\r
+\r
+\r
+    /**\r
+     * Check client request for validity.\r
+     *\r
+     * Per section 4.2.1 of the Bayuex spec a connect request must contain:\r
+     *  1) The "/meta/connect" channel identifier.\r
+     *  2) The clientId returned by the server after handshake.\r
+     *  3) The desired connectionType (must be one of the server's supported\r
+     *     types returned by handshake response.\r
+     *  \r
+     * @return HttpError This method returns null if no errors were found\r
+     */\r
+    public HttpError validate() {\r
+        if(clientId==null|| (!getTomcatBayeux().hasClient(clientId)))\r
+            return new HttpError(400,"Client Id not valid.", null);\r
+        if (! (Bayeux.TRANSPORT_LONG_POLL.equals(conType) || Bayeux.TRANSPORT_CALLBACK_POLL.equals(conType)))\r
+            return new HttpError(400,"Unsupported connection type.",null);\r
+        return null;//no error\r
+    }\r
+\r
+    /**\r
+     * Transition to connected state, flushing pending messages if\r
+     * available.  If there are pending subscriptions and no messages to\r
+     * flush then the connection is held until there is a pending publish\r
+     * event to be delivered to this client (Section 4.2.2 of spec).\r
+     */\r
+    public int process(int prevops) throws BayeuxException {\r
+        super.process(prevops);\r
+        response = (HashMap<String, Object>)responseTemplate.clone();\r
+        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);\r
+        boolean success = false;\r
+        HttpError error = validate();\r
+        if (error == null) {\r
+            client.setDesirectConnType(desiredConnTypeFlag);\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.RETRY_RESPONSE);\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.INTERVAL_FIELD, getReconnectInterval());\r
+            success = true;\r
+        }else {\r
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
+            response.put(Bayeux.ERROR_FIELD, error.toString());\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.HANDSHAKE_RESPONSE);\r
+            if (client==null) client = TomcatBayeux.getErrorClient();\r
+        }\r
+        response.put(Bayeux.CLIENT_FIELD, client.getId());\r
+        response.put(Bayeux.TIMESTAMP_FIELD,getTimeStamp());\r
+        try {\r
+            JSONObject obj = new JSONObject(response);\r
+            addToDeliveryQueue(client, obj);\r
+        } catch (ServletException x) {\r
+            throw new BayeuxException(x);\r
+        } catch (IOException x) {\r
+            throw new BayeuxException(x);\r
+        }\r
+        \r
+        //return immediately if there is no subscriptions\r
+        //so that we can process the next message\r
+        int result = client.isSubscribed()?1:0; \r
+\r
+        if (success && client!=null && client.hasMessages()) {\r
+            //send out messages \r
+            flushMessages(client);\r
+            result = 0; //flush out the messages\r
+        }\r
+\r
+        return result;\r
+    }\r
+}\r
+\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaDisconnectRequest.java b/modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaDisconnectRequest.java
new file mode 100644 (file)
index 0000000..be840e9
--- /dev/null
@@ -0,0 +1,105 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux.request;\r
+\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import javax.servlet.ServletException;\r
+\r
+import org.apache.catalina.CometEvent;\r
+import org.apache.tomcat.bayeux.HttpError;\r
+import org.apache.tomcat.bayeux.BayeuxException;\r
+import org.apache.tomcat.bayeux.BayeuxRequest;\r
+import org.apache.tomcat.bayeux.ClientImpl;\r
+import org.apache.tomcat.bayeux.TomcatBayeux;\r
+import org.json.JSONException;\r
+import org.json.JSONObject;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+import org.apache.tomcat.bayeux.*;\r
+import org.apache.cometd.bayeux.Channel;\r
+\r
+/******************************************************************************\r
+ * Handshake request Bayeux message.\r
+ *\r
+ * @author Guy A. Molinari\r
+ * @author Filip Hanik\r
+ * @version 1.0\r
+ *\r
+ */\r
+public class MetaDisconnectRequest extends RequestBase implements BayeuxRequest {\r
+\r
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
+\r
+    static {\r
+        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_DISCONNECT);\r
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
+    }\r
+\r
+    public MetaDisconnectRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
+        super(tb, event, jsReq);\r
+    }\r
+\r
+\r
+    /**\r
+     * Check client request for validity.\r
+     *\r
+     * Per section 4.4.1 of the Bayuex spec a connect request must contain:\r
+     *  1) The "/meta/disconnect" channel identifier.\r
+     *  2) The clientId.\r
+     *  \r
+     * @return HttpError This method returns null if no errors were found\r
+     */\r
+    public HttpError validate() {\r
+        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))\r
+            return new HttpError(400,"Client Id not valid.", null);\r
+//        if (! (Bayeux.TRANSPORT_LONG_POLL.equals(conType) || Bayeux.TRANSPORT_CALLBACK_POLL.equals(conType)))\r
+//            return new HttpError(400,"Unsupported connection type.",null);\r
+        return null;//no error\r
+    }\r
+\r
+    /**\r
+     * Disconnect a client session.\r
+     */\r
+    public int process(int prevops) throws BayeuxException {\r
+        super.process(prevops);\r
+        response = (HashMap<String, Object>)responseTemplate.clone();\r
+        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);\r
+        HttpError error = validate();\r
+        if (error == null) {\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "retry");\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("interval", getReconnectInterval());\r
+        }else {\r
+            getTomcatBayeux().remove(client);\r
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
+            response.put(Bayeux.ERROR_FIELD, error.toString());\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "none");\r
+            if (client==null) client = TomcatBayeux.getErrorClient();\r
+        }\r
+        response.put(Bayeux.CLIENT_FIELD, client.getId());\r
+        try {\r
+            JSONObject obj = new JSONObject(response);\r
+            addToDeliveryQueue(client, obj);\r
+        } catch (ServletException x) {\r
+            throw new BayeuxException(x);\r
+        } catch (IOException x) {\r
+            throw new BayeuxException(x);\r
+        }\r
+        return 0;\r
+    }\r
+}\r
+\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaHandshakeRequest.java b/modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaHandshakeRequest.java
new file mode 100644 (file)
index 0000000..bd38b9e
--- /dev/null
@@ -0,0 +1,116 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux.request;\r
+\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import javax.servlet.ServletException;\r
+\r
+import org.apache.catalina.CometEvent;\r
+import org.apache.tomcat.bayeux.HttpError;\r
+import org.apache.tomcat.bayeux.BayeuxException;\r
+import org.apache.tomcat.bayeux.BayeuxRequest;\r
+import org.apache.tomcat.bayeux.ClientImpl;\r
+import org.apache.tomcat.bayeux.TomcatBayeux;\r
+import org.json.JSONException;\r
+import org.json.JSONObject;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+import org.apache.tomcat.bayeux.*;\r
+\r
+/******************************************************************************\r
+ * Handshake request Bayeux message.\r
+ *\r
+ * @author Guy A. Molinari\r
+ * @author Filip Hanik\r
+ * @version 1.0\r
+ *\r
+ */\r
+public class MetaHandshakeRequest extends RequestBase implements BayeuxRequest {\r
+\r
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
+    \r
+    static {\r
+        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_HANDSHAKE);\r
+        responseTemplate.put(Bayeux.VERSION_FIELD,"1.0");\r
+        responseTemplate.put(Bayeux.SUPP_CONNECTION_TYPE_FIELD,new String[] { Bayeux.TRANSPORT_LONG_POLL, Bayeux.TRANSPORT_CALLBACK_POLL });\r
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
+    }\r
+\r
+    public MetaHandshakeRequest(TomcatBayeux tomcatBayeux, CometEvent event, JSONObject jsReq) throws JSONException {\r
+        super(tomcatBayeux, event, jsReq);\r
+    }\r
+    \r
+\r
+    public String getVersion() { return version; }\r
+    public String getMinimumVersion() { return minVersion; }\r
+\r
+\r
+    /**\r
+     * Check client request for validity.\r
+     *\r
+     * Per section 4.1.1 of the Bayuex spec a handshake request must contain:\r
+     *  1) The "/meta/handshake" channel identifier.\r
+     *  2) The version of the protocol supported by the client\r
+     *  3) The client's supported connection types.\r
+     *  \r
+     * @return HttpError This method returns null if no errors were found\r
+     */\r
+    public HttpError validate() {\r
+        boolean error = (version==null || version.length()==0);\r
+        if (!error) error = suppConnTypesFlag==0;\r
+        if (error) return new HttpError(400,"Invalid handshake request, supportedConnectionType field missing.",null);\r
+        else return null;\r
+    }\r
+\r
+    /**\r
+     * Generate and return a client identifier.  Return a list of\r
+     * supported connection types.  Must be a subset of or identical to\r
+     * the list of types supported by the client.  See section 4.1.2 of\r
+     * the Bayuex specification.\r
+     */\r
+    public int process(int prevops) throws BayeuxException {\r
+        super.process(prevops);\r
+        response = (HashMap<String, Object>)responseTemplate.clone();\r
+        ClientImpl client = null;\r
+        HttpError error = validate();\r
+        if (error == null) {\r
+            client = (ClientImpl) getTomcatBayeux().newClient("http-", null, false,getEvent());\r
+            clientId = client.getId();\r
+            client.setSupportedConnTypes(suppConnTypesFlag);\r
+            client.setUseJsonFiltered(getExt().get(Bayeux.JSON_COMMENT_FILTERED_FIELD) != null);\r
+            response.put(Bayeux.CLIENT_FIELD, client.getId());\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.RETRY_RESPONSE);\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.INTERVAL_FIELD, getReconnectInterval());\r
+        }else {\r
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
+            response.put(Bayeux.ERROR_FIELD, error.toString());\r
+            client = TomcatBayeux.getErrorClient();\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.NONE_RESPONSE);\r
+        }\r
+        try {\r
+            JSONObject obj = new JSONObject(response);\r
+            addToDeliveryQueue(client, obj);\r
+        } catch (ServletException x) {\r
+            throw new BayeuxException(x);\r
+        } catch (IOException x) {\r
+            throw new BayeuxException(x);\r
+        }\r
+        return 0;\r
+    }\r
+}\r
+\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaSubscribeRequest.java b/modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaSubscribeRequest.java
new file mode 100644 (file)
index 0000000..31994f3
--- /dev/null
@@ -0,0 +1,130 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux.request;\r
+\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import javax.servlet.ServletException;\r
+\r
+import org.apache.catalina.CometEvent;\r
+import org.apache.tomcat.bayeux.HttpError;\r
+import org.apache.tomcat.bayeux.BayeuxException;\r
+import org.apache.tomcat.bayeux.BayeuxRequest;\r
+import org.apache.tomcat.bayeux.ChannelImpl;\r
+import org.apache.tomcat.bayeux.ClientImpl;\r
+import org.apache.tomcat.bayeux.TomcatBayeux;\r
+import org.json.JSONException;\r
+import org.json.JSONObject;\r
+import org.apache.cometd.bayeux.Channel;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+import org.apache.tomcat.bayeux.*;\r
+\r
+/******************************************************************************\r
+ * Handshake request Bayeux message.\r
+ *\r
+ * @author Guy A. Molinari\r
+ * @author Filip Hanik\r
+ * @version 1.0\r
+ */\r
+public class MetaSubscribeRequest extends RequestBase implements BayeuxRequest {\r
+\r
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
+\r
+    static {\r
+        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_SUBSCRIBE);\r
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
+    }\r
+\r
+    public MetaSubscribeRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
+        super(tb, event, jsReq);\r
+    }\r
+\r
+\r
+    /**\r
+     * Check client request for validity.\r
+     *\r
+     * Per section 4.5.1 of the Bayuex spec a connect request must contain:\r
+     *  1) The "/meta/subscribe" channel identifier.\r
+     *  2) The clientId.\r
+     *  3) The subscription.  This is the name of the channel of interest,\r
+     *     or a pattern.\r
+     *  \r
+     * @return HttpError This method returns null if no errors were found\r
+     */\r
+    public HttpError validate() {\r
+        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))\r
+            return new HttpError(400,"Client Id not valid.", null);\r
+        if (subscription==null||subscription.length()==0)\r
+            return new HttpError(400,"Subscription missing.",null);\r
+        return null;//no error\r
+    }\r
+\r
+    /**\r
+     * Register interest for one or more channels.  Per section 2.2.1 of the\r
+     * Bayeux spec, a pattern may be specified.  Assign client to matching\r
+     * channels and inverse client to channel reference.\r
+     */\r
+    public int process(int prevops) throws BayeuxException {\r
+        super.process(prevops);\r
+        response = (HashMap<String, Object>)this.responseTemplate.clone();\r
+        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);\r
+        HttpError error = validate();\r
+        if (error == null) {\r
+            boolean wildcard = subscription.indexOf('*')!=-1;\r
+            boolean subscribed = false;\r
+            if (wildcard) {\r
+                List<Channel> channels = getTomcatBayeux().getChannels();\r
+                Iterator<Channel> it = channels.iterator();\r
+                while (it.hasNext()) {\r
+                    ChannelImpl ch = (ChannelImpl)it.next();\r
+                    if (ch.matches(subscription)) {\r
+                        ch.subscribe(client);\r
+                        subscribed = true;\r
+                    }\r
+                }\r
+            }else {\r
+                ChannelImpl ch = (ChannelImpl)getTomcatBayeux().getChannel(subscription,true);\r
+                ch.subscribe(client);\r
+                subscribed = true;\r
+            }\r
+            response.put(Bayeux.SUCCESSFUL_FIELD, Boolean.valueOf(subscribed));\r
+            response.put(Bayeux.SUBSCRIPTION_FIELD,subscription);\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "retry");\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("interval", getReconnectInterval());\r
+        }else {\r
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
+            response.put(Bayeux.ERROR_FIELD, error.toString());\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "handshake");\r
+            if (client==null) client = TomcatBayeux.getErrorClient();\r
+        }\r
+        response.put(Bayeux.CLIENT_FIELD, client.getId());\r
+        response.put(Bayeux.TIMESTAMP_FIELD,getTimeStamp());\r
+        try {\r
+            JSONObject obj = new JSONObject(response);\r
+            addToDeliveryQueue(client, obj);\r
+        } catch (ServletException x) {\r
+            throw new BayeuxException(x);\r
+        } catch (IOException x) {\r
+            throw new BayeuxException(x);\r
+        }\r
+        return 0;\r
+    }\r
+}\r
+\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaUnsubscribeRequest.java b/modules/bayeux/java/org/apache/tomcat/bayeux/request/MetaUnsubscribeRequest.java
new file mode 100644 (file)
index 0000000..69a57cd
--- /dev/null
@@ -0,0 +1,130 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux.request;\r
+\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import javax.servlet.ServletException;\r
+\r
+import org.apache.catalina.CometEvent;\r
+import org.apache.tomcat.bayeux.HttpError;\r
+import org.apache.tomcat.bayeux.BayeuxException;\r
+import org.apache.tomcat.bayeux.BayeuxRequest;\r
+import org.apache.tomcat.bayeux.ChannelImpl;\r
+import org.apache.tomcat.bayeux.ClientImpl;\r
+import org.apache.tomcat.bayeux.TomcatBayeux;\r
+import org.json.JSONException;\r
+import org.json.JSONObject;\r
+import org.apache.cometd.bayeux.Channel;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+import org.apache.tomcat.bayeux.*;\r
+\r
+/******************************************************************************\r
+ * Handshake request Bayeux message.\r
+ *\r
+ * @author Guy A. Molinari\r
+ * @author Filip Hanik\r
+ * @version 1.0\r
+ *\r
+ */\r
+public class MetaUnsubscribeRequest extends RequestBase implements BayeuxRequest {\r
+\r
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
+\r
+    static {\r
+        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_UNSUBSCRIBE);\r
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
+    }\r
+\r
+    public MetaUnsubscribeRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
+        super(tb, event, jsReq);\r
+    }\r
+\r
+\r
+    /**\r
+     * Check client request for validity.\r
+     *\r
+     * Per section 4.6.1 of the Bayuex spec a connect request must contain:\r
+     *  1) The "/meta/unsubscribe" channel identifier.\r
+     *  2) The clientId.\r
+     *  3) The subscription.  This is the name of the channel of interest,\r
+     *     or a pattern.\r
+     *  \r
+     * @return HttpError This method returns null if no errors were found\r
+     */\r
+    public HttpError validate() {\r
+        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))\r
+            return new HttpError(400,"Client Id not valid.", null);\r
+        if (subscription==null||subscription.length()==0)\r
+            return new HttpError(400,"Subscription missing.",null);\r
+        return null;//no error\r
+    }\r
+\r
+    /**\r
+     * De-register interest for one or more channels.  Per section 2.2.1 of the\r
+     * Bayeux spec, a pattern may be specified.  Sever relationships.\r
+     */\r
+    public int process(int prevops) throws BayeuxException {\r
+        super.process(prevops);\r
+        response = (HashMap<String, Object>)responseTemplate.clone();\r
+        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);\r
+        HttpError error = validate();\r
+        if (error == null) {\r
+            boolean wildcard = subscription.indexOf('*')!=-1;\r
+            boolean unsubscribed = false;\r
+            if (wildcard) {\r
+                List<Channel> channels = getTomcatBayeux().getChannels();\r
+                Iterator<Channel> it = channels.iterator();\r
+                while (it.hasNext()) {\r
+                    ChannelImpl ch = (ChannelImpl)it.next();\r
+                    if (ch.matches(subscription)) {\r
+                        ch.unsubscribe(client);\r
+                        unsubscribed = true;\r
+                    }\r
+                }\r
+            }else {\r
+                ChannelImpl ch = (ChannelImpl)getTomcatBayeux().getChannel(subscription,true);\r
+                ch.unsubscribe(client);\r
+                unsubscribed = true;\r
+            }\r
+            response.put(Bayeux.SUCCESSFUL_FIELD, Boolean.valueOf(unsubscribed));\r
+            response.put(Bayeux.SUBSCRIPTION_FIELD,subscription);\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "retry");\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("interval", getReconnectInterval());\r
+        }else {\r
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
+            response.put(Bayeux.ERROR_FIELD, error.toString());\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "handshake");\r
+            if (client==null) client = TomcatBayeux.getErrorClient();\r
+        }\r
+        response.put(Bayeux.CLIENT_FIELD, client.getId());\r
+        response.put(Bayeux.TIMESTAMP_FIELD,getTimeStamp());\r
+        try {\r
+            JSONObject obj = new JSONObject(response);\r
+            addToDeliveryQueue(client, obj);\r
+        } catch (ServletException x) {\r
+            throw new BayeuxException(x);\r
+        } catch (IOException x) {\r
+            throw new BayeuxException(x);\r
+        }\r
+        return 0;\r
+    }\r
+}\r
+\r
diff --git a/modules/bayeux/java/org/apache/tomcat/bayeux/request/PublishRequest.java b/modules/bayeux/java/org/apache/tomcat/bayeux/request/PublishRequest.java
new file mode 100644 (file)
index 0000000..fcf956c
--- /dev/null
@@ -0,0 +1,140 @@
+/*\r
+ * Licensed to the Apache Software Foundation (ASF) under one or more\r
+ * contributor license agreements.  See the NOTICE file distributed with\r
+ * this work for additional information regarding copyright ownership.\r
+ * The ASF licenses this file to You under the Apache License, Version 2.0\r
+ * (the "License"); you may not use this file except in compliance with\r
+ * the License.  You may obtain a copy of the License at\r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package org.apache.tomcat.bayeux.request;\r
+\r
+import java.io.IOException;\r
+import java.util.HashMap;\r
+import javax.servlet.ServletException;\r
+\r
+import org.apache.catalina.CometEvent;\r
+import org.apache.tomcat.bayeux.HttpError;\r
+import org.apache.tomcat.bayeux.BayeuxException;\r
+import org.apache.tomcat.bayeux.BayeuxRequest;\r
+import org.apache.tomcat.bayeux.ChannelImpl;\r
+import org.apache.tomcat.bayeux.ClientImpl;\r
+import org.apache.tomcat.bayeux.MessageImpl;\r
+import org.apache.tomcat.bayeux.TomcatBayeux;\r
+import org.json.JSONException;\r
+import org.json.JSONObject;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+import java.util.List;\r
+import org.apache.cometd.bayeux.Message;\r
+import java.util.Iterator;\r
+import org.apache.tomcat.bayeux.*;\r
+\r
+/******************************************************************************\r
+ * Handshake request Bayeux message.\r
+ *\r
+ * @author Guy A. Molinari\r
+ * @author Filip Hanik\r
+ * @version 1.0\r
+ *\r
+ */\r
+public class PublishRequest extends RequestBase implements BayeuxRequest {\r
+\r
+    JSONObject msgData = null;\r
+\r
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();\r
+\r
+    static {\r
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);\r
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());\r
+    }\r
+\r
+    public PublishRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {\r
+        super(tb, event, jsReq);\r
+    }\r
+\r
+\r
+    /**\r
+     * Check client request for validity.\r
+     *\r
+     * Per section 5.1.1 of the Bayuex spec a connect request must contain:\r
+     *  1) The channel identifier of the channel for publication.\r
+     *  2) The data to send.\r
+     *  \r
+     * @return HttpError This method returns null if no errors were found\r
+     */\r
+    public HttpError validate() {\r
+        if(channel==null|| (!this.getTomcatBayeux().hasChannel(channel)))\r
+            return new HttpError(400,"Channel Id not valid.", null);\r
+        if(data==null || data.length()==0)\r
+            return new HttpError(400,"Message data missing.", null);\r
+        try {\r
+            this.msgData = new JSONObject(data);\r
+        }catch (JSONException x) {\r
+            return new HttpError(400,"Invalid JSON object in data attribute.",x);\r
+        }\r
+        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))\r
+            return new HttpError(400,"Client Id not valid.", null);\r
+        return null;//no error\r
+    }\r
+\r
+    /**\r
+     *  Send the event message to all registered subscribers.\r
+     */\r
+    public int process(int prevops) throws BayeuxException {\r
+        super.process(prevops);\r
+        response = (HashMap<String, Object>)responseTemplate.clone();\r
+        ClientImpl client = clientId!=null?(ClientImpl)getTomcatBayeux().getClient(clientId):\r
+                                           (ClientImpl)event.getHttpServletRequest().getAttribute("client");\r
+        boolean success = false;\r
+        HttpError error = validate();\r
+        if (error == null) {\r
+            ChannelImpl chimpl = (ChannelImpl)getTomcatBayeux().getChannel(channel,false);\r
+            MessageImpl mimpl = (MessageImpl)getTomcatBayeux().newMessage(client);\r
+            \r
+            try {\r
+                String[] keys = JSONObject.getNames(msgData);\r
+                for (int i = 0; i < keys.length; i++) {\r
+                    mimpl.put(keys[i], msgData.get(keys[i]));\r
+                }\r
+                success = true;\r
+                ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.RETRY_RESPONSE);\r
+                ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.INTERVAL_FIELD, getReconnectInterval());\r
+            }catch (JSONException x) {\r
+                if (log.isErrorEnabled()) log.error("Unable to parse:"+msgData,x);\r
+                throw new BayeuxException(x);\r
+            }\r
+            chimpl.publish(mimpl);\r
+        }\r
+        if(!success) {\r
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);\r
+            response.put(Bayeux.ERROR_FIELD, error.toString());\r
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.HANDSHAKE_RESPONSE);\r
+            if (client==null) client = TomcatBayeux.getErrorClient();\r
+        }\r
+        response.put(Bayeux.CHANNEL_FIELD,channel);\r
+        response.put(Bayeux.CLIENT_FIELD, client.getId());\r
+        try {\r
+            JSONObject obj = new JSONObject(response);\r
+            addToDeliveryQueue(client, obj);\r
+        } catch (ServletException x) {\r
+            throw new BayeuxException(x);\r
+        } catch (IOException x) {\r
+            throw new BayeuxException(x);\r
+        }\r
+        \r
+        if (success && client!=null && client.hasMessages()) {\r
+            //send out messages \r
+            flushMessages(client);\r
+        }\r
+\r
+        return 0;\r
+    }\r
+}\r
+\r
diff --git a/modules/bayeux/test/org/apache/cometd/bayeux/samples/BayeuxStockTicker.java b/modules/bayeux/test/org/apache/cometd/bayeux/samples/BayeuxStockTicker.java
new file mode 100644 (file)
index 0000000..5f61d29
--- /dev/null
@@ -0,0 +1,215 @@
+package org.apache.cometd.bayeux.samples;\r
+\r
+import javax.servlet.ServletContextEvent;\r
+import javax.servlet.ServletContextListener;\r
+import javax.servlet.ServletContextAttributeListener;\r
+import javax.servlet.ServletContextAttributeEvent;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+\r
+import java.text.DecimalFormat;\r
+import java.util.List;\r
+import java.util.Random;\r
+import java.util.concurrent.atomic.AtomicInteger;\r
+import org.apache.cometd.bayeux.Client;\r
+import org.apache.cometd.bayeux.Listener;\r
+import org.apache.cometd.bayeux.Message;\r
+import org.apache.cometd.bayeux.Channel;\r
+\r
+public class BayeuxStockTicker implements ServletContextListener,\r
+        ServletContextAttributeListener, Listener {\r
+\r
+    static AtomicInteger counter = new AtomicInteger(0);\r
+    protected int id;\r
+    protected Bayeux b;\r
+    protected Client c;\r
+    protected boolean alive = true;\r
+    protected boolean initialized = false;\r
+    protected TickerThread tt = new TickerThread();\r
+\r
+    public BayeuxStockTicker() {\r
+        id = counter.incrementAndGet();\r
+        System.out.println("new listener created with id:" + id);\r
+    }\r
+\r
+    public void contextDestroyed(ServletContextEvent servletContextEvent) {\r
+        alive = false;\r
+        tt.run = false;\r
+        tt.interrupt();\r
+    }\r
+\r
+    public void contextInitialized(ServletContextEvent servletContextEvent) {\r
+    }\r
+\r
+    public void attributeAdded(ServletContextAttributeEvent scae) {\r
+        if (scae.getName().equals(Bayeux.DOJOX_COMETD_BAYEUX)) {\r
+            if (initialized) return;\r
+            initialized = true;\r
+            System.out.println("Starting stock ticker server client!");\r
+            b = (Bayeux) scae.getValue();\r
+            c = b.newClient("stock-ticker-", this);\r
+            tt.start();\r
+        }\r
+    }\r
+\r
+    public void attributeRemoved(ServletContextAttributeEvent scae) {\r
+        if (scae.getName().equals(Bayeux.DOJOX_COMETD_BAYEUX)) {\r
+            initialized = false;\r
+            b = (Bayeux) scae.getValue();\r
+            List<Channel> chs = b.getChannels();\r
+            for (Channel ch : chs) {\r
+                ch.unsubscribe(c);\r
+            }\r
+        }\r
+    }\r
+\r
+    public void attributeReplaced(\r
+            ServletContextAttributeEvent servletContextAttributeEvent) {\r
+    }\r
+\r
+    public void removed(boolean timeout) {\r
+        System.out.println("Client removed.");\r
+    }\r
+\r
+    public void deliver(Message[] msgs) {\r
+        for (int i = 0; msgs != null && i < msgs.length; i++) {\r
+            Message msg = msgs[i];\r
+            System.out.println("[stock ticker server client ]received message:" + msg);\r
+        }\r
+    }\r
+\r
+    public class TickerThread extends Thread {\r
+        public boolean run = true;\r
+\r
+        public TickerThread() {\r
+            setName("Ticker Thread");\r
+        }\r
+\r
+        public void run() {\r
+            try {\r
+                \r
+                Stock[] stocks = new Stock[] { \r
+                        new Stock("GOOG", 435.43),\r
+                        new Stock("YHOO", 27.88), \r
+                        new Stock("SPRG", 1015.55), };\r
+                for (Stock s : stocks) {\r
+                    Channel ch = b.getChannel("/stock/"+s.getSymbol(), true);\r
+                    ch.subscribe(c);\r
+                    \r
+                }\r
+                Random r = new Random(System.currentTimeMillis());\r
+                while (run) {\r
+                    for (int j = 0; j < 1; j++) {\r
+                        int i = r.nextInt() % 3;\r
+                        if (i < 0)\r
+                            i = i * (-1);\r
+                        Stock stock = stocks[i];\r
+                        double change = r.nextDouble();\r
+                        boolean plus = r.nextBoolean();\r
+                        if (plus) {\r
+                            stock.setValue(stock.getValue() + change);\r
+                        } else {\r
+                            stock.setValue(stock.getValue() - change);\r
+                        }\r
+                        Channel ch = b.getChannel("/stock/"+stock.getSymbol(), true);\r
+                        Message m = b.newMessage(c);\r
+                        m.put("stock", stock.toString());\r
+                        m.put("symbol", stock.getSymbol());\r
+                        m.put("price", stock.getValueAsString());\r
+                        m.put("change", stock.getLastChangeAsString());\r
+                        ch.publish(m);\r
+                        System.out.println("Stock: "+stock.getSymbol()+" Price: "+stock.getValueAsString()+" Change: "+stock.getLastChangeAsString());\r
+                    }\r
+                    Thread.sleep(850);\r
+                }\r
+            } catch (InterruptedException ix) {\r
+\r
+            } catch (Exception x) {\r
+                x.printStackTrace();\r
+            }\r
+        }\r
+    }\r
+\r
+    public static class Stock {\r
+        protected static DecimalFormat df = new DecimalFormat("0.00");\r
+        protected String symbol = "";\r
+        protected double value = 0.0d;\r
+        protected double lastchange = 0.0d;\r
+        protected int cnt = 0;\r
+\r
+        public Stock(String symbol, double initvalue) {\r
+            this.symbol = symbol;\r
+            this.value = initvalue;\r
+        }\r
+\r
+        public void setCnt(int c) {\r
+            this.cnt = c;\r
+        }\r
+\r
+        public int getCnt() {\r
+            return cnt;\r
+        }\r
+\r
+        public String getSymbol() {\r
+            return symbol;\r
+        }\r
+\r
+        public double getValue() {\r
+            return value;\r
+        }\r
+\r
+        public void setValue(double value) {\r
+            double old = this.value;\r
+            this.value = value;\r
+            this.lastchange = value - old;\r
+        }\r
+\r
+        public String getValueAsString() {\r
+            return df.format(value);\r
+        }\r
+\r
+        public double getLastChange() {\r
+            return this.lastchange;\r
+        }\r
+\r
+        public void setLastChange(double lastchange) {\r
+            this.lastchange = lastchange;\r
+        }\r
+\r
+        public String getLastChangeAsString() {\r
+            return df.format(lastchange);\r
+        }\r
+\r
+        public int hashCode() {\r
+            return symbol.hashCode();\r
+        }\r
+\r
+        public boolean equals(Object other) {\r
+            if (other instanceof Stock) {\r
+                return this.symbol.equals(((Stock) other).symbol);\r
+            } else {\r
+                return false;\r
+            }\r
+        }\r
+        \r
+        public String toString(){\r
+            StringBuffer buf = new StringBuffer("STOCK#");\r
+            buf.append(getSymbol());\r
+            buf.append("#");\r
+            buf.append(getValueAsString());\r
+            buf.append("#");\r
+            buf.append(getLastChangeAsString());\r
+            buf.append("#");\r
+            buf.append(String.valueOf(getCnt()));\r
+            return buf.toString();\r
+         \r
+        }\r
+\r
+        public Object clone() {\r
+            Stock s = new Stock(this.getSymbol(), this.getValue());\r
+            s.setLastChange(this.getLastChange());\r
+            s.setCnt(this.cnt);\r
+            return s;\r
+        }\r
+    }\r
+\r
+}
\ No newline at end of file
diff --git a/modules/bayeux/test/org/apache/cometd/bayeux/samples/EchoChatClient.java b/modules/bayeux/test/org/apache/cometd/bayeux/samples/EchoChatClient.java
new file mode 100644 (file)
index 0000000..6f6ca8e
--- /dev/null
@@ -0,0 +1,101 @@
+package org.apache.cometd.bayeux.samples;\r
+\r
+import javax.servlet.ServletContextEvent;\r
+import javax.servlet.ServletContextListener;\r
+import javax.servlet.ServletContextAttributeListener;\r
+import javax.servlet.ServletContextAttributeEvent;\r
+import org.apache.cometd.bayeux.Bayeux;\r
+import java.util.concurrent.atomic.AtomicInteger;\r
+import org.apache.cometd.bayeux.Client;\r
+import org.apache.cometd.bayeux.Listener;\r
+import org.apache.cometd.bayeux.Message;\r
+import org.apache.cometd.bayeux.Channel;\r
+\r
+public class EchoChatClient implements ServletContextListener, ServletContextAttributeListener, Listener {\r
+    \r
+    static AtomicInteger counter = new AtomicInteger(0);\r
+    protected int id;\r
+    protected Bayeux b;\r
+    protected Client c;\r
+    protected boolean alive = true;\r
+    protected TimestampThread tt = new TimestampThread();\r
+\r
+    public EchoChatClient() {\r
+        id = counter.incrementAndGet();\r
+        System.out.println("new listener created with id:"+id);\r
+    }\r
+\r
+    public void contextDestroyed(ServletContextEvent servletContextEvent) {\r
+        alive = false;\r
+        tt.interrupt();\r
+    }\r
+\r
+    public void contextInitialized(ServletContextEvent servletContextEvent) {\r
+    }\r
+\r
+    public void attributeAdded(ServletContextAttributeEvent scae) {\r
+        if (scae.getName().equals(Bayeux.DOJOX_COMETD_BAYEUX)) {\r
+            System.out.println("Starting echo chat client!");\r
+            b = (Bayeux)scae.getValue();\r
+            c = b.newClient("echochat-",this);\r
+            Channel ch = b.getChannel("/chat/demo",true);\r
+            ch.subscribe(c);\r
+            tt.start();\r
+        }\r
+    }\r
+\r
+    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {\r
+    }\r
+\r
+    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {\r
+    }\r
+\r
+    public void removed(boolean timeout) {\r
+        System.out.println("Client removed.");\r
+    }\r
+\r
+    public void deliver(Message[] msgs) {\r
+        for (int i=0; msgs!=null && i<msgs.length; i++) {\r
+            Message msg = msgs[i];\r
+            System.out.println("[echochatclient ]received message:" + msg);\r
+            Message m = b.newMessage(c);\r
+            m.putAll(msg);\r
+            //echo the same message\r
+            m.put("user", "echochatserver");\r
+            if (m.containsKey("msg")) {\r
+                //simple chat demo\r
+                String chat = (String) m.get("msg");\r
+                m.put("msg", "echochatserver|I received your message-" + chat.substring(chat.indexOf("|") + 1));\r
+            }\r
+            System.out.println("[echochatclient ]sending message:" + m);\r
+            msg.getChannel().publish(m);\r
+        }\r
+    }\r
+\r
+    public class TimestampThread extends Thread {\r
+        public TimestampThread() {\r
+            setDaemon(true);\r
+        }\r
+        \r
+        public void run() {\r
+            while (alive) {\r
+                try {\r
+                    sleep(5000);\r
+                    Channel ch = b.getChannel("/chat/demo",false);\r
+                    if (ch.getSubscribers().size()<=1) {\r
+                        continue;\r
+                    }\r
+                    Message m = b.newMessage(c);\r
+                    m.put("user","echochatserver");\r
+                    m.put("chat","Time is:"+new java.sql.Date(System.currentTimeMillis()).toLocaleString());\r
+                    m.put("join",false);\r
+                    ch.publish(m);\r
+                }catch (InterruptedException ignore) {\r
+                    Thread.currentThread().interrupted();\r
+                }catch (Exception x) {\r
+                    x.printStackTrace();\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
diff --git a/modules/bayeux/webapps/cometd/WEB-INF/web.xml b/modules/bayeux/webapps/cometd/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..e8d2f80
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>\r
+<web-app \r
+   xmlns="http://java.sun.com/xml/ns/javaee" \r
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"\r
+   version="2.5"> \r
+  <display-name>Cometd Test WebApp</display-name>\r
+  \r
+  <servlet>\r
+    <servlet-name>cometd</servlet-name>\r
+    <servlet-class>org.apache.tomcat.bayeux.BayeuxServlet</servlet-class>\r
+    <init-param>\r
+      <param-name>timeout</param-name>\r
+      <param-value>120000000</param-value>\r
+    </init-param>\r
+    <init-param>\r
+      <param-name>reconnectInterval</param-name>\r
+      <param-value>250</param-value>\r
+    </init-param>\r
+    <load-on-startup>1</load-on-startup>\r
+  </servlet>\r
+\r
+  <servlet-mapping>\r
+    <servlet-name>cometd</servlet-name>\r
+    <url-pattern>/cometd/*</url-pattern>\r
+  </servlet-mapping>\r
+  \r
+  <listener>\r
+    <listener-class>org.apache.cometd.bayeux.samples.EchoChatClient</listener-class>\r
+  </listener>\r
+  <listener>\r
+    <listener-class>org.apache.cometd.bayeux.samples.BayeuxStockTicker</listener-class>\r
+  </listener>\r
+  \r
+</web-app>\r
+\r
+\r
diff --git a/modules/bayeux/webapps/cometd/examples/simplechat/cometdchat.htm b/modules/bayeux/webapps/cometd/examples/simplechat/cometdchat.htm
new file mode 100644 (file)
index 0000000..4369f6a
--- /dev/null
@@ -0,0 +1,114 @@
+<html>\r
+<header><title>Comet Simple Chat Application</title>\r
+\r
+<script type="text/javascript" src="../../dojo/dojo.js.uncompressed.js"></script>\r
+<script type="text/javascript" src="../../dojox/cometd.js"></script>\r
+<script type="text/javascript" src="../../dojox/cometd/_base.js"></script>\r
+\r
+<script type="text/javascript">\r
+\r
+dojo.require("dojox.cometd");\r
+\r
+dojo.addOnLoad(function() {\r
+  dojo.byId("message").style.visibility='hidden';\r
+  dojox.cometd.init("/cometd/cometd");\r
+});\r
+\r
+\r
+function trim(str) {\r
+    return str.replace(/(^\s+|\s+$)/g,'');\r
+}\r
+\r
+\r
+function clear() {\r
+  dojo.byId("msgtext").value = "";\r
+  dojo.byId("msgtext").focus();\r
+}\r
+\r
+\r
+function enterKeyHandler(e) {\r
+if (!e) e = window.event;\r
+   if (e.keyCode == 13) {\r
+      send(trim(dojo.byId("msgtext").value));\r
+      clear();\r
+   }\r
+\r
+}\r
+\r
+\r
+function connect() {\r
+  dojox.cometd.subscribe("/chat/demo", onMsgEvent);\r
+  dojo.byId("login").style.visibility='hidden';\r
+  dojo.byId("message").style.visibility='visible';\r
+  send("Has joined the chat room");\r
+  clear();\r
+  dojo.byId("msgtext").onkeydown = enterKeyHandler;\r
+  dojo.byId("myname").appendChild(document.createTextNode("-> " + dojo.byId("scrname").value + " <-"));\r
+}\r
+\r
+\r
+function onMsgEvent(event) {\r
+\r
+   // Break apart the text string into screen name and message parts.\r
+   var str = trim(event.data.msg);\r
+   var scrname = ""; \r
+   if (str.match(/^.*[|].*$/)) {\r
+       var spl = str.split("|");\r
+       scrname = spl[0];\r
+       str = " - " + spl[1];\r
+   }\r
+\r
+   // Insert the screen name in red and the message black into the DOM\r
+   var newP = document.createElement("p");\r
+   var fnt1 = document.createElement("font");\r
+   var attr1 = document.createAttribute("color");\r
+   attr1.nodeValue = "red";\r
+   fnt1.setAttributeNode(attr1);\r
+\r
+   var newT = document.createTextNode(scrname);\r
+   fnt1.appendChild(newT);\r
+\r
+   newP.appendChild(fnt1);  \r
+\r
+   var fnt2 = document.createElement("font");\r
+   var attr2 = document.createAttribute("color");\r
+   attr2.nodeValue = "black";\r
+   fnt2.setAttributeNode(attr2);\r
+\r
+   var newT2 = document.createTextNode(str);\r
+   fnt2.appendChild(newT2);\r
+\r
+   newP.appendChild(fnt2);  \r
+\r
+   dojo.byId("dialog").appendChild(newP)\r
+}\r
+\r
+\r
+function send(msg) {\r
+  var scrname = dojo.byId("scrname").value;\r
+  var evt = {'data': { 'msg': trim(scrname) + '|' + msg }};\r
+  onMsgEvent(evt);  // Echo local\r
+  dojox.cometd.publish("/chat/demo", evt.data);\r
+}\r
+\r
+\r
+</script>\r
+\r
+</head>\r
+</header>\r
+<body>\r
+<form>\r
+<div id="login">\r
+Screen name:&nbsp;<input type="text" id="scrname">\r
+<input type=Button Id=logbtn value=Connect onClick=connect()><br/>Type a screen name and click the 'Connect' button\r
+</div>\r
+\r
+<div id="dialog"></div>\r
+<hr/>\r
+<div id="message">\r
+<div id="myname"></div> Is my screen name<br/>\r
+<textarea rows="3" cols="50" id="msgtext"></textarea>[ENTER] sends message</div>\r
+</form>\r
+</body>\r
+</html>\r
+\r
diff --git a/modules/bayeux/webapps/cometd/examples/simplechat/ticker.html b/modules/bayeux/webapps/cometd/examples/simplechat/ticker.html
new file mode 100644 (file)
index 0000000..3a88447
--- /dev/null
@@ -0,0 +1,128 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">\r
+<html>\r
+<head>\r
+<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1" >\r
+<title>Bayeux Stock Ticker</title>\r
+<script type="text/javascript" src="../../dojo/dojo.js.uncompressed.js"></script>\r
+<script type="text/javascript" src="../../dojox/cometd.js"></script>\r
+<script type="text/javascript" src="../../dojox/cometd/_base.js"></script>\r
+<script type="text/javascript">\r
+\r
+dojo.require("dojox.cometd");\r
+\r
+dojo.addOnUnload(function() {\r
+         dojox.cometd.init("/cometd/cometd");\r
+         dojox.cometd.startBatch();\r
+         dojox.cometd.unsubscribe("/stock/GOOG", this,"");\r
+         dojox.cometd.unsubscribe("/stock/YHOO", this,"");\r
+         dojox.cometd.unsubscribe("/stock/SPRG", this,"");\r
+         dojox.cometd.endBatch();\r
+       });\r
+\r
+\r
+dojo.addOnLoad(function() {\r
+  dojox.cometd.init("/cometd/cometd");\r
+  dojox.cometd.startBatch();\r
+  dojox.cometd.subscribe("/stock/GOOG", onMsgEvent);\r
+  dojox.cometd.subscribe("/stock/YHOO", onMsgEvent);\r
+  dojox.cometd.subscribe("/stock/SPRG", onMsgEvent);\r
+  dojox.cometd.endBatch();\r
+});\r
+\r
+\r
+function subscribe(box, symbol) {\r
+       if (box.checked) {\r
+               dojox.cometd.subscribe("/stock/"+symbol, onMsgEvent);\r
+               var rowCurrent = dojo.byId("row."+symbol);\r
+               rowCurrent.bgColor="white";\r
+       } else {\r
+               dojox.cometd.unsubscribe("/stock/"+symbol, onMsgEvent);\r
+               var rowCurrent = dojo.byId("row."+symbol);\r
+               rowCurrent.bgColor="gray";\r
+       }\r
+}\r
+\r
+function removeChildrenFromNode(node)\r
+{\r
+   if(node == undefined || node == null)\r
+   {\r
+      return;\r
+   }\r
+\r
+   var len = node.childNodes.length;\r
+\r
+       while (node.hasChildNodes())\r
+       {\r
+         node.removeChild(node.firstChild);\r
+       }\r
+}\r
+\r
+function onMsgEvent(event) {\r
+   // Break apart the text string into screen name and message parts.\r
+   var symbol = event.data.symbol;\r
+   var price = event.data.price;\r
+   var pricechange = event.data.change;\r
+   //alert("symbol: "+symbol+" price: "+price+" change: "+pricechange);\r
+\r
+   var pricenode = dojo.byId("price."+symbol);\r
+   var changenode = dojo.byId("change."+symbol);\r
+   removeChildrenFromNode(pricenode);\r
+   removeChildrenFromNode(changenode);\r
+   var pricelabel = document.createTextNode(price);\r
+   pricelabel.value = price;\r
+   var changelabel = document.createTextNode(pricechange);\r
+   changelabel.value = pricechange;\r
+   pricenode.appendChild(pricelabel);\r
+   changenode.appendChild(changelabel);\r
+\r
+   var table = dojo.byId("stocktable");  \r
+   var rows = table.getElementsByTagName("tr");  \r
+   for(i = 0; i < rows.length; i++){\r
+          if (rows[i].bgColor != "gray") {\r
+              rows[i].bgColor = "white"; \r
+          }\r
+   }          \r
+   //manipulate rows \r
+   var rowCurrent = dojo.byId("row."+symbol);\r
+   if (pricechange<=0) {\r
+       rowCurrent.bgColor = "red";\r
+   } else {\r
+          rowCurrent.bgColor = "cyan";\r
+   }\r
+}\r
+\r
+\r
+</script>\r
+</head>\r
+<body bgcolor="#ffffff">\r
+<h1 align="center">Bayeux Stock Ticker</h1>\r
+<h2 align="left"> &nbsp;</h2>\r
+<p>\r
+<table id="stocktable" cellspacing="0" cellpadding="3" width="100%" align="center" border="0">\r
+  <tr id="row.HEADER">\r
+    <td>SYMBOL</td>\r
+    <td>PRICE</td>\r
+    <td>LAST CHANGE</td>\r
+    <td>SUBSCRIBE</td></tr>\r
+  <tr id="row.SPRG">\r
+    <td>SPRG</td>\r
+    <td id="price.SPRG"></td>\r
+    <td id="change.SPRG"></td>\r
+    <td id="check.SPRG"><input type="checkbox" id="check.SPRG" checked onClick="subscribe(this,'SPRG')"></td>\r
+  </tr>\r
+  <tr id="row.GOOG">\r
+    <td>GOOG</td>\r
+    <td id="price.GOOG"></td>\r
+    <td id="change.GOOG"></td>\r
+    <td id="check.GOOG"><input type="checkbox" id="check.GOOG" checked  onClick="subscribe(this,'GOOG')"></td>\r
+  </tr>\r
+  <tr id="row.YHOO">\r
+    <td>YHOO</td>\r
+    <td id="price.YHOO"></td>\r
+    <td id="change.YHOO"></td>\r
+    <td id="check.YHOO"><input type="checkbox" id="check.GOOG" checked  onClick="subscribe(this,'YHOO')"></td>\r
+  </tr>\r
+</table>\r
+</p>\r
+</body>\r
+</html>
\ No newline at end of file
diff --git a/modules/bayeux/webapps/cometd/index.html b/modules/bayeux/webapps/cometd/index.html
new file mode 100644 (file)
index 0000000..9a7d6d7
--- /dev/null
@@ -0,0 +1,7 @@
+\r
+<h1>Cometd demo</h1>\r
+\r
+<p>\r
+Try the <a href="examples/simplechat/cometdchat.htm">Simple Chat Demo</a>.</br>\r
+Try the <a href="examples/simplechat/ticker.html">Stock Ticker Demo</a>.</br>\r
+</p>\r
diff --git a/test/org/apache/cometd/bayeux/samples/BayeuxStockTicker.java b/test/org/apache/cometd/bayeux/samples/BayeuxStockTicker.java
deleted file mode 100644 (file)
index 5f61d29..0000000
+++ /dev/null
@@ -1,215 +0,0 @@
-package org.apache.cometd.bayeux.samples;\r
-\r
-import javax.servlet.ServletContextEvent;\r
-import javax.servlet.ServletContextListener;\r
-import javax.servlet.ServletContextAttributeListener;\r
-import javax.servlet.ServletContextAttributeEvent;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-\r
-import java.text.DecimalFormat;\r
-import java.util.List;\r
-import java.util.Random;\r
-import java.util.concurrent.atomic.AtomicInteger;\r
-import org.apache.cometd.bayeux.Client;\r
-import org.apache.cometd.bayeux.Listener;\r
-import org.apache.cometd.bayeux.Message;\r
-import org.apache.cometd.bayeux.Channel;\r
-\r
-public class BayeuxStockTicker implements ServletContextListener,\r
-        ServletContextAttributeListener, Listener {\r
-\r
-    static AtomicInteger counter = new AtomicInteger(0);\r
-    protected int id;\r
-    protected Bayeux b;\r
-    protected Client c;\r
-    protected boolean alive = true;\r
-    protected boolean initialized = false;\r
-    protected TickerThread tt = new TickerThread();\r
-\r
-    public BayeuxStockTicker() {\r
-        id = counter.incrementAndGet();\r
-        System.out.println("new listener created with id:" + id);\r
-    }\r
-\r
-    public void contextDestroyed(ServletContextEvent servletContextEvent) {\r
-        alive = false;\r
-        tt.run = false;\r
-        tt.interrupt();\r
-    }\r
-\r
-    public void contextInitialized(ServletContextEvent servletContextEvent) {\r
-    }\r
-\r
-    public void attributeAdded(ServletContextAttributeEvent scae) {\r
-        if (scae.getName().equals(Bayeux.DOJOX_COMETD_BAYEUX)) {\r
-            if (initialized) return;\r
-            initialized = true;\r
-            System.out.println("Starting stock ticker server client!");\r
-            b = (Bayeux) scae.getValue();\r
-            c = b.newClient("stock-ticker-", this);\r
-            tt.start();\r
-        }\r
-    }\r
-\r
-    public void attributeRemoved(ServletContextAttributeEvent scae) {\r
-        if (scae.getName().equals(Bayeux.DOJOX_COMETD_BAYEUX)) {\r
-            initialized = false;\r
-            b = (Bayeux) scae.getValue();\r
-            List<Channel> chs = b.getChannels();\r
-            for (Channel ch : chs) {\r
-                ch.unsubscribe(c);\r
-            }\r
-        }\r
-    }\r
-\r
-    public void attributeReplaced(\r
-            ServletContextAttributeEvent servletContextAttributeEvent) {\r
-    }\r
-\r
-    public void removed(boolean timeout) {\r
-        System.out.println("Client removed.");\r
-    }\r
-\r
-    public void deliver(Message[] msgs) {\r
-        for (int i = 0; msgs != null && i < msgs.length; i++) {\r
-            Message msg = msgs[i];\r
-            System.out.println("[stock ticker server client ]received message:" + msg);\r
-        }\r
-    }\r
-\r
-    public class TickerThread extends Thread {\r
-        public boolean run = true;\r
-\r
-        public TickerThread() {\r
-            setName("Ticker Thread");\r
-        }\r
-\r
-        public void run() {\r
-            try {\r
-                \r
-                Stock[] stocks = new Stock[] { \r
-                        new Stock("GOOG", 435.43),\r
-                        new Stock("YHOO", 27.88), \r
-                        new Stock("SPRG", 1015.55), };\r
-                for (Stock s : stocks) {\r
-                    Channel ch = b.getChannel("/stock/"+s.getSymbol(), true);\r
-                    ch.subscribe(c);\r
-                    \r
-                }\r
-                Random r = new Random(System.currentTimeMillis());\r
-                while (run) {\r
-                    for (int j = 0; j < 1; j++) {\r
-                        int i = r.nextInt() % 3;\r
-                        if (i < 0)\r
-                            i = i * (-1);\r
-                        Stock stock = stocks[i];\r
-                        double change = r.nextDouble();\r
-                        boolean plus = r.nextBoolean();\r
-                        if (plus) {\r
-                            stock.setValue(stock.getValue() + change);\r
-                        } else {\r
-                            stock.setValue(stock.getValue() - change);\r
-                        }\r
-                        Channel ch = b.getChannel("/stock/"+stock.getSymbol(), true);\r
-                        Message m = b.newMessage(c);\r
-                        m.put("stock", stock.toString());\r
-                        m.put("symbol", stock.getSymbol());\r
-                        m.put("price", stock.getValueAsString());\r
-                        m.put("change", stock.getLastChangeAsString());\r
-                        ch.publish(m);\r
-                        System.out.println("Stock: "+stock.getSymbol()+" Price: "+stock.getValueAsString()+" Change: "+stock.getLastChangeAsString());\r
-                    }\r
-                    Thread.sleep(850);\r
-                }\r
-            } catch (InterruptedException ix) {\r
-\r
-            } catch (Exception x) {\r
-                x.printStackTrace();\r
-            }\r
-        }\r
-    }\r
-\r
-    public static class Stock {\r
-        protected static DecimalFormat df = new DecimalFormat("0.00");\r
-        protected String symbol = "";\r
-        protected double value = 0.0d;\r
-        protected double lastchange = 0.0d;\r
-        protected int cnt = 0;\r
-\r
-        public Stock(String symbol, double initvalue) {\r
-            this.symbol = symbol;\r
-            this.value = initvalue;\r
-        }\r
-\r
-        public void setCnt(int c) {\r
-            this.cnt = c;\r
-        }\r
-\r
-        public int getCnt() {\r
-            return cnt;\r
-        }\r
-\r
-        public String getSymbol() {\r
-            return symbol;\r
-        }\r
-\r
-        public double getValue() {\r
-            return value;\r
-        }\r
-\r
-        public void setValue(double value) {\r
-            double old = this.value;\r
-            this.value = value;\r
-            this.lastchange = value - old;\r
-        }\r
-\r
-        public String getValueAsString() {\r
-            return df.format(value);\r
-        }\r
-\r
-        public double getLastChange() {\r
-            return this.lastchange;\r
-        }\r
-\r
-        public void setLastChange(double lastchange) {\r
-            this.lastchange = lastchange;\r
-        }\r
-\r
-        public String getLastChangeAsString() {\r
-            return df.format(lastchange);\r
-        }\r
-\r
-        public int hashCode() {\r
-            return symbol.hashCode();\r
-        }\r
-\r
-        public boolean equals(Object other) {\r
-            if (other instanceof Stock) {\r
-                return this.symbol.equals(((Stock) other).symbol);\r
-            } else {\r
-                return false;\r
-            }\r
-        }\r
-        \r
-        public String toString(){\r
-            StringBuffer buf = new StringBuffer("STOCK#");\r
-            buf.append(getSymbol());\r
-            buf.append("#");\r
-            buf.append(getValueAsString());\r
-            buf.append("#");\r
-            buf.append(getLastChangeAsString());\r
-            buf.append("#");\r
-            buf.append(String.valueOf(getCnt()));\r
-            return buf.toString();\r
-         \r
-        }\r
-\r
-        public Object clone() {\r
-            Stock s = new Stock(this.getSymbol(), this.getValue());\r
-            s.setLastChange(this.getLastChange());\r
-            s.setCnt(this.cnt);\r
-            return s;\r
-        }\r
-    }\r
-\r
-}
\ No newline at end of file
diff --git a/test/org/apache/cometd/bayeux/samples/EchoChatClient.java b/test/org/apache/cometd/bayeux/samples/EchoChatClient.java
deleted file mode 100644 (file)
index 6f6ca8e..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.apache.cometd.bayeux.samples;\r
-\r
-import javax.servlet.ServletContextEvent;\r
-import javax.servlet.ServletContextListener;\r
-import javax.servlet.ServletContextAttributeListener;\r
-import javax.servlet.ServletContextAttributeEvent;\r
-import org.apache.cometd.bayeux.Bayeux;\r
-import java.util.concurrent.atomic.AtomicInteger;\r
-import org.apache.cometd.bayeux.Client;\r
-import org.apache.cometd.bayeux.Listener;\r
-import org.apache.cometd.bayeux.Message;\r
-import org.apache.cometd.bayeux.Channel;\r
-\r
-public class EchoChatClient implements ServletContextListener, ServletContextAttributeListener, Listener {\r
-    \r
-    static AtomicInteger counter = new AtomicInteger(0);\r
-    protected int id;\r
-    protected Bayeux b;\r
-    protected Client c;\r
-    protected boolean alive = true;\r
-    protected TimestampThread tt = new TimestampThread();\r
-\r
-    public EchoChatClient() {\r
-        id = counter.incrementAndGet();\r
-        System.out.println("new listener created with id:"+id);\r
-    }\r
-\r
-    public void contextDestroyed(ServletContextEvent servletContextEvent) {\r
-        alive = false;\r
-        tt.interrupt();\r
-    }\r
-\r
-    public void contextInitialized(ServletContextEvent servletContextEvent) {\r
-    }\r
-\r
-    public void attributeAdded(ServletContextAttributeEvent scae) {\r
-        if (scae.getName().equals(Bayeux.DOJOX_COMETD_BAYEUX)) {\r
-            System.out.println("Starting echo chat client!");\r
-            b = (Bayeux)scae.getValue();\r
-            c = b.newClient("echochat-",this);\r
-            Channel ch = b.getChannel("/chat/demo",true);\r
-            ch.subscribe(c);\r
-            tt.start();\r
-        }\r
-    }\r
-\r
-    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {\r
-    }\r
-\r
-    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {\r
-    }\r
-\r
-    public void removed(boolean timeout) {\r
-        System.out.println("Client removed.");\r
-    }\r
-\r
-    public void deliver(Message[] msgs) {\r
-        for (int i=0; msgs!=null && i<msgs.length; i++) {\r
-            Message msg = msgs[i];\r
-            System.out.println("[echochatclient ]received message:" + msg);\r
-            Message m = b.newMessage(c);\r
-            m.putAll(msg);\r
-            //echo the same message\r
-            m.put("user", "echochatserver");\r
-            if (m.containsKey("msg")) {\r
-                //simple chat demo\r
-                String chat = (String) m.get("msg");\r
-                m.put("msg", "echochatserver|I received your message-" + chat.substring(chat.indexOf("|") + 1));\r
-            }\r
-            System.out.println("[echochatclient ]sending message:" + m);\r
-            msg.getChannel().publish(m);\r
-        }\r
-    }\r
-\r
-    public class TimestampThread extends Thread {\r
-        public TimestampThread() {\r
-            setDaemon(true);\r
-        }\r
-        \r
-        public void run() {\r
-            while (alive) {\r
-                try {\r
-                    sleep(5000);\r
-                    Channel ch = b.getChannel("/chat/demo",false);\r
-                    if (ch.getSubscribers().size()<=1) {\r
-                        continue;\r
-                    }\r
-                    Message m = b.newMessage(c);\r
-                    m.put("user","echochatserver");\r
-                    m.put("chat","Time is:"+new java.sql.Date(System.currentTimeMillis()).toLocaleString());\r
-                    m.put("join",false);\r
-                    ch.publish(m);\r
-                }catch (InterruptedException ignore) {\r
-                    Thread.currentThread().interrupted();\r
-                }catch (Exception x) {\r
-                    x.printStackTrace();\r
-                }\r
-            }\r
-        }\r
-    }\r
-}\r
diff --git a/webapps/cometd/WEB-INF/web.xml b/webapps/cometd/WEB-INF/web.xml
deleted file mode 100644 (file)
index e8d2f80..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>\r
-<web-app \r
-   xmlns="http://java.sun.com/xml/ns/javaee" \r
-   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
-   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"\r
-   version="2.5"> \r
-  <display-name>Cometd Test WebApp</display-name>\r
-  \r
-  <servlet>\r
-    <servlet-name>cometd</servlet-name>\r
-    <servlet-class>org.apache.tomcat.bayeux.BayeuxServlet</servlet-class>\r
-    <init-param>\r
-      <param-name>timeout</param-name>\r
-      <param-value>120000000</param-value>\r
-    </init-param>\r
-    <init-param>\r
-      <param-name>reconnectInterval</param-name>\r
-      <param-value>250</param-value>\r
-    </init-param>\r
-    <load-on-startup>1</load-on-startup>\r
-  </servlet>\r
-\r
-  <servlet-mapping>\r
-    <servlet-name>cometd</servlet-name>\r
-    <url-pattern>/cometd/*</url-pattern>\r
-  </servlet-mapping>\r
-  \r
-  <listener>\r
-    <listener-class>org.apache.cometd.bayeux.samples.EchoChatClient</listener-class>\r
-  </listener>\r
-  <listener>\r
-    <listener-class>org.apache.cometd.bayeux.samples.BayeuxStockTicker</listener-class>\r
-  </listener>\r
-  \r
-</web-app>\r
-\r
-\r
diff --git a/webapps/cometd/examples/simplechat/cometdchat.htm b/webapps/cometd/examples/simplechat/cometdchat.htm
deleted file mode 100644 (file)
index 4369f6a..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-<html>\r
-<header><title>Comet Simple Chat Application</title>\r
-\r
-<script type="text/javascript" src="../../dojo/dojo.js.uncompressed.js"></script>\r
-<script type="text/javascript" src="../../dojox/cometd.js"></script>\r
-<script type="text/javascript" src="../../dojox/cometd/_base.js"></script>\r
-\r
-<script type="text/javascript">\r
-\r
-dojo.require("dojox.cometd");\r
-\r
-dojo.addOnLoad(function() {\r
-  dojo.byId("message").style.visibility='hidden';\r
-  dojox.cometd.init("/cometd/cometd");\r
-});\r
-\r
-\r
-function trim(str) {\r
-    return str.replace(/(^\s+|\s+$)/g,'');\r
-}\r
-\r
-\r
-function clear() {\r
-  dojo.byId("msgtext").value = "";\r
-  dojo.byId("msgtext").focus();\r
-}\r
-\r
-\r
-function enterKeyHandler(e) {\r
-if (!e) e = window.event;\r
-   if (e.keyCode == 13) {\r
-      send(trim(dojo.byId("msgtext").value));\r
-      clear();\r
-   }\r
-\r
-}\r
-\r
-\r
-function connect() {\r
-  dojox.cometd.subscribe("/chat/demo", onMsgEvent);\r
-  dojo.byId("login").style.visibility='hidden';\r
-  dojo.byId("message").style.visibility='visible';\r
-  send("Has joined the chat room");\r
-  clear();\r
-  dojo.byId("msgtext").onkeydown = enterKeyHandler;\r
-  dojo.byId("myname").appendChild(document.createTextNode("-> " + dojo.byId("scrname").value + " <-"));\r
-}\r
-\r
-\r
-function onMsgEvent(event) {\r
-\r
-   // Break apart the text string into screen name and message parts.\r
-   var str = trim(event.data.msg);\r
-   var scrname = ""; \r
-   if (str.match(/^.*[|].*$/)) {\r
-       var spl = str.split("|");\r
-       scrname = spl[0];\r
-       str = " - " + spl[1];\r
-   }\r
-\r
-   // Insert the screen name in red and the message black into the DOM\r
-   var newP = document.createElement("p");\r
-   var fnt1 = document.createElement("font");\r
-   var attr1 = document.createAttribute("color");\r
-   attr1.nodeValue = "red";\r
-   fnt1.setAttributeNode(attr1);\r
-\r
-   var newT = document.createTextNode(scrname);\r
-   fnt1.appendChild(newT);\r
-\r
-   newP.appendChild(fnt1);  \r
-\r
-   var fnt2 = document.createElement("font");\r
-   var attr2 = document.createAttribute("color");\r
-   attr2.nodeValue = "black";\r
-   fnt2.setAttributeNode(attr2);\r
-\r
-   var newT2 = document.createTextNode(str);\r
-   fnt2.appendChild(newT2);\r
-\r
-   newP.appendChild(fnt2);  \r
-\r
-   dojo.byId("dialog").appendChild(newP)\r
-}\r
-\r
-\r
-function send(msg) {\r
-  var scrname = dojo.byId("scrname").value;\r
-  var evt = {'data': { 'msg': trim(scrname) + '|' + msg }};\r
-  onMsgEvent(evt);  // Echo local\r
-  dojox.cometd.publish("/chat/demo", evt.data);\r
-}\r
-\r
-\r
-</script>\r
-\r
-</head>\r
-</header>\r
-<body>\r
-<form>\r
-<div id="login">\r
-Screen name:&nbsp;<input type="text" id="scrname">\r
-<input type=Button Id=logbtn value=Connect onClick=connect()><br/>Type a screen name and click the 'Connect' button\r
-</div>\r
-\r
-<div id="dialog"></div>\r
-<hr/>\r
-<div id="message">\r
-<div id="myname"></div> Is my screen name<br/>\r
-<textarea rows="3" cols="50" id="msgtext"></textarea>[ENTER] sends message</div>\r
-</form>\r
-</body>\r
-</html>\r
-\r
diff --git a/webapps/cometd/examples/simplechat/ticker.html b/webapps/cometd/examples/simplechat/ticker.html
deleted file mode 100644 (file)
index 3a88447..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">\r
-<html>\r
-<head>\r
-<meta http-equiv="Content-Type" content="text/html;charset=ISO-8859-1" >\r
-<title>Bayeux Stock Ticker</title>\r
-<script type="text/javascript" src="../../dojo/dojo.js.uncompressed.js"></script>\r
-<script type="text/javascript" src="../../dojox/cometd.js"></script>\r
-<script type="text/javascript" src="../../dojox/cometd/_base.js"></script>\r
-<script type="text/javascript">\r
-\r
-dojo.require("dojox.cometd");\r
-\r
-dojo.addOnUnload(function() {\r
-         dojox.cometd.init("/cometd/cometd");\r
-         dojox.cometd.startBatch();\r
-         dojox.cometd.unsubscribe("/stock/GOOG", this,"");\r
-         dojox.cometd.unsubscribe("/stock/YHOO", this,"");\r
-         dojox.cometd.unsubscribe("/stock/SPRG", this,"");\r
-         dojox.cometd.endBatch();\r
-       });\r
-\r
-\r
-dojo.addOnLoad(function() {\r
-  dojox.cometd.init("/cometd/cometd");\r
-  dojox.cometd.startBatch();\r
-  dojox.cometd.subscribe("/stock/GOOG", onMsgEvent);\r
-  dojox.cometd.subscribe("/stock/YHOO", onMsgEvent);\r
-  dojox.cometd.subscribe("/stock/SPRG", onMsgEvent);\r
-  dojox.cometd.endBatch();\r
-});\r
-\r
-\r
-function subscribe(box, symbol) {\r
-       if (box.checked) {\r
-               dojox.cometd.subscribe("/stock/"+symbol, onMsgEvent);\r
-               var rowCurrent = dojo.byId("row."+symbol);\r
-               rowCurrent.bgColor="white";\r
-       } else {\r
-               dojox.cometd.unsubscribe("/stock/"+symbol, onMsgEvent);\r
-               var rowCurrent = dojo.byId("row."+symbol);\r
-               rowCurrent.bgColor="gray";\r
-       }\r
-}\r
-\r
-function removeChildrenFromNode(node)\r
-{\r
-   if(node == undefined || node == null)\r
-   {\r
-      return;\r
-   }\r
-\r
-   var len = node.childNodes.length;\r
-\r
-       while (node.hasChildNodes())\r
-       {\r
-         node.removeChild(node.firstChild);\r
-       }\r
-}\r
-\r
-function onMsgEvent(event) {\r
-   // Break apart the text string into screen name and message parts.\r
-   var symbol = event.data.symbol;\r
-   var price = event.data.price;\r
-   var pricechange = event.data.change;\r
-   //alert("symbol: "+symbol+" price: "+price+" change: "+pricechange);\r
-\r
-   var pricenode = dojo.byId("price."+symbol);\r
-   var changenode = dojo.byId("change."+symbol);\r
-   removeChildrenFromNode(pricenode);\r
-   removeChildrenFromNode(changenode);\r
-   var pricelabel = document.createTextNode(price);\r
-   pricelabel.value = price;\r
-   var changelabel = document.createTextNode(pricechange);\r
-   changelabel.value = pricechange;\r
-   pricenode.appendChild(pricelabel);\r
-   changenode.appendChild(changelabel);\r
-\r
-   var table = dojo.byId("stocktable");  \r
-   var rows = table.getElementsByTagName("tr");  \r
-   for(i = 0; i < rows.length; i++){\r
-          if (rows[i].bgColor != "gray") {\r
-              rows[i].bgColor = "white"; \r
-          }\r
-   }          \r
-   //manipulate rows \r
-   var rowCurrent = dojo.byId("row."+symbol);\r
-   if (pricechange<=0) {\r
-       rowCurrent.bgColor = "red";\r
-   } else {\r
-          rowCurrent.bgColor = "cyan";\r
-   }\r
-}\r
-\r
-\r
-</script>\r
-</head>\r
-<body bgcolor="#ffffff">\r
-<h1 align="center">Bayeux Stock Ticker</h1>\r
-<h2 align="left"> &nbsp;</h2>\r
-<p>\r
-<table id="stocktable" cellspacing="0" cellpadding="3" width="100%" align="center" border="0">\r
-  <tr id="row.HEADER">\r
-    <td>SYMBOL</td>\r
-    <td>PRICE</td>\r
-    <td>LAST CHANGE</td>\r
-    <td>SUBSCRIBE</td></tr>\r
-  <tr id="row.SPRG">\r
-    <td>SPRG</td>\r
-    <td id="price.SPRG"></td>\r
-    <td id="change.SPRG"></td>\r
-    <td id="check.SPRG"><input type="checkbox" id="check.SPRG" checked onClick="subscribe(this,'SPRG')"></td>\r
-  </tr>\r
-  <tr id="row.GOOG">\r
-    <td>GOOG</td>\r
-    <td id="price.GOOG"></td>\r
-    <td id="change.GOOG"></td>\r
-    <td id="check.GOOG"><input type="checkbox" id="check.GOOG" checked  onClick="subscribe(this,'GOOG')"></td>\r
-  </tr>\r
-  <tr id="row.YHOO">\r
-    <td>YHOO</td>\r
-    <td id="price.YHOO"></td>\r
-    <td id="change.YHOO"></td>\r
-    <td id="check.YHOO"><input type="checkbox" id="check.GOOG" checked  onClick="subscribe(this,'YHOO')"></td>\r
-  </tr>\r
-</table>\r
-</p>\r
-</body>\r
-</html>
\ No newline at end of file
diff --git a/webapps/cometd/index.html b/webapps/cometd/index.html
deleted file mode 100644 (file)
index 9a7d6d7..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-\r
-<h1>Cometd demo</h1>\r
-\r
-<p>\r
-Try the <a href="examples/simplechat/cometdchat.htm">Simple Chat Demo</a>.</br>\r
-Try the <a href="examples/simplechat/ticker.html">Stock Ticker Demo</a>.</br>\r
-</p>\r