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

Matthew Swift
10.25.2011 410b7d0592ba0e1dc2f3d9c745523fee430bcabe
Partial fix for OPENDJ-194: Minor improvements to change log content and configuration

Commit main functionality:

* add support for wild-cards, and @objectClass notiation
* add support for configuring additional attributes to be included with delete operations via ecl-include-for-deletes property.

Requires protocol version upgrade which will be handled in final commit.

21 files modified
831 ■■■■■ changed files
opends/resource/schema/02-config.ldif 6 ●●●● patch | view | raw | blame | history
opends/src/admin/defn/org/opends/server/admin/std/ExternalChangelogDomainConfiguration.xml 41 ●●●●● patch | view | raw | blame | history
opends/src/admin/messages/ExternalChangelogDomainCfgDefn.properties 6 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/common/DSInfo.java 70 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/plugin/ExternalChangelogDomain.java 30 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java 159 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/protocol/LDAPUpdateMsg.java 7 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/protocol/StartSessionMsg.java 75 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/protocol/TopologyMsg.java 30 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/server/DataServerHandler.java 4 ●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/server/LightweightServerHandler.java 8 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/server/ReplicationServerHandler.java 1 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/service/ReplicationBroker.java 11 ●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/replication/service/ReplicationDomain.java 189 ●●●●● patch | view | raw | blame | history
opends/src/server/org/opends/server/types/Entry.java 50 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java 59 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/DomainFakeCfg.java 14 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ExternalChangelogDomainFakeCfg.java 35 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/TopologyViewTest.java 10 ●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/ProtocolCompatibilityTest.java 9 ●●●●● patch | view | raw | blame | history
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java 17 ●●●● patch | view | raw | blame | history
opends/resource/schema/02-config.ldif
@@ -2446,6 +2446,10 @@
  NAME 'ds-cfg-ecl-include'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  X-ORIGIN 'OpenDS Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.7
  NAME 'ds-cfg-ecl-include-for-deletes'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  X-ORIGIN 'OpenDJ Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.26027.1.1.603
  NAME 'ds-cfg-weight'
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
@@ -4262,7 +4266,7 @@
  STRUCTURAL
  MUST ( cn $
         ds-cfg-enabled )
  MAY  ( ds-cfg-ecl-include )
  MAY  ( ds-cfg-ecl-include $ ds-cfg-ecl-include-for-deletes )
  X-ORIGIN 'OpenDS Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.235
  NAME 'ds-cfg-collective-attribute-subentries-virtual-attribute'
opends/src/admin/defn/org/opends/server/admin/std/ExternalChangelogDomainConfiguration.xml
@@ -24,6 +24,7 @@
  !
  !
  !      Copyright 2009 Sun Microsystems, Inc.
  !      Portions copyright 2011 ForgeRock AS
  ! -->
<adm:managed-object name="external-changelog-domain"
  plural-name="external-changelog-domains"
@@ -59,17 +60,25 @@
  </adm:property>
  <adm:property name="ecl-include" multi-valued="true" mandatory="false">
    <adm:synopsis>
      Allows to include some target entry attributes in the external changelog.
      Specifies a list of attributes which should be published with every
      change log entry, regardless of whether or not the attribute itself
      has changed.
    </adm:synopsis>
    <adm:description>
      Specifies an attribute that will be included in every External Change Log
      entry related to this replication domain.
      The list of attributes may include wild cards such as "*" and "+" as
      well as object class references prefixed with an ampersand, for
      example "@person".
      The included attributes will be published using the "includedAttributes"
      operational attribute as a single LDIF value rather like the
      "changes" attribute. For modify and modifyDN operations the included
      attributes will be taken from the entry before any changes were applied.
    </adm:description>
    <adm:default-behavior>
      <adm:undefined/>
    </adm:default-behavior>
    <adm:syntax>
      <adm:attribute-type />
      <!--  FIXME: can we constrain this with a regex? -->
      <adm:string />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
@@ -77,4 +86,28 @@
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="ecl-include-for-deletes" multi-valued="true" mandatory="false">
    <adm:synopsis>
      Specifies a list of attributes which should be published with every
      delete operation change log entry, in addition to those specified by the
      "ecl-include" property.
    </adm:synopsis>
    <adm:description>
      This property provides a means for applications to archive entries after
      they have been deleted. See the description of the "ecl-include" property
      for further information about how the included attributes are published.
    </adm:description>
    <adm:default-behavior>
      <adm:undefined/>
    </adm:default-behavior>
    <adm:syntax>
      <!--  FIXME: can we constrain this with a regex? -->
      <adm:string />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:name>ds-cfg-ecl-include-for-deletes</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
opends/src/admin/messages/ExternalChangelogDomainCfgDefn.properties
@@ -1,6 +1,8 @@
user-friendly-name=External Changelog Domain
user-friendly-plural-name=External Changelog Domains
synopsis=The External Changelog Domain provides configuration of the external changelog for the replication domain.
property.ecl-include.synopsis=Allows to include some target entry attributes in the external changelog.
property.ecl-include.description=Specifies an attribute that will be included in every External Change Log entry related to this replication domain.
property.ecl-include.synopsis=Specifies a list of attributes which should be published with every change log entry, regardless of whether or not the attribute itself has changed.
property.ecl-include.description=The list of attributes may include wild cards such as "*" and "+" as well as object class references prefixed with an ampersand, for example "@person". The included attributes will be published using the "includedAttributes" operational attribute as a single LDIF value rather like the "changes" attribute. For modify and modifyDN operations the included attributes will be taken from the entry before any changes were applied.
property.ecl-include-for-deletes.synopsis=Specifies a list of attributes which should be published with every delete operation change log entry, in addition to those specified by the "ecl-include" property.
property.ecl-include-for-deletes.description=This property provides a means for applications to archive entries after they have been deleted. See the description of the "ecl-include" property for further information about how the included attributes are published.
property.enabled.synopsis=Indicates whether the External Changelog Domain is enabled.
opends/src/server/org/opends/server/replication/common/DSInfo.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2008-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.replication.common;
@@ -63,27 +64,44 @@
  private Set<String> eclIncludes = new HashSet<String>();
  private Set<String> eclIncludesForDeletes = new HashSet<String>();
  /**
   * Creates a new instance of DSInfo with every given info.
   *
   * @param dsId The DS id
   * @param rsId The RS id the DS is connected to
   * @param generationId The generation id the DS is using
   * @param status The DS status
   * @param assuredFlag DS assured replication enabled or not
   * @param assuredMode DS assured mode
   * @param safeDataLevel DS safe data level
   * @param groupId DS group id
   * @param refUrls DS exported referrals URLs
   * @param eclIncludes The list of entry attributes to include in the ECL.
   * @param protocolVersion Protocol version supported by this server.
   * @param dsId
   *          The DS id
   * @param rsId
   *          The RS id the DS is connected to
   * @param generationId
   *          The generation id the DS is using
   * @param status
   *          The DS status
   * @param assuredFlag
   *          DS assured replication enabled or not
   * @param assuredMode
   *          DS assured mode
   * @param safeDataLevel
   *          DS safe data level
   * @param groupId
   *          DS group id
   * @param refUrls
   *          DS exported referrals URLs
   * @param eclIncludes
   *          The list of entry attributes to include in the ECL.
   * @param eclIncludesForDeletes
   *          The list of entry attributes to include in the ECL for deletes.
   * @param protocolVersion
   *          Protocol version supported by this server.
   */
  public DSInfo(int dsId, int rsId, long generationId, ServerStatus status,
    boolean assuredFlag, AssuredMode assuredMode, byte safeDataLevel,
    byte groupId, List<String> refUrls, Set<String> eclIncludes,
    short protocolVersion)
  public DSInfo(int dsId, int rsId, long generationId,
      ServerStatus status, boolean assuredFlag,
      AssuredMode assuredMode, byte safeDataLevel, byte groupId,
      List<String> refUrls, Set<String> eclIncludes,
      Set<String> eclIncludesForDeletes, short protocolVersion)
  {
    this.dsId = dsId;
    this.rsId = rsId;
    this.generationId = generationId;
@@ -94,6 +112,7 @@
    this.groupId = groupId;
    this.refUrls = refUrls;
    this.eclIncludes = eclIncludes;
    this.eclIncludesForDeletes = eclIncludesForDeletes;
    this.protocolVersion = protocolVersion;
  }
