mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

neil_a_wilson
19.57.2007 dd0aa3d6f2295686b10d2e11c972687a225c103f
Update the schema backend so that the creatorsName, createTimestamp,
modifiersName, and modifyTimestamp attributes are included in the subschema
subentry as recommended in RFC 4512 section 4.2. The create timestamp will be
set to the oldest modification time of all the schema configuration files. The
modify timestamp will be initially set to the youngest modification time of all
the schema configuration files, but if the schema is updated with the server
online then the modifiersName and modifyTimestamp will be updated accordingly.

OpenDS Issue Number: 1157
4 files modified
285 ■■■■■ changed files
opends/src/server/org/opends/server/backends/SchemaBackend.java 101 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/SchemaConfigManager.java 35 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Schema.java 84 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java 65 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -74,6 +74,7 @@
import org.opends.server.schema.AttributeTypeSyntax;
import org.opends.server.schema.DITContentRuleSyntax;
import org.opends.server.schema.DITStructureRuleSyntax;
import org.opends.server.schema.GeneralizedTimeSyntax;
import org.opends.server.schema.MatchingRuleUseSyntax;
import org.opends.server.schema.NameFormSyntax;
import org.opends.server.schema.ObjectClassSyntax;
@@ -148,6 +149,12 @@
  // types.
  private AttributeType attributeTypesType;
  // The attribute type that will be used to hold the schema creation timestamp.
  private AttributeType createTimestampType;
  // The attribute type that will be used to hold the schema creator's name.
  private AttributeType creatorsNameType;
  // The attribute type that will be used to include the defined DIT content
  // rules.
  private AttributeType ditContentRulesType;
@@ -167,25 +174,44 @@
  // uses.
  private AttributeType matchingRuleUsesType;
  // The attribute that will be used to hold the schema modifier's name.
  private AttributeType modifiersNameType;
  // The attribute type that will be used to hold the schema modification
  // timestamp.
  private AttributeType modifyTimestampType;
  // The attribute type that will be used to include the defined object classes.
  private AttributeType objectClassesType;
  // The attribute type that will be used to include the defined name forms.
  private AttributeType nameFormsType;
  // The value containing DN of the user we'll say created the configuration.
  private AttributeValue creatorsName;
  // The value containing the DN of the last user to modify the configuration.
  private AttributeValue modifiersName;
  // The timestamp that will be used for the schema creation time.
  private AttributeValue createTimestamp;
  // The timestamp that will be used for the latest schema modification time.
  private AttributeValue modifyTimestamp;
  // Indicates whether the attributes of the schema entry should always be
  // treated as user attributes even if they are defined as operational.
  private boolean showAllAttributes;
  // The set of objectclasses that will be used in the schema entry.
  private HashMap<ObjectClass,String> schemaObjectClasses;
  // The DN of the configuration entry for this backend.
  private DN configEntryDN;
  // The set of base DNs for this backend.
  private DN[] baseDNs;
  // The set of objectclasses that will be used in the schema entry.
  private HashMap<ObjectClass,String> schemaObjectClasses;
  // The set of supported controls for this backend.
  private HashSet<String> supportedControls;
@@ -264,6 +290,29 @@
    nameFormsType = DirectoryServer.getAttributeType(ATTR_NAME_FORMS_LC, true);
    // Initialize the lastmod attributes.
    creatorsNameType =
         DirectoryServer.getAttributeType(OP_ATTR_CREATORS_NAME_LC, true);
    createTimestampType =
         DirectoryServer.getAttributeType(OP_ATTR_CREATE_TIMESTAMP_LC, true);
    modifiersNameType =
         DirectoryServer.getAttributeType(OP_ATTR_MODIFIERS_NAME_LC, true);
    modifyTimestampType =
         DirectoryServer.getAttributeType(OP_ATTR_MODIFY_TIMESTAMP_LC, true);
    creatorsName  = new AttributeValue(creatorsNameType, baseDNs[0].toString());
    modifiersName =
         new AttributeValue(modifiersNameType, baseDNs[0].toString());
    long createTime = DirectoryServer.getSchema().getOldestModificationTime();
    createTimestamp =
         GeneralizedTimeSyntax.createGeneralizedTimeValue(createTime);
    long modifyTime = DirectoryServer.getSchema().getYoungestModificationTime();
    modifyTimestamp =
         GeneralizedTimeSyntax.createGeneralizedTimeValue(modifyTime);
    // Get the set of user-defined attributes for the configuration entry.  Any
    // attributes that we don't recognize will be included directly in the
    // schema entry.
