curator-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From randg...@apache.org
Subject [01/16] curator git commit: initial work on schema validation
Date Tue, 03 May 2016 15:20:53 GMT
Repository: curator
Updated Branches:
  refs/heads/CURATOR-322 [created] ae6cb4be4


initial work on schema validation


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

Branch: refs/heads/CURATOR-322
Commit: ef1658c17e3f991968932c0bef94d547ecea790d
Parents: e76eb59
Author: randgalt <randgalt@apache.org>
Authored: Mon May 2 14:06:15 2016 -0500
Committer: randgalt <randgalt@apache.org>
Committed: Mon May 2 14:06:15 2016 -0500

----------------------------------------------------------------------
 .../framework/CuratorFrameworkFactory.java      |  20 +++
 .../framework/imps/CreateBuilderImpl.java       |   5 +-
 .../framework/imps/CuratorFrameworkImpl.java    |   9 ++
 .../curator/framework/schema/DataValidator.java |   6 +
 .../framework/schema/DefaultDataValidator.java  |  10 ++
 .../apache/curator/framework/schema/Schema.java | 144 +++++++++++++++++++
 .../curator/framework/schema/SchemaBuilder.java |  61 ++++++++
 .../curator/framework/schema/SchemaSet.java     |  77 ++++++++++
 .../framework/schema/SchemaViolation.java       |   9 ++
 9 files changed, 339 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/ef1658c1/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java
b/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java
index fedafa4..5aed199 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java
@@ -34,6 +34,7 @@ import org.apache.curator.framework.imps.CuratorFrameworkImpl;
 import org.apache.curator.framework.imps.CuratorTempFrameworkImpl;
 import org.apache.curator.framework.imps.DefaultACLProvider;
 import org.apache.curator.framework.imps.GzipCompressionProvider;
+import org.apache.curator.framework.schema.SchemaSet;
 import org.apache.curator.framework.state.ConnectionStateErrorPolicy;
 import org.apache.curator.framework.state.StandardConnectionStateErrorPolicy;
 import org.apache.curator.framework.state.ConnectionState;
@@ -143,6 +144,7 @@ public class CuratorFrameworkFactory
         private boolean useContainerParentsIfAvailable = true;
         private ConnectionStateErrorPolicy connectionStateErrorPolicy = new StandardConnectionStateErrorPolicy();
         private ConnectionHandlingPolicy connectionHandlingPolicy = Boolean.getBoolean("curator-use-classic-connection-handling")
? new ClassicConnectionHandlingPolicy() : new StandardConnectionHandlingPolicy();
+        private SchemaSet schemaSet = new SchemaSet();
 
         /**
          * Apply the current values and build a new CuratorFramework
@@ -430,6 +432,19 @@ public class CuratorFrameworkFactory
             return this;
         }
 
+        /**
+         * Add an enforced schema set
+         *
+         * @param schemaSet the schema set
+         * @return this
+         * @since 3.2.0
+         */
+        public Builder schemaSet(SchemaSet schemaSet)
+        {
+            this.schemaSet = schemaSet;
+            return this;
+        }
+
         public ACLProvider getAclProvider()
         {
             return aclProvider;
@@ -495,6 +510,11 @@ public class CuratorFrameworkFactory
             return connectionHandlingPolicy;
         }
 
+        public SchemaSet getSchemaSet()
+        {
+            return schemaSet;
+        }
+
         @Deprecated
         public String getAuthScheme()
         {

http://git-wip-us.apache.org/repos/asf/curator/blob/ef1658c1/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
b/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
index 9e8f7e6..facabe7 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/CreateBuilderImpl.java
@@ -35,7 +35,6 @@ import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.Op;
 import org.apache.zookeeper.data.ACL;
 import org.apache.zookeeper.data.Stat;
-
 import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.Callable;
@@ -481,6 +480,8 @@ class CreateBuilderImpl implements CreateBuilder, BackgroundOperation<PathAndByt
     @Override
     public String forPath(final String givenPath, byte[] data) throws Exception
     {
+        client.getSchemaSet().getSchema(givenPath).validateCreate(createMode, data);
+
         if ( compress )
         {
             data = client.getCompressionProvider().compress(givenPath, data);
@@ -714,7 +715,7 @@ class CreateBuilderImpl implements CreateBuilder, BackgroundOperation<PathAndByt
                 client.queueOperation(mainOperationAndData);
             }
         };
-        OperationAndData<T> parentOperation = new OperationAndData<T>(operation,
mainOperationAndData.getData(), null, null, backgrounding.getContext(), null);
+        OperationAndData<T> parentOperation = new OperationAndData<>(operation,
mainOperationAndData.getData(), null, null, backgrounding.getContext(), null);
         client.queueOperation(parentOperation);
     }
 