@@ -188,6 +207,15 @@
  }
  /**
   * Get the entry attributes to be included in the ECL for delete operations.
   * @return The entry attributes to be included in the ECL.
   */
  public Set<String> getEclIncludesForDeletes()
  {
    return eclIncludesForDeletes;
  }
  /**
   * Get the protocol version supported by this server.
   * Returns -1 when the protocol version is not known (too old version).
   * @return The protocol version.
@@ -224,7 +252,11 @@
        (refUrls.equals(dsInfo.getRefUrls())) &&
         (((eclIncludes == null) && (dsInfo.getEclIncludes() == null)) ||
           ((eclIncludes != null) &&
                         (eclIncludes.equals(dsInfo.getEclIncludes())))));
            (eclIncludes.equals(dsInfo.getEclIncludes())))) &&
        (((eclIncludesForDeletes == null)
          && (dsInfo.getEclIncludesForDeletes() == null)) ||
          ((eclIncludesForDeletes != null) &&
           (eclIncludesForDeletes.equals(dsInfo.getEclIncludesForDeletes())))));
    } else
    {
      return false;
@@ -249,6 +281,8 @@
    hash = 73 * hash + this.safeDataLevel;
    hash = 73 * hash + (this.refUrls != null ? this.refUrls.hashCode() : 0);
    hash = 73 * hash + (this.eclIncludes != null ? eclIncludes.hashCode() : 0);
    hash = 73 * hash + (this.eclIncludesForDeletes != null ?
        eclIncludesForDeletes.hashCode() : 0);
    hash = 73 * hash + this.groupId;
    hash = 73 * hash + this.protocolVersion;
    return hash;
@@ -284,6 +318,8 @@
    sb.append(refUrls);
    sb.append(" ; ECL Include: ");
    sb.append(eclIncludes);
    sb.append(" ; ECL Include for Deletes: ");
    sb.append(eclIncludesForDeletes);
    return sb.toString();
  }
opends/src/server/org/opends/server/replication/plugin/ExternalChangelogDomain.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions Copyright 2011 ForgeRock AS
 */
