From 55a07ce2479e1b4c74dec15ce4e78e3fdf50a27c Mon Sep 17 00:00:00 2001
From: mrossign <mrossign@localhost>
Date: Wed, 16 Sep 2009 08:34:51 +0000
Subject: [PATCH] Fix for #4098 Initializing a fractional domain through import-ldif when server is down does not work

---
 opends/resource/schema/02-config.ldif                                                                     |    6 
 opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml                                 |    7 
 opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java                                 |   18 
 opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java |    8 
 opends/src/server/org/opends/server/api/plugin/PluginType.java                                            |    8 
 opends/src/server/org/opends/server/core/PluginConfigManager.java                                         |   33 +
 opends/resource/config/config.ldif                                                                        |    1 
 opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java                            |    3 
 opends/src/admin/defn/org/opends/server/admin/std/PluginRootConfiguration.xml                             |   31 +
 opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java                    |  302 +++++++++++-
 opends/src/server/org/opends/server/util/LDIFReader.java                                                  |    2 
 opends/src/messages/messages/jeb.properties                                                               |    2 
 opends/src/messages/messages/replication.properties                                                       |   12 
 opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java                         |  947 +++++++++++++++++++++++-----------------
 14 files changed, 926 insertions(+), 454 deletions(-)

diff --git a/opends/resource/config/config.ldif b/opends/resource/config/config.ldif
index dddfa54..0d2490a 100644
--- a/opends/resource/config/config.ldif
+++ b/opends/resource/config/config.ldif
@@ -1841,6 +1841,7 @@
 ds-cfg-java-class: org.opends.server.replication.plugin.FractionalLDIFImportPlugin
 ds-cfg-enabled: true
 ds-cfg-plugin-type: ldifImport
+ds-cfg-plugin-type: ldifImportEnd
 ds-cfg-invoke-for-internal-operations: true
 
 dn: cn=Root DNs,cn=config
diff --git a/opends/resource/schema/02-config.ldif b/opends/resource/schema/02-config.ldif
index 7cf8c0c..5886eec 100644
--- a/opends/resource/schema/02-config.ldif
+++ b/opends/resource/schema/02-config.ldif
@@ -2439,6 +2439,11 @@
   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.599
+  NAME 'ds-cfg-plugin-order-ldif-import-end'
+  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+  SINGLE-VALUE
+  X-ORIGIN 'OpenDS Directory Server' )
 objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
   NAME 'ds-cfg-access-control-handler'
   SUP top
@@ -3496,6 +3501,7 @@
         ds-cfg-plugin-order-post-connect $
         ds-cfg-plugin-order-post-disconnect $
         ds-cfg-plugin-order-ldif-import $
+        ds-cfg-plugin-order-ldif-import-end $
         ds-cfg-plugin-order-ldif-export $
         ds-cfg-plugin-order-pre-parse-abandon $
         ds-cfg-plugin-order-pre-parse-add $
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml
index e67d28a..f1ae106 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/PluginConfiguration.xml
@@ -23,7 +23,7 @@
   ! CDDL HEADER END
   !
   !
-  !      Copyright 2007-2008 Sun Microsystems, Inc.
+  !      Copyright 2007-2009 Sun Microsystems, Inc.
   ! -->
 <adm:managed-object name="plugin" plural-name="plugins"
   package="org.opends.server.admin.std"
@@ -116,6 +116,11 @@
             Invoked for each entry read during an LDIF import.
           </adm:synopsis>
         </adm:value>
+        <adm:value name="ldifimportend">
+          <adm:synopsis>
+            Invoked at the end of an LDIF import session.
+          </adm:synopsis>
+        </adm:value>
         <adm:value name="ldifexport">
           <adm:synopsis>
             Invoked for each operation to be written during an LDIF
diff --git a/opends/src/admin/defn/org/opends/server/admin/std/PluginRootConfiguration.xml b/opends/src/admin/defn/org/opends/server/admin/std/PluginRootConfiguration.xml
index 05d220c..45e8c9e 100644
--- a/opends/src/admin/defn/org/opends/server/admin/std/PluginRootConfiguration.xml
+++ b/opends/src/admin/defn/org/opends/server/admin/std/PluginRootConfiguration.xml
@@ -23,7 +23,7 @@
   ! CDDL HEADER END
   !
   !
-  !      Copyright 2007-2008 Sun Microsystems, Inc.
+  !      Copyright 2007-2009 Sun Microsystems, Inc.
   ! -->
 <adm:managed-object name="plugin-root" plural-name="plugin-roots"
   package="org.opends.server.admin.std"
@@ -204,6 +204,35 @@
       </ldap:attribute>
     </adm:profile>
   </adm:property>
+  <adm:property name="plugin-order-ldif-import-end">
+    <adm:synopsis>
+      Specifies the order in which LDIF import end plug-ins are to be loaded
+      and invoked.
+    </adm:synopsis>
+    <adm:description>
+      The value is a comma-delimited list of plug-in
+      names (where the plug-in name is the RDN value from the plug-in
+      configuration entry DN). The list can include at most one asterisk
+      to indicate the position of any unspecified plug-in (and the
+      relative order of those unspecified plug-ins is undefined).
+    </adm:description>
+    <adm:default-behavior>
+      <adm:alias>
+        <adm:synopsis>
+          The order in which LDIF import end plug-ins are loaded and invoked
+          is undefined.
+        </adm:synopsis>
+      </adm:alias>
+    </adm:default-behavior>
+    <adm:syntax>
+      <adm:string />
+    </adm:syntax>
+    <adm:profile name="ldap">
+      <ldap:attribute>
+        <ldap:name>ds-cfg-plugin-order-ldif-import-end</ldap:name>
+      </ldap:attribute>
+    </adm:profile>
+  </adm:property>
   <adm:property name="plugin-order-ldif-export">
     <adm:synopsis>
       Specifies the order in which LDIF export plug-ins are to be loaded
