From b6a7d650413cf42003ffae4910e3197d14e889be Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 19 Apr 2016 16:15:40 +0000
Subject: [PATCH] Code cleanup in ACIs

---
 opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternDN.java  |  500 +++++++++++++++--------------------
 opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciTargets.java |  187 ++++--------
 opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternRDN.java |   97 +++---
 3 files changed, 328 insertions(+), 456 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciTargets.java b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciTargets.java
index 6fb83ed..065caa5 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciTargets.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciTargets.java
@@ -18,14 +18,15 @@
 
 import static org.opends.messages.AccessControlMessages.*;
 import static org.opends.server.authorization.dseecompat.Aci.*;
+import static org.opends.server.authorization.dseecompat.EnumTargetOperator.*;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.forgerock.i18n.LocalizableMessage;
-import org.forgerock.opendj.ldap.schema.AttributeType;
 import org.forgerock.opendj.ldap.DN;
 import org.forgerock.opendj.ldap.SearchScope;
+import org.forgerock.opendj.ldap.schema.AttributeType;
 
 /**
  * This class represents target part of an ACI's syntax. This is the part
@@ -36,66 +37,31 @@
  * targetscope, targetfilter, targattrfilters, targetcontrol and extop.
  */
 public class AciTargets {
-
-    /**
-     * ACI syntax has a target keyword.
-     */
+    /** ACI syntax has a target keyword. */
     private Target target;
-
-    /**
-     * ACI syntax has a targetscope keyword.
-     */
+    /** ACI syntax has a targetscope keyword. */
     private SearchScope targetScope = SearchScope.WHOLE_SUBTREE;
-
-    /**
-     * ACI syntax has a targetattr keyword.
-     */
+    /** ACI syntax has a targetattr keyword. */
     private TargetAttr targetAttr;
-
-    /**
-     * ACI syntax has a targetfilter keyword.
-     */
+    /** ACI syntax has a targetfilter keyword. */
     private TargetFilter targetFilter;
-
-    /**
-     * ACI syntax has a targattrtfilters keyword.
-     */
+    /** ACI syntax has a targattrtfilters keyword. */
     private TargAttrFilters targAttrFilters;
-
-   /**
-    * The ACI syntax has a targetcontrol keyword.
-    */
+    /** The ACI syntax has a targetcontrol keyword. */
     private TargetControl targetControl;
-
-   /**
-    * The ACI syntax has a extop keyword.
-    */
+    /** The ACI syntax has a extop keyword. */
     private ExtOp extOp;
 
-    /**
-     * The number of regular expression group positions in a valid ACI target
-     * expression.
-     */
+    /** The number of regular expression group positions in a valid ACI target expression. */
     private static final int targetElementCount = 3;
-
-    /**
-     *  Regular expression group position of a target keyword.
-     */
+    /** Regular expression group position of a target keyword. */
     private static final int targetKeywordPos       = 1;
-
-    /**
-     *  Regular expression group position of a target operator enumeration.
-     */
+    /** Regular expression group position of a target operator enumeration. */
     private static final int targetOperatorPos      = 2;
-
-    /**
-     *  Regular expression group position of a target expression statement.
-     */
+    /** Regular expression group position of a target expression statement. */
     private static final int targetExpressionPos    = 3;
 
-    /**
-     * Regular expression used to match a single target rule.
-     */
+    /** Regular expression used to match a single target rule. */
     private static final String targetRegex =
            OPEN_PAREN +  ZERO_OR_MORE_WHITESPACE  +  WORD_GROUP +
            ZERO_OR_MORE_WHITESPACE + "(!?=)" + ZERO_OR_MORE_WHITESPACE +
@@ -463,7 +429,6 @@
      */
     public static boolean isTargAttrFiltersApplicable(Aci aci,
                                                AciTargetMatchContext matchCtx) {
-        boolean ret=true;
         TargAttrFilters targAttrFilters=aci.getTargets().getTargAttrFilters();
         if(targAttrFilters != null) {
             if((matchCtx.hasRights(ACI_ADD) &&
@@ -471,17 +436,17 @@
               (matchCtx.hasRights(ACI_DELETE) &&
                targAttrFilters.hasMask(TARGATTRFILTERS_DELETE)))
             {
-              ret=targAttrFilters.isApplicableAddDel(matchCtx);
+              return targAttrFilters.isApplicableAddDel(matchCtx);
             }
             else if((matchCtx.hasRights(ACI_WRITE_ADD) &&
                      targAttrFilters.hasMask(TARGATTRFILTERS_ADD)) ||
                     (matchCtx.hasRights(ACI_WRITE_DELETE) &&
                     targAttrFilters.hasMask(TARGATTRFILTERS_DELETE)))
             {
-              ret=targAttrFilters.isApplicableMod(matchCtx, aci);
+              return targAttrFilters.isApplicableMod(matchCtx, aci);
             }
         }
-        return ret;
+        return true;
     }
 
     /*
@@ -574,8 +539,7 @@
      * @param entryDN The DN to use in this evaluation.
      * @return True if the ACI matched the target and DN.
      */
-    public static boolean isTargetApplicable(Aci aci,
-            AciTargets targets, DN entryDN) {
+    public static boolean isTargetApplicable(Aci aci, AciTargets targets, DN entryDN) {
         DN targetDN=aci.getDN();
         /*
          * Scoping of the ACI uses either the DN of the entry
@@ -583,82 +547,63 @@
          * contains a simple target DN and a equality operator, that
          * simple target DN is used as the target DN.
          */
-        if(targets.getTarget() != null && !targets.getTarget().isPattern()) {
-            EnumTargetOperator op=targets.getTarget().getOperator();
-            if(op != EnumTargetOperator.NOT_EQUALITY)
-            {
-              targetDN=targets.getTarget().getDN();
-            }
+        Target target = targets.getTarget();
+        if(target != null && !target.isPattern() && target.getOperator() != NOT_EQUALITY)
+        {
+          targetDN=target.getDN();
         }
-        //Check if the scope is correct.
-        switch(targets.getTargetScope().asEnum()) {
-        case BASE_OBJECT:
-            if(!targetDN.equals(entryDN))
-            {
-              return false;
-            }
-            break;
-        case SINGLE_LEVEL:
-            /*
-             * We use the standard definition of single level to mean the
-             * immediate children only -- not the target entry itself.
-             * Sun CR 6535035 has been raised on DSEE:
-             * Non-standard interpretation of onelevel in ACI targetScope.
-             */
-            if(!targetDN.equals(entryDN.parent()))
-            {
-              return false;
-            }
-            break;
-        case WHOLE_SUBTREE:
-            if(!entryDN.isSubordinateOrEqualTo(targetDN))
-            {
-              return false;
-            }
-            break;
-        case SUBORDINATES:
-            if (entryDN.size() <= targetDN.size() ||
-                 !entryDN.isSubordinateOrEqualTo(targetDN)) {
-              return false;
-            }
-            break;
-        default:
+        if (!isInScopeOf(entryDN, targetDN, targets.getTargetScope()))
+        {
+          return false;
+        }
+
+        if (target != null)
+        {
+          /*
+           * For inequality checks, scope was tested against the entry containing the ACI.
+           * If operator is inequality, check that it doesn't match the target DN.
+           */
+          if (!target.isPattern()
+              && target.getOperator() == NOT_EQUALITY
+              && entryDN.isSubordinateOrEqualTo(target.getDN()))
+          {
             return false;
-        }
-        /*
-         * The entry is in scope. For inequality checks, scope was tested
-         * against the entry containing the ACI. If operator is inequality,
-         * check that it doesn't match the target DN.
-         */
-        if(targets.getTarget() != null &&
-                !targets.getTarget().isPattern()) {
-            EnumTargetOperator op=targets.getTarget().getOperator();
-            if(op == EnumTargetOperator.NOT_EQUALITY) {
-                DN tmpDN=targets.getTarget().getDN();
-                if(entryDN.isSubordinateOrEqualTo(tmpDN))
-                {
-                  return false;
-                }
-            }
-        }
-        /*
-         * There is a pattern, need to match the substring filter
-         * created when the ACI was decoded. If inequality flip the
-         * result.
-         */
-        if(targets.getTarget() != null &&
-                targets.getTarget().isPattern())  {
-            final boolean ret = targets.getTarget().matchesPattern(entryDN);
-            EnumTargetOperator op=targets.getTarget().getOperator();
-            if(op == EnumTargetOperator.NOT_EQUALITY)
-            {
+          }
+          /*
+           * There is a pattern, need to match the substring filter
+           * created when the ACI was decoded. If inequality flip the result.
+           */
+          if(target.isPattern())  {
+            final boolean ret = target.matchesPattern(entryDN);
+            if (target.getOperator() == NOT_EQUALITY) {
               return !ret;
             }
             return ret;
+          }
         }
         return true;
     }
 
+    private static boolean isInScopeOf(DN entryDN, DN targetDN, SearchScope scope) {
+      switch(scope.asEnum()) {
+      case BASE_OBJECT:
+          return targetDN.equals(entryDN);
+      case SINGLE_LEVEL:
+          /*
+           * We use the standard definition of single level to mean the
+           * immediate children only -- not the target entry itself.
+           * Sun CR 6535035 has been raised on DSEE:
+           * Non-standard interpretation of onelevel in ACI targetScope.
+           */
+          return targetDN.equals(entryDN.parent());
+      case WHOLE_SUBTREE:
+          return entryDN.isSubordinateOrEqualTo(targetDN);
+      case SUBORDINATES:
+          return entryDN.size() > targetDN.size() && entryDN.isSubordinateOrEqualTo(targetDN);
+      default:
+          return false;
+      }
+    }
 
     /**
      * The method is used to try and determine if a targetAttr expression that
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternDN.java b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternDN.java
index da12b45..52cf514 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternDN.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternDN.java
@@ -22,14 +22,16 @@
 import static org.opends.server.util.StaticUtils.*;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
 import java.util.List;
 
 import org.forgerock.i18n.LocalizableMessage;
 import org.forgerock.i18n.slf4j.LocalizedLogger;
 import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.DN;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.util.Reject;
-import org.forgerock.opendj.ldap.DN;
 import org.opends.server.types.DirectoryException;
 
 /**
@@ -59,20 +61,18 @@
   private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
 
   /**
-   * If the pattern did not include any Multiple-Whole-RDN wildcards, then
-   * this is the sequence of RDN patterns in the DN pattern.  Otherwise it
-   * is null.
+   * If the pattern did not include any Multiple-Whole-RDN wildcards, then this
+   * is the sequence of RDN patterns in the DN pattern.  Otherwise it is null.
    */
-  PatternRDN[] equality;
-
+  private PatternRDN[] equality;
 
   /**
    * If the pattern included any Multiple-Whole-RDN wildcards, then these
    * are the RDN pattern sequences that appear between those wildcards.
    */
-  PatternRDN[] subInitial;
-  List<PatternRDN[]> subAnyElements;
-  PatternRDN[] subFinal;
+  private PatternRDN[] subInitial;
+  private List<PatternRDN[]> subAnyElements;
+  private PatternRDN[] subFinal;
 
 
   /**
@@ -82,14 +82,14 @@
    * suffix pattern but the pattern started with a Multiple-Whole-RDN wildcard
    * (one or more RDN components allowed before matching elements).
    */
-  boolean isSuffix;
+  private boolean isSuffix;
 
 
   /**
    * Create a DN pattern that does not include any Multiple-Whole-RDN wildcards.
    * @param equality The sequence of RDN patterns making up the DN pattern.
    */
-  private PatternDN(PatternRDN[] equality)
+  private PatternDN(PatternRDN... equality)
   {
     this.equality = equality;
   }
@@ -122,109 +122,109 @@
    */
   public boolean matchesDN(DN dn)
   {
-    if (equality != null)
+    return equality != null ? equalityMatchDN(dn) : substringMatchDN(dn);
+  }
+
+  private boolean equalityMatchDN(DN dn)
+  {
+    // There are no Multiple-Whole-RDN wildcards in the pattern.
+    if (equality.length != dn.size())
     {
-      // There are no Multiple-Whole-RDN wildcards in the pattern.
-      if (equality.length != dn.size())
+      return false;
+    }
+
+    for (int i = 0; i < dn.size(); i++)
+    {
+      if (!equality[i].matchesRDN(dn.rdn(i)))
+      {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  private boolean substringMatchDN(DN dn)
+  {
+    // There are Multiple-Whole-RDN wildcards in the pattern.
+    int valueLength = dn.size();
+
+    int pos = 0;
+    if (subInitial != null)
+    {
+      int initialLength = subInitial.length;
+      if (initialLength > valueLength)
       {
         return false;
       }
 
-      for (int i = 0; i < dn.size(); i++)
+      for (; pos < initialLength; pos++)
       {
-        if (!equality[i].matchesRDN(dn.rdn(i)))
+        if (!subInitial[pos].matchesRDN(dn.rdn(pos)))
         {
           return false;
         }
       }
-
-      return true;
+      pos++;
     }
     else
     {
-      // There are Multiple-Whole-RDN wildcards in the pattern.
-      int valueLength = dn.size();
-
-      int pos = 0;
-      if (subInitial != null)
+      if (!isSuffix)
       {
-        int initialLength = subInitial.length;
-        if (initialLength > valueLength)
-        {
-          return false;
-        }
-
-        for (; pos < initialLength; pos++)
-        {
-          if (!subInitial[pos].matchesRDN(dn.rdn(pos)))
-          {
-            return false;
-          }
-        }
         pos++;
       }
-      else
+    }
+
+
+    if (subAnyElements != null && ! subAnyElements.isEmpty())
+    {
+      for (PatternRDN[] element : subAnyElements)
       {
-        if (!isSuffix)
+        int anyLength = element.length;
+
+        int end = valueLength - anyLength;
+        boolean match = false;
+        for (; pos < end; pos++)
         {
-          pos++;
-        }
-      }
-
-
-      if (subAnyElements != null && ! subAnyElements.isEmpty())
-      {
-        for (PatternRDN[] element : subAnyElements)
-        {
-          int anyLength = element.length;
-
-          int end = valueLength - anyLength;
-          boolean match = false;
-          for (; pos < end; pos++)
+          if (element[0].matchesRDN(dn.rdn(pos)))
           {
-            if (element[0].matchesRDN(dn.rdn(pos)))
+            if (subMatch(dn, pos, element, anyLength))
             {
-              if (subMatch(dn, pos, element, anyLength))
-              {
-                match = true;
-                break;
-              }
+              match = true;
+              break;
             }
           }
-
-          if (match)
-          {
-            pos += anyLength + 1;
-          }
-          else
-          {
-            return false;
-          }
         }
-      }
 
-
-      if (subFinal != null)
-      {
-        int finalLength = subFinal.length;
-
-        if (valueLength - finalLength < pos)
+        if (!match)
         {
           return false;
         }
+        pos += anyLength + 1;
+      }
+    }
 
-        pos = valueLength - finalLength;
-        for (int i=0; i < finalLength; i++,pos++)
-        {
-          if (!subFinal[i].matchesRDN(dn.rdn(pos)))
-          {
-            return false;
-          }
-        }
+
+    if (subFinal != null)
+    {
+      int finalLength = subFinal.length;
+
+      if (valueLength - finalLength < pos)
+      {
+        return false;
       }
 
-      return pos <= valueLength;
+      pos = valueLength - finalLength;
+      for (int i=0; i < finalLength; i++,pos++)
+      {
+        if (!subFinal[i].matchesRDN(dn.rdn(pos)))
+        {
+          return false;
+        }
+      }
     }
+
+    return pos <= valueLength;
   }
 
   private boolean subMatch(DN dn, int pos, PatternRDN[] element, int length)
@@ -246,8 +246,7 @@
    * is not valid.
    * @return A new DN pattern matcher.
    */
-  public static PatternDN decodeSuffix(String pattern)
-       throws DirectoryException
+  public static PatternDN decodeSuffix(String pattern) throws DirectoryException
   {
     // Parse the user supplied pattern.
     PatternDN patternDN = decode(pattern);
@@ -281,22 +280,21 @@
    * is not valid.
    * @return A new DN pattern matcher.
    */
-  public static PatternDN decode(String dnString)
-         throws DirectoryException
+  public static PatternDN decode(String dnString) throws DirectoryException
   {
-    ArrayList<PatternRDN> rdnComponents = new ArrayList<>();
-    ArrayList<Integer> doubleWildPos = new ArrayList<>();
+    List<PatternRDN> rdnComponents = new ArrayList<>();
+    List<Integer> doubleWildPos = new ArrayList<>();
 
     // A null or empty DN is acceptable.
     if (dnString == null)
     {
-      return new PatternDN(new PatternRDN[0]);
+      return new PatternDN();
     }
 
     int length = dnString.length();
     if (length == 0)
     {
-      return new PatternDN(new PatternRDN[0]);
+      return new PatternDN();
     }
 
 
@@ -311,12 +309,9 @@
       {
         // This means that the DN was completely comprised of spaces
         // and therefore should be considered the same as a null or empty DN.
-        return new PatternDN(new PatternRDN[0]);
+        return new PatternDN();
       }
-      else
-      {
-        c = dnString.charAt(pos);
-      }
+      c = dnString.charAt(pos);
     }
 
     // We know that it's not an empty DN, so we can do the real
@@ -430,14 +425,14 @@
       // RDN component and return the DN.
       if (pos >= length)
       {
-        ArrayList<ByteString> arrayList = newArrayList(ByteString.empty());
-        rdnComponents.add(new PatternRDN(name, arrayList, dnString));
+        List<ByteString> valuePattern = newArrayList(ByteString.empty());
+        rdnComponents.add(new PatternRDN(name, valuePattern, dnString));
         break;
       }
 
 
       // Parse the value for this RDN component.
-      ArrayList<ByteString> parsedValue = new ArrayList<>();
+      List<ByteString> parsedValue = new ArrayList<>();
       pos = parseValuePattern(dnString, pos, parsedValue);
 
 
@@ -518,15 +513,10 @@
             // This means that we hit the end of the value before
             // finding a '='.  This is illegal because there is no
             // attribute-value separator.
-            LocalizableMessage message =
-                ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(dnString, name);
             throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                         message);
+                ERR_ATTR_SYNTAX_DN_END_WITH_ATTR_NAME.get(dnString, name));
           }
-          else
-          {
-            c = dnString.charAt(pos);
-          }
+          c = dnString.charAt(pos);
         }
 
 
@@ -539,8 +529,7 @@
         else
         {
           LocalizableMessage message = ERR_ATTR_SYNTAX_DN_NO_EQUAL.get(dnString, name, c);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
         }
 
 
@@ -558,8 +547,8 @@
         // the RDN component and return the DN.
         if (pos >= length)
         {
-          ArrayList<ByteString> arrayList = newArrayList(ByteString.empty());
-          rdn.addValue(name, arrayList, dnString);
+          List<ByteString> valuePattern = newArrayList(ByteString.empty());
+          rdn.addValue(name, valuePattern, dnString);
           rdnComponents.add(rdn);
           break;
         }
@@ -611,51 +600,46 @@
 
     if (doubleWildPos.isEmpty())
     {
-      PatternRDN[] patterns = new PatternRDN[rdnComponents.size()];
-      patterns = rdnComponents.toArray(patterns);
-      return new PatternDN(patterns);
+      return new PatternDN(rdnComponents.toArray(new PatternRDN[rdnComponents.size()]));
     }
-    else
+
+    PatternRDN[] subInitial = null;
+    PatternRDN[] subFinal = null;
+    List<PatternRDN[]> subAnyElements = new ArrayList<>();
+
+    int i = 0;
+    int numComponents = rdnComponents.size();
+
+    int to = doubleWildPos.get(i);
+    if (to != 0)
     {
-      PatternRDN[] subInitial = null;
-      PatternRDN[] subFinal = null;
-      List<PatternRDN[]> subAnyElements = new ArrayList<>();
-
-      int i = 0;
-      int numComponents = rdnComponents.size();
-
-      int to = doubleWildPos.get(i);
-      if (to != 0)
-      {
-        // Initial piece.
-        subInitial = new PatternRDN[to];
-        subInitial = rdnComponents.subList(0, to).toArray(subInitial);
-      }
-
-      int from;
-      for (; i < doubleWildPos.size() - 1; i++)
-      {
-        from = doubleWildPos.get(i);
-        to = doubleWildPos.get(i+1);
-        PatternRDN[] subAny = new PatternRDN[to-from];
-        subAny = rdnComponents.subList(from, to).toArray(subAny);
-        subAnyElements.add(subAny);
-      }
-
-      if (i < doubleWildPos.size())
-      {
-        from = doubleWildPos.get(i);
-        if (from != numComponents)
-        {
-          // Final piece.
-          subFinal = new PatternRDN[numComponents-from];
-          subFinal = rdnComponents.subList(from, numComponents).
-               toArray(subFinal);
-        }
-      }
-
-      return new PatternDN(subInitial, subAnyElements, subFinal);
+      // Initial piece.
+      subInitial = new PatternRDN[to];
+      subInitial = rdnComponents.subList(0, to).toArray(subInitial);
     }
+
+    int from;
+    for (; i < doubleWildPos.size() - 1; i++)
+    {
+      from = doubleWildPos.get(i);
+      to = doubleWildPos.get(i + 1);
+      PatternRDN[] subAny = new PatternRDN[to - from];
+      subAny = rdnComponents.subList(from, to).toArray(subAny);
+      subAnyElements.add(subAny);
+    }
+
+    if (i < doubleWildPos.size())
+    {
+      from = doubleWildPos.get(i);
+      if (from != numComponents)
+      {
+        // Final piece.
+        subFinal = new PatternRDN[numComponents - from];
+        subFinal = rdnComponents.subList(from, numComponents).toArray(subFinal);
+      }
+    }
+
+    return new PatternDN(subInitial, subAnyElements, subFinal);
   }
 
 
@@ -697,8 +681,7 @@
           // therefore the last non-space character of the DN must
           // have been a comma. This is not acceptable.
           LocalizableMessage message = ERR_ATTR_SYNTAX_DN_END_WITH_COMMA.get(dnString);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
         }
       }
     }
@@ -731,10 +714,7 @@
         case ')':
           // None of these are allowed in an attribute name or any
           // character immediately following it.
-          LocalizableMessage message =
-              ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw illegalCharacter(dnString, pos, c);
 
 
         case '*':
@@ -743,12 +723,7 @@
           break;
 
         case '+':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          message =
-              ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw illegalCharacter(dnString, pos, c);
 
 
         case ',':
@@ -759,17 +734,12 @@
         case '-':
           // This will be allowed as long as it isn't the first
           // character in the attribute name.
-          if (attributeName.length() > 0)
+          if (attributeName.length() == 0)
           {
-            attributeName.append(c);
+            LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH.get(dnString);
+            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
           }
-          else
-          {
-            message =
-                ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_INITIAL_DASH.get(dnString);
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                         message);
-          }
+          attributeName.append(c);
           break;
 
 
@@ -783,12 +753,7 @@
 
 
         case '/':
-          // This is not allowed in an attribute name or any character
-          // immediately following it.
-          message =
-              ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw illegalCharacter(dnString, pos, c);
 
 
         case '0':
@@ -811,12 +776,7 @@
 
 
         case ':':
-          // Not allowed in an attribute name or any
-          // character immediately following it.
-          message =
-              ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw illegalCharacter(dnString, pos, c);
 
 
         case ';': // NOTE:  attribute options are not allowed in a DN.
@@ -825,12 +785,7 @@
           break;
 
         case '<':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          message =
-              ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw illegalCharacter(dnString, pos, c);
 
 
         case '=':
@@ -842,12 +797,7 @@
         case '>':
         case '?':
         case '@':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          message =
-              ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw illegalCharacter(dnString, pos, c);
 
 
         case 'A':
@@ -885,12 +835,7 @@
         case '\\':
         case ']':
         case '^':
-          // None of these are allowed in an attribute name or any
-          // character immediately following it.
-          message =
-              ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw illegalCharacter(dnString, pos, c);
 
 
         case '_':
@@ -899,12 +844,7 @@
 
 
         case '`':
-          // This is not allowed in an attribute name or any character
-          // immediately following it.
-          message =
-              ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw illegalCharacter(dnString, pos, c);
 
 
         case 'a':
@@ -941,10 +881,7 @@
         default:
           // This is not allowed in an attribute name or any character
           // immediately following it.
-          message =
-              ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(dnString, c, pos);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw illegalCharacter(dnString, pos, c);
       }
 
 