package org.opends.server.replication.plugin;
@@ -33,11 +34,9 @@
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.server.ConfigurationDeleteListener;
import org.opends.server.admin.std.server.ExternalChangelogDomainCfg;
import org.opends.server.types.AttributeType;
import org.opends.server.types.ConfigChangeResult;
import org.opends.server.types.DN;
import org.opends.server.types.ResultCode;
import java.util.HashSet;
/**
 * This class specifies the external changelog feature for a replication
@@ -49,8 +48,8 @@
             ConfigurationChangeListener<ExternalChangelogDomainCfg>
{
  LDAPReplicationDomain domain;
  boolean isEnabled;
  private LDAPReplicationDomain domain;
  private boolean isEnabled;
  /**
   * Constructor from a provided LDAPReplicationDomain.
@@ -63,13 +62,9 @@
    this.domain =domain;
    this.isEnabled = configuration.isEnabled();
    configuration.addChangeListener(this);
    if (configuration.getECLInclude() != null)
    {
      HashSet<String> attrNames = new HashSet<String>(0);
      for (AttributeType eclIncludeAttribute : configuration.getECLInclude())
        attrNames.add(eclIncludeAttribute.getNormalizedPrimaryName());
      domain.setEclInclude(domain.getServerId(), attrNames);
    }
    domain.setEclIncludes(domain.getServerId(),
        configuration.getECLInclude(),
        configuration.getECLIncludeForDeletes());
  }
@@ -95,10 +90,9 @@
    }
    this.isEnabled = configuration.isEnabled();
    HashSet<String> attrNames = new HashSet<String>(0);
    for (AttributeType eclInclude : configuration.getECLInclude())
      attrNames.add(eclInclude.getNormalizedPrimaryName());
    domain.setEclInclude(domain.getServerId(), attrNames);
    domain.setEclIncludes(domain.getServerId(),
        configuration.getECLInclude(),
        configuration.getECLIncludeForDeletes());
    return new ConfigChangeResult(ResultCode.SUCCESS, false);
  }
@@ -126,10 +120,8 @@
      }
      this.isEnabled = configuration.isEnabled();
      HashSet<String> attrNames = new HashSet<String>(0);
      for (AttributeType eclInclude : configuration.getECLInclude())
        attrNames.add(eclInclude.getNormalizedPrimaryName());
      domain.changeConfig(attrNames);
      domain.changeConfig(configuration.getECLInclude(),
          configuration.getECLIncludeForDeletes());
      return new ConfigChangeResult(ResultCode.SUCCESS, false);
    }
    catch (Exception e)
opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -39,27 +39,14 @@
import static org.opends.server.util.StaticUtils.createEntry;
import static org.opends.server.util.StaticUtils.getFileForPath;
import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
import static org.opends.server.util.StaticUtils.toLowerCase;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -5104,27 +5091,15 @@
   * @param op
   * @throws DirectoryException
   */
  private void addEntryAttributesForCL(UpdateMsg msg,PostOperationOperation op)
  throws DirectoryException
  private void addEntryAttributesForCL(UpdateMsg msg,
      PostOperationOperation op) throws DirectoryException
  {
    String[] entryAttributeNames =
      getEclInclude().toArray(new String[0]);
    ArrayList<Attribute> newattrs = new ArrayList<Attribute>();
    if (op instanceof PostOperationDeleteOperation)
    {
      Entry entry = null;
      Set<String> names = getEclIncludesForDeletes();
      PostOperationDeleteOperation delOp = (PostOperationDeleteOperation)op;
      entry = delOp.getEntryToDelete();
      for (String name : entryAttributeNames)
      {
        AttributeType atype = DirectoryServer.getAttributeType(name);
        List<Attribute> attrs = entry.getAttribute(atype);
        if (attrs != null)
          for (Attribute a : attrs)
            newattrs.add(a);
      }
      ((DeleteMsg)msg).setEclIncludes(newattrs);
      Entry entry = delOp.getEntryToDelete();
      ((DeleteMsg) msg).setEclIncludes(getIncludedAttributes(entry, names));
      // For delete only, add the Authorized DN since it's required in the
      // ECL entry but is not part of rest of the message.
@@ -5133,61 +5108,115 @@
      {
        ((DeleteMsg)msg).setInitiatorsName(deleterDN.toString());
      }
    }
    else if (op instanceof PostOperationModifyOperation)
    {
      Entry entry = null;
      Set<String> names = getEclIncludes();
      PostOperationModifyOperation modOp = (PostOperationModifyOperation)op;
      entry = modOp.getCurrentEntry();
      for (String name : entryAttributeNames)
      {
        AttributeType atype = DirectoryServer.getAttributeType(name);
        List<Attribute> attrs = entry.getAttribute(atype);
        if (attrs != null)
          for (Attribute a : attrs)
            newattrs.add(a);
      }
      ((ModifyMsg)msg).setEclIncludes(newattrs);
      Entry entry = modOp.getCurrentEntry();
      ((ModifyMsg) msg).setEclIncludes(getIncludedAttributes(entry, names));
    }
    else if (op instanceof PostOperationModifyDNOperation)
    {
      Entry entry = null;
      Set<String> names = getEclIncludes();
      PostOperationModifyDNOperation modDNOp =
        (PostOperationModifyDNOperation)op;
      entry = modDNOp.getOriginalEntry();
      for (String name : entryAttributeNames)
      {
        AttributeType atype = DirectoryServer.getAttributeType(name);
        List<Attribute> attrs = entry.getAttribute(atype);
        if (attrs != null)
          for (Attribute a : attrs)
            newattrs.add(a);
      }
      ((ModifyDNMsg)msg).setEclIncludes(newattrs);
      Entry entry = modDNOp.getOriginalEntry();
      ((ModifyDNMsg) msg).setEclIncludes(getIncludedAttributes(entry, names));
    }
    else if (op instanceof PostOperationAddOperation)
    {
      Entry entry = null;
      Set<String> names = getEclIncludes();
      PostOperationAddOperation addOp = (PostOperationAddOperation)op;
      entry = addOp.getEntryToAdd();
      for (String name : entryAttributeNames)
      Entry entry = addOp.getEntryToAdd();
      ((AddMsg) msg).setEclIncludes(getIncludedAttributes(entry, names));
    }
  }
  private Collection<Attribute> getIncludedAttributes(Entry entry,
      Set<String> names)
      {
        AttributeType atype = DirectoryServer.getAttributeType(name);
        List<Attribute> attrs = entry.getAttribute(atype);
        if (attrs != null)
    if (names.isEmpty())
        {
          for (Attribute a : attrs)
            newattrs.add(a);
      // Fast-path.
      return Collections.emptySet();
    }
    else if (names.size() == 1 && names.contains("*"))
    {
      // Potential fast-path for delete operations.
      LinkedList<Attribute> attributes = new LinkedList<Attribute>();
      for (List<Attribute> alist : entry.getUserAttributes().values())
      {
        attributes.addAll(alist);
      }
      Attribute ocattr = entry.getObjectClassAttribute();
      if (ocattr != null)
      {
        attributes.add(ocattr);
      }
      return attributes;
        }
        else
        {
          // FIXME:ECL
      // Expand @objectclass references in attribute list if needed. We
      // do this now in order to take into account dynamic schema changes.
      // Only rebuild the attribute set if necessary.
      boolean needsExpanding = false;
      for (String name : names)
      {
        if (name.startsWith("@"))
        {
          needsExpanding = true;
          break;
        }
      }
      ((AddMsg)msg).setEclIncludes(newattrs);
      Set<String> expandedNames;
      if (needsExpanding)
      {
        expandedNames = new HashSet<String>(names.size());
        for (String name : names)
        {
          if (name.startsWith("@"))
          {
            String ocName = name.substring(1);
            ObjectClass objectClass = DirectoryServer
                .getObjectClass(toLowerCase(ocName));
            if (objectClass != null)
            {
              for (AttributeType at : objectClass
                  .getRequiredAttributeChain())
              {
                expandedNames.add(at.getNameOrOID());
              }
              for (AttributeType at : objectClass
                  .getOptionalAttributeChain())
              {
                expandedNames.add(at.getNameOrOID());
    }
  }
          }
          else
          {
            expandedNames.add(name);
          }
        }
      }
      else
      {
        expandedNames = names;
      }
      Entry filteredEntry = entry.filterEntry(expandedNames, false,
          false, false);
      return filteredEntry.getAttributes();
    }
  }
  /**
   * Gets the fractional configuration of this domain.
opends/src/server/org/opends/server/replication/protocol/LDAPUpdateMsg.java
@@ -23,12 +23,13 @@
 *
 *
 *      Copyright 2006-2009 Sun Microsystems, Inc.
 *      Portions Copyright 2011 ForgeRock AS
 */
package org.opends.server.replication.protocol;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Collection;
import java.util.zip.DataFormatException;
import org.opends.server.protocols.asn1.ASN1;
@@ -424,7 +425,7 @@
  /**
   * Encode a list of attributes.
   */
   static private byte[] encodeAttributes(List<Attribute> attributes)
   static private byte[] encodeAttributes(Collection<Attribute> attributes)
   {
     if (attributes==null)
       return new byte[0];
@@ -606,7 +607,7 @@
   * Set a provided list of entry attributes.
   * @param entryAttrs  The provided list of entry attributes.
   */
  public void setEclIncludes(List<Attribute> entryAttrs)
  public void setEclIncludes(Collection<Attribute> entryAttrs)
  {
    this.encodedEclIncludes = encodeAttributes(entryAttrs);
  }
opends/src/server/org/opends/server/replication/protocol/StartSessionMsg.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.replication.protocol;
@@ -73,6 +74,8 @@
  private Set<String> eclIncludes = new HashSet<String>();
  private Set<String> eclIncludesForDeletes = new HashSet<String>();
  /**
   * The protocolVersion that should be used when serializing this message.
   */
@@ -95,7 +98,7 @@
    }
    else
    {
      decode_V4(in);
      decode_V4(in, version);
    }
  }
