001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2010-2015 ForgeRock AS.
026 */
027package org.opends.server.core;
028
029import static org.forgerock.util.Reject.*;
030import static org.opends.messages.CoreMessages.*;
031import static org.opends.messages.ToolMessages.*;
032import static org.opends.server.config.ConfigConstants.*;
033import static org.opends.server.schema.SchemaConstants.*;
034import static org.opends.server.tools.ConfigureWindowsService.*;
035import static org.opends.server.util.CollectionUtils.*;
036import static org.opends.server.util.DynamicConstants.*;
037import static org.opends.server.util.ServerConstants.*;
038import static org.opends.server.util.StaticUtils.*;
039
040import java.io.File;
041import java.io.FileOutputStream;
042import java.io.IOException;
043import java.io.OutputStream;
044import java.io.PrintStream;
045import java.lang.management.ManagementFactory;
046import java.net.InetAddress;
047import java.text.DecimalFormat;
048import java.util.Collection;
049import java.util.Collections;
050import java.util.LinkedHashMap;
051import java.util.LinkedHashSet;
052import java.util.LinkedList;
053import java.util.List;
054import java.util.Map;
055import java.util.Properties;
056import java.util.Set;
057import java.util.TreeMap;
058import java.util.TreeSet;
059import java.util.concurrent.ConcurrentHashMap;
060import java.util.concurrent.ConcurrentMap;
061import java.util.concurrent.CopyOnWriteArrayList;
062import java.util.concurrent.CopyOnWriteArraySet;
063import java.util.concurrent.atomic.AtomicInteger;
064
065import javax.management.MBeanServer;
066import javax.management.MBeanServerFactory;
067
068import org.forgerock.i18n.LocalizableMessage;
069import org.forgerock.i18n.slf4j.LocalizedLogger;
070import org.forgerock.opendj.config.server.ConfigException;
071import org.forgerock.opendj.ldap.ResultCode;
072import org.forgerock.opendj.ldap.schema.AttributeUsage;
073import org.forgerock.opendj.ldap.schema.CoreSchema;
074import org.forgerock.opendj.ldap.schema.MatchingRule;
075import org.forgerock.opendj.ldap.schema.ObjectClassType;
076import org.forgerock.opendj.ldap.schema.SchemaBuilder;
077import org.forgerock.opendj.ldap.schema.Syntax;
078import org.forgerock.util.Reject;
079import org.forgerock.util.Utils;
080import org.opends.server.admin.AdministrationConnector;
081import org.opends.server.admin.AdministrationDataSync;
082import org.opends.server.admin.ClassLoaderProvider;
083import org.opends.server.admin.server.ServerManagementContext;
084import org.opends.server.admin.std.server.AlertHandlerCfg;
085import org.opends.server.admin.std.server.ConnectionHandlerCfg;
086import org.opends.server.admin.std.server.CryptoManagerCfg;
087import org.opends.server.admin.std.server.MonitorProviderCfg;
088import org.opends.server.admin.std.server.PasswordValidatorCfg;
089import org.opends.server.admin.std.server.RootCfg;
090import org.opends.server.admin.std.server.RootDSEBackendCfg;
091import org.opends.server.admin.std.server.SynchronizationProviderCfg;
092import org.opends.server.api.AccessControlHandler;
093import org.opends.server.api.AccountStatusNotificationHandler;
094import org.opends.server.api.AlertGenerator;
095import org.opends.server.api.AlertHandler;
096import org.opends.server.api.AuthenticationPolicy;
097import org.opends.server.api.Backend;
098import org.opends.server.api.BackendInitializationListener;
099import org.opends.server.api.BackupTaskListener;
100import org.opends.server.api.CertificateMapper;
101import org.opends.server.api.ClientConnection;
102import org.opends.server.api.CompressedSchema;
103import org.opends.server.api.ConfigAddListener;
104import org.opends.server.api.ConfigChangeListener;
105import org.opends.server.api.ConfigDeleteListener;
106import org.opends.server.api.ConfigHandler;
107import org.opends.server.api.ConnectionHandler;
108import org.opends.server.api.DirectoryServerMBean;
109import org.opends.server.api.EntryCache;
110import org.opends.server.api.ExportTaskListener;
111import org.opends.server.api.ExtendedOperationHandler;
112import org.opends.server.api.IdentityMapper;
113import org.opends.server.api.ImportTaskListener;
114import org.opends.server.api.InitializationCompletedListener;
115import org.opends.server.api.InvokableComponent;
116import org.opends.server.api.KeyManagerProvider;
117import org.opends.server.api.MatchingRuleFactory;
118import org.opends.server.api.MonitorProvider;
119import org.opends.server.api.PasswordGenerator;
120import org.opends.server.api.PasswordStorageScheme;
121import org.opends.server.api.PasswordValidator;
122import org.opends.server.api.RestoreTaskListener;
123import org.opends.server.api.SASLMechanismHandler;
124import org.opends.server.api.ServerShutdownListener;
125import org.opends.server.api.SynchronizationProvider;
126import org.opends.server.api.TrustManagerProvider;
127import org.opends.server.api.WorkQueue;
128import org.opends.server.api.plugin.InternalDirectoryServerPlugin;
129import org.opends.server.api.plugin.PluginResult;
130import org.opends.server.api.plugin.PluginType;
131import org.opends.server.backends.RootDSEBackend;
132import org.opends.server.config.ConfigEntry;
133import org.opends.server.config.JMXMBean;
134import org.opends.server.controls.PasswordPolicyErrorType;
135import org.opends.server.controls.PasswordPolicyResponseControl;
136import org.opends.server.crypto.CryptoManagerImpl;
137import org.opends.server.crypto.CryptoManagerSync;
138import org.opends.server.extensions.ConfigFileHandler;
139import org.opends.server.extensions.DiskSpaceMonitor;
140import org.opends.server.extensions.JMXAlertHandler;
141import org.opends.server.loggers.AccessLogger;
142import org.opends.server.loggers.DebugLogPublisher;
143import org.opends.server.loggers.DebugLogger;
144import org.opends.server.loggers.ErrorLogPublisher;
145import org.opends.server.loggers.ErrorLogger;
146import org.opends.server.loggers.RetentionPolicy;
147import org.opends.server.loggers.RotationPolicy;
148import org.opends.server.loggers.TextErrorLogPublisher;
149import org.opends.server.loggers.TextWriter;
150import org.opends.server.monitors.BackendMonitor;
151import org.opends.server.monitors.ConnectionHandlerMonitor;
152import org.opends.server.protocols.internal.InternalClientConnection;
153import org.opends.server.protocols.internal.InternalConnectionHandler;
154import org.opends.server.schema.BooleanEqualityMatchingRuleFactory;
155import org.opends.server.schema.CaseExactEqualityMatchingRuleFactory;
156import org.opends.server.schema.CaseExactIA5EqualityMatchingRuleFactory;
157import org.opends.server.schema.CaseExactIA5SubstringMatchingRuleFactory;
158import org.opends.server.schema.CaseExactOrderingMatchingRuleFactory;
159import org.opends.server.schema.CaseExactSubstringMatchingRuleFactory;
160import org.opends.server.schema.CaseIgnoreEqualityMatchingRuleFactory;
161import org.opends.server.schema.CaseIgnoreIA5EqualityMatchingRuleFactory;
162import org.opends.server.schema.CaseIgnoreIA5SubstringMatchingRuleFactory;
163import org.opends.server.schema.CaseIgnoreOrderingMatchingRuleFactory;
164import org.opends.server.schema.CaseIgnoreSubstringMatchingRuleFactory;
165import org.opends.server.schema.DistinguishedNameEqualityMatchingRuleFactory;
166import org.opends.server.schema.DoubleMetaphoneApproximateMatchingRuleFactory;
167import org.opends.server.schema.GeneralizedTimeEqualityMatchingRuleFactory;
168import org.opends.server.schema.GeneralizedTimeOrderingMatchingRuleFactory;
169import org.opends.server.schema.IntegerEqualityMatchingRuleFactory;
170import org.opends.server.schema.IntegerOrderingMatchingRuleFactory;
171import org.opends.server.schema.ObjectIdentifierEqualityMatchingRuleFactory;
172import org.opends.server.schema.OctetStringEqualityMatchingRuleFactory;
173import org.opends.server.schema.OctetStringOrderingMatchingRuleFactory;
174import org.opends.server.schema.OctetStringSubstringMatchingRuleFactory;
175import org.opends.server.schema.SchemaUpdater;
176import org.opends.server.schema.TelephoneNumberEqualityMatchingRuleFactory;
177import org.opends.server.schema.TelephoneNumberSubstringMatchingRuleFactory;
178import org.opends.server.types.AcceptRejectWarn;
179import org.opends.server.types.AttributeType;
180import org.opends.server.types.BackupConfig;
181import org.opends.server.types.Control;
182import org.opends.server.types.DITContentRule;
183import org.opends.server.types.DITStructureRule;
184import org.opends.server.types.DN;
185import org.opends.server.types.DirectoryEnvironmentConfig;
186import org.opends.server.types.DirectoryException;
187import org.opends.server.types.Entry;
188import org.opends.server.types.HostPort;
189import org.opends.server.types.InitializationException;
190import org.opends.server.types.LDIFExportConfig;
191import org.opends.server.types.LDIFImportConfig;
192import org.opends.server.types.LockManager;
193import org.opends.server.types.MatchingRuleUse;
194import org.opends.server.types.Modification;
195import org.opends.server.types.NameForm;
196import org.opends.server.types.ObjectClass;
197import org.opends.server.types.Operation;
198import org.opends.server.types.Privilege;
199import org.opends.server.types.RestoreConfig;
200import org.opends.server.types.Schema;
201import org.opends.server.types.VirtualAttributeRule;
202import org.opends.server.types.WritabilityMode;
203import org.opends.server.util.ActivateOnceNewConfigFrameworkIsUsed;
204import org.opends.server.util.ActivateOnceSDKSchemaIsUsed;
205import org.opends.server.util.BuildVersion;
206import org.opends.server.util.MultiOutputStream;
207import org.opends.server.util.RemoveOnceSDKSchemaIsUsed;
208import org.opends.server.util.RuntimeInformation;
209import org.opends.server.util.SetupUtils;
210import org.opends.server.util.TimeThread;
211import org.opends.server.util.VersionCompatibilityIssue;
212import org.opends.server.workflowelement.localbackend.LocalBackendWorkflowElement;
213
214import com.forgerock.opendj.cli.ArgumentConstants;
215import com.forgerock.opendj.cli.ArgumentException;
216import com.forgerock.opendj.cli.ArgumentParser;
217import com.forgerock.opendj.cli.BooleanArgument;
218import com.forgerock.opendj.cli.CommonArguments;
219import com.forgerock.opendj.cli.IntegerArgument;
220import com.forgerock.opendj.cli.StringArgument;
221import com.forgerock.opendj.cli.VersionHandler;
222import com.forgerock.opendj.util.OperatingSystem;
223
224/**
225 * This class defines the core of the Directory Server.  It manages the startup
226 * and shutdown processes and coordinates activities between all other
227 * components.
228 */
229public final class DirectoryServer
230       implements AlertGenerator
231{
232  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
233
234  /** The singleton Directory Server instance. */
235  private static DirectoryServer directoryServer = new DirectoryServer();
236
237  /** Indicates whether the server currently holds an exclusive lock on the server lock file. */
238  private static boolean serverLocked;
239
240  /** The message to be displayed on the command-line when the user asks for the usage. */
241  private static LocalizableMessage toolDescription = INFO_DSCORE_TOOL_DESCRIPTION.get();
242
243  /**
244   * Return codes used when the hidden option --checkStartability is used.
245   * NOTE: when checkstartability is specified is recommended not to allocate
246   * a lot of memory for the JVM (Using -Xms and -Xmx options) as there might
247   * be calls to Runtime.exec.
248   */
249  /**
250   * Returned when the user specified the --checkStartability option with other
251   * options like printing the usage, dumping messages, displaying version, etc.
252   */
253  private static final int NOTHING_TO_DO = 0;
254  /**
255   * Returned when the user specified the --checkStartability option with
256   * some incompatible arguments.
257   */
258  private static final int CHECK_ERROR = 1;
259  /** The server is already started. */
260  private static final int SERVER_ALREADY_STARTED = 98;
261  /** The server must be started as detached process. */
262  private static final int START_AS_DETACH = 99;
263  /** The server must be started as a non-detached process. */
264  private static final int START_AS_NON_DETACH = 100;
265  /** The server must be started as a window service. */
266  private static final int START_AS_WINDOWS_SERVICE = 101;
267  /** The server must be started as detached and it is being called from the Windows Service. */
268  private static final int START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE = 102;
269  /** The server must be started as detached process and should not produce any output. */
270  private static final int START_AS_DETACH_QUIET = 103;
271  /** The server must be started as non-detached process and should not produce any output. */
272  private static final int START_AS_NON_DETACH_QUIET = 104;
273
274  /** Temporary context object, to provide instance methods instead of static methods. */
275  private final DirectoryServerContext serverContext;
276
277  /** The policy to use regarding single structural objectclass enforcement. */
278  private AcceptRejectWarn singleStructuralClassPolicy;
279  /** The policy to use regarding syntax enforcement. */
280  private AcceptRejectWarn syntaxEnforcementPolicy;
281
282  /** The account status notification handler config manager for the server. */
283  private AccountStatusNotificationHandlerConfigManager accountStatusNotificationHandlerConfigManager;
284
285  /** The attribute type used to reference the "objectclass" attribute. */
286  private AttributeType objectClassAttributeType;
287  /** The authenticated users manager for the server. */
288  private AuthenticatedUsers authenticatedUsers;
289  /** The configuration manager that will handle the server backends. */
290  private BackendConfigManager backendConfigManager;
291
292  /**
293   * Indicates whether to automatically add missing RDN attributes to entries
294   * during an add request.
295   */
296  private boolean addMissingRDNAttributes;
297
298  /**
299   * Indicates whether to allow attribute name exceptions (i.e., attribute names
300   * can contain underscores and may start with a digit).
301   */
302  private boolean allowAttributeNameExceptions;
303
304  /** Indicates whether a simple bind request containing a DN must also provide a password. */
305  private boolean bindWithDNRequiresPassword;
306
307  /** Indicates whether the Directory Server should perform schema checking for update operations. */
308  private boolean checkSchema;
309
310  /** Indicates whether the server has been bootstrapped. */
311  private boolean isBootstrapped;
312  /** Indicates whether the server is currently online. */
313  private boolean isRunning;
314  /** Indicates whether the server is currently in "lockdown mode". */
315  private boolean lockdownMode;
316
317  /** Indicates whether the server should send a response to operations that have been abandoned. */
318  private boolean notifyAbandonedOperations;
319
320  /** Indicates whether to save a copy of the configuration on successful startup. */
321  private boolean saveConfigOnSuccessfulStartup;
322
323  /** Indicates whether the server is currently in the process of shutting down. */
324  private boolean shuttingDown;
325
326  /** Indicates whether the server should reject unauthenticated requests. */
327  private boolean rejectUnauthenticatedRequests;
328
329  /** Indicates whether bind responses should include failure reason messages. */
330  private boolean returnBindErrorMessages;
331
332  /** The configuration manager that will handle the certificate mapper. */
333  private CertificateMapperConfigManager certificateMapperConfigManager;
334
335  /** The class used to provide the config handler implementation. */
336  private Class<ConfigHandler> configClass;
337
338  /** The configuration handler for the Directory Server. */
339  private ConfigHandler configHandler;
340
341  /** The set of account status notification handlers defined in the server. */
342  private ConcurrentMap<DN, AccountStatusNotificationHandler>
343               accountStatusNotificationHandlers;
344
345  /** The set of certificate mappers registered with the server. */
346  private ConcurrentMap<DN, CertificateMapper> certificateMappers;
347
348  /** The set of alternate bind DNs for the root users. */
349  private ConcurrentMap<DN, DN> alternateRootBindDNs;
350
351  /**
352   * The set of identity mappers registered with the server (mapped between the
353   * configuration entry Dn and the mapper).
354   */
355  private ConcurrentMap<DN, IdentityMapper> identityMappers;
356
357  /**
358   * The set of JMX MBeans that have been registered with the server (mapped
359   * between the associated configuration entry DN and the MBean).
360   */
361  private ConcurrentHashMap<DN,JMXMBean> mBeans;
362
363  /** The set of key manager providers registered with the server. */
364  private ConcurrentMap<DN, KeyManagerProvider> keyManagerProviders;
365
366  /**
367   * The set of password generators registered with the Directory Server, as a
368   * mapping between the DN of the associated configuration entry and the
369   * generator implementation.
370   */
371  private ConcurrentMap<DN, PasswordGenerator> passwordGenerators;
372
373  /**
374   * The set of authentication policies registered with the Directory Server, as
375   * a mapping between the DN of the associated configuration entry and the
376   * policy implementation.
377   */
378  private ConcurrentMap<DN, AuthenticationPolicy> authenticationPolicies;
379
380  /**
381   * The set of password validators registered with the Directory Server, as a
382   * mapping between the DN of the associated configuration entry and the
383   * validator implementation.
384   */
385  private ConcurrentMap<DN, PasswordValidator<? extends PasswordValidatorCfg>>
386               passwordValidators;
387
388  /** The set of trust manager providers registered with the server. */
389  private ConcurrentMap<DN, TrustManagerProvider> trustManagerProviders;
390
391  /**
392   * The set of log rotation policies registered with the Directory Server, as a
393   * mapping between the DN of the associated configuration entry and the policy
394   * implementation.
395   */
396  private ConcurrentMap<DN, RotationPolicy> rotationPolicies;
397
398  /**
399   * The set of log retention policies registered with the Directory Server, as
400   * a mapping between the DN of the associated configuration entry and the
401   * policy implementation.
402   */
403  private ConcurrentMap<DN, RetentionPolicy> retentionPolicies;
404
405  /** The set supported LDAP protocol versions. */
406  private ConcurrentMap<Integer, List<ConnectionHandler>>
407               supportedLDAPVersions;
408
409  /**
410   * The set of extended operation handlers registered with the server (mapped
411   * between the OID of the extended operation and the handler).
412   */
413  private ConcurrentMap<String, ExtendedOperationHandler>
414               extendedOperationHandlers;
415
416  /**
417   * The set of monitor providers registered with the Directory Server, as a
418   * mapping between the monitor name and the corresponding implementation.
419   */
420  private ConcurrentMap<String, MonitorProvider<? extends MonitorProviderCfg>>
421               monitorProviders;
422
423  /**
424   * The set of password storage schemes defined in the server (mapped between
425   * the lowercase scheme name and the storage scheme) that support the
426   * authentication password syntax.
427   */
428  private ConcurrentHashMap<String,PasswordStorageScheme>
429               authPasswordStorageSchemes;
430
431  /**
432   * The set of password storage schemes defined in the server (mapped between
433   * the lowercase scheme name and the storage scheme).
434   */
435  private ConcurrentHashMap<String,PasswordStorageScheme>
436               passwordStorageSchemes;
437
438  /**
439   * The set of password storage schemes defined in the server (mapped between
440   * the DN of the configuration entry and the storage scheme).
441   */
442  private ConcurrentMap<DN, PasswordStorageScheme>
443               passwordStorageSchemesByDN;
444
445  /**
446   * The set of SASL mechanism handlers registered with the server (mapped
447   * between the mechanism name and the handler).
448   */
449  private ConcurrentMap<String, SASLMechanismHandler> saslMechanismHandlers;
450
451  /** The connection handler configuration manager for the Directory Server. */
452  private ConnectionHandlerConfigManager connectionHandlerConfigManager;
453
454  /** The set of alert handlers registered with the Directory Server. */
455  private List<AlertHandler> alertHandlers;
456
457  /** The set of backup task listeners registered with the Directory Server. */
458  private CopyOnWriteArrayList<BackupTaskListener> backupTaskListeners;
459
460  /** The set of connection handlers registered with the Directory Server. */
461  private List<ConnectionHandler> connectionHandlers;
462
463  /** The set of export task listeners registered with the Directory Server. */
464  private CopyOnWriteArrayList<ExportTaskListener> exportTaskListeners;
465
466  /** The set of import task listeners registered with the Directory Server. */
467  private CopyOnWriteArrayList<ImportTaskListener> importTaskListeners;
468
469  /** The set of restore task listeners registered with the Directory Server. */
470  private CopyOnWriteArrayList<RestoreTaskListener> restoreTaskListeners;
471
472  /**
473   * The set of initialization completed listeners that have been registered
474   * with the Directory Server.
475   */
476  private List<InitializationCompletedListener>
477          initializationCompletedListeners;
478
479  /** The set of shutdown listeners that have been registered with the Directory Server. */
480  private List<ServerShutdownListener> shutdownListeners;
481  /** The set of synchronization providers that have been registered with the Directory Server. */
482  private List<SynchronizationProvider<SynchronizationProviderCfg>> synchronizationProviders;
483  /** The set of backend initialization listeners registered with the Directory Server. */
484  private Set<BackendInitializationListener> backendInitializationListeners;
485
486  /** The set of root DNs registered with the Directory Server. */
487  private Set<DN> rootDNs;
488
489  /** The core configuration manager for the Directory Server. */
490  private CoreConfigManager coreConfigManager;
491
492  /** The crypto manager for the Directory Server. */
493  private CryptoManagerImpl cryptoManager;
494
495  /** The default compressed schema manager. */
496  private DefaultCompressedSchema compressedSchema;
497
498  /** The environment configuration for the Directory Server. */
499  private DirectoryEnvironmentConfig environmentConfig;
500
501  /** The shutdown hook that has been registered with the server. */
502  private DirectoryServerShutdownHook shutdownHook;
503
504  /** The DN of the default password policy configuration entry. */
505  private DN defaultPasswordPolicyDN;
506
507  /**
508   * The DN of the identity mapper that will be used to resolve authorization
509   * IDs contained in the proxied authorization V2 control.
510   */
511  private DN proxiedAuthorizationIdentityMapperDN;
512
513  /** The DN of the entry containing the server schema definitions. */
514  private DN schemaDN;
515
516  /** The Directory Server entry cache. */
517  private EntryCache entryCache;
518
519  /** The configuration manager for the entry cache. */
520  private EntryCacheConfigManager entryCacheConfigManager;
521
522  /** The configuration manager for extended operation handlers. */
523  private ExtendedOperationConfigManager extendedOperationConfigManager;
524
525  /**
526   * The path to the file containing the Directory Server configuration, or the
527   * information needed to bootstrap the configuration handler.
528   */
529  private File configFile;
530
531  /** The group manager for the Directory Server. */
532  private GroupManager groupManager;
533
534  /** The subentry manager for the Directory Server. */
535  private SubentryManager subentryManager;
536
537  /** The configuration manager for identity mappers. */
538  private IdentityMapperConfigManager identityMapperConfigManager;
539
540  /**
541   * The maximum number of entries that should be returned for a search unless
542   * overridden on a per-user basis.
543   */
544  private int sizeLimit;
545
546  /**
547   * The maximum length of time in seconds that should be allowed for a search
548   * unless overridden on a per-user basis.
549   */
550  private int timeLimit;
551  /** The maximum number of candidates that should be check for matches during a search. */
552  private int lookthroughLimit;
553
554  /** The current active persistent searches. */
555  private final AtomicInteger activePSearches = new AtomicInteger(0);
556
557  /** The maximum number of concurrent persistent searches. */
558  private int maxPSearches;
559
560  /** Whether to use collect operation processing times in nanosecond resolution. */
561  private boolean useNanoTime;
562
563  /** The key manager provider configuration manager for the Directory Server. */
564  private KeyManagerProviderConfigManager keyManagerProviderConfigManager;
565
566  /** The set of connections that are currently established. */
567  private Set<ClientConnection> establishedConnections;
568
569  /** The sets of mail server properties. */
570  private List<Properties> mailServerPropertySets;
571
572  /**
573   * The set of schema changes made by editing the schema configuration files
574   * with the server offline.
575   */
576  private List<Modification> offlineSchemaChanges;
577
578  /** The log rotation policy config manager for the Directory Server. */
579  private LogRotationPolicyConfigManager rotationPolicyConfigManager;
580
581  /** The log retention policy config manager for the Directory Server. */
582  private LogRetentionPolicyConfigManager retentionPolicyConfigManager;
583
584  /** The logger configuration manager for the Directory Server. */
585  private LoggerConfigManager loggerConfigManager;
586
587  /** The number of connections currently established to the server. */
588  private long currentConnections;
589  /** The idle time limit for the server. */
590  private long idleTimeLimit;
591
592  /** The maximum number of connections that will be allowed at any given time. */
593  private long maxAllowedConnections;
594  /** The maximum number of connections established at one time. */
595  private long maxConnections;
596
597  /** The time that this Directory Server instance was started. */
598  private long startUpTime;
599
600  /** The total number of connections established since startup. */
601  private long totalConnections;
602
603  /** The MBean server used to handle JMX interaction. */
604  private MBeanServer mBeanServer;
605
606  /** The monitor config manager for the Directory Server. */
607  private MonitorConfigManager monitorConfigManager;
608
609  /** The operating system on which the server is running. */
610  private final OperatingSystem operatingSystem;
611
612  /** The configuration handler used to manage the password generators. */
613  private PasswordGeneratorConfigManager passwordGeneratorConfigManager;
614  /** The default password policy for the Directory Server. */
615  private PasswordPolicy defaultPasswordPolicy;
616  /** The configuration handler used to manage the authentication policies. */
617  private PasswordPolicyConfigManager authenticationPolicyConfigManager;
618  /** The configuration handler used to manage the password storage schemes. */
619  private PasswordStorageSchemeConfigManager storageSchemeConfigManager;
620  /** The configuration handler used to manage the password validators. */
621  private PasswordValidatorConfigManager passwordValidatorConfigManager;
622
623  /** The plugin config manager for the Directory Server. */
624  private PluginConfigManager pluginConfigManager;
625
626  /** The result code that should be used for internal "server" errors. */
627  private ResultCode serverErrorResultCode;
628
629  /** The special backend used for the Directory Server root DSE. */
630  private RootDSEBackend rootDSEBackend;
631  /** The root DN config manager for the server. */
632  private RootDNConfigManager rootDNConfigManager;
633
634  /** The SASL mechanism config manager for the Directory Server. */
635  private SASLConfigManager saslConfigManager;
636
637  /** The schema for the Directory Server. */
638  private Schema schema;
639
640  /**
641   * The schema for the Directory Server.
642   * <p>
643   * This schema is synchronized indirectly to the existing schema, because
644   * syntaxes are defined in schemaNG (i.e, migrated to SDK classes) and there
645   * is currently no way to handle the SchemaOptions in the configuration (e.g.
646   * SchemaOptions.ALLOW_ZERO_LENGTH_DIRECTORY_STRINGS).
647   * Thus, configuration of the legacy syntaxes are kept, and any change related
648   * to them is synchronized with this schema.
649   */
650  @RemoveOnceSDKSchemaIsUsed("'schema' field will then be a reference to a SDK schema")
651  private org.forgerock.opendj.ldap.schema.Schema schemaNG;
652
653  /** The schema configuration manager for the Directory Server. */
654  private SchemaConfigManager schemaConfigManager;
655
656  /** The set of disabled privileges. */
657  private Set<Privilege> disabledPrivileges;
658
659  /** The set of allowed task classes. */
660  private Set<String> allowedTasks;
661
662  /** The time that the server was started, formatted in UTC time. */
663  private String startTimeUTC;
664
665  /** The synchronization provider configuration manager for the Directory Server. */
666  private SynchronizationProviderConfigManager synchronizationProviderConfigManager;
667
668  /** Registry for base DN and naming context information. */
669  private BaseDnRegistry baseDnRegistry;
670
671  /** The set of backends registered with the server. */
672  private TreeMap<String, Backend<?>> backends;
673
674  /** The set of supported controls registered with the Directory Server. */
675  private final TreeSet<String> supportedControls = newTreeSet(
676      OID_LDAP_ASSERTION,
677      OID_LDAP_READENTRY_PREREAD,
678      OID_LDAP_READENTRY_POSTREAD,
679      OID_LDAP_NOOP_OPENLDAP_ASSIGNED,
680      OID_PERSISTENT_SEARCH,
681      OID_PROXIED_AUTH_V1,
682      OID_PROXIED_AUTH_V2,
683      OID_AUTHZID_REQUEST,
684      OID_MATCHED_VALUES,
685      OID_LDAP_SUBENTRIES,
686      OID_LDUP_SUBENTRIES,
687      OID_PASSWORD_POLICY_CONTROL,
688      OID_PERMISSIVE_MODIFY_CONTROL,
689      OID_REAL_ATTRS_ONLY,
690      OID_VIRTUAL_ATTRS_ONLY,
691      OID_ACCOUNT_USABLE_CONTROL,
692      OID_NS_PASSWORD_EXPIRED,
693      OID_NS_PASSWORD_EXPIRING);
694
695  /** The set of supported feature OIDs registered with the Directory Server. */
696  private final TreeSet<String> supportedFeatures = newTreeSet(
697      OID_ALL_OPERATIONAL_ATTRS_FEATURE,
698      OID_MODIFY_INCREMENT_FEATURE,
699      OID_TRUE_FALSE_FILTERS_FEATURE);
700
701  /** The trust manager provider configuration manager for the Directory Server. */
702  private TrustManagerProviderConfigManager trustManagerProviderConfigManager;
703
704  /** The virtual attribute provider configuration manager for the Directory Server. */
705  private final VirtualAttributeConfigManager virtualAttributeConfigManager;
706
707  /** The work queue that will be used to service client requests. */
708  private WorkQueue workQueue;
709
710  /** The writability mode for the Directory Server. */
711  private WritabilityMode writabilityMode;
712
713  /** The memory reservation system. */
714  private MemoryQuota memoryQuota;
715
716  /** The Disk Space Monitor. */
717  private DiskSpaceMonitor diskSpaceMonitor;
718
719  /** The lock manager which will be used for coordinating access to LDAP entries. */
720  private final LockManager lockManager = new LockManager();
721
722  /** The maximum size that internal buffers will be allowed to grow to until they are trimmed. */
723  private int maxInternalBufferSize = DEFAULT_MAX_INTERNAL_BUFFER_SIZE;
724
725  /** The default timeout used to start the server in detach mode. */
726  public static final int DEFAULT_TIMEOUT = 200;
727
728  /** Entry point for server configuration. */
729  private org.forgerock.opendj.config.server.ServerManagementContext serverManagementContext;
730
731  /** Class that prints the version of OpenDJ server to System.out. */
732  public static final class DirectoryServerVersionHandler implements VersionHandler
733  {
734    /** {@inheritDoc} */
735    @Override
736    public void printVersion()
737    {
738      try
739      {
740        DirectoryServer.printVersion(System.out);
741      }
742      catch (Exception e){}
743    }
744  }
745
746  /**
747   * Temporary class to provide instance methods instead of static methods for
748   * server. Once all static methods related to context are removed from the
749   * server then DirectoryServer class can be used directly as implementation of
750   * ServerContext.
751   */
752  private class DirectoryServerContext implements ServerContext
753  {
754
755    /** {@inheritDoc} */
756    @Override
757    public String getInstanceRoot()
758    {
759      return DirectoryServer.getInstanceRoot();
760    }
761
762    /** {@inheritDoc} */
763    @Override
764    public String getServerRoot()
765    {
766      return DirectoryServer.getServerRoot();
767    }
768
769    /** {@inheritDoc} */
770    @Override
771    public Schema getSchema()
772    {
773      return directoryServer.schema;
774    }
775
776    /** {@inheritDoc} */
777    @Override
778    public org.forgerock.opendj.ldap.schema.Schema getSchemaNG()
779    {
780      return directoryServer.schemaNG;
781    }
782
783    /** {@inheritDoc} */
784    @Override
785    public DirectoryEnvironmentConfig getEnvironment()
786    {
787      return directoryServer.environmentConfig;
788    }
789
790    /** {@inheritDoc} */
791    @Override
792    public SchemaUpdater getSchemaUpdater()
793    {
794      return new SchemaUpdater()
795      {
796        @Override
797        public boolean updateSchema(org.forgerock.opendj.ldap.schema.Schema schema)
798        {
799          schemaNG = schema;
800          return true;
801        }
802
803        @Override
804        public SchemaBuilder getSchemaBuilder()
805        {
806          return new SchemaBuilder(schemaNG);
807        }
808      };
809    }
810
811    /** {@inheritDoc} */
812    @Override
813    public org.forgerock.opendj.config.server.ServerManagementContext getServerManagementContext()
814    {
815      return serverManagementContext;
816    }
817
818    @Override
819    public MemoryQuota getMemoryQuota()
820    {
821      return directoryServer.memoryQuota;
822    }
823
824    @Override
825    public DiskSpaceMonitor getDiskSpaceMonitor()
826    {
827      return directoryServer.diskSpaceMonitor;
828    }
829  }
830
831  /**
832   * Creates a new instance of the Directory Server.  This will allow only a
833   * single instance of the server per JVM.
834   */
835  private DirectoryServer()
836  {
837    this(new DirectoryEnvironmentConfig());
838  }
839
840  /**
841   * Creates a new instance of the Directory Server.  This will allow only a
842   * single instance of the server per JVM.
843   *
844   * @param  config  The environment configuration to use for the Directory
845   *                 Server instance.
846   */
847  private DirectoryServer(DirectoryEnvironmentConfig config)
848  {
849    environmentConfig        = config;
850    isBootstrapped           = false;
851    isRunning                = false;
852    shuttingDown             = false;
853    lockdownMode             = false;
854    serverErrorResultCode    = ResultCode.OTHER;
855
856    operatingSystem = OperatingSystem.forName(System.getProperty("os.name"));
857    serverContext = new DirectoryServerContext();
858    virtualAttributeConfigManager = new VirtualAttributeConfigManager(serverContext);
859    memoryQuota = new MemoryQuota();
860    diskSpaceMonitor = new DiskSpaceMonitor();
861  }
862
863  /**
864   * Retrieves the instance of the Directory Server that is associated with this
865   * JVM.
866   *
867   * @return  The instance of the Directory Server that is associated with this
868   *          JVM.
869   */
870  public static DirectoryServer getInstance()
871  {
872    return directoryServer;
873  }
874
875  /**
876   * Creates a new instance of the Directory Server and replaces the static
877   * reference to it.  This should only be used in the context of an in-core
878   * restart after the existing server has been shut down.
879   *
880   * @param  config  The environment configuration for the Directory Server.
881   *
882   * @return  The new instance of the Directory Server that is associated with
883   *          this JVM.
884   */
885  private static DirectoryServer
886                      getNewInstance(DirectoryEnvironmentConfig config)
887  {
888    synchronized (directoryServer)
889    {
890      return directoryServer = new DirectoryServer(config);
891    }
892  }
893
894  /**
895   * Retrieves the environment configuration for the Directory Server.
896   *
897   * @return  The environment configuration for the Directory Server.
898   */
899  public static DirectoryEnvironmentConfig getEnvironmentConfig()
900  {
901    return directoryServer.environmentConfig;
902  }
903
904  /**
905   * Sets the environment configuration for the Directory Server.  This method
906   * may only be invoked when the server is not running.
907   *
908   * @param  config  The environment configuration for the Directory Server.
909   *
910   * @throws  InitializationException  If the Directory Server is currently
911   *                                   running.
912   */
913  public void setEnvironmentConfig(DirectoryEnvironmentConfig config)
914          throws InitializationException
915  {
916    if (isRunning)
917    {
918      throw new InitializationException(
919              ERR_CANNOT_SET_ENVIRONMENT_CONFIG_WHILE_RUNNING.get());
920    }
921
922    environmentConfig = config;
923  }
924
925  /**
926   * Returns the server context.
927   *
928   * @return the server context
929   */
930  public ServerContext getServerContext() {
931    return serverContext;
932  }
933
934  /**
935   * Indicates whether the Directory Server is currently running.
936   *
937   * @return  {@code true} if the server is currently running, or {@code false}
938   *          if not.
939   */
940  public static boolean isRunning()
941  {
942    return directoryServer.isRunning;
943  }
944
945  /**
946   * Bootstraps the appropriate Directory Server structures that may be needed
947   * by both server and client-side tools.
948   */
949  public static void bootstrapClient()
950  {
951    synchronized (directoryServer)
952    {
953      // Set default values for variables that may be needed during schema
954      // processing.
955      directoryServer.syntaxEnforcementPolicy = AcceptRejectWarn.REJECT;
956
957      // Create the server schema and initialize and register a minimal set of
958      // matching rules and attribute syntaxes.
959      directoryServer.schema = new Schema();
960      directoryServer.schemaNG = new SchemaBuilder("mainSchema").addSchema(CoreSchema.getInstance(), true).toSchema();
961      directoryServer.bootstrapMatchingRules();
962      directoryServer.bootstrapAttributeSyntaxes();
963
964      // Perform any additional initialization that might be necessary before
965      // loading the configuration.
966      directoryServer.alertHandlers = new CopyOnWriteArrayList<>();
967      directoryServer.passwordStorageSchemes = new ConcurrentHashMap<>();
968      directoryServer.passwordStorageSchemesByDN = new ConcurrentHashMap<>();
969      directoryServer.passwordGenerators = new ConcurrentHashMap<>();
970      directoryServer.authPasswordStorageSchemes = new ConcurrentHashMap<>();
971      directoryServer.passwordValidators = new ConcurrentHashMap<>();
972      directoryServer.accountStatusNotificationHandlers = new ConcurrentHashMap<>();
973      directoryServer.rootDNs = new CopyOnWriteArraySet<>();
974      directoryServer.alternateRootBindDNs = new ConcurrentHashMap<>();
975      directoryServer.keyManagerProviders = new ConcurrentHashMap<>();
976      directoryServer.trustManagerProviders = new ConcurrentHashMap<>();
977      directoryServer.rotationPolicies = new ConcurrentHashMap<>();
978      directoryServer.retentionPolicies = new ConcurrentHashMap<>();
979      directoryServer.certificateMappers = new ConcurrentHashMap<>();
980      directoryServer.authenticationPolicies = new ConcurrentHashMap<>();
981      directoryServer.defaultPasswordPolicyDN = null;
982      directoryServer.defaultPasswordPolicy = null;
983      directoryServer.monitorProviders = new ConcurrentHashMap<>();
984      directoryServer.backends = new TreeMap<>();
985      directoryServer.backendInitializationListeners = new CopyOnWriteArraySet<>();
986      directoryServer.baseDnRegistry = new BaseDnRegistry();
987      directoryServer.initializationCompletedListeners = new CopyOnWriteArrayList<>();
988      directoryServer.shutdownListeners = new CopyOnWriteArrayList<>();
989      directoryServer.synchronizationProviders = new CopyOnWriteArrayList<>();
990      directoryServer.supportedLDAPVersions = new ConcurrentHashMap<>();
991      directoryServer.connectionHandlers = new CopyOnWriteArrayList<>();
992      directoryServer.identityMappers = new ConcurrentHashMap<>();
993      directoryServer.extendedOperationHandlers = new ConcurrentHashMap<>();
994      directoryServer.saslMechanismHandlers = new ConcurrentHashMap<>();
995      directoryServer.offlineSchemaChanges = new LinkedList<>();
996      directoryServer.backupTaskListeners = new CopyOnWriteArrayList<>();
997      directoryServer.restoreTaskListeners = new CopyOnWriteArrayList<>();
998      directoryServer.exportTaskListeners = new CopyOnWriteArrayList<>();
999      directoryServer.importTaskListeners = new CopyOnWriteArrayList<>();
1000      directoryServer.allowedTasks = new LinkedHashSet<>(0);
1001      directoryServer.disabledPrivileges = new LinkedHashSet<>(0);
1002      directoryServer.returnBindErrorMessages = false;
1003      directoryServer.idleTimeLimit = 0L;
1004    }
1005  }
1006
1007  /**
1008   * Bootstraps the Directory Server by initializing all the necessary
1009   * structures that should be in place before the configuration may be read.
1010   * This step must be completed before the server may be started or the
1011   * configuration is loaded, but it will not be allowed while the server is
1012   * running.
1013   *
1014   * @throws  InitializationException  If a problem occurs while attempting to
1015   *                                   bootstrap the server.
1016   */
1017  private void bootstrapServer() throws InitializationException
1018  {
1019    // First, make sure that the server isn't currently running.  If it isn't,
1020    // then make sure that no other thread will try to start or bootstrap the
1021    // server before this thread is done.
1022    synchronized (directoryServer)
1023    {
1024      if (isRunning)
1025      {
1026        LocalizableMessage message = ERR_CANNOT_BOOTSTRAP_WHILE_RUNNING.get();
1027        throw new InitializationException(message);
1028      }
1029
1030      isBootstrapped   = false;
1031      shuttingDown     = false;
1032    }
1033
1034    // Add a shutdown hook so that the server can be notified when the JVM
1035    // starts shutting down.
1036    shutdownHook = new DirectoryServerShutdownHook();
1037    Runtime.getRuntime().addShutdownHook(shutdownHook);
1038
1039    // Create the MBean server that we will use for JMX interaction.
1040    initializeJMX();
1041
1042    logger.debug(INFO_DIRECTORY_BOOTSTRAPPING);
1043
1044    // Perform all the bootstrapping that is shared with the client-side processing.
1045    bootstrapClient();
1046
1047    // Initialize the variables that will be used for connection tracking.
1048    establishedConnections = new LinkedHashSet<>(1000);
1049    currentConnections     = 0;
1050    maxConnections         = 0;
1051    totalConnections       = 0;
1052
1053    // Create the plugin config manager, but don't initialize it yet.  This will
1054    // make it possible to process internal operations before the plugins have
1055    // been loaded.
1056    pluginConfigManager = new PluginConfigManager(serverContext);
1057
1058    // If we have gotten here, then the configuration should be properly bootstrapped.
1059    synchronized (directoryServer)
1060    {
1061      isBootstrapped = true;
1062    }
1063  }
1064
1065  /**
1066   * Performs a minimal set of JMX initialization. This may be used by the core
1067   * Directory Server or by command-line tools.
1068   *
1069   * @throws  InitializationException  If a problem occurs while attempting to
1070   *                                   initialize the JMX subsystem.
1071   */
1072  public static void initializeJMX()
1073         throws InitializationException
1074  {
1075    try
1076    {
1077      // It is recommended by ManagementFactory javadoc that the platform
1078      // MBeanServer also be used to register other application managed
1079      // beans besides the platform MXBeans. Try platform MBeanServer
1080      // first. If it fails create a new, private, MBeanServer instance.
1081      try
1082      {
1083        directoryServer.mBeanServer =
1084          ManagementFactory.getPlatformMBeanServer();
1085      }
1086      catch (Exception e)
1087      {
1088        logger.traceException(e);
1089
1090        directoryServer.mBeanServer = MBeanServerFactory.newMBeanServer();
1091      }
1092      directoryServer.mBeans = new ConcurrentHashMap<>();
1093      registerAlertGenerator(directoryServer);
1094    }
1095    catch (Exception e)
1096    {
1097      logger.traceException(e);
1098
1099      throw new InitializationException(ERR_CANNOT_CREATE_MBEAN_SERVER.get(e), e);
1100    }
1101  }
1102
1103  /**
1104   * Instantiates the configuration handler and loads the Directory Server
1105   * configuration.
1106   *
1107   * @param  configClass  The fully-qualified name of the Java class that will
1108   *                      serve as the configuration handler for the Directory
1109   *                      Server.
1110   * @param  configFile   The path to the file that will hold either the entire
1111   *                      server configuration or enough information to allow
1112   *                      the server to access the configuration in some other
1113   *                      repository.
1114   *
1115   * @throws  InitializationException  If a problem occurs while trying to
1116   *                                   initialize the config handler.
1117   */
1118  public void initializeConfiguration(String configClass, String configFile)
1119         throws InitializationException
1120  {
1121    Class<?> cfgClass;
1122    try
1123    {
1124      cfgClass = Class.forName(configClass);
1125    }
1126    catch (Exception e)
1127    {
1128      logger.traceException(e);
1129
1130      LocalizableMessage message =
1131          ERR_CANNOT_LOAD_CONFIG_HANDLER_CLASS.get(
1132                  configClass, stackTraceToSingleLineString(e));
1133      throw new InitializationException(message, e);
1134    }
1135
1136    File cfgFile = new File(configFile);
1137
1138    environmentConfig.setConfigClass(cfgClass);
1139    environmentConfig.setConfigFile(cfgFile);
1140    initializeConfiguration();
1141  }
1142
1143  /**
1144   * Initializes this server.
1145   * <p>
1146   * Initialization involves the following steps:
1147   * <ul>
1148   *  <li>Configuration</li>
1149   *  <li>Schema</li>
1150   * </ul>
1151   * @throws InitializationException
1152   */
1153  @ActivateOnceNewConfigFrameworkIsUsed("it will need adaptation to be activated before sdk schema is ready")
1154  @ActivateOnceSDKSchemaIsUsed
1155  private void initializeNG() throws InitializationException
1156  {
1157    serverManagementContext = ConfigurationBootstrapper.bootstrap(serverContext);
1158    initializeSchemaNG();
1159
1160    // TODO : config backend should be initialized later, with the other backends
1161    //ConfigBackend configBackend = new ConfigBackend();
1162    //configBackend.initializeConfigBackend(serverContext, configurationHandler);
1163  }
1164
1165  /** Initialize the schema of this server. */
1166  @ActivateOnceSDKSchemaIsUsed
1167  private void initializeSchemaNG() throws InitializationException
1168  {
1169    SchemaHandler schemaHandler = new SchemaHandler();
1170    try
1171    {
1172      schemaHandler.initialize(serverContext);
1173    }
1174    catch (org.forgerock.opendj.config.server.ConfigException e)
1175    {
1176      // TODO : fix message
1177      throw new InitializationException(LocalizableMessage.raw("Cannot initialize schema handler"), e);
1178    }
1179  }
1180
1181  /**
1182   * Instantiates the configuration handler and loads the Directory Server
1183   * configuration.
1184   *
1185   * @throws  InitializationException  If a problem occurs while trying to
1186   *                                   initialize the config handler.
1187   */
1188  public void initializeConfiguration()
1189         throws InitializationException
1190  {
1191    this.configClass = environmentConfig.getConfigClass();
1192    this.configFile  = environmentConfig.getConfigFile();
1193
1194    // Make sure that administration framework definition classes are loaded.
1195    ClassLoaderProvider provider = ClassLoaderProvider.getInstance();
1196    if (! provider.isEnabled())
1197    {
1198      provider.enable();
1199    }
1200
1201    // Load and instantiate the configuration handler class.
1202    Class<ConfigHandler> handlerClass = configClass;
1203    try
1204    {
1205      configHandler = handlerClass.newInstance();
1206    }
1207    catch (Exception e)
1208    {
1209      logger.traceException(e);
1210
1211      LocalizableMessage message =
1212          ERR_CANNOT_INSTANTIATE_CONFIG_HANDLER.get(configClass, e.getLocalizedMessage());
1213      throw new InitializationException(message, e);
1214    }
1215
1216    // Perform the handler-specific initialization.
1217    try
1218    {
1219      String path;
1220      try
1221      {
1222        path = configFile.getCanonicalPath();
1223      }
1224      catch (Exception ex)
1225      {
1226        path = configFile.getAbsolutePath();
1227      }
1228      configHandler.initializeConfigHandler(path, false);
1229    }
1230    catch (InitializationException ie)
1231    {
1232      logger.traceException(ie);
1233
1234      throw ie;
1235    }
1236    catch (Exception e)
1237    {
1238      logger.traceException(e);
1239
1240      LocalizableMessage message =
1241          ERR_CANNOT_INITIALIZE_CONFIG_HANDLER.get(
1242              configClass, configFile, e.getLocalizedMessage());
1243      throw new InitializationException(message, e);
1244    }
1245  }
1246
1247  /**
1248   * Retrieves the path to the configuration file used to initialize the
1249   * Directory Server.
1250   *
1251   * @return  The path to the configuration file used to initialize the
1252   *          Directory Server.
1253   */
1254  public static String getConfigFile()
1255  {
1256    return directoryServer.configFile.getAbsolutePath();
1257  }
1258
1259  /**
1260   * Starts up the Directory Server.  It must have already been bootstrapped
1261   * and cannot be running.
1262   *
1263   * @throws  ConfigException  If there is a problem with the Directory Server
1264   *                           configuration that prevents a critical component
1265   *                           from being instantiated.
1266   *
1267   * @throws  InitializationException  If some other problem occurs while
1268   *                                   attempting to initialize and start the
1269   *                                   Directory Server.
1270   */
1271  public void startServer()
1272         throws ConfigException, InitializationException
1273  {
1274    // Checks the version - if upgrade required, cannot launch the server.
1275    try
1276    {
1277      BuildVersion.checkVersionMismatch();
1278    }
1279    catch (InitializationException e)
1280    {
1281      logger.traceException(e);
1282      throw new InitializationException(e.getMessageObject());
1283    }
1284
1285    synchronized (directoryServer)
1286    {
1287      if (! isBootstrapped)
1288      {
1289        LocalizableMessage message = ERR_CANNOT_START_BEFORE_BOOTSTRAP.get();
1290        throw new InitializationException(message);
1291      }
1292
1293      if (isRunning)
1294      {
1295        LocalizableMessage message = ERR_CANNOT_START_WHILE_RUNNING.get();
1296        throw new InitializationException(message);
1297      }
1298
1299      logger.info(NOTE_DIRECTORY_SERVER_STARTING, getVersionString(), BUILD_ID, REVISION_NUMBER);
1300
1301      // Acquire an exclusive lock for the Directory Server process.
1302      if (! serverLocked)
1303      {
1304        String lockFile = LockFileManager.getServerLockFileName();
1305        try
1306        {
1307          StringBuilder failureReason = new StringBuilder();
1308          if (! LockFileManager.acquireExclusiveLock(lockFile, failureReason))
1309          {
1310            LocalizableMessage message = ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(
1311                lockFile, failureReason);
1312            throw new InitializationException(message);
1313          }
1314
1315          serverLocked = true;
1316        }
1317        catch (InitializationException ie)
1318        {
1319          throw ie;
1320        }
1321        catch (Exception e)
1322        {
1323          logger.traceException(e);
1324
1325          LocalizableMessage message = ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(
1326              lockFile, stackTraceToSingleLineString(e));
1327          throw new InitializationException(message, e);
1328        }
1329      }
1330
1331      // Mark the current time as the start time.
1332      startUpTime  = System.currentTimeMillis();
1333      startTimeUTC = TimeThread.getGMTTime();
1334
1335      // Determine whether or not we should start the connection handlers.
1336      boolean startConnectionHandlers = !environmentConfig.disableConnectionHandlers();
1337
1338      diskSpaceMonitor.startDiskSpaceMonitor();
1339
1340      initializeSchema();
1341
1342      // Allow internal plugins to be registered.
1343      pluginConfigManager.initializePluginConfigManager();
1344
1345      virtualAttributeConfigManager.initializeVirtualAttributes();
1346
1347      // The core Directory Server configuration.
1348      coreConfigManager = new CoreConfigManager(serverContext);
1349      coreConfigManager.initializeCoreConfig();
1350
1351      initializeCryptoManager();
1352
1353      rotationPolicyConfigManager = new LogRotationPolicyConfigManager(serverContext);
1354      rotationPolicyConfigManager.initializeLogRotationPolicyConfig();
1355
1356      retentionPolicyConfigManager = new LogRetentionPolicyConfigManager(serverContext);
1357      retentionPolicyConfigManager.initializeLogRetentionPolicyConfig();
1358
1359      loggerConfigManager = new LoggerConfigManager(serverContext);
1360      loggerConfigManager.initializeLoggerConfig();
1361
1362      RuntimeInformation.logInfo();
1363
1364      new AlertHandlerConfigManager(serverContext).initializeAlertHandlers();
1365
1366      // Initialize the default entry cache. We have to have one before
1367      // <CODE>initializeBackends()</CODE> method kicks in further down.
1368      entryCacheConfigManager = new EntryCacheConfigManager(serverContext);
1369      entryCacheConfigManager.initializeDefaultEntryCache();
1370
1371      // Initialize the administration connector self signed certificate if
1372      // needed and do this before initializing the key managers so that it is
1373      // picked up.
1374      if (startConnectionHandlers)
1375      {
1376        AdministrationConnector.createSelfSignedCertificateIfNeeded(serverContext);
1377      }
1378
1379      keyManagerProviderConfigManager = new KeyManagerProviderConfigManager(serverContext);
1380      keyManagerProviderConfigManager.initializeKeyManagerProviders();
1381
1382      trustManagerProviderConfigManager = new TrustManagerProviderConfigManager(serverContext);
1383      trustManagerProviderConfigManager.initializeTrustManagerProviders();
1384
1385      certificateMapperConfigManager = new CertificateMapperConfigManager(serverContext);
1386      certificateMapperConfigManager.initializeCertificateMappers();
1387
1388      identityMapperConfigManager = new IdentityMapperConfigManager(serverContext);
1389      identityMapperConfigManager.initializeIdentityMappers();
1390
1391      initializeRootDNConfigManager();
1392
1393      initializeAuthenticatedUsers();
1394      // initialize both subentry manager and group manager for this backend.
1395      initializeSubentryManager();
1396      initializeGroupManager();
1397
1398      // Initialize both subentry manager and group manager
1399      // for the configuration backend.
1400      // TODO : why do we initialize these now ? Can't we do them after backend initialization ?
1401      subentryManager.performBackendInitializationProcessing(configHandler);
1402      groupManager.performBackendInitializationProcessing(configHandler);
1403
1404      AccessControlConfigManager.getInstance().initializeAccessControl(serverContext);
1405
1406      // Initialize all the backends and their associated suffixes
1407      // and initialize the workflows when workflow configuration mode is auto.
1408      initializeBackends();
1409
1410      // configure the remaining workflows (rootDSE and config backend).
1411      createAndRegisterRemainingWorkflows();
1412
1413      // Check for and initialize user configured entry cache if any.
1414      // If not then stick with default entry cache initialized earlier.
1415      entryCacheConfigManager.initializeEntryCache();
1416
1417      initializeExtendedOperations();
1418      initializeSASLMechanisms();
1419
1420      if (startConnectionHandlers)
1421      {
1422        // Includes the administration connector.
1423        initializeConnectionHandlers();
1424      }
1425
1426      monitorConfigManager = new MonitorConfigManager(serverContext);
1427      monitorConfigManager.initializeMonitorProviders();
1428
1429      initializeAuthenticationPolicyComponents();
1430
1431      pluginConfigManager.initializeUserPlugins(null);
1432
1433      if (!environmentConfig.disableSynchronization())
1434      {
1435        synchronizationProviderConfigManager = new SynchronizationProviderConfigManager(serverContext);
1436        synchronizationProviderConfigManager.initializeSynchronizationProviders();
1437      }
1438
1439      workQueue = new WorkQueueConfigManager(serverContext).initializeWorkQueue();
1440
1441      PluginResult.Startup startupPluginResult = pluginConfigManager.invokeStartupPlugins();
1442      if (! startupPluginResult.continueProcessing())
1443      {
1444        throw new InitializationException(ERR_STARTUP_PLUGIN_ERROR.get(startupPluginResult.getErrorMessage(),
1445                startupPluginResult.getErrorMessage().ordinal()));
1446      }
1447
1448      for (InitializationCompletedListener listener : initializationCompletedListeners)
1449      {
1450        try
1451        {
1452          listener.initializationCompleted();
1453        }
1454        catch (Exception e)
1455        {
1456          logger.traceException(e);
1457        }
1458      }
1459
1460      if (startConnectionHandlers)
1461      {
1462        startConnectionHandlers();
1463        new IdleTimeLimitThread().start();
1464      }
1465
1466      // Synchronization of ADS with the crypto manager.
1467      new CryptoManagerSync();
1468
1469      // Write a copy of the config if needed.
1470      if (saveConfigOnSuccessfulStartup)
1471      {
1472        configHandler.writeSuccessfulStartupConfig();
1473      }
1474
1475      isRunning = true;
1476
1477      LocalizableMessage message = NOTE_DIRECTORY_SERVER_STARTED.get();
1478      logger.info(message);
1479      sendAlertNotification(this, ALERT_TYPE_SERVER_STARTED, message);
1480
1481      // Force the root connection to be initialized.
1482      InternalClientConnection rootConnection = InternalClientConnection.getRootConnection();
1483
1484      if (! environmentConfig.disableAdminDataSynchronization())
1485      {
1486        AdministrationDataSync admDataSync = new AdministrationDataSync(rootConnection);
1487        admDataSync.synchronize();
1488      }
1489
1490      deleteUnnecessaryFiles();
1491    }
1492  }
1493
1494  /** Delete "server.starting" and "hostname" files if they are present. */
1495  private void deleteUnnecessaryFiles()
1496  {
1497    File serverStartingFile = new File(configHandler.getInstanceRoot() + File.separator + "logs"
1498        + File.separator + "server.starting");
1499    if (serverStartingFile.exists())
1500    {
1501      serverStartingFile.delete();
1502    }
1503
1504    File hostNameFile = new File(configHandler.getInstanceRoot() + File.separator + SetupUtils.HOST_NAME_FILE);
1505    if (hostNameFile.exists())
1506    {
1507      hostNameFile.delete();
1508    }
1509  }
1510
1511  /** Initializes authenticated users. */
1512  public void initializeAuthenticatedUsers()
1513  {
1514    directoryServer.authenticatedUsers = new AuthenticatedUsers();
1515  }
1516
1517  /**
1518   * Registers a basic set of matching rules with the server that should always
1519   * be available regardless of the server configuration and may be needed for
1520   * configuration processing.
1521   */
1522  private void bootstrapMatchingRules()
1523  {
1524    MatchingRuleFactory<?>[] factories =
1525            new MatchingRuleFactory<?>[] {
1526              new DoubleMetaphoneApproximateMatchingRuleFactory(),
1527              new BooleanEqualityMatchingRuleFactory(),
1528              new CaseExactEqualityMatchingRuleFactory(),
1529              new CaseExactIA5EqualityMatchingRuleFactory(),
1530              new CaseIgnoreEqualityMatchingRuleFactory(),
1531              new CaseIgnoreIA5EqualityMatchingRuleFactory(),
1532              new DistinguishedNameEqualityMatchingRuleFactory(),
1533              new GeneralizedTimeEqualityMatchingRuleFactory(),
1534              new IntegerEqualityMatchingRuleFactory(),
1535              new OctetStringEqualityMatchingRuleFactory(),
1536              new ObjectIdentifierEqualityMatchingRuleFactory(),
1537              new TelephoneNumberEqualityMatchingRuleFactory(),
1538              new CaseExactOrderingMatchingRuleFactory(),
1539              new CaseIgnoreOrderingMatchingRuleFactory(),
1540              new GeneralizedTimeOrderingMatchingRuleFactory(),
1541              new IntegerOrderingMatchingRuleFactory(),
1542              new OctetStringOrderingMatchingRuleFactory(),
1543              new CaseExactSubstringMatchingRuleFactory(),
1544              new CaseExactIA5SubstringMatchingRuleFactory(),
1545              new CaseIgnoreSubstringMatchingRuleFactory(),
1546              new CaseIgnoreIA5SubstringMatchingRuleFactory(),
1547              new OctetStringSubstringMatchingRuleFactory(),
1548              new TelephoneNumberSubstringMatchingRuleFactory()};
1549
1550    MatchingRuleFactory<?> currentFactory = null;
1551    try
1552    {
1553      for(MatchingRuleFactory<?> factory: factories)
1554      {
1555        currentFactory = factory;
1556        currentFactory.initializeMatchingRule(null);
1557        for(MatchingRule matchingRule: currentFactory.getMatchingRules())
1558        {
1559         registerMatchingRule(matchingRule, true);
1560        }
1561      }
1562    }
1563    catch (Exception e)
1564    {
1565      logger.traceException(e);
1566
1567      logger.error(ERR_CANNOT_BOOTSTRAP_MATCHING_RULE, currentFactory.getClass().getName(),
1568              stackTraceToSingleLineString(e));
1569    }
1570  }
1571
1572  /**
1573   * Registers a basic set of attribute syntaxes with the server that should
1574   * always be available regardless of the server configuration and may be
1575   * needed for configuration processing.
1576   */
1577  private void bootstrapAttributeSyntaxes()
1578  {
1579    schema.registerDefaultSyntax(getDefaultSyntax());
1580
1581    Syntax[] syntaxes = {
1582      getDefaultBinarySyntax(),
1583      getDefaultBooleanSyntax(),
1584      getDefaultStringSyntax(),
1585      getDefaultDNSyntax(),
1586      getDefaultIntegerSyntax(),
1587      CoreSchema.getAttributeTypeDescriptionSyntax(),
1588      CoreSchema.getIA5StringSyntax(),
1589      CoreSchema.getGeneralizedTimeSyntax(),
1590      CoreSchema.getObjectClassDescriptionSyntax(),
1591      CoreSchema.getOIDSyntax(),
1592      CoreSchema.getTelephoneNumberSyntax()
1593    };
1594    for (Syntax syntax : syntaxes)
1595    {
1596      registerSyntax(syntax);
1597    }
1598  }
1599
1600  private Syntax registerSyntax(Syntax syntax)
1601  {
1602    try
1603    {
1604      schema.registerSyntax(syntax, true);
1605    }
1606    catch (Exception e)
1607    {
1608      logger.error(ERR_CANNOT_BOOTSTRAP_SYNTAX, syntax.getClass().getName(), stackTraceToSingleLineString(e));
1609    }
1610    return syntax;
1611  }
1612
1613  /**
1614   * Retrieves the authenticated users manager for the Directory Server.
1615   *
1616   * @return  The authenticated users manager for the Directory Server.
1617   */
1618  public static AuthenticatedUsers getAuthenticatedUsers()
1619  {
1620    return directoryServer.authenticatedUsers;
1621  }
1622
1623  /**
1624   * Initializes the crypto manager for the Directory Server.
1625   *
1626   * @throws ConfigException
1627   *           If a configuration problem is identified while initializing the
1628   *           crypto manager.
1629   * @throws InitializationException
1630   *           If a problem occurs while initializing the crypto manager that is
1631   *           not related to the server configuration.
1632   */
1633  public void initializeCryptoManager()
1634         throws ConfigException, InitializationException
1635  {
1636    RootCfg root =
1637         ServerManagementContext.getInstance().getRootConfiguration();
1638    CryptoManagerCfg cryptoManagerCfg = root.getCryptoManager();
1639    cryptoManager = new CryptoManagerImpl(serverContext, cryptoManagerCfg);
1640  }
1641
1642  /**
1643   * Retrieves a reference to the Directory Server crypto manager.
1644   *
1645   * @return  A reference to the Directory Server crypto manager.
1646   */
1647  public static CryptoManagerImpl getCryptoManager()
1648  {
1649    return directoryServer.cryptoManager;
1650  }
1651
1652  /**
1653   * Indicates whether the Directory Server is configured with information about
1654   * one or more mail servers and may therefore be used to send e-mail messages.
1655   *
1656   * @return  {@code true} if the Directory Server is configured to be able to
1657   *          send e-mail messages, or {@code false} if not.
1658   */
1659  public static boolean mailServerConfigured()
1660  {
1661    return directoryServer.mailServerPropertySets != null
1662        && !directoryServer.mailServerPropertySets.isEmpty();
1663  }
1664
1665  /**
1666   * Specifies the set of mail server properties that should be used for SMTP
1667   * communication.
1668   *
1669   * @param  mailServerPropertySets  A list of {@code Properties} objects that
1670   *                                 provide information that can be used to
1671   *                                 communicate with SMTP servers.
1672   */
1673  public static void setMailServerPropertySets(List<Properties>
1674                                                    mailServerPropertySets)
1675  {
1676    directoryServer.mailServerPropertySets = mailServerPropertySets;
1677  }
1678
1679  /**
1680   * Retrieves the sets of information about the mail servers configured for use
1681   * by the Directory Server.
1682   *
1683   * @return  The sets of information about the mail servers configured for use
1684   *          by the Directory Server.
1685   */
1686  public static List<Properties> getMailServerPropertySets()
1687  {
1688    return directoryServer.mailServerPropertySets;
1689  }
1690
1691  /**
1692   * Initializes the schema elements for the Directory Server, including the
1693   * matching rules, attribute syntaxes, attribute types, and object classes.
1694   *
1695   * @throws  ConfigException  If there is a configuration problem with any of
1696   *                           the schema elements.
1697   *
1698   * @throws  InitializationException  If a problem occurs while initializing
1699   *                                   the schema elements that is not related
1700   *                                   to the server configuration.
1701   */
1702  public void initializeSchema()
1703         throws ConfigException, InitializationException
1704  {
1705    // Create the schema configuration manager, and initialize the schema from
1706    // the configuration.
1707    schemaConfigManager = new SchemaConfigManager(serverContext);
1708    schema = schemaConfigManager.getSchema();
1709
1710    schemaConfigManager.initializeMatchingRules();
1711    schemaConfigManager.initializeAttributeSyntaxes();
1712    schemaConfigManager.initializeSchemaFromFiles();
1713
1714    // With server schema in place set compressed schema.
1715    compressedSchema = new DefaultCompressedSchema();
1716
1717    // At this point we have a problem, because none of the configuration is
1718    // usable because it was all read before we had a schema (and therefore all
1719    // of the attribute types and objectclasses are bogus and won't let us find
1720    // anything).  So we have to re-read the configuration so that we can
1721    // continue the necessary startup process.  In the process, we want to
1722    // preserve any configuration add/delete/change listeners that might have
1723    // been registered with the old configuration (which will primarily be
1724    // schema elements) so they can be re-registered with the new configuration.
1725    Map<String, List<ConfigAddListener>> addListeners = new LinkedHashMap<>();
1726    Map<String, List<ConfigDeleteListener>> deleteListeners = new LinkedHashMap<>();
1727    Map<String, List<ConfigChangeListener>> changeListeners = new LinkedHashMap<>();
1728    getChangeListeners(configHandler.getConfigRootEntry(), addListeners,
1729                       deleteListeners, changeListeners);
1730
1731    try
1732    {
1733      configHandler.finalizeConfigHandler();
1734    }
1735    catch (Exception e)
1736    {
1737      logger.traceException(e);
1738    }
1739
1740    try
1741    {
1742      configHandler.initializeConfigHandler(configFile.getAbsolutePath(), true);
1743    }
1744    catch (InitializationException ie)
1745    {
1746      logger.traceException(ie);
1747
1748      throw ie;
1749    }
1750    catch (Exception e)
1751    {
1752      logger.traceException(e);
1753
1754      throw new InitializationException(ERR_CANNOT_INITIALIZE_CONFIG_HANDLER.get(
1755          configClass, configFile, e.getLocalizedMessage()));
1756    }
1757
1758    // Re-register all of the change listeners with the configuration.
1759    for (String dnStr : addListeners.keySet())
1760    {
1761      try
1762      {
1763        DN dn = DN.valueOf(dnStr);
1764        for (ConfigAddListener listener : addListeners.get(dnStr))
1765        {
1766          configHandler.getConfigEntry(dn).registerAddListener(listener);
1767        }
1768      }
1769      catch (DirectoryException de)
1770      {
1771        // This should never happen, so we'll just re-throw it.
1772        throw new InitializationException(de.getMessageObject());
1773      }
1774    }
1775
1776    for (String dnStr : deleteListeners.keySet())
1777    {
1778      try
1779      {
1780        DN dn = DN.valueOf(dnStr);
1781        for (ConfigDeleteListener listener : deleteListeners.get(dnStr))
1782        {
1783          configHandler.getConfigEntry(dn).registerDeleteListener(listener);
1784        }
1785      }
1786      catch (DirectoryException de)
1787      {
1788        // This should never happen, so we'll just re-throw it.
1789        throw new InitializationException(de.getMessageObject());
1790      }
1791    }
1792
1793    for (String dnStr : changeListeners.keySet())
1794    {
1795      try
1796      {
1797        DN dn = DN.valueOf(dnStr);
1798        for (ConfigChangeListener listener : changeListeners.get(dnStr))
1799        {
1800          configHandler.getConfigEntry(dn).registerChangeListener(listener);
1801        }
1802      }
1803      catch (DirectoryException de)
1804      {
1805        // This should never happen, so we'll just re-throw it.
1806        throw new InitializationException(de.getMessageObject());
1807      }
1808    }
1809  }
1810
1811  /**
1812   * Retrieves the default compressed schema manager for the Directory Server.
1813   *
1814   * @return  The default compressed schema manager for the Directory Server.
1815   */
1816  public static CompressedSchema getDefaultCompressedSchema()
1817  {
1818    return directoryServer.compressedSchema;
1819  }
1820
1821  /**
1822   * Gets all of the add, delete, and change listeners from the provided
1823   * configuration entry and all of its descendants and puts them in the
1824   * appropriate lists.
1825   *
1826   * @param  configEntry      The configuration entry to be processed, along
1827   *                          with all of its descendants.
1828   * @param  addListeners     The set of add listeners mapped to the DN of the
1829   *                          corresponding configuration entry.
1830   * @param  deleteListeners  The set of delete listeners mapped to the DN of
1831   *                          the corresponding configuration entry.
1832   * @param  changeListeners  The set of change listeners mapped to the DN of
1833   *                          the corresponding configuration entry.
1834   */
1835  private void getChangeListeners(ConfigEntry configEntry,
1836      Map<String, List<ConfigAddListener>> addListeners,
1837      Map<String, List<ConfigDeleteListener>> deleteListeners,
1838      Map<String, List<ConfigChangeListener>> changeListeners)
1839  {
1840    put(addListeners, configEntry, configEntry.getAddListeners());
1841    put(deleteListeners, configEntry, configEntry.getDeleteListeners());
1842    put(changeListeners, configEntry, configEntry.getChangeListeners());
1843
1844    for (ConfigEntry child : configEntry.getChildren().values())
1845    {
1846      getChangeListeners(child, addListeners, deleteListeners, changeListeners);
1847    }
1848  }
1849
1850  private <T> void put(Map<String, List<T>> listeners, ConfigEntry configEntry, List<T> cfgListeners)
1851  {
1852    if (cfgListeners != null && !cfgListeners.isEmpty())
1853    {
1854      listeners.put(configEntry.getDN().toString(), cfgListeners);
1855    }
1856  }
1857
1858  /**
1859   * Retrieves the set of backend initialization listeners that have been
1860   * registered with the Directory Server.  The contents of the returned set
1861   * must not be altered.
1862   *
1863   * @return  The set of backend initialization listeners that have been
1864   *          registered with the Directory Server.
1865   */
1866  public static Set<BackendInitializationListener>
1867                     getBackendInitializationListeners()
1868  {
1869    return directoryServer.backendInitializationListeners;
1870  }
1871
1872  /**
1873   * Registers the provided backend initialization listener with the Directory
1874   * Server.
1875   *
1876   * @param  listener  The backend initialization listener to register with the
1877   *                   Directory Server.
1878   */
1879  public static void registerBackendInitializationListener(
1880                          BackendInitializationListener listener)
1881  {
1882    directoryServer.backendInitializationListeners.add(listener);
1883  }
1884
1885  /**
1886   * Deregisters the provided backend initialization listener with the Directory
1887   * Server.
1888   *
1889   * @param  listener  The backend initialization listener to deregister with
1890   *                   the Directory Server.
1891   */
1892  public static void deregisterBackendInitializationListener(
1893                          BackendInitializationListener listener)
1894  {
1895    directoryServer.backendInitializationListeners.remove(listener);
1896  }
1897
1898  /**
1899   * Initializes the set of backends defined in the Directory Server.
1900   *
1901   * @throws  ConfigException  If there is a configuration problem with any of
1902   *                           the backends.
1903   *
1904   * @throws  InitializationException  If a problem occurs while initializing
1905   *                                   the backends that is not related to the
1906   *                                   server configuration.
1907   */
1908  private void initializeBackends() throws ConfigException, InitializationException
1909  {
1910    backendConfigManager = new BackendConfigManager(serverContext);
1911    backendConfigManager.initializeBackendConfig();
1912
1913    // Make sure to initialize the root DSE backend separately after all other
1914    // backends.
1915    RootDSEBackendCfg rootDSECfg;
1916    try
1917    {
1918      RootCfg root = ServerManagementContext.getInstance().getRootConfiguration();
1919      rootDSECfg = root.getRootDSEBackend();
1920    }
1921    catch (Exception e)
1922    {
1923      logger.traceException(e);
1924      throw new InitializationException(ERR_CANNOT_GET_ROOT_DSE_CONFIG_ENTRY.get(
1925          stackTraceToSingleLineString(e)), e);
1926    }
1927
1928    rootDSEBackend = new RootDSEBackend();
1929    rootDSEBackend.configureBackend(rootDSECfg, serverContext);
1930    rootDSEBackend.openBackend();
1931  }
1932
1933  /**
1934   * Creates a set of workflows for a given backend and registers the
1935   * workflows with the default network group, the internal network group
1936   * and he admin network group. There are as many workflows
1937   * as base DNs defined in the backend.
1938   *
1939   * @param backend  the backend handled by the workflow
1940   *
1941   * @throws  DirectoryException  If the workflow ID for the provided
1942   *                              workflow conflicts with the workflow
1943   *                              ID of an existing workflow.
1944   */
1945  private static void createAndRegisterWorkflows(Backend<?> backend) throws DirectoryException
1946  {
1947    // Create a workflow for each backend base DN and register the workflow
1948    // with the default/internal/admin network group.
1949    for (DN curBaseDN: backend.getBaseDNs())
1950    {
1951      createWorkflow(curBaseDN, backend);
1952    }
1953  }
1954
1955  /**
1956   * Creates one workflow for a given base DN in a backend.
1957   *
1958   * @param baseDN   the base DN of the workflow to create
1959   * @param backend  the backend handled by the workflow
1960   * @throws  DirectoryException  If the workflow ID for the provided
1961   *                              workflow conflicts with the workflow
1962   *                              ID of an existing workflow.
1963   */
1964  private static void createWorkflow(DN baseDN, Backend<?> backend) throws DirectoryException
1965  {
1966    LocalBackendWorkflowElement.createAndRegister(baseDN, backend);
1967  }
1968
1969  /**
1970   * Creates the missing workflows, one for the config backend and one for
1971   * the rootDSE backend.
1972   *
1973   * This method should be invoked whatever may be the workflow
1974   * configuration mode because config backend and rootDSE backend
1975   * will not have any configuration section, ever.
1976   *
1977   * @throws  ConfigException  If there is a configuration problem with any of
1978   *                           the workflows.
1979   */
1980  private void createAndRegisterRemainingWorkflows()
1981      throws ConfigException
1982  {
1983    try
1984    {
1985      createAndRegisterWorkflows(configHandler);
1986      createAndRegisterWorkflows(rootDSEBackend);
1987    }
1988    catch (DirectoryException de)
1989    {
1990      throw new ConfigException(de.getMessageObject());
1991    }
1992  }
1993
1994  /**
1995   * Initializes the Directory Server group manager.
1996   *
1997   * @throws  ConfigException  If there is a configuration problem with any of
1998   *                           the group implementations.
1999   *
2000   * @throws  InitializationException  If a problem occurs while initializing
2001   *                                   the group manager that is not related to
2002   *                                   the server configuration.
2003   */
2004  private void initializeGroupManager()
2005         throws ConfigException, InitializationException
2006  {
2007    try
2008    {
2009      groupManager = new GroupManager(serverContext);
2010    }
2011    catch (DirectoryException de)
2012    {
2013      logger.traceException(de);
2014
2015      throw new InitializationException(de.getMessageObject());
2016    }
2017
2018    groupManager.initializeGroupImplementations();
2019
2020    // The configuration backend has already been registered by this point
2021    // so we need to handle it explicitly.
2022    // Because subentryManager may depend on the groupManager, let's
2023    // delay this.
2024    // groupManager.performBackendInitializationProcessing(configHandler);
2025  }
2026
2027  /**
2028   * Retrieves the Directory Server group manager.
2029   *
2030   * @return  The Directory Server group manager.
2031   */
2032  public static GroupManager getGroupManager()
2033  {
2034    return directoryServer.groupManager;
2035  }
2036
2037  /**
2038   * Retrieves the Directory Server subentry manager.
2039   *
2040   * @return  The Directory Server subentry manager.
2041   */
2042  public static SubentryManager getSubentryManager()
2043  {
2044    return directoryServer.subentryManager;
2045  }
2046
2047  /**
2048   * Initializes the set of extended operation handlers for the Directory
2049   * Server.
2050   *
2051   * @throws  ConfigException  If there is a configuration problem with any of
2052   *                           the extended operation handlers.
2053   *
2054   * @throws  InitializationException  If a problem occurs while initializing
2055   *                                   the extended operation handlers that is
2056   *                                   not related to the server configuration.
2057   */
2058  private void initializeExtendedOperations()
2059          throws ConfigException, InitializationException
2060  {
2061    extendedOperationConfigManager = new ExtendedOperationConfigManager(serverContext);
2062    extendedOperationConfigManager.initializeExtendedOperationHandlers();
2063  }
2064
2065  /**
2066   * Initializes the set of SASL mechanism handlers for the Directory Server.
2067   *
2068   * @throws  ConfigException  If there is a configuration problem with any of
2069   *                           the SASL mechanism handlers.
2070   *
2071   * @throws  InitializationException  If a problem occurs while initializing
2072   *                                   the SASL mechanism handlers that is not
2073   *                                   related to the server configuration.
2074   */
2075  private void initializeSASLMechanisms()
2076          throws ConfigException, InitializationException
2077  {
2078    saslConfigManager = new SASLConfigManager(serverContext);
2079    saslConfigManager.initializeSASLMechanismHandlers();
2080  }
2081
2082  /**
2083   * Initializes the set of connection handlers that should be defined in the
2084   * Directory Server.
2085   *
2086   * @throws  ConfigException  If there is a configuration problem with any of
2087   *                           the connection handlers.
2088   *
2089   * @throws  InitializationException  If a problem occurs while initializing
2090   *                                   the connection handlers that is not
2091   *                                   related to the server configuration.
2092   */
2093  private void initializeConnectionHandlers()
2094          throws ConfigException, InitializationException
2095  {
2096    if (connectionHandlerConfigManager == null) {
2097      connectionHandlerConfigManager = new ConnectionHandlerConfigManager(serverContext);
2098    }
2099    connectionHandlerConfigManager.initializeConnectionHandlerConfig();
2100  }
2101
2102  /**
2103   * Initializes the subentry manager for the Directory Server.
2104   * Note that the subentry manager initialization should be
2105   * done before any dependent components initialization and
2106   * before bringing any backends online. Configuration backend
2107   * is a special case and therefore is exception to this rule.
2108   *
2109   * @throws InitializationException If a problem occurs while
2110   *                                 initializing the subentry
2111   *                                 manager.
2112   */
2113  public void initializeSubentryManager()
2114          throws InitializationException
2115  {
2116    try
2117    {
2118      subentryManager = new SubentryManager();
2119
2120      // The configuration backend should already be registered
2121      // at this point so we need to handle it explicitly here.
2122      // However, subentryManager may have dependencies on the
2123      // groupManager. So lets delay the backend initialization until then.
2124      // subentryManager.performBackendInitializationProcessing(
2125      //        configHandler);
2126    }
2127    catch (DirectoryException de)
2128    {
2129      throw new InitializationException(de.getMessageObject());
2130    }
2131  }
2132
2133  /**
2134   * Initializes the set of authentication policy components for use by the
2135   * Directory Server.
2136   *
2137   * @throws ConfigException
2138   *           If there is a configuration problem with any of the
2139   *           authentication policy components.
2140   * @throws InitializationException
2141   *           If a problem occurs while initializing the authentication policy
2142   *           components that is not related to the server configuration.
2143   */
2144  public void initializeAuthenticationPolicyComponents() throws ConfigException, InitializationException
2145  {
2146    storageSchemeConfigManager = new PasswordStorageSchemeConfigManager(serverContext);
2147    storageSchemeConfigManager.initializePasswordStorageSchemes();
2148
2149    passwordValidatorConfigManager = new PasswordValidatorConfigManager(serverContext);
2150    passwordValidatorConfigManager.initializePasswordValidators();
2151
2152    passwordGeneratorConfigManager = new PasswordGeneratorConfigManager(serverContext);
2153    passwordGeneratorConfigManager.initializePasswordGenerators();
2154
2155    accountStatusNotificationHandlerConfigManager = new AccountStatusNotificationHandlerConfigManager(serverContext);
2156    accountStatusNotificationHandlerConfigManager.initializeNotificationHandlers();
2157
2158    authenticationPolicyConfigManager = new PasswordPolicyConfigManager(serverContext);
2159    authenticationPolicyConfigManager.initializeAuthenticationPolicies();
2160  }
2161
2162  /**
2163   * Retrieves the operating system on which the Directory Server is running.
2164   *
2165   * @return  The operating system on which the Directory Server is running.
2166   */
2167  public static OperatingSystem getOperatingSystem()
2168  {
2169    return directoryServer.operatingSystem;
2170  }
2171
2172  /**
2173   * Retrieves a reference to the Directory Server configuration handler.
2174   *
2175   * @return  A reference to the Directory Server configuration handler.
2176   */
2177  public static ConfigHandler getConfigHandler()
2178  {
2179    return directoryServer.configHandler;
2180  }
2181
2182  /**
2183   * Initializes the set of plugins defined in the Directory Server.  Only the
2184   * specified types of plugins will be initialized.
2185   *
2186   * @param  pluginTypes  The set of plugin types for the plugins to
2187   *                      initialize.
2188   *
2189   * @throws  ConfigException  If there is a configuration problem with any of
2190   *                           the Directory Server plugins.
2191   *
2192   * @throws  InitializationException  If a problem occurs while initializing
2193   *                                   the plugins that is not related to the
2194   *                                   server configuration.
2195   */
2196  public void initializePlugins(Set<PluginType> pluginTypes)
2197         throws ConfigException, InitializationException
2198  {
2199    pluginConfigManager = new PluginConfigManager(serverContext);
2200    pluginConfigManager.initializePluginConfigManager();
2201    pluginConfigManager.initializeUserPlugins(pluginTypes);
2202  }
2203
2204  /**
2205   *  Initializes the root DN Config Manager in the Directory Server.
2206   *
2207   * @throws ConfigException If a problem occurs registering a DN.
2208   * @throws InitializationException If a problem occurs initializing the root
2209   *                                 DN manager.
2210   */
2211  public void initializeRootDNConfigManager()
2212         throws ConfigException, InitializationException{
2213    rootDNConfigManager = new RootDNConfigManager(serverContext);
2214    rootDNConfigManager.initializeRootDNs();
2215  }
2216
2217  /**
2218   * Initialize the root DSE in the Directory Server.
2219   *
2220   * @throws ConfigException If a problem occurs retrieving the root DSE backend
2221   *                         configuration.
2222   * @throws InitializationException If a problem occurs initializing the root
2223   *                                 root DSE backend.
2224   */
2225  public void initializeRootDSE()
2226         throws ConfigException, InitializationException {
2227  RootDSEBackendCfg rootDSECfg;
2228  try {
2229    RootCfg root =
2230         ServerManagementContext.getInstance().getRootConfiguration();
2231    rootDSECfg = root.getRootDSEBackend();
2232  }  catch (Exception e) {
2233    logger.traceException(e);
2234    LocalizableMessage message = ERR_CANNOT_GET_ROOT_DSE_CONFIG_ENTRY.get(
2235        stackTraceToSingleLineString(e));
2236    throw new InitializationException(message, e);
2237  }
2238  rootDSEBackend = new RootDSEBackend();
2239  rootDSEBackend.configureBackend(rootDSECfg, serverContext);
2240  rootDSEBackend.openBackend();
2241}
2242
2243  /**
2244   * Retrieves a reference to the Directory Server plugin configuration manager.
2245   *
2246   * @return  A reference to the Directory Server plugin configuration manager.
2247   */
2248  public static PluginConfigManager getPluginConfigManager()
2249  {
2250    return directoryServer.pluginConfigManager;
2251  }
2252
2253  /**
2254   * Registers the provided internal plugin with the Directory Server
2255   * and ensures that it will be invoked in the specified ways.
2256   *
2257   * @param plugin
2258   *          The internal plugin to register with the Directory Server.
2259   *          The plugin must specify a configuration entry which is
2260   *          guaranteed to be unique.
2261   */
2262  public static void registerInternalPlugin(
2263      InternalDirectoryServerPlugin plugin)
2264  {
2265    directoryServer.pluginConfigManager.registerInternalPlugin(plugin);
2266  }
2267
2268  /**
2269   * Deregisters the provided internal plugin with the Directory Server.
2270   *
2271   * @param plugin
2272   *          The internal plugin to deregister from the Directory Server.
2273   */
2274  public static void deregisterInternalPlugin(
2275      InternalDirectoryServerPlugin plugin)
2276  {
2277    directoryServer.pluginConfigManager.deregisterInternalPlugin(plugin);
2278  }
2279
2280  /**
2281   * Retrieves the requested entry from the Directory Server configuration.
2282   *
2283   * @param  entryDN  The DN of the configuration entry to retrieve.
2284   *
2285   * @return  The requested entry from the Directory Server configuration.
2286   *
2287   * @throws  ConfigException  If a problem occurs while trying to retrieve the
2288   *                           requested entry.
2289   */
2290  public static ConfigEntry getConfigEntry(DN entryDN)
2291         throws ConfigException
2292  {
2293    return directoryServer.configHandler.getConfigEntry(entryDN);
2294  }
2295
2296  /**
2297   * Retrieves the path to the root directory for this instance of the Directory
2298   * Server.
2299   *
2300   * @return  The path to the root directory for this instance of the Directory
2301   *          Server.
2302  */
2303  public static String getServerRoot()
2304  {
2305    return directoryServer.environmentConfig.getServerRootAsString();
2306  }
2307
2308  /**
2309   * Retrieves the path to the instance directory for this instance of the
2310   * Directory Server.
2311   *
2312   * @return The path to the instance directory for this instance of
2313   * the Directory Server.
2314   */
2315  public static String getInstanceRoot()
2316  {
2317    return directoryServer.environmentConfig.getInstanceRootAsString();
2318  }
2319
2320  /**
2321   * Retrieves the time that the Directory Server was started, in milliseconds
2322   * since the epoch.
2323   *
2324   * @return  The time that the Directory Server was started, in milliseconds
2325   *          since the epoch.
2326   */
2327  public static long getStartTime()
2328  {
2329    return directoryServer.startUpTime;
2330  }
2331
2332  /**
2333   * Retrieves the time that the Directory Server was started, formatted in UTC.
2334   *
2335   * @return  The time that the Directory Server was started, formatted in UTC.
2336   */
2337  public static String getStartTimeUTC()
2338  {
2339    return directoryServer.startTimeUTC;
2340  }
2341
2342  /**
2343   * Retrieves a reference to the Directory Server schema.
2344   *
2345   * @return  A reference to the Directory Server schema.
2346   */
2347  public static Schema getSchema()
2348  {
2349    return directoryServer.schema;
2350  }
2351
2352  /**
2353   * Replaces the Directory Server schema with the provided schema.
2354   *
2355   * @param  schema  The new schema to use for the Directory Server.
2356   */
2357  public static void setSchema(Schema schema)
2358  {
2359    directoryServer.schema = schema;
2360  }
2361
2362  /**
2363   * Retrieves a list of modifications detailing any schema changes that may
2364   * have been made with the server offline (e.g., by directly editing the
2365   * schema configuration files).  Note that this information will not be
2366   * available until the server backends (and in particular, the schema backend)
2367   * have been initialized.
2368   *
2369   * @return  A list of modifications detailing any schema changes that may have
2370   *          been made with the server offline, or an empty list if no offline
2371   *          schema changes have been detected.
2372   */
2373  public static List<Modification> getOfflineSchemaChanges()
2374  {
2375    return directoryServer.offlineSchemaChanges;
2376  }
2377
2378  /**
2379   * Specifies a list of modifications detailing any schema changes that may
2380   * have been made with the server offline.
2381   *
2382   * @param  offlineSchemaChanges  A list of modifications detailing any schema
2383   *                               changes that may have been made with the
2384   *                               server offline.  It must not be {@code null}.
2385   */
2386  public static void setOfflineSchemaChanges(List<Modification>
2387                                                  offlineSchemaChanges)
2388  {
2389    ifNull(offlineSchemaChanges);
2390
2391    directoryServer.offlineSchemaChanges = offlineSchemaChanges;
2392  }
2393
2394  /**
2395   * Retrieves the set of matching rules registered with the Directory Server.
2396   * The mapping will be between the lowercase name or OID for each matching
2397   * rule and the matching rule implementation.  The same matching rule instance
2398   * may be included multiple times with different keys.
2399   *
2400   * @return  The set of matching rules registered with the Directory Server.
2401   */
2402  public static ConcurrentMap<String, MatchingRule> getMatchingRules()
2403  {
2404    return directoryServer.schema.getMatchingRules();
2405  }
2406
2407  /**
2408   * Retrieves the matching rule with the specified name or OID.
2409   *
2410   * @param  lowerName  The lowercase name or OID for the matching rule to
2411   *                    retrieve.
2412   *
2413   * @return  The requested matching rule, or <CODE>null</CODE> if no such
2414   *          matching rule has been defined in the server.
2415   */
2416  public static MatchingRule getMatchingRule(String lowerName)
2417  {
2418    return directoryServer.schema.getMatchingRule(lowerName);
2419  }
2420
2421  /**
2422   * Registers the provided matching rule with the Directory Server.
2423   *
2424   * @param  matchingRule       The matching rule to register with the server.
2425   * @param  overwriteExisting  Indicates whether to overwrite an existing
2426   *                            mapping if there are any conflicts (i.e.,
2427   *                            another matching rule with the same OID or
2428   *                            name).
2429   *
2430   * @throws  DirectoryException  If a conflict is encountered and the
2431   *                              <CODE>overwriteExisting</CODE> flag is set to
2432   *                              <CODE>false</CODE>
2433   */
2434  public static void registerMatchingRule(MatchingRule matchingRule,
2435                                          boolean overwriteExisting)
2436         throws DirectoryException
2437  {
2438    directoryServer.schema.registerMatchingRule(matchingRule,
2439                                                overwriteExisting);
2440  }
2441
2442  /**
2443   * Deregisters the provided matching rule with the Directory Server.
2444   *
2445   * @param  matchingRule  The matching rule to deregister with the server.
2446   */
2447  public static void deregisterMatchingRule(MatchingRule matchingRule)
2448  {
2449    directoryServer.schema.deregisterMatchingRule(matchingRule);
2450  }
2451
2452  /**
2453   * Retrieves the set of objectclasses defined in the Directory Server.
2454   *
2455   * @return  The set of objectclasses defined in the Directory Server.
2456   */
2457  public static ConcurrentMap<String, ObjectClass> getObjectClasses()
2458  {
2459    return directoryServer.schema.getObjectClasses();
2460  }
2461
2462  /**
2463   * Retrieves the objectclass for the provided lowercase name or OID.
2464   *
2465   * @param  lowerName  The lowercase name or OID for the objectclass to
2466   *                    retrieve.
2467   *
2468   * @return  The requested objectclass, or <CODE>null</CODE> if there is no
2469   *          such objectclass defined in the server schema.
2470   */
2471  public static ObjectClass getObjectClass(String lowerName)
2472  {
2473    return directoryServer.schema.getObjectClass(lowerName);
2474  }
2475
2476  /**
2477   * Retrieves the objectclass for the provided lowercase name or OID.  It can
2478   * optionally return a generated "default" version if the requested
2479   * objectclass is not defined in the schema.
2480   *
2481   * @param  lowerName      The lowercase name or OID for the objectclass to
2482   *                        retrieve.
2483   * @param  returnDefault  Indicates whether to generate a default version if
2484   *                        the requested objectclass is not defined in the
2485   *                        server schema.
2486   *
2487   * @return  The objectclass type, or <CODE>null</CODE> if there is no
2488   *          objectclass with the specified name or OID defined in the server
2489   *          schema and a default class should not be returned.
2490   */
2491  public static ObjectClass getObjectClass(String lowerName,
2492                                           boolean returnDefault)
2493  {
2494    ObjectClass oc = directoryServer.schema.getObjectClass(lowerName);
2495    if (returnDefault && oc == null)
2496    {
2497      oc = getDefaultObjectClass(lowerName);
2498    }
2499
2500    return oc;
2501  }
2502
2503  /**
2504   * Registers the provided objectclass with the Directory Server.
2505   *
2506   * @param  objectClass        The objectclass instance to register with the
2507   *                            server.
2508   * @param  overwriteExisting  Indicates whether to overwrite an existing
2509   *                            mapping if there are any conflicts (i.e.,
2510   *                            another objectclass with the same OID or
2511   *                            name).
2512   *
2513   * @throws  DirectoryException  If a conflict is encountered and the
2514   *                              <CODE>overwriteExisting</CODE> flag is set to
2515   *                              <CODE>false</CODE>
2516   */
2517  public static void registerObjectClass(ObjectClass objectClass,
2518                                         boolean overwriteExisting)
2519         throws DirectoryException
2520  {
2521    directoryServer.schema.registerObjectClass(objectClass, overwriteExisting);
2522  }
2523
2524  /**
2525   * Deregisters the provided objectclass with the Directory Server.
2526   *
2527   * @param  objectClass  The objectclass instance to deregister with the
2528   *                      server.
2529   */
2530  public static void deregisterObjectClass(ObjectClass objectClass)
2531  {
2532    directoryServer.schema.deregisterObjectClass(objectClass);
2533  }
2534
2535  /**
2536   * Retrieves the "top" objectClass, which should be the topmost objectclass in
2537   * the inheritance chain for most other objectclasses.  If no such objectclass
2538   * could be found, then one will be constructed.
2539   *
2540   * @return  The "top" objectClass.
2541   */
2542  public static ObjectClass getTopObjectClass()
2543  {
2544    ObjectClass objectClass =
2545         directoryServer.schema.getObjectClass(TOP_OBJECTCLASS_NAME);
2546    if (objectClass == null)
2547    {
2548      String definition =
2549           "( 2.5.6.0 NAME 'top' ABSTRACT MUST objectClass " +
2550           "X-ORIGIN 'RFC 2256' )";
2551
2552      objectClass = new ObjectClass(definition, TOP_OBJECTCLASS_NAME,
2553                                    Collections.singleton(TOP_OBJECTCLASS_NAME),
2554                                    TOP_OBJECTCLASS_OID,
2555                                    TOP_OBJECTCLASS_DESCRIPTION, null, null,
2556                                    null, ObjectClassType.ABSTRACT, false,
2557                                    null);
2558    }
2559
2560    return objectClass;
2561  }
2562
2563  /**
2564   * Causes the Directory Server to construct a new objectclass
2565   * definition with the provided name and with no required or allowed
2566   * attributes. This should only be used if there is no objectclass
2567   * for the specified name. It will not register the created
2568   * objectclass with the Directory Server.
2569   *
2570   * @param name
2571   *          The name to use for the objectclass, as provided by the
2572   *          user.
2573   * @return The constructed objectclass definition.
2574   */
2575  public static ObjectClass getDefaultObjectClass(String name)
2576  {
2577    String lowerName = toLowerCase(name);
2578    ObjectClass objectClass = directoryServer.schema.getObjectClass(lowerName);
2579    if (objectClass == null)
2580    {
2581      String oid        = lowerName + "-oid";
2582      String definition = "( " + oid + " NAME '" + name + "' ABSTRACT )";
2583
2584      // Temporary object classes are immediately dirty.
2585      objectClass = new ObjectClass(definition, name,
2586          Collections.singleton(name), oid, null,
2587          Collections.singleton(getTopObjectClass()), null, null,
2588          ObjectClassType.ABSTRACT, false, null).setDirty();
2589    }
2590
2591    return objectClass;
2592  }
2593
2594  /**
2595   * Causes the Directory Server to construct a new auxiliary objectclass
2596   * definition with the provided name and with no required or allowed
2597   * attributes. This should only be used if there is no objectclass for the
2598   * specified name. It will not register the created objectclass with the
2599   * Directory Server.
2600   *
2601   * @param  name  The name to use for the objectclass, as provided by the user.
2602   *
2603   * @return  The constructed objectclass definition.
2604   */
2605  public static ObjectClass getDefaultAuxiliaryObjectClass(String name)
2606  {
2607    String lowerName = toLowerCase(name);
2608    ObjectClass objectClass = directoryServer.schema.getObjectClass(lowerName);
2609    if (objectClass == null)
2610    {
2611      String oid        = lowerName + "-oid";
2612      String definition = "( " + oid + " NAME '" + name + "' ABSTRACT )";
2613
2614      objectClass = new ObjectClass(definition, name,
2615                                    Collections.singleton(name), oid, null,
2616                                    Collections.singleton(getTopObjectClass()),
2617                                    null, null,
2618                                    ObjectClassType.AUXILIARY, false, null);
2619    }
2620
2621    return objectClass;
2622  }
2623
2624  /**
2625   * Retrieves the set of attribute type definitions that have been
2626   * defined in the Directory Server.
2627   *
2628   * @return The set of attribute type definitions that have been
2629   *         defined in the Directory Server.
2630   */
2631  public static ConcurrentMap<String, AttributeType> getAttributeTypes()
2632  {
2633    return directoryServer.schema.getAttributeTypes();
2634  }
2635
2636  /**
2637   * Retrieves the attribute type for the provided lowercase name or OID.
2638   *
2639   * @param  lowerName  The lowercase attribute name or OID for the attribute
2640   *                    type to retrieve.
2641   *
2642   * @return  The requested attribute type, or <CODE>null</CODE> if there is no
2643   *          attribute with the specified type defined in the server schema.
2644   */
2645  public static AttributeType getAttributeType(String lowerName)
2646  {
2647    return directoryServer.schema.getAttributeType(lowerName);
2648  }
2649
2650  /**
2651   * Retrieves the attribute type for the provided lowercase name or OID.  It
2652   * can optionally return a generated "default" version if the requested
2653   * attribute type is not defined in the schema.
2654   *
2655   * @param  lowerName      The lowercase name or OID for the attribute type to
2656   *                        retrieve.
2657   * @return  The requested attribute type, or <CODE>null</CODE> if there is no
2658   *          attribute with the specified type defined in the server schema and
2659   *          a default type should not be returned.
2660   */
2661  public static AttributeType getAttributeTypeOrDefault(String lowerName)
2662  {
2663    AttributeType type = directoryServer.schema.getAttributeType(lowerName);
2664    if (type == null)
2665    {
2666      type = getDefaultAttributeType(lowerName);
2667    }
2668    return type;
2669  }
2670
2671  /**
2672   * Retrieves the attribute type for the provided lowercase name or OID. It will return a generated
2673   * "default" version with the uppercase name or OID if the requested attribute type is not defined
2674   * in the schema.
2675   *
2676   * @param lowerName
2677   *          The lowercase name or OID for the attribute type to retrieve.
2678   * @param upperName
2679   *          The uppercase name or OID for the attribute type to generate.
2680   * @return The requested attribute type, or a generated "default" version if there is no attribute
2681   *         with the specified type defined in the server schema
2682   */
2683  public static AttributeType getAttributeTypeOrDefault(String lowerName, String upperName)
2684  {
2685    AttributeType type = directoryServer.schema.getAttributeType(lowerName);
2686    if (type == null)
2687    {
2688      type = getDefaultAttributeType(upperName);
2689    }
2690    return type;
2691  }
2692
2693  /**
2694   * Registers the provided attribute type with the Directory Server.
2695   *
2696   * @param  attributeType      The attribute type to register with the
2697   *                            Directory Server.
2698   * @param  overwriteExisting  Indicates whether to overwrite an existing
2699   *                            mapping if there are any conflicts (i.e.,
2700   *                            another attribute type with the same OID or
2701   *                            name).
2702   *
2703   * @throws  DirectoryException  If a conflict is encountered and the
2704   *                              <CODE>overwriteExisting</CODE> flag is set to
2705   *                              <CODE>false</CODE>
2706   */
2707  public static void registerAttributeType(AttributeType attributeType,
2708                                           boolean overwriteExisting)
2709         throws DirectoryException
2710  {
2711    directoryServer.schema.registerAttributeType(attributeType,
2712                                                 overwriteExisting);
2713  }
2714
2715  /**
2716   * Deregisters the provided attribute type with the Directory Server.
2717   *
2718   * @param  attributeType  The attribute type to deregister with the Directory
2719   *                        Server.
2720   */
2721  public static void deregisterAttributeType(AttributeType attributeType)
2722  {
2723    directoryServer.schema.deregisterAttributeType(attributeType);
2724  }
2725
2726  /**
2727   * Retrieves the attribute type for the "objectClass" attribute.
2728   *
2729   * @return  The attribute type for the "objectClass" attribute.
2730   */
2731  public static AttributeType getObjectClassAttributeType()
2732  {
2733    if (directoryServer.objectClassAttributeType == null)
2734    {
2735      directoryServer.objectClassAttributeType =
2736           directoryServer.schema.getAttributeType(
2737                OBJECTCLASS_ATTRIBUTE_TYPE_NAME);
2738
2739      if (directoryServer.objectClassAttributeType == null)
2740      {
2741        Syntax oidSyntax = directoryServer.schema.getSyntax(SYNTAX_OID_NAME);
2742        if (oidSyntax == null)
2743        {
2744          try
2745          {
2746            oidSyntax = CoreSchema.getOIDSyntax();
2747            directoryServer.schema.registerSyntax(oidSyntax, true);
2748          }
2749          catch (Exception e)
2750          {
2751            logger.traceException(e);
2752          }
2753        }
2754
2755        String definition =
2756             "( 2.5.4.0 NAME 'objectClass' EQUALITY objectIdentifierMatch " +
2757             "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 X-ORIGIN 'RFC 2256' )";
2758
2759        directoryServer.objectClassAttributeType =
2760             new AttributeType(definition, "objectClass",
2761                               Collections.singleton("objectClass"),
2762                               OBJECTCLASS_ATTRIBUTE_TYPE_OID, null, null,
2763                               oidSyntax, AttributeUsage.USER_APPLICATIONS,
2764                               false, false, false, false);
2765        try
2766        {
2767          directoryServer.schema.registerAttributeType(
2768                 directoryServer.objectClassAttributeType, true);
2769        }
2770        catch (Exception e)
2771        {
2772          // This should never happen.
2773          logger.traceException(e);
2774        }
2775      }
2776    }
2777
2778    return directoryServer.objectClassAttributeType;
2779  }
2780
2781  /**
2782   * Causes the Directory Server to construct a new attribute type definition
2783   * with the provided name and using the default attribute syntax.  This should
2784   * only be used if there is no real attribute type for the specified name.
2785   *
2786   * @param  name  The name to use for the attribute type, as provided by the
2787   *               user.
2788   *
2789   * @return  The constructed attribute type definition.
2790   */
2791  public static AttributeType getDefaultAttributeType(String name)
2792  {
2793    return getDefaultAttributeType(name, getDefaultAttributeSyntax());
2794  }
2795
2796  /**
2797   * Causes the Directory Server to construct a new attribute type definition
2798   * with the provided name and syntax.  This should only be used if there is no
2799   * real attribute type for the specified name.
2800   *
2801   * @param  name    The name to use for the attribute type, as provided by the
2802   *                 user.
2803   * @param  syntax  The syntax to use for the attribute type.
2804   *
2805   * @return  The constructed attribute type definition.
2806   */
2807  public static AttributeType getDefaultAttributeType(String name, Syntax syntax)
2808  {
2809    String oid        = toLowerCase(name) + "-oid";
2810    String definition = "( " + oid + " NAME '" + name + "' SYNTAX " +
2811                        syntax.getOID() + " )";
2812
2813    // Temporary attribute types are immediately dirty.
2814    return new AttributeType(definition, name, Collections.singleton(name),
2815                             oid, null, null, syntax,
2816                             AttributeUsage.USER_APPLICATIONS, false, false,
2817                             false, false).setDirty();
2818  }
2819
2820  /**
2821   * Retrieves the set of attribute syntaxes defined in the Directory Server.
2822   *
2823   * @return The set of attribute syntaxes defined in the Directory Server.
2824   */
2825  public static ConcurrentMap<String, Syntax> getAttributeSyntaxes()
2826  {
2827    return directoryServer.schema.getSyntaxes();
2828  }
2829
2830  /**
2831   * Retrieves the default attribute syntax that should be used for attributes
2832   * that are not defined in the server schema.
2833   *
2834   * @return  The default attribute syntax that should be used for attributes
2835   *          that are not defined in the server schema.
2836   */
2837  public static Syntax getDefaultAttributeSyntax()
2838  {
2839    return directoryServer.getDefaultSyntax();
2840  }
2841
2842  /**
2843   * Retrieves the default attribute syntax that should be used for attributes
2844   * that are not defined in the server schema and are meant to store binary
2845   * values.
2846   *
2847   * @return  The default attribute syntax that should be used for attributes
2848   *          that are not defined in the server schema and are meant to store
2849   *          binary values.
2850   */
2851  public static Syntax getDefaultBinarySyntax()
2852  {
2853    return CoreSchema.getBinarySyntax();
2854  }
2855
2856  /**
2857   * Retrieves the default attribute syntax that should be used for attributes
2858   * that are not defined in the server schema and are meant to store Boolean
2859   * values.
2860   *
2861   * @return  The default attribute syntax that should be used for attributes
2862   *          that are not defined in the server schema and are meant to store
2863   *          Boolean values.
2864   */
2865  public static Syntax getDefaultBooleanSyntax()
2866  {
2867    return CoreSchema.getBooleanSyntax();
2868  }
2869
2870  /**
2871   * Retrieves the default attribute syntax that should be used for attributes
2872   * that are not defined in the server schema and are meant to store DN values.
2873   *
2874   * @return  The default attribute syntax that should be used for attributes
2875   *          that are not defined in the server schema and are meant to store
2876   *          DN values.
2877   */
2878  public static Syntax getDefaultDNSyntax()
2879  {
2880    return CoreSchema.getDNSyntax();
2881  }
2882
2883  /**
2884   * Retrieves the default attribute syntax that should be used for attributes
2885   * that are not defined in the server schema and are meant to store integer
2886   * values.
2887   *
2888   * @return  The default attribute syntax that should be used for attributes
2889   *          that are not defined in the server schema and are meant to store
2890   *          integer values.
2891   */
2892  public static Syntax getDefaultIntegerSyntax()
2893  {
2894    return CoreSchema.getIntegerSyntax();
2895  }
2896
2897  /**
2898   * Retrieves the default attribute syntax that should be used for attributes
2899   * that are not defined in the server schema and are meant to store string
2900   * values.
2901   *
2902   * @return  The default attribute syntax that should be used for attributes
2903   *          that are not defined in the server schema and are meant to store
2904   *          string values.
2905   */
2906  public static Syntax getDefaultStringSyntax()
2907  {
2908    return CoreSchema.getDirectoryStringSyntax();
2909  }
2910
2911  private Syntax getDefaultSyntax()
2912  {
2913    return CoreSchema.getDirectoryStringSyntax();
2914  }
2915
2916  /**
2917   * Retrieves the set of matching rule uses defined in the Directory Server.
2918   *
2919   * @return  The set of matching rule uses defined in the Directory Server.
2920   */
2921  public static ConcurrentMap<MatchingRule, MatchingRuleUse>
2922                     getMatchingRuleUses()
2923  {
2924    return directoryServer.schema.getMatchingRuleUses();
2925  }
2926
2927  /**
2928   * Retrieves the matching rule use associated with the provided matching rule.
2929   *
2930   * @param  matchingRule  The matching rule for which to retrieve the matching
2931   *                       rule use.
2932   *
2933   * @return  The matching rule use for the provided matching rule, or
2934   *          <CODE>null</CODE> if none is defined.
2935   */
2936  public static MatchingRuleUse getMatchingRuleUse(MatchingRule matchingRule)
2937  {
2938    return directoryServer.schema.getMatchingRuleUse(matchingRule);
2939  }
2940
2941  /**
2942   * Registers the provided matching rule use with the Directory Server.
2943   *
2944   * @param  matchingRuleUse    The matching rule use to register with the
2945   *                            server.
2946   * @param  overwriteExisting  Indicates whether to overwrite an existing
2947   *                            mapping if there are any conflicts (i.e.,
2948   *                            another matching rule use with the same matching
2949   *                            rule).
2950   *
2951   * @throws  DirectoryException  If a conflict is encountered and the
2952   *                              <CODE>overwriteExisting</CODE> flag is set to
2953   *                              <CODE>false</CODE>
2954   */
2955  public static void registerMatchingRuleUse(MatchingRuleUse matchingRuleUse,
2956                                             boolean overwriteExisting)
2957         throws DirectoryException
2958  {
2959    directoryServer.schema.registerMatchingRuleUse(matchingRuleUse,
2960                                                   overwriteExisting);
2961  }
2962
2963  /**
2964   * Deregisters the provided matching rule use with the Directory Server.
2965   *
2966   * @param  matchingRuleUse  The matching rule use to deregister with the
2967   *                          server.
2968   */
2969  public static void deregisterMatchingRuleUse(MatchingRuleUse matchingRuleUse)
2970  {
2971    directoryServer.schema.deregisterMatchingRuleUse(matchingRuleUse);
2972  }
2973
2974  /**
2975   * Retrieves the set of DIT content rules defined in the Directory Server.
2976   *
2977   * @return  The set of DIT content rules defined in the Directory Server.
2978   */
2979  public static ConcurrentMap<ObjectClass, DITContentRule>
2980                     getDITContentRules()
2981  {
2982    return directoryServer.schema.getDITContentRules();
2983  }
2984
2985  /**
2986   * Retrieves the DIT content rule associated with the specified objectclass.
2987   *
2988   * @param  objectClass  The objectclass for which to retrieve the associated
2989   *                      DIT content rule.
2990   *
2991   * @return  The requested DIT content rule, or <CODE>null</CODE> if no such
2992   *          rule is defined in the schema.
2993   */
2994  public static DITContentRule getDITContentRule(ObjectClass objectClass)
2995  {
2996    return directoryServer.schema.getDITContentRule(objectClass);
2997  }
2998
2999  /**
3000   * Registers the provided DIT content rule with the Directory Server.
3001   *
3002   * @param  ditContentRule     The DIT content rule to register with the
3003   *                            server.
3004   * @param  overwriteExisting  Indicates whether to overwrite an existing
3005   *                            mapping if there are any conflicts (i.e.,
3006   *                            another DIT content rule with the same
3007   *                            structural objectclass).
3008   *
3009   * @throws  DirectoryException  If a conflict is encountered and the
3010   *                              <CODE>overwriteExisting</CODE> flag is set to
3011   *                              <CODE>false</CODE>
3012   */
3013  public static void registerDITContentRule(DITContentRule ditContentRule,
3014                                            boolean overwriteExisting)
3015         throws DirectoryException
3016  {
3017    directoryServer.schema.registerDITContentRule(ditContentRule,
3018                                                  overwriteExisting);
3019  }
3020
3021  /**
3022   * Deregisters the provided DIT content rule with the Directory Server.
3023   *
3024   * @param  ditContentRule  The DIT content rule to deregister with the server.
3025   */
3026  public static void deregisterDITContentRule(DITContentRule ditContentRule)
3027  {
3028    directoryServer.schema.deregisterDITContentRule(ditContentRule);
3029  }
3030
3031  /**
3032   * Retrieves the set of DIT structure rules defined in the Directory Server.
3033   *
3034   * @return  The set of DIT structure rules defined in the Directory Server.
3035   */
3036  public static ConcurrentMap<NameForm, DITStructureRule>
3037                     getDITStructureRules()
3038  {
3039    return directoryServer.schema.getDITStructureRulesByNameForm();
3040  }
3041
3042  /**
3043   * Retrieves the DIT structure rule associated with the provided rule ID.
3044   *
3045   * @param  ruleID  The rule ID for which to retrieve the associated DIT
3046   *                 structure rule.
3047   *
3048   * @return  The requested DIT structure rule, or <CODE>null</CODE> if no such
3049   *          rule is defined.
3050   */
3051  public static DITStructureRule getDITStructureRule(int ruleID)
3052  {
3053    return directoryServer.schema.getDITStructureRule(ruleID);
3054  }
3055
3056  /**
3057   * Retrieves the DIT structure rule associated with the provided name form.
3058   *
3059   * @param  nameForm  The name form for which to retrieve the associated DIT
3060   *                   structure rule.
3061   *
3062   * @return  The requested DIT structure rule, or <CODE>null</CODE> if no such
3063   *          rule is defined.
3064   */
3065  public static DITStructureRule getDITStructureRule(NameForm nameForm)
3066  {
3067    return directoryServer.schema.getDITStructureRule(nameForm);
3068  }
3069
3070  /**
3071   * Registers the provided DIT structure rule with the Directory Server.
3072   *
3073   * @param  ditStructureRule   The DIT structure rule to register with the
3074   *                            server.
3075   * @param  overwriteExisting  Indicates whether to overwrite an existing
3076   *                            mapping if there are any conflicts (i.e.,
3077   *                            another DIT structure rule with the same name
3078   *                            form).
3079   *
3080   * @throws  DirectoryException  If a conflict is encountered and the
3081   *                              <CODE>overwriteExisting</CODE> flag is set to
3082   *                              <CODE>false</CODE>
3083   */
3084  public static void registerDITStructureRule(DITStructureRule ditStructureRule,
3085                                              boolean overwriteExisting)
3086         throws DirectoryException
3087  {
3088    directoryServer.schema.registerDITStructureRule(ditStructureRule,
3089                                                    overwriteExisting);
3090  }
3091
3092  /**
3093   * Deregisters the provided DIT structure rule with the Directory Server.
3094   *
3095   * @param  ditStructureRule  The DIT structure rule to deregister with the
3096   *                           server.
3097   */
3098  public static void deregisterDITStructureRule(DITStructureRule
3099                                                     ditStructureRule)
3100  {
3101    directoryServer.schema.deregisterDITStructureRule(ditStructureRule);
3102  }
3103
3104  /**
3105   * Retrieves the set of name forms defined in the Directory Server.
3106   *
3107   * @return  The set of name forms defined in the Directory Server.
3108   */
3109  public static ConcurrentMap<ObjectClass, List<NameForm>> getNameForms()
3110  {
3111    return directoryServer.schema.getNameFormsByObjectClass();
3112  }
3113
3114  /**
3115   * Retrieves the name forms associated with the specified objectclass.
3116   *
3117   * @param  objectClass  The objectclass for which to retrieve the associated
3118   *                      name form.
3119   *
3120   * @return  The requested name forms, or <CODE>null</CODE> if no such name
3121   *           form is defined in the schema.
3122   */
3123  public static List<NameForm> getNameForm(ObjectClass objectClass)
3124  {
3125    return directoryServer.schema.getNameForm(objectClass);
3126  }
3127
3128  /**
3129   * Retrieves the name form associated with the specified name or OID.
3130   *
3131   * @param  lowerName  The name or OID of the name form to retrieve, formatted
3132   *                    in all lowercase characters.
3133   *
3134   * @return  The requested name form, or <CODE>null</CODE> if no such name form
3135   *          is defined in the schema.
3136   */
3137  public static NameForm getNameForm(String lowerName)
3138  {
3139    return directoryServer.schema.getNameForm(lowerName);
3140  }
3141
3142  /**
3143   * Registers the provided name form with the Directory Server.
3144   *
3145   * @param  nameForm           The name form to register with the server.
3146   * @param  overwriteExisting  Indicates whether to overwrite an existing
3147   *                            mapping if there are any conflicts (i.e.,
3148   *                            another name form with the same structural
3149   *                            objectclass).
3150   *
3151   * @throws  DirectoryException  If a conflict is encountered and the
3152   *                              <CODE>overwriteExisting</CODE> flag is set to
3153   *                              <CODE>false</CODE>
3154   */
3155  public static void registerNameForm(NameForm nameForm,
3156                                      boolean overwriteExisting)
3157         throws DirectoryException
3158  {
3159    directoryServer.schema.registerNameForm(nameForm, overwriteExisting);
3160  }
3161
3162  /**
3163   * Deregisters the provided name form with the Directory Server.
3164   *
3165   * @param  nameForm  The name form to deregister with the server.
3166   */
3167  public static void deregisterNameForm(NameForm nameForm)
3168  {
3169    directoryServer.schema.deregisterNameForm(nameForm);
3170  }
3171
3172  /**
3173   * Retrieves the set of virtual attribute rules registered with the Directory
3174   * Server.
3175   *
3176   * @return  The set of virtual attribute rules registered with the Directory
3177   *          Server.
3178   */
3179  public static Collection<VirtualAttributeRule> getVirtualAttributes()
3180  {
3181    return directoryServer.virtualAttributeConfigManager.getVirtualAttributes();
3182  }
3183
3184  /**
3185   * Retrieves the set of virtual attribute rules registered with the Directory
3186   * Server that are applicable to the provided entry.
3187   *
3188   * @param  entry  The entry for which to retrieve the applicable virtual
3189   *                attribute rules.
3190   *
3191   * @return  The set of virtual attribute rules registered with the Directory
3192   *          Server that apply to the given entry.  It may be an empty list if
3193   *          there are no applicable virtual attribute rules.
3194   */
3195  public static List<VirtualAttributeRule> getVirtualAttributes(Entry entry)
3196  {
3197    List<VirtualAttributeRule> ruleList = new LinkedList<>();
3198    for (VirtualAttributeRule rule : getVirtualAttributes())
3199    {
3200      if (rule.appliesToEntry(entry))
3201      {
3202        ruleList.add(rule);
3203      }
3204    }
3205    return ruleList;
3206  }
3207
3208  /**
3209   * Registers the provided virtual attribute rule with the Directory Server.
3210   *
3211   * @param  rule  The virtual attribute rule to be registered.
3212   */
3213  public static void registerVirtualAttribute(final VirtualAttributeRule rule)
3214  {
3215    getInstance().virtualAttributeConfigManager.register(rule);
3216  }
3217
3218  /**
3219   * Deregisters the provided virtual attribute rule with the Directory Server.
3220   *
3221   * @param  rule  The virtual attribute rule to be deregistered.
3222   */
3223  public static void deregisterVirtualAttribute(VirtualAttributeRule rule)
3224  {
3225    getInstance().virtualAttributeConfigManager.deregister(rule);
3226  }
3227
3228  /**
3229   * Retrieves a reference to the JMX MBean server that is associated with the
3230   * Directory Server.
3231   *
3232   * @return  The JMX MBean server that is associated with the Directory Server.
3233   */
3234  public static MBeanServer getJMXMBeanServer()
3235  {
3236    return directoryServer.mBeanServer;
3237  }
3238
3239  /**
3240   * Retrieves the set of JMX MBeans that are associated with the server.
3241   *
3242   * @return  The set of JMX MBeans that are associated with the server.
3243   */
3244  public static ConcurrentHashMap<DN,JMXMBean> getJMXMBeans()
3245  {
3246    return directoryServer.mBeans;
3247  }
3248
3249  /**
3250   * Retrieves the JMX MBean associated with the specified entry in the
3251   * Directory Server configuration.
3252   *
3253   * @param  configEntryDN  The DN of the configuration entry for which to
3254   *                        retrieve the associated JMX MBean.
3255   *
3256   * @return  The JMX MBean associated with the specified entry in the Directory
3257   *          Server configuration, or <CODE>null</CODE> if there is no MBean
3258   *          for the specified entry.
3259   */
3260  public static JMXMBean getJMXMBean(DN configEntryDN)
3261  {
3262    return directoryServer.mBeans.get(configEntryDN);
3263  }
3264
3265  /**
3266   * Registers the provided invokable component with the Directory Server.
3267   *
3268   * @param  component  The invokable component to register.
3269   */
3270  public static void registerInvokableComponent(InvokableComponent component)
3271  {
3272    DN componentDN = component.getInvokableComponentEntryDN();
3273    JMXMBean mBean = directoryServer.mBeans.get(componentDN);
3274    if (mBean == null)
3275    {
3276      mBean = new JMXMBean(componentDN);
3277      mBean.addInvokableComponent(component);
3278      directoryServer.mBeans.put(componentDN, mBean);
3279    }
3280    else
3281    {
3282      mBean.addInvokableComponent(component);
3283    }
3284  }
3285
3286  /**
3287   * Deregisters the provided invokable component with the Directory Server.
3288   *
3289   * @param  component  The invokable component to deregister.
3290   */
3291  public static void deregisterInvokableComponent(InvokableComponent component)
3292  {
3293    DN componentDN = component.getInvokableComponentEntryDN();
3294    JMXMBean mBean = directoryServer.mBeans.get(componentDN);
3295    if (mBean != null)
3296    {
3297      mBean.removeInvokableComponent(component);
3298    }
3299  }
3300
3301  /**
3302   * Registers the provided alert generator with the Directory Server.
3303   *
3304   * @param  alertGenerator  The alert generator to register.
3305   */
3306  public static void registerAlertGenerator(AlertGenerator alertGenerator)
3307  {
3308    DN componentDN = alertGenerator.getComponentEntryDN();
3309    JMXMBean mBean = directoryServer.mBeans.get(componentDN);
3310    if (mBean == null)
3311    {
3312      mBean = new JMXMBean(componentDN);
3313      mBean.addAlertGenerator(alertGenerator);
3314      directoryServer.mBeans.put(componentDN, mBean);
3315    }
3316    else
3317    {
3318      mBean.addAlertGenerator(alertGenerator);
3319    }
3320  }
3321
3322  /**
3323   * Deregisters the provided alert generator with the Directory Server.
3324   *
3325   * @param  alertGenerator  The alert generator to deregister.
3326   */
3327  public static void deregisterAlertGenerator(AlertGenerator alertGenerator)
3328  {
3329    DN componentDN = alertGenerator.getComponentEntryDN();
3330    JMXMBean mBean = directoryServer.mBeans.get(componentDN);
3331    if (mBean != null)
3332    {
3333      mBean.removeAlertGenerator(alertGenerator);
3334    }
3335  }
3336
3337  /**
3338   * Retrieves the set of alert handlers that have been registered with the
3339   * Directory Server.
3340   *
3341   * @return  The set of alert handlers that have been registered with the
3342   *          Directory Server.
3343   */
3344  public static List<AlertHandler> getAlertHandlers()
3345  {
3346    return directoryServer.alertHandlers;
3347  }
3348
3349  /**
3350   * Registers the provided alert handler with the Directory Server.
3351   *
3352   * @param  alertHandler  The alert handler to register.
3353   */
3354  public static void registerAlertHandler(AlertHandler alertHandler)
3355  {
3356    directoryServer.alertHandlers.add(alertHandler);
3357  }
3358
3359  /**
3360   * Deregisters the provided alert handler with the Directory Server.
3361   *
3362   * @param  alertHandler  The alert handler to deregister.
3363   */
3364  public static void deregisterAlertHandler(AlertHandler alertHandler)
3365  {
3366    directoryServer.alertHandlers.remove(alertHandler);
3367  }
3368
3369  /**
3370   * Sends an alert notification with the provided information.
3371   *
3372   * @param  generator     The alert generator that created the alert.
3373   * @param  alertType     The alert type name for this alert.
3374   * @param  alertMessage  A message (possibly <CODE>null</CODE>) that can
3375   */
3376  public static void sendAlertNotification(AlertGenerator generator,
3377                                           String alertType,
3378                                           LocalizableMessage alertMessage)
3379  {
3380    if (directoryServer.alertHandlers == null
3381        || directoryServer.alertHandlers.isEmpty())
3382    {
3383      // If the Directory Server is still in the process of starting up, then
3384      // create a JMX alert handler to use for this notification.
3385      if (! directoryServer.isRunning)
3386      {
3387        try
3388        {
3389          JMXAlertHandler alertHandler = new JMXAlertHandler();
3390          alertHandler.initializeAlertHandler(null);
3391          alertHandler.sendAlertNotification(generator, alertType,
3392                                             alertMessage);
3393        }
3394        catch (Exception e)
3395        {
3396          logger.traceException(e);
3397        }
3398      }
3399    }
3400    else
3401    {
3402      for (AlertHandler alertHandler : directoryServer.alertHandlers)
3403      {
3404        AlertHandlerCfg config = alertHandler.getAlertHandlerConfiguration();
3405        Set<String> enabledAlerts = config.getEnabledAlertType();
3406        Set<String> disabledAlerts = config.getDisabledAlertType();
3407        if (enabledAlerts == null || enabledAlerts.isEmpty())
3408        {
3409          if (disabledAlerts != null && disabledAlerts.contains(alertType))
3410          {
3411            continue;
3412          }
3413        }
3414        else
3415        {
3416          if (enabledAlerts.contains(alertType))
3417          {
3418            if (disabledAlerts != null && disabledAlerts.contains(alertType))
3419            {
3420              continue;
3421            }
3422          }
3423          else
3424          {
3425            continue;
3426          }
3427        }
3428
3429        alertHandler.sendAlertNotification(generator, alertType, alertMessage);
3430      }
3431    }
3432
3433    String alertID = alertMessage != null ? alertMessage.resourceName() + "-" + alertMessage.ordinal() : "-1";
3434    logger.info(NOTE_SENT_ALERT_NOTIFICATION, generator.getClassName(), alertType, alertID, alertMessage);
3435  }
3436
3437  /**
3438   * Retrieves the password storage scheme defined in the specified
3439   * configuration entry.
3440   *
3441   * @param  configEntryDN  The DN of the configuration entry that defines the
3442   *                        password storage scheme to retrieve.
3443   *
3444   * @return  The requested password storage scheme, or {@code null} if no such
3445   *          scheme is defined.
3446   */
3447  public static PasswordStorageScheme getPasswordStorageScheme(DN configEntryDN)
3448  {
3449    return directoryServer.passwordStorageSchemesByDN.get(configEntryDN);
3450  }
3451
3452  /**
3453   * Retrieves the set of password storage schemes defined in the Directory
3454   * Server, as a mapping between the all-lowercase scheme name and the
3455   * corresponding implementation.
3456   *
3457   * @return  The set of password storage schemes defined in the Directory
3458   *          Server.
3459   */
3460  public static ConcurrentHashMap<String,PasswordStorageScheme>
3461                     getPasswordStorageSchemes()
3462  {
3463    return directoryServer.passwordStorageSchemes;
3464  }
3465
3466  /**
3467   * Retrieves the specified password storage scheme.
3468   *
3469   * @param  lowerName  The name of the password storage scheme to retrieve,
3470   *                    formatted in all lowercase characters.
3471   *
3472   * @return  The requested password storage scheme, or <CODE>null</CODE> if no
3473   *          such scheme is defined.
3474   */
3475  public static PasswordStorageScheme getPasswordStorageScheme(String lowerName)
3476  {
3477    return directoryServer.passwordStorageSchemes.get(lowerName);
3478  }
3479
3480  /**
3481   * Retrieves the set of authentication password storage schemes defined in the
3482   * Directory Server, as a mapping between the scheme name and the
3483   * corresponding implementation.
3484   *
3485   * @return  The set of authentication password storage schemes defined in the
3486   *          Directory Server.
3487   */
3488  public static ConcurrentHashMap<String,PasswordStorageScheme>
3489                     getAuthPasswordStorageSchemes()
3490  {
3491    return directoryServer.authPasswordStorageSchemes;
3492  }
3493
3494  /**
3495   * Retrieves the specified authentication password storage scheme.
3496   *
3497   * @param  name  The case-sensitive name of the authentication password
3498   *               storage scheme to retrieve.
3499   *
3500   * @return  The requested authentication password storage scheme, or
3501   *          <CODE>null</CODE> if no such scheme is defined.
3502   */
3503  public static PasswordStorageScheme getAuthPasswordStorageScheme(String name)
3504  {
3505    return directoryServer.authPasswordStorageSchemes.get(name);
3506  }
3507
3508  /**
3509   * Registers the provided password storage scheme with the Directory Server.
3510   * If an existing password storage scheme is registered with the same name,
3511   * then it will be replaced with the provided scheme.
3512   *
3513   * @param  configEntryDN  The DN of the configuration entry that defines the
3514   *                        password storage scheme.
3515   * @param  scheme         The password storage scheme to register with the
3516   *                        Directory Server.
3517   */
3518  public static void registerPasswordStorageScheme(DN configEntryDN,
3519                                                   PasswordStorageScheme scheme)
3520  {
3521    directoryServer.passwordStorageSchemesByDN.put(configEntryDN, scheme);
3522
3523    String name = toLowerCase(scheme.getStorageSchemeName());
3524    directoryServer.passwordStorageSchemes.put(name, scheme);
3525
3526    if (scheme.supportsAuthPasswordSyntax())
3527    {
3528      directoryServer.authPasswordStorageSchemes.put(
3529           scheme.getAuthPasswordSchemeName(), scheme);
3530    }
3531  }
3532
3533  /**
3534   * Deregisters the specified password storage scheme with the Directory
3535   * Server.  If no scheme is registered with the specified name, then no action
3536   * will be taken.
3537   *
3538   * @param  configEntryDN  The DN of the configuration entry that defines the
3539   *                        password storage scheme.
3540   */
3541  public static void deregisterPasswordStorageScheme(DN configEntryDN)
3542  {
3543    PasswordStorageScheme scheme =
3544         directoryServer.passwordStorageSchemesByDN.remove(configEntryDN);
3545
3546    if (scheme != null)
3547    {
3548      directoryServer.passwordStorageSchemes.remove(
3549           toLowerCase(scheme.getStorageSchemeName()));
3550
3551      if (scheme.supportsAuthPasswordSyntax())
3552      {
3553        directoryServer.authPasswordStorageSchemes.remove(
3554             scheme.getAuthPasswordSchemeName());
3555      }
3556    }
3557  }
3558
3559  /**
3560   * Retrieves the set of password validators that have been registered for use
3561   * with the Directory Server as a mapping between the DN of the associated
3562   * validator configuration entry and the validator implementation.
3563   *
3564   * @return  The set of password validators that have been registered for use
3565   *          with the Directory Server.
3566   */
3567  public static ConcurrentMap<DN,
3568            PasswordValidator<? extends PasswordValidatorCfg>>
3569            getPasswordValidators()
3570  {
3571    return directoryServer.passwordValidators;
3572  }
3573
3574  /**
3575   * Retrieves the password validator registered with the provided configuration
3576   * entry DN.
3577   *
3578   * @param  configEntryDN  The DN of the configuration entry for which to
3579   *                        retrieve the associated password validator.
3580   *
3581   * @return  The requested password validator, or <CODE>null</CODE> if no such
3582   *          validator is defined.
3583   */
3584  public static PasswordValidator<? extends PasswordValidatorCfg>
3585                     getPasswordValidator(DN configEntryDN)
3586  {
3587    return directoryServer.passwordValidators.get(configEntryDN);
3588  }
3589
3590  /**
3591   * Registers the provided password validator for use with the Directory
3592   * Server.
3593   *
3594   * @param  configEntryDN  The DN of the configuration entry that defines the
3595   *                        specified password validator.
3596   * @param  validator      The password validator to register with the
3597   *                        Directory Server.
3598   */
3599  public static void
3600       registerPasswordValidator(DN configEntryDN,
3601            PasswordValidator<? extends PasswordValidatorCfg>
3602            validator)
3603  {
3604    directoryServer.passwordValidators.put(configEntryDN, validator);
3605  }
3606
3607  /**
3608   * Deregisters the provided password validator for use with the Directory
3609   * Server.
3610   *
3611   * @param  configEntryDN  The DN of the configuration entry that defines the
3612   *                        password validator to deregister.
3613   */
3614  public static void deregisterPasswordValidator(DN configEntryDN)
3615  {
3616    directoryServer.passwordValidators.remove(configEntryDN);
3617  }
3618
3619  /**
3620   * Retrieves the set of account status notification handlers defined in the
3621   * Directory Server, as a mapping between the DN of the configuration entry
3622   * and the notification handler implementation.
3623   *
3624   * @return  The set of account status notification handlers defined in the
3625   *          Directory Server.
3626   */
3627  public static ConcurrentMap<DN, AccountStatusNotificationHandler>
3628                     getAccountStatusNotificationHandlers()
3629  {
3630    return directoryServer.accountStatusNotificationHandlers;
3631  }
3632
3633  /**
3634   * Retrieves the account status notification handler with the specified
3635   * configuration entry DN.
3636   *
3637   * @param  handlerDN  The DN of the configuration entry associated with the
3638   *                    account status notification handler to retrieve.
3639   *
3640   * @return  The requested account status notification handler, or
3641   *          <CODE>null</CODE> if no such handler is defined in the server.
3642   */
3643  public static AccountStatusNotificationHandler
3644                     getAccountStatusNotificationHandler(DN handlerDN)
3645  {
3646    return directoryServer.accountStatusNotificationHandlers.get(handlerDN);
3647  }
3648
3649  /**
3650   * Registers the provided account status notification handler with the
3651   * Directory Server.
3652   *
3653   * @param  handlerDN  The DN of the configuration entry that defines the
3654   *                    provided account status notification handler.
3655   * @param  handler    The account status notification handler to register with
3656   *                    the Directory Server.
3657   */
3658  public static void registerAccountStatusNotificationHandler(DN handlerDN,
3659                          AccountStatusNotificationHandler handler)
3660  {
3661    directoryServer.accountStatusNotificationHandlers.put(handlerDN, handler);
3662  }
3663
3664  /**
3665   * Deregisters the specified account status notification handler with the
3666   * Directory Server.
3667   *
3668   * @param  handlerDN  The DN of the configuration entry for the account status
3669   *                    notification handler to deregister.
3670   */
3671  public static void deregisterAccountStatusNotificationHandler(DN handlerDN)
3672  {
3673    directoryServer.accountStatusNotificationHandlers.remove(handlerDN);
3674  }
3675
3676  /**
3677   * Retrieves the set of password generators that have been registered for use
3678   * with the Directory Server as a mapping between the DN of the associated
3679   * generator configuration entry and the generator implementation.
3680   *
3681   * @return  The set of password generators that have been registered for use
3682   *          with the Directory Server.
3683   */
3684  public static ConcurrentMap<DN, PasswordGenerator> getPasswordGenerators()
3685  {
3686    return directoryServer.passwordGenerators;
3687  }
3688
3689  /**
3690   * Retrieves the password generator registered with the provided configuration
3691   * entry DN.
3692   *
3693   * @param  configEntryDN  The DN of the configuration entry for which to
3694   *                        retrieve the associated password generator.
3695   *
3696   * @return  The requested password generator, or <CODE>null</CODE> if no such
3697   *          generator is defined.
3698   */
3699  public static PasswordGenerator getPasswordGenerator(DN configEntryDN)
3700  {
3701    return directoryServer.passwordGenerators.get(configEntryDN);
3702  }
3703
3704  /**
3705   * Registers the provided password generator for use with the Directory
3706   * Server.
3707   *
3708   * @param  configEntryDN  The DN of the configuration entry that defines the
3709   *                        specified password generator.
3710   * @param  generator      The password generator to register with the
3711   *                        Directory Server.
3712   */
3713  public static void registerPasswordGenerator(DN configEntryDN,
3714                                               PasswordGenerator generator)
3715  {
3716    directoryServer.passwordGenerators.put(configEntryDN, generator);
3717  }
3718
3719  /**
3720   * Deregisters the provided password generator for use with the Directory
3721   * Server.
3722   *
3723   * @param  configEntryDN  The DN of the configuration entry that defines the
3724   *                        password generator to deregister.
3725   */
3726  public static void deregisterPasswordGenerator(DN configEntryDN)
3727  {
3728    directoryServer.passwordGenerators.remove(configEntryDN);
3729  }
3730
3731  /**
3732   * Returns an unmodifiable collection containing all of the authentication
3733   * policies registered with the Directory Server. The references returned are
3734   * to the actual authentication policy objects currently in use by the
3735   * directory server and the referenced objects must not be modified.
3736   *
3737   * @return The unmodifiable collection containing all of the authentication
3738   *         policies registered with the Directory Server.
3739   */
3740  public static Collection<AuthenticationPolicy> getAuthenticationPolicies()
3741  {
3742    return Collections
3743       .unmodifiableCollection(directoryServer.authenticationPolicies.values());
3744  }
3745
3746  /**
3747   * Retrieves the authentication policy registered for the provided
3748   * configuration entry.
3749   *
3750   * @param configEntryDN
3751   *          The DN of the configuration entry for which to retrieve the
3752   *          associated authentication policy.
3753   * @return The authentication policy registered for the provided configuration
3754   *         entry, or <CODE>null</CODE> if there is no such policy.
3755   */
3756  public static AuthenticationPolicy getAuthenticationPolicy(DN configEntryDN)
3757  {
3758    Reject.ifNull(configEntryDN);
3759    return directoryServer.authenticationPolicies.get(configEntryDN);
3760  }
3761
3762  /**
3763   * Registers the provided authentication policy with the Directory Server. If
3764   * a policy is already registered for the provided configuration entry DN,
3765   * then it will be replaced.
3766   *
3767   * @param configEntryDN
3768   *          The DN of the configuration entry that defines the authentication
3769   *          policy.
3770   * @param policy
3771   *          The authentication policy to register with the server.
3772   */
3773  public static void registerAuthenticationPolicy(DN configEntryDN,
3774      AuthenticationPolicy policy)
3775  {
3776    Reject.ifNull(configEntryDN, policy);
3777
3778    // Ensure default policy is synchronized.
3779    synchronized (directoryServer.authenticationPolicies)
3780    {
3781      if (directoryServer.defaultPasswordPolicyDN.equals(configEntryDN))
3782      {
3783        // The correct policy type is enforced by the core config manager.
3784        directoryServer.defaultPasswordPolicy = (PasswordPolicy) policy;
3785      }
3786
3787      AuthenticationPolicy oldPolicy = directoryServer.authenticationPolicies
3788          .put(configEntryDN, policy);
3789
3790      if (oldPolicy != null)
3791      {
3792        oldPolicy.finalizeAuthenticationPolicy();
3793      }
3794    }
3795  }
3796
3797  /**
3798   * Deregisters the provided authentication policy with the Directory Server.
3799   * If no such policy is registered, then no action will be taken.
3800   *
3801   * @param configEntryDN
3802   *          The DN of the configuration entry that defines the authentication
3803   *          policy to deregister.
3804   */
3805  public static void deregisterAuthenticationPolicy(DN configEntryDN)
3806  {
3807    Reject.ifNull(configEntryDN);
3808
3809    // Ensure default policy is synchronized.
3810    synchronized (directoryServer.authenticationPolicies)
3811    {
3812      if (directoryServer.defaultPasswordPolicyDN.equals(configEntryDN))
3813      {
3814        directoryServer.defaultPasswordPolicy = null;
3815      }
3816
3817      AuthenticationPolicy oldPolicy = directoryServer.authenticationPolicies
3818          .remove(configEntryDN);
3819      if (oldPolicy != null)
3820      {
3821        oldPolicy.finalizeAuthenticationPolicy();
3822      }
3823    }
3824  }
3825
3826  /**
3827   * Retrieves the DN of the configuration entry for the default password policy
3828   * for the Directory Server.
3829   *
3830   * @return  The DN of the configuration entry for the default password policy
3831   *          for the Directory Server.
3832   */
3833  public static DN getDefaultPasswordPolicyDN()
3834  {
3835    synchronized (directoryServer.authenticationPolicies)
3836    {
3837      return directoryServer.defaultPasswordPolicyDN;
3838    }
3839  }
3840
3841  /**
3842   * Specifies the DN of the configuration entry for the default authentication
3843   * policy for the Directory Server. This routine does not check the registered
3844   * authentication policies for the specified DN, since in the case of server
3845   * initialization, the authentication policy entries will not yet have been
3846   * loaded from the configuration backend.
3847   *
3848   * @param defaultPasswordPolicyDN
3849   *          The DN of the configuration entry for the default authentication
3850   *          policy for the Directory Server.
3851   */
3852  public static void setDefaultPasswordPolicyDN(DN defaultPasswordPolicyDN)
3853  {
3854    // Ensure default policy is synchronized.
3855    synchronized (directoryServer.authenticationPolicies)
3856    {
3857      directoryServer.defaultPasswordPolicyDN = defaultPasswordPolicyDN;
3858      directoryServer.defaultPasswordPolicy = null;
3859    }
3860  }
3861
3862  /**
3863   * Retrieves the default password policy for the Directory Server. This
3864   * method is equivalent to invoking <CODE>getAuthenticationPolicy</CODE> on
3865   * the DN returned from
3866   * <CODE>DirectoryServer.getDefaultPasswordPolicyDN()</CODE>.
3867   *
3868   * @return The default password policy for the Directory Server.
3869   */
3870  public static PasswordPolicy getDefaultPasswordPolicy()
3871  {
3872    // Ensure default policy is synchronized.
3873    synchronized (directoryServer.authenticationPolicies)
3874    {
3875      assert null != directoryServer.authenticationPolicies
3876          .get(directoryServer.defaultPasswordPolicyDN) :
3877            "Internal Error: no default password policy defined.";
3878
3879      if (directoryServer.defaultPasswordPolicy == null
3880          && directoryServer.defaultPasswordPolicyDN != null)
3881      {
3882        // The correct policy type is enforced by the core config manager.
3883        directoryServer.defaultPasswordPolicy = (PasswordPolicy)
3884          directoryServer.authenticationPolicies
3885            .get(directoryServer.defaultPasswordPolicyDN);
3886      }
3887      assert directoryServer.authenticationPolicies
3888          .get(directoryServer.defaultPasswordPolicyDN) ==
3889            directoryServer.defaultPasswordPolicy :
3890             "Internal Error: inconsistency between defaultPasswordPolicy"
3891          + " cache and value in authenticationPolicies map.";
3892      return directoryServer.defaultPasswordPolicy;
3893    }
3894  }
3895
3896  /**
3897   * Retrieves the log rotation policy registered for the provided configuration
3898   * entry.
3899   *
3900   * @param  configEntryDN  The DN of the configuration entry for which to
3901   *                        retrieve the associated rotation policy.
3902   *
3903   * @return  The rotation policy registered for the provided configuration
3904   *          entry, or <CODE>null</CODE> if there is no such policy.
3905   */
3906  public static RotationPolicy getRotationPolicy(DN configEntryDN)
3907  {
3908    Reject.ifNull(configEntryDN);
3909
3910    return directoryServer.rotationPolicies.get(configEntryDN);
3911  }
3912
3913    /**
3914   * Registers the provided log rotation policy with the Directory Server.  If a
3915   * policy is already registered for the provided configuration entry DN, then
3916   * it will be replaced.
3917   *
3918   * @param  configEntryDN  The DN of the configuration entry that defines the
3919   *                        password policy.
3920   * @param  policy         The rotation policy to register with the server.
3921   */
3922  public static void registerRotationPolicy(DN configEntryDN,
3923                                            RotationPolicy policy)
3924  {
3925    Reject.ifNull(configEntryDN, policy);
3926
3927    directoryServer.rotationPolicies.put(configEntryDN, policy);
3928  }
3929
3930  /**
3931   * Deregisters the provided log rotation policy with the Directory Server.
3932   * If no such policy is registered, then no action will be taken.
3933   *
3934   * @param  configEntryDN  The DN of the configuration entry that defines the
3935   *                        rotation policy to deregister.
3936   */
3937  public static void deregisterRotationPolicy(DN configEntryDN)
3938  {
3939    Reject.ifNull(configEntryDN);
3940
3941    directoryServer.rotationPolicies.remove(configEntryDN);
3942  }
3943
3944  /**
3945   * Retrieves the log retention policy registered for the provided
3946   * configuration entry.
3947   *
3948   * @param  configEntryDN  The DN of the configuration entry for which to
3949   *                        retrieve the associated retention policy.
3950   *
3951   * @return  The retention policy registered for the provided configuration
3952   *          entry, or <CODE>null</CODE> if there is no such policy.
3953   */
3954  public static RetentionPolicy getRetentionPolicy(DN configEntryDN)
3955  {
3956    Reject.ifNull(configEntryDN);
3957
3958    return directoryServer.retentionPolicies.get(configEntryDN);
3959  }
3960
3961  /**
3962   * Registers the provided log retention policy with the Directory Server.
3963   * If a policy is already registered for the provided configuration entry DN,
3964   * then it will be replaced.
3965   *
3966   * @param  configEntryDN  The DN of the configuration entry that defines the
3967   *                        password policy.
3968   * @param  policy         The retention policy to register with the server.
3969   */
3970  public static void registerRetentionPolicy(DN configEntryDN,
3971                                            RetentionPolicy policy)
3972  {
3973    Reject.ifNull(configEntryDN, policy);
3974
3975    directoryServer.retentionPolicies.put(configEntryDN, policy);
3976  }
3977
3978  /**
3979   * Deregisters the provided log retention policy with the Directory Server.
3980   * If no such policy is registered, then no action will be taken.
3981   *
3982   * @param  configEntryDN  The DN of the configuration entry that defines the
3983   *                        retention policy to deregister.
3984   */
3985  public static void deregisterRetentionPolicy(DN configEntryDN)
3986  {
3987    Reject.ifNull(configEntryDN);
3988
3989    directoryServer.retentionPolicies.remove(configEntryDN);
3990  }
3991
3992  /**
3993   * Retrieves the set of monitor providers that have been registered with the
3994   * Directory Server, as a mapping between the monitor name (in all lowercase
3995   * characters) and the monitor implementation.
3996   *
3997   * @return  The set of monitor providers that have been registered with the
3998   *          Directory Server.
3999   */
4000  public static ConcurrentMap<String,
4001                                  MonitorProvider<? extends MonitorProviderCfg>>
4002                     getMonitorProviders()
4003  {
4004    return directoryServer.monitorProviders;
4005  }
4006
4007  /**
4008   * Retrieves the monitor provider with the specified name.
4009   *
4010   * @param  lowerName  The name of the monitor provider to retrieve, in all
4011   *                    lowercase characters.
4012   *
4013   * @return  The requested resource monitor, or <CODE>null</CODE> if none
4014   *          exists with the specified name.
4015   */
4016  public static MonitorProvider<? extends MonitorProviderCfg>
4017                     getMonitorProvider(String lowerName)
4018  {
4019    return directoryServer.monitorProviders.get(lowerName);
4020  }
4021
4022  /**
4023   * Registers the provided monitor provider with the Directory Server.  Note
4024   * that if a monitor provider is already registered with the specified name,
4025   * then it will be replaced with the provided implementation.
4026   *
4027   * @param  monitorProvider  The monitor provider to register with the
4028   *                          Directory Server.
4029   */
4030  public static void registerMonitorProvider(
4031                          MonitorProvider<? extends MonitorProviderCfg>
4032                               monitorProvider)
4033  {
4034    String lowerName = toLowerCase(monitorProvider.getMonitorInstanceName());
4035    directoryServer.monitorProviders.put(lowerName, monitorProvider);
4036
4037    // Try to register this monitor provider with an appropriate JMX MBean.
4038    try
4039    {
4040      DN monitorDN = getMonitorProviderDN(monitorProvider);
4041      JMXMBean mBean = directoryServer.mBeans.get(monitorDN);
4042      if (mBean == null)
4043      {
4044        mBean = new JMXMBean(monitorDN);
4045        mBean.addMonitorProvider(monitorProvider);
4046        directoryServer.mBeans.put(monitorDN, mBean);
4047      }
4048      else
4049      {
4050        mBean.addMonitorProvider(monitorProvider);
4051      }
4052    }
4053    catch (Exception e)
4054    {
4055      logger.traceException(e);
4056    }
4057  }
4058
4059  /**
4060   * Deregisters the specified monitor provider from the Directory Server. If no
4061   * such monitor provider is registered, no action will be taken.
4062   *
4063   * @param monitorProvider
4064   *          The monitor provider to deregister from the Directory Server.
4065   */
4066  public static void deregisterMonitorProvider(
4067      MonitorProvider<? extends MonitorProviderCfg> monitorProvider)
4068  {
4069    String monitorName = toLowerCase(monitorProvider.getMonitorInstanceName());
4070    MonitorProvider<?> provider = directoryServer.monitorProviders
4071        .remove(monitorName);
4072
4073    // Try to deregister the monitor provider as an MBean.
4074    if (provider != null)
4075    {
4076      try
4077      {
4078        DN monitorDN = getMonitorProviderDN(provider);
4079        JMXMBean mBean = directoryServer.mBeans.get(monitorDN);
4080        if (mBean != null)
4081        {
4082          mBean.removeMonitorProvider(provider);
4083        }
4084      }
4085      catch (Exception e)
4086      {
4087        logger.traceException(e);
4088      }
4089    }
4090  }
4091
4092  /**
4093   * Retrieves the entry cache for the Directory Server.
4094   *
4095   * @return  The entry cache for the Directory Server.
4096   */
4097  public static EntryCache getEntryCache()
4098  {
4099    return directoryServer.entryCache;
4100  }
4101
4102  /**
4103   * Specifies the entry cache that should be used by the Directory Server.
4104   * This should only be called by the entry cache configuration manager.
4105   *
4106   * @param  entryCache  The entry cache for the Directory Server.
4107   */
4108  public static void setEntryCache(EntryCache entryCache)
4109  {
4110    synchronized (directoryServer)
4111    {
4112      directoryServer.entryCache = entryCache;
4113    }
4114  }
4115
4116  /**
4117   * Retrieves the set of key manager providers registered with the Directory
4118   * Server.
4119   *
4120   * @return  The set of key manager providers registered with the Directory
4121   *          Server.
4122   */
4123  public static Map<DN,KeyManagerProvider> getKeyManagerProviders()
4124  {
4125    return directoryServer.keyManagerProviders;
4126  }
4127
4128  /**
4129   * Retrieves the key manager provider registered with the provided entry DN.
4130   *
4131   * @param  providerDN  The DN with which the key manager provider is
4132   *                     registered.
4133   *
4134   * @return  The key manager provider registered with the provided entry DN, or
4135   *          {@code null} if there is no such key manager provider registered
4136   *          with the server.
4137   */
4138  public static KeyManagerProvider getKeyManagerProvider(DN providerDN)
4139  {
4140    return directoryServer.keyManagerProviders.get(providerDN);
4141  }
4142
4143  /**
4144   * Registers the provided key manager provider with the Directory Server.
4145   *
4146   * @param  providerDN  The DN with which to register the key manager provider.
4147   * @param  provider    The key manager provider to register with the server.
4148   */
4149  public static void registerKeyManagerProvider(DN providerDN,
4150                                                KeyManagerProvider provider)
4151  {
4152    directoryServer.keyManagerProviders.put(providerDN, provider);
4153  }
4154
4155  /**
4156   * Deregisters the specified key manager provider with the Directory Server.
4157   *
4158   * @param  providerDN  The DN with which the key manager provider is
4159   *                     registered.
4160   */
4161  public static void deregisterKeyManagerProvider(DN providerDN)
4162  {
4163    directoryServer.keyManagerProviders.remove(providerDN);
4164  }
4165
4166  /**
4167   * Retrieves the set of trust manager providers registered with the Directory
4168   * Server.
4169   *
4170   * @return  The set of trust manager providers registered with the Directory
4171   *          Server.
4172   */
4173  public static Map<DN,TrustManagerProvider> getTrustManagerProviders()
4174  {
4175    return directoryServer.trustManagerProviders;
4176  }
4177
4178  /**
4179   * Retrieves the trust manager provider registered with the provided entry DN.
4180   *
4181   * @param  providerDN  The DN with which the trust manager provider is
4182   *                     registered.
4183   *
4184   * @return  The trust manager provider registered with the provided entry DN,
4185   *          or {@code null} if there is no such trust manager provider
4186   *          registered with the server.
4187   */
4188  public static TrustManagerProvider getTrustManagerProvider(DN providerDN)
4189  {
4190    return directoryServer.trustManagerProviders.get(providerDN);
4191  }
4192
4193  /**
4194   * Registers the provided trust manager provider with the Directory Server.
4195   *
4196   * @param  providerDN  The DN with which to register the trust manager
4197   *                     provider.
4198   * @param  provider    The trust manager provider to register with the server.
4199   */
4200  public static void registerTrustManagerProvider(DN providerDN,
4201                                                  TrustManagerProvider provider)
4202  {
4203    directoryServer.trustManagerProviders.put(providerDN, provider);
4204  }
4205
4206  /**
4207   * Deregisters the specified trust manager provider with the Directory Server.
4208   *
4209   * @param  providerDN  The DN with which the trust manager provider is
4210   *                     registered.
4211   */
4212  public static void deregisterTrustManagerProvider(DN providerDN)
4213  {
4214    directoryServer.trustManagerProviders.remove(providerDN);
4215  }
4216
4217  /**
4218   * Retrieves the set of certificate mappers registered with the Directory
4219   * Server.
4220   *
4221   * @return  The set of certificate mappers registered with the Directory
4222   *          Server.
4223   */
4224  public static Map<DN,CertificateMapper> getCertificateMappers()
4225  {
4226    return directoryServer.certificateMappers;
4227  }
4228
4229  /**
4230   * Retrieves the certificate mapper registered with the provided entry DN.
4231   *
4232   * @param  mapperDN  The DN with which the certificate mapper is registered.
4233   *
4234   * @return  The certificate mapper registered with the provided entry DN, or
4235   *          {@code null} if there is no such certificate mapper registered
4236   *          with the server.
4237   */
4238  public static CertificateMapper getCertificateMapper(DN mapperDN)
4239  {
4240    return directoryServer.certificateMappers.get(mapperDN);
4241  }
4242
4243  /**
4244   * Registers the provided certificate mapper with the Directory Server.
4245   *
4246   * @param  mapperDN  The DN with which to register the certificate mapper.
4247   * @param  mapper    The certificate mapper to register with the server.
4248   */
4249  public static void registerCertificateMapper(DN mapperDN,
4250                                               CertificateMapper mapper)
4251  {
4252    directoryServer.certificateMappers.put(mapperDN, mapper);
4253  }
4254
4255  /**
4256   * Deregisters the specified certificate mapper with the Directory Server.
4257   *
4258   * @param  mapperDN  The DN with which the certificate mapper is registered.
4259   */
4260  public static void deregisterCertificateMapper(DN mapperDN)
4261  {
4262    directoryServer.certificateMappers.remove(mapperDN);
4263  }
4264
4265  /**
4266   * Retrieves the set of privileges that should automatically be granted to
4267   * root users when they authenticate.
4268   *
4269   * @return  The set of privileges that should automatically be granted to root
4270   *          users when they authenticate.
4271   */
4272  public static Set<Privilege> getRootPrivileges()
4273  {
4274    return directoryServer.rootDNConfigManager.getRootPrivileges();
4275  }
4276
4277  /**
4278   * Retrieves the DNs for the root users configured in the Directory Server.
4279   * Note that this set should only contain the actual DNs for the root users
4280   * and not any alternate DNs.  Also, the contents of the returned set must not
4281   * be altered by the caller.
4282   *
4283   * @return  The DNs for the root users configured in the Directory Server.
4284   */
4285  public static Set<DN> getRootDNs()
4286  {
4287    return directoryServer.rootDNs;
4288  }
4289
4290  /**
4291   * Indicates whether the provided DN is the DN for one of the root users
4292   * configured in the Directory Server.
4293   *
4294   * @param  userDN  The user DN for which to make the determination.
4295   *
4296   * @return  <CODE>true</CODE> if the provided user DN is a Directory Server
4297   *          root DN, or <CODE>false</CODE> if not.
4298   */
4299  public static boolean isRootDN(DN userDN)
4300  {
4301    return directoryServer.rootDNs.contains(userDN);
4302  }
4303
4304  /**
4305   * Registers the provided root DN with the Directory Server.
4306   *
4307   * @param  rootDN  The root DN to register with the Directory Server.
4308   */
4309  public static void registerRootDN(DN rootDN)
4310  {
4311    directoryServer.rootDNs.add(rootDN);
4312  }
4313
4314  /**
4315   * Deregisters the provided root DN with the Directory Server.  This will have
4316   * no effect if the provided DN is not registered as a root DN.
4317   *
4318   * @param  rootDN  The root DN to deregister.
4319   */
4320  public static void deregisterRootDN(DN rootDN)
4321  {
4322    directoryServer.rootDNs.remove(rootDN);
4323  }
4324
4325  /**
4326   * Retrieves the set of alternate bind DNs for root users, mapped between the
4327   * alternate DN and the real DN.  The contents of the returned map must not be
4328   * altered by the caller.
4329   *
4330   * @return  The set of alternate bind DNs for root users, mapped between the
4331   *          alternate DN and the real DN.
4332   */
4333  public static ConcurrentMap<DN, DN> getAlternateRootBindDNs()
4334  {
4335    return directoryServer.alternateRootBindDNs;
4336  }
4337
4338  /**
4339   * Retrieves the real entry DN for the root user with the provided alternate
4340   * bind DN.
4341   *
4342   * @param  alternateRootBindDN  The alternate root bind DN for which to
4343   *                              retrieve the real entry DN.
4344   *
4345   * @return  The real entry DN for the root user with the provided alternate
4346   *          bind DN, or <CODE>null</CODE> if no such mapping has been defined.
4347   */
4348  public static DN getActualRootBindDN(DN alternateRootBindDN)
4349  {
4350    return directoryServer.alternateRootBindDNs.get(alternateRootBindDN);
4351  }
4352
4353  /**
4354   * Registers an alternate root bind DN using the provided information.
4355   *
4356   * @param  actualRootEntryDN    The actual DN for the root user's entry.
4357   * @param  alternateRootBindDN  The alternate DN that should be interpreted as
4358   *                              if it were the provided actual root entry DN.
4359   *
4360   * @throws  DirectoryException  If the provided alternate bind DN is already
4361   *                              in use for another root user.
4362   */
4363  public static void registerAlternateRootDN(DN actualRootEntryDN,
4364                                             DN alternateRootBindDN)
4365         throws DirectoryException
4366  {
4367    DN existingRootEntryDN =
4368         directoryServer.alternateRootBindDNs.putIfAbsent(alternateRootBindDN,
4369                                                          actualRootEntryDN);
4370    if (existingRootEntryDN != null
4371        && !existingRootEntryDN.equals(actualRootEntryDN))
4372    {
4373      LocalizableMessage message = ERR_CANNOT_REGISTER_DUPLICATE_ALTERNATE_ROOT_BIND_DN.
4374          get(alternateRootBindDN, existingRootEntryDN);
4375      throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
4376    }
4377  }
4378
4379  /**
4380   * Deregisters the provided alternate root bind DN from the server.  This will
4381   * have no effect if there was no mapping defined for the provided alternate
4382   * root bind DN.
4383   *
4384   * @param  alternateRootBindDN  The alternate root bind DN to be deregistered.
4385   *
4386   * @return  The actual root entry DN to which the provided alternate bind DN
4387   *          was mapped, or <CODE>null</CODE> if there was no mapping for the
4388   *          provided DN.
4389   */
4390  public static DN deregisterAlternateRootBindDN(DN alternateRootBindDN)
4391  {
4392    return directoryServer.alternateRootBindDNs.remove(alternateRootBindDN);
4393  }
4394
4395  /**
4396   * Retrieves the result code that should be used when the Directory Server
4397   * encounters an internal server error.
4398   *
4399   * @return  The result code that should be used when the Directory Server
4400   *          encounters an internal server error.
4401   */
4402  public static ResultCode getServerErrorResultCode()
4403  {
4404    return directoryServer.serverErrorResultCode;
4405  }
4406
4407  /**
4408   * Specifies the result code that should be used when the Directory Server
4409   * encounters an internal server error.
4410   *
4411   * @param  serverErrorResultCode  The result code that should be used when the
4412   *                                Directory Server encounters an internal
4413   *                                server error.
4414   */
4415  public static void setServerErrorResultCode(ResultCode serverErrorResultCode)
4416  {
4417    directoryServer.serverErrorResultCode = serverErrorResultCode;
4418  }
4419
4420  /**
4421   * Indicates whether the Directory Server should automatically add missing RDN
4422   * attributes to an entry whenever it is added.
4423   *
4424   * @return  <CODE>true</CODE> if the Directory Server should automatically add
4425   *          missing RDN attributes to an entry, or <CODE>false</CODE> if it
4426   *          should return an error to the client.
4427   */
4428  public static boolean addMissingRDNAttributes()
4429  {
4430    return directoryServer.addMissingRDNAttributes;
4431  }
4432
4433  /**
4434   * Specifies whether the Directory Server should automatically add missing RDN
4435   * attributes to an entry whenever it is added.
4436   *
4437   * @param  addMissingRDNAttributes  Specifies whether the Directory Server
4438   *                                  should automatically add missing RDN
4439   *                                  attributes to an entry whenever it is
4440   *                                  added.
4441   */
4442  public static void setAddMissingRDNAttributes(boolean addMissingRDNAttributes)
4443  {
4444    directoryServer.addMissingRDNAttributes = addMissingRDNAttributes;
4445  }
4446
4447  /**
4448   * Indicates whether to be more flexible in the set of characters allowed for
4449   * attribute names.  The standard requires that only ASCII alphabetic letters,
4450   * numeric digits, and hyphens be allowed, and that the name start with a
4451   * letter.  If attribute name exceptions are enabled, then underscores will
4452   * also be allowed, and the name will be allowed to start with a digit.
4453   *
4454   * @return  <CODE>true</CODE> if the server should use a more flexible
4455   *          syntax for attribute names, or <CODE>false</CODE> if not.
4456   */
4457  public static boolean allowAttributeNameExceptions()
4458  {
4459    return directoryServer.allowAttributeNameExceptions;
4460  }
4461
4462  /**
4463   * Specifies whether to be more flexible in the set of characters allowed for
4464   * attribute names.
4465   *
4466   * @param  allowAttributeNameExceptions  Specifies whether to be more flexible
4467   *                                       in the set of characters allowed for
4468   *                                       attribute names.
4469   */
4470  public static void setAllowAttributeNameExceptions(
4471                          boolean allowAttributeNameExceptions)
4472  {
4473    directoryServer.allowAttributeNameExceptions = allowAttributeNameExceptions;
4474  }
4475
4476  /**
4477   * Indicates whether the Directory Server should perform schema checking.
4478   *
4479   * @return  <CODE>true</CODE> if the Directory Server should perform schema
4480   *          checking, or <CODE>false</CODE> if not.
4481   */
4482  public static boolean checkSchema()
4483  {
4484    return directoryServer.checkSchema;
4485  }
4486
4487  /**
4488   * Specifies whether the Directory Server should perform schema checking.
4489   *
4490   * @param  checkSchema  Specifies whether the Directory Server should perform
4491   *                      schema checking.
4492   */
4493  public static void setCheckSchema(boolean checkSchema)
4494  {
4495    directoryServer.checkSchema = checkSchema;
4496  }
4497
4498  /**
4499   * Retrieves the policy that should be used regarding enforcement of a single
4500   * structural objectclass per entry.
4501   *
4502   * @return  The policy that should be used regarding enforcement of a single
4503   *          structural objectclass per entry.
4504   */
4505  public static AcceptRejectWarn getSingleStructuralObjectClassPolicy()
4506  {
4507    return directoryServer.singleStructuralClassPolicy;
4508  }
4509
4510  /**
4511   * Specifies the policy that should be used regarding enforcement of a single
4512   * structural objectclass per entry.
4513   *
4514   * @param  singleStructuralClassPolicy  The policy that should be used
4515   *                                      regarding enforcement of a single
4516   *                                      structural objectclass per entry.
4517   */
4518  public static void setSingleStructuralObjectClassPolicy(
4519                          AcceptRejectWarn singleStructuralClassPolicy)
4520  {
4521    directoryServer.singleStructuralClassPolicy = singleStructuralClassPolicy;
4522  }
4523
4524  /**
4525   * Retrieves the policy that should be used when an attribute value is found
4526   * that is not valid according to the associated attribute syntax.
4527   *
4528   * @return  The policy that should be used when an attribute value is found
4529   *          that is not valid according to the associated attribute syntax.
4530   */
4531  public static AcceptRejectWarn getSyntaxEnforcementPolicy()
4532  {
4533    return directoryServer.syntaxEnforcementPolicy;
4534  }
4535
4536  /**
4537   * Retrieves the policy that should be used when an attribute value is found
4538   * that is not valid according to the associated attribute syntax.
4539   *
4540   * @param  syntaxEnforcementPolicy  The policy that should be used when an
4541   *                                  attribute value is found that is not valid
4542   *                                  according to the associated attribute
4543   *                                  syntax.
4544   */
4545  public static void setSyntaxEnforcementPolicy(
4546                          AcceptRejectWarn syntaxEnforcementPolicy)
4547  {
4548    directoryServer.syntaxEnforcementPolicy = syntaxEnforcementPolicy;
4549  }
4550
4551  /**
4552   * Indicates whether the Directory Server should send a response to an
4553   * operation that has been abandoned.  Sending such a response is technically
4554   * a violation of the LDAP protocol specification, but not doing so in that
4555   * case can cause problems with clients that are expecting a response and may
4556   * hang until they get one.
4557   *
4558   * @return  <CODE>true</CODE> if the Directory Server should send a response
4559   *          to an operation that has been abandoned, or <CODE>false</CODE> if
4560   *          not.
4561   */
4562  public static boolean notifyAbandonedOperations()
4563  {
4564    return directoryServer.notifyAbandonedOperations;
4565  }
4566
4567  /**
4568   * Specifies whether the Directory Server should send a response to an
4569   * operation that has been abandoned.  Sending such a response is technically
4570   * a violation of the LDAP protocol specification, but not doing so in that
4571   * case can cause problems with clients that are expecting a response and may
4572   * hang until they get one.
4573   *
4574   * @param  notifyAbandonedOperations  Indicates whether the Directory Server
4575   *                                    should send a response to an operation
4576   *                                    that has been abandoned.
4577   */
4578  public static void setNotifyAbandonedOperations(
4579                          boolean notifyAbandonedOperations)
4580  {
4581    directoryServer.notifyAbandonedOperations = notifyAbandonedOperations;
4582  }
4583
4584  /**
4585   * Retrieves the set of backends that have been registered with the Directory
4586   * Server, as a mapping between the backend ID and the corresponding backend.
4587   *
4588   * @return  The set of backends that have been registered with the Directory
4589   *          Server.
4590   */
4591  public static Map<String, Backend> getBackends()
4592  {
4593    return new TreeMap<String, Backend>(directoryServer.backends);
4594  }
4595
4596  /**
4597   * Retrieves the backend with the specified backend ID.
4598   *
4599   * @param  backendID  The backend ID of the backend to retrieve.
4600   *
4601   * @return  The backend with the specified backend ID, or {@code null} if
4602   *          there is none.
4603   */
4604  public static Backend<?> getBackend(String backendID)
4605  {
4606    return directoryServer.backends.get(backendID);
4607  }
4608
4609  /**
4610   * Indicates whether the Directory Server has a backend with the specified
4611   * backend ID.
4612   *
4613   * @param  backendID  The backend ID for which to make the determination.
4614   *
4615   * @return  {@code true} if the Directory Server has a backend with the
4616   *          specified backend ID, or {@code false} if not.
4617   */
4618  public static boolean hasBackend(String backendID)
4619  {
4620    return directoryServer.backends.containsKey(backendID);
4621  }
4622
4623  /**
4624   * Registers the provided backend with the Directory Server.  Note that this
4625   * will not register the set of configured suffixes with the server, as that
4626   * must be done by the backend itself.
4627   *
4628   * @param  backend  The backend to register with the server.  Neither the
4629   *                  backend nor its backend ID may be null.
4630   *
4631   * @throws  DirectoryException  If the backend ID for the provided backend
4632   *                              conflicts with the backend ID of an existing
4633   *                              backend.
4634   */
4635  public static void registerBackend(Backend<?> backend) throws DirectoryException
4636  {
4637    ifNull(backend);
4638
4639    String backendID = backend.getBackendID();
4640    ifNull(backendID);
4641
4642    synchronized (directoryServer)
4643    {
4644      TreeMap<String, Backend<?>> newBackends = new TreeMap<>(directoryServer.backends);
4645      if (newBackends.containsKey(backendID))
4646      {
4647        LocalizableMessage message = ERR_REGISTER_BACKEND_ALREADY_EXISTS.get(backendID);
4648        throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
4649      }
4650      else
4651      {
4652        newBackends.put(backendID, backend);
4653        directoryServer.backends = newBackends;
4654
4655        for (String oid : backend.getSupportedControls())
4656        {
4657          registerSupportedControl(oid);
4658        }
4659
4660        for (String oid : backend.getSupportedFeatures())
4661        {
4662          registerSupportedFeature(oid);
4663        }
4664
4665        BackendMonitor monitor = new BackendMonitor(backend);
4666        monitor.initializeMonitorProvider(null);
4667        backend.setBackendMonitor(monitor);
4668        registerMonitorProvider(monitor);
4669      }
4670    }
4671  }
4672
4673  /**
4674   * Deregisters the provided backend with the Directory Server.  Note that this
4675   * will not deregister the set of configured suffixes with the server, as that
4676   * must be done by the backend itself.
4677   *
4678   * @param  backend  The backend to deregister with the server.  It must not be
4679   *                  {@code null}.
4680   */
4681  public static void deregisterBackend(Backend<?> backend)
4682  {
4683    ifNull(backend);
4684
4685    synchronized (directoryServer)
4686    {
4687      TreeMap<String, Backend<?>> newBackends = new TreeMap<>(directoryServer.backends);
4688      newBackends.remove(backend.getBackendID());
4689
4690      directoryServer.backends = newBackends;
4691
4692      // Don't need anymore the local backend workflow element so we can remove it
4693      for (DN baseDN : backend.getBaseDNs())
4694      {
4695        LocalBackendWorkflowElement.remove(baseDN);
4696      }
4697
4698      BackendMonitor monitor = backend.getBackendMonitor();
4699      if (monitor != null)
4700      {
4701        deregisterMonitorProvider(monitor);
4702        monitor.finalizeMonitorProvider();
4703        backend.setBackendMonitor(null);
4704      }
4705    }
4706  }
4707
4708  /**
4709   * Retrieves the entire set of base DNs registered with the Directory Server,
4710   * mapped from the base DN to the backend responsible for that base DN.  The
4711   * same backend may be present multiple times, mapped from different base DNs.
4712   *
4713   * @return  The entire set of base DNs registered with the Directory Server.
4714   */
4715  public static Map<DN,Backend> getBaseDNs()
4716  {
4717    return directoryServer.baseDnRegistry.getBaseDnMap();
4718  }
4719
4720  /**
4721   * Retrieves the backend with the specified base DN.
4722   *
4723   * @param  baseDN  The DN that is registered as one of the base DNs for the
4724   *                 backend to retrieve.
4725   *
4726   * @return  The backend with the specified base DN, or {@code null} if there
4727   *          is no backend registered with the specified base DN.
4728   */
4729  public static Backend<?> getBackendWithBaseDN(DN baseDN)
4730  {
4731    return directoryServer.baseDnRegistry.getBaseDnMap().get(baseDN);
4732  }
4733
4734  /**
4735   * Retrieves the backend that should be used to handle operations on the
4736   * specified entry.
4737   *
4738   * @param  entryDN  The DN of the entry for which to retrieve the
4739   *                  corresponding backend.
4740   *
4741   * @return  The backend that should be used to handle operations on the
4742   *          specified entry, or {@code null} if no appropriate backend is
4743   *          registered with the server.
4744   */
4745  public static Backend<?> getBackend(DN entryDN)
4746  {
4747    if (entryDN.isRootDN())
4748    {
4749      return directoryServer.rootDSEBackend;
4750    }
4751
4752    Map<DN,Backend> baseDNs = directoryServer.baseDnRegistry.getBaseDnMap();
4753    Backend<?> b = baseDNs.get(entryDN);
4754    while (b == null)
4755    {
4756      entryDN = entryDN.parent();
4757      if (entryDN == null)
4758      {
4759        return null;
4760      }
4761
4762      b = baseDNs.get(entryDN);
4763    }
4764
4765    return b;
4766  }
4767
4768  /**
4769   * Obtains a copy of the server's base DN registry.  The copy can be used
4770   * to test registration/deregistration of base DNs but cannot be used to
4771   * modify the backends.  To modify the server's live base DN to backend
4772   * mappings use {@link #registerBaseDN(DN, Backend, boolean)} and
4773   * {@link #deregisterBaseDN(DN)}.
4774   *
4775   * @return copy of the base DN registry
4776   */
4777  public static BaseDnRegistry copyBaseDnRegistry()
4778  {
4779    return directoryServer.baseDnRegistry.copy();
4780  }
4781
4782  /**
4783   * Registers the provided base DN with the server.
4784   *
4785   * @param  baseDN     The base DN to register with the server.  It must not be
4786   *                    {@code null}.
4787   * @param  backend    The backend responsible for the provided base DN.  It
4788   *                    must not be {@code null}.
4789   * @param  isPrivate  Indicates whether the base DN should be considered a
4790   *                    private base DN.  If the provided base DN is a naming
4791   *                    context, then this controls whether it is public or
4792   *                    private.
4793   *
4794   * @throws  DirectoryException  If a problem occurs while attempting to
4795   *                              register the provided base DN.
4796   */
4797  public static void registerBaseDN(DN baseDN, Backend<?> backend, boolean isPrivate)
4798         throws DirectoryException
4799  {
4800    ifNull(baseDN, backend);
4801
4802    synchronized (directoryServer)
4803    {
4804      List<LocalizableMessage> warnings =
4805              directoryServer.baseDnRegistry.registerBaseDN(
4806                      baseDN, backend, isPrivate);
4807
4808      // Since we've committed the changes we need to log any issues
4809      // that this registration has caused
4810      for (LocalizableMessage warning : warnings) {
4811        logger.error(warning);
4812      }
4813
4814      // When a new baseDN is registered with the server we have to create
4815      // a new workflow to handle the base DN.
4816      if (!baseDN.equals(DN.valueOf("cn=config")))
4817      {
4818        // Now create a workflow for the registered baseDN and register
4819        // the workflow with the default network group, but don't register
4820        // the workflow if the backend happens to be the configuration
4821        // backend because it's too soon for the config backend.
4822        createWorkflow(baseDN, backend);
4823      }
4824    }
4825  }
4826
4827  /**
4828   * Deregisters the provided base DN with the server.
4829   *
4830   * @param  baseDN     The base DN to deregister with the server.  It must not
4831   *                    be {@code null}.
4832   *
4833   * @throws  DirectoryException  If a problem occurs while attempting to
4834   *                              deregister the provided base DN.
4835   */
4836  public static void deregisterBaseDN(DN baseDN)
4837         throws DirectoryException
4838  {
4839    ifNull(baseDN);
4840
4841    synchronized(directoryServer) {
4842
4843      List<LocalizableMessage> warnings =
4844              directoryServer.baseDnRegistry.deregisterBaseDN(baseDN);
4845
4846      // Since we've committed the changes we need to log any issues
4847      // that this registration has caused
4848      for (LocalizableMessage error : warnings) {
4849        logger.error(error);
4850      }
4851
4852      // Now we need to deregister the workflow that was associated with the base DN
4853      if (!baseDN.equals(DN.valueOf("cn=config")))
4854      {
4855        LocalBackendWorkflowElement.remove(baseDN);
4856      }
4857    }
4858  }
4859
4860  /**
4861   * Retrieves the set of public naming contexts defined in the Directory
4862   * Server, mapped from the naming context DN to the corresponding backend.
4863   *
4864   * @return  The set of public naming contexts defined in the Directory Server.
4865   */
4866  public static Map<DN,Backend> getPublicNamingContexts()
4867  {
4868    return directoryServer.baseDnRegistry.getPublicNamingContextsMap();
4869  }
4870
4871  /**
4872   * Retrieves the set of private naming contexts defined in the Directory
4873   * Server, mapped from the naming context DN to the corresponding backend.
4874   *
4875   * @return  The set of private naming contexts defined in the Directory
4876   *          Server.
4877   */
4878  public static Map<DN,Backend> getPrivateNamingContexts()
4879  {
4880    return directoryServer.baseDnRegistry.getPrivateNamingContextsMap();
4881  }
4882
4883  /**
4884   * Indicates whether the specified DN is one of the Directory Server naming
4885   * contexts.
4886   *
4887   * @param  dn  The DN for which to make the determination.
4888   *
4889   * @return  {@code true} if the specified DN is a naming context for the
4890   *          Directory Server, or {@code false} if it is not.
4891   */
4892  public static boolean isNamingContext(DN dn)
4893  {
4894    return directoryServer.baseDnRegistry.containsNamingContext(dn);
4895  }
4896
4897  /**
4898   * Retrieves the root DSE entry for the Directory Server.
4899   *
4900   * @return  The root DSE entry for the Directory Server.
4901   */
4902  public static Entry getRootDSE()
4903  {
4904    return directoryServer.rootDSEBackend.getRootDSE();
4905  }
4906
4907  /**
4908   * Retrieves the root DSE backend for the Directory Server.
4909   *
4910   * @return  The root DSE backend for the Directory Server.
4911   */
4912  public static RootDSEBackend getRootDSEBackend()
4913  {
4914    return directoryServer.rootDSEBackend;
4915  }
4916
4917  /**
4918   * Retrieves the DN of the entry containing the server schema definitions.
4919   *
4920   * @return  The DN of the entry containing the server schema definitions, or
4921   *          <CODE>null</CODE> if none has been defined (e.g., if no schema
4922   *          backend has been configured).
4923   */
4924  public static DN getSchemaDN()
4925  {
4926    return directoryServer.schemaDN;
4927  }
4928
4929  /**
4930   * Specifies the DN of the entry containing the server schema definitions.
4931   *
4932   * @param  schemaDN  The DN of the entry containing the server schema
4933   *                   definitions.
4934   */
4935  public static void setSchemaDN(DN schemaDN)
4936  {
4937    directoryServer.schemaDN = schemaDN;
4938  }
4939
4940  /**
4941   * Retrieves the entry with the requested DN. It will first determine which backend should be used
4942   * for this DN and will then use that backend to retrieve the entry. The caller is not required to
4943   * hold any locks on the specified DN.
4944   *
4945   * @param entryDN
4946   *          The DN of the entry to retrieve.
4947   * @return The requested entry, or <CODE>null</CODE> if it does not exist.
4948   * @throws DirectoryException
4949   *           If a problem occurs while attempting to retrieve the entry.
4950   */
4951  public static Entry getEntry(DN entryDN) throws DirectoryException
4952  {
4953    if (entryDN.isRootDN())
4954    {
4955      return directoryServer.rootDSEBackend.getRootDSE();
4956    }
4957    final Backend<?> backend = getBackend(entryDN);
4958    return backend != null ? backend.getEntry(entryDN) : null;
4959  }
4960
4961  /**
4962   * Indicates whether the specified entry exists in the Directory Server.  The
4963   * caller is not required to hold any locks when invoking this method.
4964   *
4965   * @param  entryDN  The DN of the entry for which to make the determination.
4966   *
4967   * @return  <CODE>true</CODE> if the specified entry exists in one of the
4968   *          backends, or <CODE>false</CODE> if it does not.
4969   *
4970   * @throws  DirectoryException  If a problem occurs while attempting to
4971   *                              make the determination.
4972   */
4973  public static boolean entryExists(DN entryDN)
4974         throws DirectoryException
4975  {
4976    // If the entry is the root DSE, then it will always exist.
4977    if (entryDN.isRootDN())
4978    {
4979      return true;
4980    }
4981
4982    // Ask the appropriate backend if the entry exists.
4983    // If it is not appropriate for any backend, then return false.
4984    Backend<?> backend = getBackend(entryDN);
4985    return backend != null && backend.entryExists(entryDN);
4986  }
4987
4988  /**
4989   * Retrieves the set of supported controls registered with the Directory
4990   * Server.
4991   *
4992   * @return  The set of supported controls registered with the Directory
4993   *          Server.
4994   */
4995  public static TreeSet<String> getSupportedControls()
4996  {
4997    return directoryServer.supportedControls;
4998  }
4999
5000  /**
5001   * Indicates whether the specified OID is registered with the Directory Server
5002   * as a supported control.
5003   *
5004   * @param  controlOID  The OID of the control for which to make the
5005   *                     determination.
5006   *
5007   * @return  <CODE>true</CODE> if the specified OID is registered with the
5008   *          server as a supported control, or <CODE>false</CODE> if not.
5009   */
5010  public static boolean isSupportedControl(String controlOID)
5011  {
5012    return directoryServer.supportedControls.contains(controlOID);
5013  }
5014
5015  /**
5016   * Registers the provided OID as a supported control for the Directory Server.
5017   * This will have no effect if the specified control OID is already present in
5018   * the list of supported controls.
5019   *
5020   * @param  controlOID  The OID of the control to register as a supported
5021   *                     control.
5022   */
5023  public static void registerSupportedControl(String controlOID)
5024  {
5025    synchronized (directoryServer.supportedControls)
5026    {
5027      directoryServer.supportedControls.add(controlOID);
5028    }
5029  }
5030
5031  /**
5032   * Deregisters the provided OID as a supported control for the Directory
5033   * Server.  This will have no effect if the specified control OID is not
5034   * present in the list of supported controls.
5035   *
5036   * @param  controlOID  The OID of the control to deregister as a supported
5037   *                     control.
5038   */
5039  public static void deregisterSupportedControl(String controlOID)
5040  {
5041    synchronized (directoryServer.supportedControls)
5042    {
5043      directoryServer.supportedControls.remove(controlOID);
5044    }
5045  }
5046
5047  /**
5048   * Retrieves the set of supported features registered with the Directory
5049   * Server.
5050   *
5051   * @return  The set of supported features registered with the Directory
5052   *          Server.
5053   */
5054  public static TreeSet<String> getSupportedFeatures()
5055  {
5056    return directoryServer.supportedFeatures;
5057  }
5058
5059  /**
5060   * Indicates whether the specified OID is registered with the Directory Server
5061   * as a supported feature.
5062   *
5063   * @param  featureOID  The OID of the feature for which to make the
5064   *                     determination.
5065   *
5066   * @return  <CODE>true</CODE> if the specified OID is registered with the
5067   *          server as a supported feature, or <CODE>false</CODE> if not.
5068   */
5069  public static boolean isSupportedFeature(String featureOID)
5070  {
5071    return directoryServer.supportedFeatures.contains(featureOID);
5072  }
5073
5074  /**
5075   * Registers the provided OID as a supported feature for the Directory Server.
5076   * This will have no effect if the specified feature OID is already present in
5077   * the list of supported features.
5078   *
5079   * @param  featureOID  The OID of the feature to register as a supported
5080   *                     feature.
5081   */
5082  public static void registerSupportedFeature(String featureOID)
5083  {
5084    synchronized (directoryServer.supportedFeatures)
5085    {
5086      directoryServer.supportedFeatures.add(featureOID);
5087    }
5088  }
5089
5090  /**
5091   * Deregisters the provided OID as a supported feature for the Directory
5092   * Server.  This will have no effect if the specified feature OID is not
5093   * present in the list of supported features.
5094   *
5095   * @param  featureOID  The OID of the feature to deregister as a supported
5096   *                     feature.
5097   */
5098  public static void deregisterSupportedFeature(String featureOID)
5099  {
5100    synchronized (directoryServer.supportedFeatures)
5101    {
5102      directoryServer.supportedFeatures.remove(featureOID);
5103    }
5104  }
5105
5106  /**
5107   * Retrieves the set of extended operations that may be processed by the
5108   * Directory Server.
5109   *
5110   * @return  The set of extended operations that may be processed by the
5111   *         Directory Server.
5112   */
5113  public static ConcurrentMap<String, ExtendedOperationHandler>
5114                     getSupportedExtensions()
5115  {
5116    return directoryServer.extendedOperationHandlers;
5117  }
5118
5119  /**
5120   * Retrieves the handler for the extended operation for the provided OID.
5121   *
5122   * @param  oid  The OID of the extended operation to retrieve.
5123   *
5124   * @return  The handler for the specified extended operation, or
5125   *          <CODE>null</CODE> if there is none.
5126   */
5127  public static ExtendedOperationHandler getExtendedOperationHandler(String oid)
5128  {
5129    return directoryServer.extendedOperationHandlers.get(oid);
5130  }
5131
5132  /**
5133   * Registers the provided extended operation handler with the Directory
5134   * Server.
5135   *
5136   * @param  oid      The OID for the extended operation to register.
5137   * @param  handler  The extended operation handler to register with the
5138   *                  Directory Server.
5139   */
5140  public static void registerSupportedExtension(String oid,
5141                          ExtendedOperationHandler handler)
5142  {
5143    directoryServer.extendedOperationHandlers.put(toLowerCase(oid), handler);
5144  }
5145
5146  /**
5147   * Deregisters the provided extended operation handler with the Directory
5148   * Server.
5149   *
5150   * @param  oid  The OID for the extended operation to deregister.
5151   */
5152  public static void deregisterSupportedExtension(String oid)
5153  {
5154    directoryServer.extendedOperationHandlers.remove(toLowerCase(oid));
5155  }
5156
5157  /**
5158   * Retrieves the set of SASL mechanisms that are supported by the Directory
5159   * Server.
5160   *
5161   * @return  The set of SASL mechanisms that are supported by the Directory
5162   *          Server.
5163   */
5164  public static ConcurrentMap<String, SASLMechanismHandler>
5165                     getSupportedSASLMechanisms()
5166  {
5167    return directoryServer.saslMechanismHandlers;
5168  }
5169
5170  /**
5171   * Retrieves the handler for the specified SASL mechanism.
5172   *
5173   * @param  name  The name of the SASL mechanism to retrieve.
5174   *
5175   * @return  The handler for the specified SASL mechanism, or <CODE>null</CODE>
5176   *          if there is none.
5177   */
5178  public static SASLMechanismHandler getSASLMechanismHandler(String name)
5179  {
5180    return directoryServer.saslMechanismHandlers.get(name);
5181  }
5182
5183  /**
5184   * Registers the provided SASL mechanism handler with the Directory Server.
5185   *
5186   * @param  name     The name of the SASL mechanism to be registered.
5187   * @param  handler  The SASL mechanism handler to register with the Directory
5188   *                  Server.
5189   */
5190  public static void registerSASLMechanismHandler(String name,
5191                                                  SASLMechanismHandler handler)
5192  {
5193    // FIXME -- Should we force this name to be lowercase?  If so, then will
5194    // that cause the lower name to be used in the root DSE?
5195    directoryServer.saslMechanismHandlers.put(name, handler);
5196  }
5197
5198  /**
5199   * Deregisters the provided SASL mechanism handler with the Directory Server.
5200   *
5201   * @param  name  The name of the SASL mechanism to be deregistered.
5202   */
5203  public static void deregisterSASLMechanismHandler(String name)
5204  {
5205    // FIXME -- Should we force this name to be lowercase?
5206    directoryServer.saslMechanismHandlers.remove(name);
5207  }
5208
5209  /**
5210   * Retrieves the supported LDAP versions for the Directory Server.
5211   *
5212   * @return  The supported LDAP versions for the Directory Server.
5213   */
5214  public static Set<Integer> getSupportedLDAPVersions()
5215  {
5216    return directoryServer.supportedLDAPVersions.keySet();
5217  }
5218
5219  /**
5220   * Registers the provided LDAP protocol version as supported within the
5221   * Directory Server.
5222   *
5223   * @param  supportedLDAPVersion  The LDAP protocol version to register as
5224   *                               supported.
5225   * @param  connectionHandler     The connection handler that supports the
5226   *                               provided LDAP version.  Note that multiple
5227   *                               connection handlers can provide support for
5228   *                               the same LDAP versions.
5229   */
5230  public static synchronized void registerSupportedLDAPVersion(
5231                                       int supportedLDAPVersion,
5232                                       ConnectionHandler connectionHandler)
5233  {
5234    List<ConnectionHandler> handlers = directoryServer.supportedLDAPVersions.get(supportedLDAPVersion);
5235    if (handlers == null)
5236    {
5237      directoryServer.supportedLDAPVersions.put(supportedLDAPVersion, newLinkedList(connectionHandler));
5238    }
5239    else if (!handlers.contains(connectionHandler))
5240    {
5241      handlers.add(connectionHandler);
5242    }
5243  }
5244
5245  /**
5246   * Deregisters the provided LDAP protocol version as supported within the
5247   * Directory Server.
5248   *
5249   * @param  supportedLDAPVersion  The LDAP protocol version to deregister.
5250   * @param  connectionHandler     The connection handler that no longer
5251   *                               supports the provided LDAP version.
5252   */
5253  public static synchronized void deregisterSupportedLDAPVersion(
5254                                       int supportedLDAPVersion,
5255                                       ConnectionHandler connectionHandler)
5256  {
5257    List<ConnectionHandler> handlers =
5258         directoryServer.supportedLDAPVersions.get(supportedLDAPVersion);
5259    if (handlers != null)
5260    {
5261      handlers.remove(connectionHandler);
5262      if (handlers.isEmpty())
5263      {
5264        directoryServer.supportedLDAPVersions.remove(supportedLDAPVersion);
5265      }
5266    }
5267  }
5268
5269  /**
5270   * Retrieves the set of identity mappers defined in the Directory Server
5271   * configuration, as a mapping between the DN of the configuration entry and
5272   * the identity mapper.
5273   *
5274   * @return  The set of identity mappers defined in the Directory Server
5275   *          configuration.
5276   */
5277  public static ConcurrentMap<DN, IdentityMapper> getIdentityMappers()
5278  {
5279    return directoryServer.identityMappers;
5280  }
5281
5282  /**
5283   * Retrieves the Directory Server identity mapper whose configuration resides
5284   * in the specified configuration entry.
5285   *
5286   * @param  configEntryDN  The DN of the configuration entry for the identity
5287   *                        mapper to retrieve.
5288   *
5289   * @return  The requested identity mapper, or <CODE>null</CODE> if the
5290   *          provided entry DN is not associated with an active identity
5291   *          mapper.
5292   */
5293  public static IdentityMapper getIdentityMapper(DN configEntryDN)
5294  {
5295    return directoryServer.identityMappers.get(configEntryDN);
5296  }
5297
5298  /**
5299   * Registers the provided identity mapper for use with the Directory Server.
5300   *
5301   * @param  configEntryDN   The DN of the configuration entry in which the
5302   *                         identity mapper definition resides.
5303   * @param  identityMapper  The identity mapper to be registered.
5304   */
5305  public static void registerIdentityMapper(DN configEntryDN,
5306                                            IdentityMapper identityMapper)
5307  {
5308    directoryServer.identityMappers.put(configEntryDN, identityMapper);
5309  }
5310
5311  /**
5312   * Deregisters the provided identity mapper for use with the Directory Server.
5313   *
5314   * @param  configEntryDN  The DN of the configuration entry in which the
5315   *                        identity mapper definition resides.
5316   */
5317  public static void deregisterIdentityMapper(DN configEntryDN)
5318  {
5319    directoryServer.identityMappers.remove(configEntryDN);
5320  }
5321
5322  /**
5323   * Retrieves the DN of the configuration entry for the identity mapper that
5324   * should be used in conjunction with proxied authorization V2 controls.
5325   *
5326   * @return  The DN of the configuration entry for the identity mapper that
5327   *          should be used in conjunction with proxied authorization V2
5328   *          controls, or <CODE>null</CODE> if none is defined.
5329   */
5330  public static DN getProxiedAuthorizationIdentityMapperDN()
5331  {
5332    return directoryServer.proxiedAuthorizationIdentityMapperDN;
5333  }
5334
5335  /**
5336   * Specifies the DN of the configuration entry for the identity mapper that
5337   * should be used in conjunction with proxied authorization V2 controls.
5338   *
5339   * @param  proxiedAuthorizationIdentityMapperDN  The DN of the configuration
5340   *                                               entry for the identity mapper
5341   *                                               that should be used in
5342   *                                               conjunction with proxied
5343   *                                               authorization V2 controls.
5344   */
5345  public static void setProxiedAuthorizationIdentityMapperDN(
5346                          DN proxiedAuthorizationIdentityMapperDN)
5347  {
5348    directoryServer.proxiedAuthorizationIdentityMapperDN =
5349         proxiedAuthorizationIdentityMapperDN;
5350  }
5351
5352  /**
5353   * Retrieves the identity mapper that should be used to resolve authorization
5354   * IDs contained in proxied authorization V2 controls.
5355   *
5356   * @return  The identity mapper that should be used to resolve authorization
5357   *          IDs contained in proxied authorization V2 controls, or
5358   *          <CODE>null</CODE> if none is defined.
5359   */
5360  public static IdentityMapper getProxiedAuthorizationIdentityMapper()
5361  {
5362    if (directoryServer.proxiedAuthorizationIdentityMapperDN == null)
5363    {
5364      return null;
5365    }
5366
5367    return directoryServer.identityMappers.get(
5368                directoryServer.proxiedAuthorizationIdentityMapperDN);
5369  }
5370
5371  /**
5372   * Retrieves the set of connection handlers configured in the Directory
5373   * Server.  The returned list must not be altered.
5374   *
5375   * @return  The set of connection handlers configured in the Directory Server.
5376   */
5377  public static List<ConnectionHandler> getConnectionHandlers()
5378  {
5379    return directoryServer.connectionHandlers;
5380  }
5381
5382  /**
5383   * Registers the provided connection handler with the Directory Server.
5384   *
5385   * @param  handler  The connection handler to register with the Directory
5386   *                  Server.
5387   */
5388  public static void registerConnectionHandler(
5389                          ConnectionHandler<? extends ConnectionHandlerCfg>
5390                               handler)
5391  {
5392    synchronized (directoryServer.connectionHandlers)
5393    {
5394      directoryServer.connectionHandlers.add(handler);
5395
5396      ConnectionHandlerMonitor monitor = new ConnectionHandlerMonitor(handler);
5397      monitor.initializeMonitorProvider(null);
5398      handler.setConnectionHandlerMonitor(monitor);
5399      registerMonitorProvider(monitor);
5400    }
5401  }
5402
5403  /**
5404   * Deregisters the provided connection handler with the Directory Server.
5405   *
5406   * @param  handler  The connection handler to deregister with the Directory
5407   *                  Server.
5408   */
5409  public static void deregisterConnectionHandler(ConnectionHandler handler)
5410  {
5411    synchronized (directoryServer.connectionHandlers)
5412    {
5413      directoryServer.connectionHandlers.remove(handler);
5414
5415      ConnectionHandlerMonitor monitor = handler.getConnectionHandlerMonitor();
5416      if (monitor != null)
5417      {
5418        deregisterMonitorProvider(monitor);
5419        monitor.finalizeMonitorProvider();
5420        handler.setConnectionHandlerMonitor(null);
5421      }
5422    }
5423  }
5424
5425  /**
5426   * Starts the connection handlers defined in the Directory Server
5427   * Configuration.
5428   *
5429   * @throws  ConfigException If there are more than one connection handlers
5430   *                          using the same host port or no connection handler
5431   *                          are enabled or we could not bind to any of the
5432   *                          listeners.
5433   */
5434  private void startConnectionHandlers() throws ConfigException
5435  {
5436    Set<HostPort> usedListeners = new LinkedHashSet<>();
5437    Set<LocalizableMessage> errorMessages = new LinkedHashSet<>();
5438    // Check that the port specified in the connection handlers is available.
5439    for (ConnectionHandler<?> c : connectionHandlers)
5440    {
5441      for (HostPort listener : c.getListeners())
5442      {
5443        if (!usedListeners.add(listener))
5444        {
5445          // The port was already specified: this is a configuration error,
5446          // log a message.
5447          LocalizableMessage message = ERR_HOST_PORT_ALREADY_SPECIFIED.get(c.getConnectionHandlerName(), listener);
5448          logger.error(message);
5449          errorMessages.add(message);
5450        }
5451      }
5452    }
5453
5454    if (!errorMessages.isEmpty())
5455    {
5456      throw new ConfigException(ERR_ERROR_STARTING_CONNECTION_HANDLERS.get());
5457    }
5458
5459    // If there are no connection handlers log a message.
5460    if (connectionHandlers.isEmpty())
5461    {
5462      logger.error(ERR_NOT_AVAILABLE_CONNECTION_HANDLERS);
5463      throw new ConfigException(ERR_ERROR_STARTING_CONNECTION_HANDLERS.get());
5464    }
5465
5466    // At this point, we should be ready to go.
5467    for (ConnectionHandler handler : connectionHandlers)
5468    {
5469      handler.start();
5470    }
5471  }
5472
5473  /**
5474   * Retrieves a reference to the Directory Server work queue.
5475   *
5476   * @return  A reference to the Directory Server work queue.
5477   */
5478  public static WorkQueue getWorkQueue()
5479  {
5480    return directoryServer.workQueue;
5481  }
5482
5483  /**
5484   * Runs all the necessary checks prior to adding an operation to the work
5485   * queue. It throws a DirectoryException if one of the check fails.
5486   *
5487   * @param operation
5488   *          The operation to be added to the work queue.
5489   * @throws DirectoryException
5490   *           If a check failed preventing the operation from being added to
5491   *           the queue
5492   */
5493  private static void checkCanEnqueueRequest(Operation operation)
5494         throws DirectoryException
5495  {
5496    ClientConnection clientConnection = operation.getClientConnection();
5497    //Reject or accept the unauthenticated requests based on the configuration
5498    // settings.
5499    if ((directoryServer.rejectUnauthenticatedRequests ||
5500         directoryServer.lockdownMode) &&
5501        !clientConnection.getAuthenticationInfo().isAuthenticated())
5502    {
5503      switch(operation.getOperationType())
5504      {
5505        case ADD:
5506        case COMPARE:
5507        case DELETE:
5508        case SEARCH:
5509        case MODIFY:
5510        case MODIFY_DN:
5511          LocalizableMessage message = directoryServer.lockdownMode
5512              ? NOTE_REJECT_OPERATION_IN_LOCKDOWN_MODE.get()
5513              : ERR_REJECT_UNAUTHENTICATED_OPERATION.get();
5514          throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
5515
5516        case EXTENDED:
5517         ExtendedOperationBasis extOp = (ExtendedOperationBasis) operation;
5518         String   requestOID = extOp.getRequestOID();
5519         if (!OID_START_TLS_REQUEST.equals(requestOID))
5520         {
5521           message = directoryServer.lockdownMode
5522               ? NOTE_REJECT_OPERATION_IN_LOCKDOWN_MODE.get()
5523               : ERR_REJECT_UNAUTHENTICATED_OPERATION.get();
5524           throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
5525         }
5526         break;
5527
5528      }
5529    }
5530
5531    // If the associated user is required to change their password before
5532    // continuing, then make sure the associated operation is one that could
5533    // result in the password being changed.  If not, then reject it.
5534    if (clientConnection.mustChangePassword())
5535    {
5536      switch (operation.getOperationType())
5537      {
5538        case ADD:
5539        case COMPARE:
5540        case DELETE:
5541        case MODIFY_DN:
5542        case SEARCH:
5543          // See if the request included the password policy request control.
5544          // If it did, then add a corresponding response control.
5545          for (Control c : operation.getRequestControls())
5546          {
5547            if (OID_PASSWORD_POLICY_CONTROL.equals(c.getOID()))
5548            {
5549              operation.addResponseControl(new PasswordPolicyResponseControl(
5550                   null, 0, PasswordPolicyErrorType.CHANGE_AFTER_RESET));
5551              break;
5552            }
5553          }
5554
5555          DN user = clientConnection.getAuthenticationInfo()
5556              .getAuthorizationDN();
5557          LocalizableMessage message = ERR_ENQUEUE_MUST_CHANGE_PASSWORD
5558              .get(user != null ? user : "anonymous");
5559          throw new DirectoryException(
5560                  ResultCode.CONSTRAINT_VIOLATION, message);
5561
5562        case EXTENDED:
5563          // We will only allow the password modify and StartTLS extended
5564          // operations.
5565          ExtendedOperationBasis extOp = (ExtendedOperationBasis) operation;
5566          String            requestOID = extOp.getRequestOID();
5567          if (!OID_PASSWORD_MODIFY_REQUEST.equals(requestOID)
5568              && !OID_START_TLS_REQUEST.equals(requestOID))
5569          {
5570            // See if the request included the password policy request control.
5571            // If it did, then add a corresponding response control.
5572            for (Control c : operation.getRequestControls())
5573            {
5574              if (OID_PASSWORD_POLICY_CONTROL.equals(c.getOID()))
5575              {
5576                operation.addResponseControl(new PasswordPolicyResponseControl(
5577                     null, 0, PasswordPolicyErrorType.CHANGE_AFTER_RESET));
5578                break;
5579              }
5580            }
5581
5582            user = clientConnection.getAuthenticationInfo()
5583                .getAuthorizationDN();
5584            message = ERR_ENQUEUE_MUST_CHANGE_PASSWORD
5585                .get(user != null ? user : "anonymous");
5586            throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
5587                                         message);
5588          }
5589
5590          break;
5591
5592          // Bind, unbind, and abandon will always be allowed.
5593
5594          // Modify may or may not be allowed, but we'll leave that
5595          // determination up to the modify operation itself.
5596      }
5597    }
5598  }
5599
5600  /**
5601   * Adds the provided operation to the work queue so that it will be processed
5602   * by one of the worker threads.
5603   *
5604   * @param  operation  The operation to be added to the work queue.
5605   *
5606   * @throws  DirectoryException  If a problem prevents the operation from being
5607   *                              added to the queue (e.g., the queue is full).
5608   */
5609  public static void enqueueRequest(Operation operation)
5610      throws DirectoryException
5611  {
5612    checkCanEnqueueRequest(operation);
5613    directoryServer.workQueue.submitOperation(operation);
5614  }
5615
5616  /**
5617   * Tries to add the provided operation to the work queue if not full so that
5618   * it will be processed by one of the worker threads.
5619   *
5620   * @param operation
5621   *          The operation to be added to the work queue.
5622   * @return true if the operation could be enqueued, false otherwise
5623   * @throws DirectoryException
5624   *           If a problem prevents the operation from being added to the queue
5625   *           (e.g., the queue is full).
5626   */
5627  public static boolean tryEnqueueRequest(Operation operation)
5628      throws DirectoryException
5629  {
5630    checkCanEnqueueRequest(operation);
5631    return directoryServer.workQueue.trySubmitOperation(operation);
5632  }
5633
5634  /**
5635   * Retrieves the set of synchronization providers that have been registered
5636   * with the Directory Server.
5637   *
5638   * @return  The set of synchronization providers that have been registered
5639   *          with the Directory Server.
5640   */
5641  public static List<SynchronizationProvider<SynchronizationProviderCfg>>
5642      getSynchronizationProviders()
5643  {
5644    return directoryServer.synchronizationProviders;
5645  }
5646
5647  /**
5648   * Registers the provided synchronization provider with the Directory Server.
5649   *
5650   * @param  provider  The synchronization provider to register.
5651   */
5652  public static void registerSynchronizationProvider(
5653      SynchronizationProvider<SynchronizationProviderCfg> provider)
5654  {
5655    directoryServer.synchronizationProviders.add(provider);
5656
5657    provider.completeSynchronizationProvider();
5658  }
5659
5660  /**
5661   * Deregisters the provided synchronization provider with the Directory
5662   * Server.
5663   *
5664   * @param  provider  The synchronization provider to deregister.
5665   */
5666  public static void deregisterSynchronizationProvider(SynchronizationProvider
5667                                                            provider)
5668  {
5669    directoryServer.synchronizationProviders.remove(provider);
5670  }
5671
5672  /**
5673   * Retrieves a set containing the names of the allowed tasks that may be
5674   * invoked in the server.
5675   *
5676   * @return  A set containing the names of the allowed tasks that may be
5677   *          invoked in the server.
5678   */
5679  public static Set<String> getAllowedTasks()
5680  {
5681    return directoryServer.allowedTasks;
5682  }
5683
5684  /**
5685   * Specifies the set of allowed tasks that may be invoked in the server.
5686   *
5687   * @param  allowedTasks  A set containing the names of the allowed tasks that
5688   *                       may be invoked in the server.
5689   */
5690  public static void setAllowedTasks(Set<String> allowedTasks)
5691  {
5692    directoryServer.allowedTasks = allowedTasks;
5693  }
5694
5695  /**
5696   * Retrieves the set of privileges that have been disabled.
5697   *
5698   * @return  The set of privileges that have been disabled.
5699   */
5700  public static Set<Privilege> getDisabledPrivileges()
5701  {
5702    return directoryServer.disabledPrivileges;
5703  }
5704
5705  /**
5706   * Indicates whether the specified privilege is disabled.
5707   *
5708   * @param  privilege  The privilege for which to make the determination.
5709   *
5710   * @return  {@code true} if the specified privilege is disabled, or
5711   *          {@code false} if not.
5712   */
5713  public static boolean isDisabled(Privilege privilege)
5714  {
5715    return directoryServer.disabledPrivileges.contains(privilege);
5716  }
5717
5718  /**
5719   * Specifies the set of privileges that should be disabled in the server.
5720   *
5721   * @param  disabledPrivileges  The set of privileges that should be disabled
5722   *                             in the server.
5723   */
5724  public static void setDisabledPrivileges(Set<Privilege> disabledPrivileges)
5725  {
5726    directoryServer.disabledPrivileges = disabledPrivileges;
5727  }
5728
5729  /**
5730   * Indicates whether responses to failed bind operations should include a
5731   * message explaining the reason for the failure.
5732   *
5733   * @return  {@code true} if bind responses should include error messages, or
5734   *          {@code false} if not.
5735   */
5736  public static boolean returnBindErrorMessages()
5737  {
5738    return directoryServer.returnBindErrorMessages;
5739  }
5740
5741  /**
5742   * Specifies whether responses to failed bind operations should include a
5743   * message explaining the reason for the failure.
5744   *
5745   * @param  returnBindErrorMessages  Specifies whether responses to failed bind
5746   *                                  operations should include a message
5747   *                                  explaining the reason for the failure.
5748   */
5749  public static void setReturnBindErrorMessages(boolean returnBindErrorMessages)
5750  {
5751    directoryServer.returnBindErrorMessages = returnBindErrorMessages;
5752  }
5753
5754  /**
5755   * Retrieves the maximum length of time in milliseconds that client
5756   * connections should be allowed to remain idle without being disconnected.
5757   *
5758   * @return  The maximum length of time in milliseconds that client connections
5759   *          should be allowed to remain idle without being disconnected.
5760   */
5761  public static long getIdleTimeLimit()
5762  {
5763    return directoryServer.idleTimeLimit;
5764  }
5765
5766  /**
5767   * Specifies the maximum length of time in milliseconds that client
5768   * connections should be allowed to remain idle without being disconnected.
5769   *
5770   * @param  idleTimeLimit  The maximum length of time in milliseconds that
5771   *                        client connections should be allowed to remain idle
5772   *                        without being disconnected.
5773   */
5774  public static void setIdleTimeLimit(long idleTimeLimit)
5775  {
5776    directoryServer.idleTimeLimit = idleTimeLimit;
5777  }
5778
5779  /**
5780   * Indicates whether the Directory Server should save a copy of its
5781   * configuration whenever it is started successfully.
5782   *
5783   * @return  {@code true} if the server should save a copy of its configuration
5784   *          whenever it is started successfully, or {@code false} if not.
5785   */
5786  public static boolean saveConfigOnSuccessfulStartup()
5787  {
5788    return directoryServer.saveConfigOnSuccessfulStartup;
5789  }
5790
5791  /**
5792   * Specifies whether the Directory Server should save a copy of its
5793   * configuration whenever it is started successfully.
5794   *
5795   * @param  saveConfigOnSuccessfulStartup  Specifies whether the server should
5796   *                                        save a copy of its configuration
5797   *                                        whenever it is started successfully.
5798   */
5799  public static void setSaveConfigOnSuccessfulStartup(
5800                          boolean saveConfigOnSuccessfulStartup)
5801  {
5802    directoryServer.saveConfigOnSuccessfulStartup =
5803         saveConfigOnSuccessfulStartup;
5804  }
5805
5806  /**
5807   * Registers the provided backup task listener with the Directory Server.
5808   *
5809   * @param  listener  The backup task listener to register with the Directory
5810   *                   Server.
5811   */
5812  public static void registerBackupTaskListener(BackupTaskListener listener)
5813  {
5814    directoryServer.backupTaskListeners.addIfAbsent(listener);
5815  }
5816
5817  /**
5818   * Deregisters the provided backup task listener with the Directory Server.
5819   *
5820   * @param  listener  The backup task listener to deregister with the Directory
5821   *                   Server.
5822   */
5823  public static void deregisterBackupTaskListener(BackupTaskListener listener)
5824  {
5825    directoryServer.backupTaskListeners.remove(listener);
5826  }
5827
5828  /**
5829   * Notifies the registered backup task listeners that the server will be
5830   * beginning a backup task with the provided information.
5831   *
5832   * @param  backend  The backend in which the backup is to be performed.
5833   * @param  config   The configuration for the backup to be performed.
5834   */
5835  public static void notifyBackupBeginning(Backend<?> backend, BackupConfig config)
5836  {
5837    for (BackupTaskListener listener : directoryServer.backupTaskListeners)
5838    {
5839      try
5840      {
5841        listener.processBackupBegin(backend, config);
5842      }
5843      catch (Exception e)
5844      {
5845        logger.traceException(e);
5846      }
5847    }
5848  }
5849
5850  /**
5851   * Notifies the registered backup task listeners that the server has completed
5852   * processing on a backup task with the provided information.
5853   *
5854   * @param  backend     The backend in which the backup was performed.
5855   * @param  config      The configuration for the backup that was performed.
5856   * @param  successful  Indicates whether the backup completed successfully.
5857   */
5858  public static void notifyBackupEnded(Backend<?> backend, BackupConfig config, boolean successful)
5859  {
5860    for (BackupTaskListener listener : directoryServer.backupTaskListeners)
5861    {
5862      try
5863      {
5864        listener.processBackupEnd(backend, config, successful);
5865      }
5866      catch (Exception e)
5867      {
5868        logger.traceException(e);
5869      }
5870    }
5871  }
5872
5873  /**
5874   * Registers the provided restore task listener with the Directory Server.
5875   *
5876   * @param  listener  The restore task listener to register with the Directory
5877   *                   Server.
5878   */
5879  public static void registerRestoreTaskListener(RestoreTaskListener listener)
5880  {
5881    directoryServer.restoreTaskListeners.addIfAbsent(listener);
5882  }
5883
5884  /**
5885   * Deregisters the provided restore task listener with the Directory Server.
5886   *
5887   * @param  listener  The restore task listener to deregister with the
5888   *                   Directory Server.
5889   */
5890  public static void deregisterRestoreTaskListener(RestoreTaskListener listener)
5891  {
5892    directoryServer.restoreTaskListeners.remove(listener);
5893  }
5894
5895  /**
5896   * Notifies the registered restore task listeners that the server will be
5897   * beginning a restore task with the provided information.
5898   *
5899   * @param  backend  The backend in which the restore is to be performed.
5900   * @param  config   The configuration for the restore to be performed.
5901   */
5902  public static void notifyRestoreBeginning(Backend<?> backend, RestoreConfig config)
5903  {
5904    for (RestoreTaskListener listener : directoryServer.restoreTaskListeners)
5905    {
5906      try
5907      {
5908        listener.processRestoreBegin(backend, config);
5909      }
5910      catch (Exception e)
5911      {
5912        logger.traceException(e);
5913      }
5914    }
5915  }
5916
5917  /**
5918   * Notifies the registered restore task listeners that the server has
5919   * completed processing on a restore task with the provided information.
5920   *
5921   * @param  backend     The backend in which the restore was performed.
5922   * @param  config      The configuration for the restore that was performed.
5923   * @param  successful  Indicates whether the restore completed successfully.
5924   */
5925  public static void notifyRestoreEnded(Backend<?> backend, RestoreConfig config, boolean successful)
5926  {
5927    for (RestoreTaskListener listener : directoryServer.restoreTaskListeners)
5928    {
5929      try
5930      {
5931        listener.processRestoreEnd(backend, config, successful);
5932      }
5933      catch (Exception e)
5934      {
5935        logger.traceException(e);
5936      }
5937    }
5938  }
5939
5940  /**
5941   * Registers the provided LDIF export task listener with the Directory Server.
5942   *
5943   * @param  listener  The export task listener to register with the Directory
5944   *                   Server.
5945   */
5946  public static void registerExportTaskListener(ExportTaskListener listener)
5947  {
5948    directoryServer.exportTaskListeners.addIfAbsent(listener);
5949  }
5950
5951  /**
5952   * Deregisters the provided LDIF export task listener with the Directory
5953   * Server.
5954   *
5955   * @param  listener  The export task listener to deregister with the Directory
5956   *                   Server.
5957   */
5958  public static void deregisterExportTaskListener(ExportTaskListener listener)
5959  {
5960    directoryServer.exportTaskListeners.remove(listener);
5961  }
5962
5963  /**
5964   * Notifies the registered LDIF export task listeners that the server will be
5965   * beginning an export task with the provided information.
5966   *
5967   * @param  backend  The backend in which the export is to be performed.
5968   * @param  config   The configuration for the export to be performed.
5969   */
5970  public static void notifyExportBeginning(Backend<?> backend, LDIFExportConfig config)
5971  {
5972    for (ExportTaskListener listener : directoryServer.exportTaskListeners)
5973    {
5974      try
5975      {
5976        listener.processExportBegin(backend, config);
5977      }
5978      catch (Exception e)
5979      {
5980        logger.traceException(e);
5981      }
5982    }
5983  }
5984
5985  /**
5986   * Notifies the registered LDIF export task listeners that the server has
5987   * completed processing on an export task with the provided information.
5988   *
5989   * @param  backend     The backend in which the export was performed.
5990   * @param  config      The configuration for the export that was performed.
5991   * @param  successful  Indicates whether the export completed successfully.
5992   */
5993  public static void notifyExportEnded(Backend<?> backend, LDIFExportConfig config, boolean successful)
5994  {
5995    for (ExportTaskListener listener : directoryServer.exportTaskListeners)
5996    {
5997      try
5998      {
5999        listener.processExportEnd(backend, config, successful);
6000      }
6001      catch (Exception e)
6002      {
6003        logger.traceException(e);
6004      }
6005    }
6006  }
6007
6008  /**
6009   * Registers the provided LDIF import task listener with the Directory Server.
6010   *
6011   * @param  listener  The import task listener to register with the Directory
6012   *                   Server.
6013   */
6014  public static void registerImportTaskListener(ImportTaskListener listener)
6015  {
6016    directoryServer.importTaskListeners.addIfAbsent(listener);
6017  }
6018
6019  /**
6020   * Deregisters the provided LDIF import task listener with the Directory
6021   * Server.
6022   *
6023   * @param  listener  The import task listener to deregister with the Directory
6024   *                   Server.
6025   */
6026  public static void deregisterImportTaskListener(ImportTaskListener listener)
6027  {
6028    directoryServer.importTaskListeners.remove(listener);
6029  }
6030
6031  /**
6032   * Notifies the registered LDIF import task listeners that the server will be
6033   * beginning an import task with the provided information.
6034   *
6035   * @param  backend  The backend in which the import is to be performed.
6036   * @param  config   The configuration for the import to be performed.
6037   */
6038  public static void notifyImportBeginning(Backend<?> backend, LDIFImportConfig config)
6039  {
6040    for (ImportTaskListener listener : directoryServer.importTaskListeners)
6041    {
6042      try
6043      {
6044        listener.processImportBegin(backend, config);
6045      }
6046      catch (Exception e)
6047      {
6048        logger.traceException(e);
6049      }
6050    }
6051  }
6052
6053  /**
6054   * Notifies the registered LDIF import task listeners that the server has
6055   * completed processing on an import task with the provided information.
6056   *
6057   * @param  backend     The backend in which the import was performed.
6058   * @param  config      The configuration for the import that was performed.
6059   * @param  successful  Indicates whether the import completed successfully.
6060   */
6061  public static void notifyImportEnded(Backend<?> backend, LDIFImportConfig config, boolean successful)
6062  {
6063    for (ImportTaskListener listener : directoryServer.importTaskListeners)
6064    {
6065      try
6066      {
6067        listener.processImportEnd(backend, config, successful);
6068      }
6069      catch (Exception e)
6070      {
6071        logger.traceException(e);
6072      }
6073    }
6074  }
6075
6076  /**
6077   * Registers the provided initialization completed listener with the
6078   * Directory Server so that it will be notified when the server
6079   * initialization completes.
6080   *
6081   * @param  listener  The initialization competed listener to register with
6082   *                   the Directory Server.
6083   */
6084  public static void registerInitializationCompletedListener(
6085          InitializationCompletedListener listener) {
6086    directoryServer.initializationCompletedListeners.add(listener);
6087  }
6088
6089  /**
6090   * Deregisters the provided initialization completed listener with the
6091   * Directory Server.
6092   *
6093   * @param  listener  The initialization completed listener to deregister with
6094   *                   the Directory Server.
6095   */
6096  public static void deregisterInitializationCompletedListener(
6097          InitializationCompletedListener listener) {
6098    directoryServer.initializationCompletedListeners.remove(listener);
6099  }
6100
6101  /**
6102   * Registers the provided shutdown listener with the Directory Server so that
6103   * it will be notified when the server shuts down.
6104   *
6105   * @param  listener  The shutdown listener to register with the Directory
6106   *                   Server.
6107   */
6108  public static void registerShutdownListener(ServerShutdownListener listener)
6109  {
6110    directoryServer.shutdownListeners.add(listener);
6111  }
6112
6113  /**
6114   * Deregisters the provided shutdown listener with the Directory Server.
6115   *
6116   * @param  listener  The shutdown listener to deregister with the Directory
6117   *                   Server.
6118   */
6119  public static void deregisterShutdownListener(ServerShutdownListener listener)
6120  {
6121    directoryServer.shutdownListeners.remove(listener);
6122  }
6123
6124  /**
6125   * Initiates the Directory Server shutdown process.  Note that once this has
6126   * started, it should not be interrupted.
6127   *
6128   * @param  className  The fully-qualified name of the Java class that
6129   *                    initiated the shutdown.
6130   * @param  reason     The human-readable reason that the directory server is
6131   *                    shutting down.
6132   */
6133  public static void shutDown(String className, LocalizableMessage reason)
6134  {
6135    synchronized (directoryServer)
6136    {
6137      if (directoryServer.shuttingDown)
6138      {
6139        // We already know that the server is shutting down, so we don't need to
6140        // do anything.
6141        return;
6142      }
6143
6144      directoryServer.shuttingDown = true;
6145    }
6146
6147    // Send an alert notification that the server is shutting down.
6148    sendAlertNotification(directoryServer, ALERT_TYPE_SERVER_SHUTDOWN,
6149        NOTE_SERVER_SHUTDOWN.get(className, reason));
6150
6151    // Create a shutdown monitor that will watch the rest of the shutdown
6152    // process to ensure that everything goes smoothly.
6153    ServerShutdownMonitor shutdownMonitor = new ServerShutdownMonitor();
6154    shutdownMonitor.start();
6155
6156    // Shut down the connection handlers.
6157    for (ConnectionHandler handler : directoryServer.connectionHandlers)
6158    {
6159      try
6160      {
6161        handler.finalizeConnectionHandler(
6162                INFO_CONNHANDLER_CLOSED_BY_SHUTDOWN.get());
6163      }
6164      catch (Exception e)
6165      {
6166        logger.traceException(e);
6167      }
6168    }
6169    directoryServer.connectionHandlers.clear();
6170
6171    if (directoryServer.workQueue != null)
6172    {
6173      directoryServer.workQueue.finalizeWorkQueue(reason);
6174      directoryServer.workQueue.waitUntilIdle(ServerShutdownMonitor.WAIT_TIME);
6175    }
6176
6177    // shutdown replication
6178    for (SynchronizationProvider provider :
6179         directoryServer.synchronizationProviders)
6180    {
6181      provider.finalizeSynchronizationProvider();
6182    }
6183
6184    // Call the shutdown plugins, and then finalize all the plugins defined in
6185    // the server.
6186    if (directoryServer.pluginConfigManager != null)
6187    {
6188      directoryServer.pluginConfigManager.invokeShutdownPlugins(reason);
6189      directoryServer.pluginConfigManager.finalizePlugins();
6190    }
6191
6192    // Deregister the shutdown hook.
6193    if (directoryServer.shutdownHook != null)
6194    {
6195      try
6196      {
6197        Runtime.getRuntime().removeShutdownHook(directoryServer.shutdownHook);
6198      }
6199      catch (Exception e) {}
6200    }
6201
6202    // Notify all the shutdown listeners.
6203    for (ServerShutdownListener shutdownListener :
6204         directoryServer.shutdownListeners)
6205    {
6206      try
6207      {
6208        shutdownListener.processServerShutdown(reason);
6209      }
6210      catch (Exception e)
6211      {
6212        logger.traceException(e);
6213      }
6214    }
6215
6216    // Shut down all of the alert handlers.
6217    for (AlertHandler alertHandler : directoryServer.alertHandlers)
6218    {
6219      alertHandler.finalizeAlertHandler();
6220    }
6221
6222    // Deregister all of the JMX MBeans.
6223    if (directoryServer.mBeanServer != null)
6224    {
6225      Set mBeanSet = directoryServer.mBeanServer.queryMBeans(null, null);
6226      for (Object o : mBeanSet)
6227      {
6228        if (o instanceof DirectoryServerMBean)
6229        {
6230          try
6231          {
6232            DirectoryServerMBean mBean = (DirectoryServerMBean) o;
6233            directoryServer.mBeanServer.unregisterMBean(mBean.getObjectName());
6234          }
6235          catch (Exception e)
6236          {
6237            logger.traceException(e);
6238          }
6239        }
6240      }
6241    }
6242
6243    // Finalize all of the SASL mechanism handlers.
6244    for (SASLMechanismHandler handler :
6245         directoryServer.saslMechanismHandlers.values())
6246    {
6247      try
6248      {
6249        handler.finalizeSASLMechanismHandler();
6250      }
6251      catch (Exception e)
6252      {
6253        logger.traceException(e);
6254      }
6255    }
6256
6257    // Finalize all of the extended operation handlers.
6258    for (ExtendedOperationHandler handler :
6259         directoryServer.extendedOperationHandlers.values())
6260    {
6261      try
6262      {
6263        handler.finalizeExtendedOperationHandler();
6264      }
6265      catch (Exception e)
6266      {
6267        logger.traceException(e);
6268      }
6269    }
6270
6271    // Finalize the password policy map.
6272    for (DN configEntryDN : directoryServer.authenticationPolicies.keySet())
6273    {
6274      DirectoryServer.deregisterAuthenticationPolicy(configEntryDN);
6275    }
6276
6277    // Finalize password policies and their config manager.
6278    if (directoryServer.authenticationPolicyConfigManager != null)
6279    {
6280      directoryServer.authenticationPolicyConfigManager
6281          .finalizeAuthenticationPolicies();
6282    }
6283
6284    // Finalize the access control handler
6285    AccessControlHandler accessControlHandler =
6286        AccessControlConfigManager.getInstance().getAccessControlHandler();
6287    if (accessControlHandler != null)
6288    {
6289      accessControlHandler.finalizeAccessControlHandler();
6290    }
6291
6292    // Perform any necessary cleanup work for the group manager.
6293    if (directoryServer.groupManager != null)
6294    {
6295      directoryServer.groupManager.finalizeGroupManager();
6296    }
6297
6298    // Finalize the subentry manager.
6299    if (directoryServer.subentryManager != null)
6300    {
6301      directoryServer.subentryManager.finalizeSubentryManager();
6302    }
6303
6304    // Shut down all the other components that may need special handling.
6305    // NYI
6306
6307    // Shut down the monitor providers.
6308    for (MonitorProvider monitor : directoryServer.monitorProviders.values())
6309    {
6310      try
6311      {
6312        monitor.finalizeMonitorProvider();
6313      }
6314      catch (Exception e)
6315      {
6316        logger.traceException(e);
6317      }
6318    }
6319
6320    // Shut down the backends.
6321    for (Backend<?> backend : directoryServer.backends.values())
6322    {
6323      try
6324      {
6325        // Deregister all the local backend workflow elements that have been
6326        // registered with the server.
6327        LocalBackendWorkflowElement.removeAll();
6328
6329        for (BackendInitializationListener listener :
6330             directoryServer.backendInitializationListeners)
6331        {
6332          listener.performBackendFinalizationProcessing(backend);
6333        }
6334
6335        backend.finalizeBackend();
6336
6337        // Remove the shared lock for this backend.
6338        try
6339        {
6340          String lockFile = LockFileManager.getBackendLockFileName(backend);
6341          StringBuilder failureReason = new StringBuilder();
6342          if (! LockFileManager.releaseLock(lockFile, failureReason))
6343          {
6344            logger.warn(WARN_SHUTDOWN_CANNOT_RELEASE_SHARED_BACKEND_LOCK, backend.getBackendID(), failureReason);
6345            // FIXME -- Do we need to send an admin alert?
6346          }
6347        }
6348        catch (Exception e2)
6349        {
6350          logger.traceException(e2);
6351
6352          logger.warn(WARN_SHUTDOWN_CANNOT_RELEASE_SHARED_BACKEND_LOCK,
6353              backend.getBackendID(), stackTraceToSingleLineString(e2));
6354          // FIXME -- Do we need to send an admin alert?
6355        }
6356      }
6357      catch (Exception e)
6358      {
6359        logger.traceException(e);
6360      }
6361    }
6362
6363    // Finalize the entry cache.
6364    EntryCache ec = DirectoryServer.getEntryCache();
6365    if (ec != null)
6366    {
6367      ec.finalizeEntryCache();
6368    }
6369
6370    // Release exclusive lock held on server.lock file
6371    try {
6372        String serverLockFileName = LockFileManager.getServerLockFileName();
6373        StringBuilder failureReason = new StringBuilder();
6374        if (!LockFileManager.releaseLock(serverLockFileName, failureReason)) {
6375            logger.info(NOTE_SERVER_SHUTDOWN, className, failureReason);
6376        }
6377        serverLocked = false;
6378    } catch (Exception e) {
6379        logger.traceException(e);
6380    }
6381
6382    // Force a new InternalClientConnection to be created on restart.
6383    InternalConnectionHandler.clearRootClientConnectionAtShutdown();
6384
6385    // Log a final message indicating that the server is stopped (which should
6386    // be true for all practical purposes), and then shut down all the error
6387    // loggers.
6388    logger.info(NOTE_SERVER_STOPPED);
6389
6390    AccessLogger.getInstance().removeAllLogPublishers();
6391    ErrorLogger.getInstance().removeAllLogPublishers();
6392    DebugLogger.getInstance().removeAllLogPublishers();
6393
6394    // Now that the loggers are disabled we can shutdown the timer.
6395    TimeThread.stop();
6396
6397    // Just in case there's something that isn't shut down properly, wait for
6398    // the monitor to give the OK to stop.
6399    shutdownMonitor.waitForMonitor();
6400
6401    // At this point, the server is no longer running.  We should destroy the
6402    // handle to the previous instance, but we will want to get a new instance
6403    // in case the server is to be started again later in the same JVM.  Before
6404    // doing that, destroy the previous instance.
6405    DirectoryEnvironmentConfig envConfig = directoryServer.environmentConfig;
6406    directoryServer.destroy();
6407    directoryServer = getNewInstance(envConfig);
6408  }
6409
6410  /**
6411   * Destroy key structures in the current Directory Server instance in a manner
6412   * that can help detect any inappropriate cached references to server
6413   * components.
6414   */
6415  private void destroy()
6416  {
6417    checkSchema                   = true;
6418    isBootstrapped                = false;
6419    isRunning                     = false;
6420    lockdownMode                  = true;
6421    rejectUnauthenticatedRequests = true;
6422    shuttingDown                  = true;
6423
6424    configClass              = null;
6425    configFile               = null;
6426    configHandler            = null;
6427    coreConfigManager        = null;
6428    compressedSchema         = null;
6429    cryptoManager            = null;
6430    entryCache               = null;
6431    environmentConfig        = null;
6432    objectClassAttributeType = null;
6433    schemaDN                 = null;
6434    shutdownHook             = null;
6435    workQueue                = null;
6436
6437    if (baseDnRegistry != null)
6438    {
6439      baseDnRegistry.clear();
6440      baseDnRegistry = null;
6441    }
6442
6443    if (backends != null)
6444    {
6445      backends.clear();
6446      backends = null;
6447    }
6448
6449    if (schema != null)
6450    {
6451      schema.destroy();
6452      schema = null;
6453    }
6454  }
6455
6456  /**
6457   * Causes the Directory Server to perform an in-core restart.  This will
6458   * cause virtually all components of the Directory Server to shut down, and
6459   * once that has completed it will be restarted.
6460   *
6461   * @param  className  The fully-qualified name of the Java class that
6462   *                    initiated the shutdown.
6463   * @param  reason     The human-readable reason that the directory server is
6464   *                    shutting down.
6465   */
6466  public static void restart(String className, LocalizableMessage reason)
6467  {
6468    restart(className, reason, directoryServer.environmentConfig);
6469  }
6470
6471  /**
6472   * Causes the Directory Server to perform an in-core restart.  This will
6473   * cause virtually all components of the Directory Server to shut down, and
6474   * once that has completed it will be restarted.
6475   *
6476   * @param  className  The fully-qualified name of the Java class that
6477   *                    initiated the shutdown.
6478   * @param  reason     The human-readable reason that the directory server is
6479   *                    shutting down.
6480   * @param  config     The environment configuration to use for the server.
6481   */
6482  public static void restart(String className, LocalizableMessage reason,
6483                             DirectoryEnvironmentConfig config)
6484  {
6485    try
6486    {
6487      shutDown(className, reason);
6488      reinitialize(config);
6489      directoryServer.startServer();
6490    }
6491    catch (Exception e)
6492    {
6493      System.err.println("ERROR:  Unable to perform an in-core restart:");
6494      e.printStackTrace();
6495      System.err.println("Halting the JVM so that it must be manually " +
6496                         "restarted.");
6497
6498      Runtime.getRuntime().halt(1);
6499    }
6500  }
6501
6502  /**
6503   * Reinitializes the server following a shutdown, preparing it for a call to
6504   * {@code startServer}.
6505   *
6506   * @return  The new Directory Server instance created during the
6507   *          re-initialization process.
6508   *
6509   * @throws  InitializationException  If a problem occurs while trying to
6510   *                                   initialize the config handler or
6511   *                                   bootstrap that server.
6512   */
6513  public static DirectoryServer reinitialize()
6514         throws InitializationException
6515  {
6516    return reinitialize(directoryServer.environmentConfig);
6517  }
6518
6519  /**
6520   * Reinitializes the server following a shutdown, preparing it for a call to
6521   * {@code startServer}.
6522   *
6523   * @param  config  The environment configuration for the Directory Server.
6524   *
6525   * @return  The new Directory Server instance created during the
6526   *          re-initialization process.
6527   *
6528   * @throws  InitializationException  If a problem occurs while trying to
6529   *                                   initialize the config handler or
6530   *                                   bootstrap that server.
6531   */
6532  public static DirectoryServer reinitialize(DirectoryEnvironmentConfig config)
6533         throws InitializationException
6534  {
6535    // Ensure that the timer thread has started.
6536    TimeThread.start();
6537
6538    getNewInstance(config);
6539    directoryServer.bootstrapServer();
6540    directoryServer.initializeConfiguration();
6541    return directoryServer;
6542  }
6543
6544  /**
6545   * Retrieves the maximum number of concurrent client connections that may be
6546   * established.
6547   *
6548   * @return  The maximum number of concurrent client connections that may be
6549   *          established, or -1 if there is no limit.
6550   */
6551  public static long getMaxAllowedConnections()
6552  {
6553    return directoryServer.maxAllowedConnections;
6554  }
6555
6556  /**
6557   * Specifies the maximum number of concurrent client connections that may be
6558   * established.  A value that is less than or equal to zero will indicate that
6559   * no limit should be enforced.
6560   *
6561   * @param  maxAllowedConnections  The maximum number of concurrent client
6562   *                                connections that may be established.
6563   */
6564  public static void setMaxAllowedConnections(long maxAllowedConnections)
6565  {
6566    if (maxAllowedConnections > 0)
6567    {
6568      directoryServer.maxAllowedConnections = maxAllowedConnections;
6569    }
6570    else
6571    {
6572      directoryServer.maxAllowedConnections = -1;
6573    }
6574  }
6575
6576  /**
6577   * Indicates that a new connection has been accepted and increments the
6578   * associated counters.
6579   *
6580   * @param  clientConnection  The client connection that has been established.
6581   *
6582   * @return  The connection ID that should be used for this connection, or -1
6583   *          if the connection has been rejected for some reason (e.g., the
6584   *          maximum number of concurrent connections have already been
6585   *          established).
6586   */
6587  public static long newConnectionAccepted(ClientConnection clientConnection)
6588  {
6589    synchronized (directoryServer.establishedConnections)
6590    {
6591      if (directoryServer.lockdownMode)
6592      {
6593        InetAddress remoteAddress = clientConnection.getRemoteAddress();
6594        if (remoteAddress != null && !remoteAddress.isLoopbackAddress())
6595        {
6596          return -1;
6597        }
6598      }
6599
6600      final long maxAllowed = directoryServer.maxAllowedConnections;
6601      if (0 < maxAllowed && maxAllowed <= directoryServer.currentConnections)
6602      {
6603        return -1;
6604      }
6605
6606      directoryServer.establishedConnections.add(clientConnection);
6607      directoryServer.currentConnections++;
6608
6609      if (directoryServer.currentConnections > directoryServer.maxConnections)
6610      {
6611        directoryServer.maxConnections = directoryServer.currentConnections;
6612      }
6613
6614      return directoryServer.totalConnections++;
6615    }
6616  }
6617
6618  /**
6619   * Indicates that the specified client connection has been closed.
6620   *
6621   * @param  clientConnection  The client connection that has been closed.
6622   */
6623  public static void connectionClosed(ClientConnection clientConnection)
6624  {
6625    synchronized (directoryServer.establishedConnections)
6626    {
6627      directoryServer.establishedConnections.remove(clientConnection);
6628      directoryServer.currentConnections--;
6629    }
6630  }
6631
6632  /**
6633   * Retrieves the number of client connections that are currently established.
6634   *
6635   * @return  The number of client connections that are currently established.
6636   */
6637  public static long getCurrentConnections()
6638  {
6639    return directoryServer.currentConnections;
6640  }
6641
6642  /**
6643   * Retrieves the maximum number of client connections that have been
6644   * established concurrently.
6645   *
6646   * @return  The maximum number of client connections that have been
6647   *          established concurrently.
6648   */
6649  public static long getMaxConnections()
6650  {
6651    return directoryServer.maxConnections;
6652  }
6653
6654  /**
6655   * Retrieves the total number of client connections that have been established
6656   * since the Directory Server started.
6657   *
6658   * @return  The total number of client connections that have been established
6659   *          since the Directory Server started.
6660   */
6661  public static long getTotalConnections()
6662  {
6663    return directoryServer.totalConnections;
6664  }
6665
6666  /**
6667   * Retrieves the full version string for the Directory Server.
6668   *
6669   * @return  The full version string for the Directory Server.
6670   */
6671  public static String getVersionString()
6672  {
6673    return FULL_VERSION_STRING;
6674  }
6675
6676  /**
6677   * Prints out the version string for the Directory Server.
6678   *
6679   *
6680   * @param  outputStream  The output stream to which the version information
6681   *                       should be written.
6682   *
6683   * @throws  IOException  If a problem occurs while attempting to write the
6684   *                       version information to the provided output stream.
6685   */
6686  public static void printVersion(OutputStream outputStream)
6687  throws IOException
6688  {
6689    outputStream.write(PRINTABLE_VERSION_STRING.getBytes());
6690
6691    // Print extensions' extra information
6692    String extensionInformation =
6693         ClassLoaderProvider.getInstance().printExtensionInformation();
6694    if ( extensionInformation != null ) {
6695      outputStream.write(extensionInformation.getBytes());
6696    }
6697  }
6698
6699  /**
6700   * Retrieves the default maximum number of entries that should be returned for
6701   * a search.
6702   *
6703   * @return  The default maximum number of entries that should be returned for
6704   *          a search.
6705   */
6706  public static int getSizeLimit()
6707  {
6708    return directoryServer.sizeLimit;
6709  }
6710
6711  /**
6712   * Specifies the default maximum number of entries that should be returned for
6713   * a search.
6714   *
6715   * @param  sizeLimit  The default maximum number of entries that should be
6716   *                    returned for a search.
6717   */
6718  public static void setSizeLimit(int sizeLimit)
6719  {
6720    directoryServer.sizeLimit = sizeLimit;
6721  }
6722
6723  /**
6724   * Retrieves the default maximum number of entries that should checked for
6725   * matches during a search.
6726   *
6727   * @return  The default maximum number of entries that should checked for
6728   *          matches during a search.
6729   */
6730  public static int getLookthroughLimit()
6731  {
6732    return directoryServer.lookthroughLimit;
6733  }
6734
6735  /**
6736   * Specifies the default maximum number of entries that should be checked for
6737   * matches during a search.
6738   *
6739   * @param  lookthroughLimit  The default maximum number of entries that should
6740   *                           be check for matches during a search.
6741   */
6742  public static void setLookthroughLimit(int lookthroughLimit)
6743  {
6744    directoryServer.lookthroughLimit = lookthroughLimit;
6745  }
6746
6747  /**
6748   * Specifies the maximum number of simultaneous persistent
6749   * searches that are allowed.
6750   *
6751   * @param maxPSearches   The maximum number of simultaneous persistent
6752  *                      searches that are allowed.
6753   */
6754  public static void setMaxPersistentSearchLimit(int maxPSearches)
6755  {
6756    directoryServer.maxPSearches = maxPSearches;
6757  }
6758
6759  /**
6760   *  Registers a new persistent search by increasing the count
6761   *  of active persistent searches. After receiving a persistent
6762   *  search request, a Local or Remote WFE must call this method to
6763   *  let the core server manage the count of concurrent persistent
6764   *  searches.
6765   */
6766  public static void registerPersistentSearch()
6767  {
6768    directoryServer.activePSearches.incrementAndGet();
6769  }
6770
6771  /**
6772   * Deregisters a canceled persistent search.  After a persistent
6773   * search is canceled, the handler must call this method to let
6774   * the core server manage the count of concurrent persistent
6775   *  searches.
6776   */
6777  public static void deregisterPersistentSearch()
6778  {
6779    directoryServer.activePSearches.decrementAndGet();
6780  }
6781
6782  /**
6783   * Indicates whether a new persistent search is allowed.
6784   *
6785   * @return <CODE>true</CODE>if a new persistent search is allowed
6786   *          or <CODE>false</CODE>f if not.
6787   */
6788  public static boolean allowNewPersistentSearch()
6789  {
6790    //-1 indicates that there is no limit.
6791    return directoryServer.maxPSearches == -1
6792        || directoryServer.activePSearches.get() < directoryServer.maxPSearches;
6793  }
6794
6795  /**
6796   * Retrieves the default maximum length of time in seconds that should be
6797   * allowed when processing a search.
6798   *
6799   * @return  The default maximum length of time in seconds that should be
6800   *          allowed when processing a search.
6801   */
6802  public static int getTimeLimit()
6803  {
6804    return directoryServer.timeLimit;
6805  }
6806
6807  /**
6808   * Specifies the default maximum length of time in seconds that should be
6809   * allowed when processing a search.
6810   *
6811   * @param  timeLimit  The default maximum length of time in seconds that
6812   *                    should be allowed when processing a search.
6813   */
6814  public static void setTimeLimit(int timeLimit)
6815  {
6816    directoryServer.timeLimit = timeLimit;
6817  }
6818
6819  /**
6820   * Specifies whether to collect nanosecond resolution processing times for
6821   * operations.
6822   *
6823   * @param useNanoTime  <code>true</code> if nanosecond resolution times
6824   *                     should be collected or <code>false</code> to
6825   *                     only collect in millisecond resolution.
6826   */
6827  public static void setUseNanoTime(boolean useNanoTime)
6828  {
6829    directoryServer.useNanoTime = useNanoTime;
6830  }
6831
6832  /**
6833   * Retrieves whether operation processing times should be collected with
6834   * nanosecond resolution.
6835   *
6836   * @return  <code>true</code> if nanosecond resolution times are collected
6837   *          or <code>false</code> if only millisecond resolution times are
6838   *          being collected.
6839   */
6840  public static boolean getUseNanoTime()
6841  {
6842    return directoryServer.useNanoTime;
6843  }
6844
6845  /**
6846   * Retrieves the writability mode for the Directory Server.  This will only
6847   * be applicable for user suffixes.
6848   *
6849   * @return  The writability mode for the Directory Server.
6850   */
6851  public static WritabilityMode getWritabilityMode()
6852  {
6853    return directoryServer.writabilityMode;
6854  }
6855
6856  /**
6857   * Specifies the writability mode for the Directory Server.  This will only
6858   * be applicable for user suffixes.
6859   *
6860   * @param writabilityMode  Specifies the writability mode for the Directory
6861   *                         Server.
6862   */
6863  public static void setWritabilityMode(WritabilityMode writabilityMode)
6864  {
6865    directoryServer.writabilityMode = writabilityMode;
6866  }
6867
6868  /**
6869   * Indicates whether simple bind requests that contain a bind DN will also be
6870   * required to have a password.
6871   *
6872   * @return  <CODE>true</CODE> if simple bind requests containing a bind DN
6873   *          will be required to have a password, or <CODE>false</CODE> if not
6874   *          (and therefore will be treated as anonymous binds).
6875   */
6876  public static boolean bindWithDNRequiresPassword()
6877  {
6878    return directoryServer.bindWithDNRequiresPassword;
6879  }
6880
6881  /**
6882   * Specifies whether simple bind requests that contain a bind DN will also be
6883   * required to have a password.
6884   *
6885   * @param  bindWithDNRequiresPassword  Indicates whether simple bind requests
6886   *                                     that contain a bind DN will also be
6887   *                                     required to have a password.
6888   */
6889  public static void setBindWithDNRequiresPassword(boolean
6890                          bindWithDNRequiresPassword)
6891  {
6892    directoryServer.bindWithDNRequiresPassword = bindWithDNRequiresPassword;
6893  }
6894
6895  /**
6896   * Indicates whether an unauthenticated request should be rejected.
6897   *
6898   * @return <CODE>true</CODE>if an unauthenticated request should be
6899   *         rejected, or <CODE>false</CODE>f if not.
6900   */
6901  public static boolean rejectUnauthenticatedRequests()
6902  {
6903     return directoryServer.rejectUnauthenticatedRequests;
6904  }
6905
6906  /**
6907   * Specifies whether an unauthenticated request should be rejected.
6908   *
6909   * @param  rejectUnauthenticatedRequests   Indicates whether an
6910   *                                        unauthenticated request should
6911   *                                        be rejected.
6912   */
6913  public static void setRejectUnauthenticatedRequests(boolean
6914                          rejectUnauthenticatedRequests)
6915  {
6916        directoryServer.rejectUnauthenticatedRequests =
6917                                  rejectUnauthenticatedRequests;
6918  }
6919
6920  /**
6921   * Indicates whether the Directory Server is currently configured to operate
6922   * in the lockdown mode, in which all non-root requests will be rejected and
6923   * all connection attempts from non-loopback clients will be rejected.
6924   *
6925   * @return  {@code true} if the Directory Server is currently configured to
6926   *          operate in the lockdown mode, or {@code false} if not.
6927   */
6928  public static boolean lockdownMode()
6929  {
6930    return directoryServer.lockdownMode;
6931  }
6932
6933  /**
6934   * Specifies whether the server should operate in lockdown mode.
6935   *
6936   * @param  lockdownMode  Indicates whether the Directory Server should operate
6937   *                       in lockdown mode.
6938   */
6939  public static void setLockdownMode(boolean lockdownMode)
6940  {
6941    directoryServer.lockdownMode = lockdownMode;
6942
6943    if (lockdownMode)
6944    {
6945      LocalizableMessage message = WARN_DIRECTORY_SERVER_ENTERING_LOCKDOWN_MODE.get();
6946      logger.warn(message);
6947
6948      sendAlertNotification(directoryServer, ALERT_TYPE_ENTERING_LOCKDOWN_MODE,
6949              message);
6950    }
6951    else
6952    {
6953      LocalizableMessage message = NOTE_DIRECTORY_SERVER_LEAVING_LOCKDOWN_MODE.get();
6954      logger.info(message);
6955
6956      sendAlertNotification(directoryServer, ALERT_TYPE_LEAVING_LOCKDOWN_MODE,
6957              message);
6958    }
6959  }
6960
6961  /**
6962   * Sets the message to be displayed on the command-line when the user asks for
6963   * the usage.
6964   * @param msg the message to be displayed on the command-line when the user
6965   * asks for the usage.
6966   */
6967  public static void setToolDescription (LocalizableMessage msg)
6968  {
6969    toolDescription = msg;
6970  }
6971
6972  /**
6973   * Retrieves the DN of the configuration entry with which this alert generator
6974   * is associated.
6975   *
6976   * @return  The DN of the configuration entry with which this alert generator
6977   *          is associated.
6978   */
6979  @Override
6980  public DN getComponentEntryDN()
6981  {
6982    try
6983    {
6984      if (configHandler == null)
6985      {
6986        // The config handler hasn't been initialized yet.  Just return the DN
6987        // of the root DSE.
6988        return DN.rootDN();
6989      }
6990
6991      return configHandler.getConfigRootEntry().getDN();
6992    }
6993    catch (Exception e)
6994    {
6995      logger.traceException(e);
6996
6997      // This could theoretically happen if an alert needs to be sent before the
6998      // configuration is initialized.  In that case, just return an empty DN.
6999      return DN.rootDN();
7000    }
7001  }
7002
7003  /**
7004   * Retrieves the fully-qualified name of the Java class for this alert
7005   * generator implementation.
7006   *
7007   * @return  The fully-qualified name of the Java class for this alert
7008   *          generator implementation.
7009   */
7010  @Override
7011  public String getClassName()
7012  {
7013    return DirectoryServer.class.getName();
7014  }
7015
7016  /**
7017   * Retrieves information about the set of alerts that this generator may
7018   * produce.  The map returned should be between the notification type for a
7019   * particular notification and the human-readable description for that
7020   * notification.  This alert generator must not generate any alerts with types
7021   * that are not contained in this list.
7022   *
7023   * @return  Information about the set of alerts that this generator may
7024   *          produce.
7025   */
7026  @Override
7027  public Map<String, String> getAlerts()
7028  {
7029    Map<String, String> alerts = new LinkedHashMap<>();
7030
7031    alerts.put(ALERT_TYPE_SERVER_STARTED, ALERT_DESCRIPTION_SERVER_STARTED);
7032    alerts.put(ALERT_TYPE_SERVER_SHUTDOWN, ALERT_DESCRIPTION_SERVER_SHUTDOWN);
7033    alerts.put(ALERT_TYPE_ENTERING_LOCKDOWN_MODE,
7034               ALERT_DESCRIPTION_ENTERING_LOCKDOWN_MODE);
7035    alerts.put(ALERT_TYPE_LEAVING_LOCKDOWN_MODE,
7036               ALERT_DESCRIPTION_LEAVING_LOCKDOWN_MODE);
7037
7038    return alerts;
7039  }
7040
7041  /**
7042   * Indicates whether the server is currently in the process of shutting down.
7043   * @return <CODE>true</CODE> if this server is currently in the process of
7044   * shutting down and <CODE>false</CODE> otherwise.
7045   */
7046  public boolean isShuttingDown()
7047  {
7048    return shuttingDown;
7049  }
7050
7051  /**
7052   * Parses the provided command-line arguments and uses that information to
7053   * bootstrap and start the Directory Server.
7054   *
7055   * @param  args  The command-line arguments provided to this program.
7056   */
7057  public static void main(String[] args)
7058  {
7059    // Define the arguments that may be provided to the server.
7060    BooleanArgument checkStartability      = null;
7061    BooleanArgument quietMode              = null;
7062    IntegerArgument timeout                = null;
7063    BooleanArgument windowsNetStart        = null;
7064    BooleanArgument displayUsage           = null;
7065    BooleanArgument fullVersion            = null;
7066    BooleanArgument noDetach               = null;
7067    BooleanArgument systemInfo             = null;
7068    BooleanArgument useLastKnownGoodConfig = null;
7069    StringArgument  configClass            = null;
7070    StringArgument  configFile             = null;
7071
7072    // Create the command-line argument parser for use with this program.
7073    LocalizableMessage theToolDescription = DirectoryServer.toolDescription;
7074    ArgumentParser argParser =
7075         new ArgumentParser("org.opends.server.core.DirectoryServer",
7076                            theToolDescription, false);
7077    argParser.setShortToolDescription(REF_SHORT_DESC_START_DS.get());
7078
7079    // Initialize all the command-line argument types and register them with the
7080    // parser.
7081    try
7082    {
7083      configClass = new StringArgument("configclass", 'C', "configClass",
7084                                       true, false, true,
7085                                       INFO_CONFIGCLASS_PLACEHOLDER.get(),
7086                                       ConfigFileHandler.class.getName(), null,
7087                                       INFO_DSCORE_DESCRIPTION_CONFIG_CLASS.get());
7088      configClass.setHidden(true);
7089      argParser.addArgument(configClass);
7090
7091      configFile = new StringArgument("configfile", 'f', "configFile",
7092                                      true, false, true,
7093                                      INFO_CONFIGFILE_PLACEHOLDER.get(), null,
7094                                      null,
7095                                      INFO_DSCORE_DESCRIPTION_CONFIG_FILE.get());
7096      configFile.setHidden(true);
7097      argParser.addArgument(configFile);
7098
7099      checkStartability = new BooleanArgument("checkstartability", null,
7100                              "checkStartability",
7101                              INFO_DSCORE_DESCRIPTION_CHECK_STARTABILITY.get());
7102      checkStartability.setHidden(true);
7103      argParser.addArgument(checkStartability);
7104
7105      windowsNetStart = new BooleanArgument("windowsnetstart", null, "windowsNetStart",
7106                              INFO_DSCORE_DESCRIPTION_WINDOWS_NET_START.get());
7107      windowsNetStart.setHidden(true);
7108      argParser.addArgument(windowsNetStart);
7109
7110      fullVersion = new BooleanArgument("fullversion", 'F', "fullVersion",
7111                                        INFO_DSCORE_DESCRIPTION_FULLVERSION.get());
7112      fullVersion.setHidden(true);
7113      argParser.addArgument(fullVersion);
7114
7115      systemInfo = new BooleanArgument("systeminfo", 's', "systemInfo",
7116                                       INFO_DSCORE_DESCRIPTION_SYSINFO.get());
7117      argParser.addArgument(systemInfo);
7118
7119      useLastKnownGoodConfig =
7120           new BooleanArgument("lastknowngoodconfig", 'L',
7121                               "useLastKnownGoodConfig",
7122                               INFO_DSCORE_DESCRIPTION_LASTKNOWNGOODCFG.get());
7123      argParser.addArgument(useLastKnownGoodConfig);
7124
7125      noDetach = new BooleanArgument("nodetach", 'N', "nodetach",
7126                                     INFO_DSCORE_DESCRIPTION_NODETACH.get());
7127      argParser.addArgument(noDetach);
7128
7129      quietMode = CommonArguments.getQuiet();
7130      argParser.addArgument(quietMode);
7131
7132      // Not used in this class, but required by the start-ds script
7133      // (see issue #3814)
7134      timeout = new IntegerArgument("timeout", 't', "timeout", true, false,
7135                                    true, INFO_SECONDS_PLACEHOLDER.get(),
7136                                    DEFAULT_TIMEOUT,
7137                                    null, true, 0, false,
7138                                    0, INFO_DSCORE_DESCRIPTION_TIMEOUT.get());
7139      argParser.addArgument(timeout);
7140
7141      displayUsage = CommonArguments.getShowUsage();
7142      argParser.addArgument(displayUsage);
7143      argParser.setUsageArgument(displayUsage);
7144      argParser.setVersionHandler(new DirectoryServerVersionHandler());
7145    }
7146    catch (ArgumentException ae)
7147    {
7148      LocalizableMessage message = ERR_DSCORE_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
7149      System.err.println(message);
7150      System.exit(1);
7151    }
7152
7153    // Parse the command-line arguments provided to this program.
7154    try
7155    {
7156      argParser.parseArguments(args);
7157    }
7158    catch (ArgumentException ae)
7159    {
7160      argParser.displayMessageAndUsageReference(System.err, ERR_DSCORE_ERROR_PARSING_ARGS.get(ae.getMessage()));
7161      System.exit(1);
7162    }
7163
7164    // If we should just display usage information, then print it and exit.
7165    if (checkStartability.isPresent())
7166    {
7167      // This option should only be used if a PID file already exists in the
7168      // server logs directory, and we need to check which of the following
7169      // conditions best describes the current usage:
7170      // - We're trying to start the server, but it's already running.  The
7171      //   attempt to start the server should fail, and the server process will
7172      //   exit with a result code of 98.
7173      // - We're trying to start the server and it's not already running.  We
7174      //   won't start it in this invocation, but the script used to get to this
7175      //   point should go ahead and overwrite the PID file and retry the
7176      //   startup process.  The server process will exit with a result code of
7177      //   99.
7178      // - We're not trying to start the server, but instead are trying to do
7179      //   something else like display the version number.  In that case, we
7180      //   don't need to write the PID file at all and can just execute the
7181      //   intended command.  If that command was successful, then we'll have an
7182      //   exit code of NOTHING_TO_DO (0).  Otherwise, it will have an exit code
7183      //   that is something other than NOTHING_TO_DO, SERVER_ALREADY_STARTED,
7184      //   START_AS_DETACH, START_AS_NON_DETACH, START_AS_WINDOWS_SERVICE,
7185      //   START_AS_DETACH_QUIET, START_AS_NON_DETACH_QUIET to indicate that a
7186      //   problem occurred.
7187      if (argParser.usageOrVersionDisplayed())
7188      {
7189        // We're just trying to display usage, and that's already been done so
7190        // exit with a code of zero.
7191        System.exit(NOTHING_TO_DO);
7192      }
7193      else if (fullVersion.isPresent() || systemInfo.isPresent())
7194      {
7195        // We're not really trying to start, so rebuild the argument list
7196        // without the "--checkStartability" argument and try again.  Exit with
7197        // whatever that exits with.
7198        List<String> newArgList = new LinkedList<>();
7199        for (String arg : args)
7200        {
7201          if (!"--checkstartability".equalsIgnoreCase(arg))
7202          {
7203            newArgList.add(arg);
7204          }
7205        }
7206        String[] newArgs = new String[newArgList.size()];
7207        newArgList.toArray(newArgs);
7208        main(newArgs);
7209        System.exit(NOTHING_TO_DO);
7210      }
7211      else
7212      {
7213        System.exit(checkStartability(argParser));
7214      }
7215    }
7216    else if (argParser.usageOrVersionDisplayed())
7217    {
7218      System.exit(0);
7219    }
7220    else if (fullVersion.isPresent())
7221    {
7222      printFullVersionInformation();
7223      return;
7224    }
7225    else if (systemInfo.isPresent())
7226    {
7227      RuntimeInformation.printInfo();
7228      return;
7229    }
7230    else if (noDetach.isPresent() && timeout.isPresent()) {
7231      argParser.displayMessageAndUsageReference(System.err, ERR_DSCORE_ERROR_NODETACH_TIMEOUT.get());
7232      System.exit(1);
7233    }
7234
7235    // At this point, we know that we're going to try to start the server.
7236    // Attempt to grab an exclusive lock for the Directory Server process.
7237    String lockFile = LockFileManager.getServerLockFileName();
7238    try
7239    {
7240      StringBuilder failureReason = new StringBuilder();
7241      if (! LockFileManager.acquireExclusiveLock(lockFile, failureReason))
7242      {
7243        System.err.println(ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(lockFile, failureReason));
7244        System.exit(1);
7245      }
7246    }
7247    catch (Exception e)
7248    {
7249      logger.traceException(e);
7250
7251      System.err.println(ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(
7252          lockFile, stackTraceToSingleLineString(e)));
7253      System.exit(1);
7254    }
7255    serverLocked = true;
7256
7257    // Create an environment configuration for the server and populate a number
7258    // of appropriate properties.
7259    DirectoryEnvironmentConfig environmentConfig = new DirectoryEnvironmentConfig();
7260    try
7261    {
7262      environmentConfig.setProperty(PROPERTY_CONFIG_CLASS, configClass.getValue());
7263      environmentConfig.setProperty(PROPERTY_CONFIG_FILE, configFile.getValue());
7264      environmentConfig.setProperty(PROPERTY_USE_LAST_KNOWN_GOOD_CONFIG,
7265          String.valueOf(useLastKnownGoodConfig.isPresent()));
7266    }
7267    catch (Exception e)
7268    {
7269      // This shouldn't happen.  For the methods we are using, the exception is
7270      // just a guard against making changes with the server running.
7271      System.err.println("WARNING:  Unable to set environment properties in environment config : "
7272          + stackTraceToSingleLineString(e));
7273    }
7274
7275    // Configure the JVM to delete the PID file on exit, if it exists.
7276    boolean pidFileMarkedForDeletion      = false;
7277    boolean startingFileMarkedForDeletion = false;
7278    try
7279    {
7280      String pidFilePath;
7281      String startingFilePath;
7282      File instanceRoot = environmentConfig.getInstanceRoot();
7283      if (instanceRoot == null)
7284      {
7285        pidFilePath      = "logs/server.pid";
7286        startingFilePath = "logs/server.starting";
7287      }
7288      else
7289      {
7290        pidFilePath = instanceRoot.getAbsolutePath() + File.separator + "logs"
7291            + File.separator + "server.pid";
7292        startingFilePath = instanceRoot.getAbsolutePath() + File.separator
7293            + "logs" + File.separator + "server.starting";
7294      }
7295
7296      File pidFile = new File(pidFilePath);
7297      if (pidFile.exists())
7298      {
7299        pidFile.deleteOnExit();
7300        pidFileMarkedForDeletion = true;
7301      }
7302
7303      File startingFile = new File(startingFilePath);
7304      if (startingFile.exists())
7305      {
7306        startingFile.deleteOnExit();
7307        startingFileMarkedForDeletion = true;
7308      }
7309    } catch (Exception e) {}
7310
7311    // Redirect standard output and standard error to the server.out file.  If
7312    // the server hasn't detached from the terminal, then also continue writing
7313    // to the original standard output and standard error.  Also, configure the
7314    // JVM to delete the PID and server.starting files on exit, if they exist.
7315    PrintStream serverOutStream;
7316    try
7317    {
7318      File serverRoot = environmentConfig.getServerRoot();
7319      if (serverRoot == null)
7320      {
7321        System.err.println("WARNING:  Unable to determine server root in " +
7322            "order to redirect standard output and standard error.");
7323      }
7324      else
7325      {
7326        File instanceRoot = environmentConfig.getInstanceRoot();
7327        File logDir = new File(instanceRoot.getAbsolutePath() + File.separator
7328            + "logs");
7329        if (logDir.exists())
7330        {
7331          FileOutputStream fos =
7332               new FileOutputStream(new File(logDir, "server.out"), true);
7333          serverOutStream = new PrintStream(fos);
7334
7335          if (noDetach.isPresent() && !quietMode.isPresent())
7336          {
7337            MultiOutputStream multiStream =
7338                new MultiOutputStream(System.out, serverOutStream);
7339            serverOutStream = new PrintStream(multiStream);
7340          }
7341
7342          System.setOut(serverOutStream);
7343          System.setErr(serverOutStream);
7344
7345          if (! pidFileMarkedForDeletion)
7346          {
7347            File f = new File(logDir, "server.pid");
7348            if (f.exists())
7349            {
7350              f.deleteOnExit();
7351            }
7352          }
7353
7354          if (! startingFileMarkedForDeletion)
7355          {
7356            File f = new File(logDir, "server.starting");
7357            if (f.exists())
7358            {
7359              f.deleteOnExit();
7360            }
7361          }
7362        }
7363        else
7364        {
7365          System.err.println("WARNING:  Unable to redirect standard output " +
7366                             "and standard error because the logs directory " +
7367                             logDir.getAbsolutePath() + " does not exist.");
7368        }
7369      }
7370    }
7371    catch (Exception e)
7372    {
7373      System.err.println("WARNING:  Unable to redirect standard output and " +
7374                         "standard error:  " + stackTraceToSingleLineString(e));
7375    }
7376
7377    // Install the default loggers so the startup messages
7378    // will be printed.
7379    ErrorLogPublisher startupErrorLogPublisher =
7380        TextErrorLogPublisher.getServerStartupTextErrorPublisher(new TextWriter.STDOUT());
7381    ErrorLogger.getInstance().addLogPublisher(startupErrorLogPublisher);
7382
7383    DebugLogPublisher startupDebugLogPublisher =
7384        DebugLogger.getInstance().addPublisherIfRequired(new TextWriter.STDOUT());
7385
7386    // Bootstrap and start the Directory Server.
7387    DirectoryServer theDirectoryServer = DirectoryServer.getInstance();
7388    try
7389    {
7390      theDirectoryServer.setEnvironmentConfig(environmentConfig);
7391      theDirectoryServer.bootstrapServer();
7392      theDirectoryServer.initializeConfiguration(configClass.getValue(),
7393          configFile.getValue());
7394    }
7395    catch (InitializationException ie)
7396    {
7397      logger.traceException(ie);
7398
7399      LocalizableMessage message = ERR_DSCORE_CANNOT_BOOTSTRAP.get(ie.getMessage());
7400      System.err.println(message);
7401      System.exit(1);
7402    }
7403    catch (Exception e)
7404    {
7405      LocalizableMessage message = ERR_DSCORE_CANNOT_BOOTSTRAP.get(
7406              stackTraceToSingleLineString(e));
7407      System.err.println(message);
7408      System.exit(1);
7409    }
7410
7411    try
7412    {
7413      theDirectoryServer.startServer();
7414    }
7415    catch (InitializationException ie)
7416    {
7417      logger.traceException(ie);
7418
7419      LocalizableMessage message = ERR_DSCORE_CANNOT_START.get(ie.getMessage());
7420      shutDown(theDirectoryServer.getClass().getName(), message);
7421    }
7422    catch (ConfigException ce)
7423    {
7424      logger.traceException(ce);
7425
7426      LocalizableMessage message = ERR_DSCORE_CANNOT_START.get(ce.getMessage() +
7427      (ce.getCause() != null ? " " + ce.getCause().getLocalizedMessage() : ""));
7428      shutDown(theDirectoryServer.getClass().getName(), message);
7429    }
7430    catch (Exception e)
7431    {
7432      LocalizableMessage message = ERR_DSCORE_CANNOT_START.get(
7433              stackTraceToSingleLineString(e));
7434      shutDown(theDirectoryServer.getClass().getName(), message);
7435    }
7436
7437    ErrorLogger.getInstance().removeLogPublisher(startupErrorLogPublisher);
7438    if (startupDebugLogPublisher != null)
7439    {
7440      DebugLogger.getInstance().removeLogPublisher(startupDebugLogPublisher);
7441    }
7442  }
7443
7444  /**
7445   * Construct the DN of a monitor provider entry.
7446   * @param provider The monitor provider for which a DN is desired.
7447   * @return The DN of the monitor provider entry.
7448   */
7449  public static DN getMonitorProviderDN(MonitorProvider provider)
7450  {
7451    String monitorName = provider.getMonitorInstanceName();
7452    try
7453    {
7454      // Get a complete DN which could be a tree naming schema
7455      return DN.valueOf("cn="+monitorName+","+DN_MONITOR_ROOT);
7456    }
7457    catch (DirectoryException e)
7458    {
7459      // Cannot reach this point.
7460      throw new RuntimeException();
7461    }
7462  }
7463
7464  /**
7465   * Gets the class loader to be used with this directory server
7466   * application.
7467   * <p>
7468   * The class loader will automatically load classes from plugins
7469   * where required.
7470   *
7471   * @return Returns the class loader to be used with this directory
7472   *         server application.
7473   */
7474  public static ClassLoader getClassLoader()
7475  {
7476    return ClassLoaderProvider.getInstance().getClassLoader();
7477  }
7478
7479  /**
7480   * Loads the named class using this directory server application's
7481   * class loader.
7482   * <p>
7483   * This method provided as a convenience and is equivalent to
7484   * calling:
7485   *
7486   * <pre>
7487   * Class.forName(name, true, DirectoryServer.getClassLoader());
7488   * </pre>
7489   *
7490   * @param name
7491   *          The fully qualified name of the desired class.
7492   * @return Returns the class object representing the desired class.
7493   * @throws LinkageError
7494   *           If the linkage fails.
7495   * @throws ExceptionInInitializerError
7496   *           If the initialization provoked by this method fails.
7497   * @throws ClassNotFoundException
7498   *           If the class cannot be located by the specified class
7499   *           loader.
7500   * @see Class#forName(String, boolean, ClassLoader)
7501   */
7502  public static Class<?> loadClass(String name) throws LinkageError,
7503      ExceptionInInitializerError, ClassNotFoundException
7504  {
7505    return Class.forName(name, true, DirectoryServer.getClassLoader());
7506  }
7507
7508  /**
7509   * Returns the error code that we return when we are checking the startability
7510   * of the server.
7511   * If there are conflicting arguments (like asking to run the server in non
7512   * detach mode when the server is configured to run as a window service) it
7513   * returns CHECK_ERROR (1).
7514   * @param argParser the ArgumentParser with the arguments already parsed.
7515   * @return the error code that we return when we are checking the startability
7516   * of the server.
7517   */
7518  private static int checkStartability(ArgumentParser argParser)
7519  {
7520    int returnValue;
7521    boolean isServerRunning;
7522
7523    BooleanArgument noDetach =
7524      (BooleanArgument)argParser.getArgumentForLongID("nodetach");
7525    BooleanArgument quietMode =
7526      (BooleanArgument)argParser.getArgumentForLongID(ArgumentConstants.OPTION_LONG_QUIET);
7527    BooleanArgument windowsNetStart =
7528      (BooleanArgument)argParser.getArgumentForLongID("windowsnetstart");
7529
7530    boolean noDetachPresent = noDetach.isPresent();
7531    boolean windowsNetStartPresent = windowsNetStart.isPresent();
7532
7533    // We're trying to start the server, so see if it's already running by
7534    // trying to grab an exclusive lock on the server lock file.  If it
7535    // succeeds, then the server isn't running and we can try to start.
7536    // Otherwise, the server is running and this attempt should fail.
7537    String lockFile = LockFileManager.getServerLockFileName();
7538    try
7539    {
7540      StringBuilder failureReason = new StringBuilder();
7541      if (LockFileManager.acquireExclusiveLock(lockFile, failureReason))
7542      {
7543        // The server isn't running, so it can be started.
7544        LockFileManager.releaseLock(lockFile, failureReason);
7545        isServerRunning = false;
7546      }
7547      else
7548      {
7549        // The server's already running.
7550        System.err.println(ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(lockFile, failureReason));
7551        isServerRunning = true;
7552      }
7553    }
7554    catch (Exception e)
7555    {
7556      // We'll treat this as if the server is running because we won't
7557      // be able to start it anyway.
7558      LocalizableMessage message = ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(lockFile,
7559          getExceptionMessage(e));
7560      System.err.println(message);
7561      isServerRunning = true;
7562    }
7563
7564    boolean configuredAsService = isRunningAsWindowsService();
7565
7566    if (isServerRunning)
7567    {
7568      if (configuredAsService && !windowsNetStartPresent)
7569      {
7570        returnValue = START_AS_WINDOWS_SERVICE;
7571      }
7572      else
7573      {
7574        returnValue = SERVER_ALREADY_STARTED;
7575      }
7576    }
7577    else
7578    {
7579      if (configuredAsService)
7580      {
7581        if (noDetachPresent)
7582        {
7583          // Conflicting arguments
7584          returnValue = CHECK_ERROR;
7585          LocalizableMessage message = ERR_DSCORE_ERROR_NODETACH_AND_WINDOW_SERVICE.get();
7586          System.err.println(message);
7587
7588        }
7589        else
7590        {
7591          if (windowsNetStartPresent)
7592          {
7593            // start-ds.bat is being called through net start, so return
7594            // START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE so that the batch
7595            // file actually starts the server.
7596            returnValue = START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE;
7597          }
7598          else
7599          {
7600            returnValue = START_AS_WINDOWS_SERVICE;
7601          }
7602        }
7603      }
7604      else
7605      {
7606        if (noDetachPresent)
7607        {
7608          if (quietMode.isPresent())
7609          {
7610            returnValue = START_AS_NON_DETACH_QUIET;
7611          }
7612          else
7613          {
7614            returnValue = START_AS_NON_DETACH;
7615          }
7616        }
7617        else if (quietMode.isPresent())
7618        {
7619          returnValue = START_AS_DETACH_QUIET;
7620        }
7621        else
7622        {
7623          returnValue = START_AS_DETACH;
7624        }
7625      }
7626    }
7627    return returnValue;
7628  }
7629
7630  /**
7631   * Returns true if this server is configured to run as a windows service.
7632   * @return <CODE>true</CODE> if this server is configured to run as a windows
7633   * service and <CODE>false</CODE> otherwise.
7634   */
7635  public static boolean isRunningAsWindowsService()
7636  {
7637    return OperatingSystem.isWindows()
7638        && serviceState() == SERVICE_STATE_ENABLED;
7639  }
7640
7641  // TODO JNR remove error CoreMessages.ERR_REGISTER_WORKFLOW_ELEMENT_ALREADY_EXISTS
7642
7643  /** Print messages for start-ds "-F" option (full version information). */
7644  private static void printFullVersionInformation() {
7645    /*
7646     * This option is used by the upgrade to identify the server build and it
7647     * can eventually also be used to be sent to the support in case of an
7648     * issue.  Since this is not a public interface and since it is better
7649     * to always have it in English for the support team, the message is
7650     * not localized.
7651     */
7652    String separator = ": ";
7653    System.out.println(getVersionString());
7654    System.out.println(SetupUtils.BUILD_ID+separator+BUILD_ID);
7655    System.out.println(SetupUtils.MAJOR_VERSION+separator+MAJOR_VERSION);
7656    System.out.println(SetupUtils.MINOR_VERSION+separator+MINOR_VERSION);
7657    System.out.println(SetupUtils.POINT_VERSION+separator+POINT_VERSION);
7658    System.out.println(SetupUtils.VERSION_QUALIFIER+separator+
7659        VERSION_QUALIFIER);
7660    if (BUILD_NUMBER > 0)
7661    {
7662      System.out.println(SetupUtils.BUILD_NUMBER+separator+
7663                     new DecimalFormat("000").format(BUILD_NUMBER));
7664    }
7665    System.out.println(SetupUtils.REVISION_NUMBER+separator+REVISION_NUMBER);
7666    System.out.println(SetupUtils.URL_REPOSITORY+separator+URL_REPOSITORY);
7667    System.out.println(SetupUtils.FIX_IDS+separator+FIX_IDS);
7668    System.out.println(SetupUtils.DEBUG_BUILD+separator+DEBUG_BUILD);
7669    System.out.println(SetupUtils.BUILD_OS+separator+BUILD_OS);
7670    System.out.println(SetupUtils.BUILD_USER+separator+BUILD_USER);
7671    System.out.println(SetupUtils.BUILD_JAVA_VERSION+separator+
7672        BUILD_JAVA_VERSION);
7673    System.out.println(SetupUtils.BUILD_JAVA_VENDOR+separator+
7674        BUILD_JAVA_VENDOR);
7675    System.out.println(SetupUtils.BUILD_JVM_VERSION+separator+
7676        BUILD_JVM_VERSION);
7677    System.out.println(SetupUtils.BUILD_JVM_VENDOR+separator+BUILD_JVM_VENDOR);
7678    System.out.println(SetupUtils.INCOMPATIBILITY_EVENTS+separator+
7679        Utils.joinAsString(",", VersionCompatibilityIssue.getAllEvents()));
7680
7681    // Print extensions' extra information
7682    String extensionInformation =
7683                  ClassLoaderProvider.getInstance().printExtensionInformation();
7684    if ( extensionInformation != null ) {
7685      System.out.print(extensionInformation);
7686    }
7687  }
7688
7689  /**
7690   * Sets the threshold capacity beyond which internal cached buffers used for
7691   * encoding and decoding entries and protocol messages will be trimmed after
7692   * use.
7693   *
7694   * @param maxInternalBufferSize
7695   *          The threshold capacity beyond which internal cached buffers used
7696   *          for encoding and decoding entries and protocol messages will be
7697   *          trimmed after use.
7698   */
7699  public static void setMaxInternalBufferSize(int maxInternalBufferSize)
7700  {
7701    directoryServer.maxInternalBufferSize = maxInternalBufferSize;
7702  }
7703
7704  /**
7705   * Returns the threshold capacity beyond which internal cached buffers used
7706   * for encoding and decoding entries and protocol messages will be trimmed
7707   * after use.
7708   *
7709   * @return The threshold capacity beyond which internal cached buffers used
7710   *         for encoding and decoding entries and protocol messages will be
7711   *         trimmed after use.
7712   */
7713  public static int getMaxInternalBufferSize()
7714  {
7715    return directoryServer.maxInternalBufferSize;
7716  }
7717
7718  /**
7719   * Returns the lock manager which will be used for coordinating access to LDAP entries.
7720   *
7721   * @return the lock manager which will be used for coordinating access to LDAP entries.
7722   */
7723  public static LockManager getLockManager()
7724  {
7725    return directoryServer.lockManager;
7726  }
7727}