@@ -964,8 +901,7 @@
     if (attributeName.length() == 0)
     {
       LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ATTR_NO_NAME.get(dnString);
-      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                   message);
+      throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
     }
     else if (checkForOID)
     {
@@ -1045,6 +981,12 @@
     return pos;
   }
 
+  private static DirectoryException illegalCharacter(String dnString, int pos, char c)
+  {
+    return new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
+        ERR_ATTR_SYNTAX_DN_ATTR_ILLEGAL_CHAR.get(dnString, c, pos));
+  }
+
 
   /**
    * Parses the attribute value pattern from the provided DN pattern
@@ -1067,7 +1009,7 @@
    *                              provided DN string.
    */
   private static int parseValuePattern(String dnString, int pos,
-                                       ArrayList<ByteString> attributeValues)
+                                       List<ByteString> attributeValues)
           throws DirectoryException
   {
     // All leading spaces have already been stripped so we can start
@@ -1089,8 +1031,7 @@
       if (pos+2 > length)
       {
         LocalizableMessage message = ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT.get(dnString);
-        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                     message);
+        throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
       }
 
       for (int i=0; i < 2; i++)
@@ -1102,10 +1043,8 @@
         }
         else
         {
-          LocalizableMessage message =
-              ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnString, c);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          LocalizableMessage message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnString, c);
+          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
         }
       }
 
