001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2011-2015 ForgeRock AS
026 */
027package org.opends.server.core;
028
029import static org.opends.messages.ConfigMessages.*;
030import static org.opends.messages.PluginMessages.*;
031import static org.opends.server.util.StaticUtils.*;
032
033import java.util.*;
034import java.util.concurrent.ConcurrentHashMap;
035import java.util.concurrent.locks.ReentrantLock;
036
037import org.forgerock.i18n.LocalizableMessage;
038import org.forgerock.i18n.LocalizableMessageDescriptor.Arg4;
039import org.forgerock.i18n.LocalizableMessageDescriptor.Arg5;
040import org.forgerock.i18n.slf4j.LocalizedLogger;
041import org.forgerock.opendj.config.server.ConfigChangeResult;
042import org.forgerock.opendj.config.server.ConfigException;
043import org.forgerock.opendj.ldap.ResultCode;
044import org.forgerock.util.Utils;
045import org.opends.server.admin.ClassPropertyDefinition;
046import org.opends.server.admin.server.ConfigurationAddListener;
047import org.opends.server.admin.server.ConfigurationChangeListener;
048import org.opends.server.admin.server.ConfigurationDeleteListener;
049import org.opends.server.admin.server.ServerManagementContext;
050import org.opends.server.admin.std.meta.PluginCfgDefn;
051import org.opends.server.admin.std.server.PluginCfg;
052import org.opends.server.admin.std.server.PluginRootCfg;
053import org.opends.server.admin.std.server.RootCfg;
054import org.opends.server.api.ClientConnection;
055import org.opends.server.api.plugin.DirectoryServerPlugin;
056import org.opends.server.api.plugin.InternalDirectoryServerPlugin;
057import org.opends.server.api.plugin.PluginResult;
058import org.opends.server.api.plugin.PluginType;
059import org.opends.server.types.*;
060import org.opends.server.types.operation.*;
061
062/**
063 * This class defines a utility that will be used to manage the configuration
064 * for the set of plugins defined in the Directory Server.  It will perform the
065 * necessary initialization of those plugins when the server is first started,
066 * and then will manage any changes to them while the server is running.  It
067 * also provides methods for invoking all the plugins of a given type.
068 */
069public class PluginConfigManager
070       implements ConfigurationAddListener<PluginCfg>,
071                  ConfigurationDeleteListener<PluginCfg>,
072                  ConfigurationChangeListener<PluginCfg>
073{
074  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
075
076  // Arrays for holding the plugins of each type.
077  private DirectoryServerPlugin[] startupPlugins;
078  private DirectoryServerPlugin[] shutdownPlugins;
079  private DirectoryServerPlugin[] postConnectPlugins;
080  private DirectoryServerPlugin[] postDisconnectPlugins;
081  private DirectoryServerPlugin[] ldifImportPlugins;
082  private DirectoryServerPlugin[] ldifImportEndPlugins;
083  private DirectoryServerPlugin[] ldifImportBeginPlugins;
084  private DirectoryServerPlugin[] ldifExportPlugins;
085  private DirectoryServerPlugin[] preParseAbandonPlugins;
086  private DirectoryServerPlugin[] preParseAddPlugins;
087  private DirectoryServerPlugin[] preParseBindPlugins;
088  private DirectoryServerPlugin[] preParseComparePlugins;
089  private DirectoryServerPlugin[] preParseDeletePlugins;
090  private DirectoryServerPlugin[] preParseExtendedPlugins;
091  private DirectoryServerPlugin[] preParseModifyPlugins;
092  private DirectoryServerPlugin[] preParseModifyDNPlugins;
093  private DirectoryServerPlugin[] preParseSearchPlugins;
094  private DirectoryServerPlugin[] preParseUnbindPlugins;
095  private DirectoryServerPlugin[] preOperationAddPlugins;
096  private DirectoryServerPlugin[] preOperationBindPlugins;
097  private DirectoryServerPlugin[] preOperationComparePlugins;
098  private DirectoryServerPlugin[] preOperationDeletePlugins;
099  private DirectoryServerPlugin[] preOperationExtendedPlugins;
100  private DirectoryServerPlugin[] preOperationModifyPlugins;
101  private DirectoryServerPlugin[] preOperationModifyDNPlugins;
102  private DirectoryServerPlugin[] preOperationSearchPlugins;
103  private DirectoryServerPlugin[] postOperationAbandonPlugins;
104  private DirectoryServerPlugin[] postOperationAddPlugins;
105  private DirectoryServerPlugin[] postOperationBindPlugins;
106  private DirectoryServerPlugin[] postOperationComparePlugins;
107  private DirectoryServerPlugin[] postOperationDeletePlugins;
108  private DirectoryServerPlugin[] postOperationExtendedPlugins;
109  private DirectoryServerPlugin[] postOperationModifyPlugins;
110  private DirectoryServerPlugin[] postOperationModifyDNPlugins;
111  private DirectoryServerPlugin[] postOperationSearchPlugins;
112  private DirectoryServerPlugin[] postOperationUnbindPlugins;
113  private DirectoryServerPlugin[] postResponseAddPlugins;
114  private DirectoryServerPlugin[] postResponseBindPlugins;
115  private DirectoryServerPlugin[] postResponseComparePlugins;
116  private DirectoryServerPlugin[] postResponseDeletePlugins;
117  private DirectoryServerPlugin[] postResponseExtendedPlugins;
118  private DirectoryServerPlugin[] postResponseModifyPlugins;
119  private DirectoryServerPlugin[] postResponseModifyDNPlugins;
120  private DirectoryServerPlugin[] postResponseSearchPlugins;
121  private DirectoryServerPlugin[] postSynchronizationAddPlugins;
122  private DirectoryServerPlugin[] postSynchronizationDeletePlugins;
123  private DirectoryServerPlugin[] postSynchronizationModifyPlugins;
124  private DirectoryServerPlugin[] postSynchronizationModifyDNPlugins;
125  private DirectoryServerPlugin[] searchResultEntryPlugins;
126  private DirectoryServerPlugin[] searchResultReferencePlugins;
127  private DirectoryServerPlugin[] subordinateModifyDNPlugins;
128  private DirectoryServerPlugin[] subordinateDeletePlugins;
129  private DirectoryServerPlugin[] intermediateResponsePlugins;
130
131
132  /**
133   * The mapping between the DN of a plugin entry and the plugin instance loaded
134   * from that entry.
135   */
136  private ConcurrentHashMap<DN,
137               DirectoryServerPlugin<? extends PluginCfg>>
138                    registeredPlugins;
139
140  /**
141   * The mapping between an operation and a set of post operation plugins
142   * it should skip. This pairs up pre and post operation plugin processing
143   * such that only plugins that successfully execute its pre op plugin will
144   * have its post op plugin executed on a per operation basis. If an
145   * operation is not registered on this list then all all pre op plugins
146   * executed successfully for this operation so all post op plugins should
147   * execute.
148   */
149  private ConcurrentHashMap<PluginOperation, ArrayList<DirectoryServerPlugin>>
150      skippedPreOperationPlugins;
151
152  /** The plugin root configuration read at server startup. */
153  private PluginRootCfg pluginRootConfig;
154
155  /**
156   * The lock that will provide threadsafe access to the sets of registered
157   * plugins.
158   */
159  private ReentrantLock pluginLock;
160
161  private final ServerContext serverContext;
162
163  /**
164   * Creates a new instance of this plugin config manager.
165   *
166   * @param serverContext
167   *          The server context.
168   */
169  public PluginConfigManager(ServerContext serverContext)
170  {
171    this.serverContext = serverContext;
172    pluginLock = new ReentrantLock();
173
174    startupPlugins                     = new DirectoryServerPlugin[0];
175    shutdownPlugins                    = new DirectoryServerPlugin[0];
176    postConnectPlugins                 = new DirectoryServerPlugin[0];
177    postDisconnectPlugins              = new DirectoryServerPlugin[0];
178    ldifImportPlugins                  = new DirectoryServerPlugin[0];
179    ldifImportEndPlugins               = new DirectoryServerPlugin[0];
180    ldifImportBeginPlugins             = new DirectoryServerPlugin[0];
181    ldifExportPlugins                  = new DirectoryServerPlugin[0];
182    preParseAbandonPlugins             = new DirectoryServerPlugin[0];
183    preParseAddPlugins                 = new DirectoryServerPlugin[0];
184    preParseBindPlugins                = new DirectoryServerPlugin[0];
185    preParseComparePlugins             = new DirectoryServerPlugin[0];
186    preParseDeletePlugins              = new DirectoryServerPlugin[0];
187    preParseExtendedPlugins            = new DirectoryServerPlugin[0];
188    preParseModifyPlugins              = new DirectoryServerPlugin[0];
189    preParseModifyDNPlugins            = new DirectoryServerPlugin[0];
190    preParseSearchPlugins              = new DirectoryServerPlugin[0];
191    preParseUnbindPlugins              = new DirectoryServerPlugin[0];
192    preOperationAddPlugins             = new DirectoryServerPlugin[0];
193    preOperationBindPlugins            = new DirectoryServerPlugin[0];
194    preOperationComparePlugins         = new DirectoryServerPlugin[0];
195    preOperationDeletePlugins          = new DirectoryServerPlugin[0];
196    preOperationExtendedPlugins        = new DirectoryServerPlugin[0];
197    preOperationModifyPlugins          = new DirectoryServerPlugin[0];
198    preOperationModifyDNPlugins        = new DirectoryServerPlugin[0];
199    preOperationSearchPlugins          = new DirectoryServerPlugin[0];
200    postOperationAbandonPlugins        = new DirectoryServerPlugin[0];
201    postOperationAddPlugins            = new DirectoryServerPlugin[0];
202    postOperationBindPlugins           = new DirectoryServerPlugin[0];
203    postOperationComparePlugins        = new DirectoryServerPlugin[0];
204    postOperationDeletePlugins         = new DirectoryServerPlugin[0];
205    postOperationExtendedPlugins       = new DirectoryServerPlugin[0];
206    postOperationModifyPlugins         = new DirectoryServerPlugin[0];
207    postOperationModifyDNPlugins       = new DirectoryServerPlugin[0];
208    postOperationSearchPlugins         = new DirectoryServerPlugin[0];
209    postOperationUnbindPlugins         = new DirectoryServerPlugin[0];
210    postResponseAddPlugins             = new DirectoryServerPlugin[0];
211    postResponseBindPlugins            = new DirectoryServerPlugin[0];
212    postResponseComparePlugins         = new DirectoryServerPlugin[0];
213    postResponseDeletePlugins          = new DirectoryServerPlugin[0];
214    postResponseExtendedPlugins        = new DirectoryServerPlugin[0];
215    postResponseModifyPlugins          = new DirectoryServerPlugin[0];
216    postResponseModifyDNPlugins        = new DirectoryServerPlugin[0];
217    postResponseSearchPlugins          = new DirectoryServerPlugin[0];
218    postSynchronizationAddPlugins      = new DirectoryServerPlugin[0];
219    postSynchronizationDeletePlugins   = new DirectoryServerPlugin[0];
220    postSynchronizationModifyPlugins   = new DirectoryServerPlugin[0];
221    postSynchronizationModifyDNPlugins = new DirectoryServerPlugin[0];
222    searchResultEntryPlugins           = new DirectoryServerPlugin[0];
223    searchResultReferencePlugins       = new DirectoryServerPlugin[0];
224    subordinateModifyDNPlugins         = new DirectoryServerPlugin[0];
225    subordinateDeletePlugins           = new DirectoryServerPlugin[0];
226    intermediateResponsePlugins        = new DirectoryServerPlugin[0];
227    registeredPlugins                  = new ConcurrentHashMap<>();
228    skippedPreOperationPlugins = new ConcurrentHashMap<>();
229  }
230
231
232
233  /**
234   * Initializes this plugin configuration manager. This should only be called
235   * at Directory Server startup and before user plugins are loaded.
236   *
237   * @throws ConfigException
238   *           If a critical configuration problem prevents the plugin
239   *           initialization from succeeding.
240   */
241  public void initializePluginConfigManager() throws ConfigException
242  {
243    registeredPlugins.clear();
244
245    // Get the root configuration object.
246    ServerManagementContext managementContext =
247         ServerManagementContext.getInstance();
248    RootCfg rootConfiguration =
249         managementContext.getRootConfiguration();
250
251    // Get the plugin root configuration and register with it as an add and
252    // delete listener so we can be notified if any plugin entries are added or
253    // removed.
254    pluginRootConfig = rootConfiguration.getPluginRoot();
255    pluginRootConfig.addPluginAddListener(this);
256    pluginRootConfig.addPluginDeleteListener(this);
257  }
258
259
260
261  /**
262   * Initializes any plugins defined in the directory server
263   * configuration. This should only be called at Directory Server
264   * startup and after this plugin configuration manager has been
265   * initialized.
266   *
267   * @param pluginTypes
268   *          The set of plugin types for the plugins to initialize, or
269   *          <CODE>null</CODE> to initialize all types of plugins
270   *          defined in the server configuration. In general, this
271   *          should only be non-null for cases in which the server is
272   *          running in a special mode that only uses a minimal set of
273   *          plugins (e.g., LDIF import or export).
274   * @throws ConfigException
275   *           If a critical configuration problem prevents the plugin
276   *           initialization from succeeding.
277   * @throws InitializationException
278   *           If a problem occurs while initializing the plugins that
279   *           is not related to the server configuration.
280   */
281  public void initializeUserPlugins(Set<PluginType> pluginTypes)
282         throws ConfigException, InitializationException
283  {
284    //Initialize the user plugins.
285    for (String pluginName : pluginRootConfig.listPlugins())
286    {
287      PluginCfg pluginConfiguration = pluginRootConfig.getPlugin(pluginName);
288      pluginConfiguration.addChangeListener(this);
289
290      if (! pluginConfiguration.isEnabled())
291      {
292        continue;
293      }
294
295      // Create a set of plugin types for the plugin.
296      HashSet<PluginType> initTypes = new HashSet<>();
297      for (PluginCfgDefn.PluginType pluginType : pluginConfiguration.getPluginType())
298      {
299        PluginType t = getPluginType(pluginType);
300        if (pluginTypes == null || pluginTypes.contains(t))
301        {
302          initTypes.add(t);
303        }
304      }
305
306      if (initTypes.isEmpty())
307      {
308        continue;
309      }
310
311      try
312      {
313        DirectoryServerPlugin<? extends PluginCfg> plugin =
314             loadPlugin(pluginConfiguration.getJavaClass(), initTypes,
315                        pluginConfiguration, true);
316        registerPlugin(plugin, pluginConfiguration.dn(), initTypes);
317      }
318      catch (InitializationException ie)
319      {
320        logger.error(ie.getMessageObject());
321        continue;
322      }
323    }
324  }
325
326
327
328  /**
329   * Loads the specified class, instantiates it as a plugin, and optionally
330   * initializes that plugin.
331   *
332   * @param  className      The fully-qualified name of the plugin class to
333   *                        load, instantiate, and initialize.
334   * @param  pluginTypes    The set of plugin types for the plugins to
335   *                        initialize, or {@code null} to initialize all types
336   *                        of plugins defined in the server configuration.  In
337   *                        general, this should only be non-null for cases in
338   *                        which the server is running in a special mode that
339   *                        only uses a minimal set of plugins (e.g., LDIF
340   *                        import or export).
341   * @param  configuration  The configuration to use to initialize the plugin.
342   *                        It must not be {@code null}.
343   * @param  initialize     Indicates whether the plugin instance should be
344   *                        initialized.
345   *
346   * @return  The possibly initialized plugin.
347   *
348   * @throws  InitializationException  If a problem occurred while attempting to
349   *                                   initialize the plugin.
350   */
351  private <T extends PluginCfg> DirectoryServerPlugin<T>
352               loadPlugin(String className, Set<PluginType> pluginTypes,
353                          T configuration, boolean initialize)
354          throws InitializationException
355  {
356    try
357    {
358      PluginCfgDefn definition =
359           PluginCfgDefn.getInstance();
360      ClassPropertyDefinition propertyDefinition =
361           definition.getJavaClassPropertyDefinition();
362      Class<? extends DirectoryServerPlugin> pluginClass =
363           propertyDefinition.loadClass(className, DirectoryServerPlugin.class);
364      DirectoryServerPlugin<T> plugin = pluginClass.newInstance();
365
366      if (initialize)
367      {
368        plugin.initializeInternal(configuration.dn(), pluginTypes,
369            configuration.isInvokeForInternalOperations());
370        plugin.initializePlugin(pluginTypes, configuration);
371      }
372      else
373      {
374        List<LocalizableMessage> unacceptableReasons = new ArrayList<>();
375        if (!plugin.isConfigurationAcceptable(configuration, unacceptableReasons))
376        {
377          String buffer = Utils.joinAsString(".  ", unacceptableReasons);
378          throw new InitializationException(
379              ERR_CONFIG_PLUGIN_CONFIG_NOT_ACCEPTABLE.get(configuration.dn(), buffer));
380        }
381      }
382
383      return plugin;
384    }
385    catch (Exception e)
386    {
387      LocalizableMessage message = ERR_CONFIG_PLUGIN_CANNOT_INITIALIZE.
388          get(className, configuration.dn(), stackTraceToSingleLineString(e));
389      throw new InitializationException(message, e);
390    }
391  }
392
393
394
395  /**
396   * Gets the OpenDS plugin type object that corresponds to the configuration
397   * counterpart.
398   *
399   * @param  configPluginType  The configuration plugin type for which to
400   *                           retrieve the OpenDS plugin type.
401   */
402  private PluginType getPluginType(PluginCfgDefn.PluginType
403                                        configPluginType)
404  {
405    switch (configPluginType)
406    {
407      case STARTUP:                return PluginType.STARTUP;
408      case SHUTDOWN:               return PluginType.SHUTDOWN;
409      case POSTCONNECT:            return PluginType.POST_CONNECT;
410      case POSTDISCONNECT:         return PluginType.POST_DISCONNECT;
411      case LDIFIMPORT:             return PluginType.LDIF_IMPORT;
412      case LDIFIMPORTEND:          return PluginType.LDIF_IMPORT_END;
413      case LDIFIMPORTBEGIN:        return PluginType.LDIF_IMPORT_BEGIN;
414      case LDIFEXPORT:             return PluginType.LDIF_EXPORT;
415      case PREPARSEABANDON:        return PluginType.PRE_PARSE_ABANDON;
416      case PREPARSEADD:            return PluginType.PRE_PARSE_ADD;
417      case PREPARSEBIND:           return PluginType.PRE_PARSE_BIND;
418      case PREPARSECOMPARE:        return PluginType.PRE_PARSE_COMPARE;
419      case PREPARSEDELETE:         return PluginType.PRE_PARSE_DELETE;
420      case PREPARSEEXTENDED:       return PluginType.PRE_PARSE_EXTENDED;
421      case PREPARSEMODIFY:         return PluginType.PRE_PARSE_MODIFY;
422      case PREPARSEMODIFYDN:       return PluginType.PRE_PARSE_MODIFY_DN;
423      case PREPARSESEARCH:         return PluginType.PRE_PARSE_SEARCH;
424      case PREPARSEUNBIND:         return PluginType.PRE_PARSE_UNBIND;
425      case PREOPERATIONADD:        return PluginType.PRE_OPERATION_ADD;
426      case PREOPERATIONBIND:       return PluginType.PRE_OPERATION_BIND;
427      case PREOPERATIONCOMPARE:    return PluginType.PRE_OPERATION_COMPARE;
428      case PREOPERATIONDELETE:     return PluginType.PRE_OPERATION_DELETE;
429      case PREOPERATIONEXTENDED:   return PluginType.PRE_OPERATION_EXTENDED;
430      case PREOPERATIONMODIFY:     return PluginType.PRE_OPERATION_MODIFY;
431      case PREOPERATIONMODIFYDN:   return PluginType.PRE_OPERATION_MODIFY_DN;
432      case PREOPERATIONSEARCH:     return PluginType.PRE_OPERATION_SEARCH;
433      case POSTOPERATIONABANDON:   return PluginType.POST_OPERATION_ABANDON;
434      case POSTOPERATIONADD:       return PluginType.POST_OPERATION_ADD;
435      case POSTOPERATIONBIND:      return PluginType.POST_OPERATION_BIND;
436      case POSTOPERATIONCOMPARE:   return PluginType.POST_OPERATION_COMPARE;
437      case POSTOPERATIONDELETE:    return PluginType.POST_OPERATION_DELETE;
438      case POSTOPERATIONEXTENDED:  return PluginType.POST_OPERATION_EXTENDED;
439      case POSTOPERATIONMODIFY:    return PluginType.POST_OPERATION_MODIFY;
440      case POSTOPERATIONMODIFYDN:  return PluginType.POST_OPERATION_MODIFY_DN;
441      case POSTOPERATIONSEARCH:    return PluginType.POST_OPERATION_SEARCH;
442      case POSTOPERATIONUNBIND:    return PluginType.POST_OPERATION_UNBIND;
443      case POSTRESPONSEADD:        return PluginType.POST_RESPONSE_ADD;
444      case POSTRESPONSEBIND:       return PluginType.POST_RESPONSE_BIND;
445      case POSTRESPONSECOMPARE:    return PluginType.POST_RESPONSE_COMPARE;
446      case POSTRESPONSEDELETE:     return PluginType.POST_RESPONSE_DELETE;
447      case POSTRESPONSEEXTENDED:   return PluginType.POST_RESPONSE_EXTENDED;
448      case POSTRESPONSEMODIFY:     return PluginType.POST_RESPONSE_MODIFY;
449      case POSTRESPONSEMODIFYDN:   return PluginType.POST_RESPONSE_MODIFY_DN;
450      case POSTRESPONSESEARCH:     return PluginType.POST_RESPONSE_SEARCH;
451      case SEARCHRESULTENTRY:      return PluginType.SEARCH_RESULT_ENTRY;
452      case SEARCHRESULTREFERENCE:  return PluginType.SEARCH_RESULT_REFERENCE;
453      case SUBORDINATEMODIFYDN:    return PluginType.SUBORDINATE_MODIFY_DN;
454      case SUBORDINATEDELETE:      return PluginType.SUBORDINATE_DELETE;
455      case INTERMEDIATERESPONSE:   return PluginType.INTERMEDIATE_RESPONSE;
456      case POSTSYNCHRONIZATIONADD:
457                return PluginType.POST_SYNCHRONIZATION_ADD;
458      case POSTSYNCHRONIZATIONDELETE:
459                return PluginType.POST_SYNCHRONIZATION_DELETE;
460      case POSTSYNCHRONIZATIONMODIFY:
461                return PluginType.POST_SYNCHRONIZATION_MODIFY;
462      case POSTSYNCHRONIZATIONMODIFYDN:
463                return PluginType.POST_SYNCHRONIZATION_MODIFY_DN;
464      default:                     return null;
465    }
466  }
467
468
469
470  /**
471   * Finalizes all plugins that are registered with the Directory Server.
472   */
473  public void finalizePlugins()
474  {
475    pluginLock.lock();
476
477    try
478    {
479      for (DirectoryServerPlugin<? extends PluginCfg> plugin : registeredPlugins.values())
480      {
481        try
482        {
483          plugin.finalizePlugin();
484        }
485        catch (Exception e)
486        {
487          logger.traceException(e);
488        }
489      }
490
491      registeredPlugins.clear();
492    }
493    finally
494    {
495      pluginLock.unlock();
496    }
497  }
498
499
500
501  /**
502   * Retrieves the set of plugins that have been registered with the Directory
503   * Server.
504   *
505   * @return  The set of plugins that have been registered with the Directory
506   *          Server.
507   */
508  public ConcurrentHashMap<DN,
509              DirectoryServerPlugin<? extends PluginCfg>>
510                   getRegisteredPlugins()
511  {
512    return registeredPlugins;
513  }
514
515
516
517  /**
518   * Retrieves the plugin with the specified configuration entry DN.
519   *
520   * @param  pluginDN  The DN of the configuration entry for the plugin to
521   *                   retrieve.
522   *
523   * @return  The requested plugin, or <CODE>null</CODE> if there is no such
524   *          plugin.
525   */
526  public DirectoryServerPlugin getRegisteredPlugin(DN pluginDN)
527  {
528    return registeredPlugins.get(pluginDN);
529  }
530
531
532
533  /**
534   * Registers the provided internal plugin with this plugin config
535   * manager and ensures that it will be invoked in the specified ways.
536   *
537   * @param plugin
538   *          The internal plugin to register with the server. The
539   *          plugin must specify a configuration entry which is
540   *          guaranteed to be unique.
541   */
542  void registerInternalPlugin(InternalDirectoryServerPlugin plugin)
543  {
544    pluginLock.lock();
545    try
546    {
547      registerPlugin0(plugin, plugin.getPluginTypes());
548    }
549    finally
550    {
551      pluginLock.unlock();
552    }
553  }
554
555
556
557  /**
558   * Register a plugin in the appropriate tables.
559   *
560   * @param plugin
561   *          The plugin to register with the server.
562   * @param pluginTypes
563   *          The plugin types that will be used to control the points
564   *          at which the provided plugin is invoked.
565   */
566  private void registerPlugin0(
567      DirectoryServerPlugin<? extends PluginCfg> plugin,
568      Set<PluginType> pluginTypes)
569  {
570    for (PluginType t : pluginTypes)
571    {
572      switch (t)
573      {
574      case STARTUP:
575        startupPlugins =
576            addPlugin(startupPlugins, plugin, t, pluginRootConfig
577                .getPluginOrderStartup());
578        break;
579      case SHUTDOWN:
580        shutdownPlugins =
581            addPlugin(shutdownPlugins, plugin, t, pluginRootConfig
582                .getPluginOrderShutdown());
583        break;
584      case POST_CONNECT:
585        postConnectPlugins =
586            addPlugin(postConnectPlugins, plugin, t, pluginRootConfig
587                .getPluginOrderPostConnect());
588        break;
589      case POST_DISCONNECT:
590        postDisconnectPlugins =
591            addPlugin(postDisconnectPlugins, plugin, t,
592                pluginRootConfig.getPluginOrderPostDisconnect());
593        break;
594      case LDIF_IMPORT:
595        ldifImportPlugins =
596            addPlugin(ldifImportPlugins, plugin, t, pluginRootConfig
597                .getPluginOrderLDIFImport());
598        break;
599      case LDIF_IMPORT_END:
600        ldifImportEndPlugins =
601            addPlugin(ldifImportEndPlugins, plugin, t, pluginRootConfig
602                .getPluginOrderLDIFImportEnd());
603        break;
604      case LDIF_IMPORT_BEGIN:
605        ldifImportBeginPlugins =
606            addPlugin(ldifImportBeginPlugins, plugin, t,
607                pluginRootConfig.getPluginOrderLDIFImportBegin());
608        break;
609      case LDIF_EXPORT:
610        ldifExportPlugins =
611            addPlugin(ldifExportPlugins, plugin, t, pluginRootConfig
612                .getPluginOrderLDIFExport());
613        break;
614      case PRE_PARSE_ABANDON:
615        preParseAbandonPlugins =
616            addPlugin(preParseAbandonPlugins, plugin, t,
617                pluginRootConfig.getPluginOrderPreParseAbandon());
618        break;
619      case PRE_PARSE_ADD:
620        preParseAddPlugins =
621            addPlugin(preParseAddPlugins, plugin, t, pluginRootConfig
622                .getPluginOrderPreParseAdd());
623        break;
624      case PRE_PARSE_BIND:
625        preParseBindPlugins =
626            addPlugin(preParseBindPlugins, plugin, t, pluginRootConfig
627                .getPluginOrderPreParseBind());
628        break;
629      case PRE_PARSE_COMPARE:
630        preParseComparePlugins =
631            addPlugin(preParseComparePlugins, plugin, t,
632                pluginRootConfig.getPluginOrderPreParseCompare());
633        break;
634      case PRE_PARSE_DELETE:
635        preParseDeletePlugins =
636            addPlugin(preParseDeletePlugins, plugin, t,
637                pluginRootConfig.getPluginOrderPreParseDelete());
638        break;
639      case PRE_PARSE_EXTENDED:
640        preParseExtendedPlugins =
641            addPlugin(preParseExtendedPlugins, plugin, t,
642                pluginRootConfig.getPluginOrderPreParseExtended());
643        break;
644      case PRE_PARSE_MODIFY:
645        preParseModifyPlugins =
646            addPlugin(preParseModifyPlugins, plugin, t,
647                pluginRootConfig.getPluginOrderPreParseModify());
648        break;
649      case PRE_PARSE_MODIFY_DN:
650        preParseModifyDNPlugins =
651            addPlugin(preParseModifyDNPlugins, plugin, t,
652                pluginRootConfig.getPluginOrderPreParseModifyDN());
653        break;
654      case PRE_PARSE_SEARCH:
655        preParseSearchPlugins =
656            addPlugin(preParseSearchPlugins, plugin, t,
657                pluginRootConfig.getPluginOrderPreParseSearch());
658        break;
659      case PRE_PARSE_UNBIND:
660        preParseUnbindPlugins =
661            addPlugin(preParseUnbindPlugins, plugin, t,
662                pluginRootConfig.getPluginOrderPreParseUnbind());
663        break;
664      case PRE_OPERATION_ADD:
665        preOperationAddPlugins =
666            addPlugin(preOperationAddPlugins, plugin, t,
667                pluginRootConfig.getPluginOrderPreOperationAdd());
668        break;
669      case PRE_OPERATION_BIND:
670        preOperationBindPlugins =
671            addPlugin(preOperationBindPlugins, plugin, t,
672                pluginRootConfig.getPluginOrderPreOperationBind());
673        break;
674      case PRE_OPERATION_COMPARE:
675        preOperationComparePlugins =
676            addPlugin(preOperationComparePlugins, plugin, t,
677                pluginRootConfig.getPluginOrderPreOperationCompare());
678        break;
679      case PRE_OPERATION_DELETE:
680        preOperationDeletePlugins =
681            addPlugin(preOperationDeletePlugins, plugin, t,
682                pluginRootConfig.getPluginOrderPreOperationDelete());
683        break;
684      case PRE_OPERATION_EXTENDED:
685        preOperationExtendedPlugins =
686            addPlugin(preOperationExtendedPlugins, plugin, t,
687                pluginRootConfig.getPluginOrderPreOperationExtended());
688        break;
689      case PRE_OPERATION_MODIFY:
690        preOperationModifyPlugins =
691            addPlugin(preOperationModifyPlugins, plugin, t,
692                pluginRootConfig.getPluginOrderPreOperationModify());
693        break;
694      case PRE_OPERATION_MODIFY_DN:
695        preOperationModifyDNPlugins =
696            addPlugin(preOperationModifyDNPlugins, plugin, t,
697                pluginRootConfig.getPluginOrderPreOperationModifyDN());
698        break;
699      case PRE_OPERATION_SEARCH:
700        preOperationSearchPlugins =
701            addPlugin(preOperationSearchPlugins, plugin, t,
702                pluginRootConfig.getPluginOrderPreOperationSearch());
703        break;
704      case POST_OPERATION_ABANDON:
705        postOperationAbandonPlugins =
706            addPlugin(postOperationAbandonPlugins, plugin, t,
707                pluginRootConfig.getPluginOrderPostOperationAbandon());
708        break;
709      case POST_OPERATION_ADD:
710        postOperationAddPlugins =
711            addPlugin(postOperationAddPlugins, plugin, t,
712                pluginRootConfig.getPluginOrderPostOperationAdd());
713        break;
714      case POST_OPERATION_BIND:
715        postOperationBindPlugins =
716            addPlugin(postOperationBindPlugins, plugin, t,
717                pluginRootConfig.getPluginOrderPostOperationBind());
718        break;
719      case POST_OPERATION_COMPARE:
720        postOperationComparePlugins =
721            addPlugin(postOperationComparePlugins, plugin, t,
722                pluginRootConfig.getPluginOrderPostOperationCompare());
723        break;
724      case POST_OPERATION_DELETE:
725        postOperationDeletePlugins =
726            addPlugin(postOperationDeletePlugins, plugin, t,
727                pluginRootConfig.getPluginOrderPostOperationDelete());
728        break;
729      case POST_OPERATION_EXTENDED:
730        postOperationExtendedPlugins =
731            addPlugin(postOperationExtendedPlugins, plugin, t,
732                pluginRootConfig.getPluginOrderPostOperationExtended());
733        break;
734      case POST_OPERATION_MODIFY:
735        postOperationModifyPlugins =
736            addPlugin(postOperationModifyPlugins, plugin, t,
737                pluginRootConfig.getPluginOrderPostOperationModify());
738        break;
739      case POST_OPERATION_MODIFY_DN:
740        postOperationModifyDNPlugins =
741            addPlugin(postOperationModifyDNPlugins, plugin, t,
742                pluginRootConfig.getPluginOrderPostOperationModifyDN());
743        break;
744      case POST_OPERATION_SEARCH:
745        postOperationSearchPlugins =
746            addPlugin(postOperationSearchPlugins, plugin, t,
747                pluginRootConfig.getPluginOrderPostOperationSearch());
748        break;
749      case POST_OPERATION_UNBIND:
750        postOperationUnbindPlugins =
751            addPlugin(postOperationUnbindPlugins, plugin, t,
752                pluginRootConfig.getPluginOrderPostOperationUnbind());
753        break;
754      case POST_RESPONSE_ADD:
755        postResponseAddPlugins =
756            addPlugin(postResponseAddPlugins, plugin, t,
757                pluginRootConfig.getPluginOrderPostResponseAdd());
758        break;
759      case POST_RESPONSE_BIND:
760        postResponseBindPlugins =
761            addPlugin(postResponseBindPlugins, plugin, t,
762                pluginRootConfig.getPluginOrderPostResponseBind());
763        break;
764      case POST_RESPONSE_COMPARE:
765        postResponseComparePlugins =
766            addPlugin(postResponseComparePlugins, plugin, t,
767                pluginRootConfig.getPluginOrderPostResponseCompare());
768        break;
769      case POST_RESPONSE_DELETE:
770        postResponseDeletePlugins =
771            addPlugin(postResponseDeletePlugins, plugin, t,
772                pluginRootConfig.getPluginOrderPostResponseDelete());
773        break;
774      case POST_RESPONSE_EXTENDED:
775        postResponseExtendedPlugins =
776            addPlugin(postResponseExtendedPlugins, plugin, t,
777                pluginRootConfig.getPluginOrderPostResponseExtended());
778        break;
779      case POST_RESPONSE_MODIFY:
780        postResponseModifyPlugins =
781            addPlugin(postResponseModifyPlugins, plugin, t,
782                pluginRootConfig.getPluginOrderPostResponseModify());
783        break;
784      case POST_RESPONSE_MODIFY_DN:
785        postResponseModifyDNPlugins =
786            addPlugin(postResponseModifyDNPlugins, plugin, t,
787                pluginRootConfig.getPluginOrderPostResponseModifyDN());
788        break;
789      case POST_RESPONSE_SEARCH:
790        postResponseSearchPlugins =
791            addPlugin(postResponseSearchPlugins, plugin, t,
792                pluginRootConfig.getPluginOrderPostResponseSearch());
793        break;
794      case POST_SYNCHRONIZATION_ADD:
795        postSynchronizationAddPlugins =
796            addPlugin(postSynchronizationAddPlugins, plugin, t,
797                pluginRootConfig.getPluginOrderPostSynchronizationAdd());
798        break;
799      case POST_SYNCHRONIZATION_DELETE:
800        postSynchronizationDeletePlugins =
801            addPlugin(postSynchronizationDeletePlugins, plugin, t,
802                pluginRootConfig
803                    .getPluginOrderPostSynchronizationDelete());
804        break;
805      case POST_SYNCHRONIZATION_MODIFY:
806        postSynchronizationModifyPlugins =
807            addPlugin(postSynchronizationModifyPlugins, plugin, t,
808                pluginRootConfig
809                    .getPluginOrderPostSynchronizationModify());
810        break;
811      case POST_SYNCHRONIZATION_MODIFY_DN:
812        postSynchronizationModifyDNPlugins =
813            addPlugin(postSynchronizationModifyDNPlugins, plugin, t,
814                pluginRootConfig
815                    .getPluginOrderPostSynchronizationModifyDN());
816        break;
817      case SEARCH_RESULT_ENTRY:
818        searchResultEntryPlugins =
819            addPlugin(searchResultEntryPlugins, plugin, t,
820                pluginRootConfig.getPluginOrderSearchResultEntry());
821        break;
822      case SEARCH_RESULT_REFERENCE:
823        searchResultReferencePlugins =
824            addPlugin(searchResultReferencePlugins, plugin, t,
825                pluginRootConfig.getPluginOrderSearchResultReference());
826        break;
827      case SUBORDINATE_MODIFY_DN:
828        subordinateModifyDNPlugins =
829            addPlugin(subordinateModifyDNPlugins, plugin, t,
830                pluginRootConfig.getPluginOrderSubordinateModifyDN());
831        break;
832      case SUBORDINATE_DELETE:
833        subordinateDeletePlugins =
834            addPlugin(subordinateDeletePlugins, plugin, t,
835                pluginRootConfig.getPluginOrderSubordinateDelete());
836        break;
837      case INTERMEDIATE_RESPONSE:
838        intermediateResponsePlugins =
839            addPlugin(intermediateResponsePlugins, plugin, t,
840                pluginRootConfig.getPluginOrderIntermediateResponse());
841        break;
842      default:
843      }
844    }
845  }
846
847
848
849  /**
850   * Registers the provided plugin with this plugin config manager and
851   * ensures that it will be invoked in the specified ways.
852   *
853   * @param plugin
854   *          The plugin to register with the server.
855   * @param pluginEntryDN
856   *          The DN of the configuration entry for the provided plugin.
857   * @param pluginTypes
858   *          The plugin types that will be used to control the points
859   *          at which the provided plugin is invoked.
860   */
861  private void registerPlugin(
862      DirectoryServerPlugin<? extends PluginCfg> plugin,
863      DN pluginEntryDN, Set<PluginType> pluginTypes)
864  {
865    pluginLock.lock();
866    try
867    {
868      registeredPlugins.put(pluginEntryDN, plugin);
869      registerPlugin0(plugin, pluginTypes);
870    }
871    finally
872    {
873      pluginLock.unlock();
874    }
875  }
876
877
878
879  /**
880   * Adds the provided plugin to the given array.  The provided array will not
881   * itself be modified, but rather a new array will be created with one
882   * additional element.  The provided plugin will be the last element in the
883   * new array.
884   * <BR><BR>
885   * Note that the only use of this method outside of this class should be for
886   * testing purposes.
887   *
888   * @param  pluginArray  The array containing the existing set of plugins.
889   * @param  plugin       The plugin to be added to the array.
890   * @param  pluginType   The plugin type for the plugin being registered.
891   * @param  pluginOrder  A string that represents the order in which plugins of
892   *                      this type should be invoked, or {@code null} if the
893   *                      order is not considered important.
894   *
895   * @return  The new array containing the new set of plugins.
896   */
897  static DirectoryServerPlugin[] addPlugin(DirectoryServerPlugin[] pluginArray,
898                                           DirectoryServerPlugin plugin,
899                                           PluginType pluginType,
900                                           String pluginOrder)
901  {
902    // If the provided plugin order string is null, empty, or contains only a
903    // wildcard, then simply add the new plugin to the end of the list.
904    // Otherwise, parse the order string and figure out where to put the
905    // provided plugin.
906    if (pluginOrder == null
907        || (pluginOrder = pluginOrder.trim()).length() == 0
908        || pluginOrder.equals("*"))
909    {
910      DirectoryServerPlugin[] newPlugins =
911           new DirectoryServerPlugin[pluginArray.length+1];
912      System.arraycopy(pluginArray, 0, newPlugins, 0, pluginArray.length);
913      newPlugins[pluginArray.length] = plugin;
914
915      return newPlugins;
916    }
917    else
918    {
919      // Parse the plugin order into initial and final plugin names.
920      boolean starFound = false;
921      LinkedHashSet<String> initialPluginNames = new LinkedHashSet<>();
922      LinkedHashSet<String> finalPluginNames   = new LinkedHashSet<>();
923
924      StringTokenizer tokenizer = new StringTokenizer(pluginOrder, ",");
925      while (tokenizer.hasMoreTokens())
926      {
927        String token = tokenizer.nextToken().trim();
928        if (token.length() == 0)
929        {
930          // Only log the warning once per plugin type.  The plugin array will
931          // be empty the first time through, so we can use that to make the
932          // determination.
933          if (pluginArray.length == 0)
934          {
935            logger.warn(WARN_CONFIG_PLUGIN_EMPTY_ELEMENT_IN_ORDER, pluginType.getName());
936          }
937        }
938        else if (token.equals("*"))
939        {
940          if (starFound)
941          {
942            // Only log the warning once per plugin type.  The plugin array will
943            // be empty the first time through, so we can use that to make the
944            // determination.
945            if (pluginArray.length == 0)
946            {
947              logger.warn(WARN_CONFIG_PLUGIN_MULTIPLE_WILDCARDS_IN_ORDER, pluginType.getName());
948            }
949          }
950          else
951          {
952            starFound = true;
953          }
954        }
955        else
956        {
957          String lowerName = toLowerCase(token);
958          if (starFound)
959          {
960            if (initialPluginNames.contains(lowerName) ||
961                finalPluginNames.contains(lowerName))
962            {
963              // Only log the warning once per plugin type.  The plugin array
964              // will be empty the first time through, so we can use that to
965              // make the determination.
966              if (pluginArray.length == 0)
967              {
968                logger.warn(WARN_CONFIG_PLUGIN_LISTED_MULTIPLE_TIMES,
969                    pluginType.getName(), token);
970              }
971            }
972
973            finalPluginNames.add(lowerName);
974          }
975          else
976          {
977            if (initialPluginNames.contains(lowerName))
978            {
979              // Only log the warning once per plugin type.  The plugin array
980              // will be empty the first time through, so we can use that to
981              // make the determination.
982              if (pluginArray.length == 0)
983              {
984                logger.warn(WARN_CONFIG_PLUGIN_LISTED_MULTIPLE_TIMES,
985                    pluginType.getName(), token);
986              }
987            }
988
989            initialPluginNames.add(lowerName);
990          }
991        }
992      }
993
994      if (! starFound)
995      {
996        // Only log the warning once per plugin type.  The plugin array will be
997        // empty the first time through, so we can use that to make the
998        // determination.
999        if (pluginArray.length == 0)
1000        {
1001          logger.warn(WARN_CONFIG_PLUGIN_ORDER_NO_WILDCARD, pluginType.getName());
1002        }
1003      }
1004
1005
1006      // Parse the array of already registered plugins to sort them accordingly.
1007      HashMap<String,DirectoryServerPlugin> initialPlugins = new HashMap<>(initialPluginNames.size());
1008      HashMap<String,DirectoryServerPlugin> finalPlugins = new HashMap<>(finalPluginNames.size());
1009      ArrayList<DirectoryServerPlugin> otherPlugins = new ArrayList<>();
1010      for (DirectoryServerPlugin p : pluginArray)
1011      {
1012        DN dn = p.getPluginEntryDN();
1013        String lowerName = toLowerCase(dn.rdn().getAttributeValue(0).toString());
1014        if (initialPluginNames.contains(lowerName))
1015        {
1016          initialPlugins.put(lowerName, p);
1017        }
1018        else if (finalPluginNames.contains(lowerName))
1019        {
1020          finalPlugins.put(lowerName, p);
1021        }
1022        else
1023        {
1024          otherPlugins.add(p);
1025        }
1026      }
1027
1028
1029      // Get the name of the provided plugin from its RDN value and put it in
1030      // the correct category.
1031      DN dn = plugin.getPluginEntryDN();
1032      String lowerName = toLowerCase(dn.rdn().getAttributeValue(0).toString());
1033      if (initialPluginNames.contains(lowerName))
1034      {
1035        initialPlugins.put(lowerName, plugin);
1036      }
1037      else if (finalPluginNames.contains(lowerName))
1038      {
1039        finalPlugins.put(lowerName, plugin);
1040      }
1041      else
1042      {
1043        otherPlugins.add(plugin);
1044      }
1045
1046
1047      // Compile a list of all the plugins in the correct order, convert it to
1048      // an array, and return it.
1049      ArrayList<DirectoryServerPlugin> newList = new ArrayList<>(pluginArray.length + 1);
1050      for (String name : initialPluginNames)
1051      {
1052        DirectoryServerPlugin p = initialPlugins.get(name);
1053        if (p != null)
1054        {
1055          newList.add(p);
1056        }
1057      }
1058
1059      newList.addAll(otherPlugins);
1060
1061      for (String name : finalPluginNames)
1062      {
1063        DirectoryServerPlugin p = finalPlugins.get(name);
1064        if (p != null)
1065        {
1066          newList.add(p);
1067        }
1068      }
1069
1070      DirectoryServerPlugin[] newPlugins =
1071           new DirectoryServerPlugin[newList.size()];
1072      newList.toArray(newPlugins);
1073      return newPlugins;
1074    }
1075  }
1076
1077
1078
1079  /**
1080   * Deregisters the provided internal plugin.
1081   *
1082   * @param plugin
1083   *          The internal plugin to deregister from the server.
1084   */
1085  void deregisterInternalPlugin(InternalDirectoryServerPlugin plugin)
1086  {
1087    pluginLock.lock();
1088    try
1089    {
1090      deregisterPlugin0(plugin);
1091      plugin.finalizePlugin();
1092    }
1093    finally
1094    {
1095      pluginLock.unlock();
1096    }
1097  }
1098
1099
1100
1101  /**
1102   * Deregisters the plugin with the provided configuration entry DN.
1103   *
1104   * @param configEntryDN
1105   *          The DN of the configuration entry for the plugin to
1106   *          deregister.
1107   */
1108  private void deregisterPlugin(DN configEntryDN)
1109  {
1110    pluginLock.lock();
1111    DirectoryServerPlugin<? extends PluginCfg> plugin;
1112    try
1113    {
1114      plugin = registeredPlugins.remove(configEntryDN);
1115      if (plugin != null)
1116      {
1117        deregisterPlugin0(plugin);
1118        plugin.finalizePlugin();
1119      }
1120    }
1121    finally
1122    {
1123      pluginLock.unlock();
1124    }
1125  }
1126
1127
1128
1129  /**
1130   * Deregisters the provided plugin.
1131   *
1132   * @param plugin
1133   *          The plugin to deregister from the server.
1134   */
1135  private void deregisterPlugin0(
1136      DirectoryServerPlugin<? extends PluginCfg> plugin)
1137  {
1138    for (PluginType t : plugin.getPluginTypes())
1139    {
1140      switch (t)
1141      {
1142        case STARTUP:
1143          startupPlugins = removePlugin(startupPlugins, plugin);
1144          break;
1145        case SHUTDOWN:
1146          shutdownPlugins = removePlugin(shutdownPlugins, plugin);
1147          break;
1148        case POST_CONNECT:
1149          postConnectPlugins = removePlugin(postConnectPlugins, plugin);
1150          break;
1151        case POST_DISCONNECT:
1152          postDisconnectPlugins = removePlugin(postDisconnectPlugins, plugin);
1153          break;
1154        case LDIF_IMPORT:
1155          ldifImportPlugins = removePlugin(ldifImportPlugins, plugin);
1156          break;
1157        case LDIF_IMPORT_END:
1158          ldifImportEndPlugins = removePlugin(ldifImportEndPlugins, plugin);
1159          break;
1160        case LDIF_IMPORT_BEGIN:
1161          ldifImportBeginPlugins =
1162            removePlugin(ldifImportBeginPlugins, plugin);
1163          break;
1164        case LDIF_EXPORT:
1165          ldifExportPlugins = removePlugin(ldifExportPlugins, plugin);
1166          break;
1167        case PRE_PARSE_ABANDON:
1168          preParseAbandonPlugins = removePlugin(preParseAbandonPlugins,
1169                                                plugin);
1170          break;
1171        case PRE_PARSE_ADD:
1172          preParseAddPlugins = removePlugin(preParseAddPlugins, plugin);
1173          break;
1174        case PRE_PARSE_BIND:
1175          preParseBindPlugins = removePlugin(preParseBindPlugins, plugin);
1176          break;
1177        case PRE_PARSE_COMPARE:
1178          preParseComparePlugins = removePlugin(preParseComparePlugins,
1179                                                plugin);
1180          break;
1181        case PRE_PARSE_DELETE:
1182          preParseDeletePlugins = removePlugin(preParseDeletePlugins, plugin);
1183          break;
1184        case PRE_PARSE_EXTENDED:
1185          preParseExtendedPlugins = removePlugin(preParseExtendedPlugins,
1186                                                 plugin);
1187          break;
1188        case PRE_PARSE_MODIFY:
1189          preParseModifyPlugins = removePlugin(preParseModifyPlugins, plugin);
1190          break;
1191        case PRE_PARSE_MODIFY_DN:
1192          preParseModifyDNPlugins = removePlugin(preParseModifyDNPlugins,
1193                                                 plugin);
1194          break;
1195        case PRE_PARSE_SEARCH:
1196          preParseSearchPlugins = removePlugin(preParseSearchPlugins, plugin);
1197          break;
1198        case PRE_PARSE_UNBIND:
1199          preParseUnbindPlugins = removePlugin(preParseUnbindPlugins, plugin);
1200          break;
1201        case PRE_OPERATION_ADD:
1202          preOperationAddPlugins = removePlugin(preOperationAddPlugins,
1203                                                plugin);
1204          break;
1205        case PRE_OPERATION_BIND:
1206          preOperationBindPlugins = removePlugin(preOperationBindPlugins,
1207                                                 plugin);
1208          break;
1209        case PRE_OPERATION_COMPARE:
1210          preOperationComparePlugins =
1211               removePlugin(preOperationComparePlugins, plugin);
1212          break;
1213        case PRE_OPERATION_DELETE:
1214          preOperationDeletePlugins = removePlugin(preOperationDeletePlugins,
1215                                                   plugin);
1216          break;
1217        case PRE_OPERATION_EXTENDED:
1218          preOperationExtendedPlugins =
1219               removePlugin(preOperationExtendedPlugins, plugin);
1220          break;
1221        case PRE_OPERATION_MODIFY:
1222          preOperationModifyPlugins = removePlugin(preOperationModifyPlugins,
1223                                                   plugin);
1224          break;
1225        case PRE_OPERATION_MODIFY_DN:
1226          preOperationModifyDNPlugins =
1227               removePlugin(preOperationModifyDNPlugins, plugin);
1228          break;
1229        case PRE_OPERATION_SEARCH:
1230          preOperationSearchPlugins = removePlugin(preOperationSearchPlugins,
1231                                                   plugin);
1232          break;
1233        case POST_OPERATION_ABANDON:
1234          postOperationAbandonPlugins =
1235               removePlugin(postOperationAbandonPlugins, plugin);
1236          break;
1237        case POST_OPERATION_ADD:
1238          postOperationAddPlugins = removePlugin(postOperationAddPlugins,
1239                                                 plugin);
1240          break;
1241        case POST_OPERATION_BIND:
1242          postOperationBindPlugins = removePlugin(postOperationBindPlugins,
1243                                                  plugin);
1244          break;
1245        case POST_OPERATION_COMPARE:
1246          postOperationComparePlugins =
1247               removePlugin(postOperationComparePlugins, plugin);
1248          break;
1249        case POST_OPERATION_DELETE:
1250          postOperationDeletePlugins =
1251               removePlugin(postOperationDeletePlugins, plugin);
1252          break;
1253        case POST_OPERATION_EXTENDED:
1254          postOperationExtendedPlugins =
1255               removePlugin(postOperationExtendedPlugins, plugin);
1256          break;
1257        case POST_OPERATION_MODIFY:
1258          postOperationModifyPlugins =
1259               removePlugin(postOperationModifyPlugins, plugin);
1260          break;
1261        case POST_OPERATION_MODIFY_DN:
1262          postOperationModifyDNPlugins =
1263               removePlugin(postOperationModifyDNPlugins, plugin);
1264          break;
1265        case POST_OPERATION_SEARCH:
1266          postOperationSearchPlugins =
1267               removePlugin(postOperationSearchPlugins, plugin);
1268          break;
1269        case POST_OPERATION_UNBIND:
1270          postOperationUnbindPlugins =
1271               removePlugin(postOperationUnbindPlugins, plugin);
1272          break;
1273        case POST_RESPONSE_ADD:
1274          postResponseAddPlugins = removePlugin(postResponseAddPlugins,
1275                                                plugin);
1276          break;
1277        case POST_RESPONSE_BIND:
1278          postResponseBindPlugins = removePlugin(postResponseBindPlugins,
1279                                                 plugin);
1280          break;
1281        case POST_RESPONSE_COMPARE:
1282          postResponseComparePlugins =
1283               removePlugin(postResponseComparePlugins, plugin);
1284          break;
1285        case POST_RESPONSE_DELETE:
1286          postResponseDeletePlugins = removePlugin(postResponseDeletePlugins,
1287                                                   plugin);
1288          break;
1289        case POST_RESPONSE_EXTENDED:
1290          postResponseExtendedPlugins =
1291               removePlugin(postResponseExtendedPlugins, plugin);
1292          break;
1293        case POST_RESPONSE_MODIFY:
1294          postResponseModifyPlugins = removePlugin(postResponseModifyPlugins,
1295                                                   plugin);
1296          break;
1297        case POST_RESPONSE_MODIFY_DN:
1298          postResponseModifyDNPlugins =
1299               removePlugin(postResponseModifyDNPlugins, plugin);
1300          break;
1301        case POST_RESPONSE_SEARCH:
1302          postResponseSearchPlugins = removePlugin(postResponseSearchPlugins,
1303                                                   plugin);
1304          break;
1305        case POST_SYNCHRONIZATION_ADD:
1306          postSynchronizationAddPlugins =
1307               removePlugin(postSynchronizationAddPlugins, plugin);
1308          break;
1309        case POST_SYNCHRONIZATION_DELETE:
1310          postSynchronizationDeletePlugins =
1311               removePlugin(postSynchronizationDeletePlugins, plugin);
1312          break;
1313        case POST_SYNCHRONIZATION_MODIFY:
1314          postSynchronizationModifyPlugins =
1315               removePlugin(postSynchronizationModifyPlugins, plugin);
1316          break;
1317        case POST_SYNCHRONIZATION_MODIFY_DN:
1318          postSynchronizationModifyDNPlugins =
1319               removePlugin(postSynchronizationModifyDNPlugins, plugin);
1320          break;
1321        case SEARCH_RESULT_ENTRY:
1322          searchResultEntryPlugins = removePlugin(searchResultEntryPlugins,
1323                                                  plugin);
1324          break;
1325        case SEARCH_RESULT_REFERENCE:
1326          searchResultReferencePlugins =
1327               removePlugin(searchResultReferencePlugins, plugin);
1328          break;
1329        case SUBORDINATE_MODIFY_DN:
1330          subordinateModifyDNPlugins =
1331               removePlugin(subordinateModifyDNPlugins, plugin);
1332          break;
1333        case SUBORDINATE_DELETE:
1334          subordinateDeletePlugins =
1335               removePlugin(subordinateDeletePlugins, plugin);
1336          break;
1337        case INTERMEDIATE_RESPONSE:
1338          intermediateResponsePlugins =
1339               removePlugin(intermediateResponsePlugins, plugin);
1340          break;
1341        default:
1342      }
1343    }
1344  }
1345
1346
1347
1348  /**
1349   * Removes the provided plugin from the given array.  The provided array will
1350   * not itself be modified, but rather a new array will be created with one
1351   * fewer element (assuming that the specified plugin was found).
1352   *
1353   * @param  pluginArray  The array containing the existing set of plugins.
1354   * @param  plugin       The plugin to be removed from the array.
1355   *
1356   * @return  The new array containing the new set of plugins.
1357   */
1358  private DirectoryServerPlugin[]
1359               removePlugin(DirectoryServerPlugin[] pluginArray,
1360                            DirectoryServerPlugin plugin)
1361  {
1362    int slot   = -1;
1363    int length = pluginArray.length;
1364    for (int i=0; i < length; i++)
1365    {
1366      if (pluginArray[i].getPluginEntryDN().equals(plugin.getPluginEntryDN()))
1367      {
1368        slot = i;
1369        break;
1370      }
1371    }
1372
1373    if (slot < 0)
1374    {
1375      // The plugin wasn't found in the list, so return the same list.
1376      return pluginArray;
1377    }
1378
1379
1380    // If it was the only element in the array, then return an empty array.
1381    if (length == 0)
1382    {
1383      return new DirectoryServerPlugin[0];
1384    }
1385
1386
1387    // Create an array that's one element smaller and copy the remaining "good"
1388    // elements into it.
1389    DirectoryServerPlugin[] newPlugins = new DirectoryServerPlugin[length-1];
1390    if (slot > 0)
1391    {
1392      System.arraycopy(pluginArray, 0, newPlugins, 0, slot);
1393    }
1394
1395    if (slot < length-1)
1396    {
1397      System.arraycopy(pluginArray, slot+1, newPlugins, slot, length-slot-1);
1398    }
1399
1400    return newPlugins;
1401  }
1402
1403
1404
1405  /**
1406   * Invokes the set of startup plugins that have been registered with the
1407   * Directory Server.
1408   *
1409   * @return  The result of processing the startup plugins.
1410   */
1411  public PluginResult.Startup invokeStartupPlugins()
1412  {
1413    PluginResult.Startup result = null;
1414
1415    for (DirectoryServerPlugin p : startupPlugins)
1416    {
1417      try
1418      {
1419        result = p.doStartup();
1420      }
1421      catch (Exception e)
1422      {
1423        logger.traceException(e);
1424
1425        LocalizableMessage message = ERR_PLUGIN_STARTUP_PLUGIN_EXCEPTION.get(
1426                p.getPluginEntryDN(), stackTraceToSingleLineString(e));
1427        return PluginResult.Startup.stopStartup(message);
1428      }
1429
1430      if (result == null)
1431      {
1432        LocalizableMessage message = ERR_PLUGIN_STARTUP_PLUGIN_RETURNED_NULL.get(p.getPluginEntryDN());
1433        logger.error(message);
1434        return PluginResult.Startup.stopStartup(message);
1435      }
1436      else if (! result.continueProcessing())
1437      {
1438        logger.error(ERR_PLUGIN_STARTUP_PLUGIN_FAIL_ABORT,
1439                p.getPluginEntryDN(),
1440                result.getErrorMessage(),
1441                result.getErrorMessage().ordinal());
1442        return result;
1443      }
1444    }
1445
1446    if (result == null)
1447    {
1448      // This should only happen if there were no startup plugins registered,
1449      // which is fine.
1450      result = PluginResult.Startup.continueStartup();
1451    }
1452
1453    return result;
1454  }
1455
1456
1457
1458  /**
1459   * Invokes the set of shutdown plugins that have been configured in the
1460   * Directory Server.
1461   *
1462   * @param  reason  The human-readable reason for the shutdown.
1463   */
1464  public void invokeShutdownPlugins(LocalizableMessage reason)
1465  {
1466    for (DirectoryServerPlugin p : shutdownPlugins)
1467    {
1468      try
1469      {
1470        p.doShutdown(reason);
1471      }
1472      catch (Exception e)
1473      {
1474        logger.traceException(e);
1475        logger.error(ERR_PLUGIN_SHUTDOWN_PLUGIN_EXCEPTION, p.getPluginEntryDN(), stackTraceToSingleLineString(e));
1476      }
1477    }
1478  }
1479
1480
1481
1482  /**
1483   * Invokes the set of post-connect plugins that have been configured in the
1484   * Directory Server.
1485   *
1486   * @param  clientConnection  The client connection that has been established.
1487   *
1488   * @return  The result of processing the post-connect plugins.
1489   */
1490  public PluginResult.PostConnect invokePostConnectPlugins(ClientConnection
1491                                                           clientConnection)
1492  {
1493    PluginResult.PostConnect result = null;
1494
1495    for (DirectoryServerPlugin p : postConnectPlugins)
1496    {
1497      try
1498      {
1499        result = p.doPostConnect(clientConnection);
1500      }
1501      catch (Exception e)
1502      {
1503        logger.traceException(e);
1504
1505        LocalizableMessage message = ERR_PLUGIN_POST_CONNECT_PLUGIN_EXCEPTION.
1506            get(p.getPluginEntryDN(),
1507                clientConnection.getConnectionID(),
1508                clientConnection.getClientAddress(),
1509                stackTraceToSingleLineString(e));
1510        logger.error(message);
1511
1512        return PluginResult.PostConnect.disconnectClient(
1513            DisconnectReason.SERVER_ERROR, true, message);
1514      }
1515
1516
1517      if (result == null)
1518      {
1519        LocalizableMessage message = ERR_PLUGIN_POST_CONNECT_PLUGIN_RETURNED_NULL.
1520            get(p.getPluginEntryDN(), clientConnection.getConnectionID(), clientConnection.getClientAddress());
1521        logger.error(message);
1522
1523        return PluginResult.PostConnect.disconnectClient(
1524            DisconnectReason.SERVER_ERROR, true, message);
1525      }
1526      else if (!result.continuePluginProcessing())
1527      {
1528        return result;
1529      }
1530    }
1531
1532    if (result == null)
1533    {
1534      // This should only happen if there were no post-connect plugins
1535      // registered, which is fine.
1536      result = PluginResult.PostConnect.continueConnectProcessing();
1537    }
1538
1539    return result;
1540  }
1541
1542
1543
1544  /**
1545   * Invokes the set of post-disconnect plugins that have been configured in the
1546   * Directory Server.
1547   *
1548   * @param  clientConnection  The client connection that has been closed.
1549   * @param  disconnectReason  The general reason that the connection was
1550   *                           closed.
1551   * @param  message           A human-readable message that may provide
1552   *                           additional information about the closure.
1553   *
1554   * @return  The result of processing the post-connect plugins.
1555   */
1556  public PluginResult.PostDisconnect invokePostDisconnectPlugins(
1557                                        ClientConnection clientConnection,
1558                                        DisconnectReason disconnectReason,
1559                                        LocalizableMessage message)
1560  {
1561    PluginResult.PostDisconnect result = null;
1562
1563    for (DirectoryServerPlugin p : postDisconnectPlugins)
1564    {
1565      try
1566      {
1567        result = p.doPostDisconnect(clientConnection, disconnectReason,
1568                message);
1569      }
1570      catch (Exception e)
1571      {
1572        logger.traceException(e);
1573        logger.error(ERR_PLUGIN_POST_DISCONNECT_PLUGIN_EXCEPTION,
1574                p.getPluginEntryDN(),
1575                clientConnection.getConnectionID(),
1576                clientConnection.getClientAddress(),
1577                stackTraceToSingleLineString(e));
1578      }
1579
1580
1581      if (result == null)
1582      {
1583        logger.error(ERR_PLUGIN_POST_DISCONNECT_PLUGIN_RETURNED_NULL,
1584                p.getPluginEntryDN(),
1585                clientConnection.getConnectionID(),
1586                clientConnection.getClientAddress());
1587      }
1588      else if (! result.continuePluginProcessing())
1589      {
1590        return result;
1591      }
1592    }
1593
1594    if (result == null)
1595    {
1596      // This should only happen if there were no post-disconnect plugins
1597      // registered, which is fine.
1598      result = PluginResult.PostDisconnect.continueDisconnectProcessing();
1599    }
1600
1601    return result;
1602  }
1603
1604
1605
1606  /**
1607   * Invokes the set of LDIF import plugins that have been configured in the
1608   * Directory Server.
1609   *
1610   * @param  importConfig  The LDIF import configuration used to read the
1611   *                       associated entry.
1612   * @param  entry         The entry that has been read from LDIF.
1613   *
1614   * @return  The result of processing the LDIF import plugins.
1615   */
1616  public PluginResult.ImportLDIF invokeLDIFImportPlugins(
1617      LDIFImportConfig importConfig, Entry entry)
1618  {
1619    PluginResult.ImportLDIF result = null;
1620
1621    for (DirectoryServerPlugin p : ldifImportPlugins)
1622    {
1623      try
1624      {
1625        result = p.doLDIFImport(importConfig, entry);
1626      }
1627      catch (Exception e)
1628      {
1629        logger.traceException(e);
1630
1631        LocalizableMessage message = ERR_PLUGIN_LDIF_IMPORT_PLUGIN_EXCEPTION.get(
1632            p.getPluginEntryDN(), entry.getName(), stackTraceToSingleLineString(e));
1633        logger.error(message);
1634
1635        return PluginResult.ImportLDIF.stopEntryProcessing(message);
1636      }
1637
1638      if (result == null)
1639      {
1640        LocalizableMessage message = ERR_PLUGIN_LDIF_IMPORT_PLUGIN_RETURNED_NULL.
1641            get(p.getPluginEntryDN(), entry.getName());
1642        logger.error(message);
1643
1644        return PluginResult.ImportLDIF.stopEntryProcessing(message);
1645      }
1646      else if (! result.continuePluginProcessing())
1647      {
1648        return result;
1649      }
1650    }
1651
1652    if (result == null)
1653    {
1654      // This should only happen if there were no LDIF import plugins
1655      // registered, which is fine.
1656      result = PluginResult.ImportLDIF.continueEntryProcessing();
1657    }
1658
1659    return result;
1660  }
1661
1662
1663
1664  /**
1665   * Invokes the LDIF import session finalization of LDIF import plugins that
1666   * have been configured in the Directory Server.
1667   *
1668   * @param  importConfig  The LDIF import configuration used for the LDIF
1669   *                       import session.
1670   */
1671  public void invokeLDIFImportEndPlugins(
1672      LDIFImportConfig importConfig)
1673  {
1674    for (DirectoryServerPlugin p : ldifImportEndPlugins)
1675    {
1676      p.doLDIFImportEnd(importConfig);
1677    }
1678  }
1679
1680
1681
1682  /**
1683   * Invokes the LDIF import session initialization of LDIF import plugins that
1684   * have been configured in the Directory Server.
1685   *
1686   * @param  importConfig  The LDIF import configuration used for the LDIF
1687   *                       import session.
1688   */
1689  public void invokeLDIFImportBeginPlugins(
1690      LDIFImportConfig importConfig)
1691  {
1692    for (DirectoryServerPlugin p : ldifImportBeginPlugins)
1693    {
1694      p.doLDIFImportBegin(importConfig);
1695    }
1696  }
1697
1698
1699
1700  /**
1701   * Invokes the set of LDIF export plugins that have been configured in the
1702   * Directory Server.
1703   *
1704   * @param  exportConfig  The LDIF export configuration used to read the
1705   *                       associated entry.
1706   * @param  entry         The entry that has been read from LDIF.
1707   *
1708   * @return  The result of processing the LDIF export plugins.
1709   */
1710  public PluginResult.ImportLDIF invokeLDIFExportPlugins(
1711      LDIFExportConfig exportConfig, Entry entry)
1712  {
1713    PluginResult.ImportLDIF result = null;
1714
1715    for (DirectoryServerPlugin p : ldifExportPlugins)
1716    {
1717      try
1718      {
1719        result = p.doLDIFExport(exportConfig, entry);
1720      }
1721      catch (Exception e)
1722      {
1723        logger.traceException(e);
1724
1725        LocalizableMessage message = ERR_PLUGIN_LDIF_EXPORT_PLUGIN_EXCEPTION.
1726            get(p.getPluginEntryDN(),
1727                entry.getName(),
1728                stackTraceToSingleLineString(e));
1729        logger.error(message);
1730
1731        return PluginResult.ImportLDIF.stopEntryProcessing(message);
1732      }
1733
1734      if (result == null)
1735      {
1736        LocalizableMessage message = ERR_PLUGIN_LDIF_EXPORT_PLUGIN_RETURNED_NULL.
1737            get(p.getPluginEntryDN(), entry.getName());
1738        logger.error(message);
1739
1740        return PluginResult.ImportLDIF.stopEntryProcessing(message);
1741      }
1742      else if (! result.continuePluginProcessing())
1743      {
1744        return result;
1745      }
1746    }
1747
1748    if (result == null)
1749    {
1750      // This should only happen if there were no LDIF export plugins
1751      // registered, which is fine.
1752      result = PluginResult.ImportLDIF.continueEntryProcessing();
1753    }
1754
1755    return result;
1756  }
1757
1758
1759
1760  /**
1761   * Invokes the set of pre-parse abandon plugins that have been configured in
1762   * the Directory Server.
1763   *
1764   * @param  abandonOperation  The abandon operation for which to invoke the
1765   *                           pre-parse plugins.
1766   *
1767   * @return  The result of processing the pre-parse abandon plugins.
1768   */
1769  public PluginResult.PreParse invokePreParseAbandonPlugins(
1770                                   PreParseAbandonOperation abandonOperation)
1771  {
1772    PluginResult.PreParse result = null;
1773
1774    for (DirectoryServerPlugin p : preParseAbandonPlugins)
1775    {
1776      if (isInternalOperation(abandonOperation, p))
1777      {
1778        continue;
1779      }
1780
1781      try
1782      {
1783        result = p.doPreParse(abandonOperation);
1784      }
1785      catch (Exception e)
1786      {
1787        return handlePreParseException(e, abandonOperation, p);
1788      }
1789
1790      if (result == null)
1791      {
1792        return handlePreParseResult(abandonOperation, p);
1793      }
1794      else if (!result.continuePluginProcessing())
1795      {
1796        return result;
1797      }
1798    }
1799
1800    if (result == null)
1801    {
1802      // This should only happen if there were no pre-parse abandon plugins
1803      // registered, which is fine.
1804      result = PluginResult.PreParse.continueOperationProcessing();
1805    }
1806
1807    return result;
1808  }
1809
1810
1811  private PluginResult.PreParse handlePreParseException(
1812      Exception e, PreParseOperation operation, DirectoryServerPlugin plugin)
1813  {
1814    logger.traceException(e);
1815
1816    LocalizableMessage message =
1817        ERR_PLUGIN_PRE_PARSE_PLUGIN_EXCEPTION.get(operation.getOperationType()
1818            .getOperationName(), plugin.getPluginEntryDN(),
1819            operation.getConnectionID(), operation.getOperationID(),
1820            stackTraceToSingleLineString(e));
1821    logger.error(message);
1822
1823    return PluginResult.PreParse.stopProcessing(DirectoryServer
1824        .getServerErrorResultCode(), message);
1825  }
1826
1827  private PluginResult.PreParse handlePreParseResult(
1828      PreParseOperation operation, DirectoryServerPlugin plugin)
1829  {
1830    LocalizableMessage message =
1831        ERR_PLUGIN_PRE_PARSE_PLUGIN_RETURNED_NULL.get(operation
1832            .getOperationType().getOperationName(), plugin
1833            .getPluginEntryDN(), operation.getConnectionID(), operation.getOperationID());
1834    logger.error(message);
1835
1836    return PluginResult.PreParse.stopProcessing(DirectoryServer
1837        .getServerErrorResultCode(), message);
1838  }
1839
1840
1841  /**
1842   * Invokes the set of pre-parse add plugins that have been configured in the
1843   * Directory Server.
1844   *
1845   * @param  addOperation  The add operation for which to invoke the pre-parse
1846   *                       plugins.
1847   *
1848   * @return  The result of processing the pre-parse add plugins.
1849   *
1850   * @throws CanceledOperationException if the operation should be canceled.
1851   */
1852  public PluginResult.PreParse invokePreParseAddPlugins(
1853      PreParseAddOperation addOperation)
1854      throws CanceledOperationException {
1855    PluginResult.PreParse result = null;
1856
1857    for (DirectoryServerPlugin p : preParseAddPlugins)
1858    {
1859      if (isInternalOperation(addOperation, p))
1860      {
1861        continue;
1862      }
1863
1864      try
1865      {
1866        result = p.doPreParse(addOperation);
1867      }
1868      catch (CanceledOperationException coe)
1869      {
1870        throw coe;
1871      }
1872      catch (Exception e)
1873      {
1874        return handlePreParseException(e, addOperation, p);
1875      }
1876
1877      if (result == null)
1878      {
1879        return handlePreParseResult(addOperation, p);
1880      }
1881      else if (!result.continuePluginProcessing())
1882      {
1883        return result;
1884      }
1885    }
1886
1887    if (result == null)
1888    {
1889      // This should only happen if there were no pre-parse add plugins
1890      // registered, which is fine.
1891      result = PluginResult.PreParse.continueOperationProcessing();
1892    }
1893
1894    return result;
1895  }
1896
1897
1898
1899  /**
1900   * Invokes the set of pre-parse bind plugins that have been configured in
1901   * the Directory Server.
1902   *
1903   * @param  bindOperation  The bind operation for which to invoke the pre-parse
1904   *                        plugins.
1905   *
1906   * @return  The result of processing the pre-parse bind plugins.
1907   */
1908  public PluginResult.PreParse invokePreParseBindPlugins(
1909                                   PreParseBindOperation bindOperation)
1910  {
1911    PluginResult.PreParse result = null;
1912
1913    for (DirectoryServerPlugin p : preParseBindPlugins)
1914    {
1915      if (isInternalOperation(bindOperation, p))
1916      {
1917        continue;
1918      }
1919
1920      try
1921      {
1922        result = p.doPreParse(bindOperation);
1923      }
1924      catch (Exception e)
1925      {
1926        return handlePreParseException(e, bindOperation, p);
1927      }
1928
1929      if (result == null)
1930      {
1931        return handlePreParseResult(bindOperation, p);
1932      }
1933      else if (!result.continuePluginProcessing())
1934      {
1935        return result;
1936      }
1937    }
1938
1939    if (result == null)
1940    {
1941      // This should only happen if there were no pre-parse bind plugins
1942      // registered, which is fine.
1943      result = PluginResult.PreParse.continueOperationProcessing();
1944    }
1945
1946    return result;
1947  }
1948
1949
1950
1951  /**
1952   * Invokes the set of pre-parse compare plugins that have been configured in
1953   * the Directory Server.
1954   *
1955   * @param  compareOperation  The compare operation for which to invoke the
1956   *                           pre-parse plugins.
1957   *
1958   * @return  The result of processing the pre-parse compare plugins.
1959   *
1960   * @throws CanceledOperationException if the operation should be canceled.
1961   */
1962  public PluginResult.PreParse invokePreParseComparePlugins(
1963      PreParseCompareOperation compareOperation)
1964      throws CanceledOperationException {
1965    PluginResult.PreParse result = null;
1966
1967    for (DirectoryServerPlugin p : preParseComparePlugins)
1968    {
1969      if (isInternalOperation(compareOperation, p))
1970      {
1971        continue;
1972      }
1973
1974      try
1975      {
1976        result = p.doPreParse(compareOperation);
1977      }
1978      catch (CanceledOperationException coe)
1979      {
1980        throw coe;
1981      }
1982      catch (Exception e)
1983      {
1984        return handlePreParseException(e, compareOperation, p);
1985      }
1986
1987      if (result == null)
1988      {
1989        return handlePreParseResult(compareOperation, p);
1990      }
1991      else if (!result.continuePluginProcessing())
1992      {
1993        return result;
1994      }
1995    }
1996
1997    if (result == null)
1998    {
1999      // This should only happen if there were no pre-parse compare plugins
2000      // registered, which is fine.
2001      result = PluginResult.PreParse.continueOperationProcessing();
2002    }
2003
2004    return result;
2005  }
2006
2007
2008
2009  /**
2010   * Invokes the set of pre-parse delete plugins that have been configured in
2011   * the Directory Server.
2012   *
2013   * @param  deleteOperation  The delete operation for which to invoke the
2014   *                          pre-parse plugins.
2015   *
2016   * @return  The result of processing the pre-parse delete plugins.
2017   *
2018   * @throws CanceledOperationException if the operation should be canceled.
2019   */
2020  public PluginResult.PreParse invokePreParseDeletePlugins(
2021                              PreParseDeleteOperation deleteOperation)
2022      throws CanceledOperationException {
2023    PluginResult.PreParse result = null;
2024
2025    for (DirectoryServerPlugin p : preParseDeletePlugins)
2026    {
2027      if (isInternalOperation(deleteOperation, p))
2028      {
2029        continue;
2030      }
2031
2032      try
2033      {
2034        result = p.doPreParse(deleteOperation);
2035      }
2036      catch (CanceledOperationException coe)
2037      {
2038        throw coe;
2039      }
2040      catch (Exception e)
2041      {
2042        return handlePreParseException(e, deleteOperation, p);
2043      }
2044
2045      if (result == null)
2046      {
2047        return handlePreParseResult(deleteOperation, p);
2048      }
2049      else if (!result.continuePluginProcessing())
2050      {
2051        return result;
2052      }
2053    }
2054
2055    if (result == null)
2056    {
2057      // This should only happen if there were no pre-parse delete plugins
2058      // registered, which is fine.
2059      result = PluginResult.PreParse.continueOperationProcessing();
2060    }
2061
2062    return result;
2063  }
2064
2065
2066
2067  /**
2068   * Invokes the set of pre-parse extended plugins that have been configured in
2069   * the Directory Server.
2070   *
2071   * @param  extendedOperation  The extended operation for which to invoke the
2072   *                            pre-parse plugins.
2073   *
2074   * @return  The result of processing the pre-parse extended plugins.
2075   *
2076   * @throws CanceledOperationException if the operation should be canceled.
2077   */
2078  public PluginResult.PreParse invokePreParseExtendedPlugins(
2079                                   PreParseExtendedOperation extendedOperation)
2080      throws CanceledOperationException {
2081    PluginResult.PreParse result = null;
2082
2083    for (DirectoryServerPlugin p : preParseExtendedPlugins)
2084    {
2085      if (isInternalOperation(extendedOperation, p))
2086      {
2087        continue;
2088      }
2089
2090      try
2091      {
2092        result = p.doPreParse(extendedOperation);
2093      }
2094      catch (CanceledOperationException coe)
2095      {
2096        throw coe;
2097      }
2098      catch (Exception e)
2099      {
2100        return handlePreParseException(e, extendedOperation, p);
2101      }
2102
2103      if (result == null)
2104      {
2105        return handlePreParseResult(extendedOperation, p);
2106      }
2107      else if (!result.continuePluginProcessing())
2108      {
2109        return result;
2110      }
2111    }
2112
2113    if (result == null)
2114    {
2115      // This should only happen if there were no pre-parse extended plugins
2116      // registered, which is fine.
2117      result = PluginResult.PreParse.continueOperationProcessing();
2118    }
2119
2120    return result;
2121  }
2122
2123
2124
2125  /**
2126   * Invokes the set of pre-parse modify plugins that have been configured in
2127   * the Directory Server.
2128   *
2129   * @param  modifyOperation  The modify operation for which to invoke the
2130   *                          pre-parse plugins.
2131   *
2132   * @return  The result of processing the pre-parse modify plugins.
2133   *
2134   * @throws CanceledOperationException if the operation should be canceled.
2135   */
2136  public PluginResult.PreParse invokePreParseModifyPlugins(
2137                                   PreParseModifyOperation modifyOperation)
2138      throws CanceledOperationException {
2139    PluginResult.PreParse result = null;
2140
2141    for (DirectoryServerPlugin p : preParseModifyPlugins)
2142    {
2143      if (isInternalOperation(modifyOperation, p))
2144      {
2145        continue;
2146      }
2147
2148      try
2149      {
2150        result = p.doPreParse(modifyOperation);
2151      }
2152      catch (CanceledOperationException coe)
2153      {
2154        throw coe;
2155      }
2156      catch (Exception e)
2157      {
2158        return handlePreParseException(e, modifyOperation, p);
2159      }
2160
2161      if (result == null)
2162      {
2163        return handlePreParseResult(modifyOperation, p);
2164      }
2165      else if (!result.continuePluginProcessing())
2166      {
2167        return result;
2168      }
2169    }
2170
2171    if (result == null)
2172    {
2173      // This should only happen if there were no pre-parse modify plugins
2174      // registered, which is fine.
2175      result = PluginResult.PreParse.continueOperationProcessing();
2176    }
2177
2178    return result;
2179  }
2180
2181
2182
2183  /**
2184   * Invokes the set of pre-parse modify DN plugins that have been configured in
2185   * the Directory Server.
2186   *
2187   * @param  modifyDNOperation  The modify DN operation for which to invoke the
2188   *                            pre-parse plugins.
2189   *
2190   * @return  The result of processing the pre-parse modify DN plugins.
2191   *
2192   * @throws CanceledOperationException if the operation should be canceled.
2193   */
2194  public PluginResult.PreParse invokePreParseModifyDNPlugins(
2195                                   PreParseModifyDNOperation modifyDNOperation)
2196      throws CanceledOperationException {
2197    PluginResult.PreParse result = null;
2198
2199    for (DirectoryServerPlugin p : preParseModifyDNPlugins)
2200    {
2201      if (isInternalOperation(modifyDNOperation, p))
2202      {
2203        continue;
2204      }
2205
2206      try
2207      {
2208        result = p.doPreParse(modifyDNOperation);
2209      }
2210      catch (CanceledOperationException coe)
2211      {
2212        throw coe;
2213      }
2214      catch (Exception e)
2215      {
2216        return handlePreParseException(e, modifyDNOperation, p);
2217      }
2218
2219      if (result == null)
2220      {
2221        return handlePreParseResult(modifyDNOperation, p);
2222      }
2223      else if (!result.continuePluginProcessing())
2224      {
2225        return result;
2226      }
2227    }
2228
2229    if (result == null)
2230    {
2231      // This should only happen if there were no pre-parse modify DN plugins
2232      // registered, which is fine.
2233      result = PluginResult.PreParse.continueOperationProcessing();
2234    }
2235
2236    return result;
2237  }
2238
2239
2240
2241  /**
2242   * Invokes the set of pre-parse search plugins that have been configured in
2243   * the Directory Server.
2244   *
2245   * @param  searchOperation  The search operation for which to invoke the
2246   *                          pre-parse plugins.
2247   *
2248   * @return  The result of processing the pre-parse search plugins.
2249   *
2250   * @throws CanceledOperationException if the operation should be canceled.
2251   */
2252  public PluginResult.PreParse invokePreParseSearchPlugins(
2253                                   PreParseSearchOperation searchOperation)
2254      throws CanceledOperationException {
2255    PluginResult.PreParse result = null;
2256
2257    for (DirectoryServerPlugin p : preParseSearchPlugins)
2258    {
2259      if (isInternalOperation(searchOperation, p))
2260      {
2261        continue;
2262      }
2263
2264      try
2265      {
2266        result = p.doPreParse(searchOperation);
2267      }
2268      catch (CanceledOperationException coe)
2269      {
2270        throw coe;
2271      }
2272      catch (Exception e)
2273      {
2274        return handlePreParseException(e, searchOperation, p);
2275      }
2276
2277      if (result == null)
2278      {
2279        return handlePreParseResult(searchOperation, p);
2280      }
2281      else if (!result.continuePluginProcessing())
2282      {
2283        return result;
2284      }
2285    }
2286
2287    if (result == null)
2288    {
2289      // This should only happen if there were no pre-parse search plugins
2290      // registered, which is fine.
2291      result = PluginResult.PreParse.continueOperationProcessing();
2292    }
2293
2294    return result;
2295  }
2296
2297
2298
2299  /**
2300   * Invokes the set of pre-parse unbind plugins that have been configured in
2301   * the Directory Server.
2302   *
2303   * @param  unbindOperation  The unbind operation for which to invoke the
2304   *                          pre-parse plugins.
2305   *
2306   * @return  The result of processing the pre-parse unbind plugins.
2307   */
2308  public PluginResult.PreParse invokePreParseUnbindPlugins(
2309                                   PreParseUnbindOperation unbindOperation)
2310  {
2311    PluginResult.PreParse result = null;
2312
2313    for (DirectoryServerPlugin p : preParseUnbindPlugins)
2314    {
2315      if (isInternalOperation(unbindOperation, p))
2316      {
2317        continue;
2318      }
2319
2320      try
2321      {
2322        result = p.doPreParse(unbindOperation);
2323      }
2324      catch (Exception e)
2325      {
2326        return handlePreParseException(e, unbindOperation, p);
2327      }
2328
2329      if (result == null)
2330      {
2331        return handlePreParseResult(unbindOperation, p);
2332      }
2333      else if (!result.continuePluginProcessing())
2334      {
2335        return result;
2336      }
2337    }
2338
2339    if (result == null)
2340    {
2341      // This should only happen if there were no pre-parse unbind plugins
2342      // registered, which is fine.
2343      result = PluginResult.PreParse.continueOperationProcessing();
2344    }
2345
2346    return result;
2347  }
2348
2349
2350
2351  /**
2352   * Invokes the set of pre-operation add plugins that have been configured in
2353   * the Directory Server.
2354   *
2355   * @param  addOperation  The add operation for which to invoke the
2356   *                       pre-operation plugins.
2357   *
2358   * @return  The result of processing the pre-operation add plugins.
2359   *
2360   * @throws CanceledOperationException if the operation should be canceled.
2361   */
2362  public PluginResult.PreOperation invokePreOperationAddPlugins(
2363                                       PreOperationAddOperation addOperation)
2364      throws CanceledOperationException {
2365    PluginResult.PreOperation result = null;
2366
2367    for (int i = 0; i < preOperationAddPlugins.length; i++)
2368    {
2369      DirectoryServerPlugin p = preOperationAddPlugins[i];
2370      if (isInternalOperation(addOperation, p))
2371      {
2372        continue;
2373      }
2374
2375      try
2376      {
2377        result = p.doPreOperation(addOperation);
2378      }
2379      catch (CanceledOperationException coe)
2380      {
2381        throw coe;
2382      }
2383      catch (Exception e)
2384      {
2385        return handlePreOperationException(e, i, preOperationAddPlugins,
2386            addOperation, p);
2387      }
2388
2389      if (result == null)
2390      {
2391        return handlePreOperationResult(addOperation, i, preOperationAddPlugins,
2392            p);
2393      }
2394      else if (!result.continuePluginProcessing())
2395      {
2396        registerSkippedPreOperationPlugins(i, preOperationAddPlugins,
2397            addOperation);
2398        return result;
2399      }
2400    }
2401
2402    if (result == null)
2403    {
2404      // This should only happen if there were no pre-operation add plugins
2405      // registered, which is fine.
2406      result = PluginResult.PreOperation.continueOperationProcessing();
2407    }
2408
2409    return result;
2410  }
2411
2412
2413
2414  /**
2415   * Invokes the set of pre-operation bind plugins that have been configured in
2416   * the Directory Server.
2417   *
2418   * @param  bindOperation  The bind operation for which to invoke the
2419   *                        pre-operation plugins.
2420   *
2421   * @return  The result of processing the pre-operation bind plugins.
2422   */
2423  public PluginResult.PreOperation invokePreOperationBindPlugins(
2424                                       PreOperationBindOperation bindOperation)
2425  {
2426    PluginResult.PreOperation result = null;
2427
2428    for (int i = 0; i < preOperationBindPlugins.length; i++)
2429    {
2430      DirectoryServerPlugin p = preOperationBindPlugins[i];
2431      if (isInternalOperation(bindOperation, p))
2432      {
2433        continue;
2434      }
2435
2436      try
2437      {
2438        result = p.doPreOperation(bindOperation);
2439      }
2440      catch (Exception e)
2441      {
2442        return handlePreOperationException(e, i, preOperationBindPlugins,
2443            bindOperation, p);
2444      }
2445
2446      if (result == null)
2447      {
2448        return handlePreOperationResult(bindOperation, i,
2449            preOperationBindPlugins, p);
2450      }
2451      else if (!result.continuePluginProcessing())
2452      {
2453        registerSkippedPreOperationPlugins(i, preOperationBindPlugins,
2454            bindOperation);
2455
2456        return result;
2457      }
2458    }
2459
2460    if (result == null)
2461    {
2462      // This should only happen if there were no pre-operation add plugins
2463      // registered, which is fine.
2464      result = PluginResult.PreOperation.continueOperationProcessing();
2465    }
2466
2467    return result;
2468  }
2469
2470
2471
2472  /**
2473   * Invokes the set of pre-operation compare plugins that have been configured
2474   * in the Directory Server.
2475   *
2476   * @param  compareOperation  The compare operation for which to invoke the
2477   *                           pre-operation plugins.
2478   *
2479   * @return  The result of processing the pre-operation compare plugins.
2480   *
2481   * @throws CanceledOperationException if the operation should be canceled.
2482   */
2483  public PluginResult.PreOperation invokePreOperationComparePlugins(
2484     PreOperationCompareOperation compareOperation)
2485      throws CanceledOperationException {
2486    PluginResult.PreOperation result = null;
2487
2488    for (int i = 0; i < preOperationComparePlugins.length; i++)
2489    {
2490      DirectoryServerPlugin p = preOperationComparePlugins[i];
2491      if (isInternalOperation(compareOperation, p))
2492      {
2493        continue;
2494      }
2495
2496      try
2497      {
2498        result = p.doPreOperation(compareOperation);
2499      }
2500      catch (CanceledOperationException coe)
2501      {
2502        throw coe;
2503      }
2504      catch (Exception e)
2505      {
2506        return handlePreOperationException(e, i, preOperationComparePlugins,
2507            compareOperation, p);
2508      }
2509
2510      if (result == null)
2511      {
2512        return handlePreOperationResult(compareOperation, i,
2513            preOperationComparePlugins, p);
2514      }
2515      else if (!result.continuePluginProcessing())
2516      {
2517        return result;
2518      }
2519    }
2520
2521    if (result == null)
2522    {
2523      // This should only happen if there were no pre-operation add plugins
2524      // registered, which is fine.
2525      result = PluginResult.PreOperation.continueOperationProcessing();
2526    }
2527
2528    return result;
2529  }
2530
2531
2532
2533  /**
2534   * Invokes the set of pre-operation delete plugins that have been configured
2535   * in the Directory Server.
2536   *
2537   * @param  deleteOperation  The delete operation for which to invoke the
2538   *                          pre-operation plugins.
2539   *
2540   * @return  The result of processing the pre-operation delete plugins.
2541   *
2542   * @throws CanceledOperationException if the operation should be canceled.
2543   */
2544  public PluginResult.PreOperation invokePreOperationDeletePlugins(
2545                                  PreOperationDeleteOperation deleteOperation)
2546      throws CanceledOperationException {
2547    PluginResult.PreOperation result = null;
2548
2549    for (int i = 0; i < preOperationDeletePlugins.length; i++)
2550    {
2551      DirectoryServerPlugin p = preOperationDeletePlugins[i];
2552      if (isInternalOperation(deleteOperation, p))
2553      {
2554        continue;
2555      }
2556
2557      try
2558      {
2559        result = p.doPreOperation(deleteOperation);
2560      }
2561      catch (CanceledOperationException coe)
2562      {
2563        throw coe;
2564      }
2565      catch (Exception e)
2566      {
2567        return handlePreOperationException(e, i, preOperationDeletePlugins,
2568            deleteOperation, p);
2569      }
2570
2571      if (result == null)
2572      {
2573        return handlePreOperationResult(deleteOperation, i,
2574            preOperationDeletePlugins, p);
2575      }
2576      else if (!result.continuePluginProcessing())
2577      {
2578        registerSkippedPreOperationPlugins(i, preOperationDeletePlugins,
2579            deleteOperation);
2580
2581        return result;
2582      }
2583    }
2584
2585    if (result == null)
2586    {
2587      // This should only happen if there were no pre-operation add plugins
2588      // registered, which is fine.
2589      result = PluginResult.PreOperation.continueOperationProcessing();
2590    }
2591
2592    return result;
2593  }
2594
2595  private PluginResult.PreOperation handlePreOperationException(Exception e,
2596      int i, DirectoryServerPlugin[] plugins, PreOperationOperation operation,
2597      DirectoryServerPlugin plugin)
2598  {
2599    logger.traceException(e);
2600
2601    LocalizableMessage message =
2602        ERR_PLUGIN_PRE_OPERATION_PLUGIN_EXCEPTION.get(operation
2603            .getOperationType().getOperationName(), plugin
2604            .getPluginEntryDN(), operation.getConnectionID(), operation
2605            .getOperationID(), stackTraceToSingleLineString(e));
2606    logger.error(message);
2607
2608    registerSkippedPreOperationPlugins(i, plugins, operation);
2609
2610    return PluginResult.PreOperation.stopProcessing(DirectoryServer
2611        .getServerErrorResultCode(), message);
2612  }
2613
2614  private PluginResult.PreOperation handlePreOperationResult(
2615      PreOperationOperation operation, int i, DirectoryServerPlugin[] plugins,
2616      DirectoryServerPlugin plugin)
2617  {
2618    LocalizableMessage message =
2619        ERR_PLUGIN_PRE_OPERATION_PLUGIN_RETURNED_NULL.get(operation
2620            .getOperationType().getOperationName(), plugin
2621            .getPluginEntryDN(), operation.getConnectionID(), operation
2622            .getOperationID());
2623    logger.error(message);
2624
2625    registerSkippedPreOperationPlugins(i, plugins, operation);
2626
2627    return PluginResult.PreOperation.stopProcessing(DirectoryServer
2628        .getServerErrorResultCode(), message);
2629  }
2630
2631
2632
2633  /**
2634   * Invokes the set of pre-operation extended plugins that have been configured
2635   * in the Directory Server.
2636   *
2637   * @param  extendedOperation  The extended operation for which to invoke the
2638   *                            pre-operation plugins.
2639   *
2640   * @return  The result of processing the pre-operation extended plugins.
2641   *
2642   * @throws CanceledOperationException if the operation should be canceled.
2643   */
2644  public PluginResult.PreOperation invokePreOperationExtendedPlugins(
2645                               PreOperationExtendedOperation extendedOperation)
2646      throws CanceledOperationException {
2647    PluginResult.PreOperation result = null;
2648
2649    for (int i = 0; i < preOperationExtendedPlugins.length; i++)
2650    {
2651      DirectoryServerPlugin p = preOperationExtendedPlugins[i];
2652      if (isInternalOperation(extendedOperation, p))
2653      {
2654        registerSkippedPreOperationPlugin(p, extendedOperation);
2655        continue;
2656      }
2657
2658      try
2659      {
2660        result = p.doPreOperation(extendedOperation);
2661      }
2662      catch (CanceledOperationException coe)
2663      {
2664        throw coe;
2665      }
2666      catch (Exception e)
2667      {
2668        return handlePreOperationException(e, i, preOperationExtendedPlugins,
2669            extendedOperation, p);
2670      }
2671
2672      if (result == null)
2673      {
2674        return handlePreOperationResult(extendedOperation, i,
2675            preOperationExtendedPlugins, p);
2676      }
2677      else if (!result.continuePluginProcessing())
2678      {
2679        registerSkippedPreOperationPlugins(i, preOperationExtendedPlugins,
2680            extendedOperation);
2681
2682        return result;
2683      }
2684    }
2685
2686    if (result == null)
2687    {
2688      // This should only happen if there were no pre-operation add plugins
2689      // registered, which is fine.
2690      result = PluginResult.PreOperation.continueOperationProcessing();
2691    }
2692
2693    return result;
2694  }
2695
2696
2697
2698  /**
2699   * Invokes the set of pre-operation modify plugins that have been configured
2700   * in the Directory Server.
2701   *
2702   * @param  modifyOperation  The modify operation for which to invoke the
2703   *                          pre-operation plugins.
2704   *
2705   * @return  The result of processing the pre-operation modify plugins.
2706   *
2707   * @throws CanceledOperationException if the operation should be canceled.
2708   */
2709  public PluginResult.PreOperation invokePreOperationModifyPlugins(
2710                                  PreOperationModifyOperation modifyOperation)
2711      throws CanceledOperationException {
2712    PluginResult.PreOperation result = null;
2713
2714    for (int i = 0; i < preOperationModifyPlugins.length; i++)
2715    {
2716      DirectoryServerPlugin p = preOperationModifyPlugins[i];
2717      if (isInternalOperation(modifyOperation, p))
2718      {
2719        continue;
2720      }
2721
2722      try
2723      {
2724        result = p.doPreOperation(modifyOperation);
2725      }
2726      catch (CanceledOperationException coe)
2727      {
2728        throw coe;
2729      }
2730      catch (Exception e)
2731      {
2732        return handlePreOperationException(e, i, preOperationModifyPlugins,
2733            modifyOperation, p);
2734      }
2735
2736      if (result == null)
2737      {
2738        return handlePreOperationResult(modifyOperation, i,
2739            preOperationModifyPlugins, p);
2740      }
2741      else if (!result.continuePluginProcessing())
2742      {
2743        registerSkippedPreOperationPlugins(i, preOperationModifyPlugins,
2744            modifyOperation);
2745
2746        return result;
2747      }
2748    }
2749
2750    if (result == null)
2751    {
2752      // This should only happen if there were no pre-operation add plugins
2753      // registered, which is fine.
2754      result = PluginResult.PreOperation.continueOperationProcessing();
2755    }
2756
2757    return result;
2758  }
2759
2760
2761
2762  /**
2763   * Invokes the set of pre-operation modify DN plugins that have been
2764   * configured in the Directory Server.
2765   *
2766   * @param  modifyDNOperation  The modify DN operation for which to invoke the
2767   *                            pre-operation plugins.
2768   *
2769   * @return  The result of processing the pre-operation modify DN plugins.
2770   *
2771   * @throws CanceledOperationException if the operation should be canceled.
2772   */
2773  public PluginResult.PreOperation invokePreOperationModifyDNPlugins(
2774                              PreOperationModifyDNOperation modifyDNOperation)
2775      throws CanceledOperationException {
2776    PluginResult.PreOperation result = null;
2777
2778    for (int i = 0; i < preOperationModifyDNPlugins.length; i++)
2779    {
2780      DirectoryServerPlugin p = preOperationModifyDNPlugins[i];
2781      if (isInternalOperation(modifyDNOperation, p))
2782      {
2783        continue;
2784      }
2785
2786      try
2787      {
2788        result = p.doPreOperation(modifyDNOperation);
2789      }
2790      catch (CanceledOperationException coe)
2791      {
2792        throw coe;
2793      }
2794      catch (Exception e)
2795      {
2796        return handlePreOperationException(e, i, preOperationModifyDNPlugins,
2797            modifyDNOperation, p);
2798      }
2799
2800      if (result == null)
2801      {
2802        return handlePreOperationResult(modifyDNOperation, i,
2803            preOperationModifyDNPlugins, p);
2804      }
2805      else if (!result.continuePluginProcessing())
2806      {
2807        registerSkippedPreOperationPlugins(i, preOperationModifyDNPlugins,
2808            modifyDNOperation);
2809
2810        return result;
2811      }
2812    }
2813
2814    if (result == null)
2815    {
2816      // This should only happen if there were no pre-operation add plugins
2817      // registered, which is fine.
2818      result = PluginResult.PreOperation.continueOperationProcessing();
2819    }
2820
2821    return result;
2822  }
2823
2824
2825
2826  /**
2827   * Invokes the set of pre-operation search plugins that have been configured
2828   * in the Directory Server.
2829   *
2830   * @param  searchOperation  The search operation for which to invoke the
2831   *                          pre-operation plugins.
2832   *
2833   * @return  The result of processing the pre-operation search plugins.
2834   *
2835   * @throws CanceledOperationException if the operation should be canceled.
2836   */
2837  public PluginResult.PreOperation invokePreOperationSearchPlugins(
2838                                  PreOperationSearchOperation searchOperation)
2839      throws CanceledOperationException {
2840    PluginResult.PreOperation result = null;
2841
2842    for (int i = 0; i < preOperationSearchPlugins.length; i++)
2843    {
2844      DirectoryServerPlugin p = preOperationSearchPlugins[i];
2845      if (isInternalOperation(searchOperation, p))
2846      {
2847        continue;
2848      }
2849
2850      try
2851      {
2852        result = p.doPreOperation(searchOperation);
2853      }
2854      catch (CanceledOperationException coe)
2855      {
2856        throw coe;
2857      }
2858      catch (Exception e)
2859      {
2860        return handlePreOperationException(e, i, preOperationSearchPlugins,
2861            searchOperation, p);
2862      }
2863
2864      if (result == null)
2865      {
2866        return handlePreOperationResult(searchOperation, i,
2867            preOperationSearchPlugins, p);
2868      }
2869      else if (!result.continuePluginProcessing())
2870      {
2871        registerSkippedPreOperationPlugins(i, preOperationSearchPlugins,
2872             searchOperation);
2873
2874        return result;
2875      }
2876    }
2877
2878    if (result == null)
2879    {
2880      // This should only happen if there were no pre-operation add plugins
2881      // registered, which is fine.
2882      result = PluginResult.PreOperation.continueOperationProcessing();
2883    }
2884
2885    return result;
2886  }
2887
2888
2889
2890  /**
2891   * Invokes the set of post-operation abandon plugins that have been configured
2892   * in the Directory Server.
2893   *
2894   * @param  abandonOperation  The abandon operation for which to invoke the
2895   *                           post-operation plugins.
2896   *
2897   * @return  The result of processing the post-operation abandon plugins.
2898   */
2899  public PluginResult.PostOperation invokePostOperationAbandonPlugins(
2900                              PostOperationAbandonOperation abandonOperation)
2901  {
2902    PluginResult.PostOperation result = null;
2903    PluginResult.PostOperation finalResult = null;
2904
2905    for (DirectoryServerPlugin p : postOperationAbandonPlugins)
2906    {
2907      if (isInternalOperation(abandonOperation, p))
2908      {
2909        continue;
2910      }
2911
2912      try
2913      {
2914        result = p.doPostOperation(abandonOperation);
2915      }
2916      catch (Exception e)
2917      {
2918        logException(abandonOperation, p, e, ERR_PLUGIN_POST_OPERATION_PLUGIN_EXCEPTION);
2919      }
2920
2921      if (result == null)
2922      {
2923        logNullResult(abandonOperation, p, ERR_PLUGIN_POST_OPERATION_PLUGIN_RETURNED_NULL);
2924      }
2925      else if (!result.continueProcessing())
2926      {
2927        // This plugin requested operation processing to stop. However, we
2928        // still have to invoke all the post op plugins that successfully
2929        // invoked its pre op plugins. We will just take this plugin's
2930        // results as the final result.
2931        finalResult = result;
2932      }
2933    }
2934
2935    if (result == null)
2936    {
2937      // This should only happen if there were no post-operation add plugins
2938      // registered, which is fine.
2939      finalResult = PluginResult.PostOperation.continueOperationProcessing();
2940    }
2941    else if(finalResult == null)
2942    {
2943      // None of the plugins requested processing to stop so all results
2944      // have equal priority. Just return the last one.
2945      finalResult = result;
2946    }
2947
2948    return finalResult;
2949  }
2950
2951
2952
2953  /**
2954   * Invokes the set of post-operation add plugins that have been configured in
2955   * the Directory Server.
2956   *
2957   * @param  addOperation  The add operation for which to invoke the
2958   *                       post-operation plugins.
2959   *
2960   * @return  The result of processing the post-operation add plugins.
2961   */
2962  public PluginResult.PostOperation invokePostOperationAddPlugins(
2963                                        PostOperationAddOperation addOperation)
2964  {
2965    PluginResult.PostOperation result = null;
2966    PluginResult.PostOperation finalResult = null;
2967
2968    ArrayList<DirectoryServerPlugin> skippedPlugins =
2969        skippedPreOperationPlugins.remove(addOperation);
2970
2971    for (DirectoryServerPlugin p : postOperationAddPlugins)
2972    {
2973      if (isInternalOperation(addOperation, p)
2974          || isSkipped(skippedPlugins, p))
2975      {
2976        continue;
2977      }
2978
2979      try
2980      {
2981        result = p.doPostOperation(addOperation);
2982      }
2983      catch (Exception e)
2984      {
2985        logException(addOperation, p, e, ERR_PLUGIN_POST_OPERATION_PLUGIN_EXCEPTION);
2986      }
2987
2988      if (result == null)
2989      {
2990        logNullResult(addOperation, p, ERR_PLUGIN_POST_OPERATION_PLUGIN_RETURNED_NULL);
2991      }
2992      else if (!result.continueProcessing())
2993      {
2994        // This plugin requested operation processing to stop. However, we
2995        // still have to invoke all the post op plugins that successfully
2996        // invoked its pre op plugins. We will just take this plugin's
2997        // results as the final result.
2998        finalResult = result;
2999      }
3000    }
3001
3002    if (result == null)
3003    {
3004      // This should only happen if there were no post-operation add plugins
3005      // registered, which is fine.
3006      finalResult = PluginResult.PostOperation.continueOperationProcessing();
3007    }
3008    else if(finalResult == null)
3009    {
3010      // None of the plugins requested processing to stop so all results
3011      // have equal priority. Just return the last one.
3012      finalResult = result;
3013    }
3014
3015    return finalResult;
3016  }
3017
3018
3019
3020  /**
3021   * Invokes the set of post-operation bind plugins that have been configured
3022   * in the Directory Server.
3023   *
3024   * @param  bindOperation  The bind operation for which to invoke the
3025   *                        post-operation plugins.
3026   *
3027   * @return  The result of processing the post-operation bind plugins.
3028   */
3029  public PluginResult.PostOperation invokePostOperationBindPlugins(
3030                                   PostOperationBindOperation bindOperation)
3031  {
3032    PluginResult.PostOperation result = null;
3033    PluginResult.PostOperation finalResult = null;
3034
3035    ArrayList<DirectoryServerPlugin> skippedPlugins =
3036        skippedPreOperationPlugins.remove(bindOperation);
3037
3038    for (DirectoryServerPlugin p : postOperationBindPlugins)
3039    {
3040      if (isInternalOperation(bindOperation, p)
3041          || isSkipped(skippedPlugins, p))
3042      {
3043        continue;
3044      }
3045
3046      try
3047      {
3048        result = p.doPostOperation(bindOperation);
3049      }
3050      catch (Exception e)
3051      {
3052        logException(bindOperation, p, e, ERR_PLUGIN_POST_OPERATION_PLUGIN_EXCEPTION);
3053      }
3054
3055      if (result == null)
3056      {
3057        logNullResult(bindOperation, p, ERR_PLUGIN_POST_OPERATION_PLUGIN_RETURNED_NULL);
3058      }
3059      else if (!result.continueProcessing())
3060      {
3061        // This plugin requested operation processing to stop. However, we
3062        // still have to invoke all the post op plugins that successfully
3063        // invoked its pre op plugins. We will just take this plugin's
3064        // results as the final result.
3065        finalResult = result;
3066      }
3067    }
3068
3069    if (result == null)
3070    {
3071      // This should only happen if there were no post-operation add plugins
3072      // registered, which is fine.
3073      finalResult = PluginResult.PostOperation.continueOperationProcessing();
3074    }
3075    else if(finalResult == null)
3076    {
3077      // None of the plugins requested processing to stop so all results
3078      // have equal priority. Just return the last one.
3079      finalResult = result;
3080    }
3081
3082    return finalResult;
3083  }
3084
3085
3086
3087  /**
3088   * Invokes the set of post-operation compare plugins that have been configured
3089   * in the Directory Server.
3090   *
3091   * @param  compareOperation  The compare operation for which to invoke the
3092   *                           post-operation plugins.
3093   *
3094   * @return  The result of processing the post-operation compare plugins.
3095   */
3096  public PluginResult.PostOperation invokePostOperationComparePlugins(
3097      PostOperationCompareOperation compareOperation)
3098  {
3099    PluginResult.PostOperation result = null;
3100    PluginResult.PostOperation finalResult = null;
3101
3102    ArrayList<DirectoryServerPlugin> skippedPlugins =
3103        skippedPreOperationPlugins.remove(compareOperation);
3104
3105    for (DirectoryServerPlugin p : postOperationComparePlugins)
3106    {
3107      if (isInternalOperation(compareOperation, p)
3108          || isSkipped(skippedPlugins, p))
3109      {
3110        continue;
3111      }
3112
3113      try
3114      {
3115        result = p.doPostOperation(compareOperation);
3116      }
3117      catch (Exception e)
3118      {
3119        logException(compareOperation, p, e, ERR_PLUGIN_POST_OPERATION_PLUGIN_EXCEPTION);
3120      }
3121
3122      if (result == null)
3123      {
3124        logNullResult(compareOperation, p, ERR_PLUGIN_POST_OPERATION_PLUGIN_RETURNED_NULL);
3125      }
3126      else if (!result.continueProcessing())
3127      {
3128        // This plugin requested operation processing to stop. However, we
3129        // still have to invoke all the post op plugins that successfully
3130        // invoked its pre op plugins. We will just take this plugin's
3131        // results as the final result.
3132        finalResult = result;
3133      }
3134    }
3135
3136    if (result == null)
3137    {
3138      // This should only happen if there were no post-operation add plugins
3139      // registered, which is fine.
3140      finalResult = PluginResult.PostOperation.continueOperationProcessing();
3141    }
3142    else if(finalResult == null)
3143    {
3144      // None of the plugins requested processing to stop so all results
3145      // have equal priority. Just return the last one.
3146      finalResult = result;
3147    }
3148
3149    return finalResult;
3150  }
3151
3152  private boolean isInternalOperation(PluginOperation op, DirectoryServerPlugin p)
3153  {
3154    return op.isInternalOperation() && !p.invokeForInternalOperations();
3155  }
3156
3157  private boolean isSkipped(ArrayList<DirectoryServerPlugin> skippedPlugins, DirectoryServerPlugin p)
3158  {
3159    return skippedPlugins != null && skippedPlugins.contains(p);
3160  }
3161
3162  /**
3163   * Invokes the set of post-operation delete plugins that have been configured
3164   * in the Directory Server.
3165   *
3166   * @param  deleteOperation  The delete operation for which to invoke the
3167   *                          post-operation plugins.
3168   *
3169   * @return  The result of processing the post-operation delete plugins.
3170   */
3171  public PluginResult.PostOperation invokePostOperationDeletePlugins(
3172                                   PostOperationDeleteOperation deleteOperation)
3173  {
3174    PluginResult.PostOperation result = null;
3175    PluginResult.PostOperation finalResult = null;
3176
3177    ArrayList<DirectoryServerPlugin> skippedPlugins =
3178        skippedPreOperationPlugins.remove(deleteOperation);
3179
3180    for (DirectoryServerPlugin p : postOperationDeletePlugins)
3181    {
3182      if (isInternalOperation(deleteOperation, p)
3183          || isSkipped(skippedPlugins, p))
3184      {
3185        continue;
3186      }
3187
3188      try
3189      {
3190        result = p.doPostOperation(deleteOperation);
3191      }
3192      catch (Exception e)
3193      {
3194        logException(deleteOperation, p, e, ERR_PLUGIN_POST_OPERATION_PLUGIN_EXCEPTION);
3195      }
3196
3197      if (result == null)
3198      {
3199        logNullResult(deleteOperation, p, ERR_PLUGIN_POST_OPERATION_PLUGIN_RETURNED_NULL);
3200      }
3201      else if (!result.continueProcessing())
3202      {
3203        // This plugin requested operation processing to stop. However, we
3204        // still have to invoke all the post op plugins that successfully
3205        // invoked its pre op plugins. We will just take this plugin's
3206        // results as the final result.
3207        finalResult = result;
3208      }
3209    }
3210
3211    if (result == null)
3212    {
3213      // This should only happen if there were no post-operation add plugins
3214      // registered, which is fine.
3215      finalResult = PluginResult.PostOperation.continueOperationProcessing();
3216    }
3217    else if(finalResult == null)
3218    {
3219      // None of the plugins requested processing to stop so all results
3220      // have equal priority. Just return the last one.
3221      finalResult = result;
3222    }
3223
3224    return finalResult;
3225  }
3226
3227
3228
3229  /**
3230   * Invokes the set of post-operation extended plugins that have been
3231   * configured in the Directory Server.
3232   *
3233   * @param  extendedOperation  The extended operation for which to invoke the
3234   *                            post-operation plugins.
3235   *
3236   * @return  The result of processing the post-operation extended plugins.
3237   */
3238  public PluginResult.PostOperation invokePostOperationExtendedPlugins(
3239                             PostOperationExtendedOperation extendedOperation)
3240  {
3241    PluginResult.PostOperation result = null;
3242    PluginResult.PostOperation finalResult = null;
3243
3244    ArrayList<DirectoryServerPlugin> skippedPlugins =
3245        skippedPreOperationPlugins.remove(extendedOperation);
3246
3247    for (DirectoryServerPlugin p : postOperationExtendedPlugins)
3248    {
3249      if (isInternalOperation(extendedOperation, p)
3250          || isSkipped(skippedPlugins, p))
3251      {
3252        continue;
3253      }
3254
3255      try
3256      {
3257        result = p.doPostOperation(extendedOperation);
3258      }
3259      catch (Exception e)
3260      {
3261        logException(extendedOperation, p, e, ERR_PLUGIN_POST_OPERATION_PLUGIN_EXCEPTION);
3262      }
3263
3264      if (result == null)
3265      {
3266        logNullResult(extendedOperation, p, ERR_PLUGIN_POST_OPERATION_PLUGIN_RETURNED_NULL);
3267      }
3268      else if (!result.continueProcessing())
3269      {
3270        // This plugin requested operation processing to stop. However, we
3271        // still have to invoke all the post op plugins that successfully
3272        // invoked its pre op plugins. We will just take this plugin's
3273        // results as the final result.
3274        finalResult = result;
3275      }
3276    }
3277
3278    if (result == null)
3279    {
3280      // This should only happen if there were no post-operation add plugins
3281      // registered, which is fine.
3282      finalResult = PluginResult.PostOperation.continueOperationProcessing();
3283    }
3284    else if(finalResult == null)
3285    {
3286      // None of the plugins requested processing to stop so all results
3287      // have equal priority. Just return the last one.
3288      finalResult = result;
3289    }
3290
3291    return finalResult;
3292  }
3293
3294
3295
3296  /**
3297   * Invokes the set of post-operation modify plugins that have been configured
3298   * in the Directory Server.
3299   *
3300   * @param  modifyOperation  The modify operation for which to invoke the
3301   *                          post-operation plugins.
3302   *
3303   * @return  The result of processing the post-operation modify plugins.
3304   */
3305  public PluginResult.PostOperation invokePostOperationModifyPlugins(
3306                                   PostOperationModifyOperation modifyOperation)
3307  {
3308    PluginResult.PostOperation result = null;
3309    PluginResult.PostOperation finalResult = null;
3310
3311    ArrayList<DirectoryServerPlugin> skippedPlugins =
3312        skippedPreOperationPlugins.remove(modifyOperation);
3313
3314    for (DirectoryServerPlugin p : postOperationModifyPlugins)
3315    {
3316      if (isInternalOperation(modifyOperation, p)
3317          || isSkipped(skippedPlugins, p))
3318      {
3319        continue;
3320      }
3321
3322      try
3323      {
3324        result = p.doPostOperation(modifyOperation);
3325      }
3326      catch (Exception e)
3327      {
3328        logException(modifyOperation, p, e, ERR_PLUGIN_POST_OPERATION_PLUGIN_EXCEPTION);
3329      }
3330
3331      if (result == null)
3332      {
3333        logNullResult(modifyOperation, p, ERR_PLUGIN_POST_OPERATION_PLUGIN_RETURNED_NULL);
3334      }
3335      else if (!result.continueProcessing())
3336      {
3337        // This plugin requested operation processing to stop. However, we
3338        // still have to invoke all the post op plugins that successfully
3339        // invoked its pre op plugins. We will just take this plugin's
3340        // results as the final result.
3341        finalResult = result;
3342      }
3343    }
3344
3345    if (result == null)
3346    {
3347      // This should only happen if there were no post-operation add plugins
3348      // registered, which is fine.
3349      finalResult = PluginResult.PostOperation.continueOperationProcessing();
3350    }
3351    else if(finalResult == null)
3352    {
3353      // None of the plugins requested processing to stop so all results
3354      // have equal priority. Just return the last one.
3355      finalResult = result;
3356    }
3357    return finalResult;
3358  }
3359
3360
3361
3362  /**
3363   * Invokes the set of post-operation modify DN plugins that have been
3364   * configured in the Directory Server.
3365   *
3366   * @param  modifyDNOperation  The modify DN operation for which to invoke the
3367   *                            post-operation plugins.
3368   *
3369   * @return  The result of processing the post-operation modify DN plugins.
3370   */
3371  public PluginResult.PostOperation invokePostOperationModifyDNPlugins(
3372                             PostOperationModifyDNOperation modifyDNOperation)
3373  {
3374    PluginResult.PostOperation result = null;
3375    PluginResult.PostOperation finalResult = null;
3376
3377    ArrayList<DirectoryServerPlugin> skippedPlugins =
3378        skippedPreOperationPlugins.remove(modifyDNOperation);
3379
3380    for (DirectoryServerPlugin p : postOperationModifyDNPlugins)
3381    {
3382      if (isInternalOperation(modifyDNOperation, p)
3383          || isSkipped(skippedPlugins, p))
3384      {
3385        continue;
3386      }
3387
3388      try
3389      {
3390        result = p.doPostOperation(modifyDNOperation);
3391      }
3392      catch (Exception e)
3393      {
3394        logException(modifyDNOperation, p, e, ERR_PLUGIN_POST_OPERATION_PLUGIN_EXCEPTION);
3395      }
3396
3397      if (result == null)
3398      {
3399        logNullResult(modifyDNOperation, p, ERR_PLUGIN_POST_OPERATION_PLUGIN_RETURNED_NULL);
3400      }
3401      else if (!result.continueProcessing())
3402      {
3403        // This plugin requested operation processing to stop. However, we
3404        // still have to invoke all the post op plugins that successfully
3405        // invoked its pre op plugins. We will just take this plugin's
3406        // results as the final result.
3407        finalResult = result;
3408      }
3409    }
3410
3411    if (result == null)
3412    {
3413      // This should only happen if there were no post-operation add plugins
3414      // registered, which is fine.
3415      finalResult = PluginResult.PostOperation.continueOperationProcessing();
3416    }
3417    else if(finalResult == null)
3418    {
3419      // None of the plugins requested processing to stop so all results
3420      // have equal priority. Just return the last one.
3421      finalResult = result;
3422    }
3423
3424    return finalResult;
3425  }
3426
3427
3428
3429  /**
3430   * Invokes the set of post-operation search plugins that have been configured
3431   * in the Directory Server.
3432   *
3433   * @param  searchOperation  The search operation for which to invoke the
3434   *                          post-operation plugins.
3435   *
3436   * @return  The result of processing the post-operation search plugins.
3437   */
3438  public PluginResult.PostOperation invokePostOperationSearchPlugins(
3439                                   PostOperationSearchOperation searchOperation)
3440  {
3441    PluginResult.PostOperation result = null;
3442    PluginResult.PostOperation finalResult = null;
3443
3444    ArrayList<DirectoryServerPlugin> skippedPlugins =
3445        skippedPreOperationPlugins.remove(searchOperation);
3446
3447    for (DirectoryServerPlugin p : postOperationSearchPlugins)
3448    {
3449      if (isInternalOperation(searchOperation, p)
3450          || isSkipped(skippedPlugins, p))
3451      {
3452        continue;
3453      }
3454
3455      try
3456      {
3457        result = p.doPostOperation(searchOperation);
3458      }
3459      catch (Exception e)
3460      {
3461        logException(searchOperation, p, e, ERR_PLUGIN_POST_OPERATION_PLUGIN_EXCEPTION);
3462      }
3463
3464      if (result == null)
3465      {
3466        logNullResult(searchOperation, p, ERR_PLUGIN_POST_OPERATION_PLUGIN_RETURNED_NULL);
3467      }
3468      else if (!result.continueProcessing())
3469      {
3470        // This plugin requested operation processing to stop. However, we
3471        // still have to invoke all the post op plugins that successfully
3472        // invoked its pre op plugins. We will just take this plugin's
3473        // results as the final result.
3474        finalResult = result;
3475      }
3476    }
3477
3478    if (result == null)
3479    {
3480      // This should only happen if there were no post-operation add plugins
3481      // registered, which is fine.
3482      finalResult = PluginResult.PostOperation.continueOperationProcessing();
3483    }
3484    else if(finalResult == null)
3485    {
3486      // None of the plugins requested processing to stop so all results
3487      // have equal priority. Just return the last one.
3488      finalResult = result;
3489    }
3490
3491    return finalResult;
3492  }
3493
3494
3495
3496  /**
3497   * Invokes the set of post-operation unbind plugins that have been configured
3498   * in the Directory Server.
3499   *
3500   * @param  unbindOperation  The unbind operation for which to invoke the
3501   *                          post-operation plugins.
3502   *
3503   * @return  The result of processing the post-operation unbind plugins.
3504   */
3505  public PluginResult.PostOperation invokePostOperationUnbindPlugins(
3506                                 PostOperationUnbindOperation unbindOperation)
3507  {
3508    PluginResult.PostOperation result = null;
3509    PluginResult.PostOperation finalResult = null;
3510
3511    ArrayList<DirectoryServerPlugin> skippedPlugins =
3512        skippedPreOperationPlugins.remove(unbindOperation);
3513
3514    for (DirectoryServerPlugin p : postOperationUnbindPlugins)
3515    {
3516      if (isInternalOperation(unbindOperation, p)
3517          || isSkipped(skippedPlugins, p))
3518      {
3519        continue;
3520      }
3521
3522      try
3523      {
3524        result = p.doPostOperation(unbindOperation);
3525      }
3526      catch (Exception e)
3527      {
3528        logException(unbindOperation, p, e, ERR_PLUGIN_POST_OPERATION_PLUGIN_EXCEPTION);
3529      }
3530
3531      if (result == null)
3532      {
3533        logNullResult(unbindOperation, p, ERR_PLUGIN_POST_OPERATION_PLUGIN_RETURNED_NULL);
3534      }
3535      else if (!result.continueProcessing())
3536      {
3537        // This plugin requested operation processing to stop. However, we
3538        // still have to invoke all the post op plugins that successfully
3539        // invoked its pre op plugins. We will just take this plugin's
3540        // results as the final result.
3541        finalResult = result;
3542      }
3543    }
3544
3545    if (result == null)
3546    {
3547      // This should only happen if there were no post-operation add plugins
3548      // registered, which is fine.
3549      finalResult = PluginResult.PostOperation.continueOperationProcessing();
3550    }
3551    else if(finalResult == null)
3552    {
3553      // None of the plugins requested processing to stop so all results
3554      // have equal priority. Just return the last one.
3555      finalResult = result;
3556    }
3557
3558    return finalResult;
3559  }
3560
3561
3562
3563  /**
3564   * Invokes the set of post-response add plugins that have been configured in
3565   * the Directory Server.
3566   *
3567   * @param  addOperation  The add operation for which to invoke the
3568   *                       post-response plugins.
3569   *
3570   * @return  The result of processing the post-response add plugins.
3571   */
3572  public PluginResult.PostResponse invokePostResponseAddPlugins(
3573                                       PostResponseAddOperation addOperation)
3574  {
3575    PluginResult.PostResponse result = null;
3576
3577    for (DirectoryServerPlugin p : postResponseAddPlugins)
3578    {
3579      if (isInternalOperation(addOperation, p))
3580      {
3581        continue;
3582      }
3583
3584      try
3585      {
3586        result = p.doPostResponse(addOperation);
3587      }
3588      catch (Exception e)
3589      {
3590        logException(addOperation, p, e, ERR_PLUGIN_POST_RESPONSE_PLUGIN_EXCEPTION);
3591      }
3592
3593      if (result == null)
3594      {
3595        logNullResult(addOperation, p, ERR_PLUGIN_POST_RESPONSE_PLUGIN_RETURNED_NULL);
3596      }
3597      else if (!result.continuePluginProcessing())
3598      {
3599        return result;
3600      }
3601    }
3602
3603    if (result == null)
3604    {
3605      // This should only happen if there were no post-response add plugins
3606      // registered, which is fine.
3607      result = PluginResult.PostResponse.continueOperationProcessing();
3608    }
3609
3610    return result;
3611  }
3612
3613
3614
3615  /**
3616   * Invokes the set of post-response bind plugins that have been configured in
3617   * the Directory Server.
3618   *
3619   * @param  bindOperation  The bind operation for which to invoke the
3620   *                        post-response plugins.
3621   *
3622   * @return  The result of processing the post-response bind plugins.
3623   */
3624  public PluginResult.PostResponse invokePostResponseBindPlugins(
3625                                       PostResponseBindOperation bindOperation)
3626  {
3627    PluginResult.PostResponse result = null;
3628
3629    for (DirectoryServerPlugin p : postResponseBindPlugins)
3630    {
3631      if (isInternalOperation(bindOperation, p))
3632      {
3633        continue;
3634      }
3635
3636      try
3637      {
3638        result = p.doPostResponse(bindOperation);
3639      }
3640      catch (Exception e)
3641      {
3642        logException(bindOperation, p, e, ERR_PLUGIN_POST_RESPONSE_PLUGIN_EXCEPTION);
3643      }
3644
3645      if (result == null)
3646      {
3647        logNullResult(bindOperation, p, ERR_PLUGIN_POST_RESPONSE_PLUGIN_RETURNED_NULL);
3648      }
3649      else if (!result.continuePluginProcessing())
3650      {
3651        return result;
3652      }
3653    }
3654
3655    if (result == null)
3656    {
3657      // This should only happen if there were no post-response add plugins
3658      // registered, which is fine.
3659      result = PluginResult.PostResponse.continueOperationProcessing();
3660    }
3661
3662    return result;
3663  }
3664
3665
3666
3667  /**
3668   * Invokes the set of post-response compare plugins that have been configured
3669   * in the Directory Server.
3670   *
3671   * @param  compareOperation  The compare operation for which to invoke the
3672   *                           post-response plugins.
3673   *
3674   * @return  The result of processing the post-response compare plugins.
3675   */
3676  public PluginResult.PostResponse invokePostResponseComparePlugins(
3677      PostResponseCompareOperation compareOperation)
3678  {
3679    PluginResult.PostResponse result = null;
3680
3681    for (DirectoryServerPlugin p : postResponseComparePlugins)
3682    {
3683      if (isInternalOperation(compareOperation, p))
3684      {
3685        continue;
3686      }
3687
3688      try
3689      {
3690        result = p.doPostResponse(compareOperation);
3691      }
3692      catch (Exception e)
3693      {
3694        logException(compareOperation, p, e, ERR_PLUGIN_POST_RESPONSE_PLUGIN_EXCEPTION);
3695      }
3696
3697      if (result == null)
3698      {
3699        logNullResult(compareOperation, p, ERR_PLUGIN_POST_RESPONSE_PLUGIN_RETURNED_NULL);
3700      }
3701      else if (!result.continuePluginProcessing())
3702      {
3703        return result;
3704      }
3705    }
3706
3707    if (result == null)
3708    {
3709      // This should only happen if there were no post-response add plugins
3710      // registered, which is fine.
3711      result = PluginResult.PostResponse.continueOperationProcessing();
3712    }
3713
3714    return result;
3715  }
3716
3717  /**
3718   * Invokes the set of post-response delete plugins that have been configured
3719   * in the Directory Server.
3720   *
3721   * @param  deleteOperation  The delete operation for which to invoke the
3722   *                          post-response plugins.
3723   *
3724   * @return  The result of processing the post-response delete plugins.
3725   */
3726  public PluginResult.PostResponse invokePostResponseDeletePlugins(
3727                          PostResponseDeleteOperation deleteOperation)
3728  {
3729    PluginResult.PostResponse result = null;
3730
3731    for (DirectoryServerPlugin p : postResponseDeletePlugins)
3732    {
3733      if (isInternalOperation(deleteOperation, p))
3734      {
3735        continue;
3736      }
3737
3738      try
3739      {
3740        result = p.doPostResponse(deleteOperation);
3741      }
3742      catch (Exception e)
3743      {
3744        logException(deleteOperation, p, e, ERR_PLUGIN_POST_RESPONSE_PLUGIN_EXCEPTION);
3745      }
3746
3747      if (result == null)
3748      {
3749        logNullResult(deleteOperation, p, ERR_PLUGIN_POST_RESPONSE_PLUGIN_RETURNED_NULL);
3750      }
3751      else if (!result.continuePluginProcessing())
3752      {
3753        return result;
3754      }
3755    }
3756
3757    if (result == null)
3758    {
3759      // This should only happen if there were no post-response add plugins
3760      // registered, which is fine.
3761      result = PluginResult.PostResponse.continueOperationProcessing();
3762    }
3763    return result;
3764  }
3765
3766
3767
3768  /**
3769   * Invokes the set of post-response extended plugins that have been configured
3770   * in the Directory Server.
3771   *
3772   * @param  extendedOperation  The extended operation for which to invoke the
3773   *                            post-response plugins.
3774   *
3775   * @return  The result of processing the post-response extended plugins.
3776   */
3777  public PluginResult.PostResponse invokePostResponseExtendedPlugins(
3778                              PostResponseExtendedOperation extendedOperation)
3779  {
3780    PluginResult.PostResponse result = null;
3781
3782    for (DirectoryServerPlugin p : postResponseExtendedPlugins)
3783    {
3784      if (isInternalOperation(extendedOperation, p))
3785      {
3786        continue;
3787      }
3788
3789      try
3790      {
3791        result = p.doPostResponse(extendedOperation);
3792      }
3793      catch (Exception e)
3794      {
3795        logException(extendedOperation, p, e, ERR_PLUGIN_POST_RESPONSE_PLUGIN_EXCEPTION);
3796      }
3797
3798      if (result == null)
3799      {
3800        logNullResult(extendedOperation, p, ERR_PLUGIN_POST_RESPONSE_PLUGIN_RETURNED_NULL);
3801      }
3802      else if (!result.continuePluginProcessing())
3803      {
3804        return result;
3805      }
3806    }
3807
3808    if (result == null)
3809    {
3810      // This should only happen if there were no post-response add plugins
3811      // registered, which is fine.
3812      result = PluginResult.PostResponse.continueOperationProcessing();
3813    }
3814
3815    return result;
3816  }
3817
3818
3819
3820  /**
3821   * Invokes the set of post-response modify plugins that have been configured
3822   * in the Directory Server.
3823   *
3824   * @param  modifyOperation  The modify operation for which to invoke the
3825   *                          post-response plugins.
3826   *
3827   * @return  The result of processing the post-response modify plugins.
3828   */
3829  public PluginResult.PostResponse invokePostResponseModifyPlugins(
3830                                  PostResponseModifyOperation modifyOperation)
3831  {
3832    PluginResult.PostResponse result = null;
3833
3834    for (DirectoryServerPlugin p : postResponseModifyPlugins)
3835    {
3836      if (isInternalOperation(modifyOperation, p))
3837      {
3838        continue;
3839      }
3840
3841      try
3842      {
3843        result = p.doPostResponse(modifyOperation);
3844      }
3845      catch (Exception e)
3846      {
3847        logException(modifyOperation, p, e, ERR_PLUGIN_POST_RESPONSE_PLUGIN_EXCEPTION);
3848      }
3849
3850      if (result == null)
3851      {
3852        logNullResult(modifyOperation, p, ERR_PLUGIN_POST_RESPONSE_PLUGIN_RETURNED_NULL);
3853      }
3854      else if (!result.continuePluginProcessing())
3855      {
3856        return result;
3857      }
3858    }
3859
3860    if (result == null)
3861    {
3862      // This should only happen if there were no post-response add plugins
3863      // registered, which is fine.
3864      result = PluginResult.PostResponse.continueOperationProcessing();
3865    }
3866
3867    return result;
3868  }
3869
3870
3871
3872  /**
3873   * Invokes the set of post-response modify DN plugins that have been
3874   * configured in the Directory Server.
3875   *
3876   * @param  modifyDNOperation  The modify DN operation for which to invoke the
3877   *                            post-response plugins.
3878   *
3879   * @return  The result of processing the post-response modify DN plugins.
3880   */
3881  public PluginResult.PostResponse invokePostResponseModifyDNPlugins(
3882                               PostResponseModifyDNOperation modifyDNOperation)
3883  {
3884    PluginResult.PostResponse result = null;
3885
3886    for (DirectoryServerPlugin p : postResponseModifyDNPlugins)
3887    {
3888      if (isInternalOperation(modifyDNOperation, p))
3889      {
3890        continue;
3891      }
3892
3893      try
3894      {
3895        result = p.doPostResponse(modifyDNOperation);
3896      }
3897      catch (Exception e)
3898      {
3899        logException(modifyDNOperation, p, e, ERR_PLUGIN_POST_RESPONSE_PLUGIN_EXCEPTION);
3900      }
3901
3902      if (result == null)
3903      {
3904        logNullResult(modifyDNOperation, p, ERR_PLUGIN_POST_RESPONSE_PLUGIN_RETURNED_NULL);
3905      }
3906      else if (!result.continuePluginProcessing())
3907      {
3908        return result;
3909      }
3910    }
3911
3912    if (result == null)
3913    {
3914      // This should only happen if there were no post-response add plugins
3915      // registered, which is fine.
3916      result = PluginResult.PostResponse.continueOperationProcessing();
3917    }
3918
3919    return result;
3920  }
3921
3922
3923
3924  /**
3925   * Invokes the set of post-response search plugins that have been configured
3926   * in the Directory Server.
3927   *
3928   * @param  searchOperation  The search operation for which to invoke the
3929   *                          post-response plugins.
3930   *
3931   * @return  The result of processing the post-response search plugins.
3932   */
3933  public PluginResult.PostResponse invokePostResponseSearchPlugins(
3934                                  PostResponseSearchOperation searchOperation)
3935  {
3936    PluginResult.PostResponse result = null;
3937
3938    for (DirectoryServerPlugin p : postResponseSearchPlugins)
3939    {
3940      if (isInternalOperation(searchOperation, p))
3941      {
3942        continue;
3943      }
3944
3945      try
3946      {
3947        result = p.doPostResponse(searchOperation);
3948      }
3949      catch (Exception e)
3950      {
3951        logException(searchOperation, p, e, ERR_PLUGIN_POST_RESPONSE_PLUGIN_EXCEPTION);
3952      }
3953
3954      if (result == null)
3955      {
3956        logNullResult(searchOperation, p, ERR_PLUGIN_POST_RESPONSE_PLUGIN_RETURNED_NULL);
3957      }
3958      else if (!result.continuePluginProcessing())
3959      {
3960        return result;
3961      }
3962    }
3963
3964    if (result == null)
3965    {
3966      // This should only happen if there were no post-response add plugins
3967      // registered, which is fine.
3968      result = PluginResult.PostResponse.continueOperationProcessing();
3969    }
3970
3971    return result;
3972  }
3973
3974  private void logException(PluginOperation op, DirectoryServerPlugin p, Exception e,
3975      Arg5<Object, Object, Number, Number, Object> errorMsg)
3976  {
3977    logger.traceException(e);
3978    logger.error(errorMsg,
3979            op.getOperationType().getOperationName(),
3980            p.getPluginEntryDN(),
3981            op.getConnectionID(), op.getOperationID(),
3982            stackTraceToSingleLineString(e));
3983  }
3984
3985  private void logNullResult(PluginOperation op, DirectoryServerPlugin p,
3986      Arg4<Object, Object, Number, Number> nullResultMsg)
3987  {
3988    logger.error(nullResultMsg,
3989            op.getOperationType().getOperationName(),
3990            p.getPluginEntryDN(),
3991            op.getConnectionID(), op.getOperationID());
3992  }
3993
3994  /**
3995   * Invokes the set of post-synchronization add plugins that have been
3996   * configured in the Directory Server.
3997   *
3998   * @param  addOperation  The add operation for which to invoke the
3999   *                       post-synchronization plugins.
4000   */
4001  public void invokePostSynchronizationAddPlugins(
4002                   PostSynchronizationAddOperation addOperation)
4003  {
4004    for (DirectoryServerPlugin p : postSynchronizationAddPlugins)
4005    {
4006      try
4007      {
4008        p.doPostSynchronization(addOperation);
4009      }
4010      catch (Exception e)
4011      {
4012        logException(addOperation, p, e, ERR_PLUGIN_POST_SYNCHRONIZATION_PLUGIN_EXCEPTION);
4013      }
4014    }
4015  }
4016
4017
4018
4019  /**
4020   * Invokes the set of post-synchronization delete plugins that have been
4021   * configured in the Directory Server.
4022   *
4023   * @param  deleteOperation  The delete operation for which to invoke the
4024   *                          post-synchronization plugins.
4025   */
4026  public void invokePostSynchronizationDeletePlugins(
4027                   PostSynchronizationDeleteOperation deleteOperation)
4028  {
4029    for (DirectoryServerPlugin p : postSynchronizationDeletePlugins)
4030    {
4031      try
4032      {
4033        p.doPostSynchronization(deleteOperation);
4034      }
4035      catch (Exception e)
4036      {
4037        logException(deleteOperation, p, e, ERR_PLUGIN_POST_SYNCHRONIZATION_PLUGIN_EXCEPTION);
4038      }
4039    }
4040  }
4041
4042  /**
4043   * Invokes the set of post-synchronization modify plugins that have been
4044   * configured in the Directory Server.
4045   *
4046   * @param  modifyOperation  The modify operation for which to invoke the
4047   *                          post-synchronization plugins.
4048   */
4049  public void invokePostSynchronizationModifyPlugins(
4050                   PostSynchronizationModifyOperation modifyOperation)
4051  {
4052    for (DirectoryServerPlugin p : postSynchronizationModifyPlugins)
4053    {
4054      try
4055      {
4056        p.doPostSynchronization(modifyOperation);
4057      }
4058      catch (Exception e)
4059      {
4060        logException(modifyOperation, p, e, ERR_PLUGIN_POST_SYNCHRONIZATION_PLUGIN_EXCEPTION);
4061      }
4062    }
4063  }
4064
4065
4066
4067  /**
4068   * Invokes the set of post-synchronization modify DN plugins that have been
4069   * configured in the Directory Server.
4070   *
4071   * @param  modifyDNOperation  The modify DN operation for which to invoke the
4072   *                            post-synchronization plugins.
4073   */
4074  public void invokePostSynchronizationModifyDNPlugins(
4075                   PostSynchronizationModifyDNOperation modifyDNOperation)
4076  {
4077    for (DirectoryServerPlugin p : postSynchronizationModifyDNPlugins)
4078    {
4079      try
4080      {
4081        p.doPostSynchronization(modifyDNOperation);
4082      }
4083      catch (Exception e)
4084      {
4085        logException(modifyDNOperation, p, e, ERR_PLUGIN_POST_SYNCHRONIZATION_PLUGIN_EXCEPTION);
4086      }
4087    }
4088  }
4089
4090
4091
4092  /**
4093   * Invokes the set of search result entry plugins that have been configured
4094   * in the Directory Server.
4095   *
4096   * @param  searchOperation  The search operation for which to invoke the
4097   *                          search result entry plugins.
4098   * @param  searchEntry      The search result entry to be processed.
4099   *
4100   * @return  The result of processing the search result entry plugins.
4101   */
4102  public PluginResult.IntermediateResponse invokeSearchResultEntryPlugins(
4103      SearchEntrySearchOperation searchOperation,
4104      SearchResultEntry searchEntry)
4105  {
4106    PluginResult.IntermediateResponse result = null;
4107
4108    for (DirectoryServerPlugin p : searchResultEntryPlugins)
4109    {
4110      if (isInternalOperation(searchOperation, p))
4111      {
4112        continue;
4113      }
4114
4115      try
4116      {
4117        result = p.processSearchEntry(searchOperation, searchEntry);
4118      }
4119      catch (Exception e)
4120      {
4121        logger.traceException(e);
4122
4123        LocalizableMessage message = ERR_PLUGIN_SEARCH_ENTRY_PLUGIN_EXCEPTION.
4124            get(p.getPluginEntryDN(),
4125                searchOperation.getConnectionID(),
4126                searchOperation.getOperationID(),
4127                searchEntry.getName(),
4128                stackTraceToSingleLineString(e));
4129        logger.error(message);
4130
4131        return PluginResult.IntermediateResponse.stopProcessing(false,
4132            DirectoryServer.getServerErrorResultCode(), message);
4133      }
4134
4135      if (result == null)
4136      {
4137        LocalizableMessage message = ERR_PLUGIN_SEARCH_ENTRY_PLUGIN_RETURNED_NULL.
4138            get(p.getPluginEntryDN(),
4139                searchOperation.getConnectionID(),
4140                searchOperation.getOperationID(),
4141                searchEntry.getName());
4142        logger.error(message);
4143
4144        return PluginResult.IntermediateResponse.stopProcessing(false,
4145            DirectoryServer.getServerErrorResultCode(), message);
4146      }
4147      else if (! result.continuePluginProcessing())
4148      {
4149        return result;
4150      }
4151    }
4152
4153    if (result == null)
4154    {
4155      // This should only happen if there were no search result entry plugins
4156      // registered, which is fine.
4157      result =
4158          PluginResult.IntermediateResponse.continueOperationProcessing(true);
4159    }
4160
4161    return result;
4162  }
4163
4164
4165
4166  /**
4167   * Invokes the set of search result reference plugins that have been
4168   * configured in the Directory Server.
4169   *
4170   * @param  searchOperation  The search operation for which to invoke the
4171   *                          search result reference plugins.
4172   * @param  searchReference  The search result reference to be processed.
4173   *
4174   * @return  The result of processing the search result reference plugins.
4175   */
4176  public PluginResult.IntermediateResponse invokeSearchResultReferencePlugins(
4177      SearchReferenceSearchOperation searchOperation,
4178      SearchResultReference searchReference)
4179  {
4180    PluginResult.IntermediateResponse result = null;
4181
4182    for (DirectoryServerPlugin p : searchResultReferencePlugins)
4183    {
4184      if (isInternalOperation(searchOperation, p))
4185      {
4186        continue;
4187      }
4188
4189      try
4190      {
4191        result = p.processSearchReference(searchOperation, searchReference);
4192      }
4193      catch (Exception e)
4194      {
4195        logger.traceException(e);
4196
4197        LocalizableMessage message = ERR_PLUGIN_SEARCH_REFERENCE_PLUGIN_EXCEPTION.
4198            get(p.getPluginEntryDN(),
4199                searchOperation.getConnectionID(),
4200                searchOperation.getOperationID(),
4201                searchReference.getReferralURLString(),
4202                stackTraceToSingleLineString(e));
4203        logger.error(message);
4204
4205        return PluginResult.IntermediateResponse.stopProcessing(false,
4206            DirectoryServer.getServerErrorResultCode(), message);
4207      }
4208
4209      if (result == null)
4210      {
4211        LocalizableMessage message = ERR_PLUGIN_SEARCH_REFERENCE_PLUGIN_RETURNED_NULL.
4212            get(p.getPluginEntryDN(),
4213                searchOperation.getConnectionID(),
4214                searchOperation.getOperationID(),
4215                searchReference.getReferralURLString());
4216        logger.error(message);
4217
4218        return PluginResult.IntermediateResponse.stopProcessing(false,
4219            DirectoryServer.getServerErrorResultCode(), message);
4220      }
4221      else if (! result.continuePluginProcessing())
4222      {
4223        return result;
4224      }
4225    }
4226
4227    if (result == null)
4228    {
4229      // This should only happen if there were no search result reference
4230      // plugins registered, which is fine.
4231      result =
4232          PluginResult.IntermediateResponse.continueOperationProcessing(true);
4233    }
4234
4235    return result;
4236  }
4237
4238
4239
4240  /**
4241   * Invokes the set of subordinate modify DN plugins that have been configured
4242   * in the Directory Server.
4243   *
4244   * @param  modifyDNOperation  The modify DN operation with which the
4245   *                            subordinate entry is associated.
4246   * @param  oldEntry           The subordinate entry prior to the move/rename
4247   *                            operation.
4248   * @param  newEntry           The subordinate entry after the move/rename
4249   *                            operation.
4250   * @param  modifications      A list into which any modifications made to the
4251   *                            target entry should be placed.
4252   *
4253   * @return  The result of processing the subordinate modify DN plugins.
4254   */
4255  public PluginResult.SubordinateModifyDN invokeSubordinateModifyDNPlugins(
4256              SubordinateModifyDNOperation modifyDNOperation, Entry oldEntry,
4257              Entry newEntry, List<Modification> modifications)
4258  {
4259    PluginResult.SubordinateModifyDN result = null;
4260
4261    for (DirectoryServerPlugin p : subordinateModifyDNPlugins)
4262    {
4263      if (isInternalOperation(modifyDNOperation, p))
4264      {
4265        continue;
4266      }
4267
4268      try
4269      {
4270        result = p.processSubordinateModifyDN(modifyDNOperation, oldEntry,
4271                                               newEntry, modifications);
4272      }
4273      catch (Exception e)
4274      {
4275        logger.traceException(e);
4276
4277        LocalizableMessage message =
4278            ERR_PLUGIN_SUBORDINATE_MODIFY_DN_PLUGIN_EXCEPTION.get(
4279                p.getPluginEntryDN(),
4280                modifyDNOperation.getConnectionID(),
4281                modifyDNOperation.getOperationID(),
4282                stackTraceToSingleLineString(e));
4283        logger.error(message);
4284
4285        return PluginResult.SubordinateModifyDN.stopProcessing(
4286            DirectoryServer.getServerErrorResultCode(), message);
4287      }
4288
4289      if (result == null)
4290      {
4291        LocalizableMessage message =
4292            ERR_PLUGIN_SUBORDINATE_MODIFY_DN_PLUGIN_RETURNED_NULL.get(
4293                        p.getPluginEntryDN(),
4294                        modifyDNOperation.getConnectionID(),
4295                        modifyDNOperation.getOperationID());
4296        logger.error(message);
4297
4298        return PluginResult.SubordinateModifyDN.stopProcessing(
4299            DirectoryServer.getServerErrorResultCode(), message);
4300      }
4301      else if (! result.continuePluginProcessing())
4302      {
4303        return result;
4304      }
4305    }
4306
4307    if (result == null)
4308    {
4309      // This should only happen if there were no subordinate modify DN plugins
4310      // registered, which is fine.
4311      result = PluginResult.SubordinateModifyDN.continueOperationProcessing();
4312    }
4313
4314    return result;
4315  }
4316
4317
4318
4319  /**
4320   * Invokes the set of subordinate delete plugins that have been configured
4321   * in the Directory Server.
4322   *
4323   * @param  deleteOperation  The delete operation with which the
4324   *                          subordinate entry is associated.
4325   * @param  entry            The subordinate entry being deleted.
4326   *
4327   * @return The result of processing the subordinate delete plugins.
4328   */
4329  public PluginResult.SubordinateDelete invokeSubordinateDeletePlugins(
4330              DeleteOperation deleteOperation, Entry entry)
4331  {
4332    PluginResult.SubordinateDelete result = null;
4333
4334    for (DirectoryServerPlugin p : subordinateDeletePlugins)
4335    {
4336      if (deleteOperation.isInternalOperation() && !p.invokeForInternalOperations())
4337      {
4338        continue;
4339      }
4340
4341      try
4342      {
4343        result = p.processSubordinateDelete(deleteOperation, entry);
4344      }
4345      catch (Exception e)
4346      {
4347        logger.traceException(e);
4348
4349        LocalizableMessage message =
4350            ERR_PLUGIN_SUBORDINATE_DELETE_PLUGIN_EXCEPTION.get(
4351                p.getPluginEntryDN(),
4352                deleteOperation.getConnectionID(),
4353                deleteOperation.getOperationID(),
4354                stackTraceToSingleLineString(e));
4355        logger.error(message);
4356
4357        return PluginResult.SubordinateDelete.stopProcessing(
4358            DirectoryServer.getServerErrorResultCode(), message);
4359      }
4360
4361      if (result == null)
4362      {
4363        LocalizableMessage message =
4364            ERR_PLUGIN_SUBORDINATE_DELETE_PLUGIN_RETURNED_NULL.get(
4365                        p.getPluginEntryDN(),
4366                        deleteOperation.getConnectionID(),
4367                        deleteOperation.getOperationID());
4368        logger.error(message);
4369
4370        return PluginResult.SubordinateDelete.stopProcessing(
4371            DirectoryServer.getServerErrorResultCode(), message);
4372      }
4373      else if (! result.continuePluginProcessing())
4374      {
4375        return result;
4376      }
4377    }
4378
4379    if (result == null)
4380    {
4381      // This should only happen if there were no subordinate modify DN plugins
4382      // registered, which is fine.
4383      result = PluginResult.SubordinateDelete.continueOperationProcessing();
4384    }
4385
4386    return result;
4387  }
4388
4389
4390
4391  /**
4392   * Invokes the set of intermediate response plugins that have been configured
4393   * in the Directory Server.
4394   *
4395   * @param  intermediateResponse  The intermediate response for which to invoke
4396   *                               the intermediate response plugins.
4397   *
4398   * @return  The result of processing the intermediate response plugins.
4399   */
4400  public PluginResult.IntermediateResponse
4401              invokeIntermediateResponsePlugins(
4402                   IntermediateResponse intermediateResponse)
4403  {
4404    PluginResult.IntermediateResponse result = null;
4405    Operation operation = intermediateResponse.getOperation();
4406
4407    for (DirectoryServerPlugin p : intermediateResponsePlugins)
4408    {
4409      try
4410      {
4411        result = p.processIntermediateResponse(intermediateResponse);
4412      }
4413      catch (Exception e)
4414      {
4415        logger.traceException(e);
4416
4417        LocalizableMessage message = ERR_PLUGIN_INTERMEDIATE_RESPONSE_PLUGIN_EXCEPTION.
4418            get(p.getPluginEntryDN(),
4419                operation.getConnectionID(), operation.getOperationID(),
4420                stackTraceToSingleLineString(e));
4421        logger.error(message);
4422
4423        return PluginResult.IntermediateResponse.stopProcessing
4424            (false, DirectoryServer.getServerErrorResultCode(), message);
4425      }
4426
4427      if (result == null)
4428      {
4429        LocalizableMessage message = ERR_PLUGIN_INTERMEDIATE_RESPONSE_PLUGIN_RETURNED_NULL.
4430            get(p.getPluginEntryDN(),
4431                operation.getConnectionID(), operation.getOperationID());
4432        logger.error(message);
4433
4434        return PluginResult.IntermediateResponse.stopProcessing
4435            (false, DirectoryServer.getServerErrorResultCode(), message);
4436      }
4437      else if (! result.continuePluginProcessing())
4438      {
4439        return result;
4440      }
4441    }
4442
4443    if (result == null)
4444    {
4445      // This should only happen if there were no intermediate response plugins
4446      // registered, which is fine.WARN
4447
4448      result =
4449          PluginResult.IntermediateResponse.continueOperationProcessing(true);
4450    }
4451
4452    return result;
4453  }
4454
4455
4456
4457  /** {@inheritDoc} */
4458  @Override
4459  public boolean isConfigurationAddAcceptable(PluginCfg configuration,
4460                                              List<LocalizableMessage> unacceptableReasons)
4461  {
4462    if (configuration.isEnabled())
4463    {
4464      HashSet<PluginType> pluginTypes = getPluginTypes(configuration);
4465
4466      // Get the name of the class and make sure we can instantiate it as a plugin.
4467      String className = configuration.getJavaClass();
4468      try
4469      {
4470        loadPlugin(className, pluginTypes, configuration, false);
4471      }
4472      catch (InitializationException ie)
4473      {
4474        unacceptableReasons.add(ie.getMessageObject());
4475        return false;
4476      }
4477    }
4478
4479    // If we've gotten here, then it's fine.
4480    return true;
4481  }
4482
4483
4484
4485  /** {@inheritDoc} */
4486  @Override
4487  public ConfigChangeResult applyConfigurationAdd(
4488                                 PluginCfg configuration)
4489  {
4490    final ConfigChangeResult ccr = new ConfigChangeResult();
4491
4492    configuration.addChangeListener(this);
4493
4494    if (! configuration.isEnabled())
4495    {
4496      return ccr;
4497    }
4498
4499    HashSet<PluginType> pluginTypes = getPluginTypes(configuration);
4500
4501    // Get the name of the class and make sure we can instantiate it as a plugin.
4502    DirectoryServerPlugin<? extends PluginCfg> plugin = null;
4503    String className = configuration.getJavaClass();
4504    try
4505    {
4506      plugin = loadPlugin(className, pluginTypes, configuration, true);
4507    }
4508    catch (InitializationException ie)
4509    {
4510      ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode());
4511      ccr.addMessage(ie.getMessageObject());
4512    }
4513
4514    if (ccr.getResultCode() == ResultCode.SUCCESS)
4515    {
4516      registerPlugin(plugin, configuration.dn(), pluginTypes);
4517    }
4518
4519    return ccr;
4520  }
4521
4522
4523
4524  /** {@inheritDoc} */
4525  @Override
4526  public boolean isConfigurationDeleteAcceptable(
4527                      PluginCfg configuration,
4528                      List<LocalizableMessage> unacceptableReasons)
4529  {
4530    // We will always allow plugins to be removed.
4531    return true;
4532  }
4533
4534
4535
4536  /** {@inheritDoc} */
4537  @Override
4538  public ConfigChangeResult applyConfigurationDelete(
4539                                 PluginCfg configuration)
4540  {
4541    final ConfigChangeResult ccr = new ConfigChangeResult();
4542
4543    deregisterPlugin(configuration.dn());
4544
4545    return ccr;
4546  }
4547
4548
4549
4550  /** {@inheritDoc} */
4551  @Override
4552  public boolean isConfigurationChangeAcceptable(
4553                      PluginCfg configuration,
4554                      List<LocalizableMessage> unacceptableReasons)
4555  {
4556    if (configuration.isEnabled())
4557    {
4558      HashSet<PluginType> pluginTypes = getPluginTypes(configuration);
4559
4560      // Get the name of the class and make sure we can instantiate it as a plugin.
4561      String className = configuration.getJavaClass();
4562      try
4563      {
4564        loadPlugin(className, pluginTypes, configuration, false);
4565      }
4566      catch (InitializationException ie)
4567      {
4568        unacceptableReasons.add(ie.getMessageObject());
4569        return false;
4570      }
4571    }
4572
4573    // If we've gotten here, then it's fine.
4574    return true;
4575  }
4576
4577
4578
4579  /** {@inheritDoc} */
4580  @Override
4581  public ConfigChangeResult applyConfigurationChange(
4582                                 PluginCfg configuration)
4583  {
4584    final ConfigChangeResult ccr = new ConfigChangeResult();
4585
4586
4587    // Get the existing plugin if it's already enabled.
4588    DirectoryServerPlugin existingPlugin =
4589         registeredPlugins.get(configuration.dn());
4590
4591
4592    // If the new configuration has the plugin disabled, then deregister it if
4593    // it is enabled, or do nothing if it's already disabled.
4594    if (! configuration.isEnabled())
4595    {
4596      if (existingPlugin != null)
4597      {
4598        deregisterPlugin(configuration.dn());
4599      }
4600
4601      return ccr;
4602    }
4603
4604
4605    // Get the class for the identity mapper.  If the mapper is already enabled,
4606    // then we shouldn't do anything with it although if the class has changed
4607    // then we'll at least need to indicate that administrative action is
4608    // required.  If the mapper is disabled, then instantiate the class and
4609    // initialize and register it as an identity mapper.  Also, update the
4610    // plugin to indicate whether it should be invoked for internal operations.
4611    String className = configuration.getJavaClass();
4612    if (existingPlugin != null)
4613    {
4614      if (! className.equals(existingPlugin.getClass().getName()))
4615      {
4616        ccr.setAdminActionRequired(true);
4617      }
4618
4619      existingPlugin.setInvokeForInternalOperations(
4620                          configuration.isInvokeForInternalOperations());
4621
4622      return ccr;
4623    }
4624
4625    // Create a set of plugin types for the plugin.
4626    HashSet<PluginType> pluginTypes = getPluginTypes(configuration);
4627
4628    DirectoryServerPlugin<? extends PluginCfg> plugin = null;
4629    try
4630    {
4631      plugin = loadPlugin(className, pluginTypes, configuration, true);
4632    }
4633    catch (InitializationException ie)
4634    {
4635      ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode());
4636      ccr.addMessage(ie.getMessageObject());
4637    }
4638
4639    if (ccr.getResultCode() == ResultCode.SUCCESS)
4640    {
4641      registerPlugin(plugin, configuration.dn(), pluginTypes);
4642    }
4643
4644    return ccr;
4645  }
4646
4647  private HashSet<PluginType> getPluginTypes(PluginCfg configuration)
4648  {
4649    HashSet<PluginType> pluginTypes = new HashSet<>();
4650    for (PluginCfgDefn.PluginType pluginType : configuration.getPluginType())
4651    {
4652      pluginTypes.add(getPluginType(pluginType));
4653    }
4654    return pluginTypes;
4655  }
4656
4657  private void registerSkippedPreOperationPlugins(int i,
4658                                                DirectoryServerPlugin[] plugins,
4659                                                 PluginOperation operation)
4660  {
4661    ArrayList<DirectoryServerPlugin> skippedPlugins = new ArrayList<>(plugins.length - i);
4662    for(int j = i; j < plugins.length; j++)
4663    {
4664      skippedPlugins.add(plugins[j]);
4665    }
4666    skippedPreOperationPlugins.put(operation, skippedPlugins);
4667  }
4668
4669  private void registerSkippedPreOperationPlugin(DirectoryServerPlugin plugin,
4670                                                 PluginOperation operation)
4671  {
4672    ArrayList<DirectoryServerPlugin> existingList =
4673        skippedPreOperationPlugins.get(operation);
4674    if(existingList == null)
4675    {
4676      existingList = new ArrayList<>();
4677    }
4678    existingList.add(plugin);
4679    skippedPreOperationPlugins.put(operation, existingList);
4680  }
4681}