diff --git a/opends/src/messages/messages/jeb.properties b/opends/src/messages/messages/jeb.properties
index 5070dd6..e75be31 100644
--- a/opends/src/messages/messages/jeb.properties
+++ b/opends/src/messages/messages/jeb.properties
@@ -343,7 +343,7 @@
 NOTICE_JEB_IMPORT_LDIF_LOG_BYTES_184=Setting DB log byte size to %d bytes
 NOTICE_JEB_IMPORT_LDIF_DB_MEM_BUF_INFO_185=Setting DB cache size to %d bytes \
  and phase one buffer size to to %d bytes
-NOTICE_JEB_IMPORT_LDIF_TOT_MEM_BUF_186=The amount of freeemory available to \
+NOTICE_JEB_IMPORT_LDIF_TOT_MEM_BUF_186=The amount of free memory available to \
 the import task is %d bytes. The number of phase one buffers required is \
 %d buffers
 NOTICE_JEB_IMPORT_LDIF_BUFFER_CHECKPOINTS_187=Checkpoints performed: %d
diff --git a/opends/src/messages/messages/replication.properties b/opends/src/messages/messages/replication.properties
index 6636253..ba4ca5b 100644
--- a/opends/src/messages/messages/replication.properties
+++ b/opends/src/messages/messages/replication.properties
@@ -414,5 +414,13 @@
  database of the draft change number : %s
 SEVERE_ERR_INITIALIZATION_FAILED_NOCONN_174=The initialization failed because \
  the domain %s is not connected to a replication server
-
- 
\ No newline at end of file
+SEVERE_ERR_FRACTIONAL_COULD_NOT_RETRIEVE_CONFIG_175=Could not retrieve the \
+ configuration for a replication domain matching the entry %s
+NOTICE_ERR_LDIF_IMPORT_FRACTIONAL_BAD_DATA_SET_176=The LDIF import for \
+ importing suffix %s data has been stopped due to fractional configuration \
+ inconsistency : imported data set has not the same fractional configuration \
+ as local server
+NOTICE_ERR_LDIF_IMPORT_FRACTIONAL_DATA_SET_IS_FRACTIONAL_177=The LDIF import \
+ for importing suffix %s data has been stopped due to fractional configuration \
+ inconsistency : imported data set has some fractional configuration but not \
+ local server
\ No newline at end of file
diff --git a/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java b/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
index 4ce5818..2f6653d 100644
--- a/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
+++ b/opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.api.plugin;
 import org.opends.messages.Message;
@@ -312,7 +312,6 @@
   }
 
 
-
   /**
    * Performs any necessary processing that should be done during an
    * LDIF import operation immediately after reading an entry and
@@ -333,7 +332,20 @@
     throw new UnsupportedOperationException(message.toString());
   }
 
-
+  /**
+   * Terminates an import session.
+   * Performs any necessary processing that should be done at the end
+   * of an LDIF import session based on the provided configuration.
+   *
+   * @param  importConfig  The configuration used for the LDIF import.
+   */
+  public void doLDIFImportEnd(LDIFImportConfig importConfig)
+  {
+    Message message = ERR_PLUGIN_TYPE_NOT_SUPPORTED.get(
+        String.valueOf(pluginDN),
+        PluginType.LDIF_IMPORT_END.getName());
+    throw new UnsupportedOperationException(message.toString());
+  }
 
   /**
    * Performs any necessary processing that should be done during an
diff --git a/opends/src/server/org/opends/server/api/plugin/PluginType.java b/opends/src/server/org/opends/server/api/plugin/PluginType.java
index dd5d5f2..23bf480 100644
--- a/opends/src/server/org/opends/server/api/plugin/PluginType.java
+++ b/opends/src/server/org/opends/server/api/plugin/PluginType.java
@@ -86,6 +86,14 @@
 
 
   /**
+   * The plugin type for plugins that are to be invoked for each
+   * import session end.
+   */
+  LDIF_IMPORT_END("ldifimportend"),
+
+
+
+  /**
    * The plugin type for plugins that are to be invoked for each entry
    * written during an LDIF export.
    */
diff --git a/opends/src/server/org/opends/server/core/PluginConfigManager.java b/opends/src/server/org/opends/server/core/PluginConfigManager.java
index 43bc080..92cd78e 100644
--- a/opends/src/server/org/opends/server/core/PluginConfigManager.java
+++ b/opends/src/server/org/opends/server/core/PluginConfigManager.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.core;
 
@@ -90,6 +90,7 @@
   private DirectoryServerPlugin[] postConnectPlugins;
   private DirectoryServerPlugin[] postDisconnectPlugins;
   private DirectoryServerPlugin[] ldifImportPlugins;
+  private DirectoryServerPlugin[] ldifImportEndPlugins;
   private DirectoryServerPlugin[] ldifExportPlugins;
   private DirectoryServerPlugin[] preParseAbandonPlugins;
   private DirectoryServerPlugin[] preParseAddPlugins;
@@ -174,6 +175,7 @@
     postConnectPlugins                 = new DirectoryServerPlugin[0];
     postDisconnectPlugins              = new DirectoryServerPlugin[0];
     ldifImportPlugins                  = new DirectoryServerPlugin[0];
+    ldifImportEndPlugins               = new DirectoryServerPlugin[0];
     ldifExportPlugins                  = new DirectoryServerPlugin[0];
     preParseAbandonPlugins             = new DirectoryServerPlugin[0];
     preParseAddPlugins                 = new DirectoryServerPlugin[0];
@@ -423,6 +425,7 @@
       case POSTCONNECT:            return PluginType.POST_CONNECT;
       case POSTDISCONNECT:         return PluginType.POST_DISCONNECT;
       case LDIFIMPORT:             return PluginType.LDIF_IMPORT;
+      case LDIFIMPORTEND:          return PluginType.LDIF_IMPORT_END;
       case LDIFEXPORT:             return PluginType.LDIF_EXPORT;
       case PREPARSEABANDON:        return PluginType.PRE_PARSE_ABANDON;
       case PREPARSEADD:            return PluginType.PRE_PARSE_ADD;
@@ -595,6 +598,11 @@
                  addPlugin(ldifImportPlugins, plugin, t,
                            pluginRootConfig.getPluginOrderLDIFImport());
             break;