@@ -1129,18 +1068,14 @@
             }
             else
             {
-              LocalizableMessage message =
-                  ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnString, c);
-              throw new DirectoryException(
-                             ResultCode.INVALID_DN_SYNTAX, message);
+              LocalizableMessage message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnString, c);
+              throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
             }
           }
           else
           {
-            LocalizableMessage message =
-                ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT.get(dnString);
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                         message);
+            LocalizableMessage message = ERR_ATTR_SYNTAX_DN_HEX_VALUE_TOO_SHORT.get(dnString);
+            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
           }
         }
         else if (c == ' ' || c == ',' || c == ';')
@@ -1151,10 +1086,8 @@
         }
         else
         {
-          LocalizableMessage message =
-              ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnString, c);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          LocalizableMessage message = ERR_ATTR_SYNTAX_DN_INVALID_HEX_DIGIT.get(dnString, c);
+          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
         }
       }
 
@@ -1181,8 +1114,7 @@
     // should continue until the corresponding closing quotation mark.
     else if (c == '"')
     {
-      // Keep reading until we find an unescaped closing quotation
-      // mark.
+      // Keep reading until we find an unescaped closing quotation mark.
       boolean escaped = false;
       StringBuilder valueString = new StringBuilder();
       while (true)
@@ -1192,8 +1124,7 @@
           // We hit the end of the DN before the closing quote.
           // That's an error.
           LocalizableMessage message = ERR_ATTR_SYNTAX_DN_UNMATCHED_QUOTE.get(dnString);
-          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                       message);
+          throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
         }
 
         c = dnString.charAt(pos++);
