You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by fh...@apache.org on 2008/09/02 22:00:38 UTC

svn commit: r691359 [2/8] - in /tomcat/trunk: ./ java/org/apache/cometd/ java/org/apache/cometd/bayeux/ java/org/apache/tomcat/bayeux/ java/org/apache/tomcat/bayeux/request/ test/org/apache/cometd/ test/org/apache/cometd/bayeux/ test/org/apache/cometd/...

Added: tomcat/trunk/java/org/apache/tomcat/bayeux/RequestFactory.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/bayeux/RequestFactory.java?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/bayeux/RequestFactory.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/bayeux/RequestFactory.java Tue Sep  2 13:00:36 2008
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+package org.apache.tomcat.bayeux;
+
+import org.json.JSONObject;
+import org.apache.tomcat.bayeux.request.MetaHandshakeRequest;
+import org.apache.catalina.CometEvent;
+import org.json.JSONException;
+import org.apache.tomcat.bayeux.request.MetaConnectRequest;
+import org.apache.tomcat.bayeux.request.MetaDisconnectRequest;
+import org.apache.tomcat.bayeux.request.MetaSubscribeRequest;
+import org.apache.tomcat.bayeux.request.MetaUnsubscribeRequest;
+import org.apache.tomcat.bayeux.request.PublishRequest;
+import org.apache.cometd.bayeux.Bayeux;
+
+public class RequestFactory {
+
+    public static BayeuxRequest getRequest(TomcatBayeux tomcatBayeux, CometEvent event, JSONObject msg) throws JSONException {
+        String channel = msg.optString(Bayeux.CHANNEL_FIELD);
+        if (Bayeux.META_HANDSHAKE.equals(channel)) {
+            return new MetaHandshakeRequest(tomcatBayeux,event,msg);
+        }else if (Bayeux.META_CONNECT.equals(channel)) {
+            return new MetaConnectRequest(tomcatBayeux,event,msg);
+        }else if (Bayeux.META_DISCONNECT.equals(channel)) {
+            return new MetaDisconnectRequest(tomcatBayeux,event,msg);
+        }else if (Bayeux.META_SUBSCRIBE.equals(channel)) {
+            return new MetaSubscribeRequest(tomcatBayeux,event,msg);
+        }else if (Bayeux.META_UNSUBSCRIBE.equals(channel)) {
+            return new MetaUnsubscribeRequest(tomcatBayeux,event,msg);
+        } else {
+            return new PublishRequest(tomcatBayeux,event,msg);
+        }
+    }
+}
\ No newline at end of file

Added: tomcat/trunk/java/org/apache/tomcat/bayeux/TomcatBayeux.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/bayeux/TomcatBayeux.java?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/bayeux/TomcatBayeux.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/bayeux/TomcatBayeux.java Tue Sep  2 13:00:36 2008
@@ -0,0 +1,176 @@
+/*
+ * 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.
+ */
+package org.apache.tomcat.bayeux;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+
+import org.apache.catalina.CometEvent;
+import org.apache.catalina.tribes.util.Arrays;
+import org.apache.catalina.tribes.util.UUIDGenerator;
+import org.apache.cometd.bayeux.Bayeux;
+import org.apache.cometd.bayeux.Channel;
+import org.apache.cometd.bayeux.Client;
+import org.apache.cometd.bayeux.Listener;
+import org.apache.cometd.bayeux.Message;
+import org.apache.cometd.bayeux.SecurityPolicy;
+/**
+ * 
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class TomcatBayeux implements Bayeux {
+    
+
+    protected int reconnectInterval = 5000;
+    /**
+     * a list of all active clients
+     */
+    protected HashMap<String,Client> clients = new HashMap<String,Client>();
+    
+    /**
+     * a list of all active channels
+     */
+    protected LinkedHashMap<String, Channel> channels = new LinkedHashMap<String,Channel>();
+    
+    /**
+     * security policy to be used.
+     */
+    protected SecurityPolicy securityPolicy = null;
+    /**
+     * default client to use when we need to send an error message but don't have a client valid reference
+     */
+    protected static ClientImpl errorClient = new ClientImpl("error-no-client",false);
+    
+    /**
+     * returns the default error client
+     * @return ClientImpl
+     */
+    public static ClientImpl getErrorClient() {
+        return errorClient;
+    }
+    
+    protected TomcatBayeux() {
+    }
+    
+    /**
+     * should be invoked when the servlet is destroyed or when the context shuts down
+     */
+    public void destroy() {
+        throw new UnsupportedOperationException("TomcatBayeux.destroy() not yet implemented");
+    }
+
+    public Channel getChannel(String channelId, boolean create) {
+        Channel result = channels.get(channelId);
+        if (result==null && create) {
+            result = new ChannelImpl(channelId);
+            channels.put(channelId,result);
+        }
+        return result;
+    }
+    
+    public Channel remove(Channel channel) {
+        return channels.remove(channel.getId());
+    }
+    
+    public Client remove(Client client) {
+        if (client==null) return null;
+        for (Channel ch : getChannels()) {
+            ch.unsubscribe(client);
+        }
+        return clients.remove(client.getId());
+    }
+
+    public Client getClient(String clientId) {
+        return clients.get(clientId);
+    }
+    
+    public boolean hasClient(String clientId) {
+        return clients.containsKey(clientId);
+    }
+    
+    public List<Client> getClients() {
+        return java.util.Arrays.asList(clients.entrySet().toArray(new Client[0]));
+    }
+
+    public SecurityPolicy getSecurityPolicy() {
+        return securityPolicy;
+    }
+
+    public int getReconnectInterval() { 
+        return reconnectInterval;
+    }
+
+    public boolean hasChannel(String channel) {
+        return channels.containsKey(channel);
+    }
+
+    public Client newClient(String idprefix, Listener listener, boolean local, CometEvent event) {
+        String id = createUUID(idprefix);
+        ClientImpl client = new ClientImpl(id, local);
+        client.setListener(listener);
+        clients.put(id, client);
+        return client;
+    }
+
+    public Client newClient(String idprefix, Listener listener) {
+        assert listener!=null;
+        //if this method gets called, someone is using the API inside
+        //the JVM, this is a local client
+        return newClient(idprefix,listener,true, null);
+    }
+    
+    protected ClientImpl getClientImpl(CometEvent event) {
+        return (ClientImpl)event.getHttpServletRequest().getAttribute(ClientImpl.COMET_EVENT_ATTR);
+    }
+    
+    protected void remove(CometEvent event) {
+        ClientImpl client = getClientImpl(event);
+        if (client!=null) {
+            client.removeCometEvent(event);
+        }
+    }
+
+    public String createUUID(String idprefix) {
+        if (idprefix==null) idprefix="";
+        return idprefix + Arrays.toString(UUIDGenerator.randomUUID(false));
+    }
+    
+    public List<Channel> getChannels() {
+        return java.util.Arrays.asList(channels.entrySet().toArray(new Channel[0]));
+    }
+
+    protected Message newMessage() {
+        String id = createUUID("msg-");
+        return new MessageImpl(id);
+    }
+
+    public Message newMessage(Client from) {
+        MessageImpl msg = (MessageImpl)newMessage();
+        msg.setClient(from);
+        return msg;
+    }
+    public void setSecurityPolicy(SecurityPolicy securityPolicy) {
+        this.securityPolicy = securityPolicy;
+    }
+
+    public void setReconnectInterval(int reconnectTimeout) {
+        this.reconnectInterval = reconnectTimeout;
+    }
+
+}

