You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by cm...@apache.org on 2012/01/06 11:24:36 UTC

svn commit: r1228060 [1/2] - in /camel/trunk/components/camel-websocket: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/camel/ src/main/java/org/apache/camel/component/ src/main/java/org/apache/ca...

Author: cmoulliard
Date: Fri Jan  6 10:24:34 2012
New Revision: 1228060

URL: http://svn.apache.org/viewvc?rev=1228060&view=rev
Log:
CAMEL-4498 : Add new camel component for websockets

Added:
    camel/trunk/components/camel-websocket/
    camel/trunk/components/camel-websocket/pom.xml
    camel/trunk/components/camel-websocket/src/
    camel/trunk/components/camel-websocket/src/main/
    camel/trunk/components/camel-websocket/src/main/java/
    camel/trunk/components/camel-websocket/src/main/java/org/
    camel/trunk/components/camel-websocket/src/main/java/org/apache/
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/DefaultWebsocket.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/MemoryWebsocketStore.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/NodeSynchronization.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/NodeSynchronizationImpl.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketComponent.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketComponentServlet.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConfiguration.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConstants.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConsumer.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketEndpoint.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketProducer.java
    camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketStore.java
    camel/trunk/components/camel-websocket/src/main/resources/
    camel/trunk/components/camel-websocket/src/main/resources/META-INF/
    camel/trunk/components/camel-websocket/src/main/resources/META-INF/services/
    camel/trunk/components/camel-websocket/src/main/resources/META-INF/services/org/
    camel/trunk/components/camel-websocket/src/main/resources/META-INF/services/org/apache/
    camel/trunk/components/camel-websocket/src/main/resources/META-INF/services/org/apache/camel/
    camel/trunk/components/camel-websocket/src/main/resources/META-INF/services/org/apache/camel/component/
    camel/trunk/components/camel-websocket/src/main/resources/META-INF/services/org/apache/camel/component/websocket
    camel/trunk/components/camel-websocket/src/main/resources/index.html
    camel/trunk/components/camel-websocket/src/main/resources/log4j.properties
    camel/trunk/components/camel-websocket/src/test/
    camel/trunk/components/camel-websocket/src/test/integration/
    camel/trunk/components/camel-websocket/src/test/integration/org/
    camel/trunk/components/camel-websocket/src/test/integration/org/apache/
    camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/
    camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/WebsocketComponentTest.java
    camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/
    camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/
    camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/ProducerOnlyTest.java
    camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/WebsocketComponentLiveTest.java
    camel/trunk/components/camel-websocket/src/test/java/
    camel/trunk/components/camel-websocket/src/test/java/org/
    camel/trunk/components/camel-websocket/src/test/java/org/apache/
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/DefaultWebsocketTest.java
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/MemoryWebsocketStoreTest.java
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/NodeSynchronizationImplTest.java
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/WebsocketComponentServletTest.java
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/WebsocketComponentTest.java
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/WebsocketConfigurationTest.java
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/WebsocketConsumerTest.java
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/WebsocketEndpointTest.java
    camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/WebsocketProducerTest.java
    camel/trunk/components/camel-websocket/src/test/resources/
    camel/trunk/components/camel-websocket/src/test/resources/index.html
    camel/trunk/components/camel-websocket/src/test/resources/producer-only.html

