opends/src/server/org/opends/server/api/plugin/DirectoryServerPlugin.java
@@ -114,23 +114,26 @@ * plugins regardless of type. This should only be called by the * core Directory Server code during the course of loading a plugin. * * @param configuration The configuration for this plugin. * @param pluginTypes The set of plugin types for which this * plugin is registered. * @param pluginDN * The configuration entry name of this plugin. * @param pluginTypes * The set of plugin types for which this plugin is * registered. * @param invokeForInternalOps * Indicates whether this plugin should be invoked for * internal operations. */ @org.opends.server.types.PublicAPI( stability=org.opends.server.types.StabilityLevel.PRIVATE, mayInstantiate=false, mayExtend=false, mayInvoke=false) public final void initializeInternal(PluginCfg configuration, Set<PluginType> pluginTypes) public final void initializeInternal(DN pluginDN, Set<PluginType> pluginTypes, boolean invokeForInternalOps) { this.pluginDN = pluginDN; this.pluginTypes = pluginTypes; pluginDN = configuration.dn(); invokeForInternalOps = configuration.isInvokeForInternalOperations(); this.invokeForInternalOps = invokeForInternalOps; } opends/src/server/org/opends/server/api/plugin/InternalDirectoryServerPlugin.java
New file @@ -0,0 +1,96 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2009 Sun Microsystems, Inc. */ package org.opends.server.api.plugin; import java.util.List; import java.util.Set; import org.opends.messages.Message; import org.opends.server.admin.std.server.PluginCfg; import org.opends.server.config.ConfigException; import org.opends.server.types.DN; import org.opends.server.types.InitializationException; /** * An internal directory server plugin which can be registered with * the server without requiring any associated configuration. */ public abstract class InternalDirectoryServerPlugin extends DirectoryServerPlugin<PluginCfg> { /** * Creates a new internal directory server plugin using the provided * component name and plugin types. * * @param componentDN * The configuration entry name of the component associated * with this internal plugin. * @param pluginTypes * The set of plugin types for which this internal plugin * is registered. * @param invokeForInternalOps * Indicates whether this internal plugin should be invoked * for internal operations. */ protected InternalDirectoryServerPlugin(DN componentDN, Set<PluginType> pluginTypes, boolean invokeForInternalOps) { initializeInternal(componentDN, pluginTypes, invokeForInternalOps); } /** * {@inheritDoc} */ public final void initializePlugin(Set<PluginType> pluginTypes, PluginCfg configuration) throws ConfigException, InitializationException { // Unused. } /** * {@inheritDoc} */ public final boolean isConfigurationAcceptable( PluginCfg configuration, List<Message> unacceptableReasons) { // Unused. return true; } } opends/src/server/org/opends/server/authorization/dseecompat/AciListenerManager.java
@@ -22,21 +22,27 @@ * CDDL HEADER END * * * Copyright 2008 Sun Microsystems, Inc. * Copyright 2008-2009 Sun Microsystems, Inc. */ package org.opends.server.authorization.dseecompat; import org.opends.messages.Message; import org.opends.server.workflowelement.localbackend.*; import org.opends.server.api.ChangeNotificationListener; import org.opends.server.api.BackendInitializationListener; import org.opends.server.api.Backend; import org.opends.server.api.AlertGenerator; import org.opends.server.types.operation.PostResponseAddOperation; import org.opends.server.types.operation.PostResponseDeleteOperation; import org.opends.server.types.operation.PostResponseModifyOperation; import org.opends.server.types.operation.PostResponseModifyDNOperation; import org.opends.server.api.plugin.InternalDirectoryServerPlugin; import org.opends.server.api.plugin.PluginResult; import org.opends.server.api.plugin.PluginType; import org.opends.server.api.plugin.PluginResult.PostOperation; import org.opends.server.types.operation.PostOperationAddOperation; import org.opends.server.types.operation.PostOperationDeleteOperation; import org.opends.server.types.operation.PostOperationModifyDNOperation; import org.opends.server.types.operation.PostOperationModifyOperation; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.ldap.LDAPControl; @@ -44,38 +50,166 @@ import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.*; import static org.opends.messages.AccessControlMessages.*; import org.opends.server.core.DirectoryServer; import static org.opends.server.util.ServerConstants.*; import java.util.*; /** * The AciListenerManager updates an ACI list after each * modification operation. Also, updates ACI list when backends are initialized * and finalized. * The AciListenerManager updates an ACI list after each modification * operation. Also, updates ACI list when backends are initialized and * finalized. */ public class AciListenerManager implements ChangeNotificationListener, BackendInitializationListener, AlertGenerator { public class AciListenerManager implements BackendInitializationListener, AlertGenerator { /** * The tracer object for the debug logger. */ private static final DebugTracer TRACER = getTracer(); /** * The fully-qualified name of this class. */ private static final String CLASS_NAME = "org.opends.server.authorization.dseecompat.AciListenerManager"; /** * Internal plugin used for updating the cache before a response is * sent to the client. */ private final class AciChangeListenerPlugin extends InternalDirectoryServerPlugin { private AciChangeListenerPlugin() { super(configurationDN, EnumSet.of(PluginType.POST_OPERATION_ADD, PluginType.POST_OPERATION_DELETE, PluginType.POST_OPERATION_MODIFY, PluginType.POST_OPERATION_MODIFY_DN), true); } /** * {@inheritDoc} */ public PostOperation doPostOperation( PostOperationAddOperation addOperation) { // This entry might have both global and aci attribute types. Entry entry = addOperation.getEntryToAdd(); boolean hasAci, hasGlobalAci = false; if ((hasAci = entry.hasOperationalAttribute(AciHandler.aciType)) || (hasGlobalAci = entry.hasAttribute(AciHandler.globalAciType))) { // Ignore this list, the ACI syntax has already passed and it // should be empty. LinkedList<Message> failedACIMsgs = new LinkedList<Message>(); aciList.addAci(entry, hasAci, hasGlobalAci, failedACIMsgs); } // If we've gotten here, then everything is acceptable. return PluginResult.PostOperation.continueOperationProcessing(); } /** * {@inheritDoc} */ public PostOperation doPostOperation( PostOperationDeleteOperation deleteOperation) { // This entry might have both global and aci attribute types. boolean hasAci, hasGlobalAci = false; Entry entry = deleteOperation.getEntryToDelete(); if ((hasAci = entry.hasOperationalAttribute(AciHandler.aciType)) || (hasGlobalAci = entry.hasAttribute(AciHandler.globalAciType))) { aciList.removeAci(entry, hasAci, hasGlobalAci); } // If we've gotten here, then everything is acceptable. return PluginResult.PostOperation.continueOperationProcessing(); } /** * {@inheritDoc} */ public PostOperation doPostOperation( PostOperationModifyDNOperation modifyDNOperation) { aciList.renameAci(modifyDNOperation.getOriginalEntry().getDN(), modifyDNOperation.getUpdatedEntry().getDN()); // If we've gotten here, then everything is acceptable. return PluginResult.PostOperation.continueOperationProcessing(); } /** * {@inheritDoc} */ public PostOperation doPostOperation( PostOperationModifyOperation modifyOperation) { // A change to the ACI list is expensive so let's first make sure // that the modification included changes to the ACI. We'll check // for both "aci" attribute types and global "ds-cfg-global-aci" // attribute types. boolean hasAci = false, hasGlobalAci = false; List<Modification> mods = modifyOperation.getModifications(); for (Modification mod : mods) { AttributeType attributeType = mod.getAttribute().getAttributeType(); if (attributeType.equals(AciHandler.aciType)) { hasAci = true; } else if (attributeType.equals(AciHandler.globalAciType)) { hasGlobalAci = true; } if (hasAci && hasGlobalAci) { break; } } if (hasAci || hasGlobalAci) { Entry oldEntry = modifyOperation.getCurrentEntry(); Entry newEntry = modifyOperation.getModifiedEntry(); aciList.modAciOldNewEntry(oldEntry, newEntry, hasAci, hasGlobalAci); } // If we've gotten here, then everything is acceptable. return PluginResult.PostOperation.continueOperationProcessing(); } } /* * The configuration DN. */ private DN configurationDN; /* * True if the server is in lockdown mode. */ @@ -92,149 +226,95 @@ private static SearchFilter aciFilter; /* * The aci attribute type is operational so we need to specify it to be * returned. * Internal plugin used for updating the cache before a response is * sent to the client. */ private static LinkedHashSet<String> attrs = new LinkedHashSet<String>(); private final AciChangeListenerPlugin plugin; static { /* * The aci attribute type is operational so we need to specify it to * be returned. */ private static LinkedHashSet<String> attrs = new LinkedHashSet<String>(); static { /* * Set up the filter used to search private and public contexts. */ try { try { aciFilter=SearchFilter.createFilterFromString("(aci=*)"); } catch (DirectoryException ex) { } catch (DirectoryException ex) { //TODO should never happen, error message? } attrs.add("aci"); } /** * Save the list created by the AciHandler routine. Registers as an * Alert Generator that can send alerts when the server is being put * in lockdown mode. Registers as backend initialization listener that is * used to manage the ACI list cache when backends are * initialized/finalized. Registers as a change notification listener that * is used to manage the ACI list cache after ACI modifications have been * performed. * in lockdown mode. Registers as backend initialization listener that * is used to manage the ACI list cache when backends are * initialized/finalized. Registers as a change notification listener * that is used to manage the ACI list cache after ACI modifications * have been performed. * * @param aciList The list object created and loaded by the handler. * @param cfgDN The DN of the access control configuration entry. * @param aciList * The list object created and loaded by the handler. * @param cfgDN * The DN of the access control configuration entry. */ public AciListenerManager(AciList aciList, DN cfgDN) { public AciListenerManager(AciList aciList, DN cfgDN) { this.aciList=aciList; this.configurationDN=cfgDN; DirectoryServer.registerChangeNotificationListener(this); this.plugin = new AciChangeListenerPlugin(); DirectoryServer.registerInternalPlugin(plugin); DirectoryServer.registerBackendInitializationListener(this); DirectoryServer.registerAlertGenerator(this); } /** * Deregister from the change notification listener, the backend * initialization listener and the alert generator. */ public void finalizeListenerManager() { DirectoryServer.deregisterChangeNotificationListener(this); public void finalizeListenerManager() { DirectoryServer.deregisterInternalPlugin(plugin); DirectoryServer.deregisterBackendInitializationListener(this); DirectoryServer.deregisterAlertGenerator(this); } /** * A delete operation succeeded. Remove any ACIs associated with the * entry deleted. * @param deleteOperation The delete operation. * @param entry The entry being deleted. */ public void handleDeleteOperation(PostResponseDeleteOperation deleteOperation, Entry entry) { boolean hasAci, hasGlobalAci=false; //This entry might have both global and aci attribute types. if((hasAci=entry.hasOperationalAttribute(AciHandler.aciType)) || (hasGlobalAci=entry.hasAttribute(AciHandler.globalAciType))) aciList.removeAci(entry, hasAci, hasGlobalAci); } /** * An Add operation succeeded. Add any ACIs associated with the * entry being added. * @param addOperation The add operation. * @param entry The entry being added. * {@inheritDoc} In this case, the server will search the backend to * find all aci attribute type values that it may contain and add them * to the ACI list. */ public void handleAddOperation(PostResponseAddOperation addOperation, Entry entry) { boolean hasAci, hasGlobalAci=false; //Ignore this list, the ACI syntax has already passed and it should be //empty. LinkedList<Message>failedACIMsgs=new LinkedList<Message>(); //This entry might have both global and aci attribute types. if((hasAci=entry.hasOperationalAttribute(AciHandler.aciType)) || (hasGlobalAci=entry.hasAttribute(AciHandler.globalAciType))) aciList.addAci(entry, hasAci, hasGlobalAci, failedACIMsgs); } /** * A modify operation succeeded. Adjust the ACIs by removing * ACIs based on the oldEntry and then adding ACIs based on the new * entry. * @param modOperation the modify operation. * @param oldEntry The old entry to examine. * @param newEntry The new entry to examine. */ public void handleModifyOperation(PostResponseModifyOperation modOperation, Entry oldEntry, Entry newEntry) public void performBackendInitializationProcessing(Backend backend) { // A change to the ACI list is expensive so let's first make sure that // the modification included changes to the ACI. We'll check for //both "aci" attribute types and global "ds-cfg-global-aci" attribute //types. boolean hasAci = false, hasGlobalAci=false; List<Modification> mods = modOperation.getModifications(); for (Modification mod : mods) { AttributeType attributeType=mod.getAttribute().getAttributeType(); if (attributeType.equals(AciHandler.aciType)) hasAci = true; else if(attributeType.equals(AciHandler.globalAciType)) hasGlobalAci=true; if(hasAci && hasGlobalAci) break; } if (hasAci || hasGlobalAci) aciList.modAciOldNewEntry(oldEntry, newEntry, hasAci, hasGlobalAci); } /** * A modify DN operation has succeeded. Adjust the ACIs by moving ACIs * under the old entry DN to the new entry DN. * @param modifyDNOperation The LDAP modify DN operation. * @param oldEntry The old entry. * @param newEntry The new entry. */ public void handleModifyDNOperation( PostResponseModifyDNOperation modifyDNOperation, Entry oldEntry, Entry newEntry) // Check to make sure that the backend has a presence index defined // for the ACI attribute. If it does not, then log a warning message // because this processing could be very expensive. AttributeType aciType = DirectoryServer.getAttributeType("aci", true); if (backend.getEntryCount() > 0 && !backend.isIndexed(aciType, IndexType.PRESENCE)) { aciList.renameAci(oldEntry.getDN(), newEntry.getDN()); logError(WARN_ACI_ATTRIBUTE_NOT_INDEXED.get(backend .getBackendID(), "aci")); } /** * {@inheritDoc} In this case, the server will search the backend to find * all aci attribute type values that it may contain and add them to the * ACI list. */ public void performBackendInitializationProcessing(Backend backend) { // Check to make sure that the backend has a presence index defined for // the ACI attribute. If it does not, then log a warning message because // this processing could be very expensive. AttributeType aciType = DirectoryServer.getAttributeType("aci", true); if (backend.getEntryCount() > 0 && ! backend.isIndexed(aciType, IndexType.PRESENCE)) { logError(WARN_ACI_ATTRIBUTE_NOT_INDEXED.get(backend.getBackendID(), "aci")); } InternalClientConnection conn = InternalClientConnection.getRootConnection(); LinkedList<Message>failedACIMsgs=new LinkedList<Message>(); @@ -244,14 +324,19 @@ controls.add(new LDAPControl(OID_MANAGE_DSAIT_CONTROL, true)); //Add group membership control to let a backend look for it and //decide if it would abort searches. controls.add(new LDAPControl( OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE ,false)); for (DN baseDN : backend.getBaseDNs()) { try { if (! backend.entryExists(baseDN)) { controls.add(new LDAPControl(OID_INTERNAL_GROUP_MEMBERSHIP_UPDATE, false)); for (DN baseDN : backend.getBaseDNs()) { try { if (!backend.entryExists(baseDN)) { continue; } } catch (Exception e) { } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); @@ -259,41 +344,50 @@ continue; } InternalSearchOperation internalSearch = new InternalSearchOperation( conn, InternalClientConnection.nextOperationID(), InternalClientConnection.nextMessageID(), controls, baseDN, SearchScope.WHOLE_SUBTREE, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, aciFilter, attrs, null); new InternalSearchOperation(conn, InternalClientConnection .nextOperationID(), InternalClientConnection .nextMessageID(), controls, baseDN, SearchScope.WHOLE_SUBTREE, DereferencePolicy.NEVER_DEREF_ALIASES, 0, 0, false, aciFilter, attrs, null); LocalBackendSearchOperation localInternalSearch = new LocalBackendSearchOperation(internalSearch); try { try { backend.search(localInternalSearch); } catch (Exception e) { } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } continue; } if(!internalSearch.getSearchEntries().isEmpty()) { int validAcis = aciList.addAci( internalSearch.getSearchEntries(), failedACIMsgs); if (!internalSearch.getSearchEntries().isEmpty()) { int validAcis = aciList.addAci(internalSearch.getSearchEntries(), failedACIMsgs); if(!failedACIMsgs.isEmpty()) logMsgsSetLockDownMode(failedACIMsgs); Message message = INFO_ACI_ADD_LIST_ACIS.get( Integer.toString(validAcis), String.valueOf(baseDN)); Message message = INFO_ACI_ADD_LIST_ACIS.get(Integer.toString(validAcis), String.valueOf(baseDN)); logError(message); } } } /** * {@inheritDoc} In this case, the server will remove all aci attribute * type values associated with entries in the provided backend. * {@inheritDoc} In this case, the server will remove all aci * attribute type values associated with entries in the provided * backend. */ public void performBackendFinalizationProcessing(Backend backend) { public void performBackendFinalizationProcessing(Backend backend) { aciList.removeAci(backend); } @@ -312,12 +406,13 @@ } /** * Retrieves the DN of the configuration entry used to configure the * handler. * * @return The DN of the configuration entry containing the Access Control * configuration information. * @return The DN of the configuration entry containing the Access * Control configuration information. */ public DN getComponentEntryDN() { @@ -325,12 +420,13 @@ } /** * Retrieves information about the set of alerts that this generator may * produce. The map returned should be between the notification type for a * particular notification and the human-readable description for that * notification. This alert generator must not generate any alerts with * types that are not contained in this list. * Retrieves information about the set of alerts that this generator * may produce. The map returned should be between the notification * type for a particular notification and the human-readable * description for that notification. This alert generator must not * generate any alerts with types that are not contained in this list. * * @return Information about the set of alerts that this generator may * produce. @@ -345,15 +441,20 @@ } /** * Log the exception messages from the failed ACI decode and then put the * server in lockdown mode -- if needed. * * @param failedACIMsgs List of exception messages from failed ACI decodes. */ public void logMsgsSetLockDownMode(LinkedList<Message> failedACIMsgs) { for(Message msg : failedACIMsgs) { /** * Log the exception messages from the failed ACI decode and then put * the server in lockdown mode -- if needed. * * @param failedACIMsgs * List of exception messages from failed ACI decodes. */ public void logMsgsSetLockDownMode(LinkedList<Message> failedACIMsgs) { for (Message msg : failedACIMsgs) { Message message=WARN_ACI_SERVER_DECODE_FAILED.get(msg); logError(message); } @@ -362,20 +463,21 @@ } /** * Send an WARN_ACI_ENTER_LOCKDOWN_MODE alert notification and put the * server in lockdown mode. * */ private void setLockDownMode() { if(!inLockDownMode) { private void setLockDownMode() { if (!inLockDownMode) { inLockDownMode=true; //Send ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED alert that //lockdown is about to be entered. Message lockDownMsg=WARN_ACI_ENTER_LOCKDOWN_MODE.get(); DirectoryServer.sendAlertNotification(this, ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED, lockDownMsg ); ALERT_TYPE_ACCESS_CONTROL_PARSE_FAILED, lockDownMsg); //Enter lockdown mode. DirectoryServer.setLockdownMode(true); opends/src/server/org/opends/server/core/DirectoryServer.java
@@ -123,6 +123,7 @@ import org.opends.server.api.SynchronizationProvider; import org.opends.server.api.TrustManagerProvider; import org.opends.server.api.WorkQueue; import org.opends.server.api.plugin.InternalDirectoryServerPlugin; import org.opends.server.api.plugin.PluginResult; import org.opends.server.api.plugin.PluginType; import org.opends.server.api.ExtensibleMatchingRule; @@ -1341,6 +1342,11 @@ initializeSchema(); // Initialize the plugin manager so that internal plugins can be // registered. pluginConfigManager.initializePluginConfigManager(); // Initialize all the virtual attribute handlers. initializeVirtualAttributes(); @@ -1474,9 +1480,8 @@ initializePasswordPolicyComponents(); // Load and initialize all the plugins, and then call the registered // startup plugins. initializePlugins(); // Load and initialize the user plugins. pluginConfigManager.initializeUserPlugins(null); // Initialize any synchronization providers that may be defined. if (!environmentConfig.disableSynchronization()) @@ -1491,6 +1496,7 @@ workQueue = new WorkQueueConfigManager().initializeWorkQueue(); // Invoke the startup plugins. PluginResult.Startup startupPluginResult = pluginConfigManager.invokeStartupPlugins(); if (! startupPluginResult.continueProcessing()) @@ -2906,24 +2912,6 @@ /** * Initializes the set of plugins defined in the Directory Server. * * @throws ConfigException If there is a configuration problem with any of * the Directory Server plugins. * * @throws InitializationException If a problem occurs while initializing * the plugins that is not related to the * server configuration. */ public void initializePlugins() throws ConfigException, InitializationException { pluginConfigManager.initializePluginConfig(null); } /** * Initializes the set of plugins defined in the Directory Server. Only the * specified types of plugins will be initialized. * @@ -2941,7 +2929,8 @@ throws ConfigException, InitializationException { pluginConfigManager = new PluginConfigManager(); pluginConfigManager.initializePluginConfig(pluginTypes); pluginConfigManager.initializePluginConfigManager(); pluginConfigManager.initializeUserPlugins(pluginTypes); } @@ -3005,6 +2994,37 @@ /** * Registers the provided internal plugin with the Directory Server * and ensures that it will be invoked in the specified ways. * * @param plugin * The internal plugin to register with the Directory Server. * The plugin must specify a configuration entry which is * guaranteed to be unique. */ public static void registerInternalPlugin( InternalDirectoryServerPlugin plugin) { directoryServer.pluginConfigManager.registerInternalPlugin(plugin); } /** * Deregisters the provided internal plugin with the Directory Server. * * @param plugin * The internal plugin to deregister from the Directory Server. */ public static void deregisterInternalPlugin( InternalDirectoryServerPlugin plugin) { directoryServer.pluginConfigManager.deregisterInternalPlugin(plugin); } /** * Retrieves the requested entry from the Directory Server configuration. * * @param entryDN The DN of the configuration entry to retrieve. opends/src/server/org/opends/server/core/PluginConfigManager.java
@@ -234,46 +234,58 @@ /** * Initializes the configuration associated with the Directory Server plugins. * This should only be called at Directory Server startup. * Initializes this plugin configuration manager. This should only * be called at Directory Server startup and before user plugins are * loaded. * * @param pluginTypes The set of plugin types for the plugins to initialize, * or <CODE>null</CODE> to initialize all types of * plugins defined in the server configuration. In * general, this should only be non-null for cases in * which the server is running in a special mode that * only uses a minimal set of plugins (e.g., LDIF import * or export). * * @throws ConfigException If a critical configuration problem prevents the * plugin initialization from succeeding. * * @throws InitializationException If a problem occurs while initializing * the plugins that is not related to the * server configuration. * @throws ConfigException * If a critical configuration problem prevents the plugin * initialization from succeeding. */ public void initializePluginConfig(Set<PluginType> pluginTypes) throws ConfigException, InitializationException public void initializePluginConfigManager() throws ConfigException { registeredPlugins.clear(); // Get the root configuration object. ServerManagementContext managementContext = ServerManagementContext.getInstance(); RootCfg rootConfiguration = managementContext.getRootConfiguration(); // 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. /** * Initializes any plugins defined in the directory server * configuration. This should only be called at Directory Server * startup and after this plugin configuration manager has been * initialized. * * @param pluginTypes * The set of plugin types for the plugins to initialize, or * <CODE>null</CODE> to initialize all types of plugins * defined in the server configuration. In general, this * should only be non-null for cases in which the server is * running in a special mode that only uses a minimal set of * plugins (e.g., LDIF import or export). * @throws ConfigException * If a critical configuration problem prevents the plugin * initialization from succeeding. * @throws InitializationException * If a problem occurs while initializing the plugins that * is not related to the server configuration. */ public void initializeUserPlugins(Set<PluginType> pluginTypes) throws ConfigException, InitializationException { //Initialize the user plugins. for (String pluginName : pluginRootConfig.listPlugins()) { PluginCfg pluginConfiguration = pluginRootConfig.getPlugin(pluginName); @@ -360,11 +372,11 @@ if (initialize) { Method method = plugin.getClass().getMethod("initializeInternal", PluginCfg.class, Set.class); method.invoke(plugin, configuration, pluginTypes); plugin.initializeInternal(configuration.dn(), pluginTypes, configuration.isInvokeForInternalOperations()); method = plugin.getClass().getMethod("initializePlugin", Set.class, Method method = plugin.getClass().getMethod("initializePlugin", Set.class, configuration.configurationClass()); method.invoke(plugin, pluginTypes, configuration); } @@ -553,43 +565,60 @@ /** * Registers the provided plugin with this plugin config manager and ensures * that it will be invoked in the specified ways. * Registers the provided internal plugin with this plugin config * manager and ensures that it will be invoked in the specified ways. * * @param plugin The plugin to register with the server. * @param pluginEntryDN The DN of the configuration entry for the provided * plugin. * @param pluginTypes The plugin types that will be used to control the * points at which the provided plugin is invoked. * @param plugin * The internal plugin to register with the server. The * plugin must specify a configuration entry which is * guaranteed to be unique. */ private void registerPlugin( DirectoryServerPlugin<? extends PluginCfg> plugin, DN pluginEntryDN, Set<PluginType> pluginTypes) void registerInternalPlugin(InternalDirectoryServerPlugin plugin) { pluginLock.lock(); try { registeredPlugins.put(pluginEntryDN, plugin); registerPlugin0(plugin, plugin.getPluginTypes()); } finally { pluginLock.unlock(); } } /** * Register a plugin in the appropriate tables. * * @param plugin * The plugin to register with the server. * @param pluginTypes * The plugin types that will be used to control the points * at which the provided plugin is invoked. */ private void registerPlugin0( DirectoryServerPlugin<? extends PluginCfg> plugin, Set<PluginType> pluginTypes) { for (PluginType t : pluginTypes) { switch (t) { case STARTUP: startupPlugins = addPlugin(startupPlugins, plugin, t, pluginRootConfig.getPluginOrderStartup()); addPlugin(startupPlugins, plugin, t, pluginRootConfig .getPluginOrderStartup()); break; case SHUTDOWN: shutdownPlugins = addPlugin(shutdownPlugins, plugin, t, pluginRootConfig.getPluginOrderShutdown()); addPlugin(shutdownPlugins, plugin, t, pluginRootConfig .getPluginOrderShutdown()); break; case POST_CONNECT: postConnectPlugins = addPlugin(postConnectPlugins, plugin, t, pluginRootConfig.getPluginOrderPostConnect()); addPlugin(postConnectPlugins, plugin, t, pluginRootConfig .getPluginOrderPostConnect()); break; case POST_DISCONNECT: postDisconnectPlugins = @@ -598,13 +627,13 @@ break; case LDIF_IMPORT: ldifImportPlugins = addPlugin(ldifImportPlugins, plugin, t, pluginRootConfig.getPluginOrderLDIFImport()); addPlugin(ldifImportPlugins, plugin, t, pluginRootConfig .getPluginOrderLDIFImport()); break; case LDIF_IMPORT_END: ldifImportEndPlugins = addPlugin(ldifImportEndPlugins, plugin, t, pluginRootConfig.getPluginOrderLDIFImportEnd()); addPlugin(ldifImportEndPlugins, plugin, t, pluginRootConfig .getPluginOrderLDIFImportEnd()); break; case LDIF_IMPORT_BEGIN: ldifImportBeginPlugins = @@ -613,8 +642,8 @@ break; case LDIF_EXPORT: ldifExportPlugins = addPlugin(ldifExportPlugins, plugin, t, pluginRootConfig.getPluginOrderLDIFExport()); addPlugin(ldifExportPlugins, plugin, t, pluginRootConfig .getPluginOrderLDIFExport()); break; case PRE_PARSE_ABANDON: preParseAbandonPlugins = @@ -623,13 +652,13 @@ break; case PRE_PARSE_ADD: preParseAddPlugins = addPlugin(preParseAddPlugins, plugin, t, pluginRootConfig.getPluginOrderPreParseAdd()); addPlugin(preParseAddPlugins, plugin, t, pluginRootConfig .getPluginOrderPreParseAdd()); break; case PRE_PARSE_BIND: preParseBindPlugins = addPlugin(preParseBindPlugins, plugin, t, pluginRootConfig.getPluginOrderPreParseBind()); addPlugin(preParseBindPlugins, plugin, t, pluginRootConfig .getPluginOrderPreParseBind()); break; case PRE_PARSE_COMPARE: preParseComparePlugins = @@ -799,26 +828,25 @@ case POST_SYNCHRONIZATION_ADD: postSynchronizationAddPlugins = addPlugin(postSynchronizationAddPlugins, plugin, t, pluginRootConfig. getPluginOrderPostSynchronizationAdd()); pluginRootConfig.getPluginOrderPostSynchronizationAdd()); break; case POST_SYNCHRONIZATION_DELETE: postSynchronizationDeletePlugins = addPlugin(postSynchronizationDeletePlugins, plugin, t, pluginRootConfig. getPluginOrderPostSynchronizationDelete()); pluginRootConfig .getPluginOrderPostSynchronizationDelete()); break; case POST_SYNCHRONIZATION_MODIFY: postSynchronizationModifyPlugins = addPlugin(postSynchronizationModifyPlugins, plugin, t, pluginRootConfig. getPluginOrderPostSynchronizationModify()); pluginRootConfig .getPluginOrderPostSynchronizationModify()); break; case POST_SYNCHRONIZATION_MODIFY_DN: postSynchronizationModifyDNPlugins = addPlugin(postSynchronizationModifyDNPlugins, plugin, t, pluginRootConfig. getPluginOrderPostSynchronizationModifyDN()); pluginRootConfig .getPluginOrderPostSynchronizationModifyDN()); break; case SEARCH_RESULT_ENTRY: searchResultEntryPlugins = @@ -844,6 +872,31 @@ } } } /** * Registers the provided plugin with this plugin config manager and * ensures that it will be invoked in the specified ways. * * @param plugin * The plugin to register with the server. * @param pluginEntryDN * The DN of the configuration entry for the provided plugin. * @param pluginTypes * The plugin types that will be used to control the points * at which the provided plugin is invoked. */ private void registerPlugin( DirectoryServerPlugin<? extends PluginCfg> plugin, DN pluginEntryDN, Set<PluginType> pluginTypes) { pluginLock.lock(); registeredPlugins.put(pluginEntryDN, plugin); try { registerPlugin0(plugin, pluginTypes); } finally { pluginLock.unlock(); @@ -1067,24 +1120,64 @@ /** * Deregisters the provided internal plugin. * * @param plugin * The internal plugin to deregister from the server. */ void deregisterInternalPlugin(InternalDirectoryServerPlugin plugin) { pluginLock.lock(); try { deregisterPlugin0(plugin); plugin.finalizePlugin(); } finally { pluginLock.unlock(); } } /** * Deregisters the plugin with the provided configuration entry DN. * * @param configEntryDN The DN of the configuration entry for the plugin to * @param configEntryDN * The DN of the configuration entry for the plugin to * deregister. */ private void deregisterPlugin(DN configEntryDN) { pluginLock.lock(); DirectoryServerPlugin<? extends PluginCfg> plugin; try { plugin = registeredPlugins.remove(configEntryDN); if (plugin == null) if (plugin != null) { return; deregisterPlugin0(plugin); plugin.finalizePlugin(); } } finally { pluginLock.unlock(); } } /** * Deregisters the provided plugin. * * @param plugin * The plugin to deregister from the server. */ private void deregisterPlugin0( DirectoryServerPlugin<? extends PluginCfg> plugin) { for (PluginType t : plugin.getPluginTypes()) { switch (t) @@ -1288,13 +1381,6 @@ } } } finally { pluginLock.unlock(); } plugin.finalizePlugin(); } opends/tests/unit-tests-testng/src/server/org/opends/server/api/plugin/DirectoryServerPluginTestCase.java
@@ -560,8 +560,9 @@ sigList = new LinkedList<String>(); sigList.add("initializeInternal"); sigList.add("void"); sigList.add("org.opends.server.admin.std.server.PluginCfg"); sigList.add("org.opends.server.types.DN"); sigList.add("java.util.Set"); sigList.add("boolean"); expectedPublicMethods.add(sigList); sigList = new LinkedList<String>(); @@ -821,7 +822,8 @@ pluginTypes.add(t); } nullPlugin.initializeInternal(configuration, pluginTypes); nullPlugin.initializeInternal(configuration.dn(), pluginTypes, configuration.isInvokeForInternalOperations()); assertEquals(nullPlugin.getPluginEntryDN(), pluginEntryDN); } @@ -907,7 +909,8 @@ pluginTypes.add(t); } nullPlugin.initializeInternal(configuration, pluginTypes); nullPlugin.initializeInternal(configuration.dn(), pluginTypes, configuration.isInvokeForInternalOperations()); assertEquals(nullPlugin.getPluginTypes(), pluginTypes); }