@@ -188,7 +191,7 @@
    }
    else
    {
      return getBytes_V4();
      return getBytes_V4(protocolVersion);
    }
  }
@@ -205,11 +208,11 @@
    }
    else
    {
      return getBytes_V4();
      return getBytes_V4(reqProtocolVersion);
    }
  }
  private byte[] getBytes_V4()
  private byte[] getBytes_V4(short version)
  {
    try
    {
@@ -229,14 +232,23 @@
      writer.writeStartSequence();
      for (String attrDef : eclIncludes)
      {
        writer.writeOctetString(attrDef);
      }
      writer.writeEndSequence();
      writer.writeStartSequence();
      for (String attrDef : eclIncludesForDeletes)
      {
        writer.writeOctetString(attrDef);
      }
      writer.writeEndSequence();
      return byteBuilder.toByteArray();
    }
    catch (Exception e)
    {
      return null;
      throw new RuntimeException(e);
    }
  }
@@ -290,7 +302,7 @@
  // Msg decoding
  // ============
  private void decode_V4(byte[] in)
  private void decode_V4(byte[] in, short version)
  throws DataFormatException
  {
    ByteSequenceReader reader = ByteString.wrap(in).asReader();
@@ -328,6 +340,14 @@
        this.eclIncludes.add(s);
      }
      asn1Reader.readEndSequence();
      asn1Reader.readStartSequence();
      while (asn1Reader.hasNextElement())
      {
        String s = asn1Reader.readOctetStringAsString();
        this.eclIncludesForDeletes.add(s);
      }
      asn1Reader.readEndSequence();
    }
    catch (Exception e)
    {
@@ -428,7 +448,8 @@
      "\nassuredMode: " + assuredMode +
      "\nsafeDataLevel: " + safeDataLevel +
      "\nreferralsURLs: " + urls +
      "\nEclIncludes: " + eclIncludes);
      "\nEclIncludes " + eclIncludes +
      "\nEclIncludeForDeletes: " + eclIncludesForDeletes);
  }
  /**
@@ -459,22 +480,48 @@
  }
  /**
   * Set the list of entry attributes to include in the ECL.
   * @param eclIncludes The list of attributes.
   * Set the attributes configured on a server to be included in the ECL.
   *
   * @param includeAttributes
   *          attributes to be included with all change records.
   * @param includeAttributesForDeletes
   *          additional attributes to be included with delete change records.
   */
  public void setEclIncludes(Set<String> eclIncludes)
  public void setEclIncludes(
      Set<String> includeAttributes,
      Set<String> includeAttributesForDeletes)
  {
    if (eclIncludes != null)
      this.eclIncludes = eclIncludes;
    if (includeAttributes != null)
    {
      eclIncludes = includeAttributes;
    }
    if (includeAttributesForDeletes != null)
    {
      eclIncludesForDeletes = includeAttributesForDeletes;
    }
  }
  /**
   * Get the list of entry attributes to include in the ECL..
   * @return The list of entry attributes to include in the ECL.
   * Get the attributes to include in each change for the ECL.
   *
   * @return The attributes to include in each change for the ECL.
   */
  public Set<String> getEclIncludes()
  {
    return eclIncludes;
  }
  /**
   * Get the attributes to include in each delete change for the ECL.
   *
   * @return The attributes to include in each delete change for the ECL.
   */
  public Set<String> getEclIncludesForDeletes()
  {
    return eclIncludesForDeletes;
  }
}
opends/src/server/org/opends/server/replication/protocol/TopologyMsg.java
@@ -151,15 +151,14 @@
        }
        Set<String> attrs = new HashSet<String>();
        Set<String> delattrs = new HashSet<String>();
        short protocolVersion = -1;
        if (version>=ProtocolVersion.REPLICATION_PROTOCOL_V4)
        {
          byte nAttrs = in[pos++];
          nRead = 0;
          /* Read attrs until expected number read */
          while ((nRead != nAttrs) &&
            (pos < in.length) //security
            )
          while ((nRead != nAttrs) && (pos < in.length))
          {
            length = getNextLength(in, pos);
            String attr = new String(in, pos, length, "UTF-8");
@@ -167,6 +166,19 @@
            pos += length + 1;
            nRead++;
          }
          nAttrs = in[pos++];
          nRead = 0;
          /* Read attrs until expected number read */
          while ((nRead != nAttrs) && (pos < in.length))
          {
            length = getNextLength(in, pos);
            String attr = new String(in, pos, length, "UTF-8");
            delattrs.add(attr);
            pos += length + 1;
            nRead++;
          }
          /* Read Protocol version */
          protocolVersion = Short.valueOf(in[pos++]);
        }
@@ -175,7 +187,7 @@
        DSInfo dsInfo = new DSInfo(dsId, rsId, generationId, status,
          assuredFlag, assuredMode, safeDataLevel, groupId, refUrls, attrs,
          protocolVersion);
          delattrs, protocolVersion);
        dsList.add(dsInfo);
        nDsInfo--;
@@ -347,9 +359,17 @@
            oStream.write(attr.getBytes("UTF-8"));
            oStream.write(0);
          }
          oStream.write(dsInfo.getProtocolVersion());
          Set<String> delattrs = dsInfo.getEclIncludesForDeletes();
          oStream.write(delattrs.size());
          for (String attr : delattrs)
          {
            oStream.write(attr.getBytes("UTF-8"));
            oStream.write(0);
        }
          oStream.write(dsInfo.getProtocolVersion());
        }
      }
      // Put number of following RS info entries