Added: camel/trunk/components/camel-websocket/pom.xml
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/pom.xml?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/pom.xml (added)
+++ camel/trunk/components/camel-websocket/pom.xml Fri Jan  6 10:24:34 2012
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.camel</groupId>
+        <artifactId>camel-parent</artifactId>
+        <version>2.10-SNAPSHOT</version>
+        <relativePath>../../parent</relativePath>
+    </parent>
+
+    <artifactId>camel-websocket</artifactId>
+    <packaging>bundle</packaging>
+    <name>Camel :: WebSocket</name>
+    <description>Camel WebSocket</description>
+
+    <properties>
+        <camel.osgi.export.pkg>
+            org.apache.camel.component.websocket.*;${camel.osgi.version}
+        </camel.osgi.export.pkg>
+        <camel.osgi.import.pkg>
+            !org.apache.camel.component.websocket.*,
+            ${camel.osgi.import.defaults},
+            *
+        </camel.osgi.import.pkg>
+    </properties>
+
+    <dependencies>
+        <!-- Camel -->
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-core</artifactId>
+        </dependency>
+        <!-- Jetty -->
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-websocket</artifactId>
+            <version>${jetty-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlet</artifactId>
+            <version>${jetty-version}</version>
+        </dependency>
+        <!-- Unit test -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+         		<dependency>
+			<groupId>org.mockito</groupId>
+			<artifactId>mockito-core</artifactId>
+
+			<scope>test</scope>
+		</dependency>
+    </dependencies>
+</project>
\ No newline at end of file

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/DefaultWebsocket.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/DefaultWebsocket.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/DefaultWebsocket.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/DefaultWebsocket.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,82 @@
+/**
+ * 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.camel.component.websocket;
+
+import java.io.Serializable;
+import java.util.UUID;
+
+import org.eclipse.jetty.websocket.WebSocket;
+import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;
+
+public class DefaultWebsocket implements WebSocket, OnTextMessage, Serializable {
+
+    private static final long serialVersionUID = -575701599776801400L;
+    private Connection connection;
+    private String connectionKey;
+    private NodeSynchronization sync;
+
+    private transient WebsocketConsumer consumer;
+
+    public DefaultWebsocket(NodeSynchronization sync, WebsocketConsumer consumer) {
+        this.sync = sync;
+        this.consumer = consumer;
+    }
+
+    @Override
+    public void onClose(int closeCode, String message) {
+        sync.removeSocket(this);
+    }
+
+    @Override
+    public void onOpen(Connection connection) {
+        this.connection = connection;
+
+        this.connectionKey = UUID.randomUUID().toString();
+        sync.addSocket(this);
+    }
+
+    @Override
+    public void onMessage(String message) {
+        if (this.consumer != null) {
+            this.consumer.sendExchange(this.connectionKey, message);
+        }
+        // consumer is not set, this is produce only websocket
+        // TODO - 06.06.2011, LK - deliver exchange to dead letter channel
+    }
+
+    // getters and setters
+    public Connection getConnection() {
+        return connection;
+    }
+
+    public void setConnection(Connection connection) {
+        this.connection = connection;
+    }
+
+    public String getConnectionKey() {
+        return connectionKey;
+    }
+
+    public void setConnectionKey(String connectionKey) {
+        this.connectionKey = connectionKey;
+    }
+
+    public void setConsumer(WebsocketConsumer consumer) {
+        this.consumer = consumer;
+    }
+
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/MemoryWebsocketStore.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/MemoryWebsocketStore.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/MemoryWebsocketStore.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/MemoryWebsocketStore.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,51 @@
+/**
+ * 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.camel.component.websocket;
+
+import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class MemoryWebsocketStore extends ConcurrentHashMap<String, DefaultWebsocket> implements WebsocketStore {
+
+    private static final long serialVersionUID = -2826843758230613922L;
+
+    @Override
+    public void add(DefaultWebsocket ws) {
+        super.put(ws.getConnectionKey(), ws);
+    }
+
+    @Override
+    public void remove(DefaultWebsocket ws) {
+        super.remove(ws.getConnectionKey());
+    }
+
+    @Override
+    public void remove(String key) {
+        super.remove(key);
+    }
+
+    @Override
+    public DefaultWebsocket get(String key) {
+        return super.get(key);
+    }
+
+    @Override
+    public Collection<DefaultWebsocket> getAll() {
+        return super.values();
+    }
+
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/NodeSynchronization.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/NodeSynchronization.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/NodeSynchronization.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/NodeSynchronization.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,30 @@
+/**
+ * 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.camel.component.websocket;
+
+public interface NodeSynchronization {
+
+    /** adds the Websocket to both (always if present) stores */
+    void addSocket(DefaultWebsocket socket);
+
+    /** deletes the Websocket from both stores */
+    void removeSocket(String id);
+
+    /** deletes the Websocket from both stores */
+    void removeSocket(DefaultWebsocket socket);
+
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/NodeSynchronizationImpl.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/NodeSynchronizationImpl.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/NodeSynchronizationImpl.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/NodeSynchronizationImpl.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,58 @@
+/**
+ * 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.camel.component.websocket;
+
+public class NodeSynchronizationImpl implements NodeSynchronization {
+
+    private WebsocketStore memoryStore;
+
+    private WebsocketStore globalStore;
+
+    public NodeSynchronizationImpl(WebsocketStore memoryStore, WebsocketStore globalStore) {
+        this.memoryStore = memoryStore;
+        this.globalStore = globalStore;
+    }
+
+    public NodeSynchronizationImpl(WebsocketStore memoryStore) {
+        this.memoryStore = memoryStore;
+    }
+
+    @Override
+    public void addSocket(DefaultWebsocket socket) {
+        memoryStore.add(socket);
+        if (this.globalStore != null) {
+            globalStore.add(socket);
+        }
+    }
+
+    @Override
+    public void removeSocket(String id) {
+        memoryStore.remove(id);
+        if (this.globalStore != null) {
+            globalStore.remove(id);
+        }
+    }
+
+    @Override
+    public void removeSocket(DefaultWebsocket socket) {
+        memoryStore.remove(socket);
+        if (this.globalStore != null) {
+            globalStore.remove(socket);
+        }
+    }
+
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketComponent.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketComponent.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketComponent.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketComponent.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,184 @@
+/**
+ * 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.camel.component.websocket;
+
+import java.net.InetSocketAddress;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.impl.DefaultComponent;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.SessionManager;
+import org.eclipse.jetty.server.session.HashSessionManager;
+import org.eclipse.jetty.server.session.SessionHandler;
+import org.eclipse.jetty.servlet.DefaultServlet;
+import org.eclipse.jetty.servlet.ServletContextHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebsocketComponent extends DefaultComponent {
+
+    private static final Logger LOG = LoggerFactory.getLogger(WebsocketComponent.class);
+
+    private ServletContextHandler context;
+    private Server server;
+
+    /** Host name for server. */
+    private String host = WebsocketConstants.DEFAULT_HOST;
+
+    /** Port for server. */
+    private int port = WebsocketConstants.DEFAULT_PORT;
+
+    /** Server static content location. */
+    private String staticResources;
+
+    /**
+     * Map for storing endpoints. Endpoint is identified by remaining part from endpoint URI. Eg. <tt>ws://foo?bar=123</tt> and <tt>ws://foo</tt> are referring to the same endpoint.
+     */
+    private Map<String, WebsocketEndpoint> endpoints = new HashMap<String, WebsocketEndpoint>();
+
+    /**
+     * Map for storing servlets. {@link WebsocketComponentServlet} is identified by pathSpec {@link String}.
+     */
+    private Map<String, WebsocketComponentServlet> servlets = new HashMap<String, WebsocketComponentServlet>();
+
+    public WebsocketComponent() {
+    }
+
+    @Override
+    /**
+     * uri --> websocket://foo?storeImplementationClass=org.apache.camel.hazelcast.HazelcastWebsocketStore&storeName=foo
+     */
+    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+        WebsocketEndpoint endpoint = endpoints.get(remaining);
+        if (endpoint == null) {
+            WebsocketConfiguration websocketConfiguration = new WebsocketConfiguration();
+            setProperties(websocketConfiguration, parameters);
+            endpoint = new WebsocketEndpoint(uri, this, remaining, websocketConfiguration);
+            endpoints.put(remaining, endpoint);
+        }
+        return endpoint;
+    }
+
+    /**
+     * @param host
+     *            the host to set
+     */
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    /**
+     * @param port
+     *            the port to set
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    /**
+     * @param staticResources
+     *            the staticResources to set
+     */
+    public void setStaticResources(String staticResources) {
+        this.staticResources = staticResources;
+    }
+
+    ServletContextHandler createContext() {
+        return new ServletContextHandler(ServletContextHandler.SESSIONS);
+    }
+
+    protected Server createServer(ServletContextHandler context, String host, int port, String home) {
+        InetSocketAddress address = new InetSocketAddress(host, port);
+        Server server = new Server(address);
+
+        context.setContextPath("/");
+
+        SessionManager sm = new HashSessionManager();
+        SessionHandler sh = new SessionHandler(sm);
+        context.setSessionHandler(sh);
+
+        if (home != null) {
+            context.setResourceBase(home);
+            DefaultServlet defaultServlet = new DefaultServlet();
+            ServletHolder holder = new ServletHolder(defaultServlet);
+
+            // avoid file locking on windows
+            // http://stackoverflow.com/questions/184312/how-to-make-jetty-dynamically-load-static-pages
+            holder.setInitParameter("useFileMappedBuffer", "false");
+            context.addServlet(holder, "/");
+        }
+
+        server.setHandler(context);
+
+        return server;
+    }
+
+    public WebsocketComponentServlet addServlet(NodeSynchronization sync, WebsocketConsumer consumer, String remaining) {
+
+        String pathSpec = createPathSpec(remaining);
+        WebsocketComponentServlet servlet = servlets.get(pathSpec);
+        if (servlet == null) {
+            servlet = createServlet(sync, pathSpec, servlets, context);
+        }
+        setServletConsumer(servlet, consumer);
+        return servlet;
+    }
+
+    String createPathSpec(String remaining) {
+        return String.format("/%s/*", remaining);
+    }
+
+    void setServletConsumer(WebsocketComponentServlet servlet, WebsocketConsumer consumer) {
+        if (servlet.getConsumer() == null && consumer != null) {
+            servlet.setConsumer(consumer);
+        }
+    }
+
+    WebsocketComponentServlet createServlet(NodeSynchronization sync, String pathSpec, Map<String, WebsocketComponentServlet> servlets, ServletContextHandler handler) {
+
+        WebsocketComponentServlet servlet = new WebsocketComponentServlet(sync);
+        servlets.put(pathSpec, servlet);
+        handler.addServlet(new ServletHolder(servlet), pathSpec);
+        return servlet;
+    }
+
+    /**
+     * @see org.apache.camel.impl.DefaultComponent#doStart()
+     */
+    @Override
+    protected void doStart() throws Exception {
+        super.doStart();
+        LOG.info("Staring server {}:{}; static resources: {}", new Object[] {host, port, staticResources});
+        context = createContext();
+        server = createServer(context, host, port, staticResources);
+        server.start();
+    }
+
+    /**
+     * @see org.apache.camel.impl.DefaultComponent#doStop()
+     */
+    @Override
+    public void doStop() throws Exception {
+        if (server != null) {
+            server.stop();
+        }
+    }
+
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketComponentServlet.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketComponentServlet.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketComponentServlet.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketComponentServlet.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,65 @@
+/**
+ * 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.camel.component.websocket;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.websocket.WebSocket;
+import org.eclipse.jetty.websocket.WebSocketServlet;
+
+public class WebsocketComponentServlet extends WebSocketServlet {
+
+    private static final long serialVersionUID = 207837507742337364L;
+
+    private WebsocketConsumer consumer;
+    private NodeSynchronization sync;
+
+    public WebsocketComponentServlet(NodeSynchronization sync) {
+        this.sync = sync;
+    }
+
+    /**
+     * @return the consumer
+     */
+    public WebsocketConsumer getConsumer() {
+        return consumer;
+    }
+
+    /**
+     * @param consumer
+     *            the consumer to set
+     */
+    public void setConsumer(WebsocketConsumer consumer) {
+        this.consumer = consumer;
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+
+        getServletContext().getNamedDispatcher("default").forward(request, response);
+    }
+
+    @Override
+    public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) {
+        return new DefaultWebsocket(sync, consumer);
+    }
+
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConfiguration.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConfiguration.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConfiguration.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConfiguration.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,31 @@
+/**
+ * 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.camel.component.websocket;
+
+public class WebsocketConfiguration {
+
+    private String globalStore;
+
+    public String getGlobalStore() {
+        return globalStore;
+    }
+
+    public void setGlobalStore(String globalStore) {
+        this.globalStore = globalStore;
+    }
+
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConstants.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConstants.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConstants.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConstants.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,27 @@
+/**
+ * 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.camel.component.websocket;
+
+public class WebsocketConstants {
+
+    public static final String CONNECTION_KEY = "websocket.connectionKey";
+    public static final String SEND_TO_ALL = "websocket.sendToAll";
+
+    public static final String DEFAULT_HOST = "0.0.0.0";
+    public static final int DEFAULT_PORT = 9292;
+
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConsumer.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConsumer.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConsumer.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketConsumer.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,47 @@
+/**
+ * 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.camel.component.websocket;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+import org.apache.camel.impl.DefaultConsumer;
+
+public class WebsocketConsumer extends DefaultConsumer {
+
+    public WebsocketConsumer(Endpoint endpoint, Processor processor) {
+        super(endpoint, processor);
+    }
+
+    public void sendExchange(String connectionKey, String message) {
+        Exchange exchange = this.getEndpoint().createExchange();
+
+        // set header and body
+        exchange.getIn().setHeader(WebsocketConstants.CONNECTION_KEY, connectionKey);
+        exchange.getIn().setBody(message);
+
+        // send exchange
+        try {
+            this.getProcessor().process(exchange);
+        } catch (Exception e) {
+            if (exchange.getException() != null) {
+                this.getExceptionHandler().handleException(String.format("Error processing exchange for websocket consumer on message '%s'.", message), exchange, exchange.getException());
+            }
+        }
+    }
+
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketEndpoint.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketEndpoint.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketEndpoint.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketEndpoint.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,92 @@
+/**
+ * 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.camel.component.websocket;
+
+import org.apache.camel.Consumer;
+import org.apache.camel.Processor;
+import org.apache.camel.Producer;
+import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.util.ObjectHelper;
+
+public class WebsocketEndpoint extends DefaultEndpoint {
+
+    // Todo: Change to Options
+    private NodeSynchronization sync;
+    private String remaining;
+
+    private WebsocketStore memoryStore;
+    private WebsocketStore globalStore;
+
+    private WebsocketConfiguration websocketConfiguration;
+
+    public WebsocketEndpoint() {
+
+    }
+    
+    public WebsocketEndpoint(String uri, WebsocketComponent component, String remaining, WebsocketConfiguration websocketConfiguration) throws InstantiationException, IllegalAccessException {
+        super(uri, component);
+        this.remaining = remaining;
+
+        this.memoryStore = new MemoryWebsocketStore();
+        // TODO: init globalStore
+
+        this.websocketConfiguration = websocketConfiguration;
+
+        if (websocketConfiguration.getGlobalStore() != null) {
+            this.globalStore = (WebsocketStore) ObjectHelper.loadClass(this.websocketConfiguration.getGlobalStore()).newInstance();
+        }
+
+        // this.sync = new NodeSynchronizationImpl(this.memoryStore, null);
+        this.sync = new NodeSynchronizationImpl(this.memoryStore, this.globalStore);
+    }
+
+    public WebsocketStore getMemoryStore() {
+        return memoryStore;
+    }
+
+    public WebsocketStore getGlobalStore() {
+        return globalStore;
+    }
+
+    @Override
+    public Consumer createConsumer(Processor processor) throws Exception {
+
+        // init consumer
+        WebsocketConsumer consumer = new WebsocketConsumer(this, processor);
+
+        // register servlet
+        ((WebsocketComponent) super.getComponent()).addServlet(this.sync, consumer, this.remaining);
+
+        return consumer;
+    }
+
+    @Override
+    public Producer createProducer() throws Exception {
+
+        // register servlet without consumer
+        ((WebsocketComponent) super.getComponent()).addServlet(this.sync, null, this.remaining);
+
+        return new WebsocketProducer(this, this.memoryStore);
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return true;
+    }
+
+    // TODO --> implement store factory
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketProducer.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketProducer.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketProducer.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketProducer.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,90 @@
+/**
+ * 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.camel.component.websocket;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.apache.camel.Endpoint;
+import org.apache.camel.Exchange;
+import org.apache.camel.Message;
+import org.apache.camel.impl.DefaultProducer;
+
+public class WebsocketProducer extends DefaultProducer {
+
+    private WebsocketStore store;
+
+    public WebsocketProducer(Endpoint endpoint) {
+        super(endpoint);
+    }
+
+    public WebsocketProducer(Endpoint endpoint, WebsocketStore store) {
+        super(endpoint);
+        this.store = store;
+    }
+
+    @Override
+    public void process(Exchange exchange) throws Exception {
+
+        Message in = exchange.getIn();
+        String message = in.getBody(String.class);
+
+        if (isSendToAllSet(in)) {
+            sendToAll(this.store, message);
+        } else {
+            // look for connection key and get Websocket
+            String connectionKey = in.getHeader(WebsocketConstants.CONNECTION_KEY, String.class);
+            if (connectionKey != null) {
+                DefaultWebsocket websocket = store.get(connectionKey);
+                sendMessage(websocket, message);
+            } else {
+                throw new IllegalArgumentException("Failed to send message to single connection; connetion key not set.");
+            }
+        }
+    }
+
+    boolean isSendToAllSet(Message in) {
+        // header may be null; have to be careful here
+        Object value = in.getHeader(WebsocketConstants.SEND_TO_ALL);
+        return value == null ? false : (Boolean) value;
+    }
+
+    void sendToAll(WebsocketStore store, String message) throws Exception {
+        Collection<DefaultWebsocket> websockets = store.getAll();
+        Exception exception = null;
+        for (DefaultWebsocket websocket : websockets) {
+            try {
+                sendMessage(websocket, message);
+            } catch (Exception e) {
+                if (exception == null) {
+                    exception = new Exception("Failed to deliver message to one or more recipients.", e);
+                }
+            }
+        }
+        if (exception != null) {
+            throw exception;
+        }
+    }
+
+    void sendMessage(DefaultWebsocket websocket, String message) throws IOException {
+        // in case there is web socket and socket connection is open - send
+        // message
+        if (websocket != null && websocket.getConnection().isOpen()) {
+            websocket.getConnection().sendMessage(message);
+        }
+    }
+}

Added: camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketStore.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketStore.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketStore.java (added)
+++ camel/trunk/components/camel-websocket/src/main/java/org/apache/camel/component/websocket/WebsocketStore.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,32 @@
+/**
+ * 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.camel.component.websocket;
+
+import java.util.Collection;
+
+public interface WebsocketStore {
+
+    void add(DefaultWebsocket ws);
+
+    void remove(DefaultWebsocket ws);
+
+    void remove(String key);
+
+    DefaultWebsocket get(String key);
+
+    Collection<DefaultWebsocket> getAll();
+}

Added: camel/trunk/components/camel-websocket/src/main/resources/META-INF/services/org/apache/camel/component/websocket
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/resources/META-INF/services/org/apache/camel/component/websocket?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/resources/META-INF/services/org/apache/camel/component/websocket (added)
+++ camel/trunk/components/camel-websocket/src/main/resources/META-INF/services/org/apache/camel/component/websocket Fri Jan  6 10:24:34 2012
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+class=org.apache.camel.component.websocket.WebsocketComponent

Added: camel/trunk/components/camel-websocket/src/main/resources/index.html
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/resources/index.html?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/resources/index.html (added)
+++ camel/trunk/components/camel-websocket/src/main/resources/index.html Fri Jan  6 10:24:34 2012
@@ -0,0 +1,109 @@
+<html><head>
+    <title>WebSocket Chat</title>
+    <script type='text/javascript'>
+    
+      if (!window.WebSocket)
+        alert("WebSocket not supported by this browser");
+    
+      function $() { return document.getElementById(arguments[0]); }
+      function $F() { return document.getElementById(arguments[0]).value; }
+      
+      function getKeyCode(ev) { if (window.event) return window.event.keyCode; return ev.keyCode; } 
+      
+      var room = {
+        join: function(name) {
+          this._username=name;
+          var location = "ws://localhost:1989/foo/";
+          this._ws=new WebSocket(location);
+          this._ws.onopen=this._onopen;
+          this._ws.onmessage=this._onmessage;
+          this._ws.onclose=this._onclose;
+        },
+        
+        _onopen: function(){
+          $('join').className='hidden';
+          $('joined').className='';
+          $('phrase').focus();
+          room._send(room._username,'has joined!');
+        },
+        
+        _send: function(user,message){
+          user=user.replace(':','_');
+          if (this._ws)
+            this._ws.send(user+':'+message);
+        },
+      
+        chat: function(text) {
+          if (text != null && text.length>0 )
+              room._send(room._username,text);
+        },
+        
+        _onmessage: function(m) {
+          if (m.data){
+            var c=m.data.indexOf(':');
+            var from=m.data.substring(0,c).replace('<','&lt;').replace('>','&gt;');
+            var text=m.data.substring(c+1).replace('<','&lt;').replace('>','&gt;');
+            
+            var chat=$('chat');
+            var spanFrom = document.createElement('span');
+            spanFrom.className='from';
+            spanFrom.innerHTML=from+':&nbsp;';
+            var spanText = document.createElement('span');
+            spanText.className='text';
+            spanText.innerHTML=text;
+            var lineBreak = document.createElement('br');
+            chat.appendChild(spanFrom);
+            chat.appendChild(spanText);
+            chat.appendChild(lineBreak);
+            chat.scrollTop = chat.scrollHeight - chat.clientHeight;   
+          }
+        },
+        
+        _onclose: function(m) {
+          this._ws=null;
+          $('join').className='';
+          $('joined').className='hidden';
+          $('username').focus();
+          $('chat').innerHTML='';
+        }
+        
+      };
+      
+    </script>
+    <style type='text/css'>
+    div { border: 0px solid black; }
+    div#chat { clear: both; width: 40em; height: 20ex; overflow: auto; background-color: #f0f0f0; padding: 4px; border: 1px solid black; }
+    div#input { clear: both; width: 40em; padding: 4px; background-color: #e0e0e0; border: 1px solid black; border-top: 0px }
+    input#phrase { width:30em; background-color: #e0f0f0; }
+    input#username { width:14em; background-color: #e0f0f0; }
+    div.hidden { display: none; }
+    span.from { font-weight: bold; }
+    span.alert { font-style: italic; }
+    </style>
+</head><body>
+<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'/>
+  </div>
+</div>
+<script type='text/javascript'>
+$('username').setAttribute('autocomplete','OFF');
+$('username').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.join($F('username')); return false; } return true; } ;        
+$('joinB').onclick = function(event) { room.join($F('username')); return false; };
+$('phrase').setAttribute('autocomplete','OFF');
+$('phrase').onkeyup = function(ev) {   var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.chat($F('phrase')); $('phrase').value=''; return false; } return true; };
+$('sendB').onclick = function(event) { room.chat($F('phrase')); $('phrase').value=''; return false; };
+</script>
+
+<p>
+This is a demonstration of the Jetty websocket server.
+</p>
+</body></html>
+        
+        
+        
\ No newline at end of file

Added: camel/trunk/components/camel-websocket/src/main/resources/log4j.properties
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/main/resources/log4j.properties?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/main/resources/log4j.properties (added)
+++ camel/trunk/components/camel-websocket/src/main/resources/log4j.properties Fri Jan  6 10:24:34 2012
@@ -0,0 +1,37 @@
+/**
+ * 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.
+ */
+#
+# The logging properties used for eclipse testing, We want to see debug output on the console.
+#
+log4j.rootLogger=INFO, out
+
+# uncomment the following line to turn on Camel debugging
+#log4j.logger.org.apache.camel=DEBUG
+
+# uncomment the following line to turn on ActiveMQ debugging
+#log4j.logger.org.apache.activemq=DEBUG
+
+log4j.logger.org.springframework=WARN
+
+
+# CONSOLE appender not used by default
+log4j.appender.out=org.apache.log4j.ConsoleAppender
+log4j.appender.out.layout=org.apache.log4j.PatternLayout
+log4j.appender.out.layout.ConversionPattern=[%30.30t] %-30.30c{1} %-5p %m%n
+#log4j.appender.out.layout.ConversionPattern=%d [%-15.15t] %-5p %-30.30c{1} - %m%n
+
+log4j.throwableRenderer=org.apache.log4j.EnhancedThrowableRenderer
\ No newline at end of file