Added: tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaConnectRequest.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaConnectRequest.java?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaConnectRequest.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaConnectRequest.java Tue Sep  2 13:00:36 2008
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+package org.apache.tomcat.bayeux.request;
+
+import java.io.IOException;
+import java.util.HashMap;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.CometEvent;
+import org.apache.tomcat.bayeux.HttpError;
+import org.apache.tomcat.bayeux.BayeuxException;
+import org.apache.tomcat.bayeux.BayeuxRequest;
+import org.apache.tomcat.bayeux.ClientImpl;
+import org.apache.tomcat.bayeux.TomcatBayeux;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.apache.cometd.bayeux.Bayeux;
+import org.apache.tomcat.bayeux.*;
+
+/******************************************************************************
+ * Handshake request Bayeux message.
+ *
+ * @author Guy A. Molinari
+ * @author Filip Hanik
+ * @version 1.0
+ *
+ */
+public class MetaConnectRequest extends RequestBase implements BayeuxRequest {
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();
+
+    static {
+        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_CONNECT);
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());
+    }
+
+    public MetaConnectRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {
+        super(tb, event, jsReq);
+        if (clientId!=null && getTomcatBayeux().hasClient(clientId)) {
+            event.getHttpServletRequest().setAttribute("client",getTomcatBayeux().getClient(clientId));
+        }
+    }
+
+
+    /**
+     * Check client request for validity.
+     *
+     * Per section 4.2.1 of the Bayuex spec a connect request must contain:
+     *  1) The "/meta/connect" channel identifier.
+     *  2) The clientId returned by the server after handshake.
+     *  3) The desired connectionType (must be one of the server's supported
+     *     types returned by handshake response.
+     *  
+     * @return HttpError This method returns null if no errors were found
+     */
+    public HttpError validate() {
+        if(clientId==null|| (!getTomcatBayeux().hasClient(clientId)))
+            return new HttpError(400,"Client Id not valid.", null);
+        if (! (Bayeux.TRANSPORT_LONG_POLL.equals(conType) || Bayeux.TRANSPORT_CALLBACK_POLL.equals(conType)))
+            return new HttpError(400,"Unsupported connection type.",null);
+        return null;//no error
+    }
+
+    /**
+     * Transition to connected state, flushing pending messages if
+     * available.  If there are pending subscriptions and no messages to
+     * flush then the connection is held until there is a pending publish
+     * event to be delivered to this client (Section 4.2.2 of spec).
+     */
+    public int process(int prevops) throws BayeuxException {
+        prevops = super.process(prevops);
+        response = (HashMap<String, Object>)responseTemplate.clone();
+        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);
+        boolean success = false;
+        HttpError error = validate();
+        if (error == null) {
+            client.setDesirectConnType(desiredConnTypeFlag);
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.RETRY_RESPONSE);
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.INTERVAL_FIELD, getReconnectInterval());
+            success = true;
+        }else {
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);
+            response.put(Bayeux.ERROR_FIELD, error.toString());
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.HANDSHAKE_RESPONSE);
+            if (client==null) client = TomcatBayeux.getErrorClient();
+        }
+        response.put(Bayeux.CLIENT_FIELD, client.getId());
+        response.put(Bayeux.TIMESTAMP_FIELD,getTimeStamp());
+        try {
+            JSONObject obj = new JSONObject(response);
+            addToDeliveryQueue(client, obj);
+        } catch (ServletException x) {
+            throw new BayeuxException(x);
+        } catch (IOException x) {
+            throw new BayeuxException(x);
+        }
+        
+        //return immediately if there is no subscriptions
+        //so that we can process the next message
+        int result = client.isSubscribed()?1:0; 
+
+        if (success && client!=null && client.hasMessages()) {
+            //send out messages 
+            flushMessages(client);
+            result = 0; //flush out the messages
+        }
+
+        return result;
+    }
+}
+