opends/src/server/org/opends/server/replication/server/DataServerHandler.java
@@ -77,6 +77,7 @@
  // DS safe data level (relevant if assured mode is safe data)
  private byte safeDataLevel = (byte) -1;
  private Set<String> eclIncludes = new HashSet<String>();
  private Set<String> eclIncludesForDeletes = new HashSet<String>();
  /**
   * Creates a new data server handler.
@@ -651,7 +652,7 @@
  {
    DSInfo dsInfo = new DSInfo(serverId, replicationServerId, generationId,
      status, assuredFlag, assuredMode, safeDataLevel, groupId, refUrls,
      eclIncludes, protocolVersion);
      eclIncludes, eclIncludesForDeletes, protocolVersion);
    return dsInfo;
  }
@@ -727,6 +728,7 @@
    this.assuredMode = startSessionMsg.getAssuredMode();
    this.safeDataLevel = startSessionMsg.getSafeDataLevel();
    this.eclIncludes = startSessionMsg.getEclIncludes();
    this.eclIncludesForDeletes = startSessionMsg.getEclIncludesForDeletes();
    /*
     * If we have already a generationID set for the domain
opends/src/server/org/opends/server/replication/server/LightweightServerHandler.java
@@ -91,6 +91,7 @@
  private short protocolVersion = -1;
  private Set<String> eclInclude = new HashSet<String>();
  private Set<String> eclIncludeForDeletes = new HashSet<String>();
  /**
   * Creates a new LighweightServerHandler with the provided serverid, connected
@@ -109,13 +110,15 @@
   * @param assuredMode The assured mode of the remote DS
   * @param safeDataLevel The safe data level of the remote DS
   * @param eclInclude The list of entry attributes to be added to the ECL.
   * @param eclIncludeForDeletes The list of entry attributes to be added to
   *                             the ECL.
   * @param protocolVersion The protocol version supported by the remote DS.
   */
  public LightweightServerHandler(ReplicationServerHandler replServerHandler,
    int replicationServerId, int serverId, long generationId, byte groupId,
    ServerStatus status, List<String> refUrls, boolean assuredFlag,
    AssuredMode assuredMode, byte safeDataLevel, Set<String> eclInclude,
    short protocolVersion)
    Set<String> eclIncludeForDeletes, short protocolVersion)
  {
    this.replServerHandler = replServerHandler;
    this.rsDomain = replServerHandler.getDomain();
@@ -129,6 +132,7 @@
    this.assuredMode = assuredMode;
    this.safeDataLevel = safeDataLevel;
    this.eclInclude = eclInclude;
    this.eclIncludeForDeletes = eclIncludeForDeletes;
    this.protocolVersion = protocolVersion;
    if (debugEnabled())
@@ -148,7 +152,7 @@
  {
    DSInfo dsInfo = new DSInfo(serverId, replicationServerId, generationId,
      status, assuredFlag, assuredMode, safeDataLevel, groupId, refUrls,
      eclInclude, protocolVersion);
      eclInclude, eclIncludeForDeletes, protocolVersion);
    return dsInfo;
  }
opends/src/server/org/opends/server/replication/server/ReplicationServerHandler.java
@@ -721,6 +721,7 @@
            dsInfo.isAssured(), dsInfo.getAssuredMode(),
            dsInfo.getSafeDataLevel(),
            dsInfo.getEclIncludes(),
            dsInfo.getEclIncludesForDeletes(),
            dsInfo.getProtocolVersion());
        lsh.startHandler();
        remoteDirectoryServers.put(lsh.getServerId(), lsh);
opends/src/server/org/opends/server/replication/service/ReplicationBroker.java
@@ -1406,8 +1406,10 @@
          domain.getAssuredMode(),
          domain.getAssuredSdLevel());
        startSessionMsg.setEclIncludes(
          domain.getEclInclude(domain.getServerId()));
      } else
            domain.getEclIncludes(domain.getServerId()),
            domain.getEclIncludesForDeletes(domain.getServerId()));
      }
      else
      {
        startSessionMsg =
          new StartSessionMsg(initStatus, new ArrayList<String>());
@@ -2908,7 +2910,10 @@
    if (domain != null)
    {
      for (DSInfo info : dsList)
        domain.setEclInclude(info.getDsId(), info.getEclIncludes());
      {
        domain.setEclIncludes(info.getDsId(), info.getEclIncludes(),
            info.getEclIncludesForDeletes());
      }
    }
  }