Added: camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/WebsocketComponentTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/WebsocketComponentTest.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/WebsocketComponentTest.java (added)
+++ camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/WebsocketComponentTest.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,44 @@
+/**
+ * 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.camel;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+
+public class WebsocketComponentTest extends CamelTestSupport {
+
+    @Test
+    public void testWebsocketCall() throws Exception {
+        Thread.sleep(15 * 60 * 1000);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+
+                from("websocket://foo").log("received message: ").log(" --> ${body}").choice().when(body(Integer.class).isGreaterThan(500)).to("seda://greater500")
+                        .when(body(Integer.class).isLessThan(500)).to("seda://less500").otherwise().setBody(constant("request failed...")).to("websocket://foo");
+
+                from("seda://greater500").setBody(constant("forms/c.xml")).log("C --> ${body}").to("websocket://foo");
+
+                from("seda://less500").setBody(constant("forms/b.xml")).log("B --> ${body}").to("websocket://foo");
+            }
+        };
+    }
+}

Added: camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/ProducerOnlyTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/ProducerOnlyTest.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/ProducerOnlyTest.java (added)
+++ camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/ProducerOnlyTest.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,67 @@
+/**
+ * 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.camel.component.websocket;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class ProducerOnlyTest extends CamelTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(WebsocketComponentLiveTest.class);
+
+    @Test
+    public void liveTest() throws Exception {
+        LOG.info("*** open URL  http://localhost:1989/producer-only.html ***");
+        Thread.sleep(1 * 60 * 1000);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+
+        return new RouteBuilder() {
+
+            private Counter counter = new Counter();
+
+            public void configure() {
+
+                WebsocketComponent component = getContext().getComponent("websocket", WebsocketComponent.class);
+                component.setHost("localhost");
+                component.setPort(1989);
+                component.setStaticResources("src/test/resources");
+
+                from("timer://foo?fixedRate=true&period=1000").bean(counter).setHeader(WebsocketConstants.SEND_TO_ALL, constant(true)).to("websocket://counter");
+            }
+        };
+    }
+
+    public class Counter {
+
+        //private int counter = 0;
+
+        private int counter;
+        
+        public int next() {
+            return ++counter;
+        }
+    }
+}

Added: camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/WebsocketComponentLiveTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/WebsocketComponentLiveTest.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/WebsocketComponentLiveTest.java (added)
+++ camel/trunk/components/camel-websocket/src/test/integration/org/apache/camel/component/websocket/WebsocketComponentLiveTest.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,57 @@
+/**
+ * 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.camel.component.websocket;
+
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.junit4.CamelTestSupport;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ *
+ */
+public class WebsocketComponentLiveTest extends CamelTestSupport {
+
+    private static final Logger LOG = LoggerFactory.getLogger(WebsocketComponentLiveTest.class);
+    
+    @Test
+    public void liveTest() throws Exception {
+        LOG.info("*** open URL  http://localhost:1989  and start chating ***");
+        Thread.sleep(1 * 60 * 1000);
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            public void configure() {
+                
+                WebsocketComponent component = getContext().getComponent("websocket", WebsocketComponent.class);
+                component.setHost("localhost");
+                component.setPort(1989);
+                component.setStaticResources("src/test/resources");
+                
+                from("websocket://foo")
+                    .log("${body}")
+                    .setHeader(WebsocketConstants.SEND_TO_ALL, constant(true))
+                    .to("websocket://foo");
+            }
+        };
+    }
+
+}

