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