From 3a581808a2e96b019c3ed1faa41acfcf286b7c3a Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Tue, 22 Sep 2015 11:50:17 +0000
Subject: [PATCH] Replaced AttrHistoricalWithOptions by a new class AttributeDescription

---
 /dev/null                                                                                                        |   78 ---------
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/EntryHistorical.java          |  233 ++++++++--------------------
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/HistoricalAttributeValue.java |   39 ++--
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/AttrValueHistorical.java      |   13 -
 opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/types/AttributeDescription.java                  |   90 +++++++++++
 5 files changed, 177 insertions(+), 276 deletions(-)

diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/AttrHistoricalWithOptions.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/AttrHistoricalWithOptions.java
deleted file mode 100644
index e213c00..0000000
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/AttrHistoricalWithOptions.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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 legal-notices/CDDLv1_0.txt
- * or http://forgerock.org/license/CDDLv1.0.html.
- * 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 legal-notices/CDDLv1_0.txt.
- * 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.
- *      Portions Copyright 2015 ForgeRock AS.
- */
-package org.opends.server.replication.plugin;
-
-import java.util.HashMap;
-import java.util.Set;
-
-
-/**
- * Used to store historical information.
- * Contain a map of AttrInfo for each options of a given attribute type.
- */
-public class AttrHistoricalWithOptions
-{
-  private final HashMap<Set<String>, AttrHistorical> attributesInfo = new HashMap<>();
-
-  /** Creates a new AttrInfoWithOptions. */
-  public AttrHistoricalWithOptions()
-  {
-  }
-
-  /**
-   * Get the info for a given option.
-   *
-   * @param options the options
-   * @return the information
-   */
-  public AttrHistorical get(Set<String> options)
-  {
-    return attributesInfo.get(options);
-  }
-
-  /**
-   * Associate some info to a given set of options.
-   *
-   * @param options the options
-   * @param attrInfo the info to associate
-   * @return the info to associate
-   */
-  public AttrHistorical put(Set<String> options, AttrHistorical attrInfo )
-  {
-    return attributesInfo.put(options, attrInfo);
-  }
-
-  /**
-   * Get the Attributes information associated to this object.
-   * @return the set of informations
-   */
-  public HashMap<Set<String>, AttrHistorical> getAttributesInfo()
-  {
-    return attributesInfo;
-  }
-}
-
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/AttrValueHistorical.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/AttrValueHistorical.java
index 3e54e32..71d6e68 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/AttrValueHistorical.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/AttrValueHistorical.java
@@ -29,7 +29,7 @@
 import org.forgerock.opendj.ldap.ByteString;
 import org.opends.server.replication.common.CSN;
 
-/** Store historical information for an attribute value. */
+/** AttrValueHistorical is the historical information of the modification of one attribute value. */
 public class AttrValueHistorical
 {
   private ByteString value;
@@ -50,12 +50,6 @@
     this.valueDeleteTime = csnDelete;
   }
 
-  /**
-   * Compares this object with another ValueInfo object.
-   * Object are said equals when their values matches.
-   * @param obj object to be compared with this object
-   * @return true if equal, false otherwise
-   */
   @Override
   public boolean equals(Object obj)
   {
@@ -67,11 +61,6 @@
     return false;
   }
 