http://git-wip-us.apache.org/repos/asf/curator/blob/ef1658c1/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java
b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java
index 4e1aefc..739f07e 100644
--- a/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java
+++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorFrameworkImpl.java
@@ -37,6 +37,7 @@ import org.apache.curator.framework.api.transaction.CuratorTransaction;
 import org.apache.curator.framework.api.transaction.TransactionOp;
 import org.apache.curator.framework.listen.Listenable;
 import org.apache.curator.framework.listen.ListenerContainer;
+import org.apache.curator.framework.schema.SchemaSet;
 import org.apache.curator.framework.state.ConnectionState;
 import org.apache.curator.framework.state.ConnectionStateErrorPolicy;
 import org.apache.curator.framework.state.ConnectionStateListener;
@@ -89,6 +90,7 @@ public class CuratorFrameworkImpl implements CuratorFramework
     private final AtomicLong currentInstanceIndex = new AtomicLong(-1);
     private final InternalConnectionHandler internalConnectionHandler;
     private final EnsembleTracker ensembleTracker;
+    private final SchemaSet schemaSet;
 
     private volatile ExecutorService executorService;
     private final AtomicBoolean logAsErrorConnectionErrors = new AtomicBoolean(false);
@@ -143,6 +145,7 @@ public class CuratorFrameworkImpl implements CuratorFramework
         state = new AtomicReference<CuratorFrameworkState>(CuratorFrameworkState.LATENT);
         useContainerParentsIfAvailable = builder.useContainerParentsIfAvailable();
         connectionStateErrorPolicy = Preconditions.checkNotNull(builder.getConnectionStateErrorPolicy(),
"errorPolicy cannot be null");
+        schemaSet = Preconditions.checkNotNull(builder.getSchemaSet(), "schemaSet cannot
be null");
 
         byte[] builderDefaultData = builder.getDefaultData();
         defaultData = (builderDefaultData != null) ? Arrays.copyOf(builderDefaultData, builderDefaultData.length)
: new byte[0];
@@ -226,6 +229,7 @@ public class CuratorFrameworkImpl implements CuratorFramework
         useContainerParentsIfAvailable = parent.useContainerParentsIfAvailable;
         connectionStateErrorPolicy = parent.connectionStateErrorPolicy;
         internalConnectionHandler = parent.internalConnectionHandler;
+        schemaSet = parent.schemaSet;
         ensembleTracker = null;
     }
 
@@ -548,6 +552,11 @@ public class CuratorFrameworkImpl implements CuratorFramework
         return namespace.newNamespaceAwareEnsurePath(path);
     }
 