Added: camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/DefaultWebsocketTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/DefaultWebsocketTest.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/DefaultWebsocketTest.java (added)
+++ camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/DefaultWebsocketTest.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,161 @@
+/**
+ * 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.camel.component.websocket;
+
+import org.eclipse.jetty.websocket.WebSocket.Connection;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.times;
+
+/**
+ *
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class DefaultWebsocketTest {
+
+    private static final int CLOSE_CODE = -1;
+    private static final String MESSAGE = "message";
+    private static final String CONNECTION_KEY = "random-connection-key";
+
+    @Mock
+    private Connection connection;
+
+    @Mock
+    private WebsocketConsumer consumer;
+
+    @Mock
+    private NodeSynchronization sync;
+
+    private DefaultWebsocket defaultWebsocket;
+
+    /**
+     * @throws Exception
+     */
+    @Before
+    public void setUp() throws Exception {
+        // sync = new NodeSynchronizationImpl(new MemoryWebsocketStore());
+        defaultWebsocket = new DefaultWebsocket(sync, consumer);
+        defaultWebsocket.setConnectionKey(CONNECTION_KEY);
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.DefaultWebsocket#onClose(int, String)} .
+     */
+    @Test
+    public void testOnClose() {
+        defaultWebsocket.onClose(CLOSE_CODE, MESSAGE);
+        InOrder inOrder = inOrder(connection, consumer, sync);
+        inOrder.verify(sync, times(1)).removeSocket(defaultWebsocket);
+        inOrder.verifyNoMoreInteractions();
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.DefaultWebsocket#onOpen(org.eclipse.jetty.websocket.WebSocket.Connection)} .
+     */
+    @Test
+    public void testOnOpen() {
+        defaultWebsocket.onOpen(connection);
+
+        /*
+         * keyCaptor not functional anymore, because addSocket cannot be called with connectionKey
+         * 
+         * InOrder inOrder = inOrder(connection, consumer, sync); ArgumentCaptor<String> keyCaptor = ArgumentCaptor.forClass(String.class); inOrder.verify(sync,
+         * times(1)).addSocket((eq(defaultWebsocket))); inOrder.verifyNoMoreInteractions();
+         */
+
+        assertEquals(connection, defaultWebsocket.getConnection());
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.DefaultWebsocket#onMessage(String)} .
+     */
+    @Test
+    public void testOnMessage() {
+        defaultWebsocket.setConnectionKey(CONNECTION_KEY);
+        defaultWebsocket.onMessage(MESSAGE);
+        InOrder inOrder = inOrder(connection, consumer, sync);
+        inOrder.verify(consumer, times(1)).sendExchange(CONNECTION_KEY, MESSAGE);
+        inOrder.verifyNoMoreInteractions();
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.DefaultWebsocket#onMessage(String)} .
+     */
+    @Test
+    public void testOnMessageWithNullConsumer() {
+        defaultWebsocket = new DefaultWebsocket(sync, null);
+        defaultWebsocket.setConnectionKey(CONNECTION_KEY);
+        defaultWebsocket.onMessage(MESSAGE);
+        InOrder inOrder = inOrder(connection, consumer, sync);
+        inOrder.verify(consumer, times(0)).sendExchange(CONNECTION_KEY, MESSAGE);
+        inOrder.verifyNoMoreInteractions();
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.DefaultWebsocket#getConnection()} .
+     */
+    @Test
+    public void testGetConnection() {
+        assertNull(defaultWebsocket.getConnection());
+        defaultWebsocket.onOpen(connection);
+        assertEquals(connection, defaultWebsocket.getConnection());
+        defaultWebsocket.setConnection(null);
+        assertNull(defaultWebsocket.getConnection());
+        defaultWebsocket.setConnection(connection);
+        assertEquals(connection, defaultWebsocket.getConnection());
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.DefaultWebsocket#setConnection(org.eclipse.jetty.websocket.WebSocket.Connection)} .
+     */
+    @Test
+    public void testSetConnection() {
+        testGetConnection();
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.DefaultWebsocket#getConnectionKey()} .
+     */
+    @Test
+    public void testGetConnectionKey() {
+        defaultWebsocket.setConnectionKey(null);
+        assertNull(defaultWebsocket.getConnectionKey());
+        defaultWebsocket.onOpen(connection);
+        assertNotNull(defaultWebsocket.getConnectionKey());
+        defaultWebsocket.setConnectionKey(CONNECTION_KEY);
+        assertEquals(CONNECTION_KEY, defaultWebsocket.getConnectionKey());
+        defaultWebsocket.setConnectionKey(null);
+        assertNull(defaultWebsocket.getConnectionKey());
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.DefaultWebsocket#setConnectionKey(String)} .
+     */
+    @Test
+    public void testSetConnectionKey() {
+        testGetConnectionKey();
+    }
+}

Added: camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/MemoryWebsocketStoreTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/MemoryWebsocketStoreTest.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/MemoryWebsocketStoreTest.java (added)
+++ camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/MemoryWebsocketStoreTest.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,216 @@
+/**
+ * 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.camel.component.websocket;
+
+import java.util.Collection;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.when;
+
+/**
+ *
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class MemoryWebsocketStoreTest {
+
+    private static final String KEY_1 = "one";
+    private static final String KEY_2 = "two";
+
+    @Mock
+    private WebsocketConsumer consumer;
+
+    @Mock
+    private NodeSynchronization sync;
+
+    @Mock
+    private DefaultWebsocket websocket1 = new DefaultWebsocket(sync, consumer);;
+
+    @Mock
+    private DefaultWebsocket websocket2 = new DefaultWebsocket(sync, consumer);;
+
+    private MemoryWebsocketStore store;
+
+    /**
+     * @throws Exception
+     */
+    @Before
+    public void setUp() throws Exception {
+        store = new MemoryWebsocketStore();
+        when(websocket1.getConnectionKey()).thenReturn(KEY_1);
+        when(websocket2.getConnectionKey()).thenReturn(KEY_2);
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.MemoryWebsocketStore#add(String, org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test
+    public void testAdd() {
+        assertNotNull(websocket1.getConnectionKey());
+
+        store.add(websocket1);
+        assertEquals(websocket1, store.get(KEY_1));
+
+        store.add(websocket2);
+        assertEquals(websocket2, store.get(KEY_2));
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.MemoryWebsocketStore#add(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test(expected = NullPointerException.class)
+    public void testAddNullValue() {
+        store.add(null);
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.MemoryWebsocketStore#remove(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test
+    public void testRemoveDefaultWebsocket() {
+        // first call of websocket1.getConnectionKey()
+        store.add(websocket1);
+        assertEquals(websocket1, store.get(KEY_1));
+        // second call of websocket1.getConnectionKey()
+        store.remove(websocket1);
+        assertNull(store.get(KEY_1));
+
+        InOrder inOrder = inOrder(websocket1, websocket2);
+        inOrder.verify(websocket1, times(2)).getConnectionKey();
+        inOrder.verifyNoMoreInteractions();
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.MemoryWebsocketStore#remove(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test
+    public void testRemoveDefaultWebsocketKeyNotSet() {
+        // first call of websocket1.getConnectionKey()
+        store.add(websocket1);
+
+        // overload getConnectionKey() after store.add() - otherwise npe
+        when(websocket1.getConnectionKey()).thenReturn(null);
+
+        assertEquals(websocket1, store.get(KEY_1));
+
+        try {
+            store.remove(websocket1);
+            fail("Exception expected");
+        } catch (Exception e) {
+            assertEquals(NullPointerException.class, e.getClass());
+        }
+
+        InOrder inOrder = inOrder(websocket1, websocket2);
+        inOrder.verify(websocket1, times(2)).getConnectionKey();
+        inOrder.verifyNoMoreInteractions();
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.MemoryWebsocketStore#remove(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test
+    public void testRemoveNotExisting() {
+        websocket1.setConnectionKey(KEY_1);
+        store.add(websocket1);
+        assertEquals(websocket1, store.get(KEY_1));
+        assertNull(store.get(KEY_2));
+        store.remove(websocket2);
+        assertEquals(websocket1, store.get(KEY_1));
+        assertNull(store.get(KEY_2));
+
+        InOrder inOrder = inOrder(websocket1, websocket2);
+        inOrder.verify(websocket2, times(1)).getConnectionKey();
+        inOrder.verifyNoMoreInteractions();
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.MemoryWebsocketStore#remove(String)} .
+     */
+    @Test
+    public void testRemoveString() {
+        websocket1.setConnectionKey(KEY_1);
+        store.add(websocket1);
+        assertEquals(websocket1, store.get(KEY_1));
+        store.remove(KEY_1);
+        assertNull(store.get(KEY_1));
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.MemoryWebsocketStore#remove(String)} .
+     */
+    @Test
+    public void testRemoveStringNotExisting() {
+        websocket1.setConnectionKey(KEY_1);
+        store.add(websocket1);
+        assertEquals(websocket1, store.get(KEY_1));
+        assertNull(store.get(KEY_2));
+        store.remove(KEY_2);
+        assertEquals(websocket1, store.get(KEY_1));
+        assertNull(store.get(KEY_2));
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.MemoryWebsocketStore#get(String)} .
+     */
+    @Test
+    public void testGetString() {
+        websocket1.setConnectionKey(KEY_1);
+        store.add(websocket1);
+        assertEquals(websocket1, store.get(KEY_1));
+        assertNull(store.get(KEY_2));
+        websocket2.setConnectionKey(KEY_2);
+        store.add(websocket2);
+        assertEquals(websocket1, store.get(KEY_1));
+        assertEquals(websocket2, store.get(KEY_2));
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.MemoryWebsocketStore#getAll()} .
+     */
+    @Test
+    public void testGetAll() {
+        Collection<DefaultWebsocket> sockets = store.getAll();
+        assertNotNull(sockets);
+        assertEquals(0, sockets.size());
+
+        websocket1.setConnectionKey(KEY_1);
+        store.add(websocket1);
+        sockets = store.getAll();
+        assertNotNull(sockets);
+        assertEquals(1, sockets.size());
+        assertTrue(sockets.contains(websocket1));
+
+        websocket2.setConnectionKey(KEY_2);
+        store.add(websocket2);
+        sockets = store.getAll();
+        assertNotNull(sockets);
+        assertEquals(2, sockets.size());
+        assertTrue(sockets.contains(websocket1));
+        assertTrue(sockets.contains(websocket2));
+    }
+}

Added: camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/NodeSynchronizationImplTest.java
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/NodeSynchronizationImplTest.java?rev=1228060&view=auto
==============================================================================
--- camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/NodeSynchronizationImplTest.java (added)
+++ camel/trunk/components/camel-websocket/src/test/java/org/apache/camel/component/websocket/NodeSynchronizationImplTest.java Fri Jan  6 10:24:34 2012
@@ -0,0 +1,235 @@
+/**
+ * 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.camel.component.websocket;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+/**
+ *
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class NodeSynchronizationImplTest {
+
+    private static final String KEY_1 = "one";
+    private static final String KEY_2 = "two";
+    private static final String KEY_3 = "three";
+
+    @Mock
+    private WebsocketConsumer consumer;
+
+    private DefaultWebsocket websocket1;
+    private DefaultWebsocket websocket2;
+
+    private NodeSynchronization sync;
+
+    private MemoryWebsocketStore store1;
+    private MemoryWebsocketStore store2;
+
+    /**
+     * @throws Exception
+     */
+    @Before
+    public void setUp() throws Exception {
+
+        store1 = new MemoryWebsocketStore();
+        store2 = new MemoryWebsocketStore();
+
+        websocket1 = new DefaultWebsocket(sync, consumer);
+        websocket1.setConnectionKey(KEY_1);
+
+        websocket2 = new DefaultWebsocket(sync, consumer);
+        websocket2.setConnectionKey(KEY_2);
+
+        // when(websocket1.getConnectionKey()).thenReturn(KEY_1);
+        // when(websocket2.getConnectionKey()).thenReturn(KEY_2);
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.NodeSynchronization#addSocket(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test
+    public void testAddSocketMemoryAndGlobal() {
+        sync = new NodeSynchronizationImpl(store1, store2);
+
+        sync.addSocket(websocket1);
+        assertEquals(websocket1, store1.get(KEY_1));
+        assertEquals(store1.get(KEY_1), store2.get(KEY_1));
+
+        sync.addSocket(websocket2);
+        assertEquals(websocket2, store1.get(KEY_2));
+        assertEquals(store1.get(KEY_2), store2.get(KEY_2));
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.NodeSynchronization#addSocket(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test
+    public void testAddSocketMemoryOnly() {
+        sync = new NodeSynchronizationImpl(store1);
+
+        sync.addSocket(websocket1);
+        assertEquals(websocket1, store1.get(KEY_1));
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.NodeSynchronization#addSocket(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test
+    public void testAddSocketMemoryAndNullGlobal() {
+        sync = new NodeSynchronizationImpl(store1, null);
+
+        sync.addSocket(websocket1);
+        assertEquals(websocket1, store1.get(KEY_1));
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.NodeSynchronization#addSocket(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test(expected = NullPointerException.class)
+    public void testAddNullValue() {
+        sync.addSocket(null);
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.NodeSynchronization#removeSocket(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test
+    public void testRemoveDefaultWebsocket() {
+        sync = new NodeSynchronizationImpl(store1, store2);
+
+        // first call of websocket1.getConnectionKey()
+        sync.addSocket(websocket1);
+        assertEquals(websocket1, store1.get(KEY_1));
+        assertEquals(store1.get(KEY_1), store2.get(KEY_1));
+
+        sync.addSocket(websocket2);
+        assertEquals(websocket2, store1.get(KEY_2));
+        assertEquals(store1.get(KEY_2), store2.get(KEY_2));
+
+        // second call of websocket1.getConnectionKey()
+        sync.removeSocket(websocket1);
+        assertNull(store1.get(KEY_1));
+        assertNull(store2.get(KEY_1));
+
+        assertNotNull(store1.get(KEY_2));
+        assertNotNull(store2.get(KEY_2));
+
+        sync.removeSocket(websocket2);
+        assertNull(store1.get(KEY_2));
+        assertNull(store2.get(KEY_2));
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.NodeSynchronization#removeSocket(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test
+    public void testRemoveDefaultWebsocketKeyNotSet() {
+        sync = new NodeSynchronizationImpl(store1);
+
+        // first call of websocket1.getConnectionKey()
+        sync.addSocket(websocket1);
+        assertEquals(websocket1, store1.get(KEY_1));
+
+        // setConnectionKey(null) after sync.addSocket()- otherwise npe
+        websocket1.setConnectionKey(null);
+
+        try {
+            // second call of websocket1.getConnectionKey()
+            sync.removeSocket(websocket1);
+            fail("Exception expected");
+        } catch (Exception e) {
+            assertEquals(NullPointerException.class, e.getClass());
+        }
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.NodeSynchronization#removeSocket(org.apache.camel.component.websocket.DefaultWebsocket)} .
+     */
+    @Test
+    public void testRemoveNotExisting() {
+        sync = new NodeSynchronizationImpl(store1);
+
+        // first call of websocket1.getConnectionKey()
+        sync.addSocket(websocket1);
+        assertEquals(websocket1, store1.get(KEY_1));
+
+        assertNull(store1.get(KEY_2));
+        sync.removeSocket(websocket2);
+
+        assertEquals(websocket1, store1.get(KEY_1));
+        assertNull(store1.get(KEY_2));
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.NodeSynchronization#removeSocket(String)} .
+     */
+    @Test
+    public void testRemoveString() {
+        sync = new NodeSynchronizationImpl(store1, store2);
+
+        // first call of websocket1.getConnectionKey()
+        sync.addSocket(websocket1);
+        assertEquals(websocket1, store1.get(KEY_1));
+        assertEquals(store1.get(KEY_1), store2.get(KEY_1));
+
+        sync.addSocket(websocket2);
+        assertEquals(websocket2, store1.get(KEY_2));
+        assertEquals(store1.get(KEY_2), store2.get(KEY_2));
+
+        // second call of websocket1.getConnectionKey()
+        sync.removeSocket(KEY_1);
+        assertNull(store1.get(KEY_1));
+        assertNull(store2.get(KEY_1));
+
+        assertNotNull(store1.get(KEY_2));
+        assertNotNull(store2.get(KEY_2));
+
+        sync.removeSocket(KEY_2);
+        assertNull(store1.get(KEY_2));
+        assertNull(store2.get(KEY_2));
+    }
+
+    /**
+     * Test method for {@link org.apache.camel.component.websocket.NodeSynchronization#removeSocket(String)} .
+     */
+    @Test
+    public void testRemoveStringNotExisting() {
+
+        sync = new NodeSynchronizationImpl(store1);
+
+        // first call of websocket1.getConnectionKey()
+        sync.addSocket(websocket1);
+        assertEquals(websocket1, store1.get(KEY_1));
+
+        assertNull(store1.get(KEY_3));
+        sync.removeSocket(KEY_3);
+
+        assertEquals(websocket1, store1.get(KEY_1));
+        assertNull(store1.get(KEY_3));
+
+    }
+
+}