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 2016/05/19 19:02:25 UTC
[10/35] curator git commit: more doc, some testing, schema set loader
more doc, some testing, schema set loader
Project: http://git-wip-us.apache.org/repos/asf/curator/repo
Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/734f4533
Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/734f4533
Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/734f4533
Branch: refs/heads/CURATOR-3.0
Commit: 734f4533808f1a4b8b8086407476bca8862339ff
Parents: 8ccfdeb
Author: randgalt <ra...@apache.org>
Authored: Mon May 2 21:41:25 2016 -0500
Committer: randgalt <ra...@apache.org>
Committed: Mon May 2 21:41:25 2016 -0500
----------------------------------------------------------------------
curator-framework/pom.xml | 12 ++
.../curator/framework/schema/SchemaSet.java | 34 +++--
.../framework/schema/SchemaSetLoader.java | 148 +++++++++++++++++++
.../framework/schema/SchemaViolation.java | 7 +
.../curator/framework/imps/TestSchema.java | 61 ++++++++
.../src/test/resources/schema1.json | 9 ++
pom.xml | 13 ++
7 files changed, 272 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/curator/blob/734f4533/curator-framework/pom.xml
----------------------------------------------------------------------
diff --git a/curator-framework/pom.xml b/curator-framework/pom.xml
index 32b2cdb..c47e265 100644
--- a/curator-framework/pom.xml
+++ b/curator-framework/pom.xml
@@ -57,6 +57,18 @@
</dependency>
<dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<scope>test</scope>
http://git-wip-us.apache.org/repos/asf/curator/blob/734f4533/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaSet.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaSet.java b/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaSet.java
index 1014dc8..768f6c6 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaSet.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaSet.java
@@ -41,6 +41,7 @@ public class SchemaSet
.build(cacheLoader);
private static final Schema defaultSchema = new Schema(null, "", "Default schema", new DefaultDataValidator(), Schema.Allowance.CAN, Schema.Allowance.CAN, Schema.Allowance.CAN, true);
+ private final boolean useDefaultSchema;
/**
* Return the default (empty) schema set
@@ -49,7 +50,7 @@ public class SchemaSet
*/
public static SchemaSet getDefaultSchemaSet()
{
- return new SchemaSet(Collections.<SchemaKey, Schema>emptyMap())
+ return new SchemaSet(Collections.<SchemaKey, Schema>emptyMap(), true)
{
@Override
public String toDocumentation()
@@ -62,9 +63,11 @@ public class SchemaSet
/**
* @param schemas the schemas for the set. The key of the map is a key/name for the schema that can be
* used when calling {@link #getNamedSchema(SchemaKey)}
+ * @param useDefaultSchema if true, return a default schema when there is no match. Otherwise, an exception is thrown
*/
- public SchemaSet(Map<SchemaKey, Schema> schemas)
+ public SchemaSet(Map<SchemaKey, Schema> schemas, boolean useDefaultSchema)
{
+ this.useDefaultSchema = useDefaultSchema;
this.schemas = ImmutableMap.copyOf(Preconditions.checkNotNull(schemas, "schemas cannot be null"));
ImmutableMap.Builder<String, Schema> builder = ImmutableMap.builder();
for ( Schema schema : schemas.values() )
@@ -85,24 +88,31 @@ public class SchemaSet
*/
public Schema getSchema(String path)
{
- if ( schemas.size() == 0 )
+ Schema schema = null;
+ if ( schemas.size() > 0 )
{
- return defaultSchema;
+ schema = pathSchemas.get(path);
+ if ( schema == null )
+ {
+ try
+ {
+ schema = regexCache.get(path);
+ }
+ catch ( ExecutionException e )
+ {
+ throw new RuntimeException(e);
+ }
+ }
}
- Schema schema = pathSchemas.get(path);
if ( schema != null )
{
return schema;
}
-
- try
+ if ( useDefaultSchema )
{
- return regexCache.get(path);
- }
- catch ( ExecutionException e )
- {
- throw new RuntimeException(e);
+ return defaultSchema;
}
+ throw new SchemaViolation("No schema found for: " + path);
}
/**
http://git-wip-us.apache.org/repos/asf/curator/blob/734f4533/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaSetLoader.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaSetLoader.java b/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaSetLoader.java
new file mode 100644
index 0000000..092b161
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaSetLoader.java
@@ -0,0 +1,148 @@
+package org.apache.curator.framework.schema;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableMap;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.regex.Pattern;
+
+/**
+ * <p>
+ * Utility to load schems set from a JSON stream/file. <strong>NOTE:</strong>
+ * to avoid adding a new dependency to Curator, the Jackson library has been used
+ * with "provided" scope. You will need to add a dependency to <code>com.fasterxml.jackson.core:jackson-core:2.7.3</code>
+ * and <code>com.fasterxml.jackson.core:jackson-databind:2.7.3</code> to your project
+ * </p>
+ *
+ * <p>
+ * The JSON stream should be an array of named schemas:<br><br>
+ * <code><pre>
+ * [
+ * {
+ * "name": "name", required - name of the schema
+ * "path": "path or pattern", required - full path or regex pattern
+ * "isRegex": true/false, optional - true if path is a regular expression - default is false
+ * "dataValidator": "name", optional - name of a data validator - default is no validator
+ * "documentation": "docs", optional - user displayable docs - default is ""
+ * "ephemeral": "allowance", optional - "can", "must" or "cannot" - default is "can"
+ * "sequential": "allowance", optional - "can", "must" or "cannot" - default is "can"
+ * "watched": "allowance", optional - "can", "must" or "cannot" - default is "can"
+ * "canBeDeleted": "true/false optional - true if ZNode at path can be deleted - default is true
+ * }
+ * ]
+ * </pre></code>
+ * </p>
+ */
+public class SchemaSetLoader
+{
+ private final Map<SchemaKey, Schema> schemas;
+
+ /**
+ * Called to map a data validator name in the JSON stream to an actual data validator
+ */
+ public interface DataValidatorMapper
+ {
+ /**
+ * @param name name of the validator
+ * @return the validator
+ */
+ DataValidator getDataValidator(String name);
+ }
+
+ public SchemaSetLoader(String json, DataValidatorMapper dataValidatorMapper)
+ {
+ this(new StringReader(json), dataValidatorMapper);
+ }
+
+ public SchemaSetLoader(Reader in, DataValidatorMapper dataValidatorMapper)
+ {
+ ImmutableMap.Builder<SchemaKey, Schema> builder = ImmutableMap.builder();
+ try
+ {
+ JsonNode root = new ObjectMapper().readTree(in);
+ read(builder, root, dataValidatorMapper);
+ }
+ catch ( IOException e )
+ {
+ throw new RuntimeException(e);
+ }
+ schemas = builder.build();
+ }
+
+ public SchemaSet toSchemaSet(boolean useDefaultSchema)
+ {
+ return new SchemaSet(schemas, useDefaultSchema);
+ }
+
+ private void read(ImmutableMap.Builder<SchemaKey, Schema> builder, JsonNode node, DataValidatorMapper dataValidatorMapper)
+ {
+ for ( JsonNode child : node )
+ {
+ readNode(builder, child, dataValidatorMapper);
+ }
+ }
+
+ private void readNode(ImmutableMap.Builder<SchemaKey, Schema> builder, JsonNode node, DataValidatorMapper dataValidatorMapper)
+ {
+ String name = getText(node, "name", null);
+ String path = getText(node, "path", null);
+ boolean isRegex = getBoolean(node, "isRegex");
+ if ( name == null )
+ {
+ throw new RuntimeException("name is required at: " + node);
+ }
+ if ( path == null )
+ {
+ throw new RuntimeException("path is required at: " + node);
+ }
+
+ SchemaBuilder schemaBuilder = isRegex ? Schema.builder(Pattern.compile(path)) : Schema.builder(path);
+
+ String dataValidatorName = getText(node, "dataValidator", null);
+ if ( dataValidatorName != null )
+ {
+ if ( dataValidatorMapper == null )
+ {
+ throw new RuntimeException("No DataValidatorMapper provided but needed at: " + node);
+ }
+ schemaBuilder.dataValidator(dataValidatorMapper.getDataValidator(dataValidatorName));
+ }
+
+ Schema schema = schemaBuilder.documentation(getText(node, "documentation", ""))
+ .ephemeral(getAllowance(node, "ephemeral"))
+ .sequential(getAllowance(node, "sequential"))
+ .watched(getAllowance(node, "watched"))
+ .canBeDeleted(getBoolean(node, "canBeDeleted"))
+ .build();
+ builder.put(new SchemaKey(name), schema);
+ }
+
+ private String getText(JsonNode node, String name, String defaultValue)
+ {
+ JsonNode namedNode = node.get(name);
+ return (namedNode != null) ? namedNode.asText() : defaultValue;
+ }
+
+ private boolean getBoolean(JsonNode node, String name)
+ {
+ JsonNode namedNode = node.get(name);
+ return (namedNode != null) && namedNode.asBoolean();
+ }
+
+ private Schema.Allowance getAllowance(JsonNode node, String name)
+ {
+ JsonNode namedNode = node.get(name);
+ try
+ {
+ return (namedNode != null) ? Schema.Allowance.valueOf(namedNode.asText().toUpperCase()) : Schema.Allowance.CAN;
+ }
+ catch ( IllegalArgumentException ignore )
+ {
+ throw new RuntimeException("Must be one of: " + Arrays.toString(Schema.Allowance.values()) + " at " + node);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/734f4533/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaViolation.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaViolation.java b/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaViolation.java
index afd6bbf..4953c65 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaViolation.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaViolation.java
@@ -8,6 +8,13 @@ public class SchemaViolation extends RuntimeException
private final Schema schema;
private final String violation;
+ public SchemaViolation(String violation)
+ {
+ super(String.format("Schema violation: %s", violation));
+ this.schema = null;
+ this.violation = violation;
+ }
+
public SchemaViolation(Schema schema, String violation)
{
super(String.format("Schema violation: %s for schema: %s", violation, schema));
http://git-wip-us.apache.org/repos/asf/curator/blob/734f4533/curator-framework/src/test/java/org/apache/curator/framework/imps/TestSchema.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/java/org/apache/curator/framework/imps/TestSchema.java b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestSchema.java
new file mode 100644
index 0000000..a55ad8e
--- /dev/null
+++ b/curator-framework/src/test/java/org/apache/curator/framework/imps/TestSchema.java
@@ -0,0 +1,61 @@
+package org.apache.curator.framework.imps;
+
+import com.google.common.base.Charsets;
+import com.google.common.io.Resources;
+import org.apache.curator.framework.CuratorFramework;
+import org.apache.curator.framework.CuratorFrameworkFactory;
+import org.apache.curator.framework.schema.SchemaSet;
+import org.apache.curator.framework.schema.SchemaSetLoader;
+import org.apache.curator.framework.schema.SchemaViolation;
+import org.apache.curator.retry.RetryOneTime;
+import org.apache.curator.test.BaseClassForTests;
+import org.apache.curator.utils.CloseableUtils;
+import org.apache.zookeeper.CreateMode;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+import java.io.IOException;
+
+public class TestSchema extends BaseClassForTests
+{
+ @Test
+ public void testBasics() throws Exception
+ {
+ SchemaSet schemaSet = loadSchemaSet("schema1.json");
+ CuratorFramework client = newClient(schemaSet);
+ try
+ {
+ client.start();
+
+ try
+ {
+ client.create().creatingParentsIfNeeded().forPath("/a/b/c");
+ Assert.fail("Should've violated schema");
+ }
+ catch ( SchemaViolation dummy )
+ {
+ // expected
+ }
+
+ client.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath("/a/b/c");
+ }
+ finally
+ {
+ CloseableUtils.closeQuietly(client);
+ }
+ }
+
+ private CuratorFramework newClient(SchemaSet schemaSet)
+ {
+ return CuratorFrameworkFactory.builder()
+ .connectString(server.getConnectString())
+ .retryPolicy(new RetryOneTime(1))
+ .schemaSet(schemaSet)
+ .build();
+ }
+
+ private SchemaSet loadSchemaSet(String name) throws IOException
+ {
+ String json = Resources.toString(Resources.getResource(name), Charsets.UTF_8);
+ return new SchemaSetLoader(json, null).toSchemaSet(true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/curator/blob/734f4533/curator-framework/src/test/resources/schema1.json
----------------------------------------------------------------------
diff --git a/curator-framework/src/test/resources/schema1.json b/curator-framework/src/test/resources/schema1.json
new file mode 100644
index 0000000..5491059
--- /dev/null
+++ b/curator-framework/src/test/resources/schema1.json
@@ -0,0 +1,9 @@
+[
+ {
+ "name": "test",
+ "path": "/a/b/c",
+ "documentation": "This is a schema",
+ "ephemeral": "must",
+ "sequential": "cannot"
+ }
+]
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/curator/blob/734f4533/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index f946f59..d9d33fa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,6 +67,7 @@
<maven-license-plugin-version>1.9.0</maven-license-plugin-version>
<commons-math-version>2.2</commons-math-version>
<jackson-mapper-asl-version>1.9.13</jackson-mapper-asl-version>
+ <jackson-version>2.7.3</jackson-version>
<jersey-version>1.18.1</jersey-version>
<jsr311-api-version>1.1.1</jsr311-api-version>
<jetty-version>6.1.26</jetty-version>
@@ -356,6 +357,18 @@
</dependency>
<dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>${jackson-version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>${jackson-version}</version>
+ </dependency>
+
+ <dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey-version}</version>