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

gbellato
08.45.2007 7302736c0007f2851e1b8bce3101e18ec884090f
Fix for 2577 : replication generationID is not correctly saved
in schema backend files and is not returned when searching.

This code fixes the problem and also generalize the ability to store
user attributes in the schema backend.
5 files modified
243 ■■■■ changed files
opends/src/server/org/opends/server/backends/SchemaBackend.java 51 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/config/ConfigConstants.java 11 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/core/SchemaConfigManager.java 84 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Schema.java 78 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/InitOnLineTest.java 19 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/backends/SchemaBackend.java
@@ -45,6 +45,7 @@
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
@@ -171,13 +172,6 @@
  // The attribute type that will be used to include the defined name forms.
  private AttributeType nameFormsType;
  // The attribute type that will be used to save the synchronization state.
  private AttributeType synchronizationStateType;
  // The attribute type that will be used to save the synchronization
  // generationId.
  private AttributeType synchronizationGenerationIdType;
  // The value containing DN of the user we'll say created the configuration.
  private AttributeValue creatorsName;
@@ -272,12 +266,6 @@
    matchingRuleUsesType =
         DirectoryServer.getAttributeType(ATTR_MATCHING_RULE_USE_LC, true);
    nameFormsType = DirectoryServer.getAttributeType(ATTR_NAME_FORMS_LC, true);
    synchronizationStateType =
      DirectoryServer.getAttributeType(ATTR_SYNCHRONIZATION_STATE_LC, true);
    synchronizationGenerationIdType =
      DirectoryServer.getAttributeType(ATTR_SYNCHRONIZATION_GENERATIONID_LC,
          true);
    // Initialize the lastmod attributes.
    creatorsNameType =
@@ -955,21 +943,15 @@
                               valueSet));
    operationalAttrs.put(modifyTimestampType, attrList);
    //  Add the synchronization State attribute.
    valueSet = DirectoryServer.getSchema().getSynchronizationState();
    attr = new Attribute(synchronizationStateType,
                         ATTR_SYNCHRONIZATION_STATE_LC, valueSet);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(attr);
    operationalAttrs.put(synchronizationStateType, attrList);
    //  Add the synchronization GenerationId attribute.
    valueSet = DirectoryServer.getSchema().getSynchronizationGenerationId();
    attr = new Attribute(synchronizationGenerationIdType,
                         ATTR_SYNCHRONIZATION_GENERATIONID_LC, valueSet);
    attrList = new ArrayList<Attribute>(1);
    attrList.add(attr);
    operationalAttrs.put(synchronizationGenerationIdType, attrList);
    //  Add the extra attributes.
    Map<String, Attribute> attributes =
      DirectoryServer.getSchema().getExtraAttributes();
    for (Attribute attribute : attributes.values())
    {
      attrList = new ArrayList<Attribute>(1);
      attrList.add(attribute);
      operationalAttrs.put(attribute.getAttributeType(), attrList);
    }
    // Add all the user-defined attributes.
    for (Attribute a : userDefinedAttributes)
@@ -1497,8 +1479,7 @@
          }
          else
          {
            if (at.equals(synchronizationStateType))
              newSchema.setSynchronizationState(a.getValues());
            newSchema.addExtraAttribute(at.getNameOrOID(), a);
            modifiedSchemaFiles.add(FILE_USER_SCHEMA_ELEMENTS);
          }
      }
@@ -3441,14 +3422,12 @@
    if (schemaFile.equals(FILE_USER_SCHEMA_ELEMENTS))
    {
      values = schema.getSynchronizationState();
      if (values != null)
      Map<String, Attribute> attributes = schema.getExtraAttributes();
      for (Attribute attribute : attributes.values())
      {
        ArrayList<Attribute> attrList = new ArrayList<Attribute>(1);
        attrList.add(new Attribute(synchronizationStateType,
                                   synchronizationStateType.getPrimaryName(),
                                   values));
        schemaEntry.putAttribute(synchronizationStateType, attrList);
        attrList.add(attribute);
        schemaEntry.putAttribute(attribute.getAttributeType(), attrList);
      }
    }
opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -1327,18 +1327,7 @@
   */
  public static final String ATTR_MATCHING_RULE_USE_LC = "matchingruleuse";
  /**
   * The name of the attribute that holds the synchronization state,
   * formatted in lowercase.
   */
  public static final String ATTR_SYNCHRONIZATION_STATE_LC = "ds-sync-state";
  /**
   * The name of the attribute that holds the replication generationId,
   * formatted in lowercase.
   */
  public static final String ATTR_SYNCHRONIZATION_GENERATIONID_LC =
       "ds-sync-generation-id";
  /**
   * The default maximum request size that should be used if none is specified
opends/src/server/org/opends/server/core/SchemaConfigManager.java
@@ -710,29 +710,16 @@
      }
    }
    AttributeType synchronizationStateType =
      schema.getAttributeType(ATTR_SYNCHRONIZATION_STATE_LC);
    if (synchronizationStateType == null)
    // Loop on all the attribute of the schema entry to
    // find the extra attribute that shoule be loaded in the Schema.
    for (Attribute attribute : entry.getAttributes())
    {
      synchronizationStateType =
        DirectoryServer.getDefaultAttributeType(ATTR_SYNCHRONIZATION_STATE_LC,
            new MatchingRuleUseSyntax());
      if (!isSchemaAttribute(attribute))
      {
        schema.addExtraAttribute(attribute.getName(), attribute);
      }
    }
    AttributeType synchronizationGenerationIdType =
      schema.getAttributeType(ATTR_SYNCHRONIZATION_GENERATIONID_LC);
    if (synchronizationGenerationIdType == null)
    {
      synchronizationGenerationIdType = DirectoryServer.getDefaultAttributeType
          (ATTR_SYNCHRONIZATION_GENERATIONID_LC, new MatchingRuleUseSyntax());
    }
    List<Attribute> synchronizationState =
      entry.getAttribute(synchronizationStateType);
    if (synchronizationState != null && !(synchronizationState.isEmpty()))
      schema.setSynchronizationState(synchronizationState.get(0).getValues());
    // Parse the attribute type definitions if there are any.
    if (attrList != null)
    {
@@ -744,7 +731,7 @@
          AttributeType attrType;
          try
          {
            attrType = attrTypeSyntax.decodeAttributeType(v.getValue(),
            attrType = AttributeTypeSyntax.decodeAttributeType(v.getValue(),
                                                          schema, false);
            attrType.setExtraProperty(SCHEMA_PROPERTY_FILENAME, (String) null);
            attrType.setSchemaFile(schemaFile);
@@ -837,7 +824,8 @@
          ObjectClass oc;
          try
          {
            oc = ocSyntax.decodeObjectClass(v.getValue(), schema, false);
            oc =
              ObjectClassSyntax.decodeObjectClass(v.getValue(), schema, false);
            oc.setExtraProperty(SCHEMA_PROPERTY_FILENAME, (String) null);
            oc.setSchemaFile(schemaFile);
          }
@@ -931,7 +919,7 @@
          NameForm nf;
          try
          {
            nf = nfSyntax.decodeNameForm(v.getValue(), schema, false);
            nf = NameFormSyntax.decodeNameForm(v.getValue(), schema, false);
            nf.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
            nf.setSchemaFile(schemaFile);
          }
@@ -1023,7 +1011,8 @@
          DITContentRule dcr;
          try
          {
            dcr = dcrSyntax.decodeDITContentRule(v.getValue(), schema, false);
            dcr = DITContentRuleSyntax.decodeDITContentRule(
                v.getValue(), schema, false);
            dcr.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
            dcr.setSchemaFile(schemaFile);
          }
@@ -1116,8 +1105,8 @@
          DITStructureRule dsr;
          try
          {
            dsr = dsrSyntax.decodeDITStructureRule(v.getValue(), schema,
                                                   false);
            dsr = DITStructureRuleSyntax.decodeDITStructureRule(
                v.getValue(), schema, false);
            dsr.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
            dsr.setSchemaFile(schemaFile);
          }
@@ -1210,8 +1199,8 @@
          MatchingRuleUse mru;
          try
          {
            mru = mruSyntax.decodeMatchingRuleUse(v.getValue(), schema,
                                                  false);
            mru = MatchingRuleUseSyntax.decodeMatchingRuleUse(
                            v.getValue(), schema, false);
            mru.getExtraProperties().remove(SCHEMA_PROPERTY_FILENAME);
            mru.setSchemaFile(schemaFile);
          }
@@ -1296,5 +1285,44 @@
    return mods;
  }
  /**
   * This method checks if a given attribute is an attribute that
   * is used by the definition of the schema.
   *
   * @param attribute   The attribute to be checked.
   * @return            true if the attribute is part of the schema definition,
   *                    false if the attribute is not part of the schema
   *                    definition.
   */
  private static boolean isSchemaAttribute(Attribute attribute)
  {
    String attributeOid = attribute.getAttributeType().getOID();
    if (attributeOid.equals("2.5.21.1") ||
        attributeOid.equals("2.5.21.2") ||
        attributeOid.equals("2.5.21.4") ||
        attributeOid.equals("2.5.21.5") ||
        attributeOid.equals("2.5.21.6") ||
        attributeOid.equals("2.5.21.7") ||
        attributeOid.equals("2.5.21.8") ||
        attributeOid.equals("2.5.4.3")  ||
        attributeOid.equals("attributetypes-oid")      ||
        attributeOid.equals("objectclasses-oid")       ||
        attributeOid.equals("matchingRules-oid")       ||
        attributeOid.equals("matchingRuleUse-oid")     ||
        attributeOid.equals("NameFormDescription-oid") ||
        attributeOid.equals("dITContentRules-oid")     ||
        attributeOid.equals("dITStructureRules")
        )
    {
      return true;
    }
    else
    {
      return false;
    }
  }
}
opends/src/server/org/opends/server/types/Schema.java
@@ -35,9 +35,11 @@
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
@@ -212,12 +214,13 @@
  // file.
  private long youngestModificationTime;
  // The synchronization State.
  private LinkedHashSet<AttributeValue> synchronizationState = null;
  // A set of extra attributes that are not used directly by
  // the schema but may be used by other component to store
  // information in the schema.
  // ex : Replication uses this to store its state and GenerationID.
  // The synchronization generationId.
  private LinkedHashSet<AttributeValue> synchronizationGenerationId
    = null;
  private Map<String, Attribute> extraAttributes =
    new HashMap<String, Attribute>();