Added: tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaDisconnectRequest.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaDisconnectRequest.java?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaDisconnectRequest.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaDisconnectRequest.java Tue Sep  2 13:00:36 2008
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+package org.apache.tomcat.bayeux.request;
+
+import java.io.IOException;
+import java.util.HashMap;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.CometEvent;
+import org.apache.tomcat.bayeux.HttpError;
+import org.apache.tomcat.bayeux.BayeuxException;
+import org.apache.tomcat.bayeux.BayeuxRequest;
+import org.apache.tomcat.bayeux.ClientImpl;
+import org.apache.tomcat.bayeux.TomcatBayeux;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.apache.cometd.bayeux.Bayeux;
+import org.apache.tomcat.bayeux.*;
+import org.apache.cometd.bayeux.Channel;
+
+/******************************************************************************
+ * Handshake request Bayeux message.
+ *
+ * @author Guy A. Molinari
+ * @author Filip Hanik
+ * @version 1.0
+ *
+ */
+public class MetaDisconnectRequest extends RequestBase implements BayeuxRequest {
+
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();
+
+    static {
+        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_DISCONNECT);
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());
+    }
+
+    public MetaDisconnectRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {
+        super(tb, event, jsReq);
+    }
+
+
+    /**
+     * Check client request for validity.
+     *
+     * Per section 4.4.1 of the Bayuex spec a connect request must contain:
+     *  1) The "/meta/disconnect" channel identifier.
+     *  2) The clientId.
+     *  
+     * @return HttpError This method returns null if no errors were found
+     */
+    public HttpError validate() {
+        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))
+            return new HttpError(400,"Client Id not valid.", null);
+//        if (! (Bayeux.TRANSPORT_LONG_POLL.equals(conType) || Bayeux.TRANSPORT_CALLBACK_POLL.equals(conType)))
+//            return new HttpError(400,"Unsupported connection type.",null);
+        return null;//no error
+    }
+
+    /**
+     * Disconnect a client session.
+     */
+    public int process(int prevops) throws BayeuxException {
+        prevops = super.process(prevops);
+        response = (HashMap<String, Object>)responseTemplate.clone();
+        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);
+        HttpError error = validate();
+        if (error == null) {
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "retry");
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("interval", getReconnectInterval());
+        }else {
+            getTomcatBayeux().remove(client);
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);
+            response.put(Bayeux.ERROR_FIELD, error.toString());
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "none");
+            if (client==null) client = TomcatBayeux.getErrorClient();
+        }
+        response.put(Bayeux.CLIENT_FIELD, client.getId());
+        try {
+            JSONObject obj = new JSONObject(response);
+            addToDeliveryQueue(client, obj);
+        } catch (ServletException x) {
+            throw new BayeuxException(x);
+        } catch (IOException x) {
+            throw new BayeuxException(x);
+        }
+        return 0;
+    }
+}
+

Added: tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaHandshakeRequest.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaHandshakeRequest.java?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaHandshakeRequest.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaHandshakeRequest.java Tue Sep  2 13:00:36 2008
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+package org.apache.tomcat.bayeux.request;
+
+import java.io.IOException;
+import java.util.HashMap;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.CometEvent;
+import org.apache.tomcat.bayeux.HttpError;
+import org.apache.tomcat.bayeux.BayeuxException;
+import org.apache.tomcat.bayeux.BayeuxRequest;
+import org.apache.tomcat.bayeux.ClientImpl;
+import org.apache.tomcat.bayeux.TomcatBayeux;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.apache.cometd.bayeux.Bayeux;
+import org.apache.tomcat.bayeux.*;
+
+/******************************************************************************
+ * Handshake request Bayeux message.
+ *
+ * @author Guy A. Molinari
+ * @author Filip Hanik
+ * @version 1.0
+ *
+ */
+public class MetaHandshakeRequest extends RequestBase implements BayeuxRequest {
+
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();
+    
+    static {
+        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_HANDSHAKE);
+        responseTemplate.put(Bayeux.VERSION_FIELD,"1.0");
+        responseTemplate.put(Bayeux.SUPP_CONNECTION_TYPE_FIELD,new String[] { Bayeux.TRANSPORT_LONG_POLL, Bayeux.TRANSPORT_CALLBACK_POLL });
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());
+    }
+
+    public MetaHandshakeRequest(TomcatBayeux tomcatBayeux, CometEvent event, JSONObject jsReq) throws JSONException {
+        super(tomcatBayeux, event, jsReq);
+    }
+    
+
+    public String getVersion() { return version; }
+    public String getMinimumVersion() { return minVersion; }
+
+
+    /**
+     * Check client request for validity.
+     *
+     * Per section 4.1.1 of the Bayuex spec a handshake request must contain:
+     *  1) The "/meta/handshake" channel identifier.
+     *  2) The version of the protocol supported by the client
+     *  3) The client's supported connection types.
+     *  
+     * @return HttpError This method returns null if no errors were found
+     */
+    public HttpError validate() {
+        boolean error = (version==null || version.length()==0);
+        if (!error) error = suppConnTypesFlag==0;
+        if (error) return new HttpError(400,"Invalid handshake request, supportedConnectionType field missing.",null);
+        else return null;
+    }
+
+    /**
+     * Generate and return a client identifier.  Return a list of
+     * supported connection types.  Must be a subset of or identical to
+     * the list of types supported by the client.  See section 4.1.2 of
+     * the Bayuex specification.
+     */
+    public int process(int prevops) throws BayeuxException {
+        prevops = super.process(prevops);
+        response = (HashMap<String, Object>)responseTemplate.clone();
+        ClientImpl client = null;
+        HttpError error = validate();
+        if (error == null) {
+            client = (ClientImpl) getTomcatBayeux().newClient("http-", null, false,getEvent());
+            clientId = client.getId();
+            client.setSupportedConnTypes(suppConnTypesFlag);
+            client.setUseJsonFiltered(getExt().get(Bayeux.JSON_COMMENT_FILTERED_FIELD) != null);
+            response.put(Bayeux.CLIENT_FIELD, client.getId());
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.RETRY_RESPONSE);
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.INTERVAL_FIELD, getReconnectInterval());
+        }else {
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);
+            response.put(Bayeux.ERROR_FIELD, error.toString());
+            client = TomcatBayeux.getErrorClient();
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.NONE_RESPONSE);
+        }
+        try {
+            JSONObject obj = new JSONObject(response);
+            addToDeliveryQueue(client, obj);
+        } catch (ServletException x) {
+            throw new BayeuxException(x);
+        } catch (IOException x) {
+            throw new BayeuxException(x);
+        }
+        return 0;
+    }
+}
+