@@ -418,7 +467,11 @@
        attrType.hasName(ATTR_BACKEND_BASE_DN.toLowerCase()) ||
        attrType.hasName(ATTR_BACKEND_WRITABILITY_MODE.toLowerCase()) ||
        attrType.hasName(ATTR_SCHEMA_SHOW_ALL_ATTRIBUTES.toLowerCase()) ||
        attrType.hasName(ATTR_COMMON_NAME))
        attrType.hasName(ATTR_COMMON_NAME) ||
        attrType.hasName(OP_ATTR_CREATORS_NAME_LC) ||
        attrType.hasName(OP_ATTR_CREATE_TIMESTAMP_LC) ||
        attrType.hasName(OP_ATTR_MODIFIERS_NAME_LC) ||
        attrType.hasName(OP_ATTR_MODIFY_TIMESTAMP_LC))
    {
      return true;
    }
@@ -700,6 +753,36 @@
    }
    // Add the lastmod attributes.
    valueSet = new LinkedHashSet<AttributeValue>(1);
    valueSet.add(creatorsName);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(new Attribute(creatorsNameType, OP_ATTR_CREATORS_NAME,
                               valueSet));
    operationalAttrs.put(creatorsNameType, attrList);
    valueSet = new LinkedHashSet<AttributeValue>(1);
    valueSet.add(createTimestamp);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(new Attribute(createTimestampType, OP_ATTR_CREATE_TIMESTAMP,
                               valueSet));
    operationalAttrs.put(createTimestampType, attrList);
    valueSet = new LinkedHashSet<AttributeValue>(1);
    valueSet.add(modifiersName);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(new Attribute(modifiersNameType, OP_ATTR_MODIFIERS_NAME,
                               valueSet));
    operationalAttrs.put(modifiersNameType, attrList);
    valueSet = new LinkedHashSet<AttributeValue>(1);
    valueSet.add(modifyTimestamp);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(new Attribute(modifyTimestampType, OP_ATTR_MODIFY_TIMESTAMP,
                               valueSet));
    operationalAttrs.put(modifyTimestampType, attrList);
    // Add all the user-defined attributes.
    for (Attribute a : userDefinedAttributes)
    {
@@ -1279,6 +1362,16 @@
    {
      cleanUpTempSchemaFiles(tempSchemaFiles);
    }
    DN authzDN = modifyOperation.getAuthorizationDN();
    if (authzDN == null)
    {
      authzDN = DN.nullDN();
    }
    modifiersName = new AttributeValue(modifiersNameType, authzDN.toString());
    modifyTimestamp = GeneralizedTimeSyntax.createGeneralizedTimeValue(
                           System.currentTimeMillis());
  }
opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -646,8 +646,10 @@
    // Construct the path to the directory that should contain the schema files
    // and make sure that it exists and is a directory.  Get a list of the files
    // in that directory sorted in alphabetic order.
    String schemaDirPath = getSchemaDirectoryPath();
    File schemaDir = new File(schemaDirPath);
    String schemaDirPath          = getSchemaDirectoryPath();
    File schemaDir                = new File(schemaDirPath);
    long oldestModificationTime   = -1L;
    long youngestModificationTime = -1L;
    String[] fileNames;
    try
@@ -673,6 +675,19 @@
        {
          fileList.add(f.getAbsolutePath());
        }
        long modificationTime = f.lastModified();
        if ((oldestModificationTime <= 0L) ||
            (modificationTime < oldestModificationTime))
        {
          oldestModificationTime = modificationTime;
        }
        if ((youngestModificationTime <= 0) ||
            (modificationTime > youngestModificationTime))
        {
          youngestModificationTime = modificationTime;
        }
      }
      fileNames = new String[fileList.size()];
@@ -696,6 +711,22 @@
    }
    // If the oldest and youngest modification timestamps didn't get set for
    // some reason, then set them to the current time.
    if (oldestModificationTime <= 0)
    {
      oldestModificationTime = System.currentTimeMillis();
    }
    if (youngestModificationTime <= 0)
    {
      youngestModificationTime = oldestModificationTime;
    }
    schema.setOldestModificationTime(oldestModificationTime);
    schema.setYoungestModificationTime(youngestModificationTime);
    // Iterate through the schema files and read them as an LDIF file containing
    // a single entry.  Then get the attributeTypes and objectClasses attributes
    // from that entry and parse them to initialize the server schema.
