From c73429505ef9b16e4c343c49e240f21d78fa34ca Mon Sep 17 00:00:00 2001
From: ludovicp <ludovicp@localhost>
Date: Fri, 30 Jul 2010 11:59:52 +0000
Subject: [PATCH] Extend RFC3672 subtreeSpecification to allow OpenDS specific RelativeSubtreeSpec and AbsoluteSubtreeSpec.

---
 opendj-sdk/opends/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java                    |  320 ++++++++++++++++++++++++++
 opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecification.java                             |   26 ++
 opendj-sdk/opends/src/server/org/opends/server/core/AbsoluteSubtreeSpecification.java                    |   17 
 opendj-sdk/opends/src/server/org/opends/server/types/SubEntry.java                                       |   65 +++++
 opendj-sdk/opends/resource/config/config.ldif                                                            |   16 -
 opendj-sdk/opends/src/server/org/opends/server/core/RelativeSubtreeSpecification.java                    |   17 
 opendj-sdk/opends/src/server/org/opends/server/core/SubentryManager.java                                 |   11 
 opendj-sdk/opends/src/messages/messages/schema.properties                                                |    6 
 opendj-sdk/opends/src/server/org/opends/server/core/SimpleSubtreeSpecification.java                      |   19 -
 opendj-sdk/opends/src/server/org/opends/server/schema/SchemaConstants.java                               |   96 +++++---
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java |   82 ++++++
 11 files changed, 584 insertions(+), 91 deletions(-)

diff --git a/opendj-sdk/opends/resource/config/config.ldif b/opendj-sdk/opends/resource/config/config.ldif
index 7e0f22d..f66374b 100644
--- a/opendj-sdk/opends/resource/config/config.ldif
+++ b/opendj-sdk/opends/resource/config/config.ldif
@@ -1982,13 +1982,6 @@
 objectClass: ds-cfg-branch
 cn: Syntaxes
 
-dn: cn=Absolute Subtree Specification,cn=Syntaxes,cn=config
-objectClass: top
-objectClass: ds-cfg-attribute-syntax
-cn: Absolute Subtree Specification
-ds-cfg-java-class: org.opends.server.schema.AbsoluteSubtreeSpecificationSyntax
-ds-cfg-enabled: true
-
 dn: cn=Sun-defined Access Control Information,cn=Syntaxes,cn=config
 objectClass: top
 objectClass: ds-cfg-attribute-syntax
@@ -2252,13 +2245,6 @@
 ds-cfg-java-class: org.opends.server.schema.ProtocolInformationSyntax
 ds-cfg-enabled: true
 
-dn: cn=Relative Subtree Specification,cn=Syntaxes,cn=config
-objectClass: top
-objectClass: ds-cfg-attribute-syntax
-cn: Relative Subtree Specification
-ds-cfg-java-class: org.opends.server.schema.RelativeSubtreeSpecificationSyntax
-ds-cfg-enabled: true
-
 dn: cn=Substring Assertion,cn=Syntaxes,cn=config
 objectClass: top
 objectClass: ds-cfg-attribute-syntax
@@ -2270,7 +2256,7 @@
 objectClass: top
 objectClass: ds-cfg-attribute-syntax
 cn: Subtree Specification
-ds-cfg-java-class: org.opends.server.schema.RFC3672SubtreeSpecificationSyntax
+ds-cfg-java-class: org.opends.server.schema.SubtreeSpecificationSyntax
 ds-cfg-enabled: true
 
 dn: cn=Supported Algorithm,cn=Syntaxes,cn=config
diff --git a/opendj-sdk/opends/src/messages/messages/schema.properties b/opendj-sdk/opends/src/messages/messages/schema.properties
index 15c5608..ac0c7c2 100644
--- a/opendj-sdk/opends/src/messages/messages/schema.properties
+++ b/opendj-sdk/opends/src/messages/messages/schema.properties
@@ -20,7 +20,7 @@
 #
 # CDDL HEADER END
 #
-#      Copyright 2006-2009 Sun Microsystems, Inc.
+#      Copyright 2006-2010 Sun Microsystems, Inc.
 
 
 