Added: tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaSubscribeRequest.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaSubscribeRequest.java?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaSubscribeRequest.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaSubscribeRequest.java Tue Sep  2 13:00:36 2008
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+package org.apache.tomcat.bayeux.request;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.CometEvent;
+import org.apache.tomcat.bayeux.HttpError;
+import org.apache.tomcat.bayeux.BayeuxException;
+import org.apache.tomcat.bayeux.BayeuxRequest;
+import org.apache.tomcat.bayeux.ChannelImpl;
+import org.apache.tomcat.bayeux.ClientImpl;
+import org.apache.tomcat.bayeux.TomcatBayeux;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.apache.cometd.bayeux.Channel;
+import org.apache.cometd.bayeux.Bayeux;
+import org.apache.tomcat.bayeux.*;
+
+/******************************************************************************
+ * Handshake request Bayeux message.
+ *
+ * @author Guy A. Molinari
+ * @author Filip Hanik
+ * @version 1.0
+ */
+public class MetaSubscribeRequest extends RequestBase implements BayeuxRequest {
+
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();
+
+    static {
+        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_SUBSCRIBE);
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());
+    }
+
+    public MetaSubscribeRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {
+        super(tb, event, jsReq);
+    }
+
+
+    /**
+     * Check client request for validity.
+     *
+     * Per section 4.5.1 of the Bayuex spec a connect request must contain:
+     *  1) The "/meta/subscribe" channel identifier.
+     *  2) The clientId.
+     *  3) The subscription.  This is the name of the channel of interest,
+     *     or a pattern.
+     *  
+     * @return HttpError This method returns null if no errors were found
+     */
+    public HttpError validate() {
+        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))
+            return new HttpError(400,"Client Id not valid.", null);
+        if (subscription==null||subscription.length()==0)
+            return new HttpError(400,"Subscription missing.",null);
+        return null;//no error
+    }
+
+    /**
+     * Register interest for one or more channels.  Per section 2.2.1 of the
+     * Bayeux spec, a pattern may be specified.  Assign client to matching
+     * channels and inverse client to channel reference.
+     */
+    public int process(int prevops) throws BayeuxException {
+        prevops = super.process(prevops);
+        response = (HashMap<String, Object>)this.responseTemplate.clone();
+        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);
+        HttpError error = validate();
+        if (error == null) {
+            boolean wildcard = subscription.indexOf('*')!=-1;
+            boolean subscribed = false;
+            if (wildcard) {
+                List<Channel> channels = getTomcatBayeux().getChannels();
+                Iterator<Channel> it = channels.iterator();
+                while (it.hasNext()) {
+                    ChannelImpl ch = (ChannelImpl)it.next();
+                    if (ch.matches(subscription)) {
+                        ch.subscribe(client);
+                        subscribed = true;
+                    }
+                }
+            }else {
+                ChannelImpl ch = (ChannelImpl)getTomcatBayeux().getChannel(subscription,true);
+                ch.subscribe(client);
+                subscribed = true;
+            }
+            response.put(Bayeux.SUCCESSFUL_FIELD, Boolean.valueOf(subscribed));
+            response.put(Bayeux.SUBSCRIPTION_FIELD,subscription);
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "retry");
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("interval", getReconnectInterval());
+        }else {
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);
+            response.put(Bayeux.ERROR_FIELD, error.toString());
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "handshake");
+            if (client==null) client = TomcatBayeux.getErrorClient();
+        }
+        response.put(Bayeux.CLIENT_FIELD, client.getId());
+        response.put(Bayeux.TIMESTAMP_FIELD,getTimeStamp());
+        try {
+            JSONObject obj = new JSONObject(response);
+            addToDeliveryQueue(client, obj);
+        } catch (ServletException x) {
+            throw new BayeuxException(x);
+        } catch (IOException x) {
+            throw new BayeuxException(x);
+        }
+        return 0;
+    }
+}
+