-  /**
-   * Calculates the hasCode for this object.
-   * Only value is used when calculating the hashCode
-   * @return the hashcode
-   */
   @Override
   public int hashCode()
   {
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/EntryHistorical.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/EntryHistorical.java
index 265cbda..7adbf56 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/EntryHistorical.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/EntryHistorical.java
@@ -100,55 +100,14 @@
    */
   private int lastPurgedValuesCount;
 
-  /**
-   * The in-memory historical information is made of.
-   *
-   * EntryHistorical ::= ADDDate MODDNDate attributesInfo
-   * ADDDate       ::= CSN  // the date the entry was added
-   * MODDNDate     ::= CSN  // the date the entry was last renamed
-   *
-   * attributesInfo      ::= (AttrInfoWithOptions)*
-   *                         one AttrInfoWithOptions by attributeType
-   *
-   * AttrInfoWithOptions ::= (AttributeInfo)*
-   *                         one AttributeInfo by attributeType and option
-   *
-   * AttributeInfo       ::= AttrInfoSingle | AttrInfoMultiple
-   *
-   * AttrInfoSingle      ::= AddTime DeleteTime ValueInfo
-   *
-   * AttrInfoMultiple    ::= AddTime DeleteTime ValuesInfo
-   *
-   * ValuesInfo          ::= (AttrValueHistorical)*
-   *                         AttrValueHistorical is the historical of the
-   *                         the modification of one value
-   *
-   * AddTime             ::= CSN // last time the attribute was added to the entry
-   * DeleteTime          ::= CSN // last time the attribute was deleted from the entry
-   *
-   * AttrValueHistorical ::= AttributeValue valueDeleteTime valueUpdateTime
-   * valueDeleteTime     ::= CSN
-   * valueUpdateTime     ::= CSN
-   *
-   * - a list indexed on AttributeType of AttrInfoWithOptions :
-   *     each value is the historical for this attribute
-   *     an AttrInfoWithOptions is a set indexed on the optionValue(string) of
-   *     AttributeInfo
-   */
-
   /** The date when the entry was added. */
   private CSN entryADDDate;
-
   /** The date when the entry was last renamed. */
   private CSN entryMODDNDate;
 
-  /**
-   * Contains Historical information for each attribute sorted by attribute
-   * type. key:AttributeType value:AttrInfoWithOptions
-   */
-  private final HashMap<AttributeType,AttrHistoricalWithOptions> attributesHistorical = new HashMap<>();
+  /** Contains Historical information for each attribute description. */
+  private final Map<AttributeDescription, AttrHistorical> attributesHistorical = new HashMap<>();
 
-  /** {@inheritDoc} */
   @Override
   public String toString()
   {
@@ -341,28 +300,15 @@
       // used to store the historical information.
       return null;
     }
-    Set<String> modOptions = modAttr.getOptions();
-    AttributeType modAttrType = modAttr.getAttributeType();
 
     // Read from this entryHistorical,
     // Create one empty if none was existing in this entryHistorical.
-    AttrHistoricalWithOptions attrHistWithOptions = attributesHistorical.get(modAttrType);
-    AttrHistorical attrHist;
-    if (attrHistWithOptions != null)
-    {
-      attrHist = attrHistWithOptions.get(modOptions);
-    }
-    else
-    {
-      attrHistWithOptions = new AttrHistoricalWithOptions();
-      attributesHistorical.put(modAttrType, attrHistWithOptions);
-      attrHist = null;
-    }
-
+    AttributeDescription attrDesc = new AttributeDescription(modAttr);
+    AttrHistorical attrHist = attributesHistorical.get(attrDesc);
     if (attrHist == null)
     {
-      attrHist = AttrHistorical.createAttributeHistorical(modAttrType);
-      attrHistWithOptions.put(modOptions, attrHist);
+      attrHist = AttrHistorical.createAttributeHistorical(modAttr.getAttributeType());
+      attributesHistorical.put(attrDesc, attrHist);
     }
     return attrHist;
   }
@@ -401,81 +347,73 @@
     AttributeType historicalAttrType = DirectoryServer.getAttributeType(HISTORICAL_ATTRIBUTE_NAME);
     AttributeBuilder builder = new AttributeBuilder(historicalAttrType);
 