@@ -1251,15 +1182,13 @@
       }
 
 
-      // Keep reading until we find an unescaped comma or plus sign or
-      // the end of the DN.
+      // Keep reading until we find an unescaped comma or plus sign or the end of the DN.
       while (true)
       {
         if (pos >= length)
         {
-          // This is the end of the DN and therefore the end of the
-          // value.  If there are any hex characters, then we need to
-          // deal with them accordingly.
+          // This is the end of the DN and therefore the end of the value.
+          // If there are any hex characters, then we need to deal with them accordingly.
           appendHexChars(dnString, valueString, hexChars);
           break;
         }
@@ -1267,44 +1196,31 @@
         c = dnString.charAt(pos++);
         if (escaped)
         {
-          // The previous character was an escape, so we'll take this
-          // one.  However, this could be a hex digit, and if that's
+          // The previous character was an escape, so we'll take this one.
+          // However, this could be a hex digit, and if that's
           // the case then the escape would actually be in front of
-          // two hex digits that should be treated as a special
-          // character.
+          // two hex digits that should be treated as a special character.
           if (isHexDigit(c))
           {
-            // It is a hexadecimal digit, so the next digit must be
-            // one too.  However, this could be just one in a series
-            // of escaped hex pairs that is used in a string
-            // containing one or more multi-byte UTF-8 characters so
-            // we can't just treat this byte in isolation.  Collect
-            // all the bytes together and make sure to take care of
-            // these hex bytes before appending anything else to the
-            // value.
+            // It is a hexadecimal digit, so the next digit must be one too.
+            // However, this could be just one in a series of escaped hex pairs
+            // that is used in a string containing one or more multi-byte UTF-8
+            // characters so we can't just treat this byte in isolation.
+            // Collect all the bytes together and make sure to take care of
+            // these hex bytes before appending anything else to the value.
             if (pos >= length)
             {
-              LocalizableMessage message =
-                  ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID.get(dnString);
-              throw new DirectoryException(
-                             ResultCode.INVALID_DN_SYNTAX, message);
+              LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID.get(dnString);
+              throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
             }
-            else
+            char c2 = dnString.charAt(pos++);
+            if (!isHexDigit(c2))
             {
-              char c2 = dnString.charAt(pos++);
-              if (isHexDigit(c2))
-              {
-                hexChars.append(c);
-                hexChars.append(c2);
-              }
-              else
-              {
-                LocalizableMessage message =
-                    ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID.get(dnString);
-                throw new DirectoryException(
-                               ResultCode.INVALID_DN_SYNTAX, message);
-              }
+              LocalizableMessage message = ERR_ATTR_SYNTAX_DN_ESCAPED_HEX_VALUE_INVALID.get(dnString);
+              throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
             }
+            hexChars.append(c);
+            hexChars.append(c2);
           }
           else
           {
@@ -1337,8 +1253,7 @@
           {
             LocalizableMessage message =
                 WARN_PATTERN_DN_CONSECUTIVE_WILDCARDS_IN_VALUE.get(dnString);
-            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX,
-                                         message);
+            throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
           }
           attributeValues.add(ByteString.valueOfUtf8(valueString));
           valueString = new StringBuilder();
@@ -1360,15 +1275,12 @@
         int lastPos = valueString.length() - 1;
         while (lastPos > 0)
         {
-          if (valueString.charAt(lastPos) == ' ')
-          {
-            valueString.delete(lastPos, lastPos+1);
-            lastPos--;
-          }
-          else
+          if (valueString.charAt(lastPos) != ' ')
           {
             break;
           }
+          valueString.delete(lastPos, lastPos + 1);
+          lastPos--;
         }
       }
 
@@ -1413,4 +1325,30 @@
           ERR_ATTR_SYNTAX_DN_ATTR_VALUE_DECODE_FAILURE.get(dnString, e));
     }
   }
