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