You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@curator.apache.org by ra...@apache.org on 2014/03/22 14:35:20 UTC

[05/10] git commit: wip

wip


Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/0910d482
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/0910d482
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/0910d482

Branch: refs/heads/websockets
Commit: 0910d4821f09bf1d965c8547ef82b1516976a6b8
Parents: 20d8c06
Author: randgalt <ra...@apache.org>
Authored: Fri Jan 10 18:44:13 2014 -0500
Committer: randgalt <ra...@apache.org>
Committed: Fri Jan 10 18:44:13 2014 -0500

----------------------------------------------------------------------
 curator-x-websockets/pom.xml                    |  71 ++++++++++++
 .../curator/x/websockets/ClientCreator.java     |  27 +++++
 .../x/websockets/CuratorWebsocketsConfig.java   |  68 ++++++++++++
 .../x/websockets/CuratorWebsocketsServer.java   |  77 +++++++++++++
 .../x/websockets/DefaultClientCreator.java      |  45 ++++++++
 .../curator/x/websockets/api/ApiCommand.java    |  30 ++++++
 .../x/websockets/api/CommandManager.java        |  49 +++++++++
 .../curator/x/websockets/api/JsonUtils.java     |  56 ++++++++++
 .../x/websockets/api/zookeeper/Create.java      |  46 ++++++++
 .../x/websockets/details/CuratorEndpoint.java   | 107 +++++++++++++++++++
 .../details/CuratorWebsocketsSession.java       |  53 +++++++++
 .../x/websockets/details/SessionManager.java    |  64 +++++++++++
 .../apache/curator/x/websockets/TestServer.java |  30 ++++++
 pom.xml                                         |   1 +
 14 files changed, 724 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/pom.xml