+
+  @Override
+  public String toString()
+  {
+    if (this.equality != null)
+    {
+      return getClass().getSimpleName() + "(equality=" + Arrays.toString(equality) + ")";
+    }
+    StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append("(substring:");
+    if (subInitial!=null) {
+      sb.append(" subInitial=").append(Arrays.toString(subInitial));
+    }
+    sb.append(", subAnyElements=[");
+    final Iterator<PatternRDN[]> iterator = subAnyElements.iterator();
+    if (iterator.hasNext()) {
+        sb.append(Arrays.toString(iterator.next()));
+
+        while (iterator.hasNext()) {
+            sb.append(", ");
+            sb.append(Arrays.toString(iterator.next()));
+        }
+    }
+    sb.append("]");
+    sb.append(", subFinal=").append(Arrays.toString(subFinal)).append(")");
+    return sb.toString();
+  }
 }
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternRDN.java b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternRDN.java
index 2411ab9..75a1d51 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternRDN.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/PatternRDN.java
@@ -19,10 +19,9 @@
 import static org.opends.messages.AccessControlMessages.*;
 import static org.opends.server.util.CollectionUtils.*;
 
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 import java.util.TreeMap;
 
 import org.forgerock.i18n.LocalizableMessage;
@@ -30,6 +29,7 @@
 import org.forgerock.opendj.ldap.AVA;
 import org.forgerock.opendj.ldap.ByteString;
 import org.forgerock.opendj.ldap.DecodeException;
