You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by uj...@apache.org on 2012/11/22 09:38:46 UTC

svn commit: r1412448 - in /accumulo/trunk/core/src: main/java/org/apache/accumulo/core/security/ColumnVisibility.java test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java

Author: ujustgotbilld
Date: Thu Nov 22 08:38:46 2012
New Revision: 1412448

URL: http://svn.apache.org/viewvc?rev=1412448&view=rev
Log:
ACCUMULO-871

Updated the ColumnVisibility class to be more aggressive and consistent when flattening/normalizing expressions. Labels are dedupe'd and sorted and equivalent subtrees are pruned.


Modified:
    accumulo/trunk/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java
    accumulo/trunk/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java

Modified: accumulo/trunk/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java?rev=1412448&r1=1412447&r2=1412448&view=diff
==============================================================================
--- accumulo/trunk/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java (original)
+++ accumulo/trunk/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java Thu Nov 22 08:38:46 2012
@@ -22,6 +22,7 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.TreeSet;
 
 import org.apache.accumulo.core.data.ArrayByteSequence;
 import org.apache.accumulo.core.data.ByteSequence;
@@ -137,31 +138,77 @@ public class ColumnVisibility {
       return 0;
     }
   }
-  
-  static private void flatten(Node root, byte[] expression, StringBuilder out) {
-    if (root.type == NodeType.TERM)
+
+  /* Convience method that delegates to normalize with a new
+   * NodeComparator constructed using the supplied expression.
+   */
+  private static Node normalize(Node root, byte[] expression) {
+    return normalize(root, expression, new NodeComparator(expression));
+  } 
+
+  /* Walks an expression's AST in order to:
+   *  1) roll up expressions with the same operant (`a&(b&c) becomes a&b&c`)
+   *  2) sorts labels lexicographically (permutations of `a&b&c` are re-ordered to appear as `a&b&c`)
+   *  3) dedupes labels (`a&b&a` becomes `a&b`)
+   */
+  private static Node normalize(Node root, byte[] expression, NodeComparator comparator) {
+    if(root.type != NodeType.TERM) {
+      TreeSet<Node> rolledUp = new TreeSet<Node>(comparator);
+      java.util.Iterator<Node> itr = root.children.iterator();
+      while(itr.hasNext()) { 
+        Node c = normalize(itr.next(), expression, comparator);
+        if(c.type == root.type) {
+          rolledUp.addAll(c.children);
+          itr.remove();
+        }
+      }
+      rolledUp.addAll(root.children);
+      root.children.clear();
+      root.children.addAll(rolledUp);
+      
+      //need to promote a child if it's an only child
+      if(root.children.size() == 1) {
+        return root.children.get(0);
+      }
+    }
+
+    return root;
+  }
+
+  /* Walks an expression's AST and appends a string representation to a supplied
+   * StringBuilder. This method adds parens where necessary.
+   */
+  private static void stringify(Node root, byte[] expression, StringBuilder out) {
+    if (root.type == NodeType.TERM) {
       out.append(new String(expression, root.start, root.end - root.start));
+    }
     else {
       String sep = "";
-      Collections.sort(root.children, new NodeComparator(expression));
       for (Node c : root.children) {
         out.append(sep);
         boolean parens = (c.type != NodeType.TERM && root.type != c.type);
         if (parens)
           out.append("(");
-        flatten(c, expression, out);
+        stringify(c, expression, out);
         if (parens)
           out.append(")");
         sep = root.type == NodeType.AND ? "&" : "|";
       }
     }
   }
-  
+
+  /**
+   * Generates a byte[] that represents a normalized, but logically equivalent,
+   * form of the supplied expression.
+   *
+   * @return normalized expression in byte[] form
+   */
   public byte[] flatten() {
-    StringBuilder builder = new StringBuilder();
-    flatten(node, expression, builder);
+    Node normRoot = normalize(node, expression);
+    StringBuilder builder = new StringBuilder(expression.length);
+    stringify(normRoot, expression, builder);
     return builder.toString().getBytes();
-  }
+  } 
   
   private static class ColumnVisibilityParser {
     private int index = 0;

Modified: accumulo/trunk/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
URL: http://svn.apache.org/viewvc/accumulo/trunk/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java?rev=1412448&r1=1412447&r2=1412448&view=diff
==============================================================================
--- accumulo/trunk/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java (original)
+++ accumulo/trunk/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java Thu Nov 22 08:38:46 2012
@@ -82,6 +82,11 @@ public class ColumnVisibilityTest {
   @Test
   public void testNormalization() {
     normalized("a", "a", "(a)", "a", "b|a", "a|b", "(b)|a", "a|b", "(b|(a|c))&x", "x&(a|b|c)", "(((a)))", "a");
+    final String normForm = "a&b&c";
+    normalized("b&c&a", normForm, "c&b&a", normForm, "a&(b&c)", normForm, "(a&c)&b", normForm);
+
+    // this an expression that's basically `expr | expr`
+    normalized("(d&c&b&a)|(b&c&a&d)", "a&b&c&d");
   }
   
   @Test