opends/src/server/org/opends/server/types/Schema.java
@@ -172,6 +172,14 @@
  // The set of pre-encoded objectclass representations.
  private LinkedHashSet<AttributeValue> objectClassSet;
  // The oldest modification timestamp for any schema configuration
  // file.
  private long oldestModificationTime;
  // The youngest modification timestamp for any schema configuration
  // file.
  private long youngestModificationTime;
  /**
@@ -214,6 +222,9 @@
    matchingRuleUseSet  = new LinkedHashSet<AttributeValue>();
    nameFormSet         = new LinkedHashSet<AttributeValue>();
    objectClassSet      = new LinkedHashSet<AttributeValue>();
    oldestModificationTime   = System.currentTimeMillis();
    youngestModificationTime = oldestModificationTime;
  }
@@ -2542,6 +2553,77 @@
  /**
   * Retrieves the modification timestamp for the file in the schema
   * configuration directory with the oldest last modified time.
   *
   * @return  The modification timestamp for the file in the schema
   *          configuration directory with the oldest last modified
   *          time.
   */
  public long getOldestModificationTime()
  {
    assert debugEnter(CLASS_NAME, "getOldestModificationTime");
    return oldestModificationTime;
  }
  /**
   * Sets the modification timestamp for the oldest file in the schema
   * configuration directory.
   *
   * @param  oldestModificationTime  The modification timestamp for
   *                                 the oldest file in the schema
   *                                 configuration directory.
   */
  public void setOldestModificationTime(long oldestModificationTime)
  {
    assert debugEnter(CLASS_NAME, "setOldestModificationTime",
                      String.valueOf(oldestModificationTime));
    this.oldestModificationTime = oldestModificationTime;
  }
  /**
   * Retrieves the modification timestamp for the file in the schema
   * configuration directory with the youngest last modified time.
   *
   * @return  The modification timestamp for the file in the schema
   *          configuration directory with the youngest last modified
   *          time.
   */
  public long getYoungestModificationTime()
  {
    assert debugEnter(CLASS_NAME, "getYoungestModificationTime");
    return youngestModificationTime;
  }
  /**
   * Sets the modification timestamp for the youngest file in the
   * schema configuration directory.
   *
   * @param  youngestModificationTime  The modification timestamp for
   *                                   the youngest file in the schema
   *                                   configuration directory.
   */
  public void setYoungestModificationTime(
                   long youngestModificationTime)
  {
    assert debugEnter(CLASS_NAME, "setYoungestModificationTime",
                      String.valueOf(youngestModificationTime));
    this.youngestModificationTime = youngestModificationTime;
  }
  /**
   * Recursively rebuilds all schema elements that are dependent upon
   * the provided element.  This must be invoked whenever an existing
   * schema element is modified in order to ensure that any elements
@@ -2817,6 +2899,8 @@
    dupSchema.matchingRuleUseSet.addAll(matchingRuleUseSet);
    dupSchema.nameFormSet.addAll(nameFormSet);
    dupSchema.objectClassSet.addAll(objectClassSet);
    dupSchema.oldestModificationTime   = oldestModificationTime;
    dupSchema.youngestModificationTime = youngestModificationTime;
    return dupSchema;
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/backends/SchemaBackendTestCase.java
@@ -3674,6 +3674,71 @@
  /**
   * Tests to ensure that the schema subentry includes the lastmod attributes
   * and that the modifiersName and modifyTimestamp attributes get updated when
   * the schema is modified.
   *
   * @throws  Exception  If an unexpected problem occurs.
   */
  @Test()
  public void testLastModAttributes()
         throws Exception
  {
    Entry schemaEntry = DirectoryServer.getEntry(DN.decode("cn=schema"));
    assertNotNull(schemaEntry);
    AttributeType cnType =
         DirectoryServer.getAttributeType("creatorsname", true);
    AttributeType ctType =
         DirectoryServer.getAttributeType("createtimestamp", true);
    AttributeType mnType =
         DirectoryServer.getAttributeType("modifiersname", true);
    AttributeType mtType =
         DirectoryServer.getAttributeType("modifytimestamp", true);
    assertTrue(schemaEntry.hasAttribute(cnType));
    assertTrue(schemaEntry.hasAttribute(ctType));
    assertTrue(schemaEntry.hasAttribute(mnType));
    assertTrue(schemaEntry.hasAttribute(mtType));
    AttributeValue oldMTValue =
         schemaEntry.getAttribute(mtType).get(0).getValues().iterator().next();
    String path = TestCaseUtils.createTempFile(
         "dn: cn=schema",
         "changetype: modify",
         "add: attributeTypes",
         "attributeTypes: ( testlastmodattributes-oid " +
              "NAME 'testLastModAttributes' " +
              "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE " +
              "X-ORGIN 'SchemaBackendTestCase' )");
    String[] args =
    {
      "-h", "127.0.0.1",
      "-p", String.valueOf(TestCaseUtils.getServerLdapPort()),
      "-D", "cn=Directory Manager",
      "-w", "password",
      "-f", path
    };
    assertEquals(LDAPModify.mainModify(args, false, null, System.err), 0);
    schemaEntry = DirectoryServer.getEntry(DN.decode("cn=schema"));
    assertNotNull(schemaEntry);
    assertTrue(schemaEntry.hasAttribute(cnType));
    assertTrue(schemaEntry.hasAttribute(ctType));
    assertTrue(schemaEntry.hasAttribute(mnType));
    assertTrue(schemaEntry.hasAttribute(mtType));
    AttributeValue newMTValue =
         schemaEntry.getAttribute(mtType).get(0).getValues().iterator().next();
    assertFalse(oldMTValue.equals(newMTValue));
  }
  /**
   * Tests the {@code exportLDIF} method with a valid configuration.
   *
   * @throws  Exception  If an unexpected problem occurs.