+import org.forgerock.opendj.ldap.RDN;
 import org.forgerock.opendj.ldap.ResultCode;
 import org.forgerock.opendj.ldap.schema.AttributeType;
 import org.forgerock.opendj.ldap.schema.MatchingRule;
@@ -37,7 +37,6 @@
 import org.opends.server.types.Attribute;
 import org.opends.server.types.Attributes;
 import org.opends.server.types.DirectoryException;
-import org.forgerock.opendj.ldap.RDN;
 
 /**
  * This class is used to match RDN patterns containing wildcards in either
@@ -61,10 +60,7 @@
    * a list of one element A.  The value "*A*" is represented as a list
    * of three elements "", A and "".
    */
-  private ArrayList<ArrayList<ByteString>> valuePatterns;
-  /** The number of attribute-value pairs in this RDN pattern. */
-  private int numValues;
-
+  private List<List<ByteString>> valuePatterns;
 
   /**
    * Create a new RDN pattern composed of a single attribute-value pair.
@@ -73,7 +69,7 @@
    * @param dnString The DN pattern containing the attribute-value pair.
    * @throws DirectoryException If the attribute-value pair is not valid.
    */
-  public PatternRDN(String type, ArrayList<ByteString> valuePattern, String dnString)
+  public PatternRDN(String type, List<ByteString> valuePattern, String dnString)
        throws DirectoryException
   {
     // Only Whole-Type wildcards permitted.
@@ -89,7 +85,6 @@
       hasTypeWildcard = true;
     }
 