----------------------------------------------------------------------
diff --git a/curator-x-websockets/pom.xml b/curator-x-websockets/pom.xml
new file mode 100644
index 0000000..95803c1
--- /dev/null
+++ b/curator-x-websockets/pom.xml
@@ -0,0 +1,71 @@
+<?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/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>apache-curator</artifactId>
+        <groupId>org.apache.curator</groupId>
+        <version>2.3.2-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>curator-x-websockets</artifactId>
+    <version>2.3.2-SNAPSHOT</version>
+
+    <properties>
+        <tyrus.version>1.3.3</tyrus.version>
+
+        <osgi.import.package>
+            *
+        </osgi.import.package>
+        <osgi.export.package>
+            org.apache.curator.x.websockets*;version="${project.version}";-noimport:=true
+        </osgi.export.package>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.curator</groupId>
+            <artifactId>curator-recipes</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.glassfish.tyrus</groupId>
+            <artifactId>tyrus-server</artifactId>
+            <version>${tyrus.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.glassfish.tyrus</groupId>
+            <artifactId>tyrus-container-grizzly-server</artifactId>
+            <version>${tyrus.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+            <version>1.9.2</version>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/ClientCreator.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/ClientCreator.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/ClientCreator.java
new file mode 100644
index 0000000..65b8fe0
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/ClientCreator.java
@@ -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.curator.x.websockets;
+
+import org.apache.curator.framework.CuratorFramework;
+
+public interface ClientCreator
+{
+    public CuratorFramework newClient() throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/CuratorWebsocketsConfig.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/CuratorWebsocketsConfig.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/CuratorWebsocketsConfig.java
new file mode 100644
index 0000000..c7227c4
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/CuratorWebsocketsConfig.java
@@ -0,0 +1,68 @@
+/**
+ * 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.curator.x.websockets;
+
+public class CuratorWebsocketsConfig
+{
+    private String bindHost = "localhost";
+    private int port = 8080;
+    private String rootPath = "/websockets";
+    private String websocketPath = "/curator";
+
+    public String getBindHost()
+    {
+        return bindHost;
+    }
+
+    public void setBindHost(String bindHost)
+    {
+        this.bindHost = bindHost;
+    }
+
+    public int getPort()
+    {
+        return port;
+    }
+
+    public void setPort(int port)
+    {
+        this.port = port;
+    }
+
+    public String getRootPath()
+    {
+        return rootPath;
+    }
+
+    public void setRootPath(String rootPath)
+    {
+        this.rootPath = rootPath;
+    }
+
+    public String getWebsocketPath()
+    {
+        return websocketPath;
+    }
+
+    public void setWebsocketPath(String websocketPath)
+    {
+        this.websocketPath = websocketPath;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/CuratorWebsocketsServer.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/CuratorWebsocketsServer.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/CuratorWebsocketsServer.java
new file mode 100644
index 0000000..3bc8ff2
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/CuratorWebsocketsServer.java
@@ -0,0 +1,77 @@
+/**
+ * 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.curator.x.websockets;
+
+import com.google.common.base.Preconditions;
+import org.apache.curator.x.websockets.api.CommandManager;
+import org.apache.curator.x.websockets.details.CuratorEndpoint;
+import org.apache.curator.x.websockets.details.SessionManager;
+import org.glassfish.tyrus.spi.ServerContainer;
+import org.glassfish.tyrus.spi.ServerContainerFactory;
+import javax.websocket.server.ServerEndpointConfig;
+import java.io.Closeable;
+import java.util.List;
+
+public class CuratorWebsocketsServer implements Closeable
+{
+    private final ServerContainer serverContainer;
+    private final String rootPath;
+    private final int port;
+    private final CommandManager commandManager = new CommandManager();
+
+    public CuratorWebsocketsServer(CuratorWebsocketsConfig config, ClientCreator clientCreator) throws Exception
+    {
+        rootPath = config.getRootPath();
+        port = config.getPort();
+
+        serverContainer = ServerContainerFactory.createServerContainer(null);
+
+        final SessionManager sessionManager = new SessionManager(clientCreator, commandManager);
+        ServerEndpointConfig.Configurator configurator = new ServerEndpointConfig.Configurator()
+        {
+            @Override
+            public String getNegotiatedSubprotocol(List<String> supported, List<String> requested)
+            {
+                return super.getNegotiatedSubprotocol(supported, requested);
+            }
+
+            @Override
+            public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException
+            {
+                Preconditions.checkArgument(endpointClass.equals(CuratorEndpoint.class), "Expected CuratorEndpoint: " + endpointClass.getName());
+                //noinspection unchecked
+                return (T)new CuratorEndpoint(sessionManager);
+            }
+        };
+        ServerEndpointConfig serverEndpointConfig = ServerEndpointConfig.Builder.create(CuratorEndpoint.class, config.getWebsocketPath()).configurator(configurator).build();
+        serverContainer.addEndpoint(serverEndpointConfig);
+    }
+
+    public void start() throws Exception
+    {
+        serverContainer.start(rootPath, port);
+    }
+
+    @Override
+    public void close()
+    {
+        serverContainer.stop();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/DefaultClientCreator.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/DefaultClientCreator.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/DefaultClientCreator.java
new file mode 100644
index 0000000..619445c
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/DefaultClientCreator.java
@@ -0,0 +1,45 @@
+/**
+ * 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.curator.x.websockets;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.retry.ExponentialBackoffRetry;
+
+public class DefaultClientCreator implements ClientCreator
+{
+    private final ExponentialBackoffRetry retryPolicy;
+
+    public DefaultClientCreator()
+    {
+        this(new ExponentialBackoffRetry(100, 3));
+    }
+
+    public DefaultClientCreator(ExponentialBackoffRetry retryPolicy)
+    {
+        this.retryPolicy = retryPolicy;
+    }
+
+    @Override
+    public CuratorFramework newClient() throws Exception
+    {
+        return CuratorFrameworkFactory.newClient("localhost:2181", retryPolicy);
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/ApiCommand.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/ApiCommand.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/ApiCommand.java
new file mode 100644
index 0000000..438e1a6
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/ApiCommand.java
@@ -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.curator.x.websockets.api;
+
+import org.apache.curator.x.websockets.details.CuratorWebsocketsSession;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectReader;
+import org.codehaus.jackson.map.ObjectWriter;
+
+public interface ApiCommand
+{
+    public String process(JsonNode input, CuratorWebsocketsSession session, ObjectReader reader, ObjectWriter writer) throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/CommandManager.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/CommandManager.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/CommandManager.java
new file mode 100644
index 0000000..c16e927
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/CommandManager.java
@@ -0,0 +1,49 @@
+/**
+ * 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.curator.x.websockets.api;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.curator.x.websockets.api.zookeeper.Create;
+import java.io.FileNotFoundException;
+import java.util.Map;
+
+public class CommandManager
+{
+    private final Map<String, Class<? extends ApiCommand>> commands;
+
+    public CommandManager()
+    {
+        ImmutableMap.Builder<String, Class<? extends ApiCommand>> builder = ImmutableMap.builder();
+
+        builder.put("zookeeper/create", Create.class);
+
+        commands = builder.build();
+    }
+
+    public ApiCommand newCommand(String name) throws Exception
+    {
+        Class<? extends ApiCommand> clazz = commands.get(name);
+        if ( clazz == null )
+        {
+            throw new FileNotFoundException(name);
+        }
+        return clazz.newInstance();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/JsonUtils.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/JsonUtils.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/JsonUtils.java
new file mode 100644
index 0000000..8c18d7c
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/JsonUtils.java
@@ -0,0 +1,56 @@
+/**
+ * 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.curator.x.websockets.api;
+
+import org.codehaus.jackson.JsonNode;
+
+public class JsonUtils
+{
+    public static String getRequiredString(JsonNode node, String name) throws Exception
+    {
+        JsonNode jsonNode = node.get(name);
+        if ( jsonNode == null )
+        {
+            throw new Exception("Required field is missing: " + name);
+        }
+        return jsonNode.asText();
+    }
+
+    public static String getOptionalString(JsonNode node, String name)
+    {
+        return getOptionalString(node, name, null);
+    }
+
+    public static String getOptionalString(JsonNode node, String name, String defaultValue)
+    {
+        JsonNode jsonNode = node.get(name);
+        return (jsonNode != null) ? jsonNode.asText() : defaultValue;
+    }
+
+    public static boolean getOptionalBoolean(JsonNode node, String name)
+    {
+        JsonNode jsonNode = node.get(name);
+        return (jsonNode != null) && jsonNode.asBoolean();
+    }
+
+    private JsonUtils()
+    {
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/zookeeper/Create.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/zookeeper/Create.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/zookeeper/Create.java
new file mode 100644
index 0000000..3cd148d
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/api/zookeeper/Create.java
@@ -0,0 +1,46 @@
+/**
+ * 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.curator.x.websockets.api.zookeeper;
+
+import org.apache.curator.x.websockets.api.ApiCommand;
+import org.apache.curator.x.websockets.api.JsonUtils;
+import org.apache.curator.x.websockets.details.CuratorWebsocketsSession;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectReader;
+import org.codehaus.jackson.map.ObjectWriter;
+
+public class Create implements ApiCommand
+{
+    @Override
+    public String process(JsonNode input, CuratorWebsocketsSession session, ObjectReader reader, ObjectWriter writer) throws Exception
+    {
+        String path = JsonUtils.getRequiredString(input, "path");
+        boolean withProtection = JsonUtils.getOptionalBoolean(input, "withProtection");
+        boolean creatingParentsIfNeeded = JsonUtils.getOptionalBoolean(input, "creatingParentsIfNeeded");
+        boolean compressed = JsonUtils.getOptionalBoolean(input, "compressed");
+        boolean async = JsonUtils.getOptionalBoolean(input, "async");
+        String mode = JsonUtils.getOptionalString(input, "mode", "persistent");
+
+        JsonNode payload = input.get("payload");
+
+        // TODO ACL
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/CuratorEndpoint.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/CuratorEndpoint.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/CuratorEndpoint.java
new file mode 100644
index 0000000..576f475
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/CuratorEndpoint.java
@@ -0,0 +1,107 @@
+/**
+ * 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.curator.x.websockets.details;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.x.websockets.api.ApiCommand;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectReader;
+import org.codehaus.jackson.map.ObjectWriter;
+import javax.websocket.CloseReason;
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
+import javax.websocket.Session;
+import java.io.IOException;
+
+public class CuratorEndpoint extends Endpoint
+{
+    private final SessionManager sessionManager;
+    private final ObjectReader reader = new ObjectMapper().reader();
+    private final ObjectWriter writer = new ObjectMapper().writer();
+
+    public CuratorEndpoint(SessionManager sessionManager)
+    {
+        this.sessionManager = sessionManager;
+    }
+
+    @Override
+    public void onOpen(final Session session, EndpointConfig config)
+    {
+        try
+        {
+            CuratorFramework client = sessionManager.getClientCreator().newClient();
+            sessionManager.put(session, new CuratorWebsocketsSession(client, session));
+
+            client.start();
+        }
+        catch ( Exception e )
+        {
+            // TODO
+        }
+
+        MessageHandler handler = new MessageHandler.Whole<String>()
+        {
+            @Override
+            public void onMessage(String message)
+            {
+                processMessage(session, message);
+            }
+        };
+        session.addMessageHandler(handler);
+    }
+
+    @Override
+    public void onClose(Session session, CloseReason closeReason)
+    {
+        CuratorWebsocketsSession curatorWebsocketsSession = sessionManager.remove(session);
+        if ( curatorWebsocketsSession != null )
+        {
+            curatorWebsocketsSession.close();
+        }
+    }
+
+    private void processMessage(Session session, String message)
+    {
+        try
+        {
+            CuratorWebsocketsSession curatorWebsocketsSession = sessionManager.get(session);
+            if ( curatorWebsocketsSession == null )
+            {
+                throw new Exception("No session found for sessionId: " + session.getId());
+            }
+
+            JsonNode jsonNode = reader.readTree(message);
+            JsonNode command = jsonNode.get("command");
+            if ( command == null )
+            {
+                throw new Exception("Missing field: \"command\"");
+            }
+            String commandName = command.asText();
+            ApiCommand apiCommand = sessionManager.getCommandManager().newCommand(commandName);
+            apiCommand.process(jsonNode, curatorWebsocketsSession, reader, writer);
+        }
+        catch ( Exception e )
+        {
+            // TODO
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/CuratorWebsocketsSession.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/CuratorWebsocketsSession.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/CuratorWebsocketsSession.java
new file mode 100644
index 0000000..9df8b68
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/CuratorWebsocketsSession.java
@@ -0,0 +1,53 @@
+/**
+ * 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.curator.x.websockets.details;
+
+import com.google.common.io.Closeables;
+import org.apache.curator.framework.CuratorFramework;
+import javax.websocket.Session;
+import java.io.Closeable;
+
+public class CuratorWebsocketsSession implements Closeable
+{
+    private final CuratorFramework client;
+    private final Session session;
+
+    public CuratorWebsocketsSession(CuratorFramework client, Session session)
+    {
+        this.client = client;
+        this.session = session;
+    }
+
+    @Override
+    public void close()
+    {
+        Closeables.closeQuietly(client);
+    }
+
+    public CuratorFramework getClient()
+    {
+        return client;
+    }
+
+    public Session getSession()
+    {
+        return session;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/SessionManager.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/SessionManager.java b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/SessionManager.java
new file mode 100644
index 0000000..5c37ac3
--- /dev/null
+++ b/curator-x-websockets/src/main/java/org/apache/curator/x/websockets/details/SessionManager.java
@@ -0,0 +1,64 @@
+/**
+ * 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.curator.x.websockets.details;
+
+import com.google.common.collect.Maps;
+import org.apache.curator.x.websockets.ClientCreator;
+import org.apache.curator.x.websockets.api.CommandManager;
+import javax.websocket.Session;
+import java.util.Map;
+
+public class SessionManager
+{
+    private final Map<String, CuratorWebsocketsSession> sessions = Maps.newConcurrentMap();
+    private final ClientCreator clientCreator;
+    private final CommandManager commandManager;
+
+    public SessionManager(ClientCreator clientCreator, CommandManager commandManager)
+    {
+        this.clientCreator = clientCreator;
+        this.commandManager = commandManager;
+    }
+
+    public void put(Session session, CuratorWebsocketsSession curatorWebsocketsSession)
+    {
+        sessions.put(session.getId(), curatorWebsocketsSession);
+    }
+
+    public CuratorWebsocketsSession get(Session session)
+    {
+        return sessions.get(session.getId());
+    }
+
+    public CuratorWebsocketsSession remove(Session session)
+    {
+        return sessions.remove(session.getId());
+    }
+
+    public ClientCreator getClientCreator()
+    {
+        return clientCreator;
+    }
+
+    public CommandManager getCommandManager()
+    {
+        return commandManager;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/curator-x-websockets/src/test/java/org/apache/curator/x/websockets/TestServer.java
----------------------------------------------------------------------
diff --git a/curator-x-websockets/src/test/java/org/apache/curator/x/websockets/TestServer.java b/curator-x-websockets/src/test/java/org/apache/curator/x/websockets/TestServer.java
new file mode 100644
index 0000000..f9eef23
--- /dev/null
+++ b/curator-x-websockets/src/test/java/org/apache/curator/x/websockets/TestServer.java
@@ -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.curator.x.websockets;
+
+public class TestServer
+{
+    public static void main(String[] args) throws Exception
+    {
+        CuratorWebsocketsServer server = new CuratorWebsocketsServer(new CuratorWebsocketsConfig(), new DefaultClientCreator());
+        server.start();
+        Thread.currentThread().join();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/0910d482/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index af548c2..91e899f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -224,6 +224,7 @@
         <module>curator-examples</module>
         <module>curator-x-discovery</module>
         <module>curator-x-discovery-server</module>
+        <module>curator-x-websockets</module>
     </modules>
 
     <dependencyManagement>