Better exceptions messaging when there is a Schema violation. This is much more useful for debugging purposes
Project: http://git-wip-us.apache.org/repos/asf/curator/repo Commit: http://git-wip-us.apache.org/repos/asf/curator/commit/3735b50b Tree: http://git-wip-us.apache.org/repos/asf/curator/tree/3735b50b Diff: http://git-wip-us.apache.org/repos/asf/curator/diff/3735b50b Branch: refs/heads/CURATOR-351 Commit: 3735b50ba8ecdd60325bb9b1d65ff13ddc4836e4 Parents: 1998491 Author: randgalt <randg...@apache.org> Authored: Mon Oct 3 18:34:53 2016 +0200 Committer: randgalt <randg...@apache.org> Committed: Mon Oct 3 18:34:53 2016 +0200 ---------------------------------------------------------------------- .../imps/CuratorMultiTransactionImpl.java | 4 +- .../framework/imps/DeleteBuilderImpl.java | 2 +- .../framework/imps/ExistsBuilderImpl.java | 2 +- .../framework/imps/GetChildrenBuilderImpl.java | 2 +- .../framework/imps/GetDataBuilderImpl.java | 2 +- .../apache/curator/framework/schema/Schema.java | 22 ++-- .../curator/framework/schema/SchemaSet.java | 2 +- .../framework/schema/SchemaViolation.java | 101 +++++++++++++++++++ 8 files changed, 121 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/curator/blob/3735b50b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java index 40eb4a2..d0a8e7f 100644 --- a/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java +++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/CuratorMultiTransactionImpl.java @@ -38,6 +38,7 @@ import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.OpResult; import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.proto.CreateRequest; +import org.apache.zookeeper.proto.DeleteRequest; import org.apache.zookeeper.proto.SetDataRequest; import java.util.Arrays; import java.util.List; @@ -133,7 +134,8 @@ public class CuratorMultiTransactionImpl implements } else if ( (curatorOp.get().getType() == ZooDefs.OpCode.delete) || (curatorOp.get().getType() == ZooDefs.OpCode.deleteContainer) ) { - schema.validateDelete(); + DeleteRequest deleteRequest = (DeleteRequest)curatorOp.get().toRequestRecord(); + schema.validateDelete(deleteRequest.getPath()); } else if ( curatorOp.get().getType() == ZooDefs.OpCode.setData ) { http://git-wip-us.apache.org/repos/asf/curator/blob/3735b50b/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java index cbd12dd..78eafd8 100644 --- a/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java +++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/DeleteBuilderImpl.java @@ -213,7 +213,7 @@ class DeleteBuilderImpl implements DeleteBuilder, BackgroundOperation<String>, E @Override public Void forPath(String path) throws Exception { - client.getSchemaSet().getSchema(path).validateDelete(); + client.getSchemaSet().getSchema(path).validateDelete(path); final String unfixedPath = path; path = client.fixForNamespace(path); http://git-wip-us.apache.org/repos/asf/curator/blob/3735b50b/curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java index 960b577..97e8147 100644 --- a/curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java +++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/ExistsBuilderImpl.java @@ -158,7 +158,7 @@ class ExistsBuilderImpl implements ExistsBuilder, BackgroundOperation<String>, E { path = client.fixForNamespace(path); - client.getSchemaSet().getSchema(path).validateWatch(watching.isWatched() || watching.hasWatcher()); + client.getSchemaSet().getSchema(path).validateWatch(path, watching.isWatched() || watching.hasWatcher()); Stat returnStat = null; if ( backgrounding.inBackground() ) http://git-wip-us.apache.org/repos/asf/curator/blob/3735b50b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java index 000c911..d26f270 100644 --- a/curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java +++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetChildrenBuilderImpl.java @@ -197,7 +197,7 @@ class GetChildrenBuilderImpl implements GetChildrenBuilder, BackgroundOperation< @Override public List<String> forPath(String path) throws Exception { - client.getSchemaSet().getSchema(path).validateWatch(watching.isWatched() || watching.hasWatcher()); + client.getSchemaSet().getSchema(path).validateWatch(path, watching.isWatched() || watching.hasWatcher()); path = client.fixForNamespace(path); http://git-wip-us.apache.org/repos/asf/curator/blob/3735b50b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java ---------------------------------------------------------------------- diff --git a/curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java index bae126c..8d92f8d 100644 --- a/curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java +++ b/curator-framework/src/main/java/org/apache/curator/framework/imps/GetDataBuilderImpl.java @@ -276,7 +276,7 @@ class GetDataBuilderImpl implements GetDataBuilder, BackgroundOperation<String>, @Override public byte[] forPath(String path) throws Exception { - client.getSchemaSet().getSchema(path).validateWatch(watching.isWatched() || watching.hasWatcher()); + client.getSchemaSet().getSchema(path).validateWatch(path, watching.isWatched() || watching.hasWatcher()); path = client.fixForNamespace(path); http://git-wip-us.apache.org/repos/asf/curator/blob/3735b50b/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 index ce128e9..e9f4f18 100644 --- 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 @@ -134,32 +134,34 @@ public class Schema /** * Validate that this schema allows znode deletion * + * @param path the znode full path * @throws SchemaViolation if schema does not allow znode deletion */ - public void validateDelete() + public void validateDelete(String path) { if ( !canBeDeleted ) { - throw new SchemaViolation(this, "Cannot be deleted"); + throw new SchemaViolation(this, new SchemaViolation.ViolatorData(path, null, null), "Cannot be deleted"); } } /** * Validate that this schema's watching setting matches * + * @param path the znode full path * @param isWatching true if attempt is being made to watch node * @throws SchemaViolation if schema's watching setting does not match */ - public void validateWatch(boolean isWatching) + public void validateWatch(String path, boolean isWatching) { if ( isWatching && (watched == Allowance.CANNOT) ) { - throw new SchemaViolation(this, "Cannot be watched"); + throw new SchemaViolation(this, new SchemaViolation.ViolatorData(path, null, null), "Cannot be watched"); } if ( !isWatching && (watched == Allowance.MUST) ) { - throw new SchemaViolation(this, "Must be watched"); + throw new SchemaViolation(this, new SchemaViolation.ViolatorData(path, null, null), "Must be watched"); } } @@ -176,22 +178,22 @@ public class Schema { if ( mode.isEphemeral() && (ephemeral == Allowance.CANNOT) ) { - throw new SchemaViolation(this, "Cannot be ephemeral"); + throw new SchemaViolation(this, new SchemaViolation.ViolatorData(path, data, acl), "Cannot be ephemeral"); } if ( !mode.isEphemeral() && (ephemeral == Allowance.MUST) ) { - throw new SchemaViolation(this, "Must be ephemeral"); + throw new SchemaViolation(this, new SchemaViolation.ViolatorData(path, data, acl), "Must be ephemeral"); } if ( mode.isSequential() && (sequential == Allowance.CANNOT) ) { - throw new SchemaViolation(this, "Cannot be sequential"); + throw new SchemaViolation(this, new SchemaViolation.ViolatorData(path, data, acl), "Cannot be sequential"); } if ( !mode.isSequential() && (sequential == Allowance.MUST) ) { - throw new SchemaViolation(this, "Must be sequential"); + throw new SchemaViolation(this, new SchemaViolation.ViolatorData(path, data, acl), "Must be sequential"); } validateGeneral(path, data, acl); @@ -210,7 +212,7 @@ public class Schema { if ( !schemaValidator.isValid(this, path, data, acl) ) { - throw new SchemaViolation(this, "Data is not valid"); + throw new SchemaViolation(this, new SchemaViolation.ViolatorData(path, data, acl), "Data is not valid"); } } http://git-wip-us.apache.org/repos/asf/curator/blob/3735b50b/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 95a6ef9..98eeefc 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 @@ -171,7 +171,7 @@ public class SchemaSet { return defaultSchema; } - throw new SchemaViolation("No schema found for: " + path); + throw new SchemaViolation(null, new SchemaViolation.ViolatorData(path, null, null), "No schema found for: " + path); } /** http://git-wip-us.apache.org/repos/asf/curator/blob/3735b50b/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 47661d1..3f8f1d9 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 @@ -18,6 +18,12 @@ */ package org.apache.curator.framework.schema; +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; +import org.apache.zookeeper.data.ACL; +import java.util.Arrays; +import java.util.List; + /** * Thrown by the various <code>validation</code> methods in a Schema */ @@ -25,19 +31,98 @@ public class SchemaViolation extends RuntimeException { private final Schema schema; private final String violation; + private final ViolatorData violatorData; + + /** + * Data about the calling API that violated the schema + */ + public static class ViolatorData + { + private final String path; + private final byte[] data; + private final List<ACL> acl; + + public ViolatorData(String path, byte[] data, List<ACL> acl) + { + this.path = path; + this.data = (data != null) ? Arrays.copyOf(data, data.length) : null; + this.acl = (acl != null) ? ImmutableList.copyOf(acl) : null; + } + + /** + * The path used in the API or <code>null</code> + * + * @return path or null + */ + public String getPath() + { + return path; + } + + /** + * The data used in the API or <code>null</code> + * + * @return data or null + */ + public byte[] getData() + { + return data; + } + /** + * The ACLs used in the API or <code>null</code> + * + * @return ACLs or null + */ + public List<ACL> getAcl() + { + return acl; + } + + @Override + public String toString() + { + String dataString = (data != null) ? new String(data) : ""; + return "ViolatorData{" + "path='" + path + '\'' + ", data=" + dataString + ", acl=" + acl + '}'; + } + } + + /** + * @param violation the violation + * @deprecated use {@link #SchemaViolation(Schema, ViolatorData, String)} instance + */ public SchemaViolation(String violation) { super(String.format("Schema violation: %s", violation)); this.schema = null; this.violation = violation; + this.violatorData = new ViolatorData(null, null, null); } + /** + * @param schema the schema + * @param violation the violation + * @deprecated use {@link #SchemaViolation(Schema, ViolatorData, String)} instance + */ public SchemaViolation(Schema schema, String violation) { super(String.format("Schema violation: %s for schema: %s", violation, schema)); this.schema = schema; this.violation = violation; + this.violatorData = new ViolatorData(null, null, null); + } + + /** + * @param schema the schema + * @param violatorData data about the caller who violated the schema + * @param violation the violation + */ + public SchemaViolation(Schema schema, ViolatorData violatorData, String violation) + { + super(toString(schema, violation, violatorData)); + this.schema = schema; + this.violation = violation; + this.violatorData = violatorData; } public Schema getSchema() @@ -49,4 +134,20 @@ public class SchemaViolation extends RuntimeException { return violation; } + + public ViolatorData getViolatorData() + { + return violatorData; + } + + @Override + public String toString() + { + return toString(schema, violation, violatorData) + super.toString(); + } + + private static String toString(Schema schema, String violation, ViolatorData violatorData) + { + return Objects.firstNonNull(violation, "") + " " + schema + " " + violatorData; + } }