@@ -2931,15 +2934,10 @@
    dupSchema.objectClassSet.addAll(objectClassSet);
    dupSchema.oldestModificationTime   = oldestModificationTime;
    dupSchema.youngestModificationTime = youngestModificationTime;
    if (synchronizationState != null)
    if (extraAttributes != null)
    {
      dupSchema.synchronizationState =
        new LinkedHashSet<AttributeValue>(synchronizationState);
    }
    if (synchronizationGenerationId != null)
    {
      dupSchema.synchronizationGenerationId = new
        LinkedHashSet<AttributeValue>(synchronizationGenerationId);
      dupSchema.extraAttributes =
        new HashMap<String, Attribute>(extraAttributes);
    }
    return dupSchema;
@@ -2947,49 +2945,29 @@
  /**
   * Retrieves the Synchronization state for this schema.
   * Get the extraAttributes stored in this schema.
   *
   * @return  The Synchronization state for this schema.
   * @return  The extraAttributes stored in this schema.
   */
  public LinkedHashSet<AttributeValue> getSynchronizationState()
  public Map<String, Attribute> getExtraAttributes()
  {
    return synchronizationState;
    return extraAttributes;
  }
  /**
   * Sets the Synchronization generationId for this schema.
   * Add a new extra Attribute for this schema.
   *
   * @param  values  Synchronization generationId for this schema.
   */
  public void setSynchronizationGenerationId(
              LinkedHashSet<AttributeValue> values)
  {
    synchronizationGenerationId = values;
  }
  /**
   * Retrieves the Synchronization generationId for this schema.
   * @param  name     The identifier of the extra Attribute.
   *
   * @return  The Synchronization generationId for this schema.
   * @param  attr     The extra attribute that must be added to
   *                  this Schema.
   */
  public LinkedHashSet<AttributeValue>
    getSynchronizationGenerationId()
  public void addExtraAttribute(String name, Attribute attr)
  {
    return synchronizationGenerationId;
    extraAttributes.put(name, attr);
  }
  /**
   * Sets the Synchronization state for this schema.
   *
   * @param  values  Synchronization state for this schema.
   */
  public void setSynchronizationState(
              LinkedHashSet<AttributeValue> values)
  {
    synchronizationState = values;
  }
  /**
   * Writes a single file containing all schema element definitions,
@@ -3557,16 +3535,10 @@
      substringMatchingRules = null;
    }
    if (synchronizationGenerationId != null)
    if (extraAttributes != null)
    {
      synchronizationGenerationId.clear();
      synchronizationGenerationId = null;
    }
    if (synchronizationState != null)
    {
      synchronizationState.clear();
      synchronizationState = null;
      extraAttributes.clear();
      extraAttributes = null;
    }
    if (syntaxes != null)
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/InitOnLineTest.java
@@ -1453,8 +1453,27 @@
  protected void afterTest()
  {
    // Check that the domain hsa completed the import/export task.
    if (replDomain != null)
    {
      // race condition could cause the main thread to reach
      // this code before the task is fully completed.
      // in those cases, loop for a while waiting for completion.
      for (int i = 0; i< 10; i++)
      {
        if (replDomain.ieRunning())
        {
          try
          {
            Thread.sleep(500);
          } catch (InterruptedException e)
          { }
        }
        else
        {
          break;
        }
      }
       assertTrue(!replDomain.ieRunning(),
         "ReplicationDomain: Import/Export is not expected to be running");
    }