-    numValues = 1;
     typePatterns = new String[] { type };
     valuePatterns = newArrayList(valuePattern);
   }
@@ -105,9 +100,7 @@
    *          this RDN, or <CODE>false</CODE> if it was not (e.g., it
    *          was already present).
    */
-  public boolean addValue(String type, ArrayList<ByteString> valuePattern,
-                          String dnString)
-       throws DirectoryException
+  public boolean addValue(String type, List<ByteString> valuePattern, String dnString) throws DirectoryException
   {
     // No type wildcards permitted in multi-valued patterns.
     if (hasTypeWildcard || type.contains("*"))
@@ -117,13 +110,9 @@
       throw new DirectoryException(ResultCode.INVALID_DN_SYNTAX, message);
     }
 
-    numValues++;
-
-    String[] newTypes = new String[numValues];
-    System.arraycopy(typePatterns, 0, newTypes, 0,
-                     typePatterns.length);
-    newTypes[typePatterns.length] = type;
-    typePatterns = newTypes;
+    int oldLength = typePatterns.length;
+    typePatterns = Arrays.copyOf(typePatterns, oldLength + 1);
+    typePatterns[oldLength] = type;
 
     valuePatterns.add(valuePattern);
 
@@ -140,7 +129,7 @@
    */
   public int getNumValues()
   {
-    return numValues;
+    return typePatterns.length;
   }
 
 