Added: tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaUnsubscribeRequest.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaUnsubscribeRequest.java?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaUnsubscribeRequest.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/bayeux/request/MetaUnsubscribeRequest.java Tue Sep  2 13:00:36 2008
@@ -0,0 +1,130 @@
+/*
+ * 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.
+ */
+package org.apache.tomcat.bayeux.request;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.CometEvent;
+import org.apache.tomcat.bayeux.HttpError;
+import org.apache.tomcat.bayeux.BayeuxException;
+import org.apache.tomcat.bayeux.BayeuxRequest;
+import org.apache.tomcat.bayeux.ChannelImpl;
+import org.apache.tomcat.bayeux.ClientImpl;
+import org.apache.tomcat.bayeux.TomcatBayeux;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.apache.cometd.bayeux.Channel;
+import org.apache.cometd.bayeux.Bayeux;
+import org.apache.tomcat.bayeux.*;
+
+/******************************************************************************
+ * Handshake request Bayeux message.
+ *
+ * @author Guy A. Molinari
+ * @author Filip Hanik
+ * @version 1.0
+ *
+ */
+public class MetaUnsubscribeRequest extends RequestBase implements BayeuxRequest {
+
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();
+
+    static {
+        responseTemplate.put(Bayeux.CHANNEL_FIELD,Bayeux.META_UNSUBSCRIBE);
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());
+    }
+
+    public MetaUnsubscribeRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {
+        super(tb, event, jsReq);
+    }
+
+
+    /**
+     * Check client request for validity.
+     *
+     * Per section 4.6.1 of the Bayuex spec a connect request must contain:
+     *  1) The "/meta/unsubscribe" channel identifier.
+     *  2) The clientId.
+     *  3) The subscription.  This is the name of the channel of interest,
+     *     or a pattern.
+     *  
+     * @return HttpError This method returns null if no errors were found
+     */
+    public HttpError validate() {
+        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))
+            return new HttpError(400,"Client Id not valid.", null);
+        if (subscription==null||subscription.length()==0)
+            return new HttpError(400,"Subscription missing.",null);
+        return null;//no error
+    }
+
+    /**
+     * De-register interest for one or more channels.  Per section 2.2.1 of the
+     * Bayeux spec, a pattern may be specified.  Sever relationships.
+     */
+    public int process(int prevops) throws BayeuxException {
+        prevops = super.process(prevops);
+        response = (HashMap<String, Object>)responseTemplate.clone();
+        ClientImpl client = (ClientImpl)getTomcatBayeux().getClient(clientId);
+        HttpError error = validate();
+        if (error == null) {
+            boolean wildcard = subscription.indexOf('*')!=-1;
+            boolean unsubscribed = false;
+            if (wildcard) {
+                List<Channel> channels = getTomcatBayeux().getChannels();
+                Iterator<Channel> it = channels.iterator();
+                while (it.hasNext()) {
+                    ChannelImpl ch = (ChannelImpl)it.next();
+                    if (ch.matches(subscription)) {
+                        ch.unsubscribe(client);
+                        unsubscribed = true;
+                    }
+                }
+            }else {
+                ChannelImpl ch = (ChannelImpl)getTomcatBayeux().getChannel(subscription,true);
+                ch.unsubscribe(client);
+                unsubscribed = true;
+            }
+            response.put(Bayeux.SUCCESSFUL_FIELD, Boolean.valueOf(unsubscribed));
+            response.put(Bayeux.SUBSCRIPTION_FIELD,subscription);
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "retry");
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("interval", getReconnectInterval());
+        }else {
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);
+            response.put(Bayeux.ERROR_FIELD, error.toString());
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put("reconnect", "handshake");
+            if (client==null) client = TomcatBayeux.getErrorClient();
+        }
+        response.put(Bayeux.CLIENT_FIELD, client.getId());
+        response.put(Bayeux.TIMESTAMP_FIELD,getTimeStamp());
+        try {
+            JSONObject obj = new JSONObject(response);
+            addToDeliveryQueue(client, obj);
+        } catch (ServletException x) {
+            throw new BayeuxException(x);
+        } catch (IOException x) {
+            throw new BayeuxException(x);
+        }
+        return 0;
+    }
+}
+

