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