-    for (Map.Entry<AttributeType, AttrHistoricalWithOptions> entryWithOptions :
-          attributesHistorical.entrySet())
+    for (Map.Entry<AttributeDescription, AttrHistorical> mapEntry : attributesHistorical.entrySet())
     {
-      // Encode an attribute type
-      AttributeType type = entryWithOptions.getKey();
-      Map<Set<String>, AttrHistorical> attrWithOptions =
-                                entryWithOptions.getValue().getAttributesInfo();
+      AttributeDescription attrDesc = mapEntry.getKey();
+      AttributeType type = attrDesc.attributeType;
+      String optionsString = attrDesc.toOptionsString();
+      AttrHistorical attrHist = mapEntry.getValue();
 
-      for (Map.Entry<Set<String>, AttrHistorical> entry : attrWithOptions.entrySet())
+      CSN deleteTime = attrHist.getDeleteTime();
+      /* generate the historical information for deleted attributes */
+      boolean attrDel = deleteTime != null;
+
+      for (AttrValueHistorical attrValHist : attrHist.getValuesHistorical())
       {
-        // Encode an (attribute type/option)
-        String optionsString = toOptionsString(entry.getKey());
-        AttrHistorical attrHist = entry.getValue();
+        final ByteString value = attrValHist.getAttributeValue();
 
-        CSN deleteTime = attrHist.getDeleteTime();
-        /* generate the historical information for deleted attributes */
-        boolean attrDel = deleteTime != null;
-
-        for (AttrValueHistorical attrValHist : attrHist.getValuesHistorical())
+        // Encode an attribute value
+        if (attrValHist.getValueDeleteTime() != null)
         {
-          final ByteString value = attrValHist.getAttributeValue();
-
-          // Encode an attribute value
-          if (attrValHist.getValueDeleteTime() != null)
-          {
-            if (needsPurge(attrValHist.getValueDeleteTime(), purgeDate))
-            {
-              // this hist must be purged now, so skip its encoding
-              continue;
-            }
-            String strValue = encode(DEL, type, optionsString, attrValHist.getValueDeleteTime(), value);
-            builder.add(strValue);
-          }
-          else if (attrValHist.getValueUpdateTime() != null)
-          {
-            if (needsPurge(attrValHist.getValueUpdateTime(), purgeDate))
-            {
-              // this hist must be purged now, so skip its encoding
-              continue;
-            }
-
-            String strValue;
-            final CSN updateTime = attrValHist.getValueUpdateTime();
-            // FIXME very suspicious use of == in the next if statement,
-            // unit tests do not like changing it
-            if (attrDel && updateTime == deleteTime && value != null)
-            {
-              strValue = encode(REPL, type, optionsString, updateTime, value);
-              attrDel = false;
-            }
-            else if (value != null)
-            {
-              strValue = encode(ADD, type, optionsString, updateTime, value);
-            }
-            else
-            {
-              // "add" without any value is suspicious. Tests never go there.
-              // Is this used to encode "add" with an empty string?
-              strValue = encode(ADD, type, optionsString, updateTime);
-            }
-
-            builder.add(strValue);
-          }
-        }
-
-        if (attrDel)
-        {
-          if (needsPurge(deleteTime, purgeDate))
+          if (needsPurge(attrValHist.getValueDeleteTime(), purgeDate))
           {
             // this hist must be purged now, so skip its encoding
             continue;
           }
-          String strValue = encode(ATTRDEL, type, optionsString, deleteTime);
+          String strValue = encode(DEL, type, optionsString, attrValHist.getValueDeleteTime(), value);
           builder.add(strValue);
         }
+        else if (attrValHist.getValueUpdateTime() != null)
+        {
+          if (needsPurge(attrValHist.getValueUpdateTime(), purgeDate))
+          {
+            // this hist must be purged now, so skip its encoding
+            continue;
+          }
+
+          String strValue;
+          final CSN updateTime = attrValHist.getValueUpdateTime();
+          // FIXME very suspicious use of == in the next if statement,
+          // unit tests do not like changing it
+          if (attrDel && updateTime == deleteTime && value != null)
+          {
+            strValue = encode(REPL, type, optionsString, updateTime, value);
+            attrDel = false;
+          }
+          else if (value != null)
+          {
+            strValue = encode(ADD, type, optionsString, updateTime, value);
+          }
+          else
+          {
+            // "add" without any value is suspicious. Tests never go there.
+            // Is this used to encode "add" with an empty string?
+            strValue = encode(ADD, type, optionsString, updateTime);
+          }
+
+          builder.add(strValue);
+        }
+      }
+
+      if (attrDel)
+      {
+        if (needsPurge(deleteTime, purgeDate))
+        {
+          // this hist must be purged now, so skip its encoding
+          continue;
+        }
+        String strValue = encode(ATTRDEL, type, optionsString, deleteTime);
+        builder.add(strValue);
       }
     }
 
@@ -496,20 +434,6 @@
     return builder.toAttribute();
   }
 