@@ -881,6 +881,8 @@
 SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_INVALID_SUPERIOR_USAGE_268=The definition \
  for attribute type %s is invalid because its attribute usage %s is not the \
  same as the usage for its superior type %s
+MILD_ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID_269=The provided \
+ value "%s" could not be parsed as a valid subtree specification
 SEVERE_WARN_ATTR_SYNTAX_ATTRTYPE_NONCOLLECTIVE_FROM_COLLECTIVE_270=The \
  definition for attribute type %s is invalid because it is not defined as a \
  collective type but the superior type %s is collective
@@ -1023,4 +1025,4 @@
   conflicting  value "%d" for m(Minute) specification
 MILD_WARN_ATTR_DUPLICATE_HOUR_ASSERTION_FORMAT_316=The provided \
   value "%s" could not be parsed as a valid assertion value because there is  \
-  conflicting  value "%d" for h(Hour) specification
\ No newline at end of file
+  conflicting  value "%d" for h(Hour) specification
diff --git a/opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecification.java b/opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecification.java
index d89aeff..ffebe35 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecification.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/api/SubtreeSpecification.java
@@ -22,12 +22,13 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
  */
 package org.opends.server.api;
 
 
 
+import org.opends.server.types.DN;
 import org.opends.server.types.Entry;
 
 
@@ -53,6 +54,16 @@
 
 
   /**
+   * Get the absolute base DN of the subtree specification.
+   *
+   * @return Returns the absolute base DN of the subtree
+   *         specification.
+   */
+  public abstract DN getBaseDN();
+
+
+
+  /**
    * Determine if an entry is within the scope of the subtree
    * specification.
    *
@@ -66,6 +77,19 @@
 
 
   /**
+   * Determine if the specified DN is within the scope of the subtree
+   * specification.
+   *
+   * @param dn  The distinguished name.
+   * @return Returns <code>true</code> if the DN is within the scope
+   *         of the subtree specification, or <code>false</code>
+   *         otherwise.
+   */
+  public abstract boolean isDNWithinScope(DN dn);
+
+
+
+  /**
    * Indicates whether the provided object is logically equal to this
    * subtree specification object.
    *
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/AbsoluteSubtreeSpecification.java b/opendj-sdk/opends/src/server/org/opends/server/core/AbsoluteSubtreeSpecification.java
index e50cb64..1e330c2 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/AbsoluteSubtreeSpecification.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/AbsoluteSubtreeSpecification.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
  */
 package org.opends.server.core;
 import org.opends.messages.Message;
