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