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