opends/src/server/org/opends/server/replication/service/ReplicationDomain.java
@@ -38,17 +38,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketTimeoutException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.*;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
@@ -305,9 +295,15 @@
   */
  private final ChangeNumberGenerator generator;
  private final Map<Integer, Set<String>> eclIncludeByServer =
    new ConcurrentHashMap<Integer, Set<String>>();
  Set<String> crossServersECLIncludes = new HashSet<String>();
  private final Object eclIncludesLock = new Object();
  private final Map<Integer, Set<String>> eclIncludesByServer =
    new HashMap<Integer, Set<String>>();
  private Set<String> eclIncludesAllServers = Collections.emptySet();
  private final Map<Integer, Set<String>> eclIncludesForDeletesByServer =
    new HashMap<Integer, Set<String>>();
  private Set<String> eclIncludesForDeletesAllServers = Collections
      .emptySet();
  /**
   * An object used to protect the initialization of the underlying broker
@@ -3174,37 +3170,23 @@
    }
  }
  /**
   * Change some ReplicationDomain parameters : the ECL include attribute.
   * Applies a configuration change to the attributes which should be be
   * included in the ECL.
   *
   * @param newECLInclude The new ECL attribute.
   * @param includeAttributes
   *          attributes to be included with all change records.
   * @param includeAttributesForDeletes
   *          additional attributes to be included with delete change records.
   */
  public void changeConfig(Set<String> newECLInclude)
  public void changeConfig(Set<String> includeAttributes,
      Set<String> includeAttributesForDeletes)
  {
    boolean configECLIncludeChanged = false;
    Set<String>  currentECLInclude = this.getEclInclude(serverID);
    if (newECLInclude.size() != currentECLInclude.size())
    if (setEclIncludes(serverID, includeAttributes,
        includeAttributesForDeletes))
    {
      configECLIncludeChanged = true;
    }
    else
    {
      // compare current config and new config
      for (String attr : currentECLInclude)
      {
        if (!newECLInclude.contains(attr))
        {
          configECLIncludeChanged = true;
          break;
        }
      }
    }
    if (configECLIncludeChanged)
    {
      // set new config
      this.setEclInclude(this.serverID, newECLInclude);
      if (broker != null)
      {
        disableService();
@@ -3213,6 +3195,8 @@
    }
  }
  /**
   * This method should trigger an export of the replicated data.
   * to the provided outputStream.
@@ -3633,50 +3617,137 @@
      return 0;
  }
  /**
   * Set the attributes configured on a server  to be included in the ECL.
   * @param serverId    server where these attributes are configured.
   * @param attributes  the configured attributes.
   *
   * @param serverId
   *          Server where these attributes are configured.
   * @param includeAttributes
   *          Attributes to be included with all change records, may include
   *          wild-cards.
   * @param includeAttributesForDeletes
   *          Additional attributes to be included with delete change records,
   *          may include wild-cards.
   * @return {@code true} if the set of attributes was modified.
   */
  public void setEclInclude(int serverId, Set<String> attributes)
  public boolean setEclIncludes(int serverId,
      Set<String> includeAttributes,
      Set<String> includeAttributesForDeletes)
  {
    synchronized(eclIncludeByServer)
    boolean configurationChanged = false;
    synchronized (eclIncludesLock)
    {
      eclIncludeByServer.put(serverId, attributes);
      Set<String> s1 = new HashSet<String>(includeAttributes);
      // Combine all+delete attributes.
      Set<String> s2 = new HashSet<String>(s1);
      s2.addAll(includeAttributesForDeletes);
      Set<String> s = eclIncludesByServer.get(serverId);
      if (!s1.equals(s))
      {
        configurationChanged = true;
        eclIncludesByServer.put(serverId, Collections.unmodifiableSet(s1));
      }
      s = eclIncludesForDeletesByServer.get(serverId);
      if (!s2.equals(s))
      {
        configurationChanged = true;
        eclIncludesForDeletesByServer.put(serverId,
            Collections.unmodifiableSet(s2));
      }
      // and rebuild the global list to be ready for usage
      crossServersECLIncludes.clear();
      for (Set<String> attributesByServer : eclIncludeByServer.values())
        for (String attribute : attributesByServer)
          crossServersECLIncludes.add(attribute);
      s = new HashSet<String>();
      for (Set<String> attributes : eclIncludesByServer.values())
      {
        s.addAll(attributes);
    }
      eclIncludesAllServers = Collections.unmodifiableSet(s);
      s = new HashSet<String>();
      for (Set<String> attributes : eclIncludesForDeletesByServer.values())
      {
        s.addAll(attributes);
  }
      eclIncludesForDeletesAllServers = Collections.unmodifiableSet(s);
    }
    return configurationChanged;
  }
  /**
   * Get the attributes to include in each change for the ECL.
   * It's a set : an attribute appears once even if configured on more than one
   * server.
   *
   * @return The attributes to include in each change for the ECL.
   */
  public Set<String> getEclInclude()
  public Set<String> getEclIncludes()
  {
    return crossServersECLIncludes;
    synchronized (eclIncludesLock)
    {
      return eclIncludesAllServers;
    }
  }
  /**
   * Get the attributes to include in each change for the ECL
   * for a given serverId.
   * @param  serverId The serverId for which we want the include attributes.
   * Get the attributes to include in each delete change for the ECL.
   *
   * @return The attributes to include in each delete change for the ECL.
   */
  public Set<String> getEclIncludesForDeletes()
  {
    synchronized (eclIncludesLock)
    {
      return eclIncludesForDeletesAllServers;
    }
  }
  /**
   * Get the attributes to include in each change for the ECL for a given
   * serverId.
   *
   * @param serverId
   *          The serverId for which we want the include attributes.
   * @return The attributes.
   */
  public Set<String> getEclInclude(int serverId)
  public Set<String> getEclIncludes(int serverId)
  {
    synchronized(eclIncludeByServer)
    synchronized (eclIncludesLock)
    {
      return eclIncludeByServer.get(serverId);
      return eclIncludesByServer.get(serverId);
    }
  }
  /**
   * Get the attributes to include in each change for the ECL for a given
   * serverId.
   *
   * @param serverId
   *          The serverId for which we want the include attributes.
   * @return The attributes.
   */
  public Set<String> getEclIncludesForDeletes(int serverId)
  {
    synchronized (eclIncludesLock)
    {
      return eclIncludesForDeletesByServer.get(serverId);
    }
  }
  /**
   * Returns the ChangeNUmber of the last Change that was fully processed
   * by this ReplicationDomain.
opends/src/server/org/opends/server/types/Entry.java
@@ -5062,9 +5062,7 @@
  @Override
  public String toString()
  {
    StringBuilder buffer = new StringBuilder();
    toString(buffer);
    return buffer.toString();
    return toLDIFString();
  }
@@ -5078,51 +5076,7 @@
   */
  public void toString(StringBuilder buffer)
  {
    buffer.append("Entry(dn=\"");
    dn.toString(buffer);
    buffer.append("\", objectClasses={");
    if (! objectClasses.isEmpty())
    {
      Iterator<String> ocNames = objectClasses.values().iterator();
      buffer.append(ocNames.next());
      while (ocNames.hasNext())
      {
        buffer.append(",");
        buffer.append(ocNames.next());
      }
    }
    buffer.append("}, userAttrs={");
    if (! userAttributes.isEmpty())
    {
      Iterator<AttributeType> attrs =
           userAttributes.keySet().iterator();
      buffer.append(attrs.next().getNameOrOID());
      while (attrs.hasNext())
      {
        buffer.append(",");
        buffer.append(attrs.next().getNameOrOID());
      }
    }
    buffer.append("}, operationalAttrs={");
    if (! operationalAttributes.isEmpty())
    {
      Iterator<AttributeType> attrs =
           operationalAttributes.keySet().iterator();
      buffer.append(attrs.next().getNameOrOID());
      while (attrs.hasNext())
      {
        buffer.append(",");
        buffer.append(attrs.next().getNameOrOID());
      }
    }
    buffer.append("})");
    buffer.append(toString());
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ExternalChangeLogTest.java
@@ -48,16 +48,7 @@
import java.io.StringReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.*;
import org.opends.server.TestCaseUtils;
import org.opends.server.api.Backend;
@@ -117,7 +108,6 @@
import org.opends.server.types.AbstractOperation;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeBuilder;
import org.opends.server.types.AttributeType;
import org.opends.server.types.AttributeValue;
import org.opends.server.types.Attributes;
import org.opends.server.types.ByteString;
@@ -693,7 +683,7 @@
      DomainFakeCfg domainConf =
        new DomainFakeCfg(baseDn2,  1602, replServers);
      ExternalChangelogDomainFakeCfg eclCfg =
        new ExternalChangelogDomainFakeCfg(true, null);
        new ExternalChangelogDomainFakeCfg(true, null, null);
      domainConf.setExternalChangelogDomain(eclCfg);
      LDAPReplicationDomain domain2 =
        MultimasterReplication.createNewDomain(domainConf);
@@ -753,7 +743,7 @@
      }
      eclCfg =
        new ExternalChangelogDomainFakeCfg(false, null);
        new ExternalChangelogDomainFakeCfg(false, null, null);
      domainConf.setExternalChangelogDomain(eclCfg);
      domain2.applyConfigurationChange(domainConf);
@@ -4008,11 +3998,11 @@
        new DomainFakeCfg(baseDn2, 1702, replServers);
      // on o=test2,sid=1702 include attrs set to : 'sn'
      SortedSet<AttributeType> eclInclude = new TreeSet<AttributeType>();
      eclInclude.add(DirectoryServer.getAttributeType("sn"));
      eclInclude.add(DirectoryServer.getAttributeType("roomnumber"));
      SortedSet<String> eclInclude = new TreeSet<String>();
      eclInclude.add("sn");
      eclInclude.add("roomnumber");
      ExternalChangelogDomainFakeCfg eclCfg =
        new ExternalChangelogDomainFakeCfg(true, eclInclude);
        new ExternalChangelogDomainFakeCfg(true, eclInclude, eclInclude);
      domainConf.setExternalChangelogDomain(eclCfg);
      // Set a Changetime heartbeat interval low enough (less than default
      // value that is 1000 ms) for the test to be sure to consider all changes
@@ -4028,10 +4018,13 @@
        new DomainFakeCfg(baseDn3, 1703, replServers);
      // on o=test3,sid=1703 include attrs set to : 'objectclass'
      eclInclude = new TreeSet<AttributeType>();
      eclInclude.add(DirectoryServer.getAttributeType("objectclass"));
      eclCfg =
        new ExternalChangelogDomainFakeCfg(true, eclInclude);
      eclInclude = new TreeSet<String>();
      eclInclude.add("objectclass");
      TreeSet<String> eclIncludeForDeletes = new TreeSet<String>();
      eclIncludeForDeletes.add("*");
      eclCfg = new ExternalChangelogDomainFakeCfg(true, eclInclude, eclIncludeForDeletes);
      domainConf.setExternalChangelogDomain(eclCfg);
      // Set a Changetime heartbeat interval low enough (less than default
      // value that is 1000 ms) for the test to be sure to consider all changes
@@ -4043,10 +4036,11 @@
      // on o=test2,sid=1704 include attrs set to : 'cn'
      domainConf =
        new DomainFakeCfg(baseDn2, 1704, replServers);
      eclInclude = new TreeSet<AttributeType>();
      eclInclude.add(DirectoryServer.getAttributeType("cn"));
      eclInclude = new TreeSet<String>();
      eclInclude.add("cn");
      eclCfg =
        new ExternalChangelogDomainFakeCfg(true, eclInclude);
        new ExternalChangelogDomainFakeCfg(true, eclInclude, eclInclude);
      domainConf.setExternalChangelogDomain(eclCfg);
      // Set a Changetime heartbeat interval low enough (less than default
      // value that is 1000 ms) for the test to be sure to consider all changes
@@ -4185,8 +4179,23 @@
            HashSet<String> eoc = new HashSet<String>();
            eoc.add("person");eoc.add("inetOrgPerson");eoc.add("organizationalPerson");eoc.add("top");
            assertEquals(targetEntry.getAttributes().size(), 0); // objectClass is handled separately
            checkValues(targetEntry,"objectclass",eoc);
            String changeType = getAttributeValue(resultEntry,
                "changetype");
            if (changeType.equals("delete"))
            {
              // We are using "*" for deletes so should get back 4 attributes.
              assertEquals(targetEntry.getAttributes().size(), 4);
              checkValue(targetEntry, "uid", "robert");
              checkValue(targetEntry, "cn", "Robert Hue2");
              checkValue(targetEntry, "telephonenumber", "555555");
              checkValue(targetEntry, "sn", "Robby");
            }
            else
            {
              assertEquals(targetEntry.getAttributes().size(), 0);
            }
          }
          if (targetdn.endsWith("cn=fiona jensen,o=test2"))
          {
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/DomainFakeCfg.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2007-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.replication.plugin;
@@ -78,9 +79,8 @@
  private SortedSet<String> fractionalExcludes = new TreeSet<String>();
  private SortedSet<String> fractionalIncludes = new TreeSet<String>();
  private SortedSet<String> eclIncludes = new TreeSet<String>();
  private ExternalChangelogDomainCfg eclCfg =
    new ExternalChangelogDomainFakeCfg(true, new TreeSet<AttributeType>());
    new ExternalChangelogDomainFakeCfg(true, null, null);
  /**
   * Creates a new Domain with the provided information
@@ -380,16 +380,6 @@
    return true;
  }
  public void setEclIncludes(SortedSet<String> attrs)
  {
    this.eclIncludes = attrs;
  }
  public SortedSet<String> getECLInclude()
  {
    return this.eclIncludes;
  }
  public long getInitializationHeartbeatInterval()
  {
    return 180;
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/ExternalChangelogDomainFakeCfg.java
@@ -23,14 +23,15 @@
 *
 *
 *      Copyright 2007-2009 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import java.util.SortedSet;
import java.util.TreeSet;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.ExternalChangelogDomainCfg;
import org.opends.server.types.AttributeType;
import org.opends.server.types.DN;
/**
@@ -42,7 +43,10 @@
{
  // The value of the "ecl-include" property.
  private SortedSet<AttributeType> pECLInclude;
  private SortedSet<String> pECLInclude;
  // The value of the "ecl-include-for-deletes" property.
  private SortedSet<String> pECLIncludeForDeletes;
  // The value of the "enabled" property.
  private boolean pEnabled;
@@ -54,10 +58,12 @@
   * (assured mode disabled, default group id)
   */
  public ExternalChangelogDomainFakeCfg(boolean isEnabled,
      SortedSet<AttributeType> eCLInclude)
      SortedSet<String> eclInclude,
      SortedSet<String> eclIncludeForDeletes)
  {
    this.pEnabled = isEnabled;
    this.pECLInclude = eCLInclude;
    this.pECLInclude = eclInclude != null ? eclInclude : new TreeSet<String>();
    this.pECLIncludeForDeletes = eclIncludeForDeletes != null ? eclIncludeForDeletes : new TreeSet<String>();
  }
  /**
@@ -92,29 +98,14 @@
  /**
   * Gets the "ecl-include" property.
   * <p>
   * Allows to include some target entry attributes in the external
   * changelog.
   * <p>
   * Specifies an attribute that will be included in every External
   * Change Log entry related to this replication domain.
   *
   * @return Returns an unmodifiable set containing the values of the "ecl-include" property.
   */
  public SortedSet<AttributeType> getECLInclude()
  public SortedSet<String> getECLInclude()
  {
    return this.pECLInclude;
  }
  /**
   * Set eclInclude.
   * @param eclInclude the attribute to include.
   */
  public void setECLInclude(SortedSet<AttributeType> eclInclude)
  public SortedSet<String> getECLIncludeForDeletes()
  {
    this.pECLInclude = eclInclude;
    return this.pECLIncludeForDeletes;
  }
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/TopologyViewTest.java
@@ -23,12 +23,11 @@
 *
 *
 *      Copyright 2008-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.replication.plugin;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.opends.server.TestCaseUtils.TEST_ROOT_DN_STRING;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
