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/02/15 17:38:38 UTC
[1/2] initial commit for Curator REST
Repository: curator
Updated Branches:
refs/heads/CURATOR-88 [created] 2b2e78582
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/SetDataSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/SetDataSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/SetDataSpec.java
new file mode 100644
index 0000000..faa83a9
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/SetDataSpec.java
@@ -0,0 +1,113 @@
+package org.apache.curator.x.rest.entities;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class SetDataSpec
+{
+ private String path;
+ private boolean watched;
+ private String watchId;
+ private boolean async;
+ private String asyncId;
+ private boolean compressed;
+ private int version;
+ private String data;
+
+ public SetDataSpec()
+ {
+ this("/", false, "", false, "", false, -1, "");
+ }
+
+ public SetDataSpec(String path, boolean watched, String watchId, boolean async, String asyncId, boolean compressed, int version, String data)
+ {
+ this.path = path;
+ this.watched = watched;
+ this.watchId = watchId;
+ this.async = async;
+ this.asyncId = asyncId;
+ this.compressed = compressed;
+ this.version = version;
+ this.data = data;
+ }
+
+ public String getData()
+ {
+ return data;
+ }
+
+ public void setData(String data)
+ {
+ this.data = data;
+ }
+
+ public int getVersion()
+ {
+ return version;
+ }
+
+ public void setVersion(int version)
+ {
+ this.version = version;
+ }
+
+ public String getWatchId()
+ {
+ return watchId;
+ }
+
+ public void setWatchId(String watchId)
+ {
+ this.watchId = watchId;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public boolean isWatched()
+ {
+ return watched;
+ }
+
+ public void setWatched(boolean watched)
+ {
+ this.watched = watched;
+ }
+
+ public boolean isAsync()
+ {
+ return async;
+ }
+
+ public void setAsync(boolean async)
+ {
+ this.async = async;
+ }
+
+ public String getAsyncId()
+ {
+ return asyncId;
+ }
+
+ public void setAsyncId(String asyncId)
+ {
+ this.asyncId = asyncId;
+ }
+
+ public boolean isCompressed()
+ {
+ return compressed;
+ }
+
+ public void setCompressed(boolean compressed)
+ {
+ this.compressed = compressed;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/StatusMessage.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/StatusMessage.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/StatusMessage.java
new file mode 100644
index 0000000..9171f94
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/StatusMessage.java
@@ -0,0 +1,65 @@
+package org.apache.curator.x.rest.entities;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class StatusMessage
+{
+ private String type;
+ private String message;
+ private String details;
+ private String sourceId;
+
+ public StatusMessage()
+ {
+ this("", "", "", "");
+ }
+
+ public StatusMessage(String type, String sourceId, String message, String details)
+ {
+ this.type = type;
+ this.sourceId = sourceId;
+ this.message = message;
+ this.details = details;
+ }
+
+ public String getType()
+ {
+ return type;
+ }
+
+ public void setType(String type)
+ {
+ this.type = type;
+ }
+
+ public String getMessage()
+ {
+ return message;
+ }
+
+ public void setMessage(String message)
+ {
+ this.message = message;
+ }
+
+ public String getDetails()
+ {
+ return details;
+ }
+
+ public void setDetails(String details)
+ {
+ this.details = details;
+ }
+
+ public String getSourceId()
+ {
+ return sourceId;
+ }
+
+ public void setSourceId(String sourceId)
+ {
+ this.sourceId = sourceId;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 981e405..e600d42 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-rest</module>
</modules>
<dependencyManagement>
@@ -275,6 +276,18 @@
<artifactId>curator-x-discovery-server</artifactId>
<version>2.4.1-SNAPSHOT</version>
</dependency>
+
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ <version>1.9.2</version>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ <version>1.1.1</version>
+ </dependency>
</dependencies>
</dependencyManagement>
[2/2] git commit: initial commit for Curator REST
Posted by ra...@apache.org.
initial commit for Curator REST
Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/2b2e7858
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/2b2e7858
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/2b2e7858
Branch: refs/heads/CURATOR-88
Commit: 2b2e7858212def66c50ac9d383e0bbbc88793e4e
Parents: 9f10828
Author: randgalt <ra...@apache.org>
Authored: Sat Feb 15 11:39:22 2014 -0500
Committer: randgalt <ra...@apache.org>
Committed: Sat Feb 15 11:39:22 2014 -0500
----------------------------------------------------------------------
curator-x-discovery-server/pom.xml | 1 -
curator-x-discovery/pom.xml | 1 -
curator-x-rest/pom.xml | 47 ++++
.../curator/x/rest/CuratorRestClasses.java | 35 +++
.../curator/x/rest/CuratorRestContext.java | 132 ++++++++++
.../curator/x/rest/api/ClientResource.java | 247 +++++++++++++++++++
.../apache/curator/x/rest/api/Constants.java | 70 ++++++
.../curator/x/rest/api/LeaderResource.java | 91 +++++++
.../apache/curator/x/rest/api/LockResource.java | 77 ++++++
.../curator/x/rest/api/NodeCacheResource.java | 102 ++++++++
.../x/rest/api/PathChildrenCacheResource.java | 128 ++++++++++
.../api/PersistentEphemeralNodeResource.java | 68 +++++
.../x/rest/api/ReadWriteLockResource.java | 94 +++++++
.../x/rest/api/RestBackgroundCallback.java | 32 +++
.../apache/curator/x/rest/api/RestWatcher.java | 27 ++
.../curator/x/rest/api/SemaphoreResource.java | 103 ++++++++
.../curator/x/rest/api/SessionResource.java | 61 +++++
.../apache/curator/x/rest/details/Closer.java | 6 +
.../apache/curator/x/rest/details/Session.java | 85 +++++++
.../curator/x/rest/details/SessionManager.java | 73 ++++++
.../curator/x/rest/entities/CreateSpec.java | 114 +++++++++
.../curator/x/rest/entities/DeleteSpec.java | 77 ++++++
.../curator/x/rest/entities/ExistsSpec.java | 77 ++++++
.../x/rest/entities/GetChildrenSpec.java | 89 +++++++
.../curator/x/rest/entities/GetDataSpec.java | 89 +++++++
.../curator/x/rest/entities/LeaderSpec.java | 38 +++
.../curator/x/rest/entities/LockSpec.java | 41 +++
.../curator/x/rest/entities/NodeCacheSpec.java | 54 ++++
.../curator/x/rest/entities/NodeData.java | 54 ++++
.../x/rest/entities/PathChildrenCacheSpec.java | 66 +++++
.../entities/PersistentEphemeralNodeSpec.java | 52 ++++
.../curator/x/rest/entities/SemaphoreSpec.java | 65 +++++
.../curator/x/rest/entities/SetDataSpec.java | 113 +++++++++
.../curator/x/rest/entities/StatusMessage.java | 65 +++++
pom.xml | 13 +
35 files changed, 2485 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-discovery-server/pom.xml
----------------------------------------------------------------------
diff --git a/curator-x-discovery-server/pom.xml b/curator-x-discovery-server/pom.xml
index 2901abf..a39c04d 100644
--- a/curator-x-discovery-server/pom.xml
+++ b/curator-x-discovery-server/pom.xml
@@ -55,7 +55,6 @@
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
- <version>1.1.1</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-discovery/pom.xml
----------------------------------------------------------------------
diff --git a/curator-x-discovery/pom.xml b/curator-x-discovery/pom.xml
index d40b225..9ff2280 100644
--- a/curator-x-discovery/pom.xml
+++ b/curator-x-discovery/pom.xml
@@ -54,7 +54,6 @@
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
- <version>1.9.2</version>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/pom.xml
----------------------------------------------------------------------
diff --git a/curator-x-rest/pom.xml b/curator-x-rest/pom.xml
new file mode 100644
index 0000000..2e26034
--- /dev/null
+++ b/curator-x-rest/pom.xml
@@ -0,0 +1,47 @@
+<?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.4.1-SNAPSHOT</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>curator-x-rest</artifactId>
+ <version>2.4.1-SNAPSHOT</version>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.curator</groupId>
+ <artifactId>curator-recipes</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.ws.rs</groupId>
+ <artifactId>jsr311-api</artifactId>
+ </dependency>
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/CuratorRestClasses.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/CuratorRestClasses.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/CuratorRestClasses.java
new file mode 100644
index 0000000..5b56b46
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/CuratorRestClasses.java
@@ -0,0 +1,35 @@
+package org.apache.curator.x.rest;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.curator.x.rest.api.ClientResource;
+import org.apache.curator.x.rest.api.LeaderResource;
+import org.apache.curator.x.rest.api.LockResource;
+import org.apache.curator.x.rest.api.NodeCacheResource;
+import org.apache.curator.x.rest.api.PathChildrenCacheResource;
+import org.apache.curator.x.rest.api.PersistentEphemeralNodeResource;
+import org.apache.curator.x.rest.api.ReadWriteLockResource;
+import org.apache.curator.x.rest.api.SemaphoreResource;
+import org.apache.curator.x.rest.api.SessionResource;
+import java.util.List;
+
+public class CuratorRestClasses
+{
+ public static List<Class<?>> getClasses()
+ {
+ ImmutableList.Builder<Class<?>> builder = ImmutableList.builder();
+ builder.add(SessionResource.class);
+ builder.add(ClientResource.class);
+ builder.add(LockResource.class);
+ builder.add(SemaphoreResource.class);
+ builder.add(PathChildrenCacheResource.class);
+ builder.add(NodeCacheResource.class);
+ builder.add(LeaderResource.class);
+ builder.add(ReadWriteLockResource.class);
+ builder.add(PersistentEphemeralNodeResource.class);
+ return builder.build();
+ }
+
+ private CuratorRestClasses()
+ {
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/CuratorRestContext.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/CuratorRestContext.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/CuratorRestContext.java
new file mode 100644
index 0000000..ba33fe6
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/CuratorRestContext.java
@@ -0,0 +1,132 @@
+package org.apache.curator.x.rest;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Queues;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.state.ConnectionState;
+import org.apache.curator.framework.state.ConnectionStateListener;
+import org.apache.curator.utils.ThreadUtils;
+import org.apache.curator.x.rest.details.SessionManager;
+import org.apache.curator.x.rest.entities.StatusMessage;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.io.Closeable;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class CuratorRestContext implements Closeable
+{
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final SessionManager sessionManager = new SessionManager();
+ private final ObjectMapper mapper = new ObjectMapper();
+ private final ObjectWriter writer = mapper.writer();
+ private final CuratorFramework client;
+ private final int sessionLengthMs;
+ private final AtomicReference<State> state = new AtomicReference<State>(State.LATENT);
+ private final ScheduledExecutorService executorService = ThreadUtils.newSingleThreadScheduledExecutor("CuratorRestContext");
+ private final ConnectionStateListener connectionStateListener = new ConnectionStateListener()
+ {
+ @Override
+ public void stateChanged(CuratorFramework client, ConnectionState newState)
+ {
+ if ( newState == ConnectionState.LOST )
+ {
+ handleLostConnection();
+ }
+ }
+ };
+ private final BlockingQueue<StatusMessage> messages = Queues.newLinkedBlockingQueue();
+
+ private enum State
+ {
+ LATENT,
+ STARTED,
+ CLOSED
+ }
+
+ public CuratorRestContext(CuratorFramework client, int sessionLengthMs) throws Exception
+ {
+ this.client = client;
+ this.sessionLengthMs = sessionLengthMs;
+ }
+
+ public CuratorFramework getClient()
+ {
+ Preconditions.checkState(state.get() == State.STARTED, "Not started");
+ return client;
+ }
+
+ public SessionManager getSessionManager()
+ {
+ Preconditions.checkState(state.get() == State.STARTED, "Not started");
+ return sessionManager;
+ }
+
+ public void start()
+ {
+ Preconditions.checkState(state.compareAndSet(State.LATENT, State.STARTED), "Already started");
+
+ client.getConnectionStateListenable().addListener(connectionStateListener);
+
+ Runnable runner = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ checkSessions();
+ }
+ };
+ executorService.scheduleAtFixedRate(runner, sessionLengthMs, sessionLengthMs, TimeUnit.MILLISECONDS);
+ }
+
+ public void pushMessage(StatusMessage message)
+ {
+ messages.add(message);
+ }
+
+ public Collection<StatusMessage> drainMessages()
+ {
+ List<StatusMessage> localMessages = Lists.newArrayList();
+ messages.drainTo(localMessages);
+ return localMessages;
+ }
+
+ private void checkSessions()
+ {
+
+ }
+
+ @Override
+ public void close()
+ {
+ if ( state.compareAndSet(State.STARTED, State.CLOSED) )
+ {
+ client.getConnectionStateListenable().removeListener(connectionStateListener);
+ executorService.shutdownNow();
+ sessionManager.close();
+ }
+ }
+
+ public ObjectMapper getMapper()
+ {
+ return mapper;
+ }
+
+ public ObjectWriter getWriter()
+ {
+ return writer;
+ }
+
+ private void handleLostConnection()
+ {
+ log.warn("Connection lost - closing all REST sessions");
+ sessionManager.deleteAllSessions();
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ClientResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ClientResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ClientResource.java
new file mode 100644
index 0000000..bee1b6f
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ClientResource.java
@@ -0,0 +1,247 @@
+package org.apache.curator.x.rest.api;
+
+import com.google.common.base.Joiner;
+import org.apache.curator.framework.api.*;
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.entities.CreateSpec;
+import org.apache.curator.x.rest.entities.DeleteSpec;
+import org.apache.curator.x.rest.entities.ExistsSpec;
+import org.apache.curator.x.rest.entities.GetChildrenSpec;
+import org.apache.curator.x.rest.entities.GetDataSpec;
+import org.apache.curator.x.rest.entities.SetDataSpec;
+import org.codehaus.jackson.node.ObjectNode;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.List;
+
+@Path("/curator/v1/client/{session-id}")
+public class ClientResource
+{
+ private final CuratorRestContext context;
+
+ public ClientResource(@Context CuratorRestContext context)
+ {
+ this.context = context;
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/get-children")
+ public Response getChildren(@PathParam("session-id") String sessionId, final GetChildrenSpec getChildrenSpec) throws Exception
+ {
+ Constants.getSession(context, sessionId);
+
+ Object builder = context.getClient().getChildren();
+ if ( getChildrenSpec.isWatched() )
+ {
+ builder = castBuilder(builder, Watchable.class).usingWatcher(new RestWatcher(context, getChildrenSpec.getWatchId()));
+ }
+
+ if ( getChildrenSpec.isAsync() )
+ {
+ BackgroundCallback backgroundCallback = new RestBackgroundCallback(context, Constants.CLIENT_GET_CHILDREN_ASYNC, getChildrenSpec.getAsyncId())
+ {
+ @Override
+ protected String getMessage(CuratorEvent event)
+ {
+ List<String> children = event.getChildren();
+ if ( children != null )
+ {
+ return Joiner.on(getChildrenSpec.getAsyncListSeparator()).join(children);
+ }
+ return "";
+ }
+ };
+ builder = castBuilder(builder, Backgroundable.class).inBackground(backgroundCallback);
+ }
+
+ Object children = castBuilder(builder, Pathable.class).forPath(getChildrenSpec.getPath());
+ if ( children != null )
+ {
+ return Response.ok(children).build();
+ }
+ return Response.ok().build();
+ }
+
+ @DELETE
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/delete")
+ public Response delete(@PathParam("session-id") String sessionId, final DeleteSpec deleteSpec) throws Exception
+ {
+ Constants.getSession(context, sessionId);
+
+ Object builder = context.getClient().delete();
+ if ( deleteSpec.isGuaranteed() )
+ {
+ builder = castBuilder(builder, DeleteBuilder.class).guaranteed();
+ }
+ builder = castBuilder(builder, Versionable.class).withVersion(deleteSpec.getVersion());
+
+ if ( deleteSpec.isAsync() )
+ {
+ BackgroundCallback backgroundCallback = new RestBackgroundCallback(context, Constants.CLIENT_DELETE_ASYNC, deleteSpec.getAsyncId());
+ builder = castBuilder(builder, Backgroundable.class).inBackground(backgroundCallback);
+ }
+
+ castBuilder(builder, Pathable.class).forPath(deleteSpec.getPath());
+ return Response.ok().build();
+ }
+
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/set-data")
+ public Response setData(@PathParam("session-id") String sessionId, final SetDataSpec setDataSpec) throws Exception
+ {
+ Constants.getSession(context, sessionId);
+
+ Object builder = context.getClient().setData();
+ if ( setDataSpec.isCompressed() )
+ {
+ builder = castBuilder(builder, Compressible.class).compressed();
+ }
+ if ( setDataSpec.isWatched() )
+ {
+ builder = castBuilder(builder, Watchable.class).usingWatcher(new RestWatcher(context, setDataSpec.getWatchId()));
+ }
+ builder = castBuilder(builder, Versionable.class).withVersion(setDataSpec.getVersion());
+
+ if ( setDataSpec.isAsync() )
+ {
+ BackgroundCallback backgroundCallback = new RestBackgroundCallback(context, Constants.CLIENT_SET_DATA_ASYNC, setDataSpec.getAsyncId());
+ builder = castBuilder(builder, Backgroundable.class).inBackground(backgroundCallback);
+ }
+
+ castBuilder(builder, PathAndBytesable.class).forPath(setDataSpec.getPath(), setDataSpec.getData().getBytes());
+ return Response.ok().build();
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/create")
+ public Response create(@PathParam("session-id") String sessionId, final CreateSpec createSpec) throws Exception
+ {
+ Constants.getSession(context, sessionId);
+
+ Object builder = context.getClient().create();
+ if ( createSpec.isCreatingParentsIfNeeded() )
+ {
+ builder = castBuilder(builder, CreateBuilder.class).creatingParentsIfNeeded();
+ }
+ if ( createSpec.isCompressed() )
+ {
+ builder = castBuilder(builder, Compressible.class).compressed();
+ }
+ if ( createSpec.isWithProtection() )
+ {
+ builder = castBuilder(builder, CreateBuilder.class).withProtection();
+ }
+ builder = castBuilder(builder, CreateModable.class).withMode(createSpec.getMode());
+
+ if ( createSpec.isAsync() )
+ {
+ BackgroundCallback backgroundCallback = new RestBackgroundCallback(context, Constants.CLIENT_CREATE_ASYNC, createSpec.getAsyncId());
+ builder = castBuilder(builder, Backgroundable.class).inBackground(backgroundCallback);
+ }
+
+ String returnPath = String.valueOf(castBuilder(builder, PathAndBytesable.class).forPath(createSpec.getPath(), createSpec.getData().getBytes()));
+
+ ObjectNode node = context.getMapper().createObjectNode();
+ node.put("path", returnPath);
+ return Response.ok(context.getWriter().writeValueAsString(node)).build();
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/get-data")
+ public Response getData(@PathParam("session-id") String sessionId, final GetDataSpec getDataSpec) throws Exception
+ {
+ Constants.getSession(context, sessionId);
+
+ Object builder = context.getClient().getData();
+ if ( getDataSpec.isWatched() )
+ {
+ builder = castBuilder(builder, Watchable.class).usingWatcher(new RestWatcher(context, getDataSpec.getWatchId()));
+ }
+ if ( getDataSpec.isDecompressed() )
+ {
+ builder = castBuilder(builder, Decompressible.class).decompressed();
+ }
+
+ if ( getDataSpec.isAsync() )
+ {
+ BackgroundCallback backgroundCallback = new RestBackgroundCallback(context, Constants.CLIENT_GET_DATA_ASYNC, getDataSpec.getAsyncId())
+ {
+ @Override
+ protected String getMessage(CuratorEvent event)
+ {
+ return (event.getData() != null) ? new String(event.getData()) : "";
+ }
+ };
+ castBuilder(builder, Backgroundable.class).inBackground(backgroundCallback);
+ }
+
+ String result = "";
+ Object bytes = castBuilder(builder, Pathable.class).forPath(getDataSpec.getPath());
+ if ( bytes != null )
+ {
+ result = new String((byte[])bytes);
+ }
+
+ ObjectNode node = context.getMapper().createObjectNode();
+ node.put("data", result);
+ return Response.ok(context.getWriter().writeValueAsString(node)).build();
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/exists")
+ public Response exists(@PathParam("session-id") String sessionId, final ExistsSpec existsSpec) throws Exception
+ {
+ Constants.getSession(context, sessionId);
+
+ Object builder = context.getClient().checkExists();
+ if ( existsSpec.isWatched() )
+ {
+ builder = castBuilder(builder, Watchable.class).usingWatcher(new RestWatcher(context, existsSpec.getWatchId()));
+ }
+
+ if ( existsSpec.isAsync() )
+ {
+ BackgroundCallback backgroundCallback = new RestBackgroundCallback(context, Constants.CLIENT_EXISTS_ASYNC, existsSpec.getAsyncId());
+ castBuilder(builder, Backgroundable.class).inBackground(backgroundCallback);
+ }
+
+ Object stat = castBuilder(builder, Pathable.class).forPath(existsSpec.getPath());
+ if ( stat != null )
+ {
+ return Response.ok(stat).build();
+ }
+
+ return Response.ok("{}").build();
+ }
+
+ private static <T> T castBuilder(Object createBuilder, Class<T> clazz)
+ {
+ if ( clazz.isAssignableFrom(createBuilder.getClass()) )
+ {
+ return clazz.cast(createBuilder);
+ }
+ throw new WebApplicationException(Response.Status.BAD_REQUEST);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/Constants.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/Constants.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/Constants.java
new file mode 100644
index 0000000..8d21a0f
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/Constants.java
@@ -0,0 +1,70 @@
+package org.apache.curator.x.rest.api;
+
+import org.apache.curator.framework.recipes.cache.ChildData;
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.details.Session;
+import org.apache.curator.x.rest.entities.NodeData;
+import org.codehaus.jackson.node.ObjectNode;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Response;
+
+class Constants
+{
+ static final String CLIENT_CREATE_ASYNC = "client-create-async";
+ static final String CLIENT_GET_DATA_ASYNC = "client-get-data-async";
+ static final String CLIENT_GET_CHILDREN_ASYNC = "client-get-children-async";
+ static final String CLIENT_SET_DATA_ASYNC = "client-set-data-async";
+ static final String CLIENT_EXISTS_ASYNC = "client-exists-async";
+ static final String CLIENT_DELETE_ASYNC = "client-delete-async";
+ static final String WATCH = "watch";
+ static final String PATH_CACHE = "path-cache";
+ static final String NODE_CACHE = "node-cache";
+ static final String LEADER = "leader";
+
+ static ObjectNode makeIdNode(CuratorRestContext context, String id)
+ {
+ ObjectNode node = context.getMapper().createObjectNode();
+ node.put("id", id);
+ return node;
+ }
+
+ static Session getSession(CuratorRestContext context, String sessionId)
+ {
+ Session session = context.getSessionManager().getSession(sessionId);
+ if ( session == null )
+ {
+ throw new WebApplicationException(Response.Status.NOT_FOUND);
+ }
+ return session;
+ }
+
+ static <T> T getThing(Session session, String id, Class<T> clazz)
+ {
+ T thing = session.getThing(id, clazz);
+ if ( thing == null )
+ {
+ throw new WebApplicationException(Response.Status.NOT_FOUND);
+ }
+ return thing;
+ }
+
+ static <T> T deleteThing(Session session, String id, Class<T> clazz)
+ {
+ T thing = session.deleteThing(id, clazz);
+ if ( thing == null )
+ {
+ throw new WebApplicationException(Response.Status.NOT_FOUND);
+ }
+ return thing;
+ }
+
+ private Constants()
+ {
+ }
+
+ static NodeData toNodeData(ChildData c)
+ {
+ String payload = (c.getData() != null) ? new String(c.getData()) : "";
+ return new NodeData(c.getPath(), c.getStat(), payload);
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LeaderResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LeaderResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LeaderResource.java
new file mode 100644
index 0000000..be41246
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LeaderResource.java
@@ -0,0 +1,91 @@
+package org.apache.curator.x.rest.api;
+
+import org.apache.curator.framework.recipes.leader.LeaderLatch;
+import org.apache.curator.framework.recipes.leader.LeaderLatchListener;
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.details.Closer;
+import org.apache.curator.x.rest.details.Session;
+import org.apache.curator.x.rest.entities.LeaderSpec;
+import org.apache.curator.x.rest.entities.StatusMessage;
+import org.codehaus.jackson.node.ObjectNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+
+@Path("/curator/v1/recipes/leader/{session-id}")
+public class LeaderResource
+{
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final CuratorRestContext context;
+
+ public LeaderResource(@Context CuratorRestContext context)
+ {
+ this.context = context;
+ }
+
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response startLeaderSelection(@PathParam("session-id") String sessionId, final LeaderSpec leaderSpec) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+
+ LeaderLatch leaderLatch = new LeaderLatch(context.getClient(), leaderSpec.getPath(), leaderSpec.getId());
+ leaderLatch.start();
+
+ Closer<LeaderLatch> closer = new Closer<LeaderLatch>()
+ {
+ @Override
+ public void close(LeaderLatch latch)
+ {
+ try
+ {
+ latch.close();
+ }
+ catch ( IOException e )
+ {
+ log.error("Could not close left-over leader latch for path: " + leaderSpec.getPath(), e);
+ }
+ }
+ };
+ final String id = session.addThing(leaderLatch, closer);
+
+ LeaderLatchListener listener = new LeaderLatchListener()
+ {
+ @Override
+ public void isLeader()
+ {
+ context.pushMessage(new StatusMessage(Constants.LEADER, id, "true", ""));
+ }
+
+ @Override
+ public void notLeader()
+ {
+ context.pushMessage(new StatusMessage(Constants.LEADER, id, "false", ""));
+ }
+ };
+ leaderLatch.addListener(listener);
+
+ ObjectNode node = Constants.makeIdNode(context, id);
+ return Response.ok(context.getWriter().writeValueAsString(node)).build();
+ }
+
+ @DELETE
+ @Path("{leader-id}")
+ public Response closeLeader(@PathParam("session-id") String sessionId, @PathParam("leader-id") String leaderId) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ LeaderLatch leaderLatch = Constants.deleteThing(session, leaderId, LeaderLatch.class);
+ leaderLatch.close();
+ return Response.ok().build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LockResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LockResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LockResource.java
new file mode 100644
index 0000000..0e59844
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/LockResource.java
@@ -0,0 +1,77 @@
+package org.apache.curator.x.rest.api;
+
+import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreMutex;
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.details.Closer;
+import org.apache.curator.x.rest.details.Session;
+import org.apache.curator.x.rest.entities.LockSpec;
+import org.codehaus.jackson.node.ObjectNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.concurrent.TimeUnit;
+
+@Path("/curator/v1/recipes/lock/{session-id}")
+public class LockResource
+{
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final CuratorRestContext context;
+
+ public LockResource(@Context CuratorRestContext context)
+ {
+ this.context = context;
+ }
+
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response acquireLock(@PathParam("session-id") String sessionId, final LockSpec lockSpec) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ InterProcessSemaphoreMutex lock = new InterProcessSemaphoreMutex(context.getClient(), lockSpec.getPath());
+ if ( !lock.acquire(lockSpec.getMaxWaitMs(), TimeUnit.MILLISECONDS) )
+ {
+ return Response.status(Response.Status.SERVICE_UNAVAILABLE).build();
+ }
+
+ Closer<InterProcessSemaphoreMutex> closer = new Closer<InterProcessSemaphoreMutex>()
+ {
+ @Override
+ public void close(InterProcessSemaphoreMutex mutex)
+ {
+ if ( mutex.isAcquiredInThisProcess() )
+ {
+ try
+ {
+ mutex.release();
+ }
+ catch ( Exception e )
+ {
+ log.error("Could not release left-over lock for path: " + lockSpec.getPath(), e);
+ }
+ }
+ }
+ };
+ String id = session.addThing(lock, closer);
+ ObjectNode node = Constants.makeIdNode(context, id);
+ return Response.ok(context.getWriter().writeValueAsString(node)).build();
+ }
+
+ @DELETE
+ @Path("{lock-id}")
+ public Response releaseLock(@PathParam("session-id") String sessionId, @PathParam("lock-id") String lockId) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ InterProcessSemaphoreMutex lock = Constants.deleteThing(session, lockId, InterProcessSemaphoreMutex.class);
+ lock.release();
+ return Response.ok().build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/NodeCacheResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/NodeCacheResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/NodeCacheResource.java
new file mode 100644
index 0000000..fa46548
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/NodeCacheResource.java
@@ -0,0 +1,102 @@
+package org.apache.curator.x.rest.api;
+
+import org.apache.curator.framework.recipes.cache.NodeCache;
+import org.apache.curator.framework.recipes.cache.NodeCacheListener;
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.details.Closer;
+import org.apache.curator.x.rest.details.Session;
+import org.apache.curator.x.rest.entities.NodeCacheSpec;
+import org.apache.curator.x.rest.entities.StatusMessage;
+import org.codehaus.jackson.node.ObjectNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+
+@Path("/curator/v1/recipes/node-cache/{session-id}")
+public class NodeCacheResource
+{
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final CuratorRestContext context;
+
+ public NodeCacheResource(@Context CuratorRestContext context)
+ {
+ this.context = context;
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response newCache(@PathParam("session-id") String sessionId, final NodeCacheSpec spec) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+
+ NodeCache cache = new NodeCache(context.getClient(), spec.getPath(), spec.isDataIsCompressed());
+ cache.start(spec.isBuildInitial());
+
+ Closer<NodeCache> closer = new Closer<NodeCache>()
+ {
+ @Override
+ public void close(NodeCache cache)
+ {
+ try
+ {
+ cache.close();
+ }
+ catch ( IOException e )
+ {
+ log.error("Could not close left-over NodeCache for path: " + spec.getPath(), e);
+ }
+ }
+ };
+ final String id = session.addThing(cache, closer);
+
+ NodeCacheListener listener = new NodeCacheListener()
+ {
+ @Override
+ public void nodeChanged() throws Exception
+ {
+ context.pushMessage(new StatusMessage(Constants.NODE_CACHE, id, "", ""));
+ }
+ };
+ cache.getListenable().addListener(listener);
+
+ ObjectNode node = Constants.makeIdNode(context, id);
+ return Response.ok(context.getWriter().writeValueAsString(node)).build();
+ }
+
+ @DELETE
+ @Path("/{cache-id}")
+ public Response deleteCache(@PathParam("session-id") String sessionId, @PathParam("cache-id") String cacheId)
+ {
+ Session session = Constants.getSession(context, sessionId);
+ NodeCache cache = Constants.deleteThing(session, cacheId, NodeCache.class);
+ try
+ {
+ cache.close();
+ }
+ catch ( IOException e )
+ {
+ log.error("Could not close NodeCache id: " + cacheId, e);
+ }
+ return Response.ok().build();
+ }
+
+ @GET
+ @Path("/{cache-id}")
+ public Response getCacheData(@PathParam("session-id") String sessionId, @PathParam("cache-id") String cacheId) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ NodeCache cache = Constants.getThing(session, cacheId, NodeCache.class);
+ return Response.ok(Constants.toNodeData(cache.getCurrentData())).build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PathChildrenCacheResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PathChildrenCacheResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PathChildrenCacheResource.java
new file mode 100644
index 0000000..f118d55
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PathChildrenCacheResource.java
@@ -0,0 +1,128 @@
+package org.apache.curator.x.rest.api;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.recipes.cache.ChildData;
+import org.apache.curator.framework.recipes.cache.PathChildrenCache;
+import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
+import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
+import org.apache.curator.utils.ThreadUtils;
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.details.Closer;
+import org.apache.curator.x.rest.details.Session;
+import org.apache.curator.x.rest.entities.PathChildrenCacheSpec;
+import org.apache.curator.x.rest.entities.StatusMessage;
+import org.codehaus.jackson.node.ArrayNode;
+import org.codehaus.jackson.node.ObjectNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+
+@Path("/curator/v1/recipes/path-cache/{session-id}")
+public class PathChildrenCacheResource
+{
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final CuratorRestContext context;
+
+ public PathChildrenCacheResource(@Context CuratorRestContext context)
+ {
+ this.context = context;
+ }
+
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response newCache(@PathParam("session-id") String sessionId, final PathChildrenCacheSpec spec) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+
+ PathChildrenCache cache = new PathChildrenCache(context.getClient(), spec.getPath(), spec.isCacheData(), spec.isDataIsCompressed(), ThreadUtils.newThreadFactory("PathChildrenCacheResource"));
+ cache.start(spec.getStartMode());
+
+ Closer<PathChildrenCache> closer = new Closer<PathChildrenCache>()
+ {
+ @Override
+ public void close(PathChildrenCache cache)
+ {
+ try
+ {
+ cache.close();
+ }
+ catch ( IOException e )
+ {
+ log.error("Could not close left-over PathChildrenCache for path: " + spec.getPath(), e);
+ }
+ }
+ };
+ final String id = session.addThing(cache, closer);
+
+ PathChildrenCacheListener listener = new PathChildrenCacheListener()
+ {
+ @Override
+ public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception
+ {
+ context.pushMessage(new StatusMessage(Constants.PATH_CACHE, id, event.getType().name(), ""));
+ }
+ };
+ cache.getListenable().addListener(listener);
+
+ ObjectNode node = Constants.makeIdNode(context, id);
+ return Response.ok(context.getWriter().writeValueAsString(node)).build();
+ }
+
+ @DELETE
+ @Path("/{cache-id}")
+ public Response deleteCache(@PathParam("session-id") String sessionId, @PathParam("cache-id") String cacheId)
+ {
+ Session session = Constants.getSession(context, sessionId);
+ PathChildrenCache cache = Constants.deleteThing(session, cacheId, PathChildrenCache.class);
+ try
+ {
+ cache.close();
+ }
+ catch ( IOException e )
+ {
+ log.error("Could not close PathChildrenCache id: " + cacheId, e);
+ }
+ return Response.ok().build();
+ }
+
+ @GET
+ @Path("/{cache-id}")
+ public Response getCacheData(@PathParam("session-id") String sessionId, @PathParam("cache-id") String cacheId) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ PathChildrenCache cache = Constants.getThing(session, cacheId, PathChildrenCache.class);
+
+ ArrayNode data = context.getMapper().createArrayNode();
+ for ( ChildData c : cache.getCurrentData() )
+ {
+ data.addPOJO(Constants.toNodeData(c));
+ }
+ return Response.ok(context.getWriter().writeValueAsString(data)).build();
+ }
+
+ @GET
+ @Path("/{cache-id}/{path:.*}")
+ public Response getCacheDataForPath(@PathParam("session-id") String sessionId, @PathParam("cache-id") String cacheId, @PathParam("path") String path) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ PathChildrenCache cache = Constants.getThing(session, cacheId, PathChildrenCache.class);
+ ChildData currentData = cache.getCurrentData(path);
+ if ( currentData == null )
+ {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
+ return Response.ok(Constants.toNodeData(currentData)).build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PersistentEphemeralNodeResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PersistentEphemeralNodeResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PersistentEphemeralNodeResource.java
new file mode 100644
index 0000000..165d373
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/PersistentEphemeralNodeResource.java
@@ -0,0 +1,68 @@
+package org.apache.curator.x.rest.api;
+
+import org.apache.curator.framework.recipes.nodes.PersistentEphemeralNode;
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.details.Closer;
+import org.apache.curator.x.rest.details.Session;
+import org.apache.curator.x.rest.entities.PersistentEphemeralNodeSpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/curator/v1/recipes/persistent-ephemeral-node/{session-id}")
+public class PersistentEphemeralNodeResource
+{
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final CuratorRestContext context;
+
+ public PersistentEphemeralNodeResource(@Context CuratorRestContext context)
+ {
+ this.context = context;
+ }
+
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response start(@PathParam("session-id") String sessionId, final PersistentEphemeralNodeSpec spec) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ PersistentEphemeralNode node = new PersistentEphemeralNode(context.getClient(), spec.getMode(), spec.getPath(), spec.getData().getBytes());
+ node.start();
+
+ Closer<PersistentEphemeralNode> closer = new Closer<PersistentEphemeralNode>()
+ {
+ @Override
+ public void close(PersistentEphemeralNode node)
+ {
+ try
+ {
+ node.close();
+ }
+ catch ( Exception e )
+ {
+ log.error("Could not release left-over persistent ephemeral node for path: " + spec.getPath(), e);
+ }
+ }
+ };
+ String id = session.addThing(node, closer);
+ return Response.ok(context.getWriter().writeValueAsString(Constants.makeIdNode(context, id))).build();
+ }
+
+ @DELETE
+ @Path("{node-id}")
+ public Response close(@PathParam("session-id") String sessionId, @PathParam("node-id") String nodeId) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ PersistentEphemeralNode node = Constants.deleteThing(session, nodeId, PersistentEphemeralNode.class);
+ node.close();
+ return Response.ok().build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ReadWriteLockResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ReadWriteLockResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ReadWriteLockResource.java
new file mode 100644
index 0000000..28634d5
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/ReadWriteLockResource.java
@@ -0,0 +1,94 @@
+package org.apache.curator.x.rest.api;
+
+import org.apache.curator.framework.recipes.locks.InterProcessMutex;
+import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.details.Closer;
+import org.apache.curator.x.rest.details.Session;
+import org.apache.curator.x.rest.entities.LockSpec;
+import org.codehaus.jackson.node.ObjectNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.concurrent.TimeUnit;
+
+@Path("/curator/v1/recipes/read-write-lock/{session-id}")
+public class ReadWriteLockResource
+{
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final CuratorRestContext context;
+
+ public ReadWriteLockResource(@Context CuratorRestContext context)
+ {
+ this.context = context;
+ }
+
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/read")
+ public Response acquireReadLock(@PathParam("session-id") String sessionId, final LockSpec lockSpec) throws Exception
+ {
+ return internalLock(sessionId, lockSpec, false);
+ }
+
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("/write")
+ public Response acquireWriteLock(@PathParam("session-id") String sessionId, final LockSpec lockSpec) throws Exception
+ {
+ return internalLock(sessionId, lockSpec, true);
+ }
+
+ private Response internalLock(String sessionId, final LockSpec lockSpec, boolean writeLock) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ InterProcessReadWriteLock lock = new InterProcessReadWriteLock(context.getClient(), lockSpec.getPath());
+ InterProcessMutex actualLock = writeLock ? lock.writeLock() : lock.readLock();
+ if ( !actualLock.acquire(lockSpec.getMaxWaitMs(), TimeUnit.MILLISECONDS) )
+ {
+ return Response.status(Response.Status.SERVICE_UNAVAILABLE).build();
+ }
+
+ Closer<InterProcessMutex> closer = new Closer<InterProcessMutex>()
+ {
+ @Override
+ public void close(InterProcessMutex lock)
+ {
+ if ( lock.isAcquiredInThisProcess() )
+ {
+ try
+ {
+ lock.release();
+ }
+ catch ( Exception e )
+ {
+ log.error("Could not release left-over read/write lock for path: " + lockSpec.getPath(), e);
+ }
+ }
+ }
+ };
+ String id = session.addThing(actualLock, closer);
+ ObjectNode node = Constants.makeIdNode(context, id);
+ return Response.ok(context.getWriter().writeValueAsString(node)).build();
+ }
+
+ @DELETE
+ @Path("{lock-id}")
+ public Response releaseLock(@PathParam("session-id") String sessionId, @PathParam("lock-id") String lockId) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ InterProcessMutex lock = Constants.deleteThing(session, lockId, InterProcessMutex.class);
+ lock.release();
+ return Response.ok().build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/RestBackgroundCallback.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/RestBackgroundCallback.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/RestBackgroundCallback.java
new file mode 100644
index 0000000..364b0b8
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/RestBackgroundCallback.java
@@ -0,0 +1,32 @@
+package org.apache.curator.x.rest.api;
+
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.api.BackgroundCallback;
+import org.apache.curator.framework.api.CuratorEvent;
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.entities.StatusMessage;
+
+class RestBackgroundCallback implements BackgroundCallback
+{
+ private final CuratorRestContext context;
+ private final String type;
+ private final String asyncId;
+
+ RestBackgroundCallback(CuratorRestContext context, String type, String asyncId)
+ {
+ this.context = context;
+ this.type = type;
+ this.asyncId = asyncId;
+ }
+
+ @Override
+ public void processResult(CuratorFramework client, CuratorEvent event) throws Exception
+ {
+ context.pushMessage(new StatusMessage(type, asyncId, getMessage(event), Integer.toString(event.getResultCode())));
+ }
+
+ protected String getMessage(CuratorEvent event)
+ {
+ return String.valueOf(event.getName());
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/RestWatcher.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/RestWatcher.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/RestWatcher.java
new file mode 100644
index 0000000..4f76227
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/RestWatcher.java
@@ -0,0 +1,27 @@
+package org.apache.curator.x.rest.api;
+
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.entities.StatusMessage;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+
+class RestWatcher implements Watcher
+{
+ private final CuratorRestContext context;
+ private final String watchId;
+
+ RestWatcher(CuratorRestContext context, String watchId)
+ {
+ this.context = context;
+ this.watchId = watchId;
+ }
+
+ @Override
+ public void process(WatchedEvent event)
+ {
+ if ( event.getType() != Event.EventType.None )
+ {
+ context.pushMessage(new StatusMessage(Constants.WATCH, watchId, event.getType().name(), String.valueOf(event.getPath())));
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SemaphoreResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SemaphoreResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SemaphoreResource.java
new file mode 100644
index 0000000..9e02d8a
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SemaphoreResource.java
@@ -0,0 +1,103 @@
+package org.apache.curator.x.rest.api;
+
+import com.google.common.collect.Lists;
+import org.apache.curator.framework.recipes.locks.InterProcessSemaphoreV2;
+import org.apache.curator.framework.recipes.locks.Lease;
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.apache.curator.x.rest.details.Closer;
+import org.apache.curator.x.rest.details.Session;
+import org.apache.curator.x.rest.entities.SemaphoreSpec;
+import org.codehaus.jackson.node.ObjectNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@Path("/curator/v1/recipes/semaphore/{session-id}")
+public class SemaphoreResource
+{
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final CuratorRestContext context;
+
+ private static class LeasesHolder
+ {
+ final List<Lease> leases;
+
+ private LeasesHolder(Collection<Lease> leases)
+ {
+ this.leases = Lists.newArrayList(leases);
+ }
+ }
+
+ public SemaphoreResource(@Context CuratorRestContext context)
+ {
+ this.context = context;
+ }
+
+ @PUT
+ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response acquireSemaphore(@PathParam("session-id") String sessionId, final SemaphoreSpec semaphoreSpec) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ final InterProcessSemaphoreV2 semaphore = new InterProcessSemaphoreV2(context.getClient(), semaphoreSpec.getPath(), semaphoreSpec.getMaxLeases());
+ final Collection<Lease> leases = semaphore.acquire(semaphoreSpec.getAcquireQty(), semaphoreSpec.getMaxWaitMs(), TimeUnit.MILLISECONDS);
+ if ( leases == null )
+ {
+ return Response.status(Response.Status.SERVICE_UNAVAILABLE).build();
+ }
+
+ Closer<LeasesHolder> closer = new Closer<LeasesHolder>()
+ {
+ @Override
+ public void close(LeasesHolder holder)
+ {
+ try
+ {
+ semaphore.returnAll(holder.leases);
+ }
+ catch ( Exception e )
+ {
+ log.error("Could not release left-over semaphore leases for path: " + semaphoreSpec.getPath(), e);
+ }
+ }
+ };
+ String id = session.addThing(new LeasesHolder(leases), closer);
+ ObjectNode node = Constants.makeIdNode(context, id);
+ return Response.ok(context.getWriter().writeValueAsString(node)).build();
+ }
+
+ @DELETE
+ @Path("{lease-id}/{release-qty}")
+ public Response releaseSemaphore(@PathParam("session-id") String sessionId, @PathParam("lease-id") String leaseId, @PathParam("release-qty") int releaseQty) throws Exception
+ {
+ Session session = Constants.getSession(context, sessionId);
+ LeasesHolder holder = Constants.getThing(session, leaseId, LeasesHolder.class);
+ if ( holder.leases.size() < releaseQty )
+ {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
+ while ( releaseQty-- > 0 )
+ {
+ Lease lease = holder.leases.remove(0);
+ lease.close();
+ }
+ if ( holder.leases.size() == 0 )
+ {
+ session.deleteThing(leaseId, LeasesHolder.class);
+ }
+
+ return Response.ok().build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SessionResource.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SessionResource.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SessionResource.java
new file mode 100644
index 0000000..1877177
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/api/SessionResource.java
@@ -0,0 +1,61 @@
+package org.apache.curator.x.rest.api;
+
+import org.apache.curator.x.rest.CuratorRestContext;
+import org.codehaus.jackson.node.ObjectNode;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/curator/v1/session")
+public class SessionResource
+{
+ private final CuratorRestContext context;
+
+ public SessionResource(@Context CuratorRestContext context)
+ {
+ this.context = context;
+ }
+
+ @POST
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response newSession() throws Exception
+ {
+ String sessionId = context.getSessionManager().newSession();
+ ObjectNode node = Constants.makeIdNode(context, sessionId);
+ return Response.ok(context.getWriter().writeValueAsString(node)).build();
+ }
+
+ @DELETE
+ @Path("{id}")
+ public Response deleteSession(@PathParam("id") String id)
+ {
+ if ( !context.getSessionManager().deleteSession(id) )
+ {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+ return Response.ok().build();
+ }
+
+ @GET
+ @Path("{id}")
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response pingSession(@PathParam("id") String id) throws Exception
+ {
+ if ( !context.getSessionManager().pingSession(id) )
+ {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+
+ ObjectNode node = context.getMapper().createObjectNode();
+ node.put("state", context.getClient().getState().name());
+ node.putPOJO("messages", context.drainMessages());
+
+ return Response.ok(context.getWriter().writeValueAsString(node)).build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/Closer.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/Closer.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/Closer.java
new file mode 100644
index 0000000..0436975
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/Closer.java
@@ -0,0 +1,6 @@
+package org.apache.curator.x.rest.details;
+
+public interface Closer<T>
+{
+ public void close(T thing);
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/Session.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/Session.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/Session.java
new file mode 100644
index 0000000..9fe1403
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/Session.java
@@ -0,0 +1,85 @@
+package org.apache.curator.x.rest.details;
+
+import com.google.common.collect.Maps;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.io.Closeable;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class Session implements Closeable
+{
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final Map<String, Entry> things = Maps.newConcurrentMap();
+ private final AtomicLong lastUseMs = new AtomicLong(System.currentTimeMillis());
+
+ private static class Entry
+ {
+ final Object thing;
+ final Closer closer;
+
+ private Entry(Object thing, Closer closer)
+ {
+ this.thing = thing;
+ this.closer = closer;
+ }
+ }
+
+ public void updateLastUse()
+ {
+ lastUseMs.set(System.currentTimeMillis());
+ }
+
+ public long getLastUseMs()
+ {
+ return lastUseMs.get();
+ }
+
+ @Override
+ public void close()
+ {
+ for ( Map.Entry<String, Entry> mapEntry : things.entrySet() )
+ {
+ Entry entry = mapEntry.getValue();
+ if ( entry.closer != null )
+ {
+ log.debug(String.format("Closing left over thing. Type: %s - Id: %s", entry.thing.getClass(), mapEntry.getKey()));
+ //noinspection unchecked
+ entry.closer.close(entry.thing); // lack of generics is safe because addThing() is type-safe
+ }
+ }
+ }
+
+ public String addThing(Object thing)
+ {
+ return addThing(thing, null);
+ }
+
+ public <T> String addThing(T thing, Closer<T> closer)
+ {
+ String id = SessionManager.newId();
+ things.put(id, new Entry(thing, closer));
+ return id;
+ }
+
+ public <T> T getThing(String id, Class<T> clazz)
+ {
+ Entry entry = things.get(id);
+ return cast(clazz, entry);
+ }
+
+ public <T> T deleteThing(String id, Class<T> clazz)
+ {
+ Entry entry = things.remove(id);
+ return cast(clazz, entry);
+ }
+
+ private <T> T cast(Class<T> clazz, Entry entry)
+ {
+ if ( entry != null )
+ {
+ return clazz.cast(entry.thing);
+ }
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/SessionManager.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/SessionManager.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/SessionManager.java
new file mode 100644
index 0000000..619bce8
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/details/SessionManager.java
@@ -0,0 +1,73 @@
+package org.apache.curator.x.rest.details;
+
+import com.google.common.collect.Maps;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.io.Closeable;
+import java.util.Collection;
+import java.util.Map;
+import java.util.UUID;
+
+public class SessionManager implements Closeable
+{
+ private final Logger log = LoggerFactory.getLogger(getClass());
+ private final Map<String, Session> sessions = Maps.newConcurrentMap();
+
+ public String newSession()
+ {
+ String id = newId();
+ sessions.put(id, new Session());
+ log.debug("Creating session. Id: " + id);
+ return id;
+ }
+
+ static String newId()
+ {
+ return UUID.randomUUID().toString();
+ }
+
+ @Override
+ public void close()
+ {
+ deleteAllSessions();
+ }
+
+ public void deleteAllSessions()
+ {
+ Collection<Session> localSessions = sessions.values();
+ sessions.clear();
+
+ for ( Session session : localSessions )
+ {
+ session.close();
+ }
+ }
+
+ public boolean deleteSession(String id)
+ {
+ Session session = sessions.remove(id);
+ if ( session != null )
+ {
+ log.debug("Deleting session. Id: " + id);
+ session.close();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean pingSession(String id)
+ {
+ return getSession(id) != null;
+ }
+
+ public Session getSession(String id)
+ {
+ Session session = sessions.get(id);
+ if ( session != null )
+ {
+ log.debug("Pinging session. Id: " + id);
+ session.updateLastUse();
+ }
+ return session;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/CreateSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/CreateSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/CreateSpec.java
new file mode 100644
index 0000000..6a52862
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/CreateSpec.java
@@ -0,0 +1,114 @@
+package org.apache.curator.x.rest.entities;
+
+import org.apache.zookeeper.CreateMode;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class CreateSpec
+{
+ private String path;
+ private String data;
+ private CreateMode mode;
+ private boolean async;
+ private String asyncId;
+ private boolean compressed;
+ private boolean creatingParentsIfNeeded;
+ private boolean withProtection;
+
+ public CreateSpec()
+ {
+ this("/", "", CreateMode.PERSISTENT, false, "", false, false, false);
+ }
+
+ public CreateSpec(String path, String data, CreateMode mode, boolean async, String asyncId, boolean compressed, boolean creatingParentsIfNeeded, boolean withProtection)
+ {
+ this.path = path;
+ this.data = data;
+ this.mode = mode;
+ this.async = async;
+ this.asyncId = asyncId;
+ this.compressed = compressed;
+ this.creatingParentsIfNeeded = creatingParentsIfNeeded;
+ this.withProtection = withProtection;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public String getAsyncId()
+ {
+ return asyncId;
+ }
+
+ public void setAsyncId(String asyncId)
+ {
+ this.asyncId = asyncId;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public String getData()
+ {
+ return data;
+ }
+
+ public void setData(String data)
+ {
+ this.data = data;
+ }
+
+ public CreateMode getMode()
+ {
+ return mode;
+ }
+
+ public void setMode(CreateMode mode)
+ {
+ this.mode = mode;
+ }
+
+ public boolean isAsync()
+ {
+ return async;
+ }
+
+ public void setAsync(boolean async)
+ {
+ this.async = async;
+ }
+
+ public boolean isCompressed()
+ {
+ return compressed;
+ }
+
+ public void setCompressed(boolean compressed)
+ {
+ this.compressed = compressed;
+ }
+
+ public boolean isCreatingParentsIfNeeded()
+ {
+ return creatingParentsIfNeeded;
+ }
+
+ public void setCreatingParentsIfNeeded(boolean creatingParentsIfNeeded)
+ {
+ this.creatingParentsIfNeeded = creatingParentsIfNeeded;
+ }
+
+ public boolean isWithProtection()
+ {
+ return withProtection;
+ }
+
+ public void setWithProtection(boolean withProtection)
+ {
+ this.withProtection = withProtection;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/DeleteSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/DeleteSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/DeleteSpec.java
new file mode 100644
index 0000000..322d3de
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/DeleteSpec.java
@@ -0,0 +1,77 @@
+package org.apache.curator.x.rest.entities;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class DeleteSpec
+{
+ private String path;
+ private boolean async;
+ private String asyncId;
+ private boolean guaranteed;
+ private int version;
+
+ public DeleteSpec()
+ {
+ this("/", false, "", false, -1);
+ }
+
+ public DeleteSpec(String path, boolean async, String asyncId, boolean guaranteed, int version)
+ {
+ this.path = path;
+ this.async = async;
+ this.asyncId = asyncId;
+ this.guaranteed = guaranteed;
+ this.version = version;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public boolean isAsync()
+ {
+ return async;
+ }
+
+ public void setAsync(boolean async)
+ {
+ this.async = async;
+ }
+
+ public String getAsyncId()
+ {
+ return asyncId;
+ }
+
+ public void setAsyncId(String asyncId)
+ {
+ this.asyncId = asyncId;
+ }
+
+ public boolean isGuaranteed()
+ {
+ return guaranteed;
+ }
+
+ public void setGuaranteed(boolean guaranteed)
+ {
+ this.guaranteed = guaranteed;
+ }
+
+ public int getVersion()
+ {
+ return version;
+ }
+
+ public void setVersion(int version)
+ {
+ this.version = version;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/ExistsSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/ExistsSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/ExistsSpec.java
new file mode 100644
index 0000000..74905d8
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/ExistsSpec.java
@@ -0,0 +1,77 @@
+package org.apache.curator.x.rest.entities;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class ExistsSpec
+{
+ private String path;
+ private boolean watched;
+ private String watchId;
+ private boolean async;
+ private String asyncId;
+
+ public ExistsSpec()
+ {
+ this("/", false, "", false, "");
+ }
+
+ public ExistsSpec(String path, boolean watched, String watchId, boolean async, String asyncId)
+ {
+ this.path = path;
+ this.watched = watched;
+ this.watchId = watchId;
+ this.async = async;
+ this.asyncId = asyncId;
+ }
+
+ public String getWatchId()
+ {
+ return watchId;
+ }
+
+ public void setWatchId(String watchId)
+ {
+ this.watchId = watchId;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public boolean isWatched()
+ {
+ return watched;
+ }
+
+ public void setWatched(boolean watched)
+ {
+ this.watched = watched;
+ }
+
+ public boolean isAsync()
+ {
+ return async;
+ }
+
+ public void setAsync(boolean async)
+ {
+ this.async = async;
+ }
+
+ public String getAsyncId()
+ {
+ return asyncId;
+ }
+
+ public void setAsyncId(String asyncId)
+ {
+ this.asyncId = asyncId;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/GetChildrenSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/GetChildrenSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/GetChildrenSpec.java
new file mode 100644
index 0000000..1f5c46b
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/GetChildrenSpec.java
@@ -0,0 +1,89 @@
+package org.apache.curator.x.rest.entities;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class GetChildrenSpec
+{
+ private String path;
+ private boolean async;
+ private String asyncId;
+ private String asyncListSeparator;
+ private boolean watched;
+ private String watchId;
+
+ public GetChildrenSpec()
+ {
+ this("/", false, "", ",", false, "");
+ }
+
+ public GetChildrenSpec(String path, boolean async, String asyncId, String asyncListSeparator, boolean watched, String watchId)
+ {
+ this.path = path;
+ this.async = async;
+ this.asyncId = asyncId;
+ this.asyncListSeparator = asyncListSeparator;
+ this.watched = watched;
+ this.watchId = watchId;
+ }
+
+ public String getAsyncListSeparator()
+ {
+ return asyncListSeparator;
+ }
+
+ public void setAsyncListSeparator(String asyncListSeparator)
+ {
+ this.asyncListSeparator = asyncListSeparator;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public boolean isAsync()
+ {
+ return async;
+ }
+
+ public void setAsync(boolean async)
+ {
+ this.async = async;
+ }
+
+ public String getAsyncId()
+ {
+ return asyncId;
+ }
+
+ public void setAsyncId(String asyncId)
+ {
+ this.asyncId = asyncId;
+ }
+
+ public boolean isWatched()
+ {
+ return watched;
+ }
+
+ public void setWatched(boolean watched)
+ {
+ this.watched = watched;
+ }
+
+ public String getWatchId()
+ {
+ return watchId;
+ }
+
+ public void setWatchId(String watchId)
+ {
+ this.watchId = watchId;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/GetDataSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/GetDataSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/GetDataSpec.java
new file mode 100644
index 0000000..d90a01a
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/GetDataSpec.java
@@ -0,0 +1,89 @@
+package org.apache.curator.x.rest.entities;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class GetDataSpec
+{
+ private String path;
+ private boolean watched;
+ private String watchId;
+ private boolean async;
+ private String asyncId;
+ private boolean decompressed;
+
+ public GetDataSpec()
+ {
+ this("/", false, "", false, "", false);
+ }
+
+ public GetDataSpec(String path, boolean watched, String watchId, boolean async, String asyncId, boolean decompressed)
+ {
+ this.path = path;
+ this.watched = watched;
+ this.watchId = watchId;
+ this.async = async;
+ this.asyncId = asyncId;
+ this.decompressed = decompressed;
+ }
+
+ public String getWatchId()
+ {
+ return watchId;
+ }
+
+ public void setWatchId(String watchId)
+ {
+ this.watchId = watchId;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public boolean isWatched()
+ {
+ return watched;
+ }
+
+ public void setWatched(boolean watched)
+ {
+ this.watched = watched;
+ }
+
+ public boolean isAsync()
+ {
+ return async;
+ }
+
+ public void setAsync(boolean async)
+ {
+ this.async = async;
+ }
+
+ public String getAsyncId()
+ {
+ return asyncId;
+ }
+
+ public void setAsyncId(String asyncId)
+ {
+ this.asyncId = asyncId;
+ }
+
+ public boolean isDecompressed()
+ {
+ return decompressed;
+ }
+
+ public void setDecompressed(boolean decompressed)
+ {
+ this.decompressed = decompressed;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/LeaderSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/LeaderSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/LeaderSpec.java
new file mode 100644
index 0000000..734ee53
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/LeaderSpec.java
@@ -0,0 +1,38 @@
+package org.apache.curator.x.rest.entities;
+
+public class LeaderSpec
+{
+ private String path;
+ private String id;
+
+ public LeaderSpec()
+ {
+ this("/", "");
+ }
+
+ public LeaderSpec(String path, String id)
+ {
+ this.path = path;
+ this.id = id;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public void setId(String id)
+ {
+ this.id = id;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/LockSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/LockSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/LockSpec.java
new file mode 100644
index 0000000..76e8e9d
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/LockSpec.java
@@ -0,0 +1,41 @@
+package org.apache.curator.x.rest.entities;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class LockSpec
+{
+ private String path;
+ private int maxWaitMs;
+
+ public LockSpec()
+ {
+ this("", 0);
+ }
+
+ public LockSpec(String path, int maxWaitMs)
+ {
+ this.path = path;
+ this.maxWaitMs = maxWaitMs;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public int getMaxWaitMs()
+ {
+ return maxWaitMs;
+ }
+
+ public void setMaxWaitMs(int maxWaitMs)
+ {
+ this.maxWaitMs = maxWaitMs;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/NodeCacheSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/NodeCacheSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/NodeCacheSpec.java
new file mode 100644
index 0000000..f499bb5
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/NodeCacheSpec.java
@@ -0,0 +1,54 @@
+package org.apache.curator.x.rest.entities;
+
+import org.apache.curator.framework.recipes.cache.PathChildrenCache;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class NodeCacheSpec
+{
+ private String path;
+ private boolean dataIsCompressed;
+ private boolean buildInitial;
+
+ public NodeCacheSpec()
+ {
+ this("/", false, false);
+ }
+
+ public NodeCacheSpec(String path, boolean dataIsCompressed, boolean buildInitial)
+ {
+ this.path = path;
+ this.dataIsCompressed = dataIsCompressed;
+ this.buildInitial = buildInitial;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public boolean isDataIsCompressed()
+ {
+ return dataIsCompressed;
+ }
+
+ public void setDataIsCompressed(boolean dataIsCompressed)
+ {
+ this.dataIsCompressed = dataIsCompressed;
+ }
+
+ public boolean isBuildInitial()
+ {
+ return buildInitial;
+ }
+
+ public void setBuildInitial(boolean buildInitial)
+ {
+ this.buildInitial = buildInitial;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/NodeData.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/NodeData.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/NodeData.java
new file mode 100644
index 0000000..59a3cb8
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/NodeData.java
@@ -0,0 +1,54 @@
+package org.apache.curator.x.rest.entities;
+
+import org.apache.zookeeper.data.Stat;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class NodeData
+{
+ private String path;
+ private Stat stat;
+ private String data;
+
+ public NodeData()
+ {
+ this("/", new Stat(), "");
+ }
+
+ public NodeData(String path, Stat stat, String data)
+ {
+ this.path = path;
+ this.stat = stat;
+ this.data = data;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public Stat getStat()
+ {
+ return stat;
+ }
+
+ public void setStat(Stat stat)
+ {
+ this.stat = stat;
+ }
+
+ public String getData()
+ {
+ return data;
+ }
+
+ public void setData(String data)
+ {
+ this.data = data;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/PathChildrenCacheSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/PathChildrenCacheSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/PathChildrenCacheSpec.java
new file mode 100644
index 0000000..076f2cb
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/PathChildrenCacheSpec.java
@@ -0,0 +1,66 @@
+package org.apache.curator.x.rest.entities;
+
+import org.apache.curator.framework.recipes.cache.PathChildrenCache;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class PathChildrenCacheSpec
+{
+ private String path;
+ private boolean cacheData;
+ private boolean dataIsCompressed;
+ private PathChildrenCache.StartMode startMode;
+
+ public PathChildrenCacheSpec()
+ {
+ this("", false, false, PathChildrenCache.StartMode.NORMAL);
+ }
+
+ public PathChildrenCacheSpec(String path, boolean cacheData, boolean dataIsCompressed, PathChildrenCache.StartMode startMode)
+ {
+ this.path = path;
+ this.cacheData = cacheData;
+ this.dataIsCompressed = dataIsCompressed;
+ this.startMode = startMode;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public boolean isCacheData()
+ {
+ return cacheData;
+ }
+
+ public void setCacheData(boolean cacheData)
+ {
+ this.cacheData = cacheData;
+ }
+
+ public boolean isDataIsCompressed()
+ {
+ return dataIsCompressed;
+ }
+
+ public void setDataIsCompressed(boolean dataIsCompressed)
+ {
+ this.dataIsCompressed = dataIsCompressed;
+ }
+
+ public PathChildrenCache.StartMode getStartMode()
+ {
+ return startMode;
+ }
+
+ public void setStartMode(PathChildrenCache.StartMode startMode)
+ {
+ this.startMode = startMode;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/PersistentEphemeralNodeSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/PersistentEphemeralNodeSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/PersistentEphemeralNodeSpec.java
new file mode 100644
index 0000000..1c26df8
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/PersistentEphemeralNodeSpec.java
@@ -0,0 +1,52 @@
+package org.apache.curator.x.rest.entities;
+
+import org.apache.curator.framework.recipes.nodes.PersistentEphemeralNode;
+
+public class PersistentEphemeralNodeSpec
+{
+ private String path;
+ private String data;
+ private PersistentEphemeralNode.Mode mode;
+
+ public PersistentEphemeralNodeSpec()
+ {
+ this("/", "", PersistentEphemeralNode.Mode.EPHEMERAL);
+ }
+
+ public PersistentEphemeralNodeSpec(String path, String data, PersistentEphemeralNode.Mode mode)
+ {
+ this.path = path;
+ this.data = data;
+ this.mode = mode;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public String getData()
+ {
+ return data;
+ }
+
+ public void setData(String data)
+ {
+ this.data = data;
+ }
+
+ public PersistentEphemeralNode.Mode getMode()
+ {
+ return mode;
+ }
+
+ public void setMode(PersistentEphemeralNode.Mode mode)
+ {
+ this.mode = mode;
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/2b2e7858/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/SemaphoreSpec.java
----------------------------------------------------------------------
diff --git a/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/SemaphoreSpec.java b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/SemaphoreSpec.java
new file mode 100644
index 0000000..b177f35
--- /dev/null
+++ b/curator-x-rest/src/main/java/org/apache/curator/x/rest/entities/SemaphoreSpec.java
@@ -0,0 +1,65 @@
+package org.apache.curator.x.rest.entities;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class SemaphoreSpec
+{
+ private String path;
+ private int acquireQty;
+ private int maxWaitMs;
+ private int maxLeases;
+
+ public SemaphoreSpec()
+ {
+ this("", 0, 0, 0);
+ }
+
+ public SemaphoreSpec(String path, int acquireQty, int maxWaitMs, int maxLeases)
+ {
+ this.path = path;
+ this.acquireQty = acquireQty;
+ this.maxWaitMs = maxWaitMs;
+ this.maxLeases = maxLeases;
+ }
+
+ public int getAcquireQty()
+ {
+ return acquireQty;
+ }
+
+ public void setAcquireQty(int acquireQty)
+ {
+ this.acquireQty = acquireQty;
+ }
+
+ public String getPath()
+ {
+ return path;
+ }
+
+ public void setPath(String path)
+ {
+ this.path = path;
+ }
+
+ public int getMaxWaitMs()
+ {
+ return maxWaitMs;
+ }
+
+ public void setMaxWaitMs(int maxWaitMs)
+ {
+ this.maxWaitMs = maxWaitMs;
+ }
+
+ public int getMaxLeases()
+ {
+ return maxLeases;
+ }
+
+ public void setMaxLeases(int maxLeases)
+ {
+ this.maxLeases = maxLeases;
+ }
+}