-  private String toOptionsString(Set<String> options)
-  {
-    if (options != null)
-    {
-      StringBuilder optionsBuilder = new StringBuilder();
-      for (String s : options)
-      {
-        optionsBuilder.append(';').append(s);
-      }
-      return optionsBuilder.toString();
-    }
-    return "";
-  }
-
   private boolean needsPurge(CSN csn, long purgeDate)
   {
     boolean needsPurge = purgeDelayInMillisec > 0 && csn.getTime() <= purgeDate;
@@ -606,11 +530,6 @@
 
     try
     {
-      AttributeType lastAttrType = null;
-      Set<String> lastOptions = new HashSet<>();
-      AttrHistorical attrInfo = null;
-      AttrHistoricalWithOptions attrInfoWithOptions = null;
-
       // For each value of the historical attr read (mod. on a user attribute)
       //   build an AttrInfo sub-object
 
@@ -638,8 +557,8 @@
           }
           else
           {
-            AttributeType attrType = histVal.getAttrType();
-            if (attrType == null)
+            AttributeDescription attrDesc = histVal.getAttributeDescription();
+            if (attrDesc == null)
             {
               /*
                * This attribute is unknown from the schema
@@ -658,28 +577,12 @@
              *   AttrInfo that we add to AttrInfoWithOptions
              * if both match we keep everything
              */
-            Set<String> options = histVal.getOptions();
-            if (attrType != lastAttrType)
+            AttrHistorical attrInfo = newHistorical.attributesHistorical.get(attrDesc);
+            if (attrInfo == null)
             {
-              attrInfo = AttrHistorical.createAttributeHistorical(attrType);
-
-              // Create attrInfoWithOptions and store inside the attrInfo
-              attrInfoWithOptions = new AttrHistoricalWithOptions();
-              attrInfoWithOptions.put(options, attrInfo);
-
-              // Store this attrInfoWithOptions in the newHistorical object
-              newHistorical.attributesHistorical.put(attrType, attrInfoWithOptions);
-
-              lastAttrType = attrType;
-              lastOptions = options;
+              attrInfo = AttrHistorical.createAttributeHistorical(attrDesc.attributeType);
+              newHistorical.attributesHistorical.put(attrDesc, attrInfo);
             }
-            else if (!options.equals(lastOptions))
-            {
-              attrInfo = AttrHistorical.createAttributeHistorical(attrType);
-              attrInfoWithOptions.put(options, attrInfo);
-              lastOptions = options;
-            }
-
             attrInfo.assign(histVal.getHistKey(), histVal.getAttributeValue(), csn);
           }
         }
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/HistoricalAttributeValue.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/HistoricalAttributeValue.java
index 9af07c7..72c56ee 100644
--- a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/HistoricalAttributeValue.java
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/replication/plugin/HistoricalAttributeValue.java
@@ -28,6 +28,7 @@
 
 import static org.opends.server.replication.plugin.HistAttrModificationKey.*;
 
+import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Set;
 
@@ -37,6 +38,7 @@
 import org.opends.server.replication.common.CSN;
 import org.opends.server.types.Attribute;
 import org.opends.server.types.AttributeBuilder;
+import org.opends.server.types.AttributeDescription;
 import org.opends.server.types.AttributeType;
 import org.opends.server.types.Modification;
 
@@ -74,11 +76,10 @@
  */
 class HistoricalAttributeValue
 {
-  private final AttributeType attrType;
+  private final AttributeDescription attrDesc;
   private final String attrString;
   private final ByteString attributeValue;
   private final CSN csn;
-  private final Set<String> options = new LinkedHashSet<>();
   private final HistAttrModificationKey histKey;
   private final String stringValue;
 
@@ -98,8 +99,10 @@
   {
     String[] token = strVal.split(":", 4);
 
+    Set<String> options;
     if (token[0].contains(";"))
     {
+      options = new LinkedHashSet<>();
       String[] optionsToken = token[0].split(";");
       int index = 1;
       while (index < optionsToken.length)
@@ -111,9 +114,11 @@
     }
     else
     {
+      options = Collections.emptySet();
       attrString = token[0];
     }
 
+    AttributeType attrType;
     if (attrString.compareTo("dn") != 0)
     {
       // This HistVal was used to store the date when some
@@ -130,6 +135,7 @@
         isModDN = true;
       }
     }
+    this.attrDesc = attrType != null ? new AttributeDescription(attrType, options) : null;
 
     csn = new CSN(token[1]);
     histKey = HistAttrModificationKey.decodeKey(token[2]);
@@ -164,14 +170,14 @@
   }
 
   /**
-   * Get the type of this HistVal.
+   * Get the attribute description of this HistVal.
    *
-   * @return Returns the type of this HistVal.
-   *         Can return NULL if the HistVal was generated for a ADD Operation.
+   * @return Returns the attribute description of this HistVal.
+   *         Can return {@code null} if the HistVal was generated for a ADD Operation.
    */
-  public AttributeType getAttrType()
+  AttributeDescription getAttributeDescription()
   {
-    return attrType;
+    return attrDesc;
   }
 
   /**
@@ -193,15 +199,6 @@
   }
 
   /**
-   * Get the options or an empty set if there are no options.
-   * @return Returns the options.
-   */
-  public Set<String> getOptions()
-  {
-    return options;
-  }
-
-  /**
    * Get the Attribute Value.
    * @return The Attribute Value.
    */
@@ -219,8 +216,8 @@
    */
   public Modification generateMod()
   {
-    AttributeBuilder builder = new AttributeBuilder(attrType, attrString);
-    builder.setOptions(options);
+    AttributeBuilder builder = new AttributeBuilder(attrDesc.attributeType, attrString);
+    builder.setOptions(attrDesc.options);
 
     if (histKey != ATTRDEL)
     {
@@ -250,7 +247,7 @@
    */
   public boolean isADDOperation()
   {
-    return attrType == null && !isModDN;
+    return attrDesc.attributeType == null && !isModDN;
   }
 
   /**
@@ -261,7 +258,7 @@
    */
   public boolean isMODDNOperation()
   {
-    return attrType == null && isModDN;
+    return attrDesc.attributeType == null && isModDN;
   }
 
   @Override
@@ -269,7 +266,7 @@
   {
     final StringBuilder sb = new StringBuilder();
     sb.append(attrString);
-    for (String option : this.options)
+    for (String option : attrDesc.options)
     {
       sb.append(";").append(option);
     }
diff --git a/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/types/AttributeDescription.java b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/types/AttributeDescription.java
new file mode 100644
index 0000000..2df2879
--- /dev/null
+++ b/opendj-sdk/opendj-server-legacy/src/main/java/org/opends/server/types/AttributeDescription.java
@@ -0,0 +1,90 @@
+/*
+ * 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 legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * 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 legal-notices/CDDLv1_0.txt.
+ * 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 2015 ForgeRock AS
+ */
+package org.opends.server.types;
+
+import java.util.Set;
+
+/** Temporary class until we move to {@link org.forgerock.opendj.ldap.AttributeDescription}. */
+public final class AttributeDescription
+{
+  final AttributeType attributeType;
+  final Set<String> options;
+
+  AttributeDescription(Attribute attr)
+  {
+    this(attr.getAttributeType(), attr.getOptions());
+  }
+
+  AttributeDescription(AttributeType attributeType, Set<String> options)
+  {
+    this.attributeType = attributeType;
+    this.options = options;
+  }
+
+  String toOptionsString()
+  {
+    if (options != null)
+    {
+      StringBuilder optionsBuilder = new StringBuilder();
+      for (String s : options)
+      {
+        optionsBuilder.append(';').append(s);
+      }
+      return optionsBuilder.toString();
+    }
+    return "";
+  }
+
+  @Override
+  public boolean equals(Object obj)
+  {
+    if (obj == this)
+    {
+      return true;
+    }
+    if (!(obj instanceof AttributeDescription))
+    {
+      return false;
+    }
+    final AttributeDescription other = (AttributeDescription) obj;
+    return attributeType.equals(other.attributeType) && options.equals(other.options);
+  }
+
+  @Override
+  public int hashCode()
+  {
+    final int prime = 31;
+    int result = 1;
+    result = prime * result + ((attributeType == null) ? 0 : attributeType.hashCode());
+    result = prime * result + ((options == null) ? 0 : options.hashCode());
+    return result;
+  }
+
+  @Override
+  public String toString()
+  {
+    return getClass().getSimpleName() + "(" + "attributeType=" + attributeType + ", options=" + options + ")";
+  }
+}
\ No newline at end of file

--
Gitblit v1.10.0