+          case LDIF_IMPORT_END:
+            ldifImportEndPlugins =
+                 addPlugin(ldifImportEndPlugins, plugin, t,
+                           pluginRootConfig.getPluginOrderLDIFImportEnd());
+            break;
           case LDIF_EXPORT:
             ldifExportPlugins =
                  addPlugin(ldifExportPlugins, plugin, t,
@@ -1088,6 +1096,9 @@
           case LDIF_IMPORT:
             ldifImportPlugins = removePlugin(ldifImportPlugins, plugin);
             break;
+          case LDIF_IMPORT_END:
+            ldifImportEndPlugins = removePlugin(ldifImportEndPlugins, plugin);
+            break;
           case LDIF_EXPORT:
             ldifExportPlugins = removePlugin(ldifExportPlugins, plugin);
             break;
@@ -1558,7 +1569,7 @@
 
 
 
-  /**
+/**
    * Invokes the set of LDIF import plugins that have been configured in the
    * Directory Server.
    *
@@ -1622,6 +1633,24 @@
 
 
   /**
+   * Invokes the LDIF import session finalization of LDIF import plugins that
+   * have been configured in the Directory Server.
+   *
+   * @param  importConfig  The LDIF import configuration used for the LDIF
+   *                       import session.
+   */
+  public void invokeLDIFImportEndPlugins(
+      LDIFImportConfig importConfig)
+  {
+    for (DirectoryServerPlugin p : ldifImportEndPlugins)
+    {
+      p.doLDIFImportEnd(importConfig);
+    }
+  }
+
+
+
+  /**
    * Invokes the set of LDIF export plugins that have been configured in the
    * Directory Server.
    *
diff --git a/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java b/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java
index 9afb119..1f43a02 100644
--- a/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java
+++ b/opends/src/server/org/opends/server/replication/plugin/FractionalLDIFImportPlugin.java
@@ -27,6 +27,7 @@
 package org.opends.server.replication.plugin;
 
 import java.util.ArrayList;
+import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -34,24 +35,31 @@
 
 import org.opends.messages.Message;
 import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ServerManagementContext;
 import org.opends.server.admin.std.server.FractionalLDIFImportPluginCfg;
 import org.opends.server.admin.std.server.PluginCfg;
+import org.opends.server.admin.std.server.ReplicationDomainCfg;
+import org.opends.server.admin.std.server.ReplicationSynchronizationProviderCfg;
+import org.opends.server.admin.std.server.RootCfg;
 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.replication.plugin.LDAPReplicationDomain.
+  FractionalConfig;
 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.
+ * replication to initialize a just configured fractional domain (when an online
+ * full update occurs or offline/online ldif import).
  * 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)
+ * - check that the fractional configuration (if any) stored in the (incoming)
+ * 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)
@@ -60,6 +68,57 @@
   extends DirectoryServerPlugin<FractionalLDIFImportPluginCfg>
   implements ConfigurationChangeListener<FractionalLDIFImportPluginCfg>
 {
+  // Holds the fractional configuration and if available the replication domain
+  // matching this import session (they form the importfractional context).
+  // Domain is available if the server is online (import-ldif, online full
+  // update..) otherwise, this is an import-ldif with server off. The key is the
+  // ImportConfig object of the session which acts as a cookie for the whole
+  // session. This allows to potentially run man imports at the same time.
+  private final Hashtable<LDIFImportConfig, ImportFractionalContext>
+    importSessionContexts = new Hashtable<LDIFImportConfig,
+    ImportFractionalContext>();
+
+  /**
+   * Holds an import session fractional context.
+   */
+  private static class ImportFractionalContext
+  {
+    // Fractional configuration of the local domain (may be null if import on a
+    // not replicated domain)
+    private FractionalConfig fractionalConfig = null;
+    // The local domain object (may stay null if server is offline)
+    private LDAPReplicationDomain domain = null;
+
+    /**
+     * Constructor.
+     * @param fractionalConfig
+     * @param domain
+     */
+    public ImportFractionalContext(FractionalConfig fractionalConfig,
+      LDAPReplicationDomain domain)
+    {
+      this.fractionalConfig = fractionalConfig;
+      this.domain = domain;
+    }
+
+    /**
+     * Getter for the fractional configuration.
+     * @return the fractionalConfig
+     */
+    public FractionalConfig getFractionalConfig()
+    {
+      return fractionalConfig;
+    }
+
+    /**
+     * Getter for the domain..
+     * @return the domain
+     */
+    public LDAPReplicationDomain getDomain()
+    {
+      return domain;
+    }
+  }
 
   /**
    * Creates a new instance of this Directory Server plugin.  Every plugin must
@@ -86,6 +145,7 @@
       switch (t)
       {
         case LDIF_IMPORT:
+        case LDIF_IMPORT_END:
           // This is acceptable.
           break;
 
@@ -104,9 +164,81 @@
   @Override()
   public final void finalizePlugin()
   {
+    // Nothing to do
   }
 
   /**
+   * Attempts to retrieve the fractional configuration of the domain being
+   * imported.
+   * @param entry An imported entry of the imported domain
+   * @return The parsed fractional configuration for the domain matching the
+   * passed entry. Null if no configuration is found for the domain
+   * (not a replicated domain).
+   */
+  private static FractionalConfig getStaticReplicationDomainFractionalConfig(
+    Entry entry) throws Exception {
+
+    // Retrieve the configuration
+    ServerManagementContext context = ServerManagementContext.getInstance();
+    RootCfg root = context.getRootConfiguration();
+
+
+    ReplicationSynchronizationProviderCfg sync =
+      (ReplicationSynchronizationProviderCfg)
+      root.getSynchronizationProvider("Multimaster Synchronization");
+
+    String[] domainNames = sync.listReplicationDomains();
+    if (domainNames == null)
+    {
+      // No domain in replication
+      return null;
+    }
+
+    // Find the configuration for domain the entry is part of
+    ReplicationDomainCfg matchingReplicatedDomainCfg = null;
+    for (String domainName : domainNames)
+    {
+      // Get the domain configuration object
+      ReplicationDomainCfg replicationDomainCfg =
+      sync.getReplicationDomain(domainName);
+      // Is the entry a sub entry of the replicated domain main entry ?
+      DN replicatedDn = replicationDomainCfg.getBaseDN();
+      DN entryDn = entry.getDN();
+      if (entryDn.isDescendantOf(replicatedDn))
+      {
+        // Found the matching replicated domain configuration object
+        matchingReplicatedDomainCfg = replicationDomainCfg;
+        break;
+      }
+    }
+
+    if (matchingReplicatedDomainCfg == null)
+    {
+      // No matching replicated domain found
+      return null;
+    }
+
+    // Extract the fractional configuration from the domain configuration object
+    // and return it.
+    return FractionalConfig.toFractionalConfig(matchingReplicatedDomainCfg);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override()
+  public final void doLDIFImportEnd(
+    LDIFImportConfig importConfig)
+  {
+    // Remove the cookie of this import session
+    synchronized(importSessionContexts)
+    {
+      importSessionContexts.remove(importConfig);
+    }
+  }
+
+  /**
+   * See class comment for what we achieve here...
    * {@inheritDoc}
    */
   @Override()
@@ -114,24 +246,93 @@
     LDIFImportConfig importConfig, Entry entry)
   {
     /**
-     * See class comment for what we achieve here...
+     * try to get the import fractional context for this entry. If not found,
+     * create and initialize it. The mechanism here is done to take a lock only
+     * once for the whole import session (except the necessary lock of the
+     * doLDIFImportEnd method)
      */
+    ImportFractionalContext importFractionalContext =
+      importSessionContexts.get(importConfig);
 
-    // Retrieve the replicated domain this entry belongs to
     DN entryDn = entry.getDN();
-    LDAPReplicationDomain domain = MultimasterReplication.findDomain(entryDn,
-      null);
-    if (domain == null)
+    FractionalConfig localFractionalConfig = null;
+
+    // If no context, create it
+    if (importFractionalContext == null)
+    {
+      synchronized(importSessionContexts)
+      {
+        // Insure antoher thread was not creating the context at the same time
+        // (we would create it for the second time which is useless)
+        importFractionalContext = importSessionContexts.get(importConfig);
+        if (importFractionalContext == null)
+        {
+          /*
+           * Create context
+           */
+
+          /**
+           * Retrieve the replicated domain this entry belongs to. Try to
+           * retrieve replication domain instance first. If we are in an online
+           * server, we should get it (if we are treating an entry that belongs
+           * to a replicated domain), otherwise the domain is not replicated or
+           * we are in an offline server context (import-ldif command run with
+           * offline server) and we must retrieve the fractional configuration
+           * directly from the configuration management system.
+           */
+          LDAPReplicationDomain domain =
+            MultimasterReplication.findDomain(entryDn, null);
+
+          // Get the fractional configuration extracted from the local server
+          // configuration for the currently imported domain
+          if (domain == null)
+          {
+            // Server may be offline, attempt to find fractional configuration
+            // from config sub-system
+            try
+            {
+              localFractionalConfig =
+                getStaticReplicationDomainFractionalConfig(entry);
+            } catch (Exception ex)
+            {
+              Message message = ERR_FRACTIONAL_COULD_NOT_RETRIEVE_CONFIG.get(
+                entry.toString());
+              return PluginResult.ImportLDIF.stopEntryProcessing(message);
+            }
+          } else
+          {
+            // Found a live domain, retrieve the fractional configuration from
+            // it.
+            localFractionalConfig = domain.getFractionalConfig();
+          }
+          // Create context and store it
+          importFractionalContext =
+            new ImportFractionalContext(localFractionalConfig, domain);
+          importSessionContexts.put(importConfig, importFractionalContext);
+        }
+      }
+    }
+
+    // Extract the fractional configuration from the context
+    localFractionalConfig = importFractionalContext.getFractionalConfig();
+    if (localFractionalConfig == 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))
+    /**
+     * At this point, either the domain instance has been found and we  use its
+     * fractional configuration, or the server is offline and we use the parsed
+     * fractional configuration. We differentiate both cases testing if domain
+     * is null. We are also for sure handling an entry of a replicated suffix.
+     */
+
+    // Is the entry to handle the root entry of the domain ? If yes, analyze the
+    // fractional configuration in it and compare with local fractional
+    // configuration. Stop the import if some inconsistency is detected
+    DN replicatedDomainBaseDn = localFractionalConfig.getBaseDn();
+    if (replicatedDomainBaseDn.equals(entryDn))
     {
       /*
        * This is the root entry, try to read a fractional configuration from it
@@ -169,8 +370,9 @@
       }
 
       // Compare backend and local fractional configuration
-      boolean sameConfig = domain.isFractionalConfigConsistent(exclIt, inclIt);
-      if (domain.isFractional())
+      boolean sameConfig = LDAPReplicationDomain.
+        isFractionalConfigConsistent(localFractionalConfig, exclIt, inclIt);
+      if (localFractionalConfig.isFractional())
       {
         // Local domain is fractional
         if (sameConfig)
@@ -190,19 +392,28 @@
           }
           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();
+            LDAPReplicationDomain domain = importFractionalContext.getDomain();
+            if (domain != null)
+            {
+              // 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.stopEntryProcessing(null);
+            } else
+            {
+              Message message = NOTE_ERR_LDIF_IMPORT_FRACTIONAL_BAD_DATA_SET.
+                get(replicatedDomainBaseDn.toString());
+              return PluginResult.ImportLDIF.stopEntryProcessing(message);
+            }
           } 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);
+            flushFractionalConfigIntoEntry(localFractionalConfig, entry);
           }
         }
       } else
@@ -215,20 +426,32 @@
           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();
+          LDAPReplicationDomain domain = importFractionalContext.getDomain();
+          if (domain != null)
+          {
+            // 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.stopEntryProcessing(null);
+          } else
+          {
+            Message message =
+              NOTE_ERR_LDIF_IMPORT_FRACTIONAL_DATA_SET_IS_FRACTIONAL.get(
+                replicatedDomainBaseDn.toString());
+            return PluginResult.ImportLDIF.stopEntryProcessing(message);
+          }
         }
       }
     }
 
     // If we get here, local domain fractional configuration is enabled.
     // Now filter for potential attributes to be removed.
-    domain.fractionalRemoveAttributesFromEntry(entry.getDN().getRDN(),
+    LDAPReplicationDomain.fractionalRemoveAttributesFromEntry(
+      localFractionalConfig, entry.getDN().getRDN(),
       entry.getObjectClasses(), entry.getUserAttributes(), true);
 
     return PluginResult.ImportLDIF.continueEntryProcessing();
@@ -240,20 +463,21 @@
    * 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 localFractionalConfig The local domain fractional configuration
    * @param entry The entry to modify
    */
-  private static void flushFractionalConfigIntoEntry(
-    LDAPReplicationDomain domain, Entry entry)
+  private static void flushFractionalConfigIntoEntry(FractionalConfig
+    localFractionalConfig, Entry entry)
   {
-    if (domain.isFractional()) // Paranoia check
+    if (localFractionalConfig.isFractional()) // Paranoia check
     {
       // Get the fractional configuration of the domain
-      boolean fractionalExclusive = domain.isFractionalExclusive();
+      boolean fractionalExclusive =
+        localFractionalConfig.isFractionalExclusive();
       Map<String, List<String>> fractionalSpecificClassesAttributes =
-        domain.getFractionalSpecificClassesAttributes();
+        localFractionalConfig.getFractionalSpecificClassesAttributes();
       List<String> fractionalAllClassesAttributes =
-        domain.getFractionalAllClassesAttributes();
+        localFractionalConfig.getFractionalAllClassesAttributes();
 
       // Create attribute builder for the rigth fractional mode
       String fractAttribute = null;
diff --git a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
index 441af91..3890f49 100644
--- a/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
+++ b/opends/src/server/org/opends/server/replication/plugin/LDAPReplicationDomain.java
@@ -284,60 +284,8 @@
    * 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>();
+  // Holds the fractional configuration for this domain, if any.
+  private FractionalConfig fractionalConfig = null;
 
   /**
    * The list of attributes that cannot be used in fractional replication
@@ -371,7 +319,7 @@
   private boolean followImport = true;
 
   /**
-   * This is the message id to be used when an import is stopped with error by
+   * The message id to be used when an import is stopped with error by
    * the fractional replication ldif import plugin.
    */
   private int importErrorMessageId = -1;
@@ -474,6 +422,7 @@
     readAssuredConfig(configuration, false);
 
     // Get fractional configuration
+    fractionalConfig = new FractionalConfig(baseDn);
     readFractionalConfig(configuration, false);
 
     setGroupId((byte)configuration.getGroupId());
@@ -628,44 +577,6 @@
   }
 
   /**
-   * 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.
@@ -695,34 +606,12 @@
   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;
+    // Read the configuration entry
+    FractionalConfig newFractionalConfig = null;
     try
     {
-      newFractionalMode = parseFractionalConfig(exclIt, inclIt,
-      newFractionalSpecificClassesAttributes,
-      newFractionalAllClassesAttributes);
+      newFractionalConfig = FractionalConfig.toFractionalConfig(
+        configuration);
     }
     catch(ConfigException e)
     {
@@ -738,14 +627,13 @@
     /**
      * Is there any change in fractional configuration ?
      */
+
     // Compute current configuration
-    int fractionalMode = fractionalConfigToInt();
+    boolean needReconnection = false;
      try
     {
-      needReconnection = !isFractionalConfigEquivalent(fractionalMode,
-        fractionalSpecificClassesAttributes, fractionalAllClassesAttributes,
-        newFractionalMode, newFractionalSpecificClassesAttributes,
-        newFractionalAllClassesAttributes);
+      needReconnection = !FractionalConfig.
+        isFractionalConfigEquivalent(fractionalConfig, newFractionalConfig);
     }
     catch  (ConfigException e)
     {
@@ -761,25 +649,28 @@
       disableService();
 
     // Set new configuration
-    fractional = (newFractionalMode != NOT_FRACTIONAL);
-    if (fractional)
+    int newFractionalMode = newFractionalConfig.fractionalConfigToInt();
+    fractionalConfig.setFractional(newFractionalMode !=
+      FractionalConfig.NOT_FRACTIONAL);
+    if (fractionalConfig.isFractional())
     {
       // Set new fractional configuration values
-      if (newFractionalMode == EXCLUSIVE_FRACTIONAL)
-        fractionalExclusive = true;
+      if (newFractionalMode == FractionalConfig.EXCLUSIVE_FRACTIONAL)
+        fractionalConfig.setFractionalExclusive(true);
       else
-        fractionalExclusive = false;
-      fractionalSpecificClassesAttributes =
-        newFractionalSpecificClassesAttributes;
-      fractionalAllClassesAttributes = newFractionalAllClassesAttributes;
+        fractionalConfig.setFractionalExclusive(false);
+      fractionalConfig.setFractionalSpecificClassesAttributes(
+        newFractionalConfig.getFractionalSpecificClassesAttributes());
+      fractionalConfig.setFractionalAllClassesAttributes(
+        newFractionalConfig.fractionalAllClassesAttributes);
     } else
     {
       // Reset default values
-      fractionalExclusive = true;
-      fractionalSpecificClassesAttributes =
-        new HashMap<String, List<String>>();
-      fractionalAllClassesAttributes =
-        new ArrayList<String>();
+      fractionalConfig.setFractionalExclusive(true);
+      fractionalConfig.setFractionalSpecificClassesAttributes(
+        new HashMap<String, List<String>>());
+      fractionalConfig.setFractionalAllClassesAttributes(
+        new ArrayList<String>());
     }
 
     // Reconnect if required
@@ -873,7 +764,7 @@
       // 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)
+      if (fractionalConfig.isFractional())
       {
         return false;
       }
@@ -916,13 +807,14 @@
     }
 
     // Compare backend and local fractional configuration
-    return isFractionalConfigConsistent(exclIt, inclIt);
+    return isFractionalConfigConsistent(fractionalConfig, 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 fractionalConfig The local fractional configuration
    * @param exclIt Fractional exclude mode configuration attribute values to
    * analyze.
    * @param inclIt Fractional include mode configuration attribute values to
@@ -931,7 +823,8 @@
    * configuration attribute values is equivalent to the fractional
    * configuration stored in the local variables.
    */
-  public boolean isFractionalConfigConsistent(Iterator<String> exclIt,
+   static boolean isFractionalConfigConsistent(
+    FractionalConfig fractionalConfig, Iterator<String> exclIt,
     Iterator<String> inclIt)
   {
     /*
@@ -943,68 +836,61 @@
       new HashMap<String, List<String>>();
     List<String> storedFractionalAllClassesAttributes = new ArrayList<String>();
 
-    int storedFractionalMode = NOT_FRACTIONAL;
+    int storedFractionalMode = FractionalConfig.NOT_FRACTIONAL;
     try
     {
-      storedFractionalMode = parseFractionalConfig(exclIt, inclIt,
-        storedFractionalSpecificClassesAttributes,
+      storedFractionalMode = FractionalConfig.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());
+      Message message = NOTE_ERR_FRACTIONAL.get(
+        fractionalConfig.getBaseDn().toString(), e.getLocalizedMessage());
       logError(message);
       return false;
     }
 
+    FractionalConfig storedFractionalConfig = new FractionalConfig(
+      fractionalConfig.getBaseDn());
+    storedFractionalConfig.setFractional(storedFractionalMode !=
+      FractionalConfig.NOT_FRACTIONAL);
+    // Set stored fractional configuration values
+    if (storedFractionalConfig.isFractional())
+    {
+      if (storedFractionalMode == FractionalConfig.EXCLUSIVE_FRACTIONAL)
+        storedFractionalConfig.setFractionalExclusive(true);
+      else
+        storedFractionalConfig.setFractionalExclusive(false);
+    }
+    storedFractionalConfig.setFractionalSpecificClassesAttributes(
+      storedFractionalSpecificClassesAttributes);
+    storedFractionalConfig.setFractionalAllClassesAttributes(
+      storedFractionalAllClassesAttributes);
+
     /*
      * 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);
+      return FractionalConfig.
+        isFractionalConfigEquivalent(fractionalConfig, storedFractionalConfig);
     } 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());
+      Message message = NOTE_ERR_FRACTIONAL.get(
+        fractionalConfig.getBaseDn().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.
    */
@@ -1012,7 +898,6 @@
   {
     private Iterator<AttributeValue> attrValIt = null;
 
-
     /**
      * Creates a new AttributeValueStringIterator object.
      * @param attrValIt The underlying attribute iterator to use, assuming
@@ -1050,83 +935,6 @@
   }
 
   /**
-   * 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.
@@ -1181,112 +989,6 @@
     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...
@@ -1302,43 +1004,21 @@
      * Parse fractional configuration
      */
 
-    // Prepare fractional configuration variables to parse
-    Iterator<String> exclIt = null;
-    SortedSet<String> fractionalExclude = configuration.getFractionalExclude();
-    if (fractionalExclude != null)
-    {
-      exclIt = fractionalExclude.iterator();
-    }
+    // Read the configuration entry
+    FractionalConfig newFractionalConfig = FractionalConfig.toFractionalConfig(
+        configuration);
 
-    Iterator<String> inclIt = null;
-    SortedSet<String> fractionalInclude = configuration.getFractionalInclude();
-    if (fractionalInclude != null)
+    if (!newFractionalConfig.isFractional())
     {
-      inclIt = fractionalInclude.iterator();
+        // Nothing to check
+        return;
     }
 
     // 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;
-    }
+      newFractionalConfig.getFractionalSpecificClassesAttributes();
+    List<String> newFractionalAllClassesAttributes =
+      newFractionalConfig.getFractionalAllClassesAttributes();
 
     /*
      * Check attributes consistency : we only allow to filter MAY (optional)
@@ -1348,6 +1028,7 @@
 
     // Check consistency of specific classes attributes
     Schema schema = DirectoryServer.getSchema();
+    int fractionalMode = newFractionalConfig.fractionalConfigToInt();
     for (String className : newFractionalSpecificClassesAttributes.keySet())
     {
       // Does the class exist ?
@@ -1381,7 +1062,7 @@
           // No more checking for the extensibleObject class
           if (!isExtensibleObjectClass)
           {
-            if (fractionalMode == EXCLUSIVE_FRACTIONAL)
+            if (fractionalMode == FractionalConfig.EXCLUSIVE_FRACTIONAL)
             {
               // Exclusive mode : the attribute must be optional
               if (!fractionalClass.isOptional(attributeType))
@@ -1455,7 +1136,7 @@
   public boolean fractionalFilterOperation(
     PreOperationAddOperation addOperation, boolean performFiltering)
   {
-    return fractionalRemoveAttributesFromEntry(
+    return fractionalRemoveAttributesFromEntry(fractionalConfig,
       addOperation.getEntryDN().getRDN(), addOperation.getObjectClasses(),
       addOperation.getUserAttributes(), performFiltering);
   }
@@ -1494,9 +1175,10 @@
 
     Entry concernedEntry = modifyDNOperation.getOriginalEntry();
     List<String> fractionalConcernedAttributes =
-      createFractionalConcernedAttrList(
+      createFractionalConcernedAttrList(fractionalConfig,
       concernedEntry.getObjectClasses().keySet());
 
+    boolean fractionalExclusive = fractionalConfig.isFractionalExclusive();
     if ( fractionalExclusive && (fractionalConcernedAttributes.size() == 0) )
       // No attributes to filter
       return false;
@@ -1551,10 +1233,11 @@
   }
 
   /**
-   * Remove attributes from an entry, according to the current fractional
+   * Remove attributes from an entry, according to the passed 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 fractionalConfig The fractional configuration to use
    * @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
@@ -1565,9 +1248,10 @@
    * @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)
+   static boolean fractionalRemoveAttributesFromEntry(
+    FractionalConfig fractionalConfig, RDN entryRdn,
+    Map<ObjectClass,String> classes, Map<AttributeType,
+    List<Attribute>> attributesMap, boolean performFiltering)
   {
     boolean hasSomeAttributesToFilter = false;
     /*
@@ -1576,7 +1260,8 @@
      */
 
     List<String> fractionalConcernedAttributes =
-      createFractionalConcernedAttrList(classes.keySet());
+      createFractionalConcernedAttrList(fractionalConfig, classes.keySet());
+    boolean fractionalExclusive = fractionalConfig.isFractionalExclusive();
     if ( fractionalExclusive && (fractionalConcernedAttributes.size() == 0) )
       return false; // No attributes to filter
 
@@ -1724,13 +1409,14 @@
 
   /**
    * Prepares a list of attributes of interest for the fractional feature.
+   * @param fractionalConfig The fractional configuration to use
    * @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)
+  private static List<String> createFractionalConcernedAttrList(
+    FractionalConfig fractionalConfig, Set<ObjectClass> entryObjectClasses)
   {
     /*
      * Is the concerned entry of a type concerned by fractional replication
@@ -1742,6 +1428,11 @@
     List<String> fractionalConcernedAttributes = new ArrayList<String>();
 
     // Get object classes the entry matches
+    List<String> fractionalAllClassesAttributes =
+      fractionalConfig.getFractionalAllClassesAttributes();
+    Map<String, List<String>> fractionalSpecificClassesAttributes =
+      fractionalConfig.getFractionalSpecificClassesAttributes();
+
     Set<String> fractionalClasses =
         fractionalSpecificClassesAttributes.keySet();
     for (ObjectClass entryObjectClass : entryObjectClasses)
@@ -1803,8 +1494,9 @@
 
     Entry modifiedEntry = modifyOperation.getCurrentEntry();
     List<String> fractionalConcernedAttributes =
-      createFractionalConcernedAttrList(
+      createFractionalConcernedAttrList(fractionalConfig,
       modifiedEntry.getObjectClasses().keySet());
+    boolean fractionalExclusive = fractionalConfig.isFractionalExclusive();
     if ( fractionalExclusive && (fractionalConcernedAttributes.size() == 0) )
       // No attributes to filter
       return FRACTIONAL_HAS_NO_FRACTIONAL_FILTERED_ATTRIBUTES;
@@ -1959,7 +1651,7 @@
   protected void initializeRemote(short target, short requestorID,
     Task initTask) throws DirectoryException
   {
-    if ((target == RoutableMsg.ALL_SERVERS) && fractional)
+    if ((target == RoutableMsg.ALL_SERVERS) && fractionalConfig.isFractional())
     {
       Message msg = NOTE_ERR_FRACTIONAL_FORBIDDEN_FULL_UPDATE_FRACTIONAL.get(
             baseDn.toString(), Short.toString(getServerId()));
@@ -2074,7 +1766,7 @@
           ResultCode.UNWILLING_TO_PERFORM, msg);
     }
 
-    if (fractional)
+    if (fractionalConfig.isFractional())
     {
       if (addOperation.isSynchronizationOperation())
       {
@@ -2212,7 +1904,7 @@
           ResultCode.UNWILLING_TO_PERFORM, msg);
     }
 
-    if (fractional)
+    if (fractionalConfig.isFractional())
     {
       if (modifyDNOperation.isSynchronizationOperation())
       {
@@ -2331,7 +2023,7 @@
           ResultCode.UNWILLING_TO_PERFORM, msg);
     }
 
-    if (fractional)
+    if (fractionalConfig.isFractional())
     {
       if  (modifyOperation.isSynchronizationOperation())
       {
@@ -4798,4 +4490,453 @@
           resultCode, message);
     }
   }
+
+  /**
+   * Gets the fractional configuration of this domain.
+   * @return The fractional configuration of this domain.
+   */
+  FractionalConfig getFractionalConfig()
+  {
+    return fractionalConfig;
+  }
+
+  /**
+   * This bean is a utility class used for holding the parsing
+   * result of a fractional configuration. It also contains some facility
+   * methods like fractional configuration comparison...
+   */
+  static class FractionalConfig
+  {
+    /**
+     * 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>();
+
+    /**
+     * Base DN the fractional configuration is for.
+     */
+    private DN baseDn = null;
+
+    /**
+     * Constructs a new fractional configuration object.
+     * @param baseDn The base dn the object is for.
+     */
+    FractionalConfig(DN baseDn)
+    {
+      this.baseDn = baseDn;
+    }
+
+    /**
+     * Getter for fractional.
+     * @return True if the configuration has fractional enabled
+     */
+    boolean isFractional()
+    {
+      return fractional;
+    }
+
+    /**
+     * Set the fractional parameter.
+     * @param fractional The fractional parameter
+     */
+    void setFractional(boolean fractional)
+    {
+      this.fractional = fractional;
+    }
+
+    /**
+     * Getter for fractionalExclusive.
+     * @return True if the configuration has fractional exclusive enabled
+     */
+    boolean isFractionalExclusive()
+    {
+      return fractionalExclusive;
+    }
+
+    /**
+     * Set the fractionalExclusive parameter.
+     * @param fractionalExclusive The fractionalExclusive parameter
+     */
+    void setFractionalExclusive(boolean fractionalExclusive)
+    {
+      this.fractionalExclusive = fractionalExclusive;
+    }
+
+    /**
+     * Getter for fractionalSpecificClassesAttributes attribute.
+     * @return The fractionalSpecificClassesAttributes attribute.
+     */
+    Map<String, List<String>> getFractionalSpecificClassesAttributes()
+    {
+      return fractionalSpecificClassesAttributes;
+    }
+
+    /**
+     * Set the fractionalSpecificClassesAttributes parameter.
+     * @param fractionalSpecificClassesAttributes The
+     * fractionalSpecificClassesAttributes parameter to set.
+     */
+    void setFractionalSpecificClassesAttributes(Map<String,
+      List<String>> fractionalSpecificClassesAttributes)
+    {
+      this.fractionalSpecificClassesAttributes =
+        fractionalSpecificClassesAttributes;
+    }
+
+    /**
+     * Getter for fractionalSpecificClassesAttributes attribute.
+     * @return The fractionalSpecificClassesAttributes attribute.
+     */
+    List<String> getFractionalAllClassesAttributes()
+    {
+      return fractionalAllClassesAttributes;
+    }
+
+    /**
+     * Set the fractionalAllClassesAttributes parameter.
+     * @param fractionalAllClassesAttributes The
+     * fractionalSpecificClassesAttributes parameter to set.
+     */
+    void setFractionalAllClassesAttributes(
+      List<String> fractionalAllClassesAttributes)
+    {
+      this.fractionalAllClassesAttributes = fractionalAllClassesAttributes;
+    }
+
+    /**
+     * Getter for the base baseDn.
+     * @return The baseDn attribute.
+     */
+    DN getBaseDn()
+    {
+      return baseDn;
+    }
+
+    /**
+     * Extract the fractional configuration from the passed domain configuration
+     * entry.
+     * @param configuration The configuration object
+     * @return The fractional replication configuration.
+     * @throws ConfigException If an error occurred.
+     */
+    static FractionalConfig toFractionalConfig(
+      ReplicationDomainCfg configuration) throws ConfigException
+    {
+      // 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 = parseFractionalConfig(exclIt, inclIt,
+        newFractionalSpecificClassesAttributes,
+        newFractionalAllClassesAttributes);
+
+      // Create matching parsed config object
+      FractionalConfig result = new FractionalConfig(configuration.getBaseDN());
+      switch (newFractionalMode)
+      {
+        case NOT_FRACTIONAL:
+          result.setFractional(false);
+          result.setFractionalExclusive(true);
+          break;
+        case EXCLUSIVE_FRACTIONAL:
+        case INCLUSIVE_FRACTIONAL:
+          result.setFractional(true);
+          if (newFractionalMode == EXCLUSIVE_FRACTIONAL)
+            result.setFractionalExclusive(true);
+          else
+            result.setFractionalExclusive(false);
+          break;
+      }
+      result.setFractionalSpecificClassesAttributes(
+        newFractionalSpecificClassesAttributes);
+      result.setFractionalAllClassesAttributes(
+        newFractionalAllClassesAttributes);
+      return result;
+    }
+
+    /**
+     * 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;
+    }
+
+    // Return type of the parseFractionalConfig method
+    static final int NOT_FRACTIONAL = 0;
+    static final int EXCLUSIVE_FRACTIONAL = 1;
+    static final int INCLUSIVE_FRACTIONAL = 2;
+
+    /**
+     * Get an integer representation of the domain fractional configuration.
+     * @return An integer representation of the domain fractional configuration.
+     */
+    int fractionalConfigToInt()
+    {
+      int fractionalMode = -1;
+      if (fractional)
+      {
+        if (fractionalExclusive)
+          fractionalMode = EXCLUSIVE_FRACTIONAL;
+        else
+          fractionalMode = INCLUSIVE_FRACTIONAL;
+      } else
+      {
+        fractionalMode = NOT_FRACTIONAL;
+      }
+      return fractionalMode;
+    }
+
+    /**
+     * Compare 2 fractional replication configurations and returns true if they
+     * are equivalent.
+     * @param fractionalConfig1 First fractional configuration
+     * @param fractionalConfig2 Second fractional configuration
+     * @return True if both configurations are equivalent.
+     * @throws ConfigException If some classes or attributes could not be
+     * retrieved from the schema.
+     */
+     static boolean isFractionalConfigEquivalent(
+      FractionalConfig fractionalConfig1, FractionalConfig fractionalConfig2)
+      throws ConfigException
+    {
+      // Comapre base DNs just to be consistent
+      if (!fractionalConfig1.getBaseDn().equals(fractionalConfig2.getBaseDn()))
+        return false;
+
+      // Compare modes
+      if ( (fractionalConfig1.isFractional() !=
+        fractionalConfig2.isFractional()) ||
+        (fractionalConfig1.isFractionalExclusive() !=
+        fractionalConfig2.isFractionalExclusive()) )
+        return false;
+
+      // Compare all classes attributes
+      List<String> allClassesAttributes1 =
+        fractionalConfig1.getFractionalAllClassesAttributes();
+      List<String> allClassesAttributes2 =
+        fractionalConfig2.getFractionalAllClassesAttributes();
+      if (!isAttributeListEquivalent(allClassesAttributes1,
+        allClassesAttributes2))
+              return false;
+
+      // Compare specific classes attributes
+      Map<String, List<String>> specificClassesAttributes1 =
+        fractionalConfig1.getFractionalSpecificClassesAttributes();
+      Map<String, List<String>> specificClassesAttributes2 =
+        fractionalConfig2.getFractionalSpecificClassesAttributes();
+      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;
+    }
+  }
 }
diff --git a/opends/src/server/org/opends/server/util/LDIFReader.java b/opends/src/server/org/opends/server/util/LDIFReader.java
index 5ed4441..cc13a74 100644
--- a/opends/src/server/org/opends/server/util/LDIFReader.java
+++ b/opends/src/server/org/opends/server/util/LDIFReader.java
@@ -1477,6 +1477,8 @@
    */
   public void close()
   {
+    // Inform LDIF import plugins that an import session is ending
+    pluginConfigManager.invokeLDIFImportEndPlugins(importConfig);
     importConfig.close();
   }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
index 5506fd4..a46136a 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server;
 
@@ -1101,6 +1101,7 @@
       entries.add(entry);
     }
 
+    reader.close();
     return entries;
   }
 
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java
index f079a6f..97701fe 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java
@@ -22,7 +22,7 @@
  * CDDL HEADER END
  *
  *
- *      Copyright 2006-2008 Sun Microsystems, Inc.
+ *      Copyright 2006-2009 Sun Microsystems, Inc.
  */
 package org.opends.server.api.plugin;
 
@@ -225,6 +225,12 @@
     expectedPublicMethods.add(sigList);
 
     sigList = new LinkedList<String>();
+    sigList.add("doLDIFImportEnd");
+    sigList.add("void");
+    sigList.add("org.opends.server.types.LDIFImportConfig");
+    expectedPublicMethods.add(sigList);
+
+    sigList = new LinkedList<String>();
     sigList.add("doLDIFExport");
     sigList.add("org.opends.server.api.plugin.PluginResult$ImportLDIF");
     sigList.add("org.opends.server.types.LDIFExportConfig");

--
Gitblit v1.10.0