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

mrossign
16.34.2009 55a07ce2479e1b4c74dec15ce4e78e3fdf50a27c
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;