+    SchemaSet getSchemaSet()
+    {
+        return schemaSet;
+    }
+
     ACLProvider getAclProvider()
     {
         return aclProvider;

http://git-wip-us.apache.org/repos/asf/curator/blob/ef1658c1/curator-framework/src/main/java/org/apache/curator/framework/schema/DataValidator.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/schema/DataValidator.java
b/curator-framework/src/main/java/org/apache/curator/framework/schema/DataValidator.java
new file mode 100644
index 0000000..855f2bb
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/schema/DataValidator.java
@@ -0,0 +1,6 @@
+package org.apache.curator.framework.schema;
+
+public interface DataValidator
+{
+    boolean isValid(byte[] data);
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/ef1658c1/curator-framework/src/main/java/org/apache/curator/framework/schema/DefaultDataValidator.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/schema/DefaultDataValidator.java
b/curator-framework/src/main/java/org/apache/curator/framework/schema/DefaultDataValidator.java
new file mode 100644
index 0000000..05e1f7c
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/schema/DefaultDataValidator.java
@@ -0,0 +1,10 @@
+package org.apache.curator.framework.schema;
+
+public class DefaultDataValidator implements DataValidator
+{
+    @Override
+    public boolean isValid(byte[] data)
+    {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/ef1658c1/curator-framework/src/main/java/org/apache/curator/framework/schema/Schema.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/schema/Schema.java
b/curator-framework/src/main/java/org/apache/curator/framework/schema/Schema.java
new file mode 100644
index 0000000..f10542d
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/schema/Schema.java
@@ -0,0 +1,144 @@
+package org.apache.curator.framework.schema;
+
+import com.google.common.base.Preconditions;
+import org.apache.zookeeper.CreateMode;
+import java.util.regex.Pattern;
+
+public class Schema
+{
+    private final Pattern path;
+    private final String documentation;
+    private final DataValidator dataValidator;
+    private final Allowance ephemeral;
+    private final Allowance sequential;
+    private final boolean canBeWatched;
+    private final boolean canHaveChildren;
+
+    public enum Allowance
+    {
+        CAN,
+        MUST,
+        CANNOT
+    }
+
+    public static SchemaBuilder builder(String path)
+    {
+        return new SchemaBuilder(Pattern.compile(path));
+    }
+
+    public Schema(Pattern path, String documentation, DataValidator dataValidator, Allowance
ephemeral, Allowance sequential, boolean canBeWatched, boolean canHaveChildren)
+    {
+        this.path = Preconditions.checkNotNull(path, "path cannot be null");
+        this.documentation = Preconditions.checkNotNull(documentation, "documentation cannot
be null");
+        this.dataValidator = Preconditions.checkNotNull(dataValidator, "dataValidator cannot
be null");
+        this.ephemeral = Preconditions.checkNotNull(ephemeral, "ephemeral cannot be null");
+        this.sequential = Preconditions.checkNotNull(sequential, "sequential cannot be null");
+        this.canBeWatched = canBeWatched;
+        this.canHaveChildren = canHaveChildren;
+    }
+
+    public void validateCreate(CreateMode mode, byte[] data)
+    {
+        if ( mode.isEphemeral() && (ephemeral == Allowance.CANNOT) )
+        {
+            throw new SchemaViolation(this, "Cannot be ephemeral");
+        }
+
+        if ( !mode.isEphemeral() && (ephemeral == Allowance.MUST) )
+        {
+            throw new SchemaViolation(this, "Must be ephemeral");
+        }
+
+        validateData(data);
+    }
+
+    public void validateData(byte[] data)
+    {
+        if ( !dataValidator.isValid(data) )
+        {
+            throw new SchemaViolation(this, "Data is not valid");
+        }
+    }
+
+    public Pattern getPath()
+    {
+        return path;
+    }
+
+    public String getDocumentation()
+    {
+        return documentation;
+    }
+
+    public DataValidator getDataValidator()
+    {
+        return dataValidator;
+    }
+
+    public Allowance getEphemeral()
+    {
+        return ephemeral;
+    }
+
+    public Allowance getSequential()
+    {
+        return sequential;
+    }
+
+    public boolean isCanBeWatched()
+    {
+        return canBeWatched;
+    }
+
+    public boolean isCanHaveChildren()
+    {
+        return canHaveChildren;
+    }
+
+    @Override
+    public boolean equals(Object o)
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+        if ( o == null || getClass() != o.getClass() )
+        {
+            return false;
+        }
+
+        Schema schema = (Schema)o;
+
+        return path.equals(schema.path);
+
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return path.hashCode();
+    }
+
+    @Override
+    public String toString()
+    {
+        return "Schema{" +
+            "path=" + path +
+            ", documentation='" + documentation + '\'' +
+            ", dataValidator=" + dataValidator +
+            ", isEphemeral=" + ephemeral +
+            ", isSequential=" + sequential +
+            ", canBeWatched=" + canBeWatched +
+            ", canHaveChildren=" + canHaveChildren +
+            '}';
+    }
+
+    public String toDocumentation()
+    {
+        return path.pattern() + '\n'
+            + documentation + '\n'
+            + "Validator: " + dataValidator.getClass().getSimpleName() + '\n'
+            + String.format("ephemeral: %s | sequential: %s | canBeWatched: %s | canHaveChildren:
%s", ephemeral, sequential, canBeWatched, canHaveChildren) + '\n'
+            ;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/ef1658c1/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaBuilder.java
----------------------------------------------------------------------
diff --git a/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaBuilder.java
b/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaBuilder.java
new file mode 100644
index 0000000..053ccfc
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaBuilder.java
@@ -0,0 +1,61 @@
+package org.apache.curator.framework.schema;
+
+import com.google.common.base.Preconditions;
+import java.util.regex.Pattern;
+
+public class SchemaBuilder
+{
+    private Pattern path;
+    private String documentation = "";
+    private DataValidator dataValidator = new DefaultDataValidator();
+    private boolean isEphemeral = false;
+    private boolean isSequential = false;
+    private boolean canBeWatched = true;
+    private boolean canHaveChildren = true;
+
+    public Schema build()
+    {
+        return new Schema(path, documentation, dataValidator, isEphemeral, isSequential,
canBeWatched, canHaveChildren);
+    }
+
+    public SchemaBuilder documentation(String documentation)
+    {
+        this.documentation = Preconditions.checkNotNull(documentation, "documentation cannot
be null");
+        return this;
+    }
+
+    public SchemaBuilder dataValidator(DataValidator dataValidator)
+    {
+        this.dataValidator = Preconditions.checkNotNull(dataValidator, "dataValidator cannot
be null");
+        return this;
+    }
+
+    public SchemaBuilder isEphemeral(boolean isEphemeral)
+    {
+        this.isEphemeral = isEphemeral;
+        return this;
+    }
+
+    public SchemaBuilder isSequential(boolean isSequential)
+    {
+        this.isSequential = isSequential;
+        return this;
+    }
+
+    public SchemaBuilder canBeWatched(boolean canBeWatched)
+    {
+        this.canBeWatched = canBeWatched;
+        return this;
+    }
+
+    public SchemaBuilder canHaveChildren(boolean canHaveChildren)
+    {
+        this.canHaveChildren = canHaveChildren;
+        return this;
+    }
+
+    SchemaBuilder(Pattern path)
+    {
+        this.path = Preconditions.checkNotNull(path, "path cannot be null");
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/ef1658c1/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
new file mode 100644
index 0000000..0c3dfd5
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaSet.java
@@ -0,0 +1,77 @@
+package org.apache.curator.framework.schema;
+
+import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
+import com.google.common.collect.ImmutableSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Pattern;
+
+public class SchemaSet
+{
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private final Collection<Schema> schemas;
+    private final CacheLoader<String, Schema> cacheLoader = new CacheLoader<String,
Schema>()
+    {
+        @Override
+        public Schema load(String path) throws Exception
+        {
+            for ( Schema schema : schemas )
+            {
+                if ( schema.getPath().matcher(path).matches() )
+                {
+                    log.debug("path -> {}", schema);
+                    return schema;
+                }
+            }
+            return defaultSchema;
+        }
+    };
+    private final LoadingCache<String, Schema> cache = CacheBuilder
+        .newBuilder()
+        .softValues()
+        .build(cacheLoader);
+
+    private static final Schema defaultSchema = new Schema(Pattern.compile(".*"), "__default__",
new DefaultDataValidator(), Schema.Allowance.CAN, Schema.Allowance.CAN, true, true);
+
+    public SchemaSet()
+    {
+        this(Collections.<Schema>emptySet());
+    }
+
+    public SchemaSet(Collection<Schema> schemas)
+    {
+        this.schemas = ImmutableSet.copyOf(Preconditions.checkNotNull(schemas, "schemas cannot
be null"));
+    }
+
+    public Schema getSchema(String path)
+    {
+        if ( schemas.size() == 0 )
+        {
+            return defaultSchema;
+        }
+        try
+        {
+            return cache.get(path);
+        }
+        catch ( ExecutionException e )
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public String toDocumentation()
+    {
+        StringBuilder str = new StringBuilder("Curator Schemas:\n\n");
+        for ( Schema schema : schemas )
+        {
+            str.append(schema).append('\n');
+        }
+        return str.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/ef1658c1/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
new file mode 100644
index 0000000..6935094
--- /dev/null
+++ b/curator-framework/src/main/java/org/apache/curator/framework/schema/SchemaViolation.java
@@ -0,0 +1,9 @@
+package org.apache.curator.framework.schema;
+
+public class SchemaViolation extends RuntimeException
+{
+    public SchemaViolation(Schema schema, String violation)
+    {
+        super(String.format("Schema violation: %s for schema: %s", violation, schema));
+    }
+}


Mime
View raw message