Added: tomcat/trunk/java/org/apache/tomcat/bayeux/request/PublishRequest.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/bayeux/request/PublishRequest.java?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/bayeux/request/PublishRequest.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/bayeux/request/PublishRequest.java Tue Sep  2 13:00:36 2008
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+package org.apache.tomcat.bayeux.request;
+
+import java.io.IOException;
+import java.util.HashMap;
+import javax.servlet.ServletException;
+
+import org.apache.catalina.CometEvent;
+import org.apache.tomcat.bayeux.HttpError;
+import org.apache.tomcat.bayeux.BayeuxException;
+import org.apache.tomcat.bayeux.BayeuxRequest;
+import org.apache.tomcat.bayeux.ChannelImpl;
+import org.apache.tomcat.bayeux.ClientImpl;
+import org.apache.tomcat.bayeux.MessageImpl;
+import org.apache.tomcat.bayeux.TomcatBayeux;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.apache.cometd.bayeux.Bayeux;
+import java.util.List;
+import org.apache.cometd.bayeux.Message;
+import java.util.Iterator;
+import org.apache.tomcat.bayeux.*;
+
+/******************************************************************************
+ * Handshake request Bayeux message.
+ *
+ * @author Guy A. Molinari
+ * @author Filip Hanik
+ * @version 1.0
+ *
+ */
+public class PublishRequest extends RequestBase implements BayeuxRequest {
+
+    JSONObject msgData = null;
+
+    protected static HashMap<String,Object> responseTemplate = new HashMap<String,Object>();
+
+    static {
+        responseTemplate.put(Bayeux.SUCCESSFUL_FIELD,Boolean.TRUE);
+        responseTemplate.put(Bayeux.ADVICE_FIELD, new HashMap<String, Object>());
+    }
+
+    public PublishRequest(TomcatBayeux tb, CometEvent event, JSONObject jsReq) throws JSONException {
+        super(tb, event, jsReq);
+    }
+
+
+    /**
+     * Check client request for validity.
+     *
+     * Per section 5.1.1 of the Bayuex spec a connect request must contain:
+     *  1) The channel identifier of the channel for publication.
+     *  2) The data to send.
+     *  
+     * @return HttpError This method returns null if no errors were found
+     */
+    public HttpError validate() {
+        if(channel==null|| (!this.getTomcatBayeux().hasChannel(channel)))
+            return new HttpError(400,"Channel Id not valid.", null);
+        if(data==null || data.length()==0)
+            return new HttpError(400,"Message data missing.", null);
+        try {
+            this.msgData = new JSONObject(data);
+        }catch (JSONException x) {
+            return new HttpError(400,"Invalid JSON object in data attribute.",x);
+        }
+        if(clientId==null|| (!this.getTomcatBayeux().hasClient(clientId)))
+            return new HttpError(400,"Client Id not valid.", null);
+        return null;//no error
+    }
+
+    /**
+     *  Send the event message to all registered subscribers.
+     */
+    public int process(int prevops) throws BayeuxException {
+        prevops = super.process(prevops);
+        response = (HashMap<String, Object>)responseTemplate.clone();
+        ClientImpl client = clientId!=null?(ClientImpl)getTomcatBayeux().getClient(clientId):
+                                           (ClientImpl)event.getHttpServletRequest().getAttribute("client");
+        boolean success = false;
+        HttpError error = validate();
+        if (error == null) {
+            ChannelImpl chimpl = (ChannelImpl)getTomcatBayeux().getChannel(channel,false);
+            MessageImpl mimpl = (MessageImpl)getTomcatBayeux().newMessage(client);
+            
+            try {
+                String[] keys = JSONObject.getNames(msgData);
+                for (int i = 0; i < keys.length; i++) {
+                    mimpl.put(keys[i], msgData.get(keys[i]));
+                }
+                success = true;
+                ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.RETRY_RESPONSE);
+                ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.INTERVAL_FIELD, getReconnectInterval());
+            }catch (JSONException x) {
+                if (log.isErrorEnabled()) log.error("Unable to parse:"+msgData,x);
+                throw new BayeuxException(x);
+            }
+            chimpl.publish(mimpl);
+        }
+        if(!success) {
+            response.put(Bayeux.SUCCESSFUL_FIELD,Boolean.FALSE);
+            response.put(Bayeux.ERROR_FIELD, error.toString());
+            ((HashMap) response.get(Bayeux.ADVICE_FIELD)).put(Bayeux.RECONNECT_FIELD, Bayeux.HANDSHAKE_RESPONSE);
+            if (client==null) client = TomcatBayeux.getErrorClient();
+        }
+        response.put(Bayeux.CHANNEL_FIELD,channel);
+        response.put(Bayeux.CLIENT_FIELD, client.getId());
+        try {
+            JSONObject obj = new JSONObject(response);
+            addToDeliveryQueue(client, obj);
+        } catch (ServletException x) {
+            throw new BayeuxException(x);
+        } catch (IOException x) {
+            throw new BayeuxException(x);
+        }
+        
+        if (success && client!=null && client.hasMessages()) {
+            //send out messages 
+            flushMessages(client);
+        }
+
+        return 0;
+    }
+}
+

Added: tomcat/trunk/test/org/apache/cometd/bayeux/samples/EchoChatClient.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/cometd/bayeux/samples/EchoChatClient.java?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/cometd/bayeux/samples/EchoChatClient.java (added)
+++ tomcat/trunk/test/org/apache/cometd/bayeux/samples/EchoChatClient.java Tue Sep  2 13:00:36 2008
@@ -0,0 +1,111 @@
+package org.apache.cometd.bayeux.samples;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+import javax.servlet.ServletContextAttributeListener;
+import javax.servlet.ServletContextAttributeEvent;
+import org.apache.cometd.bayeux.Bayeux;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.cometd.bayeux.Client;
+import org.apache.cometd.bayeux.Listener;
+import org.apache.cometd.bayeux.Message;
+import org.apache.cometd.bayeux.Channel;
+
+public class EchoChatClient implements ServletContextListener, ServletContextAttributeListener, Listener {
+    
+    static AtomicInteger counter = new AtomicInteger(0);
+    protected int id;
+    protected Bayeux b;
+    protected Client c;
+    protected boolean alive = true;
+    protected TimestampThread tt = new TimestampThread();
+    public EchoChatClient() {
+        id = counter.incrementAndGet();
+        System.out.println("new listener created with id:"+id);
+    }
+
+    /**
+     * contextDestroyed
+     *
+     * @param servletContextEvent ServletContextEvent
+     * @todo Implement this javax.servlet.ServletContextListener method
+     */
+    public void contextDestroyed(ServletContextEvent servletContextEvent) {
+        alive = false;
+        tt.interrupt();
+    }
+
+    /**
+     * contextInitialized
+     *
+     * @param servletContextEvent ServletContextEvent
+     * @todo Implement this javax.servlet.ServletContextListener method
+     */
+    public void contextInitialized(ServletContextEvent servletContextEvent) {
+    }
+
+    public void attributeAdded(ServletContextAttributeEvent scae) {
+        if (scae.getName().equals(Bayeux.DOJOX_COMETD_BAYEUX)) {
+            b = (Bayeux)scae.getValue();
+            c = b.newClient("echochat-",this);
+            Channel ch = b.getChannel("/chat/demo",true);
+            ch.subscribe(c);
+            tt.start();
+        }
+    }
+
+    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
+    }
+
+    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
+    }
+
+    public void removed(boolean timeout) {
+        System.out.println("Client removed.");
+    }
+
+    public void deliver(Message[] msgs) {
+        for (int i=0; msgs!=null && i<msgs.length; i++) {
+            Message msg = msgs[i];
+            System.out.println("[echochatclient ]received message:" + msg);
+            Message m = b.newMessage(c);
+            m.putAll(msg);
+            //echo the same message
+            m.put("user", "echochatserver");
+            if (m.containsKey("msg")) {
+                //simple chat demo
+                String chat = (String) m.get("msg");
+                m.put("msg", "echochatserver|I received your message-" + chat.substring(chat.indexOf("|") + 1));
+            }
+            System.out.println("[echochatclient ]sending message:" + m);
+            msg.getChannel().publish(m);
+        }
+    }
+
+    public class TimestampThread extends Thread {
+        public TimestampThread() {
+            setDaemon(true);
+        }
+        
+        public void run() {
+            while (alive) {
+                try {
+                    sleep(5000);
+                    Channel ch = b.getChannel("/chat/demo",false);
+                    if (ch.getSubscribers().size()<=1) {
+                        continue;
+                    }
+                    Message m = b.newMessage(c);
+                    m.put("user","echochatserver");
+                    m.put("chat","Time is:"+new java.sql.Date(System.currentTimeMillis()).toLocaleString());
+                    m.put("join",false);
+                    ch.publish(m);
+                }catch (InterruptedException ignore) {
+                    
+                }catch (Exception x) {
+                    x.printStackTrace();
+                }
+            }
+        }
+    }
+}

