From e8911375edbab16632ebbdd58e642e49aadb2b36 Mon Sep 17 00:00:00 2001
From: mrossign <mrossign@localhost>
Date: Tue, 07 Jul 2009 09:15:52 +0000
Subject: [PATCH] Fractional replication Info about the feature:  https://www.opends.org/wiki/page/FractionalReplication

---
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java                 |   30 
 opendj-sdk/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java                                | 1671 ++++++++++++++++++++++
 opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/ReplicationDomainConfiguration.xml                             |   95 +
 opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/FractionalLDIFImportPluginConfiguration.xml                    |   50 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/DomainFakeCfg.java                |   38 
 opendj-sdk/opends/src/server/org/opends/server/replication/common/ChangeNumber.java                                         |    2 
 opendj-sdk/opends/src/messages/messages/replication.properties                                                              |   39 
 opendj-sdk/opends/resource/config/config.ldif                                                                               |   10 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/FractionalReplicationTest.java    | 2031 +++++++++++++++++++++++++++
 opendj-sdk/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java                           |  355 ++++
 opendj-sdk/opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java                                         |    2 
 opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java |   30 
 opendj-sdk/opends/src/server/org/opends/server/replication/service/ReplicationDomain.java                                   |   94 
 opendj-sdk/opends/resource/schema/02-config.ldif                                                                            |   29 
 14 files changed, 4,402 insertions(+), 74 deletions(-)

diff --git a/opendj-sdk/opends/resource/config/config.ldif b/opendj-sdk/opends/resource/config/config.ldif
index 0e486b7..850f830 100644
--- a/opendj-sdk/opends/resource/config/config.ldif
+++ b/opendj-sdk/opends/resource/config/config.ldif
@@ -1834,6 +1834,16 @@
 ds-cfg-plugin-type: postOperationModifyDn
 ds-cfg-java-class: org.opends.server.plugins.ChangeNumberControlPlugin
 
+dn: cn=Fractional Replication LDIF Import,cn=Plugins,cn=config
+objectClass: top
+objectClass: ds-cfg-plugin
+objectClass: ds-cfg-fractional-ldif-import-plugin
+cn: Fractional Replication LDIF Import
+ds-cfg-java-class: org.opends.server.replication.plugin.FractionalLDIFImportPlugin
+ds-cfg-enabled: true
+ds-cfg-plugin-type: ldifImport
+ds-cfg-invoke-for-internal-operations: true
+
 dn: cn=Root DNs,cn=config
 objectClass: top
 objectClass: ds-cfg-root-dn
diff --git a/opendj-sdk/opends/resource/schema/02-config.ldif b/opendj-sdk/opends/resource/schema/02-config.ldif
index 6aba8b1..236ecda 100644
--- a/opendj-sdk/opends/resource/schema/02-config.ldif
+++ b/opendj-sdk/opends/resource/schema/02-config.ldif
@@ -2397,6 +2397,24 @@
   NAME 'ds-cfg-index-extensible-matching-rule'
   SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
   X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.586
+  NAME 'ds-cfg-fractional-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.26027.1.1.587
+  NAME 'ds-cfg-fractional-exclude'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.588
+  NAME 'ds-sync-fractional-include'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  USAGE directoryOperation
+  X-ORIGIN 'OpenDS Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.26027.1.1.589
+  NAME 'ds-sync-fractional-exclude'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  USAGE directoryOperation
+  X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
   NAME 'ds-cfg-access-control-handler'
   SUP top
@@ -2955,7 +2973,9 @@
         ds-cfg-assured-sd-level $
         ds-cfg-assured-timeout $
         ds-cfg-group-id $
-        ds-cfg-referrals-url)
+        ds-cfg-referrals-url $
+        ds-cfg-fractional-exclude $
+        ds-cfg-fractional-include)
   X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.58
   NAME 'ds-cfg-length-based-password-validator'
@@ -3958,7 +3978,7 @@
   NAME 'ds-cfg-qos-policy'
   SUP top
   STRUCTURAL
-  MUST ( cn $
+  MUST ( cn $ 
          ds-cfg-java-class)
   X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.185
@@ -4054,4 +4074,9 @@
   SUP ds-cfg-matching-rule
   STRUCTURAL
   X-ORIGIN 'OpenDS Directory Server' )
+objectClasses: ( 1.3.6.1.4.1.26027.1.2.232
+  NAME 'ds-cfg-fractional-ldif-import-plugin'
+  SUP ds-cfg-plugin
+  STRUCTURAL
+  X-ORIGIN 'OpenDS Directory Server' )
 
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/FractionalLDIFImportPluginConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/FractionalLDIFImportPluginConfiguration.xml
new file mode 100644
index 0000000..a859f9a
--- /dev/null
+++ b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/FractionalLDIFImportPluginConfiguration.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ! CDDL HEADER START
+  !
+  ! The contents of this file are subject to the terms of the
+  ! Common Development and Distribution License, Version 1.0 only
+  ! (the "License").  You may not use this file except in compliance
+  ! with the License.
+  !
+  ! You can obtain a copy of the license at
+  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE
+  ! or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+  ! See the License for the specific language governing permissions
+  ! and limitations under the License.
+  !
+  ! When distributing Covered Code, include this CDDL HEADER in each
+  ! file and include the License file at
+  ! trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+  ! add the following below this CDDL HEADER, with the fields enclosed
+  ! by brackets "[]" replaced with your own identifying information:
+  !      Portions Copyright [yyyy] [name of copyright owner]
+  !
+  ! CDDL HEADER END
+  !
+  !
+  !      Copyright 2009 Sun Microsystems, Inc.
+  ! -->
+<adm:managed-object name="fractional-ldif-import-plugin"
+  plural-name="fractional-ldif-import-plugins"
+  package="org.opends.server.admin.std" extends="plugin"
+  xmlns:adm="http://www.opends.org/admin"
+  xmlns:ldap="http://www.opends.org/admin-ldap">
+  <adm:synopsis>
+    The 
+    <adm:user-friendly-name />
+    is used internally by the replication plugin to support fractional
+    replication.
+  </adm:synopsis>
+  <adm:description>
+    It is used to check fractional configuration consistency with local domain
+    one as well as to filter attributes when performing an online import from a
+    remote backend to a local backend.
+  </adm:description>
+  <adm:profile name="ldap">
+    <ldap:object-class>
+      <ldap:name>ds-cfg-fractional-ldif-import-plugin</ldap:name>
+      <ldap:superior>ds-cfg-plugin</ldap:superior>
+    </ldap:object-class>
+  </adm:profile>
+</adm:managed-object>
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/ReplicationDomainConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/ReplicationDomainConfiguration.xml
index b4a5726..8930324 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/ReplicationDomainConfiguration.xml
+++ b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/ReplicationDomainConfiguration.xml
@@ -345,4 +345,99 @@
       </ldap:attribute>
     </adm:profile>
   </adm:property>
+  <adm:property name="fractional-include" multi-valued="true" mandatory="false"
+  advanced="true">
+    <adm:synopsis>
+      Allows to include some attributes to replicate to this server.
+    </adm:synopsis>
+    <adm:description>
+      If fractional-include configuration attribute is used, only attributes
+      specified in this attribute will be added/modified/deleted when an
+      operation performed from another directory server is being replayed in the
+      local server. Note that the usage of this configuration attribute is
+      mutually exclusive with the usage of the fractional-exclude attribute.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:undefined/>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:string>
+        <adm:pattern>
+          <!-- This java regex is mostly derived from keystring BNF definition
+          that can be found in RFC 2252, section "4.1. Common Encoding Aspects".
+          This can be read as: (oid|\*):oid(,oid)*+
+          -->
+          <adm:regex>^((([a-zA-Z]([a-zA-Z]|[0-9]|-|;)*+)|(0|([1-9]([0-9])*+))(\\.(0|([1-9]([0-9])*+)))*+)|\\*):(([a-zA-Z]([a-zA-Z]|[0-9]|-|;)*+)|(0|([1-9]([0-9])*+))(\\.(0|([1-9]([0-9])*+)))*+)(,(([a-zA-Z]([a-zA-Z]|[0-9]|-|;)*+)|(0|([1-9]([0-9])*+))(\\.(0|([1-9]([0-9])*+)))*+))*+$</adm:regex>
+          <adm:usage>Syntax:
+          className:attributeName[,attributeName]
+          or
+          *:attributeName[,attributeName]
+          Note that any class (className) or attribute (attributeName) definition can be replaced with its OID definition.
+          Examples:
+          - inetOrgPerson:uid,employeeNumber : 'uid' and 'employeeNumber' attributes of any entry of type 'inetOrgPerson' class.
+          This can also be 2.16.840.1.113730.3.2.2:0.9.2342.19200300.100.1.1,2.16.840.1.113730.3.1.3 or a mix.
+          - *:description : the 'description' attribute of any entry that has this attribute.
+          This can also be *:2.5.4.13
+          </adm:usage>
+          <adm:synopsis>
+            Defines attribute(s) of one particular class or of all possible
+            classes, to include in the replication.
+          </adm:synopsis>
+        </adm:pattern>
+      </adm:string>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-fractional-include</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
+  <adm:property name="fractional-exclude" multi-valued="true" mandatory="false"
+  advanced="true">
+    <adm:synopsis>
+      Allows to exclude some attributes to replicate to this server.
+    </adm:synopsis>
+    <adm:description>
+      If fractional-exclude configuration attribute is used, attributes
+      specified in this attribute will be ignored (not added/modified/deleted)
+      when an operation performed from another directory server is being
+      replayed in the local server. Note that the usage of this configuration
+      attribute is mutually exclusive with the usage of the fractional-include
+      attribute.
+    </adm:description>
+    <adm:default-behavior>
+      <adm:undefined/>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:string>
+        <adm:pattern>
+          <!-- This java regex is mostly derived from keystring BNF definition
+          that can be found in RFC 2252, section "4.1. Common Encoding Aspects".
+          This can be read as: (oid|\*):oid(,oid)*+
+          -->
+          <adm:regex>^((([a-zA-Z]([a-zA-Z]|[0-9]|-|;)*+)|(0|([1-9]([0-9])*+))(\\.(0|([1-9]([0-9])*+)))*+)|\\*):(([a-zA-Z]([a-zA-Z]|[0-9]|-|;)*+)|(0|([1-9]([0-9])*+))(\\.(0|([1-9]([0-9])*+)))*+)(,(([a-zA-Z]([a-zA-Z]|[0-9]|-|;)*+)|(0|([1-9]([0-9])*+))(\\.(0|([1-9]([0-9])*+)))*+))*+$</adm:regex>
+          <adm:usage>Syntax:
+          className:attributeName[,attributeName]
+          or
+          *:attributeName[,attributeName].
+          Note that any class (className) or attribute (attributeName) definition can be replaced with its OID definition.
+          Examples:
+          inetOrgPerson:photo,jpegPhoto : 'photo' and 'jpegPhoto' attributes of any entry of type 'inetOrgPerson' class.
+          This can also be 2.16.840.1.113730.3.2.2:0.9.2342.19200300.100.1.7,0.9.2342.19200300.100.1.60 or a mix.
+          *:jpegPhoto : the 'jpegPhoto' attribute of any entry that has this attribute.
+          This can also be *:0.9.2342.19200300.100.1.60
+          </adm:usage>
+          <adm:synopsis>
+            Defines attribute(s) of one particular class or of all possible
+            classes, to exclude from the replication.
+          </adm:synopsis>
+        </adm:pattern>
+      </adm:string>
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-fractional-exclude</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
 </adm:managed-object>
diff --git a/opendj-sdk/opends/src/messages/messages/replication.properties b/opendj-sdk/opends/src/messages/messages/replication.properties
index b77bb30..0dc17b9 100644
--- a/opendj-sdk/opends/src/messages/messages/replication.properties
+++ b/opendj-sdk/opends/src/messages/messages/replication.properties
@@ -372,4 +372,41 @@
 SEVERE_ERR_INVALID_COOKIE_FULL_RESYNC_REQUIRED_158=The provided cookie is \
  valid in the current context due to %s. Full resync is required
 SEVERE_ERR_BYTE_COUNT_159=The Server Handler byte count is not correct (Fixed)
-
+NOTICE_ERR_FRACTIONAL_CONFIG_UNKNOWN_OBJECT_CLASS_160=Wrong fractional \
+ replication configuration: could not find object class definition for %s in \
+ schema
+NOTICE_ERR_FRACTIONAL_CONFIG_UNKNOWN_ATTRIBUTE_TYPE_161=Wrong fractional \
+ replication configuration : could not find attribute type definition for %s \
+ in schema
+NOTICE_ERR_FRACTIONAL_CONFIG_NOT_OPTIONAL_ATTRIBUTE_162=Wrong fractional \
+ replication configuration : attribute %s is not optional in class %s
+NOTICE_ERR_FRACTIONAL_CONFIG_WRONG_FORMAT_163=Wrong fractional replication \
+ configuration : wrong format : %s (need at least [<className>|*],attributeName)
+NOTICE_ERR_FRACTIONAL_CONFIG_BOTH_MODES_164=Wrong fractional replication \
+ configuration : cannot use both exclusive and inclusive modes
+NOTICE_ERR_FRACTIONAL_CONFIG_PROHIBITED_ATTRIBUTE_165=Wrong fractional \
+ replication configuration : prohibited attribute %s usage
+NOTICE_ERR_FRACTIONAL_166=Fractional replication : exception for domain : %s : \
+ %s
+NOTICE_FRACTIONAL_BAD_DATA_SET_NEED_RESYNC_167=Warning : domain %s fractional \
+ replication configuration is inconsistent with backend data set : need \
+ resynchronization or fractional configuration to be changed
+MILD_ERR_PLUGIN_FRACTIONAL_LDIF_IMPORT_INVALID_PLUGIN_TYPE_168=The fractional \
+ replication ldif import plugin is configured with invalid plugin type %s. \
+ Only the ldifImport plugin type is allowed
+NOTICE_ERR_FULL_UPDATE_IMPORT_FRACTIONAL_BAD_REMOTE_169=The online full \
+ update for importing suffix %s data from remote directory server %s has been \
+ stopped due to fractional configuration inconsistency between destination \
+ and source server : imported data set has not the same fractional configuration
+NOTICE_ERR_FULL_UPDATE_IMPORT_FRACTIONAL_REMOTE_IS_FRACTIONAL_170=The online \
+ full update for importing suffix %s data from remote directory server %s has \
+ been stopped due to fractional configuration inconsistency between \
+ destination and source server : imported data set has some fractional \
+ configuration but not destination server
+NOTICE_ERR_FRACTIONAL_FORBIDDEN_OPERATION_171=The following operation has \
+ been forbidden in suffix %s due to inconsistency with the fractional \
+ replication configuration : %s
+NOTICE_ERR_FRACTIONAL_FORBIDDEN_FULL_UPDATE_FRACTIONAL_172=The export of \
+ domain %s from server %s to all other servers of the topology is forbidden as \
+ the source server has some fractional configuration : only fractional servers \
+ in a replicated topology does not makes sense
diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/common/ChangeNumber.java b/opendj-sdk/opends/src/server/org/opends/server/replication/common/ChangeNumber.java
index e38bee8..49f9bab 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/replication/common/ChangeNumber.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/replication/common/ChangeNumber.java
@@ -41,7 +41,7 @@
 
   // A String representation of the ChangeNumber suitable for network
   // transmission.
