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+" </span><span class=\"text\">"+text+"</span></span><br/>";
+ room._last="";
+ }else{
+ chat.innerHTML += "<span class=\"from\">"+from+" </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: <input id="username" type="text"/><input id="joinB" class="button" type="submit" name="join" value="Join"/>
+ </div>
+ <div id="joined" class="hidden">
+ Chat: <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