@@ -922,7 +921,7 @@
    }
    return new DSInfo(dsId, rsId, TEST_DN_WITH_ROOT_ENTRY_GENID, status, assuredFlag, assMode,
       (byte)assuredSdLevel, groupId, urls, eclIncludes, protocolVersion);
       (byte)assuredSdLevel, groupId, urls, eclIncludes, eclIncludes, protocolVersion);
  }
  /**
@@ -1122,10 +1121,11 @@
     byte safeDataLevel = rd.getAssuredSdLevel();
     byte groupId = rd.getGroupId();
     List<String> refUrls = rd.getRefUrls();
     Set<String> eclInclude = rd.getEclInclude();
     Set<String> eclInclude = rd.getEclIncludes();
     Set<String> eclIncludeForDeletes = rd.getEclIncludesForDeletes();
     short protocolVersion = 4;
     DSInfo dsInfo = new DSInfo(dsId, rsId, TEST_DN_WITH_ROOT_ENTRY_GENID, status, assuredFlag, assuredMode,
       safeDataLevel, groupId, refUrls, eclInclude, protocolVersion);
       safeDataLevel, groupId, refUrls, eclInclude, eclIncludeForDeletes, protocolVersion);
     dsList.add(dsInfo);
     TopoView dsTopoView = new TopoView(dsList, rd.getRsList());
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/ProtocolCompatibilityTest.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2009-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.replication.protocol;
@@ -1069,16 +1070,16 @@
    urls4.add("ldaps://host:port/dc=foobar2??sub?(sn=Another Entry 2)");
    DSInfo dsInfo1 = new DSInfo(13, 26, (long)154631, ServerStatus.FULL_UPDATE_STATUS,
      false, AssuredMode.SAFE_DATA_MODE, (byte)12, (byte)132, urls1, new HashSet<String>(), (short)-1);
      false, AssuredMode.SAFE_DATA_MODE, (byte)12, (byte)132, urls1, new HashSet<String>(), new HashSet<String>(), (short)-1);
    DSInfo dsInfo2 = new DSInfo(-436, 493, (long)-227896, ServerStatus.DEGRADED_STATUS,
      true, AssuredMode.SAFE_READ_MODE, (byte)-7, (byte)-265, urls2, new HashSet<String>(), (short)-1);
      true, AssuredMode.SAFE_READ_MODE, (byte)-7, (byte)-265, urls2, new HashSet<String>(), new HashSet<String>(), (short)-1);
    DSInfo dsInfo3 = new DSInfo(2436, 591, (long)0, ServerStatus.NORMAL_STATUS,
      false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, new HashSet<String>(), (short)-1);
      false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, new HashSet<String>(), new HashSet<String>(), (short)-1);
    DSInfo dsInfo4 = new DSInfo(415, 146, (long)0, ServerStatus.BAD_GEN_ID_STATUS,
      true, AssuredMode.SAFE_DATA_MODE, (byte)2, (byte)15, urls4, new HashSet<String>(), (short)-1);
      true, AssuredMode.SAFE_DATA_MODE, (byte)2, (byte)15, urls4, new HashSet<String>(), new HashSet<String>(), (short)-1);
    List<DSInfo> dsList1 = new ArrayList<DSInfo>();
    dsList1.add(dsInfo1);
opends/tests/unit-tests-testng/src/server/org/opends/server/replication/protocol/SynchronizationMsgTest.java
@@ -23,6 +23,7 @@
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011 ForgeRock AS
 */
