From 0e8ee12a886660ff23c27eb97199ad97ce94df80 Mon Sep 17 00:00:00 2001
From: neil_a_wilson <neil_a_wilson@localhost>
Date: Sat, 23 Jun 2007 21:31:35 +0000
Subject: [PATCH] Provide a way to control the order in which plugins are invoked. This implementation is similar to that used by DSEE 6. The "cn=Plugins,cn=config" configuration entry now supports a number of new configuration attributes (one per plugin type) that can be used to control the invocation order for plugins of that type. The plugin order specification should be a string that is a comma-delimited list of the names of the plugins in the order in which they should be invoked, and it should also include an asterisk to indicate the order in which any unmatched plugins should be invoked.
---
opends/src/server/org/opends/server/core/PluginConfigManager.java | 434 +++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 349 insertions(+), 85 deletions(-)
diff --git a/opends/src/server/org/opends/server/core/PluginConfigManager.java b/opends/src/server/org/opends/server/core/PluginConfigManager.java
index 781d56a..ae23fab 100644
--- a/opends/src/server/org/opends/server/core/PluginConfigManager.java
+++ b/opends/src/server/org/opends/server/core/PluginConfigManager.java
@@ -30,10 +30,13 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
@@ -44,6 +47,7 @@
import org.opends.server.admin.server.ServerManagementContext;
import org.opends.server.admin.std.meta.PluginCfgDefn;
import org.opends.server.admin.std.server.PluginCfg;
+import org.opends.server.admin.std.server.PluginRootCfg;
import org.opends.server.admin.std.server.RootCfg;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.plugin.DirectoryServerPlugin;
@@ -157,6 +161,9 @@
DirectoryServerPlugin<? extends PluginCfg>>
registeredPlugins;
+ // The plugin root configuration read at server startup.
+ private PluginRootCfg pluginRootConfig;
+
// The lock that will provide threadsafe access to the sets of registered
// plugins.
private ReentrantLock pluginLock;
@@ -254,17 +261,18 @@
managementContext.getRootConfiguration();
- // Register as an add and delete listener with the root configuration so we
- // can be notified if any plugin entries are added or removed.
- rootConfiguration.addPluginAddListener(this);
- rootConfiguration.addPluginDeleteListener(this);
+ // Get the plugin root configuration and register with it as an add and
+ // delete listener so we can be notified if any plugin entries are added or
+ // removed.
+ pluginRootConfig = rootConfiguration.getPluginRoot();
+ pluginRootConfig.addPluginAddListener(this);
+ pluginRootConfig.addPluginDeleteListener(this);
//Initialize the existing plugins.
- for (String pluginName : rootConfiguration.listPlugins())
+ for (String pluginName : pluginRootConfig.listPlugins())
{
- PluginCfg pluginConfiguration =
- rootConfiguration.getPlugin(pluginName);
+ PluginCfg pluginConfiguration = pluginRootConfig.getPlugin(pluginName);
if (! pluginConfiguration.isEnabled())
{
@@ -528,168 +536,229 @@
switch (t)
{
case STARTUP:
- startupPlugins = addPlugin(startupPlugins, plugin);
+ startupPlugins =
+ addPlugin(startupPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderStartup());
break;
case SHUTDOWN:
- shutdownPlugins = addPlugin(shutdownPlugins, plugin);
+ shutdownPlugins =
+ addPlugin(shutdownPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderShutdown());
break;
case POST_CONNECT:
- postConnectPlugins = addPlugin(postConnectPlugins, plugin);
+ postConnectPlugins =
+ addPlugin(postConnectPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostConnect());
break;
case POST_DISCONNECT:
- postDisconnectPlugins = addPlugin(postDisconnectPlugins, plugin);
+ postDisconnectPlugins =
+ addPlugin(postDisconnectPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostDisconnect());
break;
case LDIF_IMPORT:
- ldifImportPlugins = addPlugin(ldifImportPlugins, plugin);
+ ldifImportPlugins =
+ addPlugin(ldifImportPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderLDIFImport());
break;
case LDIF_EXPORT:
- ldifExportPlugins = addPlugin(ldifExportPlugins, plugin);
+ ldifExportPlugins =
+ addPlugin(ldifExportPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderLDIFExport());
break;
case PRE_PARSE_ABANDON:
- preParseAbandonPlugins = addPlugin(preParseAbandonPlugins, plugin);
+ preParseAbandonPlugins =
+ addPlugin(preParseAbandonPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreParseAbandon());
break;
case PRE_PARSE_ADD:
- preParseAddPlugins = addPlugin(preParseAddPlugins, plugin);
+ preParseAddPlugins =
+ addPlugin(preParseAddPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreParseAdd());
break;
case PRE_PARSE_BIND:
- preParseBindPlugins = addPlugin(preParseBindPlugins, plugin);
+ preParseBindPlugins =
+ addPlugin(preParseBindPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreParseBind());
break;
case PRE_PARSE_COMPARE:
- preParseComparePlugins = addPlugin(preParseComparePlugins, plugin);
+ preParseComparePlugins =
+ addPlugin(preParseComparePlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreParseCompare());
break;
case PRE_PARSE_DELETE:
- preParseDeletePlugins = addPlugin(preParseDeletePlugins, plugin);
+ preParseDeletePlugins =
+ addPlugin(preParseDeletePlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreParseDelete());
break;
case PRE_PARSE_EXTENDED:
- preParseExtendedPlugins = addPlugin(preParseExtendedPlugins,
- plugin);
+ preParseExtendedPlugins =
+ addPlugin(preParseExtendedPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreParseExtended());
break;
case PRE_PARSE_MODIFY:
- preParseModifyPlugins = addPlugin(preParseModifyPlugins, plugin);
+ preParseModifyPlugins =
+ addPlugin(preParseModifyPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreParseModify());
break;
case PRE_PARSE_MODIFY_DN:
- preParseModifyDNPlugins = addPlugin(preParseModifyDNPlugins,
- plugin);
+ preParseModifyDNPlugins =
+ addPlugin(preParseModifyDNPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreParseModifyDN());
break;
case PRE_PARSE_SEARCH:
- preParseSearchPlugins = addPlugin(preParseSearchPlugins, plugin);
+ preParseSearchPlugins =
+ addPlugin(preParseSearchPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreParseSearch());
break;
case PRE_PARSE_UNBIND:
- preParseUnbindPlugins = addPlugin(preParseUnbindPlugins, plugin);
+ preParseUnbindPlugins =
+ addPlugin(preParseUnbindPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreParseUnbind());
break;
case PRE_OPERATION_ADD:
- preOperationAddPlugins = addPlugin(preOperationAddPlugins, plugin);
+ preOperationAddPlugins =
+ addPlugin(preOperationAddPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreOperationAdd());
break;
case PRE_OPERATION_BIND:
- preOperationBindPlugins = addPlugin(preOperationBindPlugins,
- plugin);
+ preOperationBindPlugins =
+ addPlugin(preOperationBindPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreOperationBind());
break;
case PRE_OPERATION_COMPARE:
- preOperationComparePlugins = addPlugin(preOperationComparePlugins,
- plugin);
+ preOperationComparePlugins =
+ addPlugin(preOperationComparePlugins,plugin, t,
+ pluginRootConfig.getPluginOrderPreOperationCompare());
break;
case PRE_OPERATION_DELETE:
- preOperationDeletePlugins = addPlugin(preOperationDeletePlugins,
- plugin);
+ preOperationDeletePlugins =
+ addPlugin(preOperationDeletePlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreOperationDelete());
break;
case PRE_OPERATION_EXTENDED:
- preOperationExtendedPlugins = addPlugin(preOperationExtendedPlugins,
- plugin);
+ preOperationExtendedPlugins =
+ addPlugin(preOperationExtendedPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreOperationExtended());
break;
case PRE_OPERATION_MODIFY:
- preOperationModifyPlugins = addPlugin(preOperationModifyPlugins,
- plugin);
+ preOperationModifyPlugins =
+ addPlugin(preOperationModifyPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreOperationModify());
break;
case PRE_OPERATION_MODIFY_DN:
- preOperationModifyDNPlugins = addPlugin(preOperationModifyDNPlugins,
- plugin);
+ preOperationModifyDNPlugins =
+ addPlugin(preOperationModifyDNPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreOperationModifyDN());
break;
case PRE_OPERATION_SEARCH:
- preOperationSearchPlugins = addPlugin(preOperationSearchPlugins,
- plugin);
+ preOperationSearchPlugins =
+ addPlugin(preOperationSearchPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPreOperationSearch());
break;
case POST_OPERATION_ABANDON:
- postOperationAbandonPlugins = addPlugin(postOperationAbandonPlugins,
- plugin);
+ postOperationAbandonPlugins =
+ addPlugin(postOperationAbandonPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostOperationAbandon());
break;
case POST_OPERATION_ADD:
- postOperationAddPlugins = addPlugin(postOperationAddPlugins,
- plugin);
+ postOperationAddPlugins =
+ addPlugin(postOperationAddPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostOperationAdd());
break;
case POST_OPERATION_BIND:
- postOperationBindPlugins = addPlugin(postOperationBindPlugins,
- plugin);
+ postOperationBindPlugins =
+ addPlugin(postOperationBindPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostOperationBind());
break;
case POST_OPERATION_COMPARE:
- postOperationComparePlugins = addPlugin(postOperationComparePlugins,
- plugin);
+ postOperationComparePlugins =
+ addPlugin(postOperationComparePlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostOperationCompare());
break;
case POST_OPERATION_DELETE:
- postOperationDeletePlugins = addPlugin(postOperationDeletePlugins,
- plugin);
+ postOperationDeletePlugins =
+ addPlugin(postOperationDeletePlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostOperationDelete());
break;
case POST_OPERATION_EXTENDED:
postOperationExtendedPlugins =
- addPlugin(postOperationExtendedPlugins, plugin);
+ addPlugin(postOperationExtendedPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostOperationExtended());
break;
case POST_OPERATION_MODIFY:
- postOperationModifyPlugins = addPlugin(postOperationModifyPlugins,
- plugin);
+ postOperationModifyPlugins =
+ addPlugin(postOperationModifyPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostOperationModify());
break;
case POST_OPERATION_MODIFY_DN:
postOperationModifyDNPlugins =
- addPlugin(postOperationModifyDNPlugins, plugin);
+ addPlugin(postOperationModifyDNPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostOperationModifyDN());
break;
case POST_OPERATION_SEARCH:
- postOperationSearchPlugins = addPlugin(postOperationSearchPlugins,
- plugin);
+ postOperationSearchPlugins =
+ addPlugin(postOperationSearchPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostOperationSearch());
break;
case POST_OPERATION_UNBIND:
- postOperationUnbindPlugins = addPlugin(postOperationUnbindPlugins,
- plugin);
+ postOperationUnbindPlugins =
+ addPlugin(postOperationUnbindPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostOperationUnbind());
break;
case POST_RESPONSE_ADD:
- postResponseAddPlugins = addPlugin(postResponseAddPlugins, plugin);
+ postResponseAddPlugins =
+ addPlugin(postResponseAddPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostResponseAdd());
break;
case POST_RESPONSE_BIND:
- postResponseBindPlugins = addPlugin(postResponseBindPlugins,
- plugin);
+ postResponseBindPlugins =
+ addPlugin(postResponseBindPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostResponseBind());
break;
case POST_RESPONSE_COMPARE:
- postResponseComparePlugins = addPlugin(postResponseComparePlugins,
- plugin);
+ postResponseComparePlugins =
+ addPlugin(postResponseComparePlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostResponseCompare());
break;
case POST_RESPONSE_DELETE:
- postResponseDeletePlugins = addPlugin(postResponseDeletePlugins,
- plugin);
+ postResponseDeletePlugins =
+ addPlugin(postResponseDeletePlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostResponseDelete());
break;
case POST_RESPONSE_EXTENDED:
- postResponseExtendedPlugins = addPlugin(postResponseExtendedPlugins,
- plugin);
+ postResponseExtendedPlugins =
+ addPlugin(postResponseExtendedPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostResponseExtended());
break;
case POST_RESPONSE_MODIFY:
- postResponseModifyPlugins = addPlugin(postResponseModifyPlugins,
- plugin);
+ postResponseModifyPlugins =
+ addPlugin(postResponseModifyPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostResponseModify());
break;
case POST_RESPONSE_MODIFY_DN:
- postResponseModifyDNPlugins = addPlugin(postResponseModifyDNPlugins,
- plugin);
+ postResponseModifyDNPlugins =
+ addPlugin(postResponseModifyDNPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostResponseModifyDN());
break;
case POST_RESPONSE_SEARCH:
- postResponseSearchPlugins = addPlugin(postResponseSearchPlugins,
- plugin);
+ postResponseSearchPlugins =
+ addPlugin(postResponseSearchPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderPostResponseSearch());
break;
case SEARCH_RESULT_ENTRY:
- searchResultEntryPlugins = addPlugin(searchResultEntryPlugins,
- plugin);
+ searchResultEntryPlugins =
+ addPlugin(searchResultEntryPlugins, plugin, t,
+ pluginRootConfig.getPluginOrderSearchResultEntry());
break;
case SEARCH_RESULT_REFERENCE:
searchResultReferencePlugins =
- addPlugin(searchResultReferencePlugins, plugin);
+ addPlugin(searchResultReferencePlugins, plugin, t,
+ pluginRootConfig.getPluginOrderSearchResultReference());
break;
case INTERMEDIATE_RESPONSE:
- intermediateResponsePlugins = addPlugin(intermediateResponsePlugins,
- plugin);
+ intermediateResponsePlugins =
+ addPlugin(intermediateResponsePlugins, plugin, t,
+ pluginRootConfig.getPluginOrderIntermediateResponse());
break;
default:
}
@@ -708,21 +777,216 @@
* itself be modified, but rather a new array will be created with one
* additional element. The provided plugin will be the last element in the
* new array.
+ * <BR><BR>
+ * Note that the only use of this method outside of this class should be for
+ * testing purposes.
*
* @param pluginArray The array containing the existing set of plugins.
* @param plugin The plugin to be added to the array.
+ * @param pluginType The plugin type for the plugin being registered.
+ * @param pluginOrder A string that represents the order in which plugins of
+ * this type should be invoked, or {@code null} if the
+ * order is not considered important.
*
* @return The new array containing the new set of plugins.
*/
- private DirectoryServerPlugin[] addPlugin(DirectoryServerPlugin[] pluginArray,
- DirectoryServerPlugin plugin)
+ static DirectoryServerPlugin[] addPlugin(DirectoryServerPlugin[] pluginArray,
+ DirectoryServerPlugin plugin,
+ PluginType pluginType,
+ String pluginOrder)
{
- DirectoryServerPlugin[] newPlugins =
- new DirectoryServerPlugin[pluginArray.length+1];
- System.arraycopy(pluginArray, 0, newPlugins, 0, pluginArray.length);
- newPlugins[pluginArray.length] = plugin;
+ // If the provided plugin order string is null, empty, or contains only a
+ // wildcard, then simply add the new plugin to the end of the list.
+ // Otherwise, parse the order string and figure out where to put the
+ // provided plugin.
+ if ((pluginOrder == null) ||
+ ((pluginOrder = pluginOrder.trim()).length() == 0) ||
+ pluginOrder.equals("*"))
+ {
+ DirectoryServerPlugin[] newPlugins =
+ new DirectoryServerPlugin[pluginArray.length+1];
+ System.arraycopy(pluginArray, 0, newPlugins, 0, pluginArray.length);
+ newPlugins[pluginArray.length] = plugin;
- return newPlugins;
+ return newPlugins;
+ }
+ else
+ {
+ // Parse the plugin order into initial and final plugin names.
+ boolean starFound = false;
+ LinkedHashSet<String> initialPluginNames = new LinkedHashSet<String>();
+ LinkedHashSet<String> finalPluginNames = new LinkedHashSet<String>();
+
+ StringTokenizer tokenizer = new StringTokenizer(pluginOrder, ",");
+ while (tokenizer.hasMoreTokens())
+ {
+ String token = tokenizer.nextToken().trim();
+ if (token.length() == 0)
+ {
+ // Only log the warning once per plugin type. The plugin array will
+ // be empty the first time through, so we can use that to make the
+ // determination.
+ if (pluginArray.length == 0)
+ {
+ int msgID = MSGID_CONFIG_PLUGIN_EMPTY_ELEMENT_IN_ORDER;
+ String message = getMessage(msgID, pluginType.getName());
+ logError(ErrorLogCategory.CONFIGURATION,
+ ErrorLogSeverity.SEVERE_WARNING, message, msgID);
+ }
+ }
+ else if (token.equals("*"))
+ {
+ if (starFound)
+ {
+ // Only log the warning once per plugin type. The plugin array will
+ // be empty the first time through, so we can use that to make the
+ // determination.
+ if (pluginArray.length == 0)
+ {
+ int msgID = MSGID_CONFIG_PLUGIN_MULTIPLE_WILDCARDS_IN_ORDER;
+ String message = getMessage(msgID, pluginType.getName());
+ logError(ErrorLogCategory.CONFIGURATION,
+ ErrorLogSeverity.SEVERE_WARNING, message, msgID);
+ }
+ }
+ else
+ {
+ starFound = true;
+ }
+ }
+ else
+ {
+ String lowerName = toLowerCase(token);
+ if (starFound)
+ {
+ if (initialPluginNames.contains(lowerName) ||
+ finalPluginNames.contains(lowerName))
+ {
+ // Only log the warning once per plugin type. The plugin array
+ // will be empty the first time through, so we can use that to
+ // make the determination.
+ if (pluginArray.length == 0)
+ {
+ int msgID = MSGID_CONFIG_PLUGIN_LISTED_MULTIPLE_TIMES;
+ String message = getMessage(msgID, pluginType.getName(), token);
+ logError(ErrorLogCategory.CONFIGURATION,
+ ErrorLogSeverity.SEVERE_WARNING, message, msgID);
+ }
+ }
+
+ finalPluginNames.add(lowerName);
+ }
+ else
+ {
+ if (initialPluginNames.contains(lowerName))
+ {
+ // Only log the warning once per plugin type. The plugin array
+ // will be empty the first time through, so we can use that to
+ // make the determination.
+ if (pluginArray.length == 0)
+ {
+ int msgID = MSGID_CONFIG_PLUGIN_LISTED_MULTIPLE_TIMES;
+ String message = getMessage(msgID, pluginType.getName(), token);
+ logError(ErrorLogCategory.CONFIGURATION,
+ ErrorLogSeverity.SEVERE_WARNING, message, msgID);
+ }
+ }
+
+ initialPluginNames.add(lowerName);
+ }
+ }
+ }
+
+ if (! starFound)
+ {
+ // Only log the warning once per plugin type. The plugin array will be
+ // empty the first time through, so we can use that to make the
+ // determination.
+ if (pluginArray.length == 0)
+ {
+ int msgID = MSGID_CONFIG_PLUGIN_ORDER_NO_WILDCARD;
+ String message = getMessage(msgID, pluginType.getName());
+ logError(ErrorLogCategory.CONFIGURATION,
+ ErrorLogSeverity.SEVERE_WARNING, message, msgID);
+ }
+ }
+
+
+ // Parse the array of already registered plugins to sort them accordingly.
+ HashMap<String,DirectoryServerPlugin> initialPlugins =
+ new HashMap<String,DirectoryServerPlugin>(initialPluginNames.size());
+ HashMap<String,DirectoryServerPlugin> finalPlugins =
+ new HashMap<String,DirectoryServerPlugin>(finalPluginNames.size());
+ ArrayList<DirectoryServerPlugin> otherPlugins =
+ new ArrayList<DirectoryServerPlugin>();
+ for (DirectoryServerPlugin p : pluginArray)
+ {
+ DN dn = p.getPluginEntryDN();
+ String lowerName =
+ toLowerCase(dn.getRDN().getAttributeValue(0).getStringValue());
+ if (initialPluginNames.contains(lowerName))
+ {
+ initialPlugins.put(lowerName, p);
+ }
+ else if (finalPluginNames.contains(lowerName))
+ {
+ finalPlugins.put(lowerName, p);
+ }
+ else
+ {
+ otherPlugins.add(p);
+ }
+ }
+
+
+ // Get the name of the provided plugin from its RDN value and put it in
+ // the correct category.
+ DN dn = plugin.getPluginEntryDN();
+ String lowerName =
+ toLowerCase(dn.getRDN().getAttributeValue(0).getStringValue());
+ if (initialPluginNames.contains(lowerName))
+ {
+ initialPlugins.put(lowerName, plugin);
+ }
+ else if (finalPluginNames.contains(lowerName))
+ {
+ finalPlugins.put(lowerName, plugin);
+ }
+ else
+ {
+ otherPlugins.add(plugin);
+ }
+
+
+ // Compile a list of all the plugins in the correct order, convert it to
+ // an array, and return it.
+ ArrayList<DirectoryServerPlugin> newList =
+ new ArrayList<DirectoryServerPlugin>(pluginArray.length+1);
+ for (String name : initialPluginNames)
+ {
+ DirectoryServerPlugin p = initialPlugins.get(name);
+ if (p != null)
+ {
+ newList.add(p);
+ }
+ }
+
+ newList.addAll(otherPlugins);
+
+ for (String name : finalPluginNames)
+ {
+ DirectoryServerPlugin p = finalPlugins.get(name);
+ if (p != null)
+ {
+ newList.add(p);
+ }
+ }
+
+ DirectoryServerPlugin[] newPlugins =
+ new DirectoryServerPlugin[newList.size()];
+ newList.toArray(newPlugins);
+ return newPlugins;
+ }
}
--
Gitblit v1.10.0