Added: tomcat/trunk/webapps/cometd/WEB-INF/filters.json
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/cometd/WEB-INF/filters.json?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/webapps/cometd/WEB-INF/filters.json (added)
+++ tomcat/trunk/webapps/cometd/WEB-INF/filters.json Tue Sep  2 13:00:36 2008
@@ -0,0 +1,27 @@
+[
+  { 
+    "channels": "/**",
+    "filter"  : "org.mortbay.cometd.filter.NoMarkupFilter",
+    "init"    : {}
+  },
+
+  { 
+    "channels": "/chat/*",
+    "filter"   : "org.mortbay.cometd.filter.RegexFilter",
+    "init"    : [ 
+	              [ "[fF].ck","dang" ],
+	              [ "teh ","the "]
+	            ]
+  },
+  
+  { 
+    "channels": "/chat/**",
+    "filter"   : "org.mortbay.cometd.filter.RegexFilter",
+    "init"    : [ 
+	              [ "[Mm]icrosoft", "Micro\\$oft" ],
+	              [ ".*tomcat.*", null ] 
+	            ]
+  }
+  
+  
+]
\ No newline at end of file

Added: tomcat/trunk/webapps/cometd/WEB-INF/web.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/cometd/WEB-INF/web.xml?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/webapps/cometd/WEB-INF/web.xml (added)
+++ tomcat/trunk/webapps/cometd/WEB-INF/web.xml Tue Sep  2 13:00:36 2008
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app 
+   xmlns="http://java.sun.com/xml/ns/javaee" 
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+   version="2.5"> 
+  <display-name>Cometd Test WebApp</display-name>
+  
+  <servlet>
+    <servlet-name>cometd</servlet-name>
+    <servlet-class>org.apache.tomcat.bayeux.BayeuxServlet</servlet-class>
+    <init-param>
+      <param-name>timeout</param-name>
+      <param-value>120000000</param-value>
+    </init-param>
+    <load-on-startup>1</load-on-startup>
+  </servlet>
+
+  <servlet-mapping>
+    <servlet-name>cometd</servlet-name>
+    <url-pattern>/cometd/*</url-pattern>
+  </servlet-mapping>
+  
+</web-app>
+
+

Added: tomcat/trunk/webapps/cometd/examples/chat/chat.css
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/cometd/examples/chat/chat.css?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/webapps/cometd/examples/chat/chat.css (added)
+++ tomcat/trunk/webapps/cometd/examples/chat/chat.css Tue Sep  2 13:00:36 2008
@@ -0,0 +1,57 @@
+
+div 
+{ 
+  border: 0px solid black; 
+}
+
+div#chatroom
+{
+  background-color: #e0e0e0;
+  border: 1px solid black; 
+  width: 45em;
+}
+
+div#chat
+{
+  height: 20ex;
+  overflow: auto; 
+  background-color: #f0f0f0;
+  padding: 4px;
+  border: 0px solid black; 
+}
+
+div#input
+{
+  clear: both;
+  padding: 4px;
+  border: 0px solid black; 
+  border-top: 1px solid black; 
+}
+
+input#phrase
+{
+  width:28em;
+  background-color: #e0f0f0;
+}
+
+input#username
+{
+  width:14em;
+  background-color: #e0f0f0;
+}
+
+div.hidden
+{
+  display: none;
+}
+
+span.from
+{
+  font-weight: bold;
+}
+
+span.alert
+{
+  font-style: italic;
+}
+

Added: tomcat/trunk/webapps/cometd/examples/chat/chat.js
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/cometd/examples/chat/chat.js?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/webapps/cometd/examples/chat/chat.js (added)
+++ tomcat/trunk/webapps/cometd/examples/chat/chat.js Tue Sep  2 13:00:36 2008
@@ -0,0 +1,139 @@
+dojo.require("dojox.cometd");
+dojo.require("dojox.cometd.timestamp");
+
+var room = {
+    _last: "",
+    _username: null,
+    _connected: true,
+
+    join: function(name){
+        
+        if(name == null || name.length==0 ){
+            alert('Please enter a username!');
+        }else{
+		
+            dojox.cometd.init(new String(document.location).replace(/http:\/\/[^\/]*/,'').replace(/\/examples\/.*$/,'')+"/cometd");
+            // dojox.cometd.init("http://127.0.0.2:8080/cometd");
+            this._connected=true;
+	    
+            this._username=name;
+            dojo.byId('join').className='hidden';
+            dojo.byId('joined').className='';
+            dojo.byId('phrase').focus();
+	    
+            // subscribe and join
+	    dojox.cometd.startBatch();
+            dojox.cometd.subscribe("/chat/demo", room, "_chat");
+            dojox.cometd.publish("/chat/demo", { user: room._username, join: true, chat : room._username+" has joined"});
+	    dojox.cometd.endBatch();
+	    
+            // handle cometd failures while in the room
+            room._meta=dojo.subscribe("/cometd/meta",dojo.hitch(this,function(event){
+                console.debug(event);   
+                if (event.action=="handshake"){
+	            room._chat({data:{join:true,user:"SERVER",chat:"reinitialized"}});
+                    dojox.cometd.subscribe("/chat/demo", room, "_chat");
+                } else if (event.action=="connect") {
+		    if (event.successful && !this._connected)
+                        room._chat({data:{leave:true,user:"SERVER",chat:"reconnected!"}});
+		    if (!event.successful && this._connected)
+                        room._chat({data:{leave:true,user:"SERVER",chat:"disconnected!"}});
+		    this._connected=event.successful;
+	        }
+            }));
+        }
+    },
+
+    leave: function(){
+        if (room._username==null)
+            return;
+	    
+	if (room._meta)
+            dojo.unsubscribe(room._meta);
+	room._meta=null;
+	
+	dojox.cometd.startBatch();
+        dojox.cometd.unsubscribe("/chat/demo", room, "_chat");
+        dojox.cometd.publish("/chat/demo", { user: room._username, leave: true, chat : room._username+" has left"});
+	dojox.cometd.endBatch();
+
+        // switch the input form
+        dojo.byId('join').className='';
+        dojo.byId('joined').className='hidden';
+        dojo.byId('username').focus();
+        room._username=null;
+        dojox.cometd.disconnect();
+    },
+      
+    chat: function(text){
+        if(!text || !text.length){ return false; }
+        dojox.cometd.publish("/chat/demo", { user: room._username, chat: text});
+    },
+
+    _chat: function(message){
+        var chat=dojo.byId('chat');
+        if(!message.data){
+            alert("bad message format "+message);
+            return;
+        }
+        var from=message.data.user;
+        var special=message.data.join || message.data.leave;
+        var text=message.data.chat;
+        if(!text){ return; }
+
+        if( !special && from == room._last ){
+            from="...";
+        }else{
+            room._last=from;
+            from+=":";
+        }
+
+        if(special){
+            chat.innerHTML += "<span class=\"alert\"><span class=\"from\">"+from+"&nbsp;</span><span class=\"text\">"+text+"</span></span><br/>";
+            room._last="";
+        }else{
+            chat.innerHTML += "<span class=\"from\">"+from+"&nbsp;</span><span class=\"text\">"+text+"</span><br/>";
+        } 
+        chat.scrollTop = chat.scrollHeight - chat.clientHeight;    
+    },
+  
+  _init: function(){
+        dojo.byId('join').className='';
+        dojo.byId('joined').className='hidden';
+        dojo.byId('username').focus();
+	
+        var element=dojo.byId('username');
+        element.setAttribute("autocomplete","OFF"); 
+        dojo.connect(element, "onkeyup", function(e){   
+            if(e.keyCode == dojo.keys.ENTER){
+                room.join(dojo.byId('username').value);
+                return false;
+            }
+            return true;
+	});
+  
+        dojo.connect(dojo.byId('joinB'), "onclick", function(e){
+            room.join(dojo.byId('username').value);
+            e.preventDefault();
+	});
+  
+        element=dojo.byId('phrase');
+        element.setAttribute("autocomplete","OFF");
+        dojo.connect(element, "onkeyup", function(e){   
+            if(e.keyCode == dojo.keys.ENTER){
+                room.chat(dojo.byId('phrase').value);
+                dojo.byId('phrase').value='';
+                e.preventDefault();
+            }
+	});
+  
+	dojo.connect(dojo.byId('sendB'), "onkeyup", function(e){   
+	    room.chat(dojo.byId('phrase').value);
+            dojo.byId('phrase').value='';
+	});
+	dojo.connect(dojo.byId('leaveB'), "onclick", room, "leave");
+    } 
+};
+
+dojo.addOnLoad(room, "_init");
+dojo.addOnUnload(room,"leave");