package org.opends.server.replication.protocol;
@@ -1006,19 +1007,19 @@
    Set<String> a4 = new HashSet<String>();
    DSInfo dsInfo1 = new DSInfo(13, 26, (long)154631, ServerStatus.FULL_UPDATE_STATUS,
      false, AssuredMode.SAFE_DATA_MODE, (byte)12, (byte)132, urls1, a1, (short)1);
      false, AssuredMode.SAFE_DATA_MODE, (byte)12, (byte)132, urls1, a1, a1, (short)1);
    DSInfo dsInfo2 = new DSInfo(-436, 493, (long)-227896, ServerStatus.DEGRADED_STATUS,
      true, AssuredMode.SAFE_READ_MODE, (byte)-7, (byte)-265, urls2, a2, (short)2);
      true, AssuredMode.SAFE_READ_MODE, (byte)-7, (byte)-265, urls2, a2, a2, (short)2);
    DSInfo dsInfo3 = new DSInfo(2436, 591, (long)0, ServerStatus.NORMAL_STATUS,
      false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, a3, (short)3);
      false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, a3, a3, (short)3);
    DSInfo dsInfo4 = new DSInfo(415, 146, (long)0, ServerStatus.BAD_GEN_ID_STATUS,
      true, AssuredMode.SAFE_DATA_MODE, (byte)2, (byte)15, urls4, a4, (short)4);
      true, AssuredMode.SAFE_DATA_MODE, (byte)2, (byte)15, urls4, a4, a4, (short)4);
    DSInfo dsInfo5 = new DSInfo(452436, 45591, (long)0, ServerStatus.NORMAL_STATUS,
        false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, a1, (short)5);
        false, AssuredMode.SAFE_READ_MODE, (byte)17, (byte)0, urls3, a1, a1, (short)5);
    List<DSInfo> dsList1 = new ArrayList<DSInfo>();
    dsList1.add(dsInfo1);
@@ -1138,7 +1139,7 @@
  {
    StartSessionMsg msg = new StartSessionMsg(status, refUrls, assuredFlag,
      assuredMode, safedataLevel);
    msg.setEclIncludes(attrs);
    msg.setEclIncludes(attrs, attrs);
    StartSessionMsg newMsg =
      new StartSessionMsg(msg.getBytes(),ProtocolVersion.getCurrentVersion());
    assertEquals(msg.getStatus(), newMsg.getStatus());
@@ -1146,8 +1147,8 @@
    assertEquals(msg.getAssuredMode(), newMsg.getAssuredMode());
    assertTrue(msg.getSafeDataLevel() == newMsg.getSafeDataLevel());
    assertEquals(msg.getReferralsURLs(), newMsg.getReferralsURLs());
    Set<String> newAttrs = newMsg.getEclIncludes();
    assertTrue(attrs.size() == newAttrs.size());
    assertTrue(attrs.equals(newMsg.getEclIncludes()));
    assertTrue(attrs.equals(newMsg.getEclIncludesForDeletes()));
  }
  /**