-  private String formatedString = null;;
+  private String formatedString = null;
 
   /**
    * Create a new ChangeNumber from a String.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java b/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java
new file mode 100644
index 0000000..9afb119
--- /dev/null
+++ b/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java
@@ -0,0 +1,355 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.replication.plugin;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.opends.messages.Message;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.std.server.FractionalLDIFImportPluginCfg;
+import org.opends.server.admin.std.server.PluginCfg;
+import org.opends.server.api.plugin.*;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.replication.plugin.LDAPReplicationDomain.
+  AttributeValueStringIterator;
+import org.opends.server.types.*;
+
+import static org.opends.messages.ReplicationMessages.*;
+
+/**
+ * This class implements a Directory Server plugin that is used in fractional
+ * replication when an online full update occurs.
+ * The following tasks are done:
+ * - check that the fractional configuration (if any) stored in the root entry
+ * of the domain is compliant with the fractional configuration of the domain
+ *  (if not make online update stop)
+ * - perform filtering according to fractional configuration of the domain
+ * - flush the fractional configuration of the domain in the root entry
+ *  (if no one already present)
+ */
+public final class FractionalLDIFImportPlugin
+  extends DirectoryServerPlugin<FractionalLDIFImportPluginCfg>
+  implements ConfigurationChangeListener<FractionalLDIFImportPluginCfg>
+{
+
+  /**
+   * Creates a new instance of this Directory Server plugin.  Every plugin must
+   * implement a default constructor (it is the only one that will be used to
+   * create plugins defined in the configuration), and every plugin constructor
+   * must call {@code super()} as its first element.
+   */
+  public FractionalLDIFImportPlugin()
+  {
+    super();
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public final void initializePlugin(Set<PluginType> pluginTypes,
+    FractionalLDIFImportPluginCfg configuration)
+    throws ConfigException
+  {
+    // Make sure that the plugin has been enabled for the appropriate types.
+    for (PluginType t : pluginTypes)
+    {
+      switch (t)
+      {
+        case LDIF_IMPORT:
+          // This is acceptable.
+          break;
+
+        default:
+          Message message =
+            ERR_PLUGIN_FRACTIONAL_LDIF_IMPORT_INVALID_PLUGIN_TYPE.get(
+            t.toString());
+          throw new ConfigException(message);
+      }
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public final void finalizePlugin()
+  {
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public final PluginResult.ImportLDIF doLDIFImport(
+    LDIFImportConfig importConfig, Entry entry)
+  {
+    /**
+     * See class comment for what we achieve here...
+     */
+
+    // Retrieve the replicated domain this entry belongs to
+    DN entryDn = entry.getDN();
+    LDAPReplicationDomain domain = MultimasterReplication.findDomain(entryDn,
+      null);
+    if (domain == null)
+    {
+      // Not part of a replicated domain : nothing to do
+      return PluginResult.ImportLDIF.continueEntryProcessing();
+    }
+
+    // Is the entry to treat the root entry of the domain ? If yes, analyze the
+    // fractional configuration in it and compare with local domain fractional
+    // configuration. Stop the import if some inconsistency is detcted
+    DN domainBaseDn = domain.getBaseDN();
+    if (domainBaseDn.equals(entryDn))
+    {
+      /*
+       * This is the root entry, try to read a fractional configuration from it
+       */
+      Iterator<String> exclIt = null;
+      AttributeType fractionalExcludeType =
+        DirectoryServer.getAttributeType(
+        LDAPReplicationDomain.REPLICATION_FRACTIONAL_EXCLUDE);
+      List<Attribute> exclAttrs =
+        entry.getAttribute(fractionalExcludeType);
+      Attribute exclAttr = null;
+      if (exclAttrs != null)
+      {
+        exclAttr = exclAttrs.get(0);
+        if (exclAttr != null)
+        {
+          exclIt = new AttributeValueStringIterator(exclAttr.iterator());
+        }
+      }
+
+      Iterator<String> inclIt = null;
+      AttributeType fractionalIncludeType =
+        DirectoryServer.getAttributeType(
+        LDAPReplicationDomain.REPLICATION_FRACTIONAL_INCLUDE);
+      List<Attribute> inclAttrs =
+        entry.getAttribute(fractionalIncludeType);
+      Attribute inclAttr = null;
+      if (inclAttrs != null)
+      {
+        inclAttr = inclAttrs.get(0);
+        if (inclAttr != null)
+        {
+          inclIt = new AttributeValueStringIterator(inclAttr.iterator());
+        }
+      }
+
+      // Compare backend and local fractional configuration
+      boolean sameConfig = domain.isFractionalConfigConsistent(exclIt, inclIt);
+      if (domain.isFractional())
+      {
+        // Local domain is fractional
+        if (sameConfig)
+        {
+          // Both local and remote fractional configuration are equivalent :
+          // follow import, no need to go with filtering as remote backend
+          // should be ok
+          return PluginResult.ImportLDIF.continueEntryProcessing();
+        } else
+        {
+          // Local domain is fractional, remote domain has not same config
+          boolean remoteDomainHasSomeConfig = false;
+          if ((exclAttr != null && (exclAttr.size() > 0)) ||
+            (inclAttr != null && (inclAttr.size() > 0)))
+          {
+            remoteDomainHasSomeConfig = true;
+          }
+          if (remoteDomainHasSomeConfig)
+          {
+            // Local domain is fractional, remote domain has some config which
+            // is different : stop import (error will be logged when import is
+            // stopped)
+            domain.setImportErrorMessageId(
+              LDAPReplicationDomain.IMPORT_ERROR_MESSAGE_BAD_REMOTE);
+            domain.setFollowImport(false);
+            return PluginResult.ImportLDIF.continueEntryProcessing();
+          } else
+          {
+            // Local domain is fractional but remote domain has no config :
+            // flush local config into root entry and follow import with
+            // filtering
+            flushFractionalConfigIntoEntry(domain, entry);
+          }
+        }
+      } else
+      {
+        // Local domain is not fractional
+        if (sameConfig)
+        {
+          // None of the local or remote domain has fractional config : nothing
+          // more to do : let import finish
+          return PluginResult.ImportLDIF.continueEntryProcessing();
+        } else
+        {
+          // Local domain is not fractional but remote one is : stop import :
+          // local domain should be configured with the same config as remote
+          // one
+          domain.setImportErrorMessageId(
+              LDAPReplicationDomain.IMPORT_ERROR_MESSAGE_REMOTE_IS_FRACTIONAL);
+          domain.setFollowImport(false);
+          return PluginResult.ImportLDIF.continueEntryProcessing();
+        }
+      }
+    }
+
+    // If we get here, local domain fractional configuration is enabled.
+    // Now filter for potential attributes to be removed.
+    domain.fractionalRemoveAttributesFromEntry(entry.getDN().getRDN(),
+      entry.getObjectClasses(), entry.getUserAttributes(), true);
+
+    return PluginResult.ImportLDIF.continueEntryProcessing();
+  }
+
+  /**
+   * Write the fractional configuration in the passed domain into the passed
+   * entry.
+   * WARNING: assumption is that no fractional attributes at all is already
+   * present in the passed entry. Also assumption is that domain fractional
+   * configuration is on.
+   * @param domain Domain containing the fractional configuration to use
+   * @param entry The entry to modify
+   */
+  private static void flushFractionalConfigIntoEntry(
+    LDAPReplicationDomain domain, Entry entry)
+  {
+    if (domain.isFractional()) // Paranoia check
+    {
+      // Get the fractional configuration of the domain
+      boolean fractionalExclusive = domain.isFractionalExclusive();
+      Map<String, List<String>> fractionalSpecificClassesAttributes =
+        domain.getFractionalSpecificClassesAttributes();
+      List<String> fractionalAllClassesAttributes =
+        domain.getFractionalAllClassesAttributes();
+
+      // Create attribute builder for the rigth fractional mode
+      String fractAttribute = null;
+      if (fractionalExclusive)
+      {
+        fractAttribute = LDAPReplicationDomain.REPLICATION_FRACTIONAL_EXCLUDE;
+      } else
+      {
+        fractAttribute = LDAPReplicationDomain.REPLICATION_FRACTIONAL_INCLUDE;
+      }
+      AttributeBuilder attrBuilder = new AttributeBuilder(fractAttribute);
+      boolean somethingToFlush = false;
+
+      // Add attribute values for all classes
+      int size = fractionalAllClassesAttributes.size();
+      if (size > 0)
+      {
+        String fracValue = "*:";
+        int i = 1;
+        for (String attrName : fractionalAllClassesAttributes)
+        {
+          fracValue += attrName;
+          if (i < size)
+          {
+            fracValue += ",";
+          }
+          i++;
+        }
+        somethingToFlush = true;
+        attrBuilder.add(fracValue);
+      }
+
+      // Add attribute values for specific classes
+      size = fractionalSpecificClassesAttributes.size();
+      if (size > 0)
+      {
+        for (String className : fractionalSpecificClassesAttributes.keySet())
+        {
+          int valuesSize =
+            fractionalSpecificClassesAttributes.get(className).size();
+          if (valuesSize > 0)
+          {
+            String fracValue = className + ":";
+            int i = 1;
+            for (String attrName : fractionalSpecificClassesAttributes.get(
+              className))
+            {
+              fracValue += attrName;
+              if (i < valuesSize)
+              {
+                fracValue += ",";
+              }
+              i++;
+            }
+            somethingToFlush = true;
+            attrBuilder.add(fracValue);
+          }
+        }
+      }
+
+      // Now flush attribute values into entry
+      if (somethingToFlush)
+      {
+        List<AttributeValue> duplicateValues = new ArrayList<AttributeValue>();
+        entry.addAttribute(attrBuilder.toAttribute(), duplicateValues);
+      }
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public boolean isConfigurationAcceptable(PluginCfg configuration,
+    List<Message> unacceptableReasons)
+  {
+    return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isConfigurationChangeAcceptable(
+    FractionalLDIFImportPluginCfg configuration,
+    List<Message> unacceptableReasons)
+  {
+    return true;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public ConfigChangeResult applyConfigurationChange(
+    FractionalLDIFImportPluginCfg configuration)
+  {
+    return new ConfigChangeResult(ResultCode.SUCCESS, false);
+  }
+}
+
diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index 76d15fc..82ed278 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -51,13 +51,18 @@
 import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
+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.concurrent.BlockingQueue;
 import java.util.concurrent.TimeoutException;
@@ -75,6 +80,7 @@
 import org.opends.server.api.DirectoryThread;
 import org.opends.server.api.SynchronizationProvider;
 import org.opends.server.backends.jeb.BackendImpl;
+import org.opends.server.backends.task.Task;
 import org.opends.server.config.ConfigException;
 import org.opends.server.controls.SubtreeDeleteControl;
 import org.opends.server.core.AddOperation;
@@ -99,6 +105,7 @@
 import org.opends.server.replication.common.ChangeNumberGenerator;
 import org.opends.server.replication.common.ServerState;
 import org.opends.server.replication.common.ServerStatus;
+import org.opends.server.replication.common.StatusMachineEvent;
 import org.opends.server.replication.protocol.AddContext;
 import org.opends.server.replication.protocol.AddMsg;
 import org.opends.server.replication.protocol.DeleteContext;
@@ -108,12 +115,14 @@
 import org.opends.server.replication.protocol.ModifyMsg;
 import org.opends.server.replication.protocol.OperationContext;
 import org.opends.server.replication.protocol.ProtocolSession;
+import org.opends.server.replication.protocol.RoutableMsg;
 import org.opends.server.replication.protocol.UpdateMsg;
 import org.opends.server.tasks.TaskUtils;
 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.AttributeValues;
 import org.opends.server.types.ByteString;
 import org.opends.server.types.ConfigChangeResult;
@@ -128,10 +137,12 @@
 import org.opends.server.types.LDIFImportConfig;
 import org.opends.server.types.Modification;
 import org.opends.server.types.ModificationType;
+import org.opends.server.types.ObjectClass;
 import org.opends.server.types.Operation;
 import org.opends.server.types.RDN;
 import org.opends.server.types.RawModification;
 import org.opends.server.types.ResultCode;
+import org.opends.server.types.Schema;
 import org.opends.server.types.SearchFilter;
 import org.opends.server.types.SearchResultEntry;
 import org.opends.server.types.SearchResultReference;
@@ -227,7 +238,7 @@
   // This list is used to temporary store operations that needs
   // to be replayed at session establishment time.
   private final TreeMap<ChangeNumber, FakeOperation> replayOperations  =
-    new TreeMap<ChangeNumber, FakeOperation>();;
+    new TreeMap<ChangeNumber, FakeOperation>();
 
   /**
    * The isolation policy that this domain is going to use.
@@ -252,6 +263,142 @@
   private ServerStateFlush flushThread;
 
   /**
+   * The attribute name used to store the generation id in the backend.
+   */
+  protected static final String REPLICATION_GENERATION_ID =
+    "ds-sync-generation-id";
+  /**
+   * The attribute name used to store the fractional include configuration in
+   * the backend.
+   */
+  public static final String REPLICATION_FRACTIONAL_INCLUDE =
+    "ds-sync-fractional-include";
+  /**
+   * The attribute name used to store the fractional exclude configuration in
+   * the backend.
+   */
+  public static final String REPLICATION_FRACTIONAL_EXCLUDE =
+    "ds-sync-fractional-exclude";
+
+  /**
+   * Fractional replication variables.
+   */
+
+  // Return type of the parseFractionalConfig method
+  private static final int NOT_FRACTIONAL = 0;
+  private static final int EXCLUSIVE_FRACTIONAL = 1;
+  private static final int INCLUSIVE_FRACTIONAL = 2;
+
+  /**
+   * Tells if fractional replication is enabled or not (some fractional
+   * constraints have been put in place). If this is true then
+   * fractionalExclusive explains the configuration mode and either
+   * fractionalSpecificClassesAttributes or fractionalAllClassesAttributes or
+   * both should be filled with something.
+   */
+  private boolean fractional = false;
+
+  /**
+   * - If true, tells that the configured fractional replication is exclusive:
+   * Every attributes contained in fractionalSpecificClassesAttributes and
+   * fractionalAllClassesAttributes should be ignored when replaying operation
+   * in local backend.
+   * - If false, tells that the configured fractional replication is inclusive:
+   * Only attributes contained in fractionalSpecificClassesAttributes and
+   * fractionalAllClassesAttributes should be taken into account in local
+   * backend.
+   */
+  private boolean fractionalExclusive = true;
+
+  /**
+   * Used in fractional replication: holds attributes of a specific object
+   * class.
+   * - key = object class (name or OID of the class)
+   * - value = the attributes of that class that should be taken into account
+   * (inclusive or exclusive fractional replication) (name or OID of the
+   * attribute)
+   * When an operation coming from the network is to be locally replayed, if the
+   * concerned entry has an objectClass attribute equals to 'key':
+   * - inclusive mode: only the attributes in 'value' will be added/deleted/
+   * modified
+   * - exclusive mode: the attributes in 'value' will not be added/deleted/
+   * modified
+   */
+  private Map<String, List<String>> fractionalSpecificClassesAttributes =
+    new HashMap<String, List<String>>();
+
+  /**
+   * Used in fractional replication: holds attributes of any object class. When
+   * an operation coming from the network is to be locally replayed:
+   * - inclusive mode: only attributes of the matching entry not present in
+   * fractionalAllClassesAttributes will be added/deleted/modified
+   * - exclusive mode: attributes of the matching entry present in
+   * fractionalAllClassesAttributes will not be added/deleted/modified
+   * The attributes may be in human readable form of OID form.
+   */
+  private List<String> fractionalAllClassesAttributes =
+    new ArrayList<String>();
+
+  /**
+   * The list of attributes that cannot be used in fractional replication
+   * configuration.
+   */
+  private static final String[] FRACTIONAL_PROHIBITED_ATTRIBUTES = new String[]
+  {
+    "objectClass",
+    "2.5.4.0" // objectClass OID
+  };
+
+  /**
+   * When true, this flag is used to force the domain status to be put in bad
+   * data set just after the connection to the replication server.
+   * This must be used when fractional replication is enabled with a
+   * configuration different from the previous one (or at the very first
+   * fractional usage time) : after connection, a ChangeStatusMsg is sent
+   * requesting the bad data set status. Then none of the update messages
+   * received from the replication server are taken into account until the
+   * backend is synchronized with brand new data set compliant with the new
+   * fractional configuration (i.e with compliant fractional configuration in
+   * domain root entry).
+   */
+  private boolean force_bad_data_set = false;
+
+  /**
+   * This flag is used by the fractional replication ldif import plugin to
+   * stop the (online) import process if a fractional configuration
+   * inconsistency is detected by it.
+   */
+  private boolean followImport = true;
+
+  /**
+   * This is the message id to be used when an import is stopped with error by
+   * the fractional replication ldif import plugin.
+   */
+  private int importErrorMessageId = -1;
+  /**
+   * Message type for ERR_FULL_UPDATE_IMPORT_FRACTIONAL_BAD_REMOTE.
+   */
+  public static final int IMPORT_ERROR_MESSAGE_BAD_REMOTE = 1;
+  /**
+   * Message type for ERR_FULL_UPDATE_IMPORT_FRACTIONAL_REMOTE_IS_FRACTIONAL.
+   */
+  public static final int IMPORT_ERROR_MESSAGE_REMOTE_IS_FRACTIONAL = 2;
+
+  /*
+   * Definitions for the return codes of the
+   * fractionalFilterOperation(PreOperationModifyOperation
+   *  modifyOperation, boolean performFiltering) method
+   */
+  // The operation contains attributes subject to fractional filtering according
+  // to the fractional configuration
+  private static final int FRACTIONAL_HAS_FRACTIONAL_FILTERED_ATTRIBUTES = 1;
+  // The operation contains no attributes subject to fractional filtering
+  // according to the fractional configuration
+  private static final int FRACTIONAL_HAS_NO_FRACTIONAL_FILTERED_ATTRIBUTES = 2;
+  // The operation should become a no-op
+  private static final int FRACTIONAL_BECOME_NO_OP = 3;
+
+  /**
    * The thread that periodically saves the ServerState of this
    * LDAPReplicationDomain in the database.
    */
@@ -326,6 +473,9 @@
     // Get assured configuration
     readAssuredConfig(configuration, false);
 
+    // Get fractional configuration
+    readFractionalConfig(configuration, false);
+
     setGroupId((byte)configuration.getGroupId());
     setURLs(configuration.getReferralsUrl());
 
@@ -477,6 +627,1352 @@
   }
 
   /**
+   * Returns true if fractional replication is configured in this domain.
+   * @return True if fractional replication is configured in this domain.
+   */
+  public boolean isFractional()
+  {
+    return fractional;
+  }
+
+  /**
+   * Returns true if the fractional replication configuration is exclusive mode
+   * in this domain, false if inclusive mode.
+   * @return True if the fractional replication configuration is exclusive mode
+   * in this domain, false if inclusive mode.
+   */
+  public boolean isFractionalExclusive()
+  {
+    return fractionalExclusive;
+  }
+
+  /**
+   * Returns the fractional configuration for specific classes.
+   * @return The fractional configuration for specific classes.
+   */
+  public Map<String, List<String>> getFractionalSpecificClassesAttributes()
+  {
+    return fractionalSpecificClassesAttributes;
+  }
+
+  /**
+   * Returns the fractional configuration for all classes.
+   * @return The fractional configuration for all classes.
+   */
+  public List<String> getFractionalAllClassesAttributes()
+  {
+    return fractionalAllClassesAttributes;
+  }
+
+  /**
+   * Sets the error message id to be used when online import is stopped with
+   * error by the fractional replication ldif import plugin.
+   * @param importErrorMessageId The message to use.
+   */
+  public void setImportErrorMessageId(int importErrorMessageId)
+  {
+    this.importErrorMessageId = importErrorMessageId;
+  }
+
+  /**
+   * Sets the boolean telling if the online import currently in progress should
+   * continue.
+   * @param followImport The boolean telling if the online import currently in
+   * progress should continue.
+   */
+  public void setFollowImport(boolean followImport)
+  {
+    this.followImport = followImport;
+  }
+
+  /**
+   * Gets and stores the fractional replication configuration parameters.
+   * @param configuration The configuration object
+   * @param allowReconnection Tells if one must reconnect if significant changes
+   *        occurred
+   */
+  private void readFractionalConfig(ReplicationDomainCfg configuration,
+    boolean allowReconnection)
+  {
+    boolean needReconnection = false;
+
+    // Prepare fractional configuration variables to parse
+    Iterator<String> exclIt = null;
+    SortedSet<String> fractionalExclude = configuration.getFractionalExclude();
+    if (fractionalExclude != null)
+    {
+      exclIt = fractionalExclude.iterator();
+    }
+
+    Iterator<String> inclIt = null;
+    SortedSet<String> fractionalInclude = configuration.getFractionalInclude();
+    if (fractionalInclude != null)
+    {
+      inclIt = fractionalInclude.iterator();
+    }
+
+    // Get potentially new fractional configuration
+    Map<String, List<String>> newFractionalSpecificClassesAttributes =
+    new HashMap<String, List<String>>();
+    List<String> newFractionalAllClassesAttributes = new ArrayList<String>();
+
+    int newFractionalMode = NOT_FRACTIONAL;
+    try
+    {
+      newFractionalMode = parseFractionalConfig(exclIt, inclIt,
+      newFractionalSpecificClassesAttributes,
+      newFractionalAllClassesAttributes);
+    }
+    catch(ConfigException e)
+    {
+      // Should not happen as normally already called without problem in
+      // isConfigurationChangeAcceptable or isConfigurationAcceptable
+      // if we come up to this method
+      Message message = NOTE_ERR_FRACTIONAL.get(baseDn.toString(),
+        e.getLocalizedMessage());
+      logError(message);
+      return;
+    }
+
+    /**
+     * Is there any change in fractional configuration ?
+     */
+    // Compute current configuration
+    int fractionalMode = fractionalConfigToInt();
+     try
+    {
+      needReconnection = !isFractionalConfigEquivalent(fractionalMode,
+        fractionalSpecificClassesAttributes, fractionalAllClassesAttributes,
+        newFractionalMode, newFractionalSpecificClassesAttributes,
+        newFractionalAllClassesAttributes);
+    }
+    catch  (ConfigException e)
+    {
+      // Should not happen
+      Message message = NOTE_ERR_FRACTIONAL.get(baseDn.toString(),
+        e.getLocalizedMessage());
+      logError(message);
+      return;
+    }
+
+    // Disable service if configuration changed
+    if (needReconnection && allowReconnection)
+      disableService();
+
+    // Set new configuration
+    fractional = (newFractionalMode != NOT_FRACTIONAL);
+    if (fractional)
+    {
+      // Set new fractional configuration values
+      if (newFractionalMode == EXCLUSIVE_FRACTIONAL)
+        fractionalExclusive = true;
+      else
+        fractionalExclusive = false;
+      fractionalSpecificClassesAttributes =
+        newFractionalSpecificClassesAttributes;
+      fractionalAllClassesAttributes = newFractionalAllClassesAttributes;
+    } else
+    {
+      // Reset default values
+      fractionalExclusive = true;
+      fractionalSpecificClassesAttributes =
+        new HashMap<String, List<String>>();
+      fractionalAllClassesAttributes =
+        new ArrayList<String>();
+    }
+
+    // Reconnect if required
+    if (needReconnection && allowReconnection)
+      enableService();
+  }
+
+  /**
+   * Return true if the fractional configuration stored in the domain root
+   * entry of the backend is equivalent to the fractional configuration stored
+   * in the local variables.
+   */
+  private boolean isBackendFractionalConfigConsistent()
+  {
+    /*
+     * Read config stored in domain root entry
+     */
+
+    if (debugEnabled())
+      TRACER.debugInfo(
+        "Attempt to read the potential fractional config in domain root " +
+        "entry " + baseDn.toString());
+
+    ByteString asn1BaseDn = ByteString.valueOf(baseDn.toString());
+    boolean found = false;
+    LDAPFilter filter;
+    try
+    {
+      filter = LDAPFilter.decode("objectclass=*");
+    } catch (LDAPException e)
+    {
+      // Can not happen
+      return false;
+    }
+
+    /*
+     * Search the domain root entry that is used to save the generation id
+     */
+
+    InternalSearchOperation search = null;
+    LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
+    attributes.add(REPLICATION_GENERATION_ID);
+    attributes.add(REPLICATION_FRACTIONAL_EXCLUDE);
+    attributes.add(REPLICATION_FRACTIONAL_INCLUDE);
+    search = conn.processSearch(asn1BaseDn,
+      SearchScope.BASE_OBJECT,
+      DereferencePolicy.DEREF_ALWAYS, 0, 0, false,
+      filter, attributes);
+    if (((search.getResultCode() != ResultCode.SUCCESS)) &&
+      ((search.getResultCode() != ResultCode.NO_SUCH_OBJECT)))
+    {
+      Message message = ERR_SEARCHING_GENERATION_ID.get(
+        search.getResultCode().getResultCodeName() + " " +
+        search.getErrorMessage(),
+        baseDn.toString());
+      logError(message);
+      return false;
+    }
+
+    SearchResultEntry resultEntry = null;
+    if (search.getResultCode() == ResultCode.SUCCESS)
+    {
+      LinkedList<SearchResultEntry> result = search.getSearchEntries();
+      resultEntry = result.getFirst();
+      if (resultEntry != null)
+      {
+        AttributeType synchronizationGenIDType =
+          DirectoryServer.getAttributeType(REPLICATION_GENERATION_ID);
+        List<Attribute> attrs =
+          resultEntry.getAttribute(synchronizationGenIDType);
+        if (attrs != null)
+        {
+          Attribute attr = attrs.get(0);
+          if (attr.size() > 1)
+          {
+            Message message = ERR_LOADING_GENERATION_ID.get(
+              baseDn.toString(), "#Values=" + attr.size() +
+              " Must be exactly 1 in entry " +
+              resultEntry.toLDIFString());
+            logError(message);
+          } else if (attr.size() == 1)
+          {
+            found = true;
+          }
+        }
+      }
+    }
+
+    if (!found)
+    {
+      // The backend is probably empty: if there is some fractional
+      // configuration in memory, we do not let the domain being connected,
+      // otherwise, it's ok
+      if (fractional)
+      {
+        return false;
+      }
+      else
+      {
+        return true;
+      }
+    }
+
+    /*
+     * Now extract fractional configuration if any
+     */
+
+    Iterator<String> exclIt = null;
+    AttributeType fractionalExcludeType =
+      DirectoryServer.getAttributeType(REPLICATION_FRACTIONAL_EXCLUDE);
+    List<Attribute> exclAttrs =
+      resultEntry.getAttribute(fractionalExcludeType);
+    if (exclAttrs != null)
+    {
+      Attribute exclAttr = exclAttrs.get(0);
+      if (exclAttr != null)
+      {
+        exclIt = new AttributeValueStringIterator(exclAttr.iterator());
+      }
+    }
+
+    Iterator<String> inclIt = null;
+    AttributeType fractionalIncludeType =
+      DirectoryServer.getAttributeType(REPLICATION_FRACTIONAL_INCLUDE);
+    List<Attribute> inclAttrs =
+      resultEntry.getAttribute(fractionalIncludeType);
+    if (inclAttrs != null)
+    {
+      Attribute inclAttr = inclAttrs.get(0);
+      if (inclAttr != null)
+      {
+        inclIt = new AttributeValueStringIterator(inclAttr.iterator());
+      }
+    }
+
+    // Compare backend and local fractional configuration
+    return isFractionalConfigConsistent(exclIt, inclIt);
+  }
+
+  /**
+   * Return true if the fractional configuration passed as fractional
+   * configuration attribute values is equivalent to the fractional
+   * configuration stored in the local variables.
+   * @param exclIt Fractional exclude mode configuration attribute values to
+   * analyze.
+   * @param inclIt Fractional include mode configuration attribute values to
+   * analyze.
+   * @return True if the fractional configuration passed as fractional
+   * configuration attribute values is equivalent to the fractional
+   * configuration stored in the local variables.
+   */
+  public boolean isFractionalConfigConsistent(Iterator<String> exclIt,
+    Iterator<String> inclIt)
+  {
+    /*
+     * Parse fractional configuration stored in passed fractional configuration
+     * attributes values
+     */
+
+    Map<String, List<String>> storedFractionalSpecificClassesAttributes =
+      new HashMap<String, List<String>>();
+    List<String> storedFractionalAllClassesAttributes = new ArrayList<String>();
+
+    int storedFractionalMode = NOT_FRACTIONAL;
+    try
+    {
+      storedFractionalMode = parseFractionalConfig(exclIt, inclIt,
+        storedFractionalSpecificClassesAttributes,
+        storedFractionalAllClassesAttributes);
+    } catch (ConfigException e)
+    {
+      // Should not happen as configuration in domain root entry is flushed
+      // from valid configuration in local variables
+      Message message = NOTE_ERR_FRACTIONAL.get(baseDn.toString(),
+        e.getLocalizedMessage());
+      logError(message);
+      return false;
+    }
+
+    /*
+     * Compare configuration stored in passed fractional configuration
+     * attributes with local variable one
+     */
+
+    // Compute current configuration from local variables
+    int fractionalMode = fractionalConfigToInt();
+    try
+    {
+      return isFractionalConfigEquivalent(fractionalMode,
+        fractionalSpecificClassesAttributes, fractionalAllClassesAttributes,
+        storedFractionalMode, storedFractionalSpecificClassesAttributes,
+        storedFractionalAllClassesAttributes);
+    } catch (ConfigException e)
+    {
+      // Should not happen as configuration in domain root entry is flushed
+      // from valid configuration in local variables so both should have already
+      // been checked
+      Message message = NOTE_ERR_FRACTIONAL.get(baseDn.toString(),
+        e.getLocalizedMessage());
+      logError(message);
+      return false;
+    }
+  }
+
+  /**
+   * Get an integer representation of the domain fractional configuration.
+   * @return An integer representation of the domain fractional configuration.
+   */
+  public int fractionalConfigToInt()
+  {
+    int fractionalMode = -1;
+    if (fractional)
+    {
+      if (fractionalExclusive)
+        fractionalMode = EXCLUSIVE_FRACTIONAL;
+      else
+        fractionalMode = INCLUSIVE_FRACTIONAL;
+    } else
+    {
+      fractionalMode = NOT_FRACTIONAL;
+    }
+    return fractionalMode;
+  }
+
+  /**
+   * Utility class to have get a sting iterator from an AtributeValue iterator.
+   * Assuming the attribute values are strings.
+   */
+  public static class AttributeValueStringIterator implements Iterator<String>
+  {
+    private Iterator<AttributeValue> attrValIt = null;
+
+
+    /**
+     * Creates a new AttributeValueStringIterator object.
+     * @param attrValIt The underlying attribute iterator to use, assuming
+     * internal values are strings.
+     */
+    public AttributeValueStringIterator(Iterator<AttributeValue> attrValIt)
+    {
+      this.attrValIt = attrValIt;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean hasNext()
+    {
+      return attrValIt.hasNext();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String next()
+    {
+      return attrValIt.next().getValue().toString();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    // Should not be needed anyway
+    public void remove()
+    {
+      attrValIt.remove();
+    }
+  }
+
+  /**
+   * Compare 2 fractional replication configurations and returns true if they
+   * are equivalent.
+   * @param mode1 Fractional mode 1
+   * @param specificClassesAttributes1 Specific classes attributes 1
+   * @param allClassesAttributes1 All classes attributes 1
+   * @param mode2 Fractional mode 1
+   * @param specificClassesAttributes2 Specific classes attributes 2
+   * @param allClassesAttributes2 Fractional mode 2
+   * @return True if both configurations are equivalent.
+   * @throws ConfigException If some classes or attributes could not be
+   * retrieved from the schema.
+   */
+  private static boolean isFractionalConfigEquivalent(int mode1,
+    Map<String, List<String>> specificClassesAttributes1,
+    List<String> allClassesAttributes1, int mode2,
+    Map<String, List<String>> specificClassesAttributes2,
+    List<String> allClassesAttributes2) throws ConfigException
+  {
+    // Compare modes
+    if (mode1 != mode2)
+      return false;
+
+    // Compare all classes attributes
+    if (!isAttributeListEquivalent(allClassesAttributes1,
+      allClassesAttributes2))
+            return false;
+
+    // Compare specific classes attributes
+    if (specificClassesAttributes1.size() != specificClassesAttributes2.size())
+      return false;
+
+    // Check consistency of specific classes attributes
+    /*
+     * For each class in specificClassesAttributes1, check that the attribute
+     * list is equivalent to specificClassesAttributes2 attribute list
+     */
+    Schema schema = DirectoryServer.getSchema();
+    for (String className1 : specificClassesAttributes1.keySet())
+    {
+      // Get class from specificClassesAttributes1
+      ObjectClass objectClass1 = schema.getObjectClass(className1);
+      if (objectClass1 == null)
+      {
+        throw new ConfigException(
+          NOTE_ERR_FRACTIONAL_CONFIG_UNKNOWN_OBJECT_CLASS.get(className1));
+      }
+
+      // Look for matching one in specificClassesAttributes2
+      boolean foundClass = false;
+      for (String className2 : specificClassesAttributes2.keySet())
+      {
+        ObjectClass objectClass2 = schema.getObjectClass(className2);
+        if (objectClass2 == null)
+        {
+          throw new ConfigException(
+            NOTE_ERR_FRACTIONAL_CONFIG_UNKNOWN_OBJECT_CLASS.get(className2));
+        }
+        if (objectClass1.equals(objectClass2))
+        {
+          foundClass = true;
+          // Now compare the 2 attribute lists
+          List<String> attributes1 = specificClassesAttributes1.get(className1);
+          List<String> attributes2 = specificClassesAttributes2.get(className2);
+          if (!isAttributeListEquivalent(attributes1, attributes2))
+            return false;
+          break;
+        }
+      }
+      // Found matching class ?
+      if (!foundClass)
+        return false;
+    }
+
+    return true;
+  }
+
+  /**
+   * Compare 2 attribute lists and returns true if they are equivalent.
+   * @param attributes1 First attribute list to compare.
+   * @param attributes2 Second attribute list to compare.
+   * @return True if both attribute lists are equivalent.
+   * @throws ConfigException If some attributes could not be retrieved from the
+   * schema.
+   */
+  private static boolean isAttributeListEquivalent(
+    List<String> attributes1, List<String> attributes2) throws ConfigException
+  {
+    // Compare all classes attributes
+    if (attributes1.size() != attributes2.size())
+      return false;
+
+    // Check consistency of all classes attributes
+    Schema schema = DirectoryServer.getSchema();
+    /*
+     * For each attribute in attributes1, check there is the matching
+     * one in attributes2.
+     */
+    for (String attributName1 : attributes1)
+    {
+      // Get attribute from attributes1
+      AttributeType attributeType1 = schema.getAttributeType(attributName1);
+      if (attributeType1 == null)
+      {
+        throw new ConfigException(
+          NOTE_ERR_FRACTIONAL_CONFIG_UNKNOWN_ATTRIBUTE_TYPE.get(attributName1));
+      }
+      // Look for matching one in attributes2
+      boolean foundAttribute = false;
+      for (String attributName2 : attributes2)
+      {
+        AttributeType attributeType2 = schema.getAttributeType(attributName2);
+        if (attributeType2 == null)
+        {
+          throw new ConfigException(
+            NOTE_ERR_FRACTIONAL_CONFIG_UNKNOWN_ATTRIBUTE_TYPE.get(
+            attributName2));
+        }
+        if (attributeType1.equals(attributeType2))
+        {
+          foundAttribute = true;
+          break;
+        }
+      }
+      // Found matching attribute ?
+      if (!foundAttribute)
+        return false;
+    }
+
+    return true;
+  }
+
+
+  /**
+   * Parses a fractional replication configuration, filling the empty passed
+   * variables and returning the used fractional mode. The 2 passed variables to
+   * fill should be initialized (not null) and empty.
+   * @param exclIt The list of fractional exclude configuration values (may be
+   *               null)
+   * @param inclIt The list of fractional include configuration values (may be
+   *               null)
+   * @param fractionalSpecificClassesAttributes An empty map to be filled with
+   *        what is read from the fractional configuration properties.
+   * @param fractionalAllClassesAttributes An empty list to be filled with what
+   *        is read from the fractional configuration properties.
+   * @return the fractional mode deduced from the passed configuration:
+   *         not fractional, exclusive fractional or inclusive fractional modes
+   */
+  private static int parseFractionalConfig (
+    Iterator<String> exclIt, Iterator<String> inclIt,
+    Map<String, List<String>> fractionalSpecificClassesAttributes,
+    List<String> fractionalAllClassesAttributes) throws ConfigException
+  {
+    int fractional_mode = NOT_FRACTIONAL;
+
+    // Determine if fractional-exclude or fractional-include property is used
+    // : only one of them is allowed
+    Iterator<String> fracConfIt = null;
+
+    // Deduce the wished fractional mode
+    if ((exclIt != null) && exclIt.hasNext())
+    {
+      if ((inclIt != null) && inclIt.hasNext())
+      {
+        throw new ConfigException(NOTE_ERR_FRACTIONAL_CONFIG_BOTH_MODES.get());
+      }
+      else
+      {
+        fractional_mode = EXCLUSIVE_FRACTIONAL;
+        fracConfIt = exclIt;
+      }
+    }
+    else
+    {
+      if ((inclIt != null) && inclIt.hasNext())
+      {
+        fractional_mode = INCLUSIVE_FRACTIONAL;
+        fracConfIt = inclIt;
+      }
+      else
+      {
+        return NOT_FRACTIONAL;
+      }
+    }
+
+    while (fracConfIt.hasNext())
+    {
+      // Parse a value with the form class:attr1,attr2...
+      // or *:attr1,attr2...
+      String fractCfgStr = fracConfIt.next();
+      StringTokenizer st = new StringTokenizer(fractCfgStr, ":");
+      int nTokens = st.countTokens();
+      if (nTokens < 2)
+      {
+        throw new ConfigException(NOTE_ERR_FRACTIONAL_CONFIG_WRONG_FORMAT.
+          get(fractCfgStr));
+      }
+      // Get the class name
+      String classNameLower = st.nextToken().toLowerCase();
+      boolean allClasses = classNameLower.equals("*");
+      // Get the attributes
+      String attributes = st.nextToken();
+      st = new StringTokenizer(attributes, ",");
+      while (st.hasMoreTokens())
+      {
+        String attrNameLower = st.nextToken().toLowerCase();
+        // Store attribute in the appropriate variable
+        if (allClasses)
+        {
+          // Avoid duplicate attributes
+          if (!fractionalAllClassesAttributes.contains(attrNameLower))
+          {
+            fractionalAllClassesAttributes.add(attrNameLower);
+          }
+        }
+        else
+        {
+          List<String> attrList =
+            fractionalSpecificClassesAttributes.get(classNameLower);
+          if (attrList != null)
+          {
+            // Avoid duplicate attributes
+            if (!attrList.contains(attrNameLower))
+            {
+              attrList.add(attrNameLower);
+            }
+          } else
+          {
+            attrList = new ArrayList<String>();
+            attrList.add(attrNameLower);
+            fractionalSpecificClassesAttributes.put(classNameLower, attrList);
+          }
+        }
+      }
+    }
+    return fractional_mode;
+  }
+
+  /**
+   * Check that the passed fractional configuration is acceptable
+   * regarding configuration syntax, schema constraints...
+   * Throws an exception if the configuration is not acceptable.
+   * @param configuration The configuration to analyze.
+   * @throws org.opends.server.config.ConfigException if the configuration is
+   * not acceptable.
+   */
+  private static void isFractionalConfigAcceptable(
+    ReplicationDomainCfg configuration) throws ConfigException
+  {
+    /*
+     * Parse fractional configuration
+     */
+
+    // Prepare fractional configuration variables to parse
+    Iterator<String> exclIt = null;
+    SortedSet<String> fractionalExclude = configuration.getFractionalExclude();
+    if (fractionalExclude != null)
+    {
+      exclIt = fractionalExclude.iterator();
+    }
+
+    Iterator<String> inclIt = null;
+    SortedSet<String> fractionalInclude = configuration.getFractionalInclude();
+    if (fractionalInclude != null)
+    {
+      inclIt = fractionalInclude.iterator();
+    }
+
+    // Prepare variables to be filled with config
+    Map<String, List<String>> newFractionalSpecificClassesAttributes =
+    new HashMap<String, List<String>>();
+    List<String> newFractionalAllClassesAttributes = new ArrayList<String>();
+
+    int fractionalMode = parseFractionalConfig(exclIt, inclIt,
+      newFractionalSpecificClassesAttributes,
+      newFractionalAllClassesAttributes);
+
+    switch (fractionalMode)
+    {
+      case NOT_FRACTIONAL:
+        // Nothing to check
+        return;
+      case EXCLUSIVE_FRACTIONAL:
+      case INCLUSIVE_FRACTIONAL:
+        // Ok, checking done out of the switch statement
+        break;
+      default:
+      // Should not happen
+        return;
+    }
+
+    /*
+     * Check attributes consistency : we only allow to filter MAY (optional)
+     * attributes of a class : to be compliant with the schema, no MUST
+     * (mandatory) attribute can be filtered by fractional replication.
+     */
+
+    // Check consistency of specific classes attributes
+    Schema schema = DirectoryServer.getSchema();
+    for (String className : newFractionalSpecificClassesAttributes.keySet())
+    {
+      // Does the class exist ?
+      ObjectClass fractionalClass = schema.getObjectClass(
+        className.toLowerCase());
+      if (fractionalClass == null)
+      {
+        throw new ConfigException(
+          NOTE_ERR_FRACTIONAL_CONFIG_UNKNOWN_OBJECT_CLASS.get(className));
+      }
+
+      boolean isExtensibleObjectClass = className.
+        equalsIgnoreCase("extensibleObject");
+
+      List<String> attributes =
+        newFractionalSpecificClassesAttributes.get(className);
+
+      for (String attrName : attributes)
+      {
+        // Not a prohibited attribute ?
+        if (isFractionalProhibitedAttr(attrName))
+        {
+          throw new ConfigException(
+            NOTE_ERR_FRACTIONAL_CONFIG_PROHIBITED_ATTRIBUTE.get(attrName));
+        }
+
+        // Does the attribute exist ?
+        AttributeType attributeType = schema.getAttributeType(attrName);
+        if (attributeType != null)
+        {
+          // No more checking for the extensibleObject class
+          if (!isExtensibleObjectClass)
+          {
+            if (fractionalMode == EXCLUSIVE_FRACTIONAL)
+            {
+              // Exclusive mode : the attribute must be optional
+              if (!fractionalClass.isOptional(attributeType))
+              {
+                throw new ConfigException(
+                  NOTE_ERR_FRACTIONAL_CONFIG_NOT_OPTIONAL_ATTRIBUTE.
+                  get(attrName, className));
+              }
+            }
+          }
+        }
+        else
+        {
+          throw new ConfigException(
+            NOTE_ERR_FRACTIONAL_CONFIG_UNKNOWN_ATTRIBUTE_TYPE.get(attrName));
+        }
+      }
+
+    }
+
+    // Check consistency of all classes attributes
+    for (String attrName : newFractionalAllClassesAttributes)
+    {
+      // Not a prohibited attribute ?
+      if (isFractionalProhibitedAttr(attrName))
+      {
+        throw new ConfigException(
+          NOTE_ERR_FRACTIONAL_CONFIG_PROHIBITED_ATTRIBUTE.get(attrName));
+      }
+
+      // Does the attribute exist ?
+      if (schema.getAttributeType(attrName) == null)
+      {
+        throw new ConfigException(
+          NOTE_ERR_FRACTIONAL_CONFIG_UNKNOWN_ATTRIBUTE_TYPE.get(attrName));
+      }
+    }
+  }
+
+  /**
+   * Test if the passed attribute is not allowed to be used in configuration of
+   * fractional replication.
+   * @param attr Attribute to test.
+   * @return true if the attribute is prohibited.
+   */
+  private static boolean isFractionalProhibitedAttr(String attr)
+  {
+    for (String forbiddenAttr : FRACTIONAL_PROHIBITED_ATTRIBUTES)
+    {
+      if (forbiddenAttr.equalsIgnoreCase(attr))
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * If fractional replication is enabled, this analyzes the operation and
+   * suppresses the forbidden attributes in it so that they are not added in
+   * the local backend.
+   *
+   * @param addOperation The operation to modify based on fractional
+   * replication configuration
+   * @param performFiltering Tells if the effective attribute filtering should
+   * be performed or if the call is just to analyze if there are some
+   * attributes filtered by fractional configuration
+   * @return true if the operation contains some attributes subject to filtering
+   * by the fractional configuration
+   */
+  public boolean fractionalFilterOperation(
+    PreOperationAddOperation addOperation, boolean performFiltering)
+  {
+    return fractionalRemoveAttributesFromEntry(
+      addOperation.getEntryDN().getRDN(), addOperation.getObjectClasses(),
+      addOperation.getUserAttributes(), performFiltering);
+  }
+
+  /**
+   * If fractional replication is enabled, this analyzes the operation and
+   * suppresses the forbidden attributes in it so that they are not added in
+   * the local backend.
+   *
+   * @param modifyDNOperation The operation to modify based on fractional
+   * replication configuration
+   * @param performFiltering Tells if the effective modifications should
+   * be performed or if the call is just to analyze if there are some
+   * inconsistency with fractional configuration
+   * @return true if the operation is inconsistent with fractional configuration
+   */
+  public boolean fractionalFilterOperation(
+    PreOperationModifyDNOperation modifyDNOperation, boolean performFiltering)
+  {
+    boolean inconsistentOperation = false;
+
+    // Quick exit if not called for analyze and
+    if (performFiltering)
+    {
+      if (modifyDNOperation.deleteOldRDN())
+      {
+        // The core will remove any occurence of attribute that was part of the
+        // old RDN, nothing more to do.
+        return true; // Will not be used as analyze was not requested
+      }
+    }
+
+    /*
+     * Create a list of filtered attributes for this entry
+     */
+
+    Entry concernedEntry = modifyDNOperation.getOriginalEntry();
+    List<String> fractionalConcernedAttributes =
+      createFractionalConcernedAttrList(
+      concernedEntry.getObjectClasses().keySet());
+
+    if ( fractionalExclusive && (fractionalConcernedAttributes.size() == 0) )
+      // No attributes to filter
+      return false;
+
+    /**
+     * Analyze the old and new rdn to see if they are some attributes to be
+     * removed: if the oldnRDN contains some forbidden attributes (for instance
+     * it is possible if the entry was created with an add operation and the
+     * RDN used contains a forbidden attribute: in this case the attribute value
+     * has been kept to be consistent with the dn of the entry.) that are no
+     * more part of the new RDN, we must remove any attribute of this type by
+     * putting a modification to delete the attribute.
+     */
+
+    RDN rdn = modifyDNOperation.getEntryDN().getRDN();
+    RDN newRdn = modifyDNOperation.getNewRDN();
+
+    // Go through each attribute of the old RDN
+    for (int i=0 ; i<rdn.getNumValues() ; i++)
+    {
+      AttributeType attributeType = rdn.getAttributeType(i);
+      boolean found = false;
+      // Is it present in the fractional attributes established list ?
+      for (String attrTypeStr : fractionalConcernedAttributes)
+      {
+        AttributeType attributeTypeFromList =
+        DirectoryServer.getAttributeType(attrTypeStr);
+        if (attributeTypeFromList.equals(attributeType))
+        {
+          found = true;
+          break;
+        }
+      }
+      boolean attributeToBeFiltered = ( (fractionalExclusive && found) ||
+        (!fractionalExclusive && !found) );
+      if (attributeToBeFiltered &&
+        !newRdn.hasAttributeType(attributeType) &&
+        !modifyDNOperation.deleteOldRDN())
+      {
+        // A forbidden attribute is in the old RDN and no more in the new RDN,
+        // and it has not been requested to remove attributes from old RDN:
+        // remove ourself the attribute from the entry to stay consistent with
+        // fractional configuration
+        Modification modification = new Modification(ModificationType.DELETE,
+          Attributes.empty(attributeType));
+        modifyDNOperation.addModification(modification);
+        inconsistentOperation = true;
+      }
+    }
+
+    return inconsistentOperation;
+  }
+
+  /**
+   * Remove attributes from an entry, according to the current fractional
+   * configuration. The entry is represented by the 2 passed parameters.
+   * The attributes to be removed are removed using the remove method on the
+   * passed iterator for the attributes in the entry.
+   * @param entryRdn The rdn of the entry to add
+   * @param classes The object classes representing the entry to modify
+   * @param attributesMap The map of attributes/values to be potentially removed
+   * from the entry.
+   * @param performFiltering Tells if the effective attribute filtering should
+   * be performed or if the call is just an analyze to see if there are some
+   * attributes filtered by fractional configuration
+   * @return true if the operation contains some attributes subject to filtering
+   * by the fractional configuration
+   */
+  public boolean fractionalRemoveAttributesFromEntry(RDN entryRdn,
+    Map<ObjectClass,String> classes, Map<AttributeType, List<Attribute>>
+    attributesMap, boolean performFiltering)
+  {
+    boolean hasSomeAttributesToFilter = false;
+    /*
+     * Prepare a list of attributes to be included/excluded according to the
+     * fractional replication configuration
+     */
+
+    List<String> fractionalConcernedAttributes =
+      createFractionalConcernedAttrList(classes.keySet());
+    if ( fractionalExclusive && (fractionalConcernedAttributes.size() == 0) )
+      return false; // No attributes to filter
+
+    // Prepare list of object classes of the added entry
+    Set<ObjectClass> entryClasses = classes.keySet();
+
+    /*
+     * Go through the user attributes and remove those that match filtered one
+     * - exclude mode : remove only attributes that are in
+     * fractionalConcernedAttributes
+     * - include mode : remove any attribute that is not in
+     * fractionalConcernedAttributes
+     */
+    Iterator<AttributeType> attributeTypes = attributesMap.keySet().iterator();
+    List<List<Attribute>> newRdnAttrLists = new ArrayList<List<Attribute>>();
+    List<AttributeType> rdnAttrTypes = new ArrayList<AttributeType>();
+    while (attributeTypes.hasNext())
+    {
+      AttributeType attributeType = attributeTypes.next();
+
+      // Only optional attributes may be removed
+      boolean isMandatoryAttribute = false;
+      for (ObjectClass objectClass : entryClasses)
+      {
+        if (objectClass.isRequired(attributeType))
+        {
+          isMandatoryAttribute = true;
+          break;
+        }
+      }
+      if (isMandatoryAttribute)
+      {
+        continue;
+      }
+
+      String attributeName = attributeType.getPrimaryName();
+      String attributeOid = attributeType.getOID();
+      // Do not remove an attribute if it is a prohibited one
+      if (((attributeName != null) &&
+        isFractionalProhibitedAttr(attributeName)) ||
+        isFractionalProhibitedAttr(attributeOid))
+      {
+        continue;
+      }
+
+      // Is the current attribute part of the established list ?
+      boolean foundAttribute =
+        fractionalConcernedAttributes.contains(attributeName.toLowerCase());
+      if (!foundAttribute)
+      {
+        foundAttribute =
+          fractionalConcernedAttributes.contains(attributeOid);
+      }
+      // Now remove the attribute if:
+      // - exclusive mode and attribute is in configuration
+      // - inclusive mode and attribute is not in configuration
+      if ((foundAttribute && fractionalExclusive) ||
+        (!foundAttribute && !fractionalExclusive))
+      {
+        if (performFiltering)
+        {
+          // Do not remove an attribute/value that is part of the RDN of the
+          // entry as it is forbidden
+          if (entryRdn.hasAttributeType(attributeType))
+          {
+            // We must remove all values of the attributes map for this
+            // attribute type but the one that has the value which is in the RDN
+            // of the entry. In fact the (underlying )attribute list does not
+            // suppot remove so we have to create a new list, keeping only the
+            // attribute value which is the same as in the RDN
+            AttributeValue rdnAttributeValue =
+              entryRdn.getAttributeValue(attributeType);
+            List<Attribute> attrList = attributesMap.get(attributeType);
+            Iterator<Attribute> attrIt = attrList.iterator();
+            AttributeValue sameAttrValue = null;
+            //    Locate the attribute value identical to the one in the RDN
+            while(attrIt.hasNext())
+            {
+              Attribute attr = attrIt.next();
+              if (attr.contains(rdnAttributeValue))
+              {
+                Iterator<AttributeValue> attrValues = attr.iterator();
+                while(attrValues.hasNext())
+                {
+                  AttributeValue attrValue = attrValues.next();
+                  if (rdnAttributeValue.equals(attrValue))
+                  {
+                    // Keep the value we want
+                    sameAttrValue = attrValue;
+                  }
+                  else
+                  {
+                    hasSomeAttributesToFilter = true;
+                  }
+                }
+              }
+              else
+              {
+                hasSomeAttributesToFilter = true;
+              }
+            }
+            //    Recreate the attribute list with only the RDN attribute value
+            if (sameAttrValue != null)
+              // Paranoia check: should never be the case as we should always
+              // find the attribute/value pair matching the pair in the RDN
+            {
+              // Construct and store new atribute list
+              List<Attribute> newRdnAttrList = new ArrayList<Attribute>();
+              AttributeBuilder attrBuilder =
+                new AttributeBuilder(attributeType);
+              attrBuilder.add(sameAttrValue);
+              newRdnAttrList.add(attrBuilder.toAttribute());
+              newRdnAttrLists.add(newRdnAttrList);
+              // Store matching attribute type
+              // The mapping will be done using object from rdnAttrTypes as key
+              // and object from newRdnAttrLists (at same index) as value in
+              // the user attribute map to be modified
+              rdnAttrTypes.add(attributeType);
+            }
+          }
+          else
+          {
+            // Found an attribute to remove, remove it from the list.
+            attributeTypes.remove();
+            hasSomeAttributesToFilter = true;
+          }
+        }
+        else
+        {
+          // The call was just to check : at least one attribute to filter
+          // found, return immediatly the answer;
+          return true;
+        }
+      }
+    }
+    // Now overwrite the attribute values for the attribute types present in the
+    // RDN, if there are some filtered attributes in the RDN
+    int index = 0;
+    for (index = 0 ; index < rdnAttrTypes.size() ; index++)
+    {
+      attributesMap.put(rdnAttrTypes.get(index), newRdnAttrLists.get(index));
+    }
+    return hasSomeAttributesToFilter;
+  }
+
+  /**
+   * Prepares a list of attributes of interest for the fractional feature.
+   * @param entryObjectClasses The object classes of an entry on which an
+   * operation is going to be performed.
+   * @return The list of attributes of the entry to be excluded/included
+   * when the operation will be performed.
+   */
+  private List<String> createFractionalConcernedAttrList(
+    Set<ObjectClass> entryObjectClasses)
+  {
+    /*
+     * Is the concerned entry of a type concerned by fractional replication
+     * configuration ? If yes, add the matching attribute names to a list of
+     * attributes to take into account for filtering
+     * (inclusive or exclusive mode)
+     */
+
+    List<String> fractionalConcernedAttributes = new ArrayList<String>();
+
+    // Get object classes the entry matches
+    Set<String> fractionalClasses =
+        fractionalSpecificClassesAttributes.keySet();
+    for (ObjectClass entryObjectClass : entryObjectClasses)
+    {
+      for(String fractionalClass : fractionalClasses)
+      {
+        if (entryObjectClass.hasNameOrOID(fractionalClass.toLowerCase()))
+        {
+          List<String> attrList =
+            fractionalSpecificClassesAttributes.get(fractionalClass);
+          for(String attr : attrList)
+          {
+            // Avoid duplicate attributes (from 2 inheriting classes for
+            // instance)
+            if (!fractionalConcernedAttributes.contains(attr))
+            {
+              fractionalConcernedAttributes.add(attr);
+            }
+          }
+        }
+      }
+    }
+
+    /*
+     * Add to the list any attribute which is class independent
+     */
+    for (String attr : fractionalAllClassesAttributes)
+    {
+      if (!fractionalConcernedAttributes.contains(attr))
+      {
+        fractionalConcernedAttributes.add(attr);
+      }
+    }
+
+    return fractionalConcernedAttributes;
+  }
+
+  /**
+   * If fractional replication is enabled, this analyzes the operation and
+   * suppresses the forbidden attributes in it so that they are not added/
+   * deleted/modified in the local backend.
+   *
+   * @param modifyOperation The operation to modify based on fractional
+   * replication configuration
+   * @param performFiltering Tells if the effective attribute filtering should
+   * be performed or if the call is just to analyze if there are some
+   * attributes filtered by fractional configuration
+   * @return FRACTIONAL_HAS_FRACTIONAL_FILTERED_ATTRIBUTES,
+   * FRACTIONAL_HAS_NO_FRACTIONAL_FILTERED_ATTRIBUTES or FRACTIONAL_BECOME_NO_OP
+   */
+  public int fractionalFilterOperation(PreOperationModifyOperation
+    modifyOperation, boolean performFiltering)
+  {
+    int result = FRACTIONAL_HAS_NO_FRACTIONAL_FILTERED_ATTRIBUTES;
+    /*
+     * Prepare a list of attributes to be included/excluded according to the
+     * fractional replication configuration
+     */
+
+    Entry modifiedEntry = modifyOperation.getCurrentEntry();
+    List<String> fractionalConcernedAttributes =
+      createFractionalConcernedAttrList(
+      modifiedEntry.getObjectClasses().keySet());
+    if ( fractionalExclusive && (fractionalConcernedAttributes.size() == 0) )
+      // No attributes to filter
+      return FRACTIONAL_HAS_NO_FRACTIONAL_FILTERED_ATTRIBUTES;
+
+    // Prepare list of object classes of the modified entry
+    DN entryToModifyDn = modifyOperation.getEntryDN();
+    Entry entryToModify = null;
+    try
+    {
+      entryToModify = DirectoryServer.getEntry(entryToModifyDn);
+    }
+    catch(DirectoryException e)
+    {
+      Message message = NOTE_ERR_FRACTIONAL.get(baseDn.toString(),
+        e.getLocalizedMessage());
+      logError(message);
+      return FRACTIONAL_HAS_NO_FRACTIONAL_FILTERED_ATTRIBUTES;
+    }
+    Set<ObjectClass> entryClasses = entryToModify.getObjectClasses().keySet();
+
+    /*
+     * Now go through the attribute modifications and filter the mods according
+     * to the fractional configuration (using the just established concerned
+     * attributes list):
+     * - delete attributes: remove them if regarding a filtered attribute
+     * - add attributes: remove them if regarding a filtered attribute
+     * - modify attributes: remove them if regarding a filtered attribute
+     */
+
+    List<Modification> mods = modifyOperation.getModifications();
+    Iterator<Modification> modsIt = mods.iterator();
+    while (modsIt.hasNext())
+    {
+      Modification mod = modsIt.next();
+      Attribute attr = mod.getAttribute();
+      AttributeType attrType = attr.getAttributeType();
+      // Fractional replication ignores operational attributes
+      if (!attrType.isOperational())
+      {
+        // Only optional attributes may be removed
+        boolean isMandatoryAttribute = false;
+        for (ObjectClass objectClass : entryClasses)
+        {
+          if (objectClass.isRequired(attrType))
+          {
+            isMandatoryAttribute = true;
+            break;
+          }
+        }
+        if (isMandatoryAttribute)
+        {
+          continue;
+        }
+
+        String attributeName = attrType.getPrimaryName();
+        String attributeOid = attrType.getOID();
+        // Do not remove an attribute if it is a prohibited one
+        if (((attributeName != null) &&
+          isFractionalProhibitedAttr(attributeName)) ||
+          isFractionalProhibitedAttr(attributeOid))
+        {
+          continue;
+        }
+        // Is the current attribute part of the established list ?
+        boolean foundAttribute =
+          fractionalConcernedAttributes.contains(attributeName.toLowerCase());
+        if (!foundAttribute)
+        {
+          foundAttribute =
+            fractionalConcernedAttributes.contains(attributeOid);
+        }
+
+        // Now remove the modification if:
+        // - exclusive mode and the concerned attribute is in configuration
+        // - inclusive mode and the concerned attribute is not in configuration
+        if ( (foundAttribute && fractionalExclusive) ||
+             (!foundAttribute && !fractionalExclusive) )
+        {
+          if (performFiltering)
+          {
+            // Found a modification to remove, remove it from the list.
+            modsIt.remove();
+            result = FRACTIONAL_HAS_FRACTIONAL_FILTERED_ATTRIBUTES;
+            if (mods.size() == 0)
+            {
+              // This operation must become a no-op as no more modification in
+              // it
+              return FRACTIONAL_BECOME_NO_OP;
+            }
+          }
+          else
+          {
+            // The call was just to check : at least one attribute to filter
+            // found, return immediatly the answer;
+            return FRACTIONAL_HAS_FRACTIONAL_FILTERED_ATTRIBUTES;
+          }
+        }
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * This is overwritten to allow stopping the (online) import process by the
+   * fractional ldif import plugin when it detects that the (imported) remote
+   * data set is not consistent with the local fractional configuration.
+   * {@inheritDoc}
+   */
+  @Override
+  protected byte[] receiveEntryBytes()
+  {
+    if (followImport)
+    {
+      // Ok, next entry is allowed to be received
+      return super.receiveEntryBytes();
+    } else
+    {
+      // Fractional ldif import plugin detected inconsistency between local
+      // and remote server fractional configuration and is stopping the import
+      // process:
+      // This is an error termination during the import
+      // The error is stored and the import is ended
+      // by returning null
+      Message msg = null;
+      switch (importErrorMessageId)
+      {
+        case IMPORT_ERROR_MESSAGE_BAD_REMOTE:
+          msg = NOTE_ERR_FULL_UPDATE_IMPORT_FRACTIONAL_BAD_REMOTE.get(
+            baseDn.toString(), Short.toString(ieContext.getImportSource()));
+          break;
+        case IMPORT_ERROR_MESSAGE_REMOTE_IS_FRACTIONAL:
+          msg = NOTE_ERR_FULL_UPDATE_IMPORT_FRACTIONAL_REMOTE_IS_FRACTIONAL.get(
+            baseDn.toString(), Short.toString(ieContext.getImportSource()));
+          break;
+      }
+      ieContext.setException(
+        new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, msg));
+      return null;
+    }
+  }
+
+  /**
+   * This is overwritten to allow stopping the (online) export process if the
+   * local domain is fractional and the destination is all other servers:
+   * This make no sense to have only fractional servers in a replicated
+   * topology. This prevents from administrator manipulation error that would
+   * lead to whole topology data corruption.
+   * {@inheritDoc}
+   */
+  @Override
+  protected void initializeRemote(short target, short requestorID,
+    Task initTask) throws DirectoryException
+  {
+    if ((target == RoutableMsg.ALL_SERVERS) && fractional)
+    {
+      Message msg = NOTE_ERR_FRACTIONAL_FORBIDDEN_FULL_UPDATE_FRACTIONAL.get(
+            baseDn.toString(), Short.toString(getServerId()));
+      throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, msg);
+    } else
+    {
+      super.initializeRemote(target, requestorID, initTask);
+    }
+  }
+
+  /**
    * Returns the base DN of this ReplicationDomain.
    *
    * @return The base DN of this ReplicationDomain
@@ -580,6 +2076,38 @@
           ResultCode.UNWILLING_TO_PERFORM, msg);
     }
 
+    if (fractional)
+    {
+      if (addOperation.isSynchronizationOperation())
+      {
+        /*
+         * Filter attributes here for fractional replication. If fractional
+         * replication is enabled, we analyze the operation to suppress the
+         * forbidden attributes in it so that they are not added in the local
+         * backend. This must be called before any other plugin is called, to
+         * keep coherency across plugin calls.
+         */
+        fractionalFilterOperation(addOperation, true);
+      }
+      else
+      {
+        /*
+         * Direct access from an LDAP client : if some attributes are to be
+         * removed according to the fractional configuration, simply forbid
+         * the operation
+         */
+        if (fractionalFilterOperation(addOperation, false))
+        {
+          StringBuilder sb = new StringBuilder();
+          addOperation.toString(sb);
+          Message msg = NOTE_ERR_FRACTIONAL_FORBIDDEN_OPERATION.get(
+            baseDn.toString(), sb.toString());
+          return new SynchronizationProviderResult.StopProcessing(
+            ResultCode.UNWILLING_TO_PERFORM, msg);
+        }
+      }
+    }
+
     if (addOperation.isSynchronizationOperation())
     {
       AddContext ctx = (AddContext) addOperation.getAttachment(SYNCHROCONTEXT);
@@ -686,6 +2214,36 @@
           ResultCode.UNWILLING_TO_PERFORM, msg);
     }
 
+    if (fractional)
+    {
+      if (modifyDNOperation.isSynchronizationOperation())
+      {
+        /*
+         * Filter operation here for fractional replication. If fractional
+         * replication is enabled, we analyze the operation and modify it if
+         * necessary to stay consistent with what is defined in fractional
+         * configuration.
+         */
+        fractionalFilterOperation(modifyDNOperation, true);
+      }
+      else
+      {
+        /*
+         * Direct access from an LDAP client : something is inconsistent with
+         * the fractional configuration, forbid the operation.
+         */
+        if (fractionalFilterOperation(modifyDNOperation, false))
+        {
+          StringBuilder sb = new StringBuilder();
+          modifyDNOperation.toString(sb);
+          Message msg = NOTE_ERR_FRACTIONAL_FORBIDDEN_OPERATION.get(
+            baseDn.toString(), sb.toString());
+          return new SynchronizationProviderResult.StopProcessing(
+            ResultCode.UNWILLING_TO_PERFORM, msg);
+        }
+      }
+    }
+
     ModifyDnContext ctx =
       (ModifyDnContext) modifyDNOperation.getAttachment(SYNCHROCONTEXT);
     if (ctx != null)
@@ -775,6 +2333,51 @@
           ResultCode.UNWILLING_TO_PERFORM, msg);
     }
 
+    if (fractional)
+    {
+      if  (modifyOperation.isSynchronizationOperation())
+      {
+        /*
+         * Filter attributes here for fractional replication. If fractional
+         * replication is enabled, we analyze the operation and modify it so
+         * that no forbidden attribute is added/modified/deleted in the local
+         * backend. This must be called before any other plugin is called, to
+         * keep coherency across plugin calls.
+         */
+        if (fractionalFilterOperation(modifyOperation, true) ==
+          FRACTIONAL_BECOME_NO_OP)
+        {
+          // Every modifications filtered in this operation: the operation
+          // becomes a no-op
+          return new SynchronizationProviderResult.StopProcessing(
+            ResultCode.SUCCESS, null);
+        }
+      }
+      else
+      {
+        /*
+         * Direct access from an LDAP client : if some attributes are to be
+         * removed according to the fractional configuration, simply forbid
+         * the operation
+         */
+        switch(fractionalFilterOperation(modifyOperation, false))
+        {
+          case FRACTIONAL_HAS_NO_FRACTIONAL_FILTERED_ATTRIBUTES:
+            // Ok, let the operation happen
+            break;
+          case FRACTIONAL_HAS_FRACTIONAL_FILTERED_ATTRIBUTES:
+            // Some attributes not compliant with fractional configuration :
+            // forbid the operation
+            StringBuilder sb = new StringBuilder();
+            modifyOperation.toString(sb);
+            Message msg = NOTE_ERR_FRACTIONAL_FORBIDDEN_OPERATION.get(
+              baseDn.toString(), sb.toString());
+            return new SynchronizationProviderResult.StopProcessing(
+              ResultCode.UNWILLING_TO_PERFORM, msg);
+        }
+      }
+    }
+
     ModifyContext ctx =
       (ModifyContext) modifyOperation.getAttachment(SYNCHROCONTEXT);
 
@@ -2045,12 +3648,6 @@
   }
 
   /**
-   * The attribute name used to store the state in the backend.
-   */
-  protected static final String REPLICATION_GENERATION_ID =
-    "ds-sync-generation-id";
-
-  /**
    * Stores the value of the generationId.
    * @param generationId The value of the generationId.
    * @return a ResultCode indicating if the method was successful.
@@ -2136,7 +3733,7 @@
 
     /*
      * Search the database entry that is used to periodically
-     * save the ServerState
+     * save the generation id
      */
     InternalSearchOperation search = null;
     LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
@@ -2534,6 +4131,11 @@
         includeBranches.add(this.baseDn);
         importConfig.setIncludeBranches(includeBranches);
         importConfig.setAppendToExistingData(false);
+        // Allow fractional replication ldif import plugin to be called
+        importConfig.setInvokeImportPlugins(true);
+        // Reset the follow import flag and message before starting the import
+        importErrorMessageId = -1;
+        followImport = true;
 
         // TODO How to deal with rejected entries during the import
         importConfig.writeRejectedEntries(
@@ -2736,6 +4338,17 @@
       unacceptableReasons.add(message);
       return false;
     }
+
+    // Check fractional configuration
+    try
+    {
+      isFractionalConfigAcceptable(configuration);
+    } catch (ConfigException e)
+    {
+      unacceptableReasons.add(e.getMessageObject());
+      return false;
+    }
+
     return true;
   }
 
@@ -2756,6 +4369,9 @@
     // Read assured configuration and reconnect if needed
     readAssuredConfig(configuration, true);
 
+    // Read fractional configuration and reconnect if needed
+    readFractionalConfig(configuration, true);
+
     return new ConfigChangeResult(ResultCode.SUCCESS, false);
   }
 
@@ -2765,14 +4381,25 @@
   public boolean isConfigurationChangeAcceptable(
          ReplicationDomainCfg configuration, List<Message> unacceptableReasons)
   {
+    // Check that a import/export is not in progress
     if (this.importInProgress() || this.exportInProgress())
     {
       unacceptableReasons.add(
           NOTE_ERR_CANNOT_CHANGE_CONFIG_DURING_TOTAL_UPDATE.get());
       return false;
     }
-    else
-      return true;
+
+    // Check fractional configuration
+    try
+    {
+      isFractionalConfigAcceptable(configuration);
+    } catch (ConfigException e)
+    {
+      unacceptableReasons.add(e.getMessageObject());
+      return false;
+    }
+
+    return true;
   }
 
   /**
@@ -2827,8 +4454,25 @@
       long generationID,
       ProtocolSession session)
   {
+    // Check domain fractional configuration consistency with local
+    // configuration variables
+    force_bad_data_set = !isBackendFractionalConfigConsistent();
+
     super.sessionInitiated(
         initStatus, replicationServerState,generationID, session);
+
+    // Now for bad data set status if needed
+    if (force_bad_data_set)
+    {
+      // Go into bad data set status
+      setNewStatus(StatusMachineEvent.TO_BAD_GEN_ID_STATUS_EVENT);
+      broker.signalStatusChange(status);
+      Message message = NOTE_FRACTIONAL_BAD_DATA_SET_NEED_RESYNC.get(
+        baseDn.toString());
+      logError(message);
+      return; // Do not send changes to the replication server
+    }
+
     try
     {
       /*
@@ -3036,6 +4680,13 @@
   @Override
   public boolean processUpdate(UpdateMsg updateMsg)
   {
+    // Ignore message if fractional configuration is inconcsistent and
+    // we have been passed into bad data set status
+    if (force_bad_data_set)
+    {
+      return false;
+    }
+
     if (updateMsg instanceof LDAPUpdateMsg)
     {
       LDAPUpdateMsg msg = (LDAPUpdateMsg) updateMsg;
diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java b/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java
index a1dd7b0..94161aa 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/replication/protocol/MonitorMsg.java
@@ -78,7 +78,7 @@
       new HashMap<Short, ServerData>();
   }
 
-  SubTopoMonitorData data = new SubTopoMonitorData();;
+  SubTopoMonitorData data = new SubTopoMonitorData();
 
   /**
    * Creates a new EntryMessage.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/replication/service/ReplicationDomain.java b/opendj-sdk/opends/src/server/org/opends/server/replication/service/ReplicationDomain.java
index c87076a..fb50284 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/replication/service/ReplicationDomain.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/replication/service/ReplicationDomain.java
@@ -151,7 +151,7 @@
   /**
    * Current status for this replicated domain.
    */
-  private ServerStatus status = ServerStatus.NOT_CONNECTED_STATUS;
+  protected ServerStatus status = ServerStatus.NOT_CONNECTED_STATUS;
 
   /**
    * The tracer object for the debug logger.
@@ -176,7 +176,7 @@
    * The ReplicationBroker that is used by this ReplicationDomain to
    * connect to the ReplicationService.
    */
-  private ReplicationBroker broker = null;
+  protected ReplicationBroker broker = null;
 
   /**
    * This Map is used to store all outgoing assured messages in order
@@ -191,7 +191,7 @@
    * The context related to an import or export being processed
    * Null when none is being processed.
    */
-  private IEContext ieContext = null;
+  protected IEContext ieContext = null;
 
   /**
    * The Thread waiting for incoming update messages for this domain and pushing
@@ -788,6 +788,7 @@
             mb.append(de.getMessageObject());
             TRACER.debugInfo(Message.toString(mb.toMessage()));
             broker.publish(errorMsg);
+            logError(de.getMessageObject());
           }
         }
         else if (msg instanceof ErrorMsg)
@@ -1076,11 +1077,11 @@
    * This class contain the context related to an import or export
    * launched on the domain.
    */
-  private class IEContext
+  protected class IEContext
   {
-    // The task that initiated the operation.
+    // Theprivate task that initiated the operation.
     Task initializeTask;
-    // The target in the case of an export
+    // The destination in the case of an export
     short exportTarget = RoutableMsg.UNKNOWN_SERVER;
     // The source in the case of an import
     short importSource = RoutableMsg.UNKNOWN_SERVER;
@@ -1111,9 +1112,9 @@
 
     /**
      * Initializes the import/export counters with the provider value.
-     * @param total
-     * @param left
-     * @throws DirectoryException
+     * @param total Total number of entries to be processed.
+     * @param left Remaining number of entries to be processed.
+     * @throws DirectoryException if an error occurred.
      */
     public void setCounters(long total, long left)
       throws DirectoryException
@@ -1139,7 +1140,7 @@
     /**
      * Update the counters of the task for each entry processed during
      * an import or export.
-     * @throws DirectoryException
+     * @throws DirectoryException if an error occurred.
      */
     public void updateCounters()
       throws DirectoryException
@@ -1166,7 +1167,7 @@
      * @param  entriesDone The number of entries that were processed
      *                     since the last time this method was called.
      *
-     * @throws DirectoryException
+     * @throws DirectoryException if an error occurred.
      */
     public void updateCounters(int entriesDone)
       throws DirectoryException
@@ -1195,6 +1196,42 @@
       return new String("[ Entry count=" + this.entryCount +
                         ", Entry left count=" + this.entryLeftCount + "]");
     }
+
+    /**
+     * Gets the server id of the exporting server.
+     * @return the server id of the exporting server.
+     */
+    public short getExportTarget()
+    {
+      return exportTarget;
+    }
+
+    /**
+     * Gets the server id of the importing server.
+     * @return the server id of the importing server.
+     */
+    public short getImportSource()
+    {
+      return importSource;
+    }
+
+    /**
+     * Get the exception that occurred during the import/export.
+     * @return the exception that occurred during the import/export.
+     */
+    public DirectoryException getException()
+    {
+      return exception;
+    }
+
+    /**
+     * Set the exception that occurred during the import/export.
+     * @param exception the exception that occurred during the import/export.
+     */
+    public void setException(DirectoryException exception)
+    {
+      this.exception = exception;
+    }
   }
   /**
    * Verifies that the given string represents a valid source
@@ -1304,8 +1341,8 @@
    *
    * @exception DirectoryException When an error occurs.
    */
-  void initializeRemote(short target, short requestorID, Task initTask)
-  throws DirectoryException
+  protected void initializeRemote(short target, short requestorID,
+    Task initTask) throws DirectoryException
   {
     Message msg = NOTE_FULL_UPDATE_ENGAGED_FOR_REMOTE_START.get(
       Short.toString(serverID),
@@ -1417,14 +1454,14 @@
 
     if (ieContext != null)
     {
-      ieContext.exception = new DirectoryException(ResultCode.OTHER,
-          errorMsg.getDetails());
+      ieContext.setException(new DirectoryException(ResultCode.OTHER,
+        errorMsg.getDetails()));
 
       if (ieContext.initializeTask instanceof InitializeTask)
       {
         // Update the task that initiated the import
         ((InitializeTask)ieContext.initializeTask).
-        updateTaskCompletionState(ieContext.exception);
+        updateTaskCompletionState(ieContext.getException());
 
         releaseIEContext();
       }
@@ -1437,7 +1474,7 @@
    *
    * @return The bytes. Null when the Done or Err message has been received
    */
-  byte[] receiveEntryBytes()
+  protected byte[] receiveEntryBytes()
   {
     ReplicationMsg msg;
     while (true)
@@ -1477,9 +1514,8 @@
           // The error is stored and the import is ended
           // by returning null
           ErrorMsg errorMsg = (ErrorMsg)msg;
-          ieContext.exception = new DirectoryException(
-                                      ResultCode.OTHER,
-                                      errorMsg.getDetails());
+          ieContext.setException(new DirectoryException(ResultCode.OTHER,
+            errorMsg.getDetails()));
           return null;
         }
         else
@@ -1490,9 +1526,9 @@
       catch(Exception e)
       {
         // TODO: i18n
-        ieContext.exception = new DirectoryException(ResultCode.OTHER,
-            Message.raw("received an unexpected message type" +
-                e.getLocalizedMessage()));
+        ieContext.setException(new DirectoryException(ResultCode.OTHER,
+          Message.raw("received an unexpected message type" +
+          e.getLocalizedMessage())));
       }
     }
   }
@@ -1547,15 +1583,15 @@
   {
     // If an error was raised - like receiving an ErrorMsg
     // we just let down the export.
-    if (ieContext.exception != null)
+    if (ieContext.getException() != null)
     {
-      IOException ioe = new IOException(ieContext.exception.getMessage());
+      IOException ioe = new IOException(ieContext.getException().getMessage());
       ieContext = null;
       throw ioe;
     }
 
     EntryMsg entryMessage = new EntryMsg(
-        serverID, ieContext.exportTarget, lDIFEntry, pos, length);
+        serverID,ieContext.getExportTarget(), lDIFEntry, pos, length);
     broker.publish(entryMessage);
 
     try
@@ -1702,8 +1738,8 @@
     }
     finally
     {
-      if ((ieContext != null)  && (ieContext.exception != null))
-        de = ieContext.exception;
+      if ((ieContext != null)  && (ieContext.getException() != null))
+        de = ieContext.getException();
 
       // Update the task that initiated the import
       if ((ieContext != null ) && (ieContext.initializeTask != null))
@@ -1732,7 +1768,7 @@
    * event.
    * @param event The event that may make the status be changed
    */
-  private void setNewStatus(StatusMachineEvent event)
+  protected void setNewStatus(StatusMachineEvent event)
   {
     ServerStatus newStatus =
       StatusMachine.computeNewStatus(status, event);
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
index 6a692eb..d10664a 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/ReplicationTestCase.java
@@ -1202,4 +1202,34 @@
       throw new Exception("Entry: " + dn + " Could not be found.");
     return found;
   }
+
+  /**
+   * Utility method : removes a domain deleting the passed config entry
+   */
+  protected void removeDomain(Entry domainCfgEntry)
+  {
+    DeleteOperationBasis op;
+    // Delete entries
+    try
+    {
+      DN dn = domainCfgEntry.getDN();
+
+      logError(Message.raw(Category.SYNC, Severity.NOTICE,
+        "cleaning config entry " + dn));
+
+      op = new DeleteOperationBasis(connection, InternalClientConnection.
+        nextOperationID(), InternalClientConnection.nextMessageID(), null,
+        dn);
+      op.run();
+      if ((op.getResultCode() != ResultCode.SUCCESS) &&
+        (op.getResultCode() != ResultCode.NO_SUCH_OBJECT))
+      {
+        fail("Deleting config entry" + dn +
+          " failed: " + op.getResultCode().getResultCodeName());
+      }
+    } catch (NoSuchElementException e)
+    {
+      // done
+    }
+  }
 }
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java
index 329e40a..73f378e 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/AssuredReplicationPluginTest.java
@@ -266,36 +266,6 @@
   }
 
   /**
-   * Removes a domain deleting the passed config entry
-   */
-  private void removeDomain(Entry domainCfgEntry)
-  {
-    DeleteOperationBasis op;
-    // Delete entries
-    try
-    {
-      DN dn = domainCfgEntry.getDN();
-
-      logError(Message.raw(Category.SYNC, Severity.NOTICE,
-        "cleaning config entry " + dn));
-
-      op = new DeleteOperationBasis(connection, InternalClientConnection.
-        nextOperationID(), InternalClientConnection.nextMessageID(), null,
-        dn);
-      op.run();
-      if ((op.getResultCode() != ResultCode.SUCCESS) &&
-        (op.getResultCode() != ResultCode.NO_SUCH_OBJECT))
-      {
-        fail("Deleting config entry" + dn +
-          " failed: " + op.getResultCode().getResultCodeName());
-      }
-    } catch (NoSuchElementException e)
-    {
-      // done
-    }
-  }
-
-  /**
    * The fake replication server used to emulate RS behaviour the way we want
    * for assured features test.
    * This fake replication server is able to receive a DS connection only.
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/DomainFakeCfg.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/DomainFakeCfg.java
index 92161f0..6f2ffbf 100644
--- a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/DomainFakeCfg.java
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/DomainFakeCfg.java
@@ -26,6 +26,7 @@
  */
 package org.opends.server.replication.plugin;
 
+import java.util.List;
 import java.util.SortedSet;
 
 import java.util.TreeSet;
@@ -63,6 +64,9 @@
   // Referrals urls to be published to other servers of the topology
   SortedSet<String> refUrls = new TreeSet<String>();
 
+  private SortedSet<String> fractionalExcludes = new TreeSet<String>();
+  private SortedSet<String> fractionalIncludes = new TreeSet<String>();
+
   /**
    * Creates a new Domain with the provided information
    * (assured mode disabled, default group id)
@@ -76,6 +80,30 @@
 
   /**
    * Creates a new Domain with the provided information
+   * (with some fractional configuration provided)
+   */
+  public DomainFakeCfg(DN baseDn, int serverId, SortedSet<String> replServers,
+    List<String> fractionalExcludes, List<String> fractionalIncludes)
+  {
+    this(baseDn, serverId, replServers);
+    if (fractionalExcludes != null)
+    {
+      for (String str : fractionalExcludes)
+      {
+        this.fractionalExcludes.add(str);
+      }
+    }
+    if (fractionalIncludes != null)
+    {
+      for (String str : fractionalIncludes)
+      {
+        this.fractionalIncludes.add(str);
+      }
+    }
+  }
+
+  /**
+   * Creates a new Domain with the provided information
    * (assured mode disabled, group id provided)
    */
   public DomainFakeCfg(DN baseDn, int serverId, SortedSet<String> replServers,
@@ -305,4 +333,14 @@
   {
     return refUrls;
   }
+
+  public SortedSet<String> getFractionalExclude()
+  {
+    return fractionalExcludes;
+  }
+
+  public SortedSet<String> getFractionalInclude()
+  {
+    return fractionalIncludes;
+  }
 }
diff --git a/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/FractionalReplicationTest.java b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/FractionalReplicationTest.java
new file mode 100644
index 0000000..ddfa514
--- /dev/null
+++ b/opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/replication/plugin/FractionalReplicationTest.java
@@ -0,0 +1,2031 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Copyright 2009 Sun Microsystems, Inc.
+ */
+package org.opends.server.replication.plugin;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import org.opends.messages.Category;
+import org.opends.messages.Message;
+import org.opends.messages.Severity;
+import org.opends.server.TestCaseUtils;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.AddOperationBasis;
+import org.opends.server.core.DirectoryServer;
+import org.opends.server.loggers.debug.DebugTracer;
+import org.opends.server.protocols.internal.InternalClientConnection;
+import org.opends.server.replication.ReplicationTestCase;
+import org.opends.server.replication.common.ChangeNumberGenerator;
+import org.opends.server.replication.common.ServerStatus;
+import org.opends.server.replication.protocol.AddMsg;
+import org.opends.server.replication.protocol.ModifyDNMsg;
+import org.opends.server.replication.protocol.ModifyMsg;
+import org.opends.server.replication.protocol.UpdateMsg;
+import org.opends.server.replication.server.ReplServerFakeConfiguration;
+import org.opends.server.replication.server.ReplicationServer;
+import org.opends.server.replication.service.ReplicationDomain;
+import org.opends.server.types.Attribute;
+import org.opends.server.types.AttributeType;
+import org.opends.server.types.AttributeValue;
+import org.opends.server.types.Attributes;
+import org.opends.server.types.DN;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.Entry;
+import org.opends.server.types.Modification;
+import org.opends.server.types.ModificationType;
+import org.opends.server.types.ObjectClass;
+import org.opends.server.types.ResultCode;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import static org.testng.Assert.*;
+import static org.opends.server.TestCaseUtils.*;
+import static org.opends.server.loggers.ErrorLogger.logError;
+import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
+import static org.opends.server.loggers.debug.DebugLogger.getTracer;
+import static org.opends.messages.ReplicationMessages.*;
+
+/**
+ * Various tests around fractional replication
+ */
+public class FractionalReplicationTest extends ReplicationTestCase {
+
+  // The RS
+  private ReplicationServer replicationServer = null;
+  // RS port
+  private int replServerPort = -1;
+  // Represents the real domain to test (replays and filters)
+  private Entry fractionalDomainCfgEntry = null;
+  // The domain used to send updates to the reald domain
+  private FakeReplicationDomain replicationDomain = null;
+
+  // Ids of servers
+  private static final short DS1_ID = 1; // fractional domain
+  private static final short DS2_ID = 2; // fake domain
+  private static final short RS_ID = 91; // replication server
+
+  private final String testName = this.getClass().getSimpleName();
+
+  // Fractional mode
+  private static final int EXCLUDE_FRAC_MODE = 0;
+  private static final int INCLUDE_FRAC_MODE = 1;
+
+  private ChangeNumberGenerator gen = null;
+
+  // The tracer object for the debug logger
+  private static final DebugTracer TRACER = getTracer();
+
+  // Number of seconds before generating an error if some conditions not met
+  private static final int TIMEOUT = 10;
+
+  // Uuid of the manipulated entry
+  private static final String ENTRY_UUID =
+    "11111111-1111-1111-1111-111111111111";
+  private static final String ENTRY_UUID2 =
+    "22222222-2222-2222-2222-222222222222";
+  private static final String ENTRY_UUID3 =
+    "33333333-3333-3333-3333-333333333333";
+  // Dn of the manipulated entry
+  private static String ENTRY_DN = "uid=1," + TEST_ROOT_DN_STRING;
+
+  // Optional attribute not part of concerned attributes of the fractional
+  // configuration during tests. It should not be impacted by fractional
+  // mechanism
+  private static final String OPTIONAL_ATTR = "description";
+
+  // Optional attribute used as synchronization attribute to know when the modify
+  // operation has been processed (used as add new attribute in the modify operation)
+  // It may or may not be part of the filtered attributes, depending on the fractional
+  // test mode : exclusive or inclusive
+  private static final String SYNCHRO_OPTIONAL_ATTR = "seeAlso";
+
+  // Second test backend
+  private static final String TEST2_ROOT_DN_STRING = "dc=example,dc=com";
+  private static final String TEST2_ORG_DN_STRING = "o=test2," + TEST2_ROOT_DN_STRING;
+  private static String ENTRY_DN2 = "uid=1," + TEST2_ORG_DN_STRING;
+
+  private void debugInfo(String s) {
+    logError(Message.raw(Category.SYNC, Severity.NOTICE, s));
+    if (debugEnabled())
+    {
+      TRACER.debugInfo("** TEST **" + s);
+    }
+  }
+
+  /**
+   * Before starting the tests configure some stuff
+   */
+  @BeforeClass
+  @Override
+  public void setUp() throws Exception
+  {    
+    super.setUp();
+
+    // Find  a free port for the replicationServer
+    ServerSocket socket = TestCaseUtils.bindFreePort();
+    replServerPort = socket.getLocalPort();
+    socket.close();
+  }
+
+  /**
+   * Returns a bunch of single values for fractional-exclude configuration
+   * attribute
+   */
+  @DataProvider(name = "testExcludePrecommitProvider")
+  private Object[][] testExcludePrecommitProvider()
+  {
+    return new Object[][]
+    {
+      { 1, new String[] {"inetOrgPerson", "displayName"}}
+    };
+  }
+
+  /**
+   * Returns a bunch of single values for fractional-exclude configuration
+   * attribute
+   */
+  @DataProvider(name = "testExcludeNightlyProvider")
+  private Object[][] testExcludeNightlyProvider()
+  {
+    return new Object[][]
+    {
+      { 1, new String[] {"INETORGPERSON", "DISPLAYNAME"}},
+      { 2, new String[] {"inetOrgPerson", "2.16.840.1.113730.3.1.241"}},
+      { 3, new String[] {"2.16.840.1.113730.3.2.2", "displayName"}},
+      { 4, new String[] {"2.16.840.1.113730.3.2.2", "2.16.840.1.113730.3.1.241"}},
+      { 5, new String[] {"inetOrgPerson", "displayName", "carLicense"}},
+      { 6, new String[] {"organizationalPerson", "title", "postalCode"}},
+      { 7, new String[] {"2.5.6.7", "title", "postalCode"}},
+      { 8, new String[] {"2.5.6.7", "TITLE", "2.5.4.17"}},
+      { 9, new String[] {"2.5.6.7", "2.5.4.12", "2.5.4.17"}},
+      { 10, new String[] {"*", "roomNumber"}},
+      { 11, new String[] {"*", "0.9.2342.19200300.100.1.6"}},
+      { 12, new String[] {"*", "postOfficeBox", "0.9.2342.19200300.100.1.6"}},
+      { 13, new String[] {"*", "2.5.4.18", "0.9.2342.19200300.100.1.6"}}
+    };
+  }
+
+  /**
+   * Calls the testExclude test with a small set of data, for precommit test
+   * purpose
+   */
+  @Test(dataProvider = "testExcludePrecommitProvider")
+  public void testExcludePrecommit(int testProviderLineId,
+    String... fractionalConf) throws Exception
+  {
+    testExclude(testProviderLineId, fractionalConf);
+  }
+
+  /**
+   * Calls the testExclude test with a larger set of data, for nightly tests
+   * purpose
+   */
+  @Test(dataProvider = "testExcludeNightlyProvider", groups = "slow")
+  public void testExcludeNightly(int testProviderLineId,
+    String... fractionalConf) throws Exception
+  {
+    testExclude(testProviderLineId, fractionalConf);
+  }
+
+  /**
+   * Performs Add and Modify operations including attributes that are excluded
+   * with the passed fractional configuration and checks that these attributes
+   * are not part of the concerned entry.
+   * Note: testProviderLineId just here to know what is the provider problematic
+   * line if the test fail: prevent some display like:
+   *  [testng] parameter[0]: [Ljava.lang.String;@151e824
+   * but have instead:
+   *  [testng] parameter[0]: 6
+   *  [testng] parameter[1]: [Ljava.lang.String;@151e824
+   */
+  private void testExclude(int testProviderLineId,
+    String... fractionalConf) throws Exception
+  {
+
+    String testcase = "testExclude" + testProviderLineId;
+
+    initTest();
+
+    try
+    {
+      // create replication server
+      createReplicationServer(testcase);
+
+      // create fractional domain with the passed fractional configuration
+      createFractionalDomain(true, EXCLUDE_FRAC_MODE, fractionalConf);
+
+      // create fake domain to send operations
+      createFakeReplicationDomain(true, readGenIdFromSuffixRootEntry(TEST_ROOT_DN_STRING));
+
+      // perform add operation
+      sendAddMsg(true, fractionalConf);
+
+      // check that entry has been created and that it does not contain
+      // forbidden attributes
+      Entry newEntry = null;
+      try
+      {
+        newEntry = getEntry(DN.decode(ENTRY_DN), TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been added: " + e.getMessage());
+      }
+      checkEntryFilteredAfterAdd(newEntry, EXCLUDE_FRAC_MODE, fractionalConf);
+
+      // perform modify operation (modify forbidden attributes +
+      // modify authorized attribute (not a no op))
+      sendModifyMsg(true, fractionalConf);
+
+      // Wait for modify operation being replayed and
+      // check that entry does not contain forbidden attributes
+      Entry entry = null;
+      boolean synchroAttrFound = false;
+      int timeout = TIMEOUT;
+      while(timeout>0)
+      {
+        try
+        {
+          entry = getEntry(DN.decode(ENTRY_DN), TIMEOUT, true);
+          if (entry.hasAttribute(DirectoryServer.getAttributeType(SYNCHRO_OPTIONAL_ATTR.toLowerCase())))
+          {
+            synchroAttrFound = true;
+            break;
+          }
+          Thread.sleep(1000);
+          timeout--;
+        } catch (Exception e)
+        {
+          fail("Error waiting for modify operation being replayed : " + e.getMessage());
+        }
+      }
+      assertTrue(synchroAttrFound, "Modify operation not replayed");
+      checkEntryFilteredAfterModify(entry, EXCLUDE_FRAC_MODE, fractionalConf);
+    }
+    finally
+    {
+      endTest();
+    }
+  }
+
+  /**
+   * Returns a bunch of single values for fractional-include configuration
+   * attribute
+   */
+  @DataProvider(name = "testIncludePrecommitProvider")
+  private Object[][] testIncludePrecommitProvider()
+  {
+    return new Object[][]
+    {
+      { 1, new String[] {"inetOrgPerson", "displayName"}}
+    };
+  }
+
+  /**
+   * Returns a bunch of single values for fractional-include configuration
+   * attribute
+   */
+  @DataProvider(name = "testIncludeNightlyProvider")
+  private Object[][] testIncludeNightlyProvider()
+  {
+    return new Object[][]
+    {
+      { 1, new String[] {"INETORGPERSON", "DISPLAYNAME"}},
+      { 2, new String[] {"inetOrgPerson", "2.16.840.1.113730.3.1.241"}},
+      { 3, new String[] {"2.16.840.1.113730.3.2.2", "displayName"}},
+      { 4, new String[] {"2.16.840.1.113730.3.2.2", "2.16.840.1.113730.3.1.241"}},
+      { 5, new String[] {"inetOrgPerson", "displayName", "carLicense"}},
+      { 6, new String[] {"organizationalPerson", "title", "postalCode"}},
+      { 7, new String[] {"2.5.6.7", "title", "postalCode"}},
+      { 8, new String[] {"2.5.6.7", "TITLE", "2.5.4.17"}},
+      { 9, new String[] {"2.5.6.7", "2.5.4.12", "2.5.4.17"}},
+      { 10, new String[] {"*", "roomNumber"}},
+      { 11, new String[] {"*", "0.9.2342.19200300.100.1.6"}},
+      { 12, new String[] {"*", "postOfficeBox", "0.9.2342.19200300.100.1.6"}},
+      { 13, new String[] {"*", "2.5.4.18", "0.9.2342.19200300.100.1.6"}}
+    };
+  }
+
+  /**
+   * Calls the testInclude test with a small set of data, for precommit test
+   * purpose
+   */
+  @Test(dataProvider = "testIncludePrecommitProvider")
+  public void testIncludePrecommit(int testProviderLineId,
+    String... fractionalConf) throws Exception
+  {
+    testInclude(testProviderLineId, fractionalConf);
+  }
+
+  /**
+   * Calls the testInclude test with a larger set of data, for nightly tests
+   * purpose
+   */
+  @Test(dataProvider = "testIncludeNightlyProvider", groups = "slow")
+  public void testIncludeNightly(int testProviderLineId,
+    String... fractionalConf) throws Exception
+  {
+    testInclude(testProviderLineId, fractionalConf);
+  }
+
+  /**
+   * Performs Add and Modify operations including attributes that are excluded
+   * with the passed fractional configuration and checks that these attributes
+   * are not part of the concerned entry.
+   * Note: testProviderLineId just here to know what is the provider problematic
+   * line if the test fail: prevent some display like:
+   *  [testng] parameter[0]: [Ljava.lang.String;@151e824
+   * but have instead:
+   *  [testng] parameter[0]: 6
+   *  [testng] parameter[1]: [Ljava.lang.String;@151e824
+   */
+  private void testInclude(int testProviderLineId,
+    String... fractionalConf) throws Exception
+  {
+
+    String testcase = "testInclude" + testProviderLineId;
+
+    initTest();
+
+    try
+    {
+      // create replication server
+      createReplicationServer(testcase);
+
+      // create fractional domain with the passed fractional configuration
+      createFractionalDomain(true, INCLUDE_FRAC_MODE, fractionalConf);
+
+      // create fake domain to send operations
+      createFakeReplicationDomain(true, readGenIdFromSuffixRootEntry(TEST_ROOT_DN_STRING));
+
+      // perform add operation
+      sendAddMsg(true, fractionalConf);
+
+      // check that entry has been created and that it does not contain
+      // forbidden attributes
+      Entry newEntry = null;
+      try
+      {
+        newEntry = getEntry(DN.decode(ENTRY_DN), TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been added: " + e.getMessage());
+      }
+      checkEntryFilteredAfterAdd(newEntry, INCLUDE_FRAC_MODE, fractionalConf);
+
+      // perform modify operation (modify forbidden attributes +
+      // modify authorized attribute (not a no op))
+      sendModifyMsg(true, fractionalConf);
+
+      // Wait for modify operation being replayed and
+      // check that entry does not contain forbidden attributes
+      Entry entry = null;
+      boolean synchroAttrFound = false;
+      int timeout = TIMEOUT;
+      while(timeout>0)
+      {
+        try
+        {
+          entry = getEntry(DN.decode(ENTRY_DN), TIMEOUT, true);
+          if (entry.hasAttribute(DirectoryServer.getAttributeType(SYNCHRO_OPTIONAL_ATTR.toLowerCase())))
+          {
+            synchroAttrFound = true;
+            break;
+          }
+          Thread.sleep(1000);
+          timeout--;
+        } catch (Exception e)
+        {
+          fail("Error waiting for modify operation being replayed : " + e.getMessage());
+        }
+      }
+      assertTrue(synchroAttrFound, "Modify operation not replayed");
+      checkEntryFilteredAfterModify(entry, INCLUDE_FRAC_MODE, fractionalConf);
+    }
+    finally
+    {
+      endTest();
+    }
+  }
+
+  /**
+   * Creates connects (to the RS) and starts the fake replication domain
+   * Use the passed generation id.
+   */
+  private void createFakeReplicationDomain(boolean firstBackend, long generationId)
+  {
+    try{
+
+      List<String> replicationServers = new ArrayList<String>();
+      replicationServers.add("localhost:" + replServerPort);
+
+      replicationDomain = new FakeReplicationDomain(
+            (firstBackend ? TEST_ROOT_DN_STRING : TEST2_ROOT_DN_STRING), DS2_ID, replicationServers, 100, 1000, generationId);
+
+      // Test connection
+      assertTrue(replicationDomain.isConnected());
+      int rdPort = -1;
+      // Check connected server port
+      String serverStr = replicationDomain.getReplicationServer();
+      int index = serverStr.lastIndexOf(':');
+      if ((index == -1) || (index >= serverStr.length()))
+        fail("Enable to find port number in: " + serverStr);
+      String rdPortStr = serverStr.substring(index + 1);
+      try
+      {
+        rdPort = (new Integer(rdPortStr)).intValue();
+      } catch (Exception e)
+      {
+        fail("Enable to get an int from: " + rdPortStr);
+      }
+      assertEquals(rdPort, replServerPort);
+    } catch (Exception e)
+    {
+      fail("createreplicationDomain " + e.getMessage());
+    }
+  }
+
+  private void initTest()
+  {
+    replicationDomain = null;
+    fractionalDomainCfgEntry = null;
+    replicationServer = null;
+
+    // Initialize the test backend
+    try {
+      TestCaseUtils.initializeTestBackend(false);
+    } catch(Exception e) {
+      fail("Could not initialize backend : " + e.getMessage());
+    }
+
+    // initialize cn generator
+    gen = new ChangeNumberGenerator(DS2_ID, 0L);
+  }
+
+  private void endTest()
+  {
+    if (replicationDomain != null)
+    {
+      replicationDomain.disableService();
+      replicationDomain = null;
+    }
+
+    if (fractionalDomainCfgEntry != null)
+    {
+      removeDomain(fractionalDomainCfgEntry);
+      fractionalDomainCfgEntry = null;
+    }
+
+    if (replicationServer != null)
+    {
+      replicationServer.clearDb();
+      replicationServer.remove();
+      replicationServer = null;
+    }
+  }
+
+  /**
+   * Creates a fractional domain with the passed configuration.
+   * Before that, initializes the backend with the root entry and if requested
+   * with the correct fractional configuration in it
+   */
+  private void createFractionalDomain(boolean initializeDomain,
+    int fractionalMode, String... fractionalConf)
+  {
+    try
+    {
+      String fractModeAttrName = null;
+      String opFractModeAttrName = null;
+      boolean addSynchroAttribute = false;
+      switch (fractionalMode)
+      {
+        case EXCLUDE_FRAC_MODE:
+          fractModeAttrName = "ds-cfg-fractional-exclude";
+          opFractModeAttrName = "ds-sync-fractional-exclude";
+          break;
+        case INCLUDE_FRAC_MODE:
+          fractModeAttrName = "ds-cfg-fractional-include";
+          opFractModeAttrName = "ds-sync-fractional-include";
+          // For inclusive mode, we use an attribute that is added in the modify
+          // operation to know when the modify operation has been played. The added
+          // attribute can only be part of the include config to be taken into account
+          addSynchroAttribute = true;
+          break;
+        default:
+          fail("Unexpected fractional mode.");
+      }
+
+      /**
+       * Create a root entry with potentially with fractional configuration before domain creation
+       */
+
+      // Create base entry with correct fractional config
+      String topEntryLdif = null;
+
+      if (initializeDomain)
+      {
+        // Add first backend top entry
+        topEntryLdif = "dn: " + TEST_ROOT_DN_STRING + "\n" +
+        "objectClass: top\n" +
+        "objectClass: organization\n" +
+        "o: " + TEST_BACKEND_ID + "\n" +
+        "entryUUID: " + ENTRY_UUID3 + "\n";
+
+        // Add fractional config
+        int i=0;
+        int size = fractionalConf.length;
+        for (String fracCfgValue : fractionalConf) // Add fractional operational attributes
+        {
+          if (i==0)
+          {
+            // First string is the class
+            topEntryLdif += opFractModeAttrName + ": " + fracCfgValue + ":";
+          }
+          else
+          {
+            // Other strings are attributes
+            String endString = (addSynchroAttribute ? ("," + SYNCHRO_OPTIONAL_ATTR + "\n") : "\n");
+            topEntryLdif += fracCfgValue + ( (i<size-1) ? "," : endString);
+          }
+            i++;
+        }
+      }
+      else
+      {
+        // Add second backend top entry
+        topEntryLdif = "dn: " + TEST2_ROOT_DN_STRING + "\n" +
+        "objectClass: top\n" +
+        "objectClass: domain\n" +
+        "dc: example\n";
+      }
+      addEntry(TestCaseUtils.entryFromLdifString(topEntryLdif));
+
+      /**
+       * Create the domain with the passed fractional configuration
+       */
+
+      // Create a config entry ldif, matching passed settings
+      String configEntryLdif = "dn: cn=" + testName + ", cn=domains, " +
+        SYNCHRO_PLUGIN_DN + "\n" + "objectClass: top\n" +
+        "objectClass: ds-cfg-replication-domain\n" + "cn: " + testName + "\n" +
+        "ds-cfg-base-dn: " + (initializeDomain ? TEST_ROOT_DN_STRING : TEST2_ROOT_DN_STRING) + "\n" +
+        "ds-cfg-replication-server: localhost:" + replServerPort + "\n" +
+        "ds-cfg-server-id: " + DS1_ID + "\n";
+
+      int i=0;
+      int size = fractionalConf.length;
+      for (String fracCfgValue : fractionalConf) // Add fractional configuration attributes
+      {
+        if (i==0)
+        {
+          // First string is the class
+          configEntryLdif += fractModeAttrName + ": " + fracCfgValue + ":";
+        }
+        else
+        {
+          // Other strings are attributes
+          String endString = (addSynchroAttribute ? ("," + SYNCHRO_OPTIONAL_ATTR + "\n") : "\n");
+          configEntryLdif += fracCfgValue + ( (i<size-1) ? "," : endString);
+        }
+          i++;
+      }
+      fractionalDomainCfgEntry = TestCaseUtils.entryFromLdifString(configEntryLdif);
+
+      // Add the config entry to create the replicated domain
+      DirectoryServer.getConfigHandler().addEntry(fractionalDomainCfgEntry, null);
+      assertNotNull(DirectoryServer.getConfigEntry(fractionalDomainCfgEntry.getDN()),
+        "Unable to add the domain config entry: " + configEntryLdif);
+    }
+    catch(Exception e)
+    {
+      fail("createFractionalDomain error: " + e.getMessage());
+    }
+  }
+
+  /**
+   * Creates a new ReplicationServer.
+   */
+  private void createReplicationServer(String testCase)
+  {
+    try
+    {
+      SortedSet<String> replServers = new TreeSet<String>();
+
+      String dir = testName + RS_ID + testCase + "Db";
+      ReplServerFakeConfiguration conf =
+        new ReplServerFakeConfiguration(replServerPort, dir, 0, RS_ID, 0, 100,
+        replServers);
+      replicationServer = new ReplicationServer(conf);
+    } catch (Exception e)
+    {
+      fail("createReplicationServer " + e.getMessage());
+    }
+  }
+
+  /**
+   * This class is the minimum implementation of a Concrete ReplicationDomain
+   * used to be able to connect to the RS with a known genid. Also to be able
+   * to send updates
+   */
+  private class FakeReplicationDomain extends ReplicationDomain
+  {
+    // A blocking queue that is used to receive updates from
+    // the Replication Service.
+
+    BlockingQueue<UpdateMsg> queue = new LinkedBlockingQueue<UpdateMsg>();
+
+    // A string that will be exported should exportBackend be called.
+    String exportString = null;
+
+    // A StringBuilder that will be used to build a new String should the
+    // import be called.
+    StringBuilder importString = null;
+    private int exportedEntryCount;
+    private long generationID = -1;
+
+    public FakeReplicationDomain(
+      String serviceID,
+      short serverID,
+      Collection<String> replicationServers,
+      int window,
+      long heartbeatInterval,
+      long generationId) throws ConfigException
+    {
+      super(serviceID, serverID);
+      generationID = generationId;
+      startPublishService(replicationServers, window, heartbeatInterval);
+      startListenService();
+    }
+
+    public void initExport(String exportString, int exportedEntryCount)
+    {
+      this.exportString = exportString;
+      this.exportedEntryCount = exportedEntryCount;
+    }
+
+    public void initImport(StringBuilder importString)
+    {
+      this.importString = importString;
+    }
+
+    @Override
+    public long countEntries() throws DirectoryException
+    {
+      return exportedEntryCount;
+    }
+
+    @Override
+    protected void exportBackend(OutputStream output) throws DirectoryException
+    {
+      try
+      {
+        output.write(exportString.getBytes());
+        output.flush();
+        output.close();
+      } catch (IOException e)
+      {
+        throw new DirectoryException(ResultCode.OPERATIONS_ERROR,
+          ERR_BACKEND_EXPORT_ENTRY.get("", ""));
+      }
+
+    }
+
+    @Override
+    public long getGenerationID()
+    {
+      return generationID;
+    }
+
+    @Override
+    protected void importBackend(InputStream input) throws DirectoryException
+    {
+      byte[] buffer = new byte[1000];
+
+      int ret;
+      do
+      {
+        try
+        {
+          ret = input.read(buffer, 0, 1000);
+        } catch (IOException e)
+        {
+          throw new DirectoryException(
+            ResultCode.OPERATIONS_ERROR,
+            ERR_BACKEND_EXPORT_ENTRY.get("", ""));
+        }
+        importString.append(new String(buffer, 0, ret));
+      } while (ret >= 0);
+    }
+
+    @Override
+    public boolean processUpdate(UpdateMsg updateMsg)
+    {
+      if (queue != null)
+        queue.add(updateMsg);
+      return true;
+    }
+
+    public void setGenerationID(long newGenerationID)
+    {
+      generationID = newGenerationID;
+    }
+  }
+
+  private static final String REPLICATION_GENERATION_ID =
+    "ds-sync-generation-id";
+
+  private long readGenIdFromSuffixRootEntry(String rootDn)
+  {
+    long genId=-1;
+    try
+    {
+      DN baseDn = DN.decode(rootDn);
+      Entry resultEntry = getEntry(baseDn, 1000, true);
+      if (resultEntry==null)
+      {
+        debugInfo("Entry not found <" + rootDn + ">");
+      }
+      else
+      {
+        debugInfo("Entry found <" + rootDn + ">");
+
+        AttributeType synchronizationGenIDType =
+          DirectoryServer.getAttributeType(REPLICATION_GENERATION_ID);
+        List<Attribute> attrs =
+          resultEntry.getAttribute(synchronizationGenIDType);
+        if (attrs != null)
+        {
+          Attribute attr = attrs.get(0);
+          if (attr.size() == 1)
+          {
+            genId =
+                Long.decode(attr.iterator().next().getValue().toString());
+          }
+        }
+
+      }
+    }
+    catch(Exception e)
+    {
+      fail("Exception raised in readGenId", e);
+    }
+    return genId;
+  }
+
+  /**
+   * Send the AddMsg (from the fake replication domain) for the passed entry
+   * containing the attributes defined in the passed fractional configuration
+   */
+  private void sendAddMsg(boolean firstBackend, String... fractionalConf)
+    {
+      String entryLdif = "dn: " + (firstBackend ? ENTRY_DN : ENTRY_DN2) + "\n" + "objectClass: top\n" +
+        "objectClass: person\n" + "objectClass: organizationalPerson\n";
+        String classStr = "";
+        if ( fractionalConf[0].equalsIgnoreCase("inetOrgPerson") ||
+        fractionalConf[0].equalsIgnoreCase("2.16.840.1.113730.3.2.2"))
+        {
+          classStr = "objectClass: " + fractionalConf[0] + "\n";
+        }
+        entryLdif += classStr + "uid: 1\n" +
+        "entryUUID: " + ENTRY_UUID + "\n" +
+        "sn: snValue\n" + "cn: cnValue\n" +
+        OPTIONAL_ATTR + ": " + OPTIONAL_ATTR + "Value\n";
+
+      // Add attributes concerned by fractional configuration
+      boolean first = true;
+      for (String fracCfgValue : fractionalConf)
+      {
+        if (!first)
+        {
+          // First string is the class
+          entryLdif += fracCfgValue + ": " + fracCfgValue + "Value\n";
+        }
+        first = false;
+      }
+
+      Entry entry = null;
+      try
+      {
+        entry = TestCaseUtils.entryFromLdifString(entryLdif);
+      } catch (Exception e)
+      {
+        fail(e.getMessage());
+      }
+
+      // Create an update message to add an entry.
+      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
+        entry.getDN().toString(),
+        ENTRY_UUID,
+        null,
+        entry.getObjectClassAttribute(),
+        entry.getAttributes(), new ArrayList<Attribute>());
+
+      replicationDomain.publish(addMsg);
+    }
+
+  /**
+   * Send (from the fake replication domain) a ModifyMsg for the passed entry
+   * modifying attributes defined in the passed fractional configuration
+   */
+  private void sendModifyMsg(boolean firstBackend, String... fractionalConf)
+    {
+
+      // Create modifications on the fractional attributes
+      List<Modification> mods = new ArrayList<Modification>();
+      boolean first = true;
+      for (String fracCfgValue : fractionalConf)
+      {
+        if (!first)
+        {
+          // First string is the class
+          Attribute attr =
+            Attributes.create(fracCfgValue.toLowerCase(), fracCfgValue + "NewValue");
+          Modification mod = new Modification(ModificationType.REPLACE, attr);
+          mods.add(mod);
+        }
+        first = false;
+      }
+
+      // Add modification for the special attribute (modified attribute)
+      Attribute attr =
+        Attributes.create(OPTIONAL_ATTR.toLowerCase(), OPTIONAL_ATTR + "NewValue");
+      Modification mod = new Modification(ModificationType.REPLACE, attr);
+      mods.add(mod);
+
+      // Add modification for the synchro attribute (added attribute)
+      attr =
+        Attributes.create(SYNCHRO_OPTIONAL_ATTR.toLowerCase(), SYNCHRO_OPTIONAL_ATTR + "Value");
+      mod = new Modification(ModificationType.ADD, attr);
+      mods.add(mod);
+
+      DN entryDn = null;
+      try
+      {
+        entryDn = DN.decode((firstBackend ? ENTRY_DN : ENTRY_DN2));
+      } catch (Exception e)
+      {
+        fail("Cannot create dn entry: " + e.getMessage());
+      }
+      ModifyMsg modifyMsg = new ModifyMsg(gen.newChangeNumber(), entryDn, mods,
+        ENTRY_UUID);
+
+      replicationDomain.publish(modifyMsg);
+    }
+
+  /**
+   * Utility method : Add an entry in the database
+   */
+  private void addEntry(Entry entry) throws Exception
+  {
+    AddOperationBasis addOp = new AddOperationBasis(connection,
+      InternalClientConnection.nextOperationID(), InternalClientConnection.
+      nextMessageID(), null, entry.getDN(), entry.getObjectClasses(),
+      entry.getUserAttributes(), entry.getOperationalAttributes());
+    addOp.setInternalOperation(true);
+    addOp.run();
+    assertNotNull(getEntry(entry.getDN(), 1000, true));
+  }
+
+  /**
+   * Check that the just added entry (newEntry) meets the fractional criteria
+   * regarding the passed configuration : mode and attributes to be filtered/not
+   * filtered
+   */
+  private void checkEntryFilteredAfterAdd(Entry newEntry,
+    int fractionalMode, String... fractionalConf) throws Exception
+  {
+    try
+    {
+      // Is the added entry of the expected object class ?
+      String objectClassStr = fractionalConf[0];
+      if (!objectClassStr.equals("*"))
+      {
+        ObjectClass objectClass = DirectoryServer.getObjectClass(objectClassStr.toLowerCase());
+
+        assertTrue(newEntry.hasObjectClass(objectClass));
+      }
+
+      // Go through each interesting attribute and check it is present or not
+      // according to the fractional mode
+      boolean first = true;
+      switch (fractionalMode)
+      {
+        case EXCLUDE_FRAC_MODE:
+          // Exclude mode: attributes should not be there, but OPTIONAL_ATTR
+          // attribute should
+          for (String fracAttr : fractionalConf)
+          {
+            if (!first)
+            {
+              assertFalse(newEntry.hasAttribute(DirectoryServer.
+                getAttributeType(fracAttr.toLowerCase())));
+            }
+            first = false;
+          }
+          checkEntryAttributeValue(newEntry, OPTIONAL_ATTR, OPTIONAL_ATTR + "Value");
+          break;
+        case INCLUDE_FRAC_MODE:
+          // Include mode: attributes should be there, but OPTIONAL_ATTR
+          // attribute should not
+          for (String fracAttr : fractionalConf)
+          {
+            if (!first)
+            {
+              checkEntryAttributeValue(newEntry, fracAttr, fracAttr + "Value");
+            }
+            first = false;
+          }
+          assertFalse(newEntry.hasAttribute(DirectoryServer.
+                getAttributeType(OPTIONAL_ATTR.toLowerCase())));
+          break;
+        default:
+          fail("Unexpected fractional mode.");
+      }
+    }
+    catch(Exception e)
+    {
+      fail("checkEntryFilteredAfterAdd error: " + e.getMessage());
+    }
+  }
+
+  /**
+   * Check that the just modified entry (entry) meets the fractional criteria
+   * regarding the passed configuration : mode and attributes to be filtered/not
+   * filtered
+   */
+  private void checkEntryFilteredAfterModify(Entry entry,
+    int fractionalMode, String... fractionalConf) throws Exception
+  {
+    try
+    {
+      // Is the added entry of the expected object class ?
+      String objectClassStr = fractionalConf[0];
+      if (!objectClassStr.equals("*"))
+      {
+        ObjectClass objectClass = DirectoryServer.getObjectClass(objectClassStr.toLowerCase());
+
+        assertTrue(entry.hasObjectClass(objectClass));
+      }
+
+      // Go through each interesting attribute and check it has been modifed or
+      // not according to the fractional mode
+      boolean first = true;
+      switch (fractionalMode)
+      {
+        case EXCLUDE_FRAC_MODE:
+          // Exclude mode: attributes should not be there, but OPTIONAL_ATTR
+          // attribute should have been modified
+          for (String fracAttr : fractionalConf)
+          {
+            if (!first)
+            {
+              assertFalse(entry.hasAttribute(DirectoryServer.
+                getAttributeType(fracAttr.toLowerCase())));
+            }
+            first = false;
+          }
+          checkEntryAttributeValue(entry, OPTIONAL_ATTR, OPTIONAL_ATTR + "NewValue");
+          break;
+        case INCLUDE_FRAC_MODE:
+          // Include mode: attributes should have been modified, but OPTIONAL_ATTR
+          // attribute should not be there
+          for (String fracAttr : fractionalConf)
+          {
+            if (!first)
+            {
+              checkEntryAttributeValue(entry, fracAttr, fracAttr + "NewValue");
+            }
+            first = false;
+          }
+          assertFalse(entry.hasAttribute(DirectoryServer.
+                getAttributeType(OPTIONAL_ATTR.toLowerCase())));
+          break;
+        default:
+          fail("Unexpected fractional mode.");
+      }
+      // In both modes, SYNCHRO_OPTIONAL_ATTR attribute should have been added
+      checkEntryAttributeValue(entry, SYNCHRO_OPTIONAL_ATTR, SYNCHRO_OPTIONAL_ATTR + "Value");
+    }
+    catch(Exception e)
+    {
+      fail("checkEntryFilteredAfterAdd error: " + e.getMessage());
+    }
+  }
+
+  /**
+   * Check that the provided entry has a single value attribute which has the
+   * expected attribute value
+   */
+  private static void checkEntryAttributeValue(Entry entry, String attributeName,
+    String attributeValue)
+  {
+    List<Attribute> attrs = entry.getAttribute(attributeName.toLowerCase());
+    assertNotNull(attrs, "Was expecting attribute " + attributeName + "=" +
+      attributeValue + " but got no attribute");
+    assertEquals(attrs.size(), 1);
+    Attribute attr = attrs.get(0);
+    assertNotNull(attr);
+    Iterator<AttributeValue> attrValues = attr.iterator();
+    assertNotNull(attrValues);
+    assertTrue(attrValues.hasNext());
+    AttributeValue attrValue = attrValues.next();
+    assertNotNull(attrValue);
+    assertFalse(attrValues.hasNext());
+    assertEquals(attrValue.toString(), attributeValue, "Was expecting attribute " +
+      attributeName + "=" + attributeValue + " but got value: " + attrValue.toString());
+    
+  }
+
+  /**
+   * Returns a bunch of single values for fractional configuration
+   * attributes
+   */
+  @DataProvider(name = "testInitWithFullUpdateExcludePrecommitProvider")
+  private Object[][] testInitWithFullUpdateExcludePrecommitProvider()
+  {
+    return new Object[][]
+    {
+      { 1, true, new String[] {"inetOrgPerson", "displayName"}}
+    };
+  }
+
+  /**
+   * Returns a bunch of single values for fractional configuration
+   * attributes
+   */
+  @DataProvider(name = "testInitWithFullUpdateExcludeNightlyProvider")
+  private Object[][] testInitWithFullUpdateExcludeNightlyProvider()
+  {
+    return new Object[][]
+    {
+      { 1, false, new String[] {"inetOrgPerson", "displayName"}}
+    };
+  }
+
+  /**
+   * Calls the testInitWithFullUpdateExclude test with a small set of data, for precommit test
+   * purpose
+   */
+  @Test(dataProvider = "testInitWithFullUpdateExcludePrecommitProvider")
+  public void testInitWithFullUpdateExcludePrecommit(int testProviderLineId,
+    boolean importedDomainIsFractional, String... fractionalConf) throws Exception
+  {
+    testInitWithFullUpdateExclude(testProviderLineId, importedDomainIsFractional, fractionalConf);
+  }
+
+  /**
+   * Calls the testInitWithFullUpdateExclude test with a larger set of data, for nightly tests
+   * purpose
+   */
+  @Test(dataProvider = "testInitWithFullUpdateExcludeNightlyProvider", groups = "slow")
+  public void testInitWithFullUpdateExcludeNightly(int testProviderLineId,
+    boolean importedDomainIsFractional, String... fractionalConf) throws Exception
+  {
+    testInitWithFullUpdateExclude(testProviderLineId, importedDomainIsFractional, fractionalConf);
+  }
+
+  /**
+   * Configures a domain which is not fractional to fractional exclusive,
+   * then emulates an online full update to initialize the fractional domain and
+   * have it operational.
+   * Note: testProviderLineId just here to know what is the provider problematic
+   * line if the test fail: prevent some display like:
+   *  [testng] parameter[0]: [Ljava.lang.String;@151e824
+   * but have instead:
+   *  [testng] parameter[0]: 6
+   *  [testng] parameter[1]: [Ljava.lang.String;@151e824
+   */  
+  private void testInitWithFullUpdateExclude(int testProviderLineId,
+    boolean importedDomainIsFractional, String... fractionalConf) throws Exception
+  {
+    String testcase = "testInitWithFullUpdateExclude" + testProviderLineId;
+
+    initTest();
+
+    // We need a backend with a real configuration in cn=config as at import time
+    // the real domain will check for backend existence in cn=config. So we use
+    // dc=example,dc=com for this particular test.
+    // Clear the backend
+   LDAPReplicationDomain.clearJEBackend(false, "userRoot", TEST2_ROOT_DN_STRING);
+
+    try
+    {
+      /*
+       * Create replication server and connect fractional domain to it then fake
+       * domain
+       */
+
+      // create replication server
+      createReplicationServer(testcase);
+
+      // create fractional domain with the passed fractional configuration
+      // without initializing the backend
+      createFractionalDomain(false, EXCLUDE_FRAC_MODE, fractionalConf);
+
+      // The domain should go in bad gen as backend is not initialized with
+      // fractional data
+      LDAPReplicationDomain fractionalReplicationDomain =
+        MultimasterReplication.findDomain(DN.decode(TEST2_ROOT_DN_STRING), null);
+      waitForDomainStatus(fractionalReplicationDomain,
+        ServerStatus.BAD_GEN_ID_STATUS, 5);
+
+      // create fake domain to perform the full update
+      long generationId = readGenIdFromSuffixRootEntry(TEST2_ROOT_DN_STRING);
+      assertTrue(generationId != 0L);
+      createFakeReplicationDomain(false, generationId);
+
+      /*
+       * Create the LDIF that will be used to initialize the domain from the
+       * fake one. Initialize the fake domain with it.
+       */
+
+      //      Top Entry
+      String exportLdif = "dn: " + TEST2_ROOT_DN_STRING + "\n" +
+        "objectClass: top\n" +
+        "objectClass: domain\n" +
+        "dc: example\n" +
+        "ds-sync-generation-id: " + generationId + "\n";
+      if (importedDomainIsFractional)
+      {
+        //                Add fractional config
+        int i=0;
+        int size = fractionalConf.length;
+        for (String fracCfgValue : fractionalConf) // Add fractional operational attributes
+        {
+          if (i==0)
+          {
+            // First string is the class
+            exportLdif += "ds-sync-fractional-exclude: " + fracCfgValue + ":";
+          }
+          else
+          {
+            // Other strings are attributes
+            exportLdif += fracCfgValue + ( (i<size-1) ? "," : "\n");
+          }
+            i++;
+        }
+      }
+      //      Org Entry
+      exportLdif += "\ndn: " + TEST2_ORG_DN_STRING + "\n" +
+        "objectClass: top\n" +
+        "objectClass: organization\n" +
+        "o: test2\n\n";
+      //      User entry
+      exportLdif += "dn: " + ENTRY_DN2 + "\n" + "objectClass: top\n" +
+        "objectClass: person\n" + "objectClass: organizationalPerson\n" +
+        "objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
+        "uid: 1\n" + "entryUUID: " +
+        ENTRY_UUID + "\n" + OPTIONAL_ATTR + ": " + OPTIONAL_ATTR + "Value\n";
+      if (!importedDomainIsFractional)
+      {
+        //                Add attributes concerned by fractional configuration
+        boolean first = true;
+        for (String fracCfgValue : fractionalConf)
+        {
+          if (!first)
+          {
+            // First string is the class
+            exportLdif += fracCfgValue + ": " + fracCfgValue + "Value\n";
+          }
+          first = false;
+        }
+      }
+      exportLdif += "\n"; // Needed ?
+
+      replicationDomain.initExport(exportLdif, 2);
+
+      // Perform full update from fake domain to fractional domain
+      replicationDomain.initializeRemote(DS1_ID);
+
+      /*
+       * Check fractional domain is operational and that filtering has been done
+       * during the full update
+       */
+
+      // The domain should go back in normal status
+      waitForDomainStatus(fractionalReplicationDomain,
+        ServerStatus.NORMAL_STATUS, 5);
+
+      // check that entry has been created and that it does not contain
+      // forbidden attributes
+      Entry newEntry = null;
+      try
+      {
+        newEntry = getEntry(DN.decode(ENTRY_DN2), TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been created: " + e.getMessage());
+      }
+      checkEntryFilteredAfterAdd(newEntry, EXCLUDE_FRAC_MODE, fractionalConf);
+
+      // perform modify operation (modify forbidden attributes +
+      // modify authorized attribute (not a no op))
+      sendModifyMsg(false, fractionalConf);
+
+      // Wait for modify operation being replayed and
+      // check that entry does not contain forbidden attributes
+      Entry entry = null;
+      boolean synchroAttrFound = false;
+      int timeout = TIMEOUT;
+      while(timeout>0)
+      {
+        try
+        {
+          entry = getEntry(DN.decode(ENTRY_DN2), TIMEOUT, true);
+          if (entry.hasAttribute(DirectoryServer.getAttributeType(SYNCHRO_OPTIONAL_ATTR.toLowerCase())))
+          {
+            synchroAttrFound = true;
+            break;
+          }
+          Thread.sleep(1000);
+          timeout--;
+        } catch (Exception e)
+        {
+          fail("Error waiting for modify operation being replayed : " + e.getMessage());
+        }
+      }
+      assertTrue(synchroAttrFound, "Modify operation not replayed");
+      checkEntryFilteredAfterModify(entry, EXCLUDE_FRAC_MODE, fractionalConf);
+    }
+    finally
+    {
+      endTest();
+    }
+  }
+
+  /**
+   * Wait for the passed domain to have the desired status or fail if timeout
+   * waiting.
+   */
+  private void waitForDomainStatus(ReplicationDomain replicationDomain,
+    ServerStatus expectedStatus, int nSec)
+  {
+    int toWait = nSec;
+    ServerStatus serverStatus = null;
+    while(nSec > 0)
+    {
+      serverStatus = replicationDomain.getStatus();
+      if ( serverStatus ==  expectedStatus )
+      {
+        debugInfo("waitForDomainStatus: expected replication " +
+          "domain status obtained after " + (toWait-nSec) + " second(s).");
+        return;
+      }
+      sleep(1000);
+      nSec--;
+    }
+    fail("Did not get expected replication domain status: expected <" + expectedStatus +
+      "> but got <" + serverStatus + ">, after " + toWait + " second(s)");
+  }
+
+  /**
+   * Returns a bunch of single values for fractional configuration
+   * attributes
+   */
+  @DataProvider(name = "testInitWithFullUpdateIncludePrecommitProvider")
+  private Object[][] testInitWithFullUpdateIncludePrecommitProvider()
+  {
+    return new Object[][]
+    {
+      { 1, true, new String[] {"inetOrgPerson", "displayName"}}
+    };
+  }
+
+  /**
+   * Returns a bunch of single values for fractional configuration
+   * attributes
+   */
+  @DataProvider(name = "testInitWithFullUpdateIncludeNightlyProvider")
+  private Object[][] testInitWithFullUpdateIncludeNightlyProvider()
+  {
+    return new Object[][]
+    {
+      { 1, false, new String[] {"inetOrgPerson", "displayName"}}
+    };
+  }
+
+  /**
+   * Calls the testInitWithFullUpdateExclude test with a small set of data, for precommit test
+   * purpose
+   */
+  @Test(dataProvider = "testInitWithFullUpdateIncludePrecommitProvider")
+  public void testInitWithFullUpdateIncludePrecommit(int testProviderLineId,
+    boolean importedDomainIsFractional, String... fractionalConf) throws Exception
+  {
+    testInitWithFullUpdateInclude(testProviderLineId, importedDomainIsFractional, fractionalConf);
+  }
+
+  /**
+   * Calls the testInitWithFullUpdateExclude test with a larger set of data, for nightly tests
+   * purpose
+   */
+  @Test(dataProvider = "testInitWithFullUpdateIncludeNightlyProvider", groups = "slow")
+  public void testInitWithFullUpdateIncludeNightly(int testProviderLineId,
+    boolean importedDomainIsFractional, String... fractionalConf) throws Exception
+  {
+    testInitWithFullUpdateInclude(testProviderLineId, importedDomainIsFractional, fractionalConf);
+  }
+
+  /**
+   * Configures a domain which is not fractional to fractional inclusive,
+   * then emulates an online full update to initialize the fractional domain and
+   * have it operational.
+   * Note: testProviderLineId just here to know what is the provider problematic
+   * line if the test fail: prevent some display like:
+   *  [testng] parameter[0]: [Ljava.lang.String;@151e824
+   * but have instead:
+   *  [testng] parameter[0]: 6
+   *  [testng] parameter[1]: [Ljava.lang.String;@151e824
+   */
+  private void testInitWithFullUpdateInclude(int testProviderLineId,
+    boolean importedDomainIsFractional, String... fractionalConf) throws Exception
+  {
+    String testcase = "testInitWithFullUpdateInclude" + testProviderLineId;
+
+    initTest();
+
+    // We need a backend with a real configuration in cn=config as at import time
+    // the real domain will check for backend existence in cn=config. So we use
+    // dc=example,dc=com for this particular test.
+    // Clear the backend
+    LDAPReplicationDomain.clearJEBackend(false, "userRoot", TEST2_ROOT_DN_STRING);
+
+    try
+    {
+      /*
+       * Create replication server and connect fractional domain to it then fake
+       * domain
+       */
+
+      // create replication server
+      createReplicationServer(testcase);
+
+      // create fractional domain with the passed fractional configuration
+      // without initializing the backend
+      createFractionalDomain(false, INCLUDE_FRAC_MODE, fractionalConf);
+
+      // The domain should go in bad gen as backend is not initialized with
+      // fractional data
+      LDAPReplicationDomain fractionalReplicationDomain =
+        MultimasterReplication.findDomain(DN.decode(TEST2_ROOT_DN_STRING), null);
+      waitForDomainStatus(fractionalReplicationDomain,
+        ServerStatus.BAD_GEN_ID_STATUS, 5);
+
+      // create fake domain to perform the full update
+      long generationId = readGenIdFromSuffixRootEntry(TEST2_ROOT_DN_STRING);
+      assertTrue(generationId != 0L);
+      createFakeReplicationDomain(false, generationId);
+
+      /*
+       * Create the LDIF that will be used to initialize the domain from the
+       * fake one. Initialize the fake domain with it.
+       */
+
+      //      Top Entry
+      String exportLdif = "dn: " + TEST2_ROOT_DN_STRING + "\n" +
+        "objectClass: top\n" +
+        "objectClass: domain\n" +
+        "dc: example\n" +
+        "ds-sync-generation-id: " + generationId + "\n";
+      if (importedDomainIsFractional)
+      {
+        //                Add fractional config
+        int i=0;
+        int size = fractionalConf.length;
+        for (String fracCfgValue : fractionalConf) // Add fractional operational attributes
+        {
+          if (i==0)
+          {
+            // First string is the class
+            exportLdif += "ds-sync-fractional-include: " + fracCfgValue + ":";
+          }
+          else
+          {
+            // Other strings are attributes
+            exportLdif += fracCfgValue + ( (i<size-1) ? "," : "," + SYNCHRO_OPTIONAL_ATTR + "\n");
+          }
+            i++;
+        }
+      }
+      //      Org Entry
+      exportLdif += "\ndn: " + TEST2_ORG_DN_STRING + "\n" +
+        "objectClass: top\n" +
+        "objectClass: organization\n" +
+        "o: test2\n\n";
+      //      User entry
+      exportLdif += "dn: " + ENTRY_DN2 + "\n" + "objectClass: top\n" +
+        "objectClass: person\n" + "objectClass: organizationalPerson\n" +
+        "objectClass: inetOrgPerson\n" +
+        "sn: snValue\n" + "cn: cnValue\n" + "uid: 1\n" + "entryUUID: " +
+        ENTRY_UUID + "\n" + OPTIONAL_ATTR + ": " + OPTIONAL_ATTR + "Value\n";      
+      //                Add attributes concerned by fractional configuration
+      boolean first = true;
+      for (String fracCfgValue : fractionalConf)
+      {
+        if (!first)
+        {
+          // First string is the class
+          exportLdif += fracCfgValue + ": " + fracCfgValue + "Value\n";
+        }
+        first = false;
+      }
+      exportLdif += "\n"; // Needed ?
+
+      replicationDomain.initExport(exportLdif, 2);
+
+      // Perform full update from fake domain to fractional domain
+      replicationDomain.initializeRemote(DS1_ID);
+
+      /*
+       * Chack fractional domain is operational and that filtering has been done
+       * during the full update
+       */
+
+      // The domain should go back in normal status
+      waitForDomainStatus(fractionalReplicationDomain,
+        ServerStatus.NORMAL_STATUS, 5);
+
+      // check that entry has been created and that it does not contain
+      // forbidden attributes
+      Entry newEntry = null;
+      try
+      {
+        newEntry = getEntry(DN.decode(ENTRY_DN2), TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been created: " + e.getMessage());
+      }
+      checkEntryFilteredAfterAdd(newEntry, INCLUDE_FRAC_MODE, fractionalConf);
+
+      // perform modify operation (modify forbidden attributes +
+      // modify authorized attribute (not a no op))
+      sendModifyMsg(false, fractionalConf);
+
+      // Wait for modify operation being replayed and
+      // check that entry does not contain forbidden attributes
+      Entry entry = null;
+      boolean synchroAttrFound = false;
+      int timeout = TIMEOUT;
+      while(timeout>0)
+      {
+        try
+        {
+          entry = getEntry(DN.decode(ENTRY_DN2), TIMEOUT, true);
+          if (entry.hasAttribute(DirectoryServer.getAttributeType(SYNCHRO_OPTIONAL_ATTR.toLowerCase())))
+          {
+            synchroAttrFound = true;
+            break;
+          }
+          Thread.sleep(1000);
+          timeout--;
+        } catch (Exception e)
+        {
+          fail("Error waiting for modify operation being replayed : " + e.getMessage());
+        }
+      }
+      assertTrue(synchroAttrFound, "Modify operation not replayed");
+      checkEntryFilteredAfterModify(entry, INCLUDE_FRAC_MODE, fractionalConf);
+    }
+    finally
+    {
+      endTest();
+    }
+  }
+
+  /**
+   * Tests an add operation on an entry with RDN containing forbidden attribute
+   * by fractional exclude configuration
+   */
+  @Test
+  public void testAddWithForbiddenAttrInRDNExclude()
+  {
+     String testcase = "testAddWithForbiddenAttrInRDNExclude";
+
+    initTest();
+
+    try
+    {
+      // create replication server
+      createReplicationServer(testcase);
+
+      // create fractional domain with the passed fractional configuration
+      createFractionalDomain(true, EXCLUDE_FRAC_MODE,
+        new String[] {"inetOrgPerson", "displayName", "description"});
+
+      // create fake domain to send operations
+      createFakeReplicationDomain(true, readGenIdFromSuffixRootEntry(TEST_ROOT_DN_STRING));
+
+      /*
+       * Perform add operation with fornbidden attribute in RDN
+       */
+
+      String entryLdif = "dn: displayName=ValueToBeKept," +
+        TEST_ROOT_DN_STRING + "\n" + "objectClass: top\n" +
+        "objectClass: person\n" + "objectClass: organizationalPerson\n" +
+        "objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
+        "entryUUID: " + ENTRY_UUID + "\n" +
+        "displayName: ValueToBeKept\ndisplayName: displayNameValue\n";
+
+      Entry entry = null;
+      try
+      {
+        entry = TestCaseUtils.entryFromLdifString(entryLdif);
+      } catch (Exception e)
+      {
+        fail(e.getMessage());
+      }
+
+      // Create an update message to add an entry.
+      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
+        entry.getDN().toString(),
+        ENTRY_UUID,
+        null,
+        entry.getObjectClassAttribute(),
+        entry.getAttributes(), new ArrayList<Attribute>());
+
+      replicationDomain.publish(addMsg);
+
+      /*
+       * check that entry has been created and has attribute values from RDN
+       * only
+       */
+
+      Entry newEntry = null;
+      try
+      {
+        newEntry = getEntry(entry.getDN(), TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been added: " + e.getMessage());
+      }
+      assertNotNull(newEntry);
+      assertEquals(entry.getDN(), newEntry.getDN());
+      ObjectClass objectClass = DirectoryServer.getObjectClass("inetOrgPerson".toLowerCase());
+      assertTrue(newEntry.hasObjectClass(objectClass));
+      checkEntryAttributeValue(newEntry, "displayName", "ValueToBeKept");
+
+      /**
+       * Now perform same test, but with 2 forbidden attributes in RDN, using '+'
+       */
+
+      /*
+       * Perform add operation with fornbidden attribute in RDN
+       */
+
+      entryLdif = "dn: displayName=ValueToBeKept+description=ValueToBeKeptToo," +
+        TEST_ROOT_DN_STRING + "\n" + "objectClass: top\n" +
+        "objectClass: person\n" + "objectClass: organizationalPerson\n" +
+        "objectClass: inetOrgPerson\n" + "entryUUID: " + ENTRY_UUID2 + "\n" +
+        "sn: snValue\n" + "cn: cnValue\n" +
+        "displayName: ValueToBeKept\ndisplayName: displayNameValue\n" +
+        "description: descriptionValue\ndescription: ValueToBeKeptToo\n";
+
+      try
+      {
+        entry = TestCaseUtils.entryFromLdifString(entryLdif);
+      } catch (Exception e)
+      {
+        fail(e.getMessage());
+      }
+
+      // Create an update message to add an entry.
+      addMsg = new AddMsg(gen.newChangeNumber(),
+        entry.getDN().toString(),
+        ENTRY_UUID2,
+        null,
+        entry.getObjectClassAttribute(),
+        entry.getAttributes(), new ArrayList<Attribute>());
+
+      replicationDomain.publish(addMsg);
+
+      /*
+       * check that entry has been created and has attribute values from RDN
+       * only
+       */
+
+      try
+      {
+        newEntry = getEntry(entry.getDN(), TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been added: " + e.getMessage());
+      }
+      assertNotNull(newEntry);
+      assertEquals(entry.getDN(), newEntry.getDN());
+      objectClass = DirectoryServer.getObjectClass("inetOrgPerson".toLowerCase());
+      assertTrue(newEntry.hasObjectClass(objectClass));
+      checkEntryAttributeValue(newEntry, "displayName", "ValueToBeKept");
+      checkEntryAttributeValue(newEntry, "description", "ValueToBeKeptToo");
+    }
+    finally
+    {
+      endTest();
+    }
+  }
+
+  /**
+   * Tests an add operation on an entry with RDN containing forbidden attribute
+   * by fractional include configuration
+   */
+  @Test
+  public void testAddWithForbiddenAttrInRDNInclude()
+  {
+     String testcase = "testAddWithForbiddenAttrInRDNInclude";
+
+    initTest();
+
+    try
+    {
+      // create replication server
+      createReplicationServer(testcase);
+
+      // create fractional domain with the passed fractional configuration
+      createFractionalDomain(true, INCLUDE_FRAC_MODE,
+        new String[] {"inetOrgPerson", "carLicense"});
+
+      // create fake domain to send operations
+      createFakeReplicationDomain(true, readGenIdFromSuffixRootEntry(TEST_ROOT_DN_STRING));
+
+      /*
+       * Perform add operation with fornbidden attribute in RDN
+       */
+
+      String entryLdif = "dn: displayName=ValueToBeKept," +
+        TEST_ROOT_DN_STRING + "\n" + "objectClass: top\n" +
+        "objectClass: person\n" + "objectClass: organizationalPerson\n" +
+        "objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
+        "entryUUID: " + ENTRY_UUID + "\n" +
+        "displayName: ValueToBeKept\ndisplayName: displayNameValue\n" +
+        "carLicense: cirLicenseValue\n";
+
+
+      Entry entry = null;
+      try
+      {
+        entry = TestCaseUtils.entryFromLdifString(entryLdif);
+      } catch (Exception e)
+      {
+        fail(e.getMessage());
+      }
+
+      // Create an update message to add an entry.
+      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
+        entry.getDN().toString(),
+        ENTRY_UUID,
+        null,
+        entry.getObjectClassAttribute(),
+        entry.getAttributes(), new ArrayList<Attribute>());
+
+      replicationDomain.publish(addMsg);
+
+      /*
+       * check that entry has been created and has attribute values from RDN
+       * only
+       */
+
+      Entry newEntry = null;
+      try
+      {
+        newEntry = getEntry(entry.getDN(), TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been added: " + e.getMessage());
+      }
+      assertNotNull(newEntry);
+      assertEquals(entry.getDN(), newEntry.getDN());
+      ObjectClass objectClass = DirectoryServer.getObjectClass("inetOrgPerson".toLowerCase());
+      assertTrue(newEntry.hasObjectClass(objectClass));
+      checkEntryAttributeValue(newEntry, "displayName", "ValueToBeKept");
+      checkEntryAttributeValue(newEntry, "carLicense", "cirLicenseValue");
+
+      /**
+       * Now perform same test, but with 2 forbidden attributes in RDN, using '+'
+       */
+
+      /*
+       * Perform add operation with fornbidden attribute in RDN
+       */
+
+      entryLdif = "dn: displayName=ValueToBeKept+description=ValueToBeKeptToo," +
+        TEST_ROOT_DN_STRING + "\n" + "objectClass: top\n" +
+        "objectClass: person\n" + "objectClass: organizationalPerson\n" +
+        "objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
+        "entryUUID: " + ENTRY_UUID2 + "\n" +
+        "displayName: ValueToBeKept\ndisplayName: displayNameValue\n" +
+        "description: descriptionValue\ndescription: ValueToBeKeptToo\n" +
+        "carLicense: cirLicenseValue\n";
+
+      try
+      {
+        entry = TestCaseUtils.entryFromLdifString(entryLdif);
+      } catch (Exception e)
+      {
+        fail(e.getMessage());
+      }
+
+      // Create an update message to add an entry.
+      addMsg = new AddMsg(gen.newChangeNumber(),
+        entry.getDN().toString(),
+        ENTRY_UUID2,
+        null,
+        entry.getObjectClassAttribute(),
+        entry.getAttributes(), new ArrayList<Attribute>());
+
+      replicationDomain.publish(addMsg);
+
+      /*
+       * check that entry has been created and has attribute values from RDN
+       * only
+       */
+
+      try
+      {
+        newEntry = getEntry(entry.getDN(), TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been added: " + e.getMessage());
+      }
+      assertNotNull(newEntry);
+      assertEquals(entry.getDN(), newEntry.getDN());
+      objectClass = DirectoryServer.getObjectClass("inetOrgPerson".toLowerCase());
+      assertTrue(newEntry.hasObjectClass(objectClass));
+      checkEntryAttributeValue(newEntry, "displayName", "ValueToBeKept");
+      checkEntryAttributeValue(newEntry, "description", "ValueToBeKeptToo");
+      checkEntryAttributeValue(newEntry, "carLicense", "cirLicenseValue");
+    }
+    finally
+    {
+      endTest();
+    }
+  }
+
+  /**
+   * Tests modify dn operation on an entry with old RDN containing forbidden
+   * attribute by fractional exclude configuration
+   */
+  @Test
+  public void testModifyDnWithForbiddenAttrInRDNExclude()
+  {
+     String testcase = "testModifyDnWithForbiddenAttrInRDNExclude";
+
+    initTest();
+
+    try
+    {
+      // create replication server
+      createReplicationServer(testcase);
+
+      // create fractional domain with the passed fractional configuration
+      createFractionalDomain(true, EXCLUDE_FRAC_MODE,
+        new String[] {"inetOrgPerson", "displayName", "description"});
+
+      // create fake domain to send operations
+      createFakeReplicationDomain(true, readGenIdFromSuffixRootEntry(TEST_ROOT_DN_STRING));
+
+      /*
+       * Perform add operation with fornbidden attribute in RDN
+       */
+
+      String entryName = "displayName=ValueToBeKept+description=ValueToBeRemoved," + TEST_ROOT_DN_STRING ;
+      String entryLdif = "dn: " + entryName + "\n" + "objectClass: top\n" +
+        "objectClass: person\n" + "objectClass: organizationalPerson\n" +
+        "objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
+        "entryUUID: " + ENTRY_UUID + "\n" +
+        "displayName: ValueToBeKept\ndescription: ValueToBeRemoved\n";
+
+      Entry entry = null;
+      try
+      {
+        entry = TestCaseUtils.entryFromLdifString(entryLdif);
+      } catch (Exception e)
+      {
+        fail(e.getMessage());
+      }
+
+      // Create an update message to add an entry.
+      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
+        entry.getDN().toString(),
+        ENTRY_UUID,
+        null,
+        entry.getObjectClassAttribute(),
+        entry.getAttributes(), new ArrayList<Attribute>());
+
+      replicationDomain.publish(addMsg);
+
+      /*
+       * check that entry has been created and has attribute values from RDN
+       */
+
+      Entry newEntry = null;
+      try
+      {
+        newEntry = getEntry(entry.getDN(), TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been added: " + e.getMessage());
+      }
+      assertNotNull(newEntry);
+      assertEquals(entry.getDN(), newEntry.getDN());
+      ObjectClass objectClass = DirectoryServer.getObjectClass("inetOrgPerson".toLowerCase());
+      assertTrue(newEntry.hasObjectClass(objectClass));
+      checkEntryAttributeValue(newEntry, "displayName", "ValueToBeKept");
+      checkEntryAttributeValue(newEntry, "description", "ValueToBeRemoved");
+
+      /*
+       * Perform modify dn operation by renaming the entry keeping only one of
+       * the forbidden attributes
+       */
+
+      String newEntryName = "displayName=ValueToBeKept," + TEST_ROOT_DN_STRING ;
+      DN newEntryDn = null;
+      try
+      {
+        newEntryDn = DN.decode(newEntryName);
+      } catch(DirectoryException e)
+      {
+        fail("Could not get DN from string: " + newEntryName);
+      }
+
+      // Create modify dn message to modify the entry.
+      ModifyDNMsg modDnMsg = new ModifyDNMsg(entryName, gen.newChangeNumber(),
+        ENTRY_UUID, ENTRY_UUID3, false, TEST_ROOT_DN_STRING,
+        "displayName=ValueToBeKept", null);
+
+      replicationDomain.publish(modDnMsg);
+
+      /*
+       * check that entry has been renamed  and has only attribute left in the
+       * new RDN
+       */
+
+      try
+      {
+        newEntry = getEntry(newEntryDn, TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been added: " + e.getMessage());
+      }
+      assertNotNull(newEntry);
+      assertEquals(newEntryDn, newEntry.getDN());
+      objectClass = DirectoryServer.getObjectClass("inetOrgPerson".toLowerCase());
+      assertTrue(newEntry.hasObjectClass(objectClass));
+      checkEntryAttributeValue(newEntry, "displayName", "ValueToBeKept");
+      assertNull(newEntry.getAttribute("description"));
+    }
+    finally
+    {
+      endTest();
+    }
+  }
+
+  /**
+   * Tests modify dn operation on an entry with old RDN containing forbidden
+   * attribute by fractional include configuration
+   */
+  @Test
+  public void testModifyDnWithForbiddenAttrInRDNInclude()
+  {
+     String testcase = "testModifyDnWithForbiddenAttrInRDNInclude";
+
+    initTest();
+
+    try
+    {
+      // create replication server
+      createReplicationServer(testcase);
+
+      // create fractional domain with the passed fractional configuration
+      createFractionalDomain(true, INCLUDE_FRAC_MODE,
+        new String[] {"inetOrgPerson", "carLicense"});
+
+      // create fake domain to send operations
+      createFakeReplicationDomain(true, readGenIdFromSuffixRootEntry(TEST_ROOT_DN_STRING));
+
+      /*
+       * Perform add operation with fornbidden attribute in RDN
+       */
+
+      String entryName = "displayName=ValueToBeKept+description=ValueToBeRemoved," + TEST_ROOT_DN_STRING ;
+      String entryLdif = "dn: " + entryName + "\n" + "objectClass: top\n" +
+        "objectClass: person\n" + "objectClass: organizationalPerson\n" +
+        "objectClass: inetOrgPerson\n" + "sn: snValue\n" + "cn: cnValue\n" +
+        "entryUUID: " + ENTRY_UUID + "\n" +
+        "displayName: ValueToBeKept\ndescription: ValueToBeRemoved\n";
+
+      Entry entry = null;
+      try
+      {
+        entry = TestCaseUtils.entryFromLdifString(entryLdif);
+      } catch (Exception e)
+      {
+        fail(e.getMessage());
+      }
+
+      // Create an update message to add an entry.
+      AddMsg addMsg = new AddMsg(gen.newChangeNumber(),
+        entry.getDN().toString(),
+        ENTRY_UUID,
+        null,
+        entry.getObjectClassAttribute(),
+        entry.getAttributes(), new ArrayList<Attribute>());
+
+      replicationDomain.publish(addMsg);
+
+      /*
+       * check that entry has been created and has attribute values from RDN
+       */
+
+      Entry newEntry = null;
+      try
+      {
+        newEntry = getEntry(entry.getDN(), TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been added: " + e.getMessage());
+      }
+      assertNotNull(newEntry);
+      assertEquals(entry.getDN(), newEntry.getDN());
+      ObjectClass objectClass = DirectoryServer.getObjectClass("inetOrgPerson".toLowerCase());
+      assertTrue(newEntry.hasObjectClass(objectClass));
+      checkEntryAttributeValue(newEntry, "displayName", "ValueToBeKept");
+      checkEntryAttributeValue(newEntry, "description", "ValueToBeRemoved");
+
+      /*
+       * Perform modify dn operation by renaming the entry keeping only one of
+       * the forbidden attributes
+       */
+
+      String newEntryName = "displayName=ValueToBeKept," + TEST_ROOT_DN_STRING ;
+      DN newEntryDn = null;
+      try
+      {
+        newEntryDn = DN.decode(newEntryName);
+      } catch(DirectoryException e)
+      {
+        fail("Could not get DN from string: " + newEntryName);
+      }
+
+      // Create modify dn message to modify the entry.
+      ModifyDNMsg modDnMsg = new ModifyDNMsg(entryName, gen.newChangeNumber(),
+        ENTRY_UUID, ENTRY_UUID3, false, TEST_ROOT_DN_STRING,
+        "displayName=ValueToBeKept", null);
+
+      replicationDomain.publish(modDnMsg);
+
+      /*
+       * check that entry has been renamed  and has only attribute left in the
+       * new RDN
+       */
+
+      try
+      {
+        newEntry = getEntry(newEntryDn, TIMEOUT, true);
+      } catch(Exception e)
+      {
+        fail("Entry has not been added: " + e.getMessage());
+      }
+      assertNotNull(newEntry);
+      assertEquals(newEntryDn, newEntry.getDN());
+      objectClass = DirectoryServer.getObjectClass("inetOrgPerson".toLowerCase());
+      assertTrue(newEntry.hasObjectClass(objectClass));
+      checkEntryAttributeValue(newEntry, "displayName", "ValueToBeKept");
+      assertNull(newEntry.getAttribute("description"));
+    }
+    finally
+    {
+      endTest();
+    }
+  }
+}

--
Gitblit v1.10.0