@@ -164,40 +153,27 @@
         return false;
       }
 
-      AVA firstAVA = rdn.getFirstAVA();
-      AttributeType thatType = firstAVA.getAttributeType();
+      AVA ava = rdn.getFirstAVA();
       if (!typePatterns[0].equals("*"))
       {
         AttributeType thisType = DirectoryServer.getAttributeType(typePatterns[0]);
-        if (thisType.isPlaceHolder() || !thisType.equals(thatType))
+        if (thisType.isPlaceHolder() || !thisType.equals(ava.getAttributeType()))
         {
           return false;
         }
       }
 
-      return matchValuePattern(valuePatterns.get(0), thatType, firstAVA.getAttributeValue());
+      return matchValuePattern(valuePatterns.get(0), ava);
     }
 
-    if (hasTypeWildcard)
-    {
-      return false;
-    }
-
-    if (numValues != rdn.size())
+    if (hasTypeWildcard || typePatterns.length != rdn.size())
     {
       return false;
     }
 
     // Sort the attribute-value pairs by attribute type.
-    TreeMap<String,ArrayList<ByteString>> patternMap = new TreeMap<>();
-    TreeMap<String, ByteString> rdnMap = new TreeMap<>();
-
-    for (AVA ava : rdn)
-    {
-      rdnMap.put(ava.getAttributeType().getNameOrOID(), ava.getAttributeValue());
-    }
-
-    for (int i = 0; i < numValues; i++)
+    TreeMap<String, List<ByteString>> patternMap = new TreeMap<>();
+    for (int i = 0; i < typePatterns.length; i++)
     {
       AttributeType type = DirectoryServer.getAttributeType(typePatterns[i]);
       if (type.isPlaceHolder())
@@ -207,18 +183,12 @@
       patternMap.put(type.getNameOrOID(), valuePatterns.get(i));
     }
 
-    Set<String> patternKeys = patternMap.keySet();
-    Set<String> rdnKeys = rdnMap.keySet();
-    Iterator<String> patternKeyIter = patternKeys.iterator();
-    for (String rdnKey : rdnKeys)
+    Iterator<String> patternKeyIter = patternMap.keySet().iterator();
+    for (AVA ava : rdn)
     {
-      if (!rdnKey.equals(patternKeyIter.next()))
-      {
-        return false;
-      }
-
-      AttributeType rdnAttrType = DirectoryServer.getAttributeType(rdnKey);
-      if (!matchValuePattern(patternMap.get(rdnKey), rdnAttrType, rdnMap.get(rdnKey)))
+      String rdnKey = ava.getAttributeType().getNameOrOID();
+      if (!rdnKey.equals(patternKeyIter.next())
+          || !matchValuePattern(patternMap.get(rdnKey), ava))
       {
         return false;
       }
@@ -227,7 +197,6 @@
     return true;
   }
 
-
   /**
    * Determine whether a value pattern matches a given attribute-value pair.
    * @param pattern The value pattern where each element of the list is a
@@ -236,15 +205,15 @@
    * @param value The value of the attribute-value pair.
    * @return true if the value pattern matches the attribute-value pair.
    */
-  private boolean matchValuePattern(List<ByteString> pattern,
-                                    AttributeType type,
-                                    ByteString value)
+  private boolean matchValuePattern(List<ByteString> pattern, AVA ava)
   {
     if (pattern == null)
     {
       return true;
     }
 
+    final AttributeType type = ava.getAttributeType();
+    ByteString value = ava.getAttributeValue();
     try
     {
       if (pattern.size() == 1)
@@ -288,4 +257,24 @@
     }
   }
 
+  @Override
+  public String toString()
+  {
+    StringBuilder sb = new StringBuilder(getClass().getSimpleName()).append("(");
+    for (int i = 0; i < typePatterns.length; i++)
+    {
+      sb.append(typePatterns[i]).append("=");
+      List<ByteString> patterns = valuePatterns.get(i);
+      if (patterns.size() == 1)
+      {
+        sb.append(patterns.get(0));
+      }
+      else
+      {
+        sb.append(patterns);
+      }
+    }
+    sb.append(")");
+    return sb.toString();
+  }
 }

--
Gitblit v1.10.0