@@ -278,13 +278,16 @@
   public boolean isWithinScope(Entry entry) {
 
     if (isDNWithinScope(entry.getDN())) {
-      try {
-        return filter.matchesEntry(entry);
-      } catch (DirectoryException e) {
-        // TODO: need to decide what to do with the exception here. It's
-        // probably safe to ignore, but we could log it perhaps.
-        return false;
+      if (filter != null) {
+        try {
+          return filter.matchesEntry(entry);
+        } catch (DirectoryException e) {
+          // TODO: need to decide what to do with the exception here. It's
+          // probably safe to ignore, but we could log it perhaps.
+          return false;
+        }
       }
+      return true;
     } else {
       return false;
     }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/RelativeSubtreeSpecification.java b/opendj-sdk/opends/src/server/org/opends/server/core/RelativeSubtreeSpecification.java
index 95e1319..125c65e 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/RelativeSubtreeSpecification.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/RelativeSubtreeSpecification.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
  */
 package org.opends.server.core;
 import org.opends.messages.Message;
@@ -287,13 +287,16 @@
   public boolean isWithinScope(Entry entry) {
 
     if (isDNWithinScope(entry.getDN())) {
-      try {
-        return filter.matchesEntry(entry);
-      } catch (DirectoryException e) {
-        // TODO: need to decide what to do with the exception here. It's
-        // probably safe to ignore, but we could log it perhaps.
-        return false;
+      if (filter != null) {
+        try {
+          return filter.matchesEntry(entry);
+        } catch (DirectoryException e) {
+          // TODO: need to decide what to do with the exception here. It's
+          // probably safe to ignore, but we could log it perhaps.
+          return false;
+        }
       }
+      return true;
     } else {
       return false;
     }
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SimpleSubtreeSpecification.java b/opendj-sdk/opends/src/server/org/opends/server/core/SimpleSubtreeSpecification.java
index 4cea53b..d303493 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SimpleSubtreeSpecification.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/SimpleSubtreeSpecification.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
  */
 package org.opends.server.core;
 
@@ -404,16 +404,9 @@
   }
 
   /**
-   * Determine if the specified DN is within the scope of the subtree
-   * specification.
-   *
-   * @param dn
-   *          The distringuished name.
-   * @return Returns <code>true</code> if the DN is within the scope
-   *         of the subtree specification, or <code>false</code>
-   *         otherwise.
+   * {@inheritDoc}
    */
-  protected final boolean isDNWithinScope(DN dn) {
+  public final boolean isDNWithinScope(DN dn) {
 
     if (!dn.isDescendantOf(baseDN)) {
       return false;
@@ -460,11 +453,9 @@
   }
 
   /**
-   * Get the absolute base DN of the subtree specification.
-   *
-   * @return Returns the absolute base DN of the subtree specification.
+   * {@inheritDoc}
    */
-  protected final DN getBaseDN() {
+  public final DN getBaseDN() {
     return baseDN;
   }
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/core/SubentryManager.java b/opendj-sdk/opends/src/server/org/opends/server/core/SubentryManager.java
index b95f626..385c9a0 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/core/SubentryManager.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/core/SubentryManager.java
@@ -28,6 +28,7 @@
 
 
 
+import org.opends.server.api.SubtreeSpecification;
 import java.util.*;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
@@ -206,7 +207,7 @@
   private void addSubEntry(Entry entry) throws DirectoryException
   {
     SubEntry subEntry = new SubEntry(entry);
-    RFC3672SubtreeSpecification subSpec =
+    SubtreeSpecification subSpec =
             subEntry.getSubTreeSpecification();
     DN subDN = subSpec.getBaseDN();
     List<SubEntry> subList = null;
@@ -488,7 +489,7 @@
         {
           for (SubEntry subEntry : subList)
           {
-            RFC3672SubtreeSpecification subSpec =
+            SubtreeSpecification subSpec =
                     subEntry.getSubTreeSpecification();
             if (subSpec.isDNWithinScope(dn))
             {
@@ -534,7 +535,7 @@
         {
           for (SubEntry subEntry : subList)
           {
-            RFC3672SubtreeSpecification subSpec =
+            SubtreeSpecification subSpec =
                     subEntry.getSubTreeSpecification();
             if (subSpec.isWithinScope(entry))
             {
@@ -580,7 +581,7 @@
         {
           for (SubEntry subEntry : subList)
           {
-            RFC3672SubtreeSpecification subSpec =
+            SubtreeSpecification subSpec =
                     subEntry.getSubTreeSpecification();
             if (subSpec.isDNWithinScope(dn))
             {
@@ -626,7 +627,7 @@
         {
           for (SubEntry subEntry : subList)
           {
-            RFC3672SubtreeSpecification subSpec =
+            SubtreeSpecification subSpec =
                     subEntry.getSubTreeSpecification();
             if (subSpec.isWithinScope(entry))
             {
diff --git a/opendj-sdk/opends/src/server/org/opends/server/schema/SchemaConstants.java b/opendj-sdk/opends/src/server/org/opends/server/schema/SchemaConstants.java
index 118ac9a..727952f 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/schema/SchemaConstants.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/schema/SchemaConstants.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2009 Sun Microsystems, Inc.
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
  */
 package org.opends.server.schema;
 
@@ -801,30 +801,6 @@
 
 
 
-  /**
-   * The OID for the absolute subtree specification attribute syntax.
-   */
-  public static final String SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_OID =
-       OID_OPENDS_SERVER_ATTRIBUTE_SYNTAX_BASE + ".3";
-
-
-
-  /**
-   * The description for the absolute subtree specification attribute syntax.
-   */
-  public static final String SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_DESCRIPTION =
-    "Absolute Subtree Specification";
-
-
-
-  /**
-   * The name for the absolute subtree specification attribute syntax.
-   */
-  public static final String SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_NAME =
-    "ds-absolute-subtree-specification";
-
-
-
    /**
     * The OID for the aci attribute syntax.
     */
@@ -1668,26 +1644,26 @@
 
 
   /**
-   * The OID for the relative subtree specification attribute syntax.
+   * The OID for the subtree specification attribute syntax.
    */
-  public static final String SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_OID =
-       OID_OPENDS_SERVER_ATTRIBUTE_SYNTAX_BASE + ".2";
+  public static final String SYNTAX_SUBTREE_SPECIFICATION_OID =
+    "1.3.6.1.4.1.1466.115.121.1.45";
 
 
 
   /**
-   * The description for the relative subtree specification attribute syntax.
+   * The description for the subtree specification attribute syntax.
    */
-  public static final String SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_DESCRIPTION =
-    "Relative Subtree Specification";
+  public static final String SYNTAX_SUBTREE_SPECIFICATION_DESCRIPTION =
+    "Subtree Specification";
 
 
 
   /**
-   * The name for the relative subtree specification attribute syntax.
+   * The name for the subtree specification attribute syntax.
    */
-  public static final String SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_NAME =
-    "ds-relative-subtree-specification";
+  public static final String SYNTAX_SUBTREE_SPECIFICATION_NAME =
+    "SubtreeSpecification";
 
 
 
@@ -1695,7 +1671,7 @@
    * The OID for the RFC3672 subtree specification attribute syntax.
    */
   public static final String SYNTAX_RFC3672_SUBTREE_SPECIFICATION_OID =
-    "1.3.6.1.4.1.1466.115.121.1.45";
+    SYNTAX_SUBTREE_SPECIFICATION_OID;
 
 
 
@@ -1711,7 +1687,55 @@
    * The name for the RFC3672 subtree specification attribute syntax.
    */
   public static final String SYNTAX_RFC3672_SUBTREE_SPECIFICATION_NAME =
-    "SubtreeSpecification";
+    SYNTAX_SUBTREE_SPECIFICATION_NAME;
+
+
+
+  /**
+   * The OID for the absolute subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_OID =
+       SYNTAX_SUBTREE_SPECIFICATION_OID;
+
+
+
+  /**
+   * The description for the absolute subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_DESCRIPTION =
+    "Absolute Subtree Specification";
+
+
+
+  /**
+   * The name for the absolute subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_ABSOLUTE_SUBTREE_SPECIFICATION_NAME =
+    SYNTAX_SUBTREE_SPECIFICATION_NAME;
+
+
+
+  /**
+   * The OID for the relative subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_OID =
+       SYNTAX_SUBTREE_SPECIFICATION_OID;
+
+
+
+  /**
+   * The description for the relative subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_DESCRIPTION =
+    "Relative Subtree Specification";
+
+
+
+  /**
+   * The name for the relative subtree specification attribute syntax.
+   */
+  public static final String SYNTAX_RELATIVE_SUBTREE_SPECIFICATION_NAME =
+    SYNTAX_SUBTREE_SPECIFICATION_NAME;
 
 
 
diff --git a/opendj-sdk/opends/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java b/opendj-sdk/opends/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java
new file mode 100644
index 0000000..7e4b494
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/schema/SubtreeSpecificationSyntax.java
@@ -0,0 +1,320 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2006-2010 Sun Microsystems, Inc.
+ */
+package org.opends.server.schema;
+
+import org.opends.messages.Message;
+import static org.opends.server.loggers.debug.DebugLogger.*;
+import org.opends.server.loggers.debug.DebugTracer;
+import static org.opends.server.loggers.ErrorLogger.logError;
+import static org.opends.messages.SchemaMessages.*;
+import org.opends.messages.MessageBuilder;
+import static org.opends.server.schema.SchemaConstants.*;
+
+import org.opends.server.admin.std.server.AttributeSyntaxCfg;
+import org.opends.server.api.ApproximateMatchingRule;
+import org.opends.server.api.AttributeSyntax;
+import org.opends.server.api.AttributeValueDecoder;
+import org.opends.server.api.EqualityMatchingRule;
+import org.opends.server.api.OrderingMatchingRule;
+import org.opends.server.api.SubstringMatchingRule;
+import org.opends.server.api.SubtreeSpecification;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.AbsoluteSubtreeSpecification;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.core.RFC3672SubtreeSpecification;
+import org.opends.server.core.RelativeSubtreeSpecification;
+import org.opends.server.types.*;
+
+
+/**
+ * This class defines the subtree specification attribute syntax,
+ * which is used to specify the scope of sub-entries (RFC 3672).
+ */
+public final class SubtreeSpecificationSyntax
+       extends AttributeSyntax<AttributeSyntaxCfg>
+{
+  /**
+   * The tracer object for the debug logger.
+   */
+  private static final DebugTracer TRACER = getTracer();
+
+  // The default equality matching rule for this syntax.
+  private EqualityMatchingRule defaultEqualityMatchingRule;
+
+  // The default ordering matching rule for this syntax.
+  private OrderingMatchingRule defaultOrderingMatchingRule;
+
+  // The default substring matching rule for this syntax.
+  private SubstringMatchingRule defaultSubstringMatchingRule;
+
+  /**
+   * Create a new attribute value decoder with the specified root DN.
+   *
+   * @param rootDN
+   *          The root DN for all decoded subtree specifications.
+   * @return The attribute value decoder.
+   */
+  public static AttributeValueDecoder<SubtreeSpecification>
+      createAttributeValueDecoder(DN rootDN) {
+    return new Decoder(rootDN);
+  }
+
+  /**
+   * Internal class implementing an attribute value decoder.
+   */
+  private static class Decoder implements
+      AttributeValueDecoder<SubtreeSpecification> {
+
+    // The root DN for all decoded relative subtree specifications.
+    private DN rootDN;
+
+    /**
+     * Create a new decoder with the specified root DN.
+     *
+     * @param rootDN
+     *          The root DN for all decoded relative subtree
+     *          specifications.
+     */
+    public Decoder(DN rootDN) {
+      this.rootDN = rootDN;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public SubtreeSpecification decode(AttributeValue value)
+        throws DirectoryException {
+
+      // Try parsing the value with every subtree spec known.
+      SubtreeSpecification subTreeSpec = null;
+      String specString = value.toString();
+      try {
+        subTreeSpec = RFC3672SubtreeSpecification.valueOf(
+                rootDN, specString);
+        return subTreeSpec;
+      } catch (DirectoryException de) {}
+      try {
+        subTreeSpec = RelativeSubtreeSpecification.valueOf(
+                rootDN, specString);
+        return subTreeSpec;
+      } catch (DirectoryException de) {}
+      try {
+        subTreeSpec = AbsoluteSubtreeSpecification.valueOf(
+                specString);
+        return subTreeSpec;
+      } catch (DirectoryException de) {}
+
+      if (subTreeSpec == null) {
+        Message message =
+          ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(
+            specString);
+        throw new DirectoryException(
+                ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
+      }
+
+      return subTreeSpec;
+    }
+  }
+
+  /**
+   * Creates a new instance of this syntax. Note that the only thing
+   * that should be done here is to invoke the default constructor for
+   * the superclass. All initialization should be performed in the
+   * <CODE>initializeSyntax</CODE> method.
+   */
+  public SubtreeSpecificationSyntax() {
+    // No implementation required.
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void initializeSyntax(AttributeSyntaxCfg configuration)
+      throws ConfigException {
+
+    defaultEqualityMatchingRule = DirectoryServer
+        .getEqualityMatchingRule(EMR_OCTET_STRING_OID);
+    if (defaultEqualityMatchingRule == null) {
+      logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get(
+          EMR_OCTET_STRING_OID, SYNTAX_SUBTREE_SPECIFICATION_NAME));
+    }
+
+    defaultOrderingMatchingRule = DirectoryServer
+        .getOrderingMatchingRule(OMR_OCTET_STRING_OID);
+    if (defaultOrderingMatchingRule == null) {
+      logError(ERR_ATTR_SYNTAX_UNKNOWN_ORDERING_MATCHING_RULE.get(
+          OMR_OCTET_STRING_OID, SYNTAX_SUBTREE_SPECIFICATION_NAME));
+    }
+
+    defaultSubstringMatchingRule = DirectoryServer
+        .getSubstringMatchingRule(SMR_OCTET_STRING_OID);
+    if (defaultSubstringMatchingRule == null) {
+      logError(ERR_ATTR_SYNTAX_UNKNOWN_SUBSTRING_MATCHING_RULE.get(
+          SMR_OCTET_STRING_OID, SYNTAX_SUBTREE_SPECIFICATION_NAME));
+    }
+  }
+
+  /**
+   * Retrieves the common name for this attribute syntax.
+   *
+   * @return The common name for this attribute syntax.
+   */
+  public String getSyntaxName() {
+
+    return SYNTAX_SUBTREE_SPECIFICATION_NAME;
+  }
+
+  /**
+   * Retrieves the OID for this attribute syntax.
+   *
+   * @return The OID for this attribute syntax.
+   */
+  public String getOID() {
+
+    return SYNTAX_SUBTREE_SPECIFICATION_OID;
+  }
+
+  /**
+   * Retrieves a description for this attribute syntax.
+   *
+   * @return A description for this attribute syntax.
+   */
+  public String getDescription() {
+
+    return SYNTAX_SUBTREE_SPECIFICATION_DESCRIPTION;
+  }
+
+  /**
+   * Retrieves the default equality matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default equality matching rule that will be used for
+   *         attributes with this syntax, or <CODE>null</CODE> if
+   *         equality matches will not be allowed for this type by
+   *         default.
+   */
+  public EqualityMatchingRule getEqualityMatchingRule() {
+
+    return defaultEqualityMatchingRule;
+  }
+
+  /**
+   * Retrieves the default ordering matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default ordering matching rule that will be used for
+   *         attributes with this syntax, or <CODE>null</CODE> if
+   *         ordering matches will not be allowed for this type by
+   *         default.
+   */
+  public OrderingMatchingRule getOrderingMatchingRule() {
+
+    return defaultOrderingMatchingRule;
+  }
+
+  /**
+   * Retrieves the default substring matching rule that will be used for
+   * attributes with this syntax.
+   *
+   * @return The default substring matching rule that will be used for
+   *         attributes with this syntax, or <CODE>null</CODE> if
+   *         substring matches will not be allowed for this type by
+   *         default.
+   */
+  public SubstringMatchingRule getSubstringMatchingRule() {
+
+    return defaultSubstringMatchingRule;
+  }
+
+  /**
+   * Retrieves the default approximate matching rule that will be used
+   * for attributes with this syntax.
+   *
+   * @return The default approximate matching rule that will be used for
+   *         attributes with this syntax, or <CODE>null</CODE> if
+   *         approximate matches will not be allowed for this type by
+   *         default.
+   */
+  public ApproximateMatchingRule getApproximateMatchingRule() {
+
+    // There is no approximate matching rule by default.
+    return null;
+  }
+
+  /**
+   * Indicates whether the provided value is acceptable for use in an
+   * attribute with this syntax. If it is not, then the reason may be
+   * appended to the provided buffer.
+   *
+   * @param value
+   *          The value for which to make the determination.
+   * @param invalidReason
+   *          The buffer to which the invalid reason should be appended.
+   * @return <CODE>true</CODE> if the provided value is acceptable for
+   *         use with this syntax, or <CODE>false</CODE> if not.
+   */
+  public boolean valueIsAcceptable(ByteSequence value,
+                                   MessageBuilder invalidReason) {
+
+    // Use the subtree specification code to make this determination.
+    // Try parsing the value with every subtree spec known.
+    SubtreeSpecification subTreeSpec = null;
+    String specString = value.toString();
+    try {
+      subTreeSpec = RFC3672SubtreeSpecification.valueOf(
+              DN.nullDN(), specString);
+      return true;
+    } catch (DirectoryException de) {}
+    try {
+      subTreeSpec = RelativeSubtreeSpecification.valueOf(
+              DN.nullDN(), specString);
+      return true;
+    } catch (DirectoryException de) {}
+    try {
+      subTreeSpec = AbsoluteSubtreeSpecification.valueOf(
+              specString);
+      return true;
+    } catch (DirectoryException de) {}
+
+    if (subTreeSpec == null) {
+      Message message =
+        ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(
+          specString);
+      invalidReason.append(message);
+    }
+
+    return false;
+  }
+
+ /**
+   * {@inheritDoc}
+   */
+  public boolean isBinary()
+  {
+    return false;
+  }
+}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/types/SubEntry.java b/opendj-sdk/opends/src/server/org/opends/server/types/SubEntry.java
index 3001ec6..8cbfe5a 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/types/SubEntry.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/types/SubEntry.java
@@ -27,6 +27,10 @@
 
 package org.opends.server.types;
 
+import org.opends.messages.Message;
+import org.opends.server.core.AbsoluteSubtreeSpecification;
+import org.opends.server.core.RelativeSubtreeSpecification;
+import org.opends.server.api.SubtreeSpecification;
 import java.util.List;
 import java.util.ArrayList;
 import java.util.Set;
@@ -37,6 +41,7 @@
 
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.loggers.debug.DebugLogger.*;
+import static org.opends.messages.SchemaMessages.*;
 
 /**
  * This class represents RFC 3672 subentries and RFC 3671
@@ -113,7 +118,7 @@
   private Entry entry;
 
   // Subtree specification.
-  private RFC3672SubtreeSpecification subTreeSpec;
+  private SubtreeSpecification subTreeSpec;
 
   // Collective subentry flag.
   private boolean isCollective = false;
@@ -138,6 +143,8 @@
 
     // Process subtree specification.
     this.subTreeSpec = null;
+    String specString = null;
+    boolean isValidSpec = true;
     AttributeType specAttrType = DirectoryServer.getAttributeType(
             ATTR_SUBTREE_SPEC_LC, true);
     List<Attribute> specAttrList =
@@ -148,8 +155,46 @@
       {
         for (AttributeValue value : attr)
         {
-          this.subTreeSpec = RFC3672SubtreeSpecification.valueOf(
-                  entry.getDN().getParent(), value.toString());
+          // Try parsing the value with every subtree spec known.
+          specString = value.toString();
+          try
+          {
+            this.subTreeSpec = RFC3672SubtreeSpecification.valueOf(
+                    entry.getDN().getParent(), specString);
+            isValidSpec = true;
+          }
+          catch (DirectoryException de)
+          {
+            isValidSpec = false;
+          }
+          if (this.subTreeSpec != null)
+          {
+            break;
+          }
+          try
+          {
+            this.subTreeSpec = RelativeSubtreeSpecification.valueOf(
+                    entry.getDN().getParent(), specString);
+            isValidSpec = true;
+          }
+          catch (DirectoryException de)
+          {
+            isValidSpec = false;
+          }
+          if (this.subTreeSpec != null)
+          {
+            break;
+          }
+          try
+          {
+            this.subTreeSpec = AbsoluteSubtreeSpecification.valueOf(
+                    specString);
+            isValidSpec = true;
+          }
+          catch (DirectoryException de)
+          {
+            isValidSpec = false;
+          }
           break;
         }
         if (this.subTreeSpec != null)
@@ -158,6 +203,18 @@
         }
       }
     }
+
+    // Check that the subtree spec is flaged as valid. If it is not
+    // that means all parsers have failed and it is ivalid syntax.
+    if (!isValidSpec)
+    {
+      Message message =
+        ERR_ATTR_SYNTAX_SUBTREE_SPECIFICATION_INVALID.get(
+          specString);
+      throw new DirectoryException(
+              ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
+    }
+
     // Subentry has to to have a subtree specification.
     if (this.subTreeSpec == null)
     {
@@ -258,7 +315,7 @@
    * Getter for subentry subtree specification.
    * @return subtree specification for this subentry.
    */
-  public RFC3672SubtreeSpecification getSubTreeSpecification()
+  public SubtreeSpecification getSubTreeSpecification()
   {
     return this.subTreeSpec;
   }
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java
index e357678..84f1c4c 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/core/SubentryManagerTestCase.java
@@ -27,6 +27,7 @@
 
 package org.opends.server.core;
 
+import org.opends.server.api.SubtreeSpecification;
 import java.util.ArrayList;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -449,6 +450,87 @@
           DN.decode("uid=rogasawara," + OLDBASE + "," + SUFFIX)).isEmpty());
   }
 
+  @Test
+  public void testExtendedSubtreeSpecification() throws Exception
+  {
+    // This one should have been added during test setup so just
+    // do a quick check here to make sure it is available there.
+    assertNotNull(DirectoryServer.getEntry(ldapSubentry.getDN()));
+
+    // RFC3672 Spec test subentry.
+    List<SubEntry> rfc3672SubList =
+            DirectoryServer.getSubentryManager().getSubentries();
+    for (SubEntry subentry : rfc3672SubList)
+    {
+      if (subentry.getDN().equals(ldapSubentry.getDN()))
+      {
+        SubtreeSpecification spec = subentry.getSubTreeSpecification();
+        assertTrue(spec instanceof RFC3672SubtreeSpecification);
+      }
+    }
+
+    InternalClientConnection connection =
+         InternalClientConnection.getRootConnection();
+
+    // Add Relative Spec test subentry.
+    Entry relativeSubentry = TestCaseUtils.makeEntry(
+         "dn: cn=Relative Subentry," + SUFFIX,
+         "objectClass: top",
+         "objectclass: subentry",
+         "subtreeSpecification: {relativeBase \"ou=Test SubEntry Manager\"}",
+         "cn: Subentry");
+    AddOperation addOperation =
+         connection.processAdd(relativeSubentry.getDN(),
+                               relativeSubentry.getObjectClasses(),
+                               relativeSubentry.getUserAttributes(),
+                               relativeSubentry.getOperationalAttributes());
+    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+    assertNotNull(DirectoryServer.getEntry(relativeSubentry.getDN()));
+
+    List<SubEntry> relativeSubList =
+            DirectoryServer.getSubentryManager().getSubentries();
+    for (SubEntry subentry : relativeSubList)
+    {
+      if (subentry.getDN().equals(relativeSubentry.getDN()))
+      {
+        SubtreeSpecification spec = subentry.getSubTreeSpecification();
+        assertTrue(spec instanceof RelativeSubtreeSpecification);
+      }
+    }
+
+    // Remove Relative Spec test subentry.
+    TestCaseUtils.deleteEntry(relativeSubentry.getDN());
+
+    // Add Absolute Spec test subentry.
+    Entry absoluteSubentry = TestCaseUtils.makeEntry(
+         "dn: cn=Absolute Subentry," + SUFFIX,
+         "objectClass: top",
+         "objectclass: subentry",
+         "subtreeSpecification: {absoluteBase \"ou=Test SubEntry Manager\"}",
+         "cn: Subentry");
+    addOperation =
+         connection.processAdd(absoluteSubentry.getDN(),
+                               absoluteSubentry.getObjectClasses(),
+                               absoluteSubentry.getUserAttributes(),
+                               absoluteSubentry.getOperationalAttributes());
+    assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
+    assertNotNull(DirectoryServer.getEntry(absoluteSubentry.getDN()));
+
+    List<SubEntry> absoluteSubList =
+            DirectoryServer.getSubentryManager().getSubentries();
+    for (SubEntry subentry : absoluteSubList)
+    {
+      if (subentry.getDN().equals(absoluteSubentry.getDN()))
+      {
+        SubtreeSpecification spec = subentry.getSubTreeSpecification();
+        assertTrue(spec instanceof AbsoluteSubtreeSpecification);
+      }
+    }
+
+    // Remove Absolute Spec test subentry.
+    TestCaseUtils.deleteEntry(absoluteSubentry.getDN());
+  }
+
   private void addTestEntries() throws Exception
   {
     InternalClientConnection connection =

--
Gitblit v1.10.0