Added: tomcat/trunk/webapps/cometd/examples/chat/index.html
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/cometd/examples/chat/index.html?rev=691359&view=auto
==============================================================================
--- tomcat/trunk/webapps/cometd/examples/chat/index.html (added)
+++ tomcat/trunk/webapps/cometd/examples/chat/index.html Tue Sep  2 13:00:36 2008
@@ -0,0 +1,26 @@
+<html>
+<head>
+    <title>Cometd chat</title>
+    <script type="text/javascript" src="../dojo/dojo/dojo.js"></script>
+    <script type="text/javascript" src="../dojo/dojox/cometd.js.uncompressed.js"></script>
+    <script type="text/javascript" src="chat.js"></script>
+    <link rel="stylesheet" type="text/css" href="chat.css">
+</head>
+<body>
+<h1>Cometd Chat</h1>
+
+<div id="chatroom">
+ <div id="chat"></div>
+ <div id="input">
+   <div id="join" >
+     Username:&nbsp;<input id="username" type="text"/><input id="joinB" class="button" type="submit" name="join" value="Join"/>
+   </div>
+   <div id="joined" class="hidden">
+     Chat:&nbsp;<input id="phrase" type="text"/>
+     <input id="sendB" class="button" type="submit" name="join" value="Send"/>
+     <input id="leaveB" class="button" type="submit" name="join" value="Leave"/>
+   </div>
+  </div>
+ </div>
+
+</body>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org