001    /*
002     * CDDL HEADER START
003     *
004     * The contents of this file are subject to the terms of the
005     * Common Development and Distribution License, Version 1.0 only
006     * (the "License").  You may not use this file except in compliance
007     * with the License.
008     *
009     * You can obtain a copy of the license at
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.core;
028    
029    import org.opends.server.admin.ClassLoaderProvider;
030    import org.opends.server.admin.server.ServerManagementContext;
031    import org.opends.server.admin.std.meta.GlobalCfgDefn.WorkflowConfigurationMode;
032    import org.opends.server.admin.std.server.*;
033    import org.opends.server.api.AccountStatusNotificationHandler;
034    import org.opends.server.api.AlertGenerator;
035    import org.opends.server.api.AlertHandler;
036    import org.opends.server.api.ApproximateMatchingRule;
037    import org.opends.server.api.AttributeSyntax;
038    import org.opends.server.api.Backend;
039    import org.opends.server.api.BackendInitializationListener;
040    import org.opends.server.api.BackupTaskListener;
041    import org.opends.server.api.CertificateMapper;
042    import org.opends.server.api.ChangeNotificationListener;
043    import org.opends.server.api.ClientConnection;
044    import org.opends.server.api.CompressedSchema;
045    import org.opends.server.api.ConfigAddListener;
046    import org.opends.server.api.ConfigChangeListener;
047    import org.opends.server.api.ConfigDeleteListener;
048    import org.opends.server.api.ConfigHandler;
049    import org.opends.server.api.ConnectionHandler;
050    import org.opends.server.api.DirectoryServerMBean;
051    import org.opends.server.api.EntryCache;
052    import org.opends.server.api.EqualityMatchingRule;
053    import org.opends.server.api.ExportTaskListener;
054    import org.opends.server.api.ExtendedOperationHandler;
055    import org.opends.server.api.IdentityMapper;
056    import org.opends.server.api.ImportTaskListener;
057    import org.opends.server.api.InvokableComponent;
058    import org.opends.server.api.KeyManagerProvider;
059    import org.opends.server.api.MatchingRule;
060    import org.opends.server.api.MonitorProvider;
061    import org.opends.server.api.OrderingMatchingRule;
062    import org.opends.server.api.PasswordGenerator;
063    import org.opends.server.api.PasswordStorageScheme;
064    import org.opends.server.api.PasswordValidator;
065    import org.opends.server.api.RestoreTaskListener;
066    import org.opends.server.api.SASLMechanismHandler;
067    import org.opends.server.api.ServerShutdownListener;
068    import org.opends.server.api.SubstringMatchingRule;
069    import org.opends.server.api.SynchronizationProvider;
070    import org.opends.server.api.TrustManagerProvider;
071    import org.opends.server.api.WorkQueue;
072    import org.opends.server.api.AccessControlHandler;
073    import org.opends.server.api.plugin.PluginType;
074    import org.opends.server.api.plugin.PluginResult;
075    import org.opends.server.backends.RootDSEBackend;
076    import static org.opends.server.config.ConfigConstants.DN_MONITOR_ROOT;
077    import static org.opends.server.config.ConfigConstants.ENV_VAR_INSTANCE_ROOT;
078    import org.opends.server.config.ConfigEntry;
079    import org.opends.server.config.ConfigException;
080    import org.opends.server.config.JMXMBean;
081    import org.opends.server.controls.PasswordPolicyErrorType;
082    import org.opends.server.controls.PasswordPolicyResponseControl;
083    import org.opends.server.extensions.ConfigFileHandler;
084    import org.opends.server.extensions.JMXAlertHandler;
085    import static org.opends.server.loggers.AccessLogger.*;
086    import static org.opends.server.loggers.ErrorLogger.*;
087    import org.opends.server.loggers.*;
088    import static org.opends.server.loggers.debug.DebugLogger.*;
089    import org.opends.server.loggers.debug.DebugTracer;
090    import org.opends.server.loggers.debug.DebugLogger;
091    import org.opends.server.loggers.debug.TextDebugLogPublisher;
092    
093    import org.opends.messages.MessageDescriptor;
094    import org.opends.messages.Message;
095    import static org.opends.messages.CoreMessages.*;
096    import static org.opends.messages.ToolMessages.*;
097    import org.opends.server.monitors.BackendMonitor;
098    import org.opends.server.monitors.ConnectionHandlerMonitor;
099    import org.opends.server.schema.AttributeTypeSyntax;
100    import org.opends.server.schema.BinarySyntax;
101    import org.opends.server.schema.BooleanEqualityMatchingRule;
102    import org.opends.server.schema.BooleanSyntax;
103    import org.opends.server.schema.CaseExactEqualityMatchingRule;
104    import org.opends.server.schema.CaseExactIA5EqualityMatchingRule;
105    import org.opends.server.schema.CaseExactIA5SubstringMatchingRule;
106    import org.opends.server.schema.CaseExactOrderingMatchingRule;
107    import org.opends.server.schema.CaseExactSubstringMatchingRule;
108    import org.opends.server.schema.CaseIgnoreEqualityMatchingRule;
109    import org.opends.server.schema.CaseIgnoreIA5EqualityMatchingRule;
110    import org.opends.server.schema.CaseIgnoreIA5SubstringMatchingRule;
111    import org.opends.server.schema.CaseIgnoreOrderingMatchingRule;
112    import org.opends.server.schema.CaseIgnoreSubstringMatchingRule;
113    import org.opends.server.schema.DirectoryStringSyntax;
114    import org.opends.server.schema.DistinguishedNameEqualityMatchingRule;
115    import org.opends.server.schema.DistinguishedNameSyntax;
116    import org.opends.server.schema.DoubleMetaphoneApproximateMatchingRule;
117    import org.opends.server.schema.GeneralizedTimeEqualityMatchingRule;
118    import org.opends.server.schema.GeneralizedTimeOrderingMatchingRule;
119    import org.opends.server.schema.GeneralizedTimeSyntax;
120    import org.opends.server.schema.IA5StringSyntax;
121    import org.opends.server.schema.IntegerEqualityMatchingRule;
122    import org.opends.server.schema.IntegerOrderingMatchingRule;
123    import org.opends.server.schema.IntegerSyntax;
124    import org.opends.server.schema.OIDSyntax;
125    import org.opends.server.schema.ObjectClassSyntax;
126    import org.opends.server.schema.ObjectIdentifierEqualityMatchingRule;
127    import org.opends.server.schema.OctetStringEqualityMatchingRule;
128    import org.opends.server.schema.OctetStringOrderingMatchingRule;
129    import org.opends.server.schema.OctetStringSubstringMatchingRule;
130    import static org.opends.server.schema.SchemaConstants.*;
131    import org.opends.server.schema.TelephoneNumberEqualityMatchingRule;
132    import org.opends.server.schema.TelephoneNumberSubstringMatchingRule;
133    import org.opends.server.schema.TelephoneNumberSyntax;
134    import org.opends.server.tools.ConfigureWindowsService;
135    import org.opends.server.types.AbstractOperation;
136    import org.opends.server.types.AcceptRejectWarn;
137    import org.opends.server.types.AttributeType;
138    import org.opends.server.types.AttributeUsage;
139    import org.opends.server.types.AttributeValue;
140    import org.opends.server.types.BackupConfig;
141    import org.opends.server.types.Control;
142    import org.opends.server.crypto.CryptoManagerImpl;
143    import org.opends.server.types.DITContentRule;
144    import org.opends.server.types.DITStructureRule;
145    import org.opends.server.types.DN;
146    import org.opends.server.types.DebugLogLevel;
147    import org.opends.server.types.DirectoryException;
148    import org.opends.server.types.Entry;
149    import org.opends.server.types.HostPort;
150    import org.opends.server.types.InitializationException;
151    import org.opends.server.types.LDIFExportConfig;
152    import org.opends.server.types.LDIFImportConfig;
153    import org.opends.server.types.MatchingRuleUse;
154    import org.opends.server.types.Modification;
155    import org.opends.server.types.NameForm;
156    import org.opends.server.types.ObjectClass;
157    import org.opends.server.types.ObjectClassType;
158    import org.opends.server.types.OperatingSystem;
159    import org.opends.server.types.OperationType;
160    import org.opends.server.types.Privilege;
161    import org.opends.server.types.RDN;
162    import org.opends.server.types.RestoreConfig;
163    import org.opends.server.types.ResultCode;
164    import org.opends.server.types.Schema;
165    import org.opends.server.types.VirtualAttributeRule;
166    import org.opends.server.types.WritabilityMode;
167    import org.opends.server.types.DirectoryEnvironmentConfig;
168    import org.opends.server.types.LockManager;
169    import static org.opends.server.util.DynamicConstants.*;
170    import static org.opends.server.util.ServerConstants.*;
171    import static org.opends.server.util.StaticUtils.*;
172    import static org.opends.server.util.Validator.ensureNotNull;
173    import org.opends.server.util.*;
174    import org.opends.server.util.args.ArgumentException;
175    import org.opends.server.util.args.ArgumentParser;
176    import org.opends.server.util.args.BooleanArgument;
177    import org.opends.server.util.args.StringArgument;
178    import org.opends.server.workflowelement.*;
179    import org.opends.server.workflowelement.localbackend.*;
180    import org.opends.server.protocols.internal.InternalConnectionHandler;
181    import org.opends.server.protocols.internal.InternalClientConnection;
182    import org.opends.server.crypto.CryptoManagerSync;
183    import static org.opends.messages.ConfigMessages.*;
184    
185    import javax.management.MBeanServer;
186    import javax.management.MBeanServerFactory;
187    import java.io.File;
188    import java.io.FileOutputStream;
189    import java.io.IOException;
190    import java.io.OutputStream;
191    import java.io.PrintStream;
192    import java.net.InetAddress;
193    import java.text.DecimalFormat;
194    import java.util.*;
195    import java.util.concurrent.ConcurrentHashMap;
196    import java.util.concurrent.CopyOnWriteArrayList;
197    import java.util.concurrent.CopyOnWriteArraySet;
198    
199    
200    /**
201     * This class defines the core of the Directory Server.  It manages the startup
202     * and shutdown processes and coordinates activities between all other
203     * components.
204     */
205    public class DirectoryServer
206           implements Thread.UncaughtExceptionHandler, AlertGenerator
207    {
208      /**
209       * The tracer object for the debug logger.
210       */
211      private static final DebugTracer TRACER = getTracer();
212    
213        /**
214        * The fully-qualified name of this class.
215        */
216        private static final String CLASS_NAME =
217           "org.opends.server.core.DirectoryServer";
218    
219    
220      /**
221       * The singleton Directory Server instance.
222       */
223      private static DirectoryServer directoryServer = new DirectoryServer();
224    
225    
226    
227      /**
228       * Indicates whether the server currently holds an exclusive lock on the
229       * server lock fiie.
230       */
231      private static boolean serverLocked = false;
232    
233    
234      /**
235       * Return codes used when the hidden option --checkStartability is used.
236       * NOTE: when checkstartability is specified is recommended not to allocate
237       * a lot of memory for the JVM (Using -Xms and -Xmx options) as there might
238       * be calls to Runtime.exec.
239       */
240      /**
241       * Returned when the user specified the --checkStartability option with other
242       * options like printing the usage, dumping messages, displaying version, etc.
243       */
244      private static int NOTHING_TO_DO = 0;
245      /**
246       * Returned when the user specified the --checkStartability option with
247       * some incompatible arguments.
248       */
249      private static int CHECK_ERROR = 1;
250      /**
251       * The server is already started.
252       */
253      private static int SERVER_ALREADY_STARTED = 98;
254      /**
255       * The server must be started as detached process.
256       */
257      private static int START_AS_DETACH = 99;
258      /**
259       * The server must be started as a non-detached process.
260       */
261      private static int START_AS_NON_DETACH = 100;
262      /**
263       * The server must be started as a window service.
264       */
265      private static int START_AS_WINDOWS_SERVICE = 101;
266      /**
267       * The server must be started as detached and it is being called from the
268       * Windows Service.
269       */
270      private static int START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE = 102;
271      /**
272       * The server must be started as detached process and should not produce any
273       * output.
274       */
275      private static int START_AS_DETACH_QUIET = 103;
276    
277      // The policy to use regarding single structural objectclass enforcement.
278      private AcceptRejectWarn singleStructuralClassPolicy;
279    
280      // The policy to use regarding syntax enforcement.
281      private AcceptRejectWarn syntaxEnforcementPolicy;
282    
283      // The account status notification handler config manager for the server.
284      private AccountStatusNotificationHandlerConfigManager
285           accountStatusNotificationHandlerConfigManager;
286    
287      // The default syntax to use for binary attributes.
288      private AttributeSyntax<AttributeSyntaxCfg> defaultBinarySyntax;
289    
290      // The default syntax to use for Boolean attributes.
291      private AttributeSyntax<AttributeSyntaxCfg> defaultBooleanSyntax;
292    
293      // The default syntax to use for DN attributes.
294      private AttributeSyntax<AttributeSyntaxCfg> defaultDNSyntax;
295    
296      // The default syntax to use for integer attributes.
297      private AttributeSyntax<AttributeSyntaxCfg> defaultIntegerSyntax;
298    
299      // The default syntax to use for string attributes.
300      private AttributeSyntax<DirectoryStringAttributeSyntaxCfg>
301                   defaultStringSyntax;
302    
303      // The default attribute syntax to use for attributes with no defined syntax.
304      private AttributeSyntax<DirectoryStringAttributeSyntaxCfg> defaultSyntax;
305    
306      // The attribute type used to reference the "objectclass" attribute.
307      private AttributeType objectClassAttributeType;
308    
309      // The authenticated users manager for the server.
310      private AuthenticatedUsers authenticatedUsers;
311    
312      // The configuration manager that will handle the server backends.
313      private BackendConfigManager backendConfigManager;
314    
315      // Indicates whether to automatically add missing RDN attributes to entries
316      // during an add request.
317      private boolean addMissingRDNAttributes;
318    
319      // Indicates whether to allow attribute name exceptions (i.e., attribute names
320      // can contain underscores and may start with a digit).
321      private boolean allowAttributeNameExceptions;
322    
323      // Indicates whether a simple bind request containing a DN must also provide a
324      // password.
325      private boolean bindWithDNRequiresPassword;
326    
327      // Indicates whether the Directory Server should perform schema checking for
328      // update operations.
329      private boolean checkSchema;
330    
331      // Indicates whether the server has been bootstrapped.
332      private boolean isBootstrapped;
333    
334      // Indicates whether the server has been bootstrapped for client use.
335      private boolean isClientBootstrapped;
336    
337      // Indicates whether the server is currently online.
338      private boolean isRunning;
339    
340      // Indicates whether the server is currently in "lockdown mode".
341      private boolean lockdownMode;
342    
343      // Indicates whether the server should send a response to operations that have
344      // been abandoned.
345      private boolean notifyAbandonedOperations;
346    
347      // Indicates whether to save a copy of the configuration on successful
348      // startup.
349      private boolean saveConfigOnSuccessfulStartup;
350    
351      // Indicates whether the server is currently in the process of shutting down.
352      private boolean shuttingDown;
353    
354      // Indicates whether the server should reject unauthenticated requests.
355      private boolean rejectUnauthenticatedRequests;
356    
357      // Indicates whether bind responses should include failure reason messages.
358      private boolean returnBindErrorMessages;
359    
360      // The configuration manager that will handle the certificate mapper.
361      private CertificateMapperConfigManager certificateMapperConfigManager;
362    
363      // The class used to provide the config handler implementation.
364      private Class configClass;
365    
366      // The configuration handler for the Directory Server.
367      private ConfigHandler configHandler;
368    
369      // The set of account status notification handlers defined in the server.
370      private ConcurrentHashMap<DN,AccountStatusNotificationHandler>
371                   accountStatusNotificationHandlers;
372    
373      // The set of certificate mappers registered with the server.
374      private ConcurrentHashMap<DN,CertificateMapper> certificateMappers;
375    
376      // The set of alternate bind DNs for the root users.
377      private ConcurrentHashMap<DN,DN> alternateRootBindDNs;
378    
379      // The set of identity mappers registered with the server (mapped between
380      // the configuration entry Dn and the mapper).
381      private ConcurrentHashMap<DN,IdentityMapper> identityMappers;
382    
383      // The set of JMX MBeans that have been registered with the server (mapped
384      // between the associated configuration entry DN and the MBean).
385      private ConcurrentHashMap<DN,JMXMBean> mBeans;
386    
387      // The set of key manager providers registered with the server.
388      private ConcurrentHashMap<DN,KeyManagerProvider> keyManagerProviders;
389    
390      // The set of password generators registered with the Directory Server, as a
391      // mapping between the DN of the associated configuration entry and the
392      // generator implementation.
393      private ConcurrentHashMap<DN,PasswordGenerator> passwordGenerators;
394    
395      // The set of password policies registered with the Directory Server, as a
396      // mapping between the DN of the associated configuration entry and the policy
397      // implementation.
398      private ConcurrentHashMap<DN,PasswordPolicyConfig> passwordPolicies;
399    
400      // The set of password validators registered with the Directory Server, as a
401      // mapping between the DN of the associated configuration entry and the
402      // validator implementation.
403      private ConcurrentHashMap<DN,
404                   PasswordValidator<? extends PasswordValidatorCfg>>
405                   passwordValidators;
406    
407      // The set of trust manager providers registered with the server.
408      private ConcurrentHashMap<DN,TrustManagerProvider> trustManagerProviders;
409    
410      // The set of log rotation policies registered with the Directory Server, as
411      // a mapping between the DN of the associated configuration entry and the
412      // policy implementation.
413      private ConcurrentHashMap<DN, RotationPolicy> rotationPolicies;
414    
415      // The set of log retention policies registered with the Directory Server, as
416      // a mapping between the DN of the associated configuration entry and the
417      // policy implementation.
418      private ConcurrentHashMap<DN, RetentionPolicy> retentionPolicies;
419    
420      // The set supported LDAP protocol versions.
421      private ConcurrentHashMap<Integer,List<ConnectionHandler>>
422                   supportedLDAPVersions;
423    
424      // The set of extended operation handlers registered with the server (mapped
425      // between the OID of the extended operation and the handler).
426      private ConcurrentHashMap<String,ExtendedOperationHandler>
427                   extendedOperationHandlers;
428    
429      // The set of monitor providers registered with the Directory Server, as a
430      // mapping between the monitor name and the corresponding implementation.
431      private ConcurrentHashMap<String,
432                                MonitorProvider<? extends MonitorProviderCfg>>
433                   monitorProviders;
434    
435      // The set of password storage schemes defined in the server (mapped between
436      // the lowercase scheme name and the storage scheme) that support the
437      // authentication password syntax.
438      private ConcurrentHashMap<String,PasswordStorageScheme>
439                   authPasswordStorageSchemes;
440    
441      // The set of password storage schemes defined in the server (mapped between
442      // the lowercase scheme name and the storage scheme).
443      private ConcurrentHashMap<String,PasswordStorageScheme>
444                   passwordStorageSchemes;
445    
446      // The set of password storage schemes defined in the server (mapped between
447      // the DN of the configuration entry and the storage scheme).
448      private ConcurrentHashMap<DN,PasswordStorageScheme>
449                   passwordStorageSchemesByDN;
450    
451      // The set of SASL mechanism handlers registered with the server (mapped
452      // between the mechanism name and the handler).
453      private ConcurrentHashMap<String,SASLMechanismHandler> saslMechanismHandlers;
454    
455      // The connection handler configuration manager for the Directory Server.
456      private ConnectionHandlerConfigManager connectionHandlerConfigManager;
457    
458      // The set of alert handlers registered with the Directory Server.
459      private CopyOnWriteArrayList<AlertHandler> alertHandlers;
460    
461      // The set of backup task listeners registered with the Directory Server.
462      private CopyOnWriteArrayList<BackupTaskListener> backupTaskListeners;
463    
464      // The set of change notification listeners registered with the Directory
465      // Server.
466      private CopyOnWriteArrayList<ChangeNotificationListener>
467                   changeNotificationListeners;
468    
469      // The set of connection handlers registered with the Directory Server.
470      private CopyOnWriteArrayList<ConnectionHandler> connectionHandlers;
471    
472      // The set of export task listeners registered with the Directory Server.
473      private CopyOnWriteArrayList<ExportTaskListener> exportTaskListeners;
474    
475      // The set of import task listeners registered with the Directory Server.
476      private CopyOnWriteArrayList<ImportTaskListener> importTaskListeners;
477    
478      // The set of persistent searches registered with the Directory Server.
479      private CopyOnWriteArrayList<PersistentSearch> persistentSearches;
480    
481      // The set of restore task listeners registered with the Directory Server.
482      private CopyOnWriteArrayList<RestoreTaskListener> restoreTaskListeners;
483    
484      // The set of shutdown listeners that have been registered with the Directory
485      // Server.
486      private CopyOnWriteArrayList<ServerShutdownListener> shutdownListeners;
487    
488      // The set of synchronization providers that have been registered with the
489      // Directory Server.
490      private
491        CopyOnWriteArrayList<SynchronizationProvider<SynchronizationProviderCfg>>
492                   synchronizationProviders;
493    
494      // The set of virtual attributes defined in the server.
495      private CopyOnWriteArrayList<VirtualAttributeRule> virtualAttributes;
496    
497      // The set of backend initialization listeners registered with the Directory
498      // Server.
499      private CopyOnWriteArraySet<BackendInitializationListener>
500                   backendInitializationListeners;
501    
502      // The set of root DNs registered with the Directory Server.
503      private CopyOnWriteArraySet<DN> rootDNs;
504    
505      // The core configuration manager for the Directory Server.
506      private CoreConfigManager coreConfigManager;
507    
508      // The crypto manager for the Directory Server.
509      private CryptoManagerImpl cryptoManager;
510    
511      // The default compressed schema manager.
512      private DefaultCompressedSchema compressedSchema;
513    
514      // The environment configuration for the Directory Server.
515      private DirectoryEnvironmentConfig environmentConfig;
516    
517      // The shutdown hook that has been registered with the server.
518      private DirectoryServerShutdownHook shutdownHook;
519    
520      // The DN of the default password policy configuration entry.
521      private DN defaultPasswordPolicyDN;
522    
523      // The DN of the identity mapper that will be used to resolve authorization
524      // IDs contained in the proxied authorization V2 control.
525      private DN proxiedAuthorizationIdentityMapperDN;
526    
527      // The DN of the entry containing the server schema definitions.
528      private DN schemaDN;
529    
530      // The Directory Server entry cache.
531      private EntryCache entryCache;
532    
533      // The configuration manager for the entry cache.
534      private EntryCacheConfigManager entryCacheConfigManager;
535    
536      // The configuration manager for extended operation handlers.
537      private ExtendedOperationConfigManager extendedOperationConfigManager;
538    
539      // The path to the file containing the Directory Server configuration, or the
540      // information needed to bootstrap the configuration handler.
541      private File configFile;
542    
543      // The group manager for the Directory Server.
544      private GroupManager groupManager;
545    
546      // The configuration manager for identity mappers.
547      private IdentityMapperConfigManager identityMapperConfigManager;
548    
549      // The maximum number of entries that should be returned for a search unless
550      // overridden on a per-user basis.
551      private int sizeLimit;
552    
553      // The maximum length of time in seconds that should be allowed for a search
554      // unless overridden on a per-user basis.
555      private int timeLimit;
556    
557      // The maxiumum number of candidates that should be check for matches during
558      // a search.
559      private int lookthroughLimit;
560    
561      // Whether to use collect operation processing times in nanosecond resolution
562      private boolean useNanoTime;
563    
564      // The key manager provider configuration manager for the Directory Server.
565      private KeyManagerProviderConfigManager keyManagerProviderConfigManager;
566    
567      // The set of connections that are currently established.
568      private LinkedHashSet<ClientConnection> establishedConnections;
569    
570      // The sets of mail server properties
571      private List<Properties> mailServerPropertySets;
572    
573      // The set of schema changes made by editing the schema configuration files
574      // with the server offline.
575      private List<Modification> offlineSchemaChanges;
576    
577      // The log rotation policy config manager for the Directory Server.
578      private LogRotationPolicyConfigManager rotationPolicyConfigManager;
579    
580      // The log retention policy config manager for the Directory Server.
581      private LogRetentionPolicyConfigManager retentionPolicyConfigManager;
582    
583      // The logger configuration manager for the Directory Server.
584      private LoggerConfigManager loggerConfigManager;
585    
586      // The number of connections currently established to the server.
587      private long currentConnections;
588    
589      // The idle time limit for the server.
590      private long idleTimeLimit;
591    
592      // The maximum number of connections that will be allowed at any given time.
593      private long maxAllowedConnections;
594    
595      // The maximum number of connections established at one time.
596      private long maxConnections;
597    
598      // The time that this Directory Server instance was started.
599      private long startUpTime;
600    
601      // The total number of connections established since startup.
602      private long totalConnections;
603    
604      // The MBean server used to handle JMX interaction.
605      private MBeanServer mBeanServer;
606    
607      // The monitor config manager for the Directory Server.
608      private MonitorConfigManager monitorConfigManager;
609    
610      // The operating system on which the server is running.
611      private OperatingSystem operatingSystem;
612    
613      // The configuration handler used to manage the password generators.
614      private PasswordGeneratorConfigManager passwordGeneratorConfigManager;
615    
616      // The default password policy for the Directory Server.
617      private PasswordPolicyConfig defaultPasswordPolicyConfig;
618    
619      // The configuration handler used to manage the password policies.
620      private PasswordPolicyConfigManager passwordPolicyConfigManager;
621    
622      // The configuration handler used to manage the password storage schemes.
623      private PasswordStorageSchemeConfigManager storageSchemeConfigManager;
624    
625      // The configuration handler used to manage the password validators.
626      private PasswordValidatorConfigManager passwordValidatorConfigManager;
627    
628      // The plugin config manager for the Directory Server.
629      private PluginConfigManager pluginConfigManager;
630    
631      // The result code that should be used for internal "server" errors.
632      private ResultCode serverErrorResultCode;
633    
634      // The special backend used for the Directory Server root DSE.
635      private RootDSEBackend rootDSEBackend;
636    
637      // The root DN config manager for the server.
638      private RootDNConfigManager rootDNConfigManager;
639    
640      // The SASL mechanism config manager for the Directory Server.
641      private SASLConfigManager saslConfigManager;
642    
643      // The schema for the Directory Server.
644      private Schema schema;
645    
646      // The schema configuration manager for the Directory Server.
647      private SchemaConfigManager schemaConfigManager;
648    
649      // The set of disabled privileges.
650      private Set<Privilege> disabledPrivileges;
651    
652      // The set of allowed task classes.
653      private Set<String> allowedTasks;
654    
655      // The time that the server was started, formatted in UTC time.
656      private String startTimeUTC;
657    
658      // The synchronization provider configuration manager for the Directory
659      // Server.
660      private SynchronizationProviderConfigManager
661                   synchronizationProviderConfigManager;
662    
663      // The thread group for all threads associated with the Directory Server.
664      private ThreadGroup directoryThreadGroup;
665    
666    
667      // Registry for base DN and naming context information.
668      private BaseDnRegistry baseDnRegistry;
669    
670    
671      // The set of backends registered with the server.
672      private TreeMap<String,Backend> backends;
673    
674      // The mapping between backends and their unique indentifiers for their
675      // offline state, representing either checksum or other unique value to
676      // be used for detecting any offline modifications to a given backend.
677      private ConcurrentHashMap<String,Long> offlineBackendsStateIDs;
678    
679      // The set of supported controls registered with the Directory Server.
680      private TreeSet<String> supportedControls;
681    
682      // The set of supported feature OIDs registered with the Directory Server.
683      private TreeSet<String> supportedFeatures;
684    
685      // The trust manager provider configuration manager for the Directory Server.
686      private TrustManagerProviderConfigManager trustManagerProviderConfigManager;
687    
688      // The virtual attribute provider configuration manager for the Directory
689      // Server.
690      private VirtualAttributeConfigManager virtualAttributeConfigManager;
691    
692      // The work queue that will be used to service client requests.
693      private WorkQueue workQueue;
694    
695      // The writability mode for the Directory Server.
696      private WritabilityMode writabilityMode;
697    
698      // The workflow configuration mode (auto or manual).
699      private WorkflowConfigurationMode workflowConfigurationMode;
700    
701      // The network group config manager for the Directory Server.
702      // This config manager is used when the workflow configuration
703      // mode is 'manual'.
704      private NetworkGroupConfigManager networkGroupConfigManager;
705    
706      // The workflow config manager for the Directory Server.
707      // This config manager is used when the workflow configuration
708      // mode is 'manual'.
709      private WorkflowConfigManager workflowConfigManager;
710    
711      // The workflow element config manager for the Directory Server.
712      // This config manager is used when the workflow configuration
713      // mode is 'manual'.
714      private WorkflowElementConfigManager workflowElementConfigManager;
715    
716    
717    
718      /**
719       * Creates a new instance of the Directory Server.  This will allow only a
720       * single instance of the server per JVM.
721       */
722      private DirectoryServer()
723      {
724        this(new DirectoryEnvironmentConfig());
725      }
726    
727    
728    
729      /**
730       * Creates a new instance of the Directory Server.  This will allow only a
731       * single instance of the server per JVM.
732       *
733       * @param  config  The environment configuration to use for the Directory
734       *                 Server instance.
735       */
736      private DirectoryServer(DirectoryEnvironmentConfig config)
737      {
738        environmentConfig        = config;
739        isBootstrapped           = false;
740        isClientBootstrapped     = false;
741        isRunning                = false;
742        shuttingDown             = false;
743        lockdownMode             = false;
744        serverErrorResultCode    = ResultCode.OTHER;
745    
746        operatingSystem = OperatingSystem.forName(System.getProperty("os.name"));
747      }
748    
749    
750    
751      /**
752       * Retrieves the instance of the Directory Server that is associated with this
753       * JVM.
754       *
755       * @return  The instance of the Directory Server that is associated with this
756       *          JVM.
757       */
758      public static DirectoryServer getInstance()
759      {
760        return directoryServer;
761      }
762    
763    
764    
765      /**
766       * Creates a new instance of the Directory Server and replaces the static
767       * reference to it.  This should only be used in the context of an in-core
768       * restart after the existing server has been shut down.
769       *
770       * @param  config  The environment configuration for the Directory Server.
771       *
772       * @return  The new instance of the Directory Server that is associated with
773       *          this JVM.
774       */
775      private static DirectoryServer
776                          getNewInstance(DirectoryEnvironmentConfig config)
777      {
778        synchronized (directoryServer)
779        {
780          return directoryServer = new DirectoryServer(config);
781        }
782      }
783    
784    
785    
786      /**
787       * Retrieves the environment configuration for the Directory Server.
788       *
789       * @return  The environment configuration for the Directory Server.
790       */
791      public static DirectoryEnvironmentConfig getEnvironmentConfig()
792      {
793        return directoryServer.environmentConfig;
794      }
795    
796    
797    
798      /**
799       * Sets the environment configuration for the Directory Server.  This method
800       * may only be invoked when the server is not running.
801       *
802       * @param  config  The environment configuration for the Directory Server.
803       *
804       * @throws  InitializationException  If the Directory Server is currently
805       *                                   running.
806       */
807      public void setEnvironmentConfig(DirectoryEnvironmentConfig config)
808              throws InitializationException
809      {
810        if (isRunning)
811        {
812          throw new InitializationException(
813                  ERR_CANNOT_SET_ENVIRONMENT_CONFIG_WHILE_RUNNING.get());
814        }
815    
816        environmentConfig = config;
817      }
818    
819    
820    
821      /**
822       * Indicates whether the Directory Server is currently running.
823       *
824       * @return  {@code true} if the server is currently running, or {@code false}
825       *          if not.
826       */
827      public static boolean isRunning()
828      {
829        return directoryServer.isRunning;
830      }
831    
832    
833    
834      /**
835       * Bootstraps the appropriate Directory Server structures that may be needed
836       * by client-side tools.  This is not intended for use in running the server
837       * itself.
838       */
839      public static void bootstrapClient()
840      {
841        synchronized (directoryServer)
842        {
843          if (directoryServer.isClientBootstrapped)
844          {
845            return;
846          }
847    
848    
849          // Set default values for variables that may be needed during schema
850          // processing.
851          directoryServer.syntaxEnforcementPolicy = AcceptRejectWarn.REJECT;
852    
853    
854          // Create the server schema and initialize and register a minimal set of
855          // matching rules and attribute syntaxes.
856          directoryServer.schema = new Schema();
857          directoryServer.bootstrapMatchingRules();
858          directoryServer.bootstrapAttributeSyntaxes();
859    
860    
861          // Perform any additional initialization that might be necessary before
862          // loading the configuration.
863          directoryServer.alertHandlers = new CopyOnWriteArrayList<AlertHandler>();
864          directoryServer.passwordStorageSchemes =
865               new ConcurrentHashMap<String,PasswordStorageScheme>();
866          directoryServer.passwordStorageSchemesByDN =
867               new ConcurrentHashMap<DN,PasswordStorageScheme>();
868          directoryServer.passwordGenerators =
869               new ConcurrentHashMap<DN,PasswordGenerator>();
870          directoryServer.authPasswordStorageSchemes =
871               new ConcurrentHashMap<String,PasswordStorageScheme>();
872          directoryServer.passwordValidators =
873               new ConcurrentHashMap<DN,
874                    PasswordValidator<? extends PasswordValidatorCfg>>();
875          directoryServer.accountStatusNotificationHandlers =
876               new ConcurrentHashMap<DN,AccountStatusNotificationHandler>();
877          directoryServer.rootDNs = new CopyOnWriteArraySet<DN>();
878          directoryServer.alternateRootBindDNs = new ConcurrentHashMap<DN,DN>();
879          directoryServer.keyManagerProviders =
880               new ConcurrentHashMap<DN,KeyManagerProvider>();
881          directoryServer.trustManagerProviders =
882               new ConcurrentHashMap<DN,TrustManagerProvider>();
883          directoryServer.rotationPolicies =
884               new ConcurrentHashMap<DN, RotationPolicy>();
885          directoryServer.retentionPolicies =
886               new ConcurrentHashMap<DN, RetentionPolicy>();
887          directoryServer.certificateMappers =
888               new ConcurrentHashMap<DN,CertificateMapper>();
889          directoryServer.passwordPolicies =
890               new ConcurrentHashMap<DN,PasswordPolicyConfig>();
891          directoryServer.defaultPasswordPolicyDN = null;
892          directoryServer.defaultPasswordPolicyConfig = null;
893          directoryServer.monitorProviders =
894               new ConcurrentHashMap<String,
895                        MonitorProvider<? extends MonitorProviderCfg>>();
896          directoryServer.backends = new TreeMap<String,Backend>();
897          directoryServer.offlineBackendsStateIDs =
898               new ConcurrentHashMap<String,Long>();
899          directoryServer.backendInitializationListeners =
900               new CopyOnWriteArraySet<BackendInitializationListener>();
901          directoryServer.baseDnRegistry = new BaseDnRegistry();
902          directoryServer.changeNotificationListeners =
903               new CopyOnWriteArrayList<ChangeNotificationListener>();
904          directoryServer.persistentSearches =
905               new CopyOnWriteArrayList<PersistentSearch>();
906          directoryServer.shutdownListeners =
907               new CopyOnWriteArrayList<ServerShutdownListener>();
908          directoryServer.synchronizationProviders =
909               new CopyOnWriteArrayList<SynchronizationProvider
910                                       <SynchronizationProviderCfg>>();
911          directoryServer.supportedControls = new TreeSet<String>();
912          directoryServer.supportedFeatures = new TreeSet<String>();
913          directoryServer.supportedLDAPVersions =
914               new ConcurrentHashMap<Integer,List<ConnectionHandler>>();
915          directoryServer.virtualAttributes =
916               new CopyOnWriteArrayList<VirtualAttributeRule>();
917          directoryServer.connectionHandlers =
918               new CopyOnWriteArrayList<ConnectionHandler>();
919          directoryServer.identityMappers =
920               new ConcurrentHashMap<DN,IdentityMapper>();
921          directoryServer.extendedOperationHandlers =
922               new ConcurrentHashMap<String,ExtendedOperationHandler>();
923          directoryServer.saslMechanismHandlers =
924               new ConcurrentHashMap<String,SASLMechanismHandler>();
925          directoryServer.authenticatedUsers = new AuthenticatedUsers();
926          directoryServer.offlineSchemaChanges = new LinkedList<Modification>();
927          directoryServer.backupTaskListeners =
928               new CopyOnWriteArrayList<BackupTaskListener>();
929          directoryServer.restoreTaskListeners =
930               new CopyOnWriteArrayList<RestoreTaskListener>();
931          directoryServer.exportTaskListeners =
932               new CopyOnWriteArrayList<ExportTaskListener>();
933          directoryServer.importTaskListeners =
934               new CopyOnWriteArrayList<ImportTaskListener>();
935          directoryServer.allowedTasks = new LinkedHashSet<String>(0);
936          directoryServer.disabledPrivileges = new LinkedHashSet<Privilege>(0);
937          directoryServer.returnBindErrorMessages = false;
938          directoryServer.idleTimeLimit = 0L;
939        }
940      }
941    
942    
943    
944      /**
945       * Bootstraps the Directory Server by initializing all the necessary
946       * structures that should be in place before the configuration may be read.
947       * This step must be completed before the server may be started or the
948       * configuration is loaded, but it will not be allowed while the server is
949       * running.
950       *
951       * @throws  InitializationException  If a problem occurs while attempting to
952       *                                   bootstrap the server.
953       */
954      public void bootstrapServer()
955             throws InitializationException
956      {
957        // First, make sure that the server isn't currently running.  If it isn't,
958        // then make sure that no other thread will try to start or bootstrap the
959        // server before this thread is done.
960        synchronized (directoryServer)
961        {
962          if (isRunning)
963          {
964            Message message = ERR_CANNOT_BOOTSTRAP_WHILE_RUNNING.get();
965            throw new InitializationException(message);
966          }
967    
968          isBootstrapped   = false;
969          shuttingDown     = false;
970        }
971    
972    
973        // Create the thread group that should be used for all Directory Server
974        // threads.
975        directoryThreadGroup = new ThreadGroup("Directory Server Thread Group");
976    
977    
978        // Add a shutdown hook so that the server can be notified when the JVM
979        // starts shutting down.
980        shutdownHook = new DirectoryServerShutdownHook();
981        Runtime.getRuntime().addShutdownHook(shutdownHook);
982    
983    
984        // Register this class as the default uncaught exception handler for the
985        // JVM.  The uncaughtException method will be called if a thread dies
986        // because it did not properly handle an exception.
987        Thread.setDefaultUncaughtExceptionHandler(this);
988    
989    
990        // Create the MBean server that we will use for JMX interaction.
991        initializeJMX();
992    
993    
994        logError(INFO_DIRECTORY_BOOTSTRAPPING.get());
995    
996    
997        // Perform all the bootstrapping that is shared with the client-side
998        // processing.
999        bootstrapClient();
1000    
1001    
1002        // Initialize the variables that will be used for connection tracking.
1003        establishedConnections = new LinkedHashSet<ClientConnection>(1000);
1004        currentConnections     = 0;
1005        maxConnections         = 0;
1006        totalConnections       = 0;
1007    
1008    
1009        // Create the plugin config manager, but don't initialize it yet.  This will
1010        // make it possible to process internal operations before the plugins have
1011        // been loaded.
1012        pluginConfigManager = new PluginConfigManager();
1013    
1014    
1015        // If we have gotten here, then the configuration should be properly
1016        // bootstrapped.
1017        synchronized (directoryServer)
1018        {
1019          isBootstrapped = true;
1020        }
1021      }
1022    
1023    
1024    
1025      /**
1026       * Performs a minimal set of JMX initialization.  This may be used by the core
1027       * Directory Server or by command-line tools.
1028       *
1029       * @throws  InitializationException  If a problem occurs while attempting to
1030       *                                   initialize the JMX subsystem.
1031       */
1032      public static void initializeJMX()
1033             throws InitializationException
1034      {
1035        try
1036        {
1037          // FIXME -- Should we use the plaform Mbean Server or
1038          // should we use a private one ?
1039          directoryServer.mBeanServer = MBeanServerFactory.newMBeanServer();
1040          // directoryServer.mBeanServer =
1041          //      ManagementFactory.getPlatformMBeanServer();
1042    
1043          directoryServer.mBeans = new ConcurrentHashMap<DN,JMXMBean>();
1044          registerAlertGenerator(directoryServer);
1045        }
1046        catch (Exception e)
1047        {
1048          if (debugEnabled())
1049          {
1050            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1051          }
1052    
1053          Message message = ERR_CANNOT_CREATE_MBEAN_SERVER.get(String.valueOf(e));
1054          throw new InitializationException(message, e);
1055        }
1056      }
1057    
1058    
1059    
1060      /**
1061       * Instantiates the configuration handler and loads the Directory Server
1062       * configuration.
1063       *
1064       * @param  configClass  The fully-qualified name of the Java class that will
1065       *                      serve as the configuration handler for the Directory
1066       *                      Server.
1067       * @param  configFile   The path to the file that will hold either the entire
1068       *                      server configuration or enough information to allow
1069       *                      the server to access the configuration in some other
1070       *                      repository.
1071       *
1072       * @throws  InitializationException  If a problem occurs while trying to
1073       *                                   initialize the config handler.
1074       */
1075      public void initializeConfiguration(String configClass, String configFile)
1076             throws InitializationException
1077      {
1078        Class cfgClass;
1079        try
1080        {
1081          cfgClass = Class.forName(configClass);
1082        }
1083        catch (Exception e)
1084        {
1085          if (debugEnabled())
1086          {
1087            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1088          }
1089    
1090          Message message =
1091              ERR_CANNOT_LOAD_CONFIG_HANDLER_CLASS.get(
1092                      configClass, stackTraceToSingleLineString(e));
1093          throw new InitializationException(message, e);
1094        }
1095    
1096        File cfgFile = new File(configFile);
1097    
1098        environmentConfig.setConfigClass(cfgClass);
1099        environmentConfig.setConfigFile(cfgFile);
1100        initializeConfiguration();
1101      }
1102    
1103    
1104    
1105      /**
1106       * Instantiates the configuration handler and loads the Directory Server
1107       * configuration.
1108       *
1109       * @throws  InitializationException  If a problem occurs while trying to
1110       *                                   initialize the config handler.
1111       */
1112      public void initializeConfiguration()
1113             throws InitializationException
1114      {
1115        this.configClass = environmentConfig.getConfigClass();
1116        this.configFile  = environmentConfig.getConfigFile();
1117    
1118    
1119        // Make sure that administration framework definition classes are loaded.
1120        ClassLoaderProvider provider = ClassLoaderProvider.getInstance();
1121        if (! provider.isEnabled())
1122        {
1123          provider.enable();
1124        }
1125    
1126    
1127        // Load and instantiate the configuration handler class.
1128        Class handlerClass = configClass;
1129        try
1130        {
1131          configHandler = (ConfigHandler) handlerClass.newInstance();
1132        }
1133        catch (Exception e)
1134        {
1135          if (debugEnabled())
1136          {
1137            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1138          }
1139    
1140          Message message =
1141              ERR_CANNOT_INSTANTIATE_CONFIG_HANDLER.get(
1142                      String.valueOf(configClass),
1143                      e.getLocalizedMessage());
1144          throw new InitializationException(message, e);
1145        }
1146    
1147    
1148        // Perform the handler-specific initialization.
1149        try
1150        {
1151          configHandler.initializeConfigHandler(configFile.getAbsolutePath(),
1152                                                false);
1153        }
1154        catch (InitializationException ie)
1155        {
1156          if (debugEnabled())
1157          {
1158            TRACER.debugCaught(DebugLogLevel.ERROR, ie);
1159          }
1160    
1161          throw ie;
1162        }
1163        catch (Exception e)
1164        {
1165          if (debugEnabled())
1166          {
1167            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1168          }
1169    
1170          Message message =
1171              ERR_CANNOT_INITIALIZE_CONFIG_HANDLER.get(
1172                      String.valueOf(configClass),
1173                      String.valueOf(configFile),
1174                      e.getLocalizedMessage());
1175          throw new InitializationException(message);
1176        }
1177    
1178      }
1179    
1180    
1181    
1182      /**
1183       * Retrieves the path to the configuration file used to initialize the
1184       * Directory Server.
1185       *
1186       * @return  The path to the configuration file used to initialize the
1187       *          Directory Server.
1188       */
1189      public static String getConfigFile()
1190      {
1191        return directoryServer.configFile.getAbsolutePath();
1192      }
1193    
1194    
1195    
1196      /**
1197       * Starts up the Directory Server.  It must have already been bootstrapped
1198       * and cannot be running.
1199       *
1200       * @throws  ConfigException  If there is a problem with the Directory Server
1201       *                           configuration that prevents a critical component
1202       *                           from being instantiated.
1203       *
1204       * @throws  InitializationException  If some other problem occurs while
1205       *                                   attempting to initialize and start the
1206       *                                   Directory Server.
1207       */
1208      public void startServer()
1209             throws ConfigException, InitializationException
1210      {
1211        synchronized (directoryServer)
1212        {
1213          if (! isBootstrapped)
1214          {
1215            Message message = ERR_CANNOT_START_BEFORE_BOOTSTRAP.get();
1216            throw new InitializationException(message);
1217          }
1218    
1219          if (isRunning)
1220          {
1221            Message message = ERR_CANNOT_START_WHILE_RUNNING.get();
1222            throw new InitializationException(message);
1223          }
1224    
1225    
1226          logError(NOTE_DIRECTORY_SERVER_STARTING.get(getVersionString(),
1227                                                      BUILD_ID, REVISION_NUMBER));
1228    
1229          RuntimeInformation.logInfo();
1230          // Acquire an exclusive lock for the Directory Server process.
1231          if (! serverLocked)
1232          {
1233            String lockFile = LockFileManager.getServerLockFileName();
1234            try
1235            {
1236              StringBuilder failureReason = new StringBuilder();
1237              if (! LockFileManager.acquireExclusiveLock(lockFile, failureReason))
1238              {
1239                Message message = ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(
1240                    lockFile, String.valueOf(failureReason));
1241                throw new InitializationException(message);
1242              }
1243    
1244              serverLocked = true;
1245            }
1246            catch (InitializationException ie)
1247            {
1248              throw ie;
1249            }
1250            catch (Exception e)
1251            {
1252              if (debugEnabled())
1253              {
1254                TRACER.debugCaught(DebugLogLevel.ERROR, e);
1255              }
1256    
1257              Message message = ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(
1258                  lockFile, stackTraceToSingleLineString(e));
1259              throw new InitializationException(message, e);
1260            }
1261          }
1262    
1263    
1264          // Determine whether or not we should start the connection handlers.
1265          boolean startConnectionHandlers =
1266               (! environmentConfig.disableConnectionHandlers());
1267    
1268    
1269          // Initialize all the schema elements.
1270          initializeSchema();
1271    
1272    
1273          // Initialize the core Directory Server configuration.
1274          coreConfigManager = new CoreConfigManager();
1275          coreConfigManager.initializeCoreConfig();
1276    
1277    
1278          // Initialize the Directory Server crypto manager.
1279          initializeCryptoManager();
1280    
1281    
1282          // Initialize the log rotation policies.
1283          rotationPolicyConfigManager = new LogRotationPolicyConfigManager();
1284          rotationPolicyConfigManager.initializeLogRotationPolicyConfig();
1285    
1286          // Initialize the log retention policies.
1287          retentionPolicyConfigManager = new LogRetentionPolicyConfigManager();
1288          retentionPolicyConfigManager.initializeLogRetentionPolicyConfig();
1289    
1290    
1291          // Initialize the server loggers.
1292          loggerConfigManager = new LoggerConfigManager();
1293          loggerConfigManager.initializeLoggerConfig();
1294    
1295    
1296          // Initialize the server alert handlers.
1297          initializeAlertHandlers();
1298    
1299    
1300          // Initialize the default entry cache. We have to have one before
1301          // <CODE>initializeBackends()</CODE> method kicks in further down.
1302          entryCacheConfigManager = new EntryCacheConfigManager();
1303          entryCacheConfigManager.initializeDefaultEntryCache();
1304    
1305    
1306          // Initialize the key manager provider.
1307          keyManagerProviderConfigManager = new KeyManagerProviderConfigManager();
1308          keyManagerProviderConfigManager.initializeKeyManagerProviders();
1309    
1310    
1311          // Initialize the trust manager provider.
1312          trustManagerProviderConfigManager =
1313               new TrustManagerProviderConfigManager();
1314          trustManagerProviderConfigManager.initializeTrustManagerProviders();
1315    
1316    
1317          // Initialize the certificate mapper.
1318          certificateMapperConfigManager = new CertificateMapperConfigManager();
1319          certificateMapperConfigManager.initializeCertificateMappers();
1320    
1321    
1322          // Initialize the identity mappers.
1323          initializeIdentityMappers();
1324    
1325    
1326          // Initialize the root DNs.
1327          rootDNConfigManager = new RootDNConfigManager();
1328          rootDNConfigManager.initializeRootDNs();
1329    
1330    
1331          // Initialize the group manager.
1332          initializeGroupManager();
1333    
1334          // Initialize the access control handler.
1335          AccessControlConfigManager.getInstance().initializeAccessControl();
1336    
1337          // Initialize all the backends and their associated suffixes
1338          // and initialize the workflows when workflow configuration mode
1339          // is auto.
1340          initializeBackends();
1341    
1342          // When workflow configuration mode is manual, do configure the
1343          // workflows now, else just configure the remaining workflows
1344          // (rootDSE and config backend).
1345          if (workflowConfigurationModeIsAuto())
1346          {
1347            createAndRegisterRemainingWorkflows();
1348          }
1349          else
1350          {
1351            configureWorkflowsManual();
1352          }
1353    
1354          // Check for and initialize user configured entry cache if any,
1355          // if not stick with default entry cache initialized earlier.
1356          entryCacheConfigManager.initializeEntryCache();
1357    
1358          // Reset the map as we can no longer guarantee offline state.
1359          directoryServer.offlineBackendsStateIDs.clear();
1360    
1361          // Register the supported controls and supported features.
1362          initializeSupportedControls();
1363          initializeSupportedFeatures();
1364    
1365    
1366          // Initialize all the extended operation handlers.
1367          initializeExtendedOperations();
1368    
1369    
1370          // Initialize all the SASL mechanism handlers.
1371          initializeSASLMechanisms();
1372    
1373    
1374          // Initialize all the virtual attribute handlers.
1375          initializeVirtualAttributes();
1376    
1377    
1378          // Initialize all the connection handlers.
1379          if (startConnectionHandlers)
1380          {
1381            initializeConnectionHandlers();
1382          }
1383    
1384    
1385          // Initialize all the monitor providers.
1386          monitorConfigManager = new MonitorConfigManager();
1387          monitorConfigManager.initializeMonitorProviders();
1388    
1389    
1390          // Initialize all the password policy components.
1391          initializePasswordPolicyComponents();
1392    
1393    
1394          // Load and initialize all the plugins, and then call the registered
1395          // startup plugins.
1396          initializePlugins();
1397    
1398    
1399          // Initialize any synchronization providers that may be defined.
1400          synchronizationProviderConfigManager =
1401               new SynchronizationProviderConfigManager();
1402          synchronizationProviderConfigManager.initializeSynchronizationProviders();
1403    
1404    
1405          // Create and initialize the work queue.
1406          workQueue = new WorkQueueConfigManager().initializeWorkQueue();
1407    
1408    
1409          PluginResult.Startup startupPluginResult =
1410               pluginConfigManager.invokeStartupPlugins();
1411          if (! startupPluginResult.continueProcessing())
1412          {
1413            Message message = ERR_STARTUP_PLUGIN_ERROR.
1414                get(startupPluginResult.getErrorMessage(),
1415                    startupPluginResult.getErrorMessage().getDescriptor().getId());
1416            throw new InitializationException(message);
1417          }
1418    
1419    
1420          if (startConnectionHandlers)
1421          {
1422            startConnectionHandlers();
1423            new IdleTimeLimitThread().start();
1424          }
1425    
1426    
1427          // Create an object to synchronize ADS with the crypto manager.
1428          new CryptoManagerSync();
1429    
1430          // If we should write a copy of the config on successful startup, then do
1431          // so now.
1432          if (saveConfigOnSuccessfulStartup)
1433          {
1434            configHandler.writeSuccessfulStartupConfig();
1435          }
1436    
1437    
1438          // Mark the current time as the start time and indicate that the server is
1439          // now running.
1440          startUpTime  = System.currentTimeMillis();
1441          startTimeUTC = TimeThread.getGMTTime();
1442          isRunning    = true;
1443    
1444          Message message = NOTE_DIRECTORY_SERVER_STARTED.get();
1445          logError(message);
1446          sendAlertNotification(this, ALERT_TYPE_SERVER_STARTED, message);
1447    
1448          // Force the root connection to be initialized.
1449          InternalClientConnection.getRootConnection();
1450    
1451          // If a server.starting file exists, then remove it.
1452          File serverStartingFile =
1453                    new File(configHandler.getServerRoot() + File.separator +
1454                             "logs" + File.separator + "server.starting");
1455          if (serverStartingFile.exists())
1456          {
1457            serverStartingFile.delete();
1458          }
1459        }
1460      }
1461    
1462    
1463    
1464      /**
1465       * Registers a basic set of matching rules with the server that should always
1466       * be available regardless of the server configuration and may be needed for
1467       * configuration processing.
1468       */
1469      private void bootstrapMatchingRules()
1470      {
1471        try
1472        {
1473          ApproximateMatchingRule matchingRule =
1474               new DoubleMetaphoneApproximateMatchingRule();
1475          matchingRule.initializeMatchingRule(null);
1476          registerApproximateMatchingRule(matchingRule, true);
1477        }
1478        catch (Exception e)
1479        {
1480          if (debugEnabled())
1481          {
1482            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1483          }
1484    
1485          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1486              get(DoubleMetaphoneApproximateMatchingRule.class.getName(),
1487                  stackTraceToSingleLineString(e));
1488          logError(message);
1489        }
1490    
1491    
1492        try
1493        {
1494          EqualityMatchingRule matchingRule = new BooleanEqualityMatchingRule();
1495          matchingRule.initializeMatchingRule(null);
1496          registerEqualityMatchingRule(matchingRule, true);
1497        }
1498        catch (Exception e)
1499        {
1500          if (debugEnabled())
1501          {
1502            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1503          }
1504    
1505          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1506              get(BooleanEqualityMatchingRule.class.getName(),
1507                  stackTraceToSingleLineString(e));
1508          logError(message);
1509        }
1510    
1511    
1512        try
1513        {
1514          EqualityMatchingRule matchingRule = new CaseExactEqualityMatchingRule();
1515          matchingRule.initializeMatchingRule(null);
1516          registerEqualityMatchingRule(matchingRule, true);
1517        }
1518        catch (Exception e)
1519        {
1520          if (debugEnabled())
1521          {
1522            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1523          }
1524    
1525          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1526              get(CaseExactEqualityMatchingRule.class.getName(),
1527                  stackTraceToSingleLineString(e));
1528          logError(message);
1529        }
1530    
1531    
1532        try
1533        {
1534          EqualityMatchingRule matchingRule =
1535               new CaseExactIA5EqualityMatchingRule();
1536          matchingRule.initializeMatchingRule(null);
1537          registerEqualityMatchingRule(matchingRule, true);
1538        }
1539        catch (Exception e)
1540        {
1541          if (debugEnabled())
1542          {
1543            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1544          }
1545    
1546          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1547              get(CaseExactIA5EqualityMatchingRule.class.getName(),
1548                  stackTraceToSingleLineString(e));
1549          logError(message);
1550        }
1551    
1552    
1553        try
1554        {
1555          EqualityMatchingRule matchingRule = new CaseIgnoreEqualityMatchingRule();
1556          matchingRule.initializeMatchingRule(null);
1557          registerEqualityMatchingRule(matchingRule, true);
1558        }
1559        catch (Exception e)
1560        {
1561          if (debugEnabled())
1562          {
1563            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1564          }
1565    
1566          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1567              get(CaseIgnoreEqualityMatchingRule.class.getName(),
1568                  stackTraceToSingleLineString(e));
1569          logError(message);
1570        }
1571    
1572    
1573        try
1574        {
1575          EqualityMatchingRule matchingRule =
1576               new CaseIgnoreIA5EqualityMatchingRule();
1577          matchingRule.initializeMatchingRule(null);
1578          registerEqualityMatchingRule(matchingRule, true);
1579        }
1580        catch (Exception e)
1581        {
1582          if (debugEnabled())
1583          {
1584            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1585          }
1586    
1587          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1588              get(CaseIgnoreIA5EqualityMatchingRule.class.getName(),
1589                  stackTraceToSingleLineString(e));
1590          logError(message);
1591        }
1592    
1593    
1594        try
1595        {
1596          EqualityMatchingRule matchingRule =
1597               new DistinguishedNameEqualityMatchingRule();
1598          matchingRule.initializeMatchingRule(null);
1599          registerEqualityMatchingRule(matchingRule, true);
1600        }
1601        catch (Exception e)
1602        {
1603          if (debugEnabled())
1604          {
1605            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1606          }
1607    
1608          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1609              get(DistinguishedNameEqualityMatchingRule.class.getName(),
1610                  stackTraceToSingleLineString(e));
1611          logError(message);
1612        }
1613    
1614    
1615        try
1616        {
1617          EqualityMatchingRule matchingRule =
1618               new GeneralizedTimeEqualityMatchingRule();
1619          matchingRule.initializeMatchingRule(null);
1620          registerEqualityMatchingRule(matchingRule, true);
1621        }
1622        catch (Exception e)
1623        {
1624          if (debugEnabled())
1625          {
1626            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1627          }
1628    
1629          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1630              get(GeneralizedTimeEqualityMatchingRule.class.getName(),
1631                  stackTraceToSingleLineString(e));
1632          logError(message);
1633        }
1634    
1635    
1636        try
1637        {
1638          EqualityMatchingRule matchingRule = new IntegerEqualityMatchingRule();
1639          matchingRule.initializeMatchingRule(null);
1640          registerEqualityMatchingRule(matchingRule, true);
1641        }
1642        catch (Exception e)
1643        {
1644          if (debugEnabled())
1645          {
1646            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1647          }
1648    
1649          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1650              get(IntegerEqualityMatchingRule.class.getName(),
1651                  stackTraceToSingleLineString(e));
1652          logError(message);
1653        }
1654    
1655    
1656        try
1657        {
1658          EqualityMatchingRule matchingRule = new OctetStringEqualityMatchingRule();
1659          matchingRule.initializeMatchingRule(null);
1660          registerEqualityMatchingRule(matchingRule, true);
1661        }
1662        catch (Exception e)
1663        {
1664          if (debugEnabled())
1665          {
1666            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1667          }
1668    
1669          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1670              get(OctetStringEqualityMatchingRule.class.getName(),
1671                  stackTraceToSingleLineString(e));
1672          logError(message);
1673        }
1674    
1675    
1676        try
1677        {
1678          EqualityMatchingRule matchingRule =
1679               new ObjectIdentifierEqualityMatchingRule();
1680          matchingRule.initializeMatchingRule(null);
1681          registerEqualityMatchingRule(matchingRule, true);
1682        }
1683        catch (Exception e)
1684        {
1685          if (debugEnabled())
1686          {
1687            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1688          }
1689    
1690          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1691              get(ObjectIdentifierEqualityMatchingRule.class.getName(),
1692                  stackTraceToSingleLineString(e));
1693          logError(message);
1694        }
1695    
1696    
1697        try
1698        {
1699          EqualityMatchingRule matchingRule =
1700               new TelephoneNumberEqualityMatchingRule();
1701          matchingRule.initializeMatchingRule(null);
1702          registerEqualityMatchingRule(matchingRule, true);
1703        }
1704        catch (Exception e)
1705        {
1706          if (debugEnabled())
1707          {
1708            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1709          }
1710    
1711          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1712              get(TelephoneNumberEqualityMatchingRule.class.getName(),
1713                  stackTraceToSingleLineString(e));
1714          logError(message);
1715        }
1716    
1717    
1718        try
1719        {
1720          OrderingMatchingRule matchingRule = new CaseExactOrderingMatchingRule();
1721          matchingRule.initializeMatchingRule(null);
1722          registerOrderingMatchingRule(matchingRule, true);
1723        }
1724        catch (Exception e)
1725        {
1726          if (debugEnabled())
1727          {
1728            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1729          }
1730    
1731          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1732              get(CaseExactOrderingMatchingRule.class.getName(),
1733                  stackTraceToSingleLineString(e));
1734          logError(message);
1735        }
1736    
1737    
1738        try
1739        {
1740          OrderingMatchingRule matchingRule = new CaseIgnoreOrderingMatchingRule();
1741          matchingRule.initializeMatchingRule(null);
1742          registerOrderingMatchingRule(matchingRule, true);
1743        }
1744        catch (Exception e)
1745        {
1746          if (debugEnabled())
1747          {
1748            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1749          }
1750    
1751          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1752              get(CaseIgnoreOrderingMatchingRule.class.getName(),
1753                  stackTraceToSingleLineString(e));
1754          logError(message);
1755        }
1756    
1757    
1758        try
1759        {
1760          OrderingMatchingRule matchingRule =
1761               new GeneralizedTimeOrderingMatchingRule();
1762          matchingRule.initializeMatchingRule(null);
1763          registerOrderingMatchingRule(matchingRule, true);
1764        }
1765        catch (Exception e)
1766        {
1767          if (debugEnabled())
1768          {
1769            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1770          }
1771    
1772          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1773              get(GeneralizedTimeOrderingMatchingRule.class.getName(),
1774                  stackTraceToSingleLineString(e));
1775          logError(message);
1776        }
1777    
1778    
1779        try
1780        {
1781          OrderingMatchingRule matchingRule = new IntegerOrderingMatchingRule();
1782          matchingRule.initializeMatchingRule(null);
1783          registerOrderingMatchingRule(matchingRule, true);
1784        }
1785        catch (Exception e)
1786        {
1787          if (debugEnabled())
1788          {
1789            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1790          }
1791    
1792          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1793              get(IntegerOrderingMatchingRule.class.getName(),
1794                  stackTraceToSingleLineString(e));
1795          logError(message);
1796        }
1797    
1798    
1799        try
1800        {
1801          OrderingMatchingRule matchingRule = new OctetStringOrderingMatchingRule();
1802          matchingRule.initializeMatchingRule(null);
1803          registerOrderingMatchingRule(matchingRule, true);
1804        }
1805        catch (Exception e)
1806        {
1807          if (debugEnabled())
1808          {
1809            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1810          }
1811    
1812          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1813              get(OctetStringOrderingMatchingRule.class.getName(),
1814                  stackTraceToSingleLineString(e));
1815          logError(message);
1816        }
1817    
1818    
1819        try
1820        {
1821          SubstringMatchingRule matchingRule = new CaseExactSubstringMatchingRule();
1822          matchingRule.initializeMatchingRule(null);
1823          registerSubstringMatchingRule(matchingRule, true);
1824        }
1825        catch (Exception e)
1826        {
1827          if (debugEnabled())
1828          {
1829            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1830          }
1831    
1832          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1833              get(CaseExactSubstringMatchingRule.class.getName(),
1834                  stackTraceToSingleLineString(e));
1835          logError(message);
1836        }
1837    
1838    
1839        try
1840        {
1841          SubstringMatchingRule matchingRule =
1842               new CaseExactIA5SubstringMatchingRule();
1843          matchingRule.initializeMatchingRule(null);
1844          registerSubstringMatchingRule(matchingRule, true);
1845        }
1846        catch (Exception e)
1847        {
1848          if (debugEnabled())
1849          {
1850            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1851          }
1852    
1853          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1854              get(CaseExactIA5SubstringMatchingRule.class.getName(),
1855                  stackTraceToSingleLineString(e));
1856          logError(message);
1857        }
1858    
1859    
1860        try
1861        {
1862          SubstringMatchingRule matchingRule =
1863               new CaseIgnoreSubstringMatchingRule();
1864          matchingRule.initializeMatchingRule(null);
1865          registerSubstringMatchingRule(matchingRule, true);
1866        }
1867        catch (Exception e)
1868        {
1869          if (debugEnabled())
1870          {
1871            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1872          }
1873    
1874          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1875              get(CaseIgnoreSubstringMatchingRule.class.getName(),
1876                  stackTraceToSingleLineString(e));
1877          logError(message);
1878        }
1879    
1880    
1881        try
1882        {
1883          SubstringMatchingRule matchingRule =
1884               new CaseIgnoreIA5SubstringMatchingRule();
1885          matchingRule.initializeMatchingRule(null);
1886          registerSubstringMatchingRule(matchingRule, true);
1887        }
1888        catch (Exception e)
1889        {
1890          if (debugEnabled())
1891          {
1892            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1893          }
1894    
1895          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1896              get(CaseIgnoreIA5SubstringMatchingRule.class.getName(),
1897                  stackTraceToSingleLineString(e));
1898          logError(message);
1899        }
1900    
1901    
1902        try
1903        {
1904          SubstringMatchingRule matchingRule =
1905               new OctetStringSubstringMatchingRule();
1906          matchingRule.initializeMatchingRule(null);
1907          registerSubstringMatchingRule(matchingRule, true);
1908        }
1909        catch (Exception e)
1910        {
1911          if (debugEnabled())
1912          {
1913            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1914          }
1915    
1916          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1917              get(OctetStringSubstringMatchingRule.class.getName(),
1918                  stackTraceToSingleLineString(e));
1919          logError(message);
1920        }
1921    
1922    
1923        try
1924        {
1925          SubstringMatchingRule matchingRule =
1926               new TelephoneNumberSubstringMatchingRule();
1927          matchingRule.initializeMatchingRule(null);
1928          registerSubstringMatchingRule(matchingRule, true);
1929        }
1930        catch (Exception e)
1931        {
1932          if (debugEnabled())
1933          {
1934            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1935          }
1936    
1937          Message message = ERR_CANNOT_BOOTSTRAP_MATCHING_RULE.
1938              get(TelephoneNumberSubstringMatchingRule.class.getName(),
1939                  stackTraceToSingleLineString(e));
1940          logError(message);
1941        }
1942      }
1943    
1944    
1945    
1946      /**
1947       * Registers a basic set of attribute syntaxes with the server that should
1948       * always be available regardless of the server configuration and may be
1949       * needed for configuration processing.
1950       */
1951      private void bootstrapAttributeSyntaxes()
1952      {
1953        try
1954        {
1955          AttributeTypeSyntax syntax = new AttributeTypeSyntax();
1956          syntax.initializeSyntax(null);
1957          registerAttributeSyntax(syntax, true);
1958        }
1959        catch (Exception e)
1960        {
1961          if (debugEnabled())
1962          {
1963            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1964          }
1965    
1966          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.get(
1967              AttributeTypeSyntax.class.getName(), stackTraceToSingleLineString(e));
1968          logError(message);
1969        }
1970    
1971    
1972        try
1973        {
1974          defaultBinarySyntax = new BinarySyntax();
1975          defaultBinarySyntax.initializeSyntax(null);
1976          registerAttributeSyntax(defaultBinarySyntax, true);
1977        }
1978        catch (Exception e)
1979        {
1980          if (debugEnabled())
1981          {
1982            TRACER.debugCaught(DebugLogLevel.ERROR, e);
1983          }
1984    
1985          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.get(
1986              BinarySyntax.class.getName(), stackTraceToSingleLineString(e));
1987          logError(message);
1988        }
1989    
1990    
1991        try
1992        {
1993          defaultBooleanSyntax = new BooleanSyntax();
1994          defaultBooleanSyntax.initializeSyntax(null);
1995          registerAttributeSyntax(defaultBooleanSyntax, true);
1996        }
1997        catch (Exception e)
1998        {
1999          if (debugEnabled())
2000          {
2001            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2002          }
2003    
2004          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.get(
2005              BooleanSyntax.class.getName(), stackTraceToSingleLineString(e));
2006          logError(message);
2007        }
2008    
2009    
2010        try
2011        {
2012          defaultStringSyntax = new DirectoryStringSyntax();
2013          defaultStringSyntax.initializeSyntax(null);
2014          registerAttributeSyntax(defaultStringSyntax, true);
2015          defaultSyntax = defaultStringSyntax;
2016        }
2017        catch (Exception e)
2018        {
2019          if (debugEnabled())
2020          {
2021            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2022          }
2023    
2024          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.
2025              get(DirectoryStringSyntax.class.getName(),
2026                  stackTraceToSingleLineString(e));
2027          logError(message);
2028        }
2029    
2030    
2031        try
2032        {
2033          defaultDNSyntax = new DistinguishedNameSyntax();
2034          defaultDNSyntax.initializeSyntax(null);
2035          registerAttributeSyntax(defaultDNSyntax, true);
2036        }
2037        catch (Exception e)
2038        {
2039          if (debugEnabled())
2040          {
2041            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2042          }
2043    
2044          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.
2045              get(DistinguishedNameSyntax.class.getName(),
2046                  stackTraceToSingleLineString(e));
2047          logError(message);
2048        }
2049    
2050    
2051        try
2052        {
2053          IA5StringSyntax syntax = new IA5StringSyntax();
2054          syntax.initializeSyntax(null);
2055          registerAttributeSyntax(syntax, true);
2056        }
2057        catch (Exception e)
2058        {
2059          if (debugEnabled())
2060          {
2061            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2062          }
2063    
2064          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.get(
2065              IA5StringSyntax.class.getName(), stackTraceToSingleLineString(e));
2066          logError(message);
2067        }
2068    
2069    
2070        try
2071        {
2072          defaultIntegerSyntax = new IntegerSyntax();
2073          defaultIntegerSyntax.initializeSyntax(null);
2074          registerAttributeSyntax(defaultIntegerSyntax, true);
2075        }
2076        catch (Exception e)
2077        {
2078          if (debugEnabled())
2079          {
2080            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2081          }
2082    
2083          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.get(
2084              IntegerSyntax.class.getName(), stackTraceToSingleLineString(e));
2085          logError(message);
2086        }
2087    
2088    
2089        try
2090        {
2091          GeneralizedTimeSyntax syntax = new GeneralizedTimeSyntax();
2092          syntax.initializeSyntax(null);
2093          registerAttributeSyntax(syntax, true);
2094        }
2095        catch (Exception e)
2096        {
2097          if (debugEnabled())
2098          {
2099            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2100          }
2101    
2102          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.
2103              get(GeneralizedTimeSyntax.class.getName(),
2104                  stackTraceToSingleLineString(e));
2105          logError(message);
2106        }
2107    
2108    
2109        try
2110        {
2111          ObjectClassSyntax syntax = new ObjectClassSyntax();
2112          syntax.initializeSyntax(null);
2113          registerAttributeSyntax(syntax, true);
2114        }
2115        catch (Exception e)
2116        {
2117          if (debugEnabled())
2118          {
2119            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2120          }
2121    
2122          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.get(
2123              ObjectClassSyntax.class.getName(), stackTraceToSingleLineString(e));
2124          logError(message);
2125        }
2126    
2127    
2128        try
2129        {
2130          OIDSyntax syntax = new OIDSyntax();
2131          syntax.initializeSyntax(null);
2132          registerAttributeSyntax(syntax, true);
2133        }
2134        catch (Exception e)
2135        {
2136          if (debugEnabled())
2137          {
2138            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2139          }
2140    
2141          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.get(
2142              OIDSyntax.class.getName(), stackTraceToSingleLineString(e));
2143          logError(message);
2144        }
2145    
2146    
2147        try
2148        {
2149          TelephoneNumberSyntax syntax = new TelephoneNumberSyntax();
2150          syntax.initializeSyntax(null);
2151          registerAttributeSyntax(syntax, true);
2152        }
2153        catch (Exception e)
2154        {
2155          if (debugEnabled())
2156          {
2157            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2158          }
2159    
2160          Message message = ERR_CANNOT_BOOTSTRAP_SYNTAX.
2161              get(TelephoneNumberSyntax.class.getName(),
2162                  stackTraceToSingleLineString(e));
2163          logError(message);
2164        }
2165      }
2166    
2167    
2168    
2169      /**
2170       * Retrieves the authenticated users manager for the Directory Server.
2171       *
2172       * @return  The authenticated users manager for the Directory Server.
2173       */
2174      public static AuthenticatedUsers getAuthenticatedUsers()
2175      {
2176        return directoryServer.authenticatedUsers;
2177      }
2178    
2179    
2180    
2181      /**
2182       * Initializes the crypto manager for the Directory Server.
2183       *
2184       * @throws  ConfigException  If a configuration problem is identified while
2185       *                           initializing the crypto manager.
2186       *
2187       * @throws  InitializationException  If a problem occurs while initializing
2188       *                                   the crypto manager that is not related
2189       *                                   to the server configuration.
2190       */
2191      public void initializeCryptoManager()
2192             throws ConfigException, InitializationException
2193      {
2194        RootCfg root =
2195             ServerManagementContext.getInstance().getRootConfiguration();
2196        CryptoManagerCfg cryptoManagerCfg = root.getCryptoManager();
2197        cryptoManager = new CryptoManagerImpl(cryptoManagerCfg);
2198      }
2199    
2200    
2201    
2202      /**
2203       * Retrieves a reference to the Directory Server crypto manager.
2204       *
2205       * @return  A reference to the Directory Server crypto manager.
2206       */
2207      public static CryptoManagerImpl getCryptoManager()
2208      {
2209        return directoryServer.cryptoManager;
2210      }
2211    
2212    
2213    
2214      /**
2215       * Indicates whether the Directory Server is configured with information about
2216       * one or more mail servers and may therefore be used to send e-mail messages.
2217       *
2218       * @return  {@code true} if the Directory Server is configured to be able to
2219       *          send e-mail messages, or {@code false} if not.
2220       */
2221      public static boolean mailServerConfigured()
2222      {
2223        return ((directoryServer.mailServerPropertySets != null) &&
2224                (! directoryServer.mailServerPropertySets.isEmpty()));
2225      }
2226    
2227    
2228    
2229      /**
2230       * Specifies the set of mail server properties that should be used for SMTP
2231       * communication.
2232       *
2233       * @param  mailServerPropertySets  A list of {@code Properties} objects that
2234       *                                 provide information that can be used to
2235       *                                 communicate with SMTP servers.
2236       */
2237      public static void setMailServerPropertySets(List<Properties>
2238                                                        mailServerPropertySets)
2239      {
2240        directoryServer.mailServerPropertySets = mailServerPropertySets;
2241      }
2242    
2243    
2244    
2245      /**
2246       * Retrieves the sets of information about the mail servers configured for use
2247       * by the Directory Server.
2248       *
2249       * @return  The sets of information about the mail servers configured for use
2250       *          by the Directory Server.
2251       */
2252      public static List<Properties> getMailServerPropertySets()
2253      {
2254        return directoryServer.mailServerPropertySets;
2255      }
2256    
2257    
2258    
2259      /**
2260       * Initializes the set of alert handlers defined in the Directory Server.
2261       *
2262       * @throws  ConfigException  If there is a configuration problem with any of
2263       *                           the alert handlers.
2264       *
2265       * @throws  InitializationException  If a problem occurs while initializing
2266       *                                   the alert handlers that is not related to
2267       *                                   the server configuration.
2268       */
2269      private void initializeAlertHandlers()
2270              throws ConfigException, InitializationException
2271      {
2272        new AlertHandlerConfigManager().initializeAlertHandlers();
2273      }
2274    
2275    
2276    
2277    
2278      /**
2279       * Initializes the schema elements for the Directory Server, including the
2280       * matching rules, attribute syntaxes, attribute types, and object classes.
2281       *
2282       * @throws  ConfigException  If there is a configuration problem with any of
2283       *                           the schema elements.
2284       *
2285       * @throws  InitializationException  If a problem occurs while initializing
2286       *                                   the schema elements that is not related
2287       *                                   to the server configuration.
2288       */
2289      public void initializeSchema()
2290             throws ConfigException, InitializationException
2291      {
2292        // Create the schema configuration manager, and initialize the schema from
2293        // the configuration.
2294        schemaConfigManager = new SchemaConfigManager();
2295        schema = schemaConfigManager.getSchema();
2296    
2297        schemaConfigManager.initializeMatchingRules();
2298        schemaConfigManager.initializeAttributeSyntaxes();
2299        schemaConfigManager.initializeSchemaFromFiles();
2300    
2301        // With server schema in place set compressed schema.
2302        compressedSchema = new DefaultCompressedSchema();
2303    
2304        // At this point we have a problem, because none of the configuration is
2305        // usable because it was all read before we had a schema (and therefore all
2306        // of the attribute types and objectclasses are bogus and won't let us find
2307        // anything).  So we have to re-read the configuration so that we can
2308        // continue the necessary startup process.  In the process, we want to
2309        // preserve any configuration add/delete/change listeners that might have
2310        // been registered with the old configuration (which will primarily be
2311        // schema elements) so they can be re-registered with the new configuration.
2312        LinkedHashMap<String,List<ConfigAddListener>> addListeners =
2313             new LinkedHashMap<String,List<ConfigAddListener>>();
2314        LinkedHashMap<String,List<ConfigDeleteListener>> deleteListeners =
2315             new LinkedHashMap<String,List<ConfigDeleteListener>>();
2316        LinkedHashMap<String,List<ConfigChangeListener>> changeListeners =
2317             new LinkedHashMap<String,List<ConfigChangeListener>>();
2318        getChangeListeners(configHandler.getConfigRootEntry(), addListeners,
2319                           deleteListeners, changeListeners);
2320    
2321        try
2322        {
2323          configHandler.finalizeConfigHandler();
2324        }
2325        catch (Exception e)
2326        {
2327          if (debugEnabled())
2328          {
2329            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2330          }
2331        }
2332    
2333        try
2334        {
2335          configHandler.initializeConfigHandler(configFile.getAbsolutePath(), true);
2336        }
2337        catch (InitializationException ie)
2338        {
2339          if (debugEnabled())
2340          {
2341            TRACER.debugCaught(DebugLogLevel.ERROR, ie);
2342          }
2343    
2344          throw ie;
2345        }
2346        catch (Exception e)
2347        {
2348          if (debugEnabled())
2349          {
2350            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2351          }
2352    
2353          Message message =
2354              ERR_CANNOT_INITIALIZE_CONFIG_HANDLER.get(
2355                      String.valueOf(configClass),
2356                      String.valueOf(configFile),
2357                      e.getLocalizedMessage());
2358          throw new InitializationException(message);
2359        }
2360    
2361    
2362        // Re-register all of the change listeners with the configuration.
2363        for (String dnStr : addListeners.keySet())
2364        {
2365          try
2366          {
2367            DN dn = DN.decode(dnStr);
2368            for (ConfigAddListener listener : addListeners.get(dnStr))
2369            {
2370              configHandler.getConfigEntry(dn).registerAddListener(listener);
2371            }
2372          }
2373          catch (DirectoryException de)
2374          {
2375            // This should never happen, so we'll just re-throw it.
2376            throw new InitializationException(de.getMessageObject());
2377          }
2378        }
2379    
2380        for (String dnStr : deleteListeners.keySet())
2381        {
2382          try
2383          {
2384            DN dn = DN.decode(dnStr);
2385            for (ConfigDeleteListener listener : deleteListeners.get(dnStr))
2386            {
2387              configHandler.getConfigEntry(dn).registerDeleteListener(listener);
2388            }
2389          }
2390          catch (DirectoryException de)
2391          {
2392            // This should never happen, so we'll just re-throw it.
2393            throw new InitializationException(de.getMessageObject());
2394          }
2395        }
2396    
2397        for (String dnStr : changeListeners.keySet())
2398        {
2399          try
2400          {
2401            DN dn = DN.decode(dnStr);
2402            for (ConfigChangeListener listener : changeListeners.get(dnStr))
2403            {
2404              configHandler.getConfigEntry(dn).registerChangeListener(listener);
2405            }
2406          }
2407          catch (DirectoryException de)
2408          {
2409            // This should never happen, so we'll just re-throw it.
2410            throw new InitializationException(de.getMessageObject());
2411          }
2412        }
2413      }
2414    
2415    
2416    
2417      /**
2418       * Retrieves the default compressed schema manager for the Directory Server.
2419       *
2420       * @return  The default compressed schema manager for the Directory Server.
2421       */
2422      public static CompressedSchema getDefaultCompressedSchema()
2423      {
2424        return directoryServer.compressedSchema;
2425      }
2426    
2427    
2428    
2429      /**
2430       * Gets all of the add, delete, and change listeners from the provided
2431       * configuration entry and all of its descendants and puts them in the
2432       * appropriate lists.
2433       *
2434       * @param  configEntry      The configuration entry to be processed, along
2435       *                          with all of its descendants.
2436       * @param  addListeners     The set of add listeners mapped to the DN of the
2437       *                          corresponding configuration entry.
2438       * @param  deleteListeners  The set of delete listeners mapped to the DN of
2439       *                          the corresponding configuration entry.
2440       * @param  changeListeners  The set of change listeners mapped to the DN of
2441       *                          the corresponding configuration entry.
2442       */
2443      private void getChangeListeners(ConfigEntry configEntry,
2444           LinkedHashMap<String,List<ConfigAddListener>> addListeners,
2445           LinkedHashMap<String,List<ConfigDeleteListener>> deleteListeners,
2446           LinkedHashMap<String,List<ConfigChangeListener>> changeListeners)
2447      {
2448        CopyOnWriteArrayList<ConfigAddListener> cfgAddListeners =
2449             configEntry.getAddListeners();
2450        if ((cfgAddListeners != null) && (cfgAddListeners.size() > 0))
2451        {
2452          addListeners.put(configEntry.getDN().toString(), cfgAddListeners);
2453        }
2454    
2455        CopyOnWriteArrayList<ConfigDeleteListener> cfgDeleteListeners =
2456             configEntry.getDeleteListeners();
2457        if ((cfgDeleteListeners != null) && (cfgDeleteListeners.size() > 0))
2458        {
2459          deleteListeners.put(configEntry.getDN().toString(), cfgDeleteListeners);
2460        }
2461    
2462        CopyOnWriteArrayList<ConfigChangeListener> cfgChangeListeners =
2463             configEntry.getChangeListeners();
2464        if ((cfgChangeListeners != null) && (cfgChangeListeners.size() > 0))
2465        {
2466          changeListeners.put(configEntry.getDN().toString(), cfgChangeListeners);
2467        }
2468    
2469        for (ConfigEntry child : configEntry.getChildren().values())
2470        {
2471          getChangeListeners(child, addListeners, deleteListeners, changeListeners);
2472        }
2473      }
2474    
2475    
2476    
2477      /**
2478       * Retrieves the set of backend initialization listeners that have been
2479       * registered with the Directory Server.  The contents of the returned set
2480       * must not be altered.
2481       *
2482       * @return  The set of backend initialization listeners that have been
2483       *          registered with the Directory Server.
2484       */
2485      public static Set<BackendInitializationListener>
2486                         getBackendInitializationListeners()
2487      {
2488        return directoryServer.backendInitializationListeners;
2489      }
2490    
2491    
2492    
2493      /**
2494       * Registers the provided backend initialization listener with the Directory
2495       * Server.
2496       *
2497       * @param  listener  The backend initialization listener to register with the
2498       *                   Directory Server.
2499       */
2500      public static void registerBackendInitializationListener(
2501                              BackendInitializationListener listener)
2502      {
2503        directoryServer.backendInitializationListeners.add(listener);
2504      }
2505    
2506    
2507    
2508      /**
2509       * Deegisters the provided backend initialization listener with the Directory
2510       * Server.
2511       *
2512       * @param  listener  The backend initialization listener to deregister with
2513       *                   the Directory Server.
2514       */
2515      public static void deregisterBackendInitializationListener(
2516                              BackendInitializationListener listener)
2517      {
2518        directoryServer.backendInitializationListeners.remove(listener);
2519      }
2520    
2521    
2522    
2523      /**
2524       * Initializes the set of backends defined in the Directory Server.
2525       *
2526       * @throws  ConfigException  If there is a configuration problem with any of
2527       *                           the backends.
2528       *
2529       * @throws  InitializationException  If a problem occurs while initializing
2530       *                                   the backends that is not related to the
2531       *                                   server configuration.
2532       */
2533      private void initializeBackends()
2534              throws ConfigException, InitializationException
2535      {
2536        backendConfigManager = new BackendConfigManager();
2537        backendConfigManager.initializeBackendConfig();
2538    
2539    
2540        // Make sure to initialize the root DSE backend separately after all other
2541        // backends.
2542        RootDSEBackendCfg rootDSECfg;
2543        try
2544        {
2545          RootCfg root =
2546               ServerManagementContext.getInstance().getRootConfiguration();
2547          rootDSECfg = root.getRootDSEBackend();
2548        }
2549        catch (Exception e)
2550        {
2551          if (debugEnabled())
2552          {
2553            TRACER.debugCaught(DebugLogLevel.ERROR, e);
2554          }
2555    
2556          Message message = ERR_CANNOT_GET_ROOT_DSE_CONFIG_ENTRY.get(
2557              stackTraceToSingleLineString(e));
2558          throw new InitializationException(message, e);
2559        }
2560    
2561        rootDSEBackend = new RootDSEBackend();
2562        rootDSEBackend.configureBackend(rootDSECfg);
2563        rootDSEBackend.initializeBackend();
2564      }
2565    
2566    
2567      /**
2568       * Deregisters a workflow with the default network group and
2569       * deregisters the workflow with the server. This method is
2570       * intended to be called when workflow configuration mode is
2571       * auto.
2572       *
2573       * @param baseDN  the DN of the workflow to deregister
2574       */
2575      private static void deregisterWorkflowWithDefaultNetworkGroup(
2576          DN baseDN
2577          )
2578      {
2579        // Get the default network group and deregister all the workflows
2580        // being configured for the backend (there is one worklfow per
2581        // backend base DN).
2582        NetworkGroup defaultNetworkGroup = NetworkGroup.getDefaultNetworkGroup();
2583        Workflow workflow = defaultNetworkGroup.deregisterWorkflow(baseDN);
2584        WorkflowImpl workflowImpl = (WorkflowImpl) workflow;
2585        workflowImpl.deregister();
2586      }
2587    
2588    
2589      /**
2590       * Creates a set of workflows for a given backend and registers the
2591       * workflows with the default network group. There are as many workflows
2592       * as base DNs defined in the backend. This method is intended
2593       * to be called when workflow configuration mode is auto.
2594       *
2595       * @param backend  the backend handled by the workflow
2596       *
2597       * @throws  DirectoryException  If the workflow ID for the provided
2598       *                              workflow conflicts with the workflow
2599       *                              ID of an existing workflow.
2600       */
2601      public static void createAndRegisterWorkflowsWithDefaultNetworkGroup(
2602          Backend backend
2603          ) throws DirectoryException
2604      {
2605        // Create a worklfow for each backend base DN and register the workflow
2606        // with the default network group.
2607        for (DN curBaseDN: backend.getBaseDNs())
2608        {
2609          WorkflowImpl workflowImpl = createWorkflow(curBaseDN, backend);
2610          registerWorkflowWithDefaultNetworkGroup(workflowImpl);
2611        }
2612      }
2613    
2614    
2615      /**
2616       * Creates one workflow for a given base DN in a backend.
2617       *
2618       * @param baseDN   the base DN of the workflow to create
2619       * @param backend  the backend handled by the workflow
2620       *
2621       * @return the newly created workflow
2622       *
2623       * @throws  DirectoryException  If the workflow ID for the provided
2624       *                              workflow conflicts with the workflow
2625       *                              ID of an existing workflow.
2626       */
2627      public static WorkflowImpl createWorkflow(
2628          DN      baseDN,
2629          Backend backend
2630          ) throws DirectoryException
2631      {
2632        String backendID = backend.getBackendID();
2633    
2634        // Create a root workflow element to encapsulate the backend
2635        LocalBackendWorkflowElement rootWE =
2636            LocalBackendWorkflowElement.createAndRegister(backendID, backend);
2637    
2638        // The workflow ID is "backendID + baseDN".
2639        // We cannot use backendID as workflow identifier because a backend
2640        // may handle several base DNs. We cannot use baseDN either because
2641        // we might want to configure several workflows handling the same
2642        // baseDN through different network groups. So a mix of both
2643        // backendID and baseDN should be ok.
2644        String workflowID = backend.getBackendID() + "#" + baseDN.toString();
2645    
2646        // Create the worklfow for the base DN and register the workflow with
2647        // the server.
2648        WorkflowImpl workflowImpl = new WorkflowImpl(
2649            workflowID, baseDN, (WorkflowElement) rootWE);
2650        workflowImpl.register();
2651    
2652        return workflowImpl;
2653      }
2654    
2655    
2656      /**
2657       * Registers a workflow with the default network group. This method
2658       * is intended to be called when workflow configuration mode is auto.
2659       *
2660       * @param workflowImpl  The workflow to register with the
2661       *                      default network group
2662       *
2663       * @throws  DirectoryException  If the workflow is already registered with
2664       *                              the default network group
2665       */
2666      private static void registerWorkflowWithDefaultNetworkGroup(
2667          WorkflowImpl workflowImpl
2668          ) throws DirectoryException
2669      {
2670        NetworkGroup defaultNetworkGroup = NetworkGroup.getDefaultNetworkGroup();
2671        defaultNetworkGroup.registerWorkflow(workflowImpl);
2672      }
2673    
2674    
2675      /**
2676       * Creates the missing workflows, one for the config backend and one for
2677       * the rootDSE backend.
2678       *
2679       * This method should be invoked whatever may be the workflow
2680       * configuration mode because config backend and rootDSE backend
2681       * will not have any configuration section, ever.
2682       *
2683       * @throws  ConfigException  If there is a configuration problem with any of
2684       *                           the workflows.
2685       */
2686      private void createAndRegisterRemainingWorkflows()
2687          throws ConfigException
2688      {
2689        try
2690        {
2691          createAndRegisterWorkflowsWithDefaultNetworkGroup (configHandler);
2692          createAndRegisterWorkflowsWithDefaultNetworkGroup (rootDSEBackend);
2693        }
2694        catch (DirectoryException de)
2695        {
2696          throw new ConfigException(de.getMessageObject());
2697        }
2698      }
2699    
2700    
2701      /**
2702       * Reconfigures the workflows when configuration mode has changed.
2703       * This method is invoked when workflows need to be reconfigured
2704       * while the server is running. If the reconfiguration is valid
2705       * then the method update the workflow configuration mode.
2706       *
2707       * @param oldMode  the current workflow configuration mode
2708       * @param newMode  the new workflow configuration mode
2709       */
2710      public static void reconfigureWorkflows(
2711          WorkflowConfigurationMode oldMode,
2712          WorkflowConfigurationMode newMode)
2713      {
2714        if ((oldMode == WorkflowConfigurationMode.AUTO)
2715            && (newMode == WorkflowConfigurationMode.MANUAL))
2716        {
2717          // move to manual mode
2718          try
2719          {
2720            directoryServer.configureWorkflowsManual();
2721            setWorkflowConfigurationMode(newMode);
2722          }
2723          catch (Exception e)
2724          {
2725            // rollback to auto mode
2726            try
2727            {
2728               directoryServer.configureWorkflowsAuto();
2729            }
2730            catch (Exception ee)
2731            {
2732              // rollback to auto mode is failing too!!
2733              // well, just log an error message and suggest the admin
2734              // to restart the server with the last valid config...
2735              Message message = ERR_CONFIG_WORKFLOW_CANNOT_CONFIGURE_MANUAL.get();
2736              logError(message);
2737            }
2738          }
2739        }
2740        else if ((oldMode == WorkflowConfigurationMode.MANUAL)
2741            && (newMode == WorkflowConfigurationMode.AUTO))
2742        {
2743          // move to auto mode
2744          try
2745          {
2746            directoryServer.configureWorkflowsAuto();
2747            setWorkflowConfigurationMode(newMode);
2748          }
2749          catch (Exception e)
2750          {
2751            // rollback to manual mode
2752            try
2753            {
2754               directoryServer.configureWorkflowsManual();
2755            }
2756            catch (Exception ee)
2757            {
2758              // rollback to auto mode is failing too!!
2759              // well, just log an error message and suggest the admin
2760              // to restart the server with the last valid config...
2761              Message message = ERR_CONFIG_WORKFLOW_CANNOT_CONFIGURE_AUTO.get();
2762              logError(message);
2763            }
2764          }
2765        }
2766      }
2767    
2768    
2769      /**
2770       * Configures the workflows when configuration mode is manual.
2771       *
2772       * @throws  ConfigException  If there is a problem with the Directory Server
2773       *                           configuration that prevents a critical component
2774       *                           from being instantiated.
2775       *
2776       * @throws  InitializationException  If some other problem occurs while
2777       *                                   attempting to initialize and start the
2778       *                                   Directory Server.
2779       */
2780      private void configureWorkflowsManual()
2781          throws ConfigException, InitializationException
2782      {
2783        // First of all re-initialize the current workflow configuration
2784        NetworkGroup.resetConfig();
2785        WorkflowImpl.resetConfig();
2786        WorkflowElement.resetConfig();
2787    
2788        // Then configure the workflows
2789        workflowElementConfigManager = new WorkflowElementConfigManager();
2790        workflowElementConfigManager.initializeWorkflowElements();
2791    
2792        workflowConfigManager = new WorkflowConfigManager();
2793        workflowConfigManager.initializeWorkflows();
2794    
2795        networkGroupConfigManager = new NetworkGroupConfigManager();
2796        networkGroupConfigManager.initializeNetworkGroups();
2797    
2798        // We now need to complete the workflow creation for the
2799        // config backend and rootDSE backend.
2800        createAndRegisterRemainingWorkflows();
2801      }
2802    
2803    
2804      /**
2805       * Configures the workflows when configuration mode is auto.
2806       *
2807       * @throws  ConfigException  If there is a problem with the Directory Server
2808       *                           configuration that prevents a critical component
2809       *                           from being instantiated.
2810       */
2811      private void configureWorkflowsAuto() throws ConfigException
2812      {
2813        // First of all re-initialize the current workflow configuration
2814        NetworkGroup.resetConfig();
2815        WorkflowImpl.resetConfig();
2816        WorkflowElement.resetConfig();
2817    
2818        // For each base DN in a backend create a workflow and register
2819        // the workflow with the default network group
2820        Map<String, Backend> backends = getBackends();
2821        for (String backendID: backends.keySet())
2822        {
2823          Backend backend = backends.get(backendID);
2824          for (DN baseDN: backend.getBaseDNs())
2825          {
2826            WorkflowImpl workflowImpl;
2827            try
2828            {
2829              workflowImpl = createWorkflow(baseDN, backend);
2830              registerWorkflowWithDefaultNetworkGroup(workflowImpl);
2831            }
2832            catch (DirectoryException e)
2833            {
2834              // TODO Auto-generated catch block
2835              throw new ConfigException(e.getMessageObject());
2836            }
2837          }
2838        }
2839    
2840        // We now need to complete the workflow creation for the
2841        // config backend and rootDSE backend.
2842        createAndRegisterRemainingWorkflows();
2843      }
2844    
2845    
2846      /**
2847       * Initializes the Directory Server group manager.
2848       *
2849       * @throws  ConfigException  If there is a configuration problem with any of
2850       *                           the group implementations.
2851       *
2852       * @throws  InitializationException  If a problem occurs while initializing
2853       *                                   the group manager that is not related to
2854       *                                   the server configuration.
2855       */
2856      public void initializeGroupManager()
2857             throws ConfigException, InitializationException
2858      {
2859        groupManager = new GroupManager();
2860        groupManager.initializeGroupImplementations();
2861    
2862        // The configuration backend has already been registered by this point
2863        // so we need to handle it explicitly.
2864        groupManager.performBackendInitializationProcessing(configHandler);
2865      }
2866    
2867    
2868    
2869      /**
2870       * Retrieves the Directory Server group manager.
2871       *
2872       * @return  The Directory Server group manager.
2873       */
2874      public static GroupManager getGroupManager()
2875      {
2876        return directoryServer.groupManager;
2877      }
2878    
2879    
2880    
2881      /**
2882       * Initializes the set of supported controls for the Directory Server.
2883       *
2884       * @throws  ConfigException  If there is a configuration problem with the
2885       *                           list of supported controls.
2886       *
2887       * @throws  InitializationException  If a problem occurs while initializing
2888       *                                   the set of supported controls that is not
2889       *                                   related to the server configuration.
2890       */
2891      private void initializeSupportedControls()
2892              throws ConfigException, InitializationException
2893      {
2894        supportedControls.add(OID_LDAP_ASSERTION);
2895        supportedControls.add(OID_LDAP_READENTRY_PREREAD);
2896        supportedControls.add(OID_LDAP_READENTRY_POSTREAD);
2897        supportedControls.add(OID_LDAP_NOOP_OPENLDAP_ASSIGNED);
2898        supportedControls.add(OID_PERSISTENT_SEARCH);
2899        supportedControls.add(OID_PROXIED_AUTH_V1);
2900        supportedControls.add(OID_PROXIED_AUTH_V2);
2901        supportedControls.add(OID_AUTHZID_REQUEST);
2902        supportedControls.add(OID_MATCHED_VALUES);
2903        supportedControls.add(OID_LDAP_SUBENTRIES);
2904        supportedControls.add(OID_PASSWORD_POLICY_CONTROL);
2905        supportedControls.add(OID_REAL_ATTRS_ONLY);
2906        supportedControls.add(OID_VIRTUAL_ATTRS_ONLY);
2907        supportedControls.add(OID_ACCOUNT_USABLE_CONTROL);
2908      }
2909    
2910    
2911    
2912      /**
2913       * Initializes the set of supported features for the Directory Server.
2914       *
2915       * @throws  ConfigException  If there is a configuration problem with the
2916       *                           list of supported features.
2917       *
2918       * @throws  InitializationException  If a problem occurs while initializing
2919       *                                   the set of supported features that is not
2920       *                                   related to the server configuration.
2921       */
2922      private void initializeSupportedFeatures()
2923              throws ConfigException, InitializationException
2924      {
2925        supportedFeatures.add(OID_ALL_OPERATIONAL_ATTRS_FEATURE);
2926        supportedFeatures.add(OID_MODIFY_INCREMENT_FEATURE);
2927        supportedFeatures.add(OID_TRUE_FALSE_FILTERS_FEATURE);
2928      }
2929    
2930    
2931    
2932      /**
2933       * Initializes the set of identity mappers for the Directory Server.
2934       *
2935       * @throws  ConfigException  If there is a configuration problem with any of
2936       *                           the extended operation handlers.
2937       *
2938       * @throws  InitializationException  If a problem occurs while initializing
2939       *                                   the extended operation handlers that is
2940       *                                   not related to the server configuration.
2941       */
2942      private void initializeIdentityMappers()
2943              throws ConfigException, InitializationException
2944      {
2945        identityMapperConfigManager = new IdentityMapperConfigManager();
2946        identityMapperConfigManager.initializeIdentityMappers();
2947      }
2948    
2949    
2950    
2951      /**
2952       * Initializes the set of extended operation handlers for the Directory
2953       * Server.
2954       *
2955       * @throws  ConfigException  If there is a configuration problem with any of
2956       *                           the extended operation handlers.
2957       *
2958       * @throws  InitializationException  If a problem occurs while initializing
2959       *                                   the extended operation handlers that is
2960       *                                   not related to the server configuration.
2961       */
2962      private void initializeExtendedOperations()
2963              throws ConfigException, InitializationException
2964      {
2965        extendedOperationConfigManager = new ExtendedOperationConfigManager();
2966        extendedOperationConfigManager.initializeExtendedOperationHandlers();
2967      }
2968    
2969    
2970    
2971      /**
2972       * Initializes the set of SASL mechanism handlers for the Directory Server.
2973       *
2974       * @throws  ConfigException  If there is a configuration problem with any of
2975       *                           the SASL mechanism handlers.
2976       *
2977       * @throws  InitializationException  If a problem occurs while initializing
2978       *                                   the SASL mechanism handlers that is not
2979       *                                   related to the server configuration.
2980       */
2981      private void initializeSASLMechanisms()
2982              throws ConfigException, InitializationException
2983      {
2984        saslConfigManager = new SASLConfigManager();
2985        saslConfigManager.initializeSASLMechanismHandlers();
2986      }
2987    
2988    
2989    
2990      /**
2991       * Initializes the set of virtual attributes that should be defined in the
2992       * Directory Server.
2993       *
2994       * @throws  ConfigException  If there is a configuration problem with any of
2995       *                           the virtual attribute handlers.
2996       *
2997       * @throws  InitializationException  If a problem occurs while initializing
2998       *                                   the virtual attribute handlers that is
2999       *                                   not related to the server configuration.
3000       */
3001      private void initializeVirtualAttributes()
3002              throws ConfigException, InitializationException
3003      {
3004        virtualAttributeConfigManager = new VirtualAttributeConfigManager();
3005        virtualAttributeConfigManager.initializeVirtualAttributes();
3006      }
3007    
3008    
3009    
3010      /**
3011       * Initializes the set of connection handlers that should be defined in the
3012       * Directory Server.
3013       *
3014       * @throws  ConfigException  If there is a configuration problem with any of
3015       *                           the connection handlers.
3016       *
3017       * @throws  InitializationException  If a problem occurs while initializing
3018       *                                   the connection handlers that is not
3019       *                                   related to the server configuration.
3020       */
3021      private void initializeConnectionHandlers()
3022              throws ConfigException, InitializationException
3023      {
3024        connectionHandlerConfigManager = new ConnectionHandlerConfigManager();
3025        connectionHandlerConfigManager.initializeConnectionHandlerConfig();
3026      }
3027    
3028    
3029    
3030      /**
3031       * Initializes the set of password policy components for use by the Directory
3032       * Server.
3033       *
3034       * @throws  ConfigException  If there is a configuration problem with any of
3035       *                           the password policy components.
3036       *
3037       * @throws  InitializationException  If a problem occurs while initializing
3038       *                                   the password policy components that is
3039       *                                   not related to the server configuration.
3040       */
3041      public void initializePasswordPolicyComponents()
3042             throws ConfigException, InitializationException
3043      {
3044        // Initialize all the password storage schemes.
3045        storageSchemeConfigManager = new PasswordStorageSchemeConfigManager();
3046        storageSchemeConfigManager.initializePasswordStorageSchemes();
3047    
3048    
3049        // Initialize all the password validators.
3050        passwordValidatorConfigManager = new PasswordValidatorConfigManager();
3051        passwordValidatorConfigManager.initializePasswordValidators();
3052    
3053    
3054        // Initialize all the password generators.
3055        passwordGeneratorConfigManager = new PasswordGeneratorConfigManager();
3056        passwordGeneratorConfigManager.initializePasswordGenerators();
3057    
3058    
3059        // Initialize the account status notification handlers.
3060        accountStatusNotificationHandlerConfigManager =
3061             new AccountStatusNotificationHandlerConfigManager();
3062        accountStatusNotificationHandlerConfigManager.
3063             initializeNotificationHandlers();
3064    
3065    
3066        // Initialize all the password policies.
3067        passwordPolicyConfigManager = new PasswordPolicyConfigManager();
3068        passwordPolicyConfigManager.initializePasswordPolicies();
3069      }
3070    
3071    
3072    
3073      /**
3074       * Retrieves the operating system on which the Directory Server is running.
3075       *
3076       * @return  The operating system on which the Directory Server is running.
3077       */
3078      public static OperatingSystem getOperatingSystem()
3079      {
3080        return directoryServer.operatingSystem;
3081      }
3082    
3083    
3084    
3085      /**
3086       * Retrieves the thread group that should be used by all threads associated
3087       * with the Directory Server.
3088       *
3089       * @return  The thread group that should be used by all threads associated
3090       *          with the Directory Server.
3091       */
3092      public static ThreadGroup getDirectoryThreadGroup()
3093      {
3094        return directoryServer.directoryThreadGroup;
3095      }
3096    
3097    
3098    
3099      /**
3100       * Retrieves a reference to the Directory Server configuration handler.
3101       *
3102       * @return  A reference to the Directory Server configuration handler.
3103       */
3104      public static ConfigHandler getConfigHandler()
3105      {
3106        return directoryServer.configHandler;
3107      }
3108    
3109    
3110    
3111      /**
3112       * Initializes the set of plugins defined in the Directory Server.
3113       *
3114       * @throws  ConfigException  If there is a configuration problem with any of
3115       *                           the Directory Server plugins.
3116       *
3117       * @throws  InitializationException  If a problem occurs while initializing
3118       *                                   the plugins that is not related to the
3119       *                                   server configuration.
3120       */
3121      public void initializePlugins()
3122             throws ConfigException, InitializationException
3123      {
3124        pluginConfigManager.initializePluginConfig(null);
3125      }
3126    
3127    
3128    
3129      /**
3130       * Initializes the set of plugins defined in the Directory Server.  Only the
3131       * specified types of plugins will be initialized.
3132       *
3133       * @param  pluginTypes  The set of plugin types for the plugins to
3134       *                      initialize.
3135       *
3136       * @throws  ConfigException  If there is a configuration problem with any of
3137       *                           the Directory Server plugins.
3138       *
3139       * @throws  InitializationException  If a problem occurs while initializing
3140       *                                   the plugins that is not related to the
3141       *                                   server configuration.
3142       */
3143      public void initializePlugins(Set<PluginType> pluginTypes)
3144             throws ConfigException, InitializationException
3145      {
3146        pluginConfigManager = new PluginConfigManager();
3147        pluginConfigManager.initializePluginConfig(pluginTypes);
3148      }
3149    
3150    
3151    
3152      /**
3153       * Retrieves a reference to the Directory Server plugin configuration manager.
3154       *
3155       * @return  A reference to the Directory Server plugin configuration manager.
3156       */
3157      public static PluginConfigManager getPluginConfigManager()
3158      {
3159        return directoryServer.pluginConfigManager;
3160      }
3161    
3162    
3163    
3164      /**
3165       * Retrieves the requested entry from the Directory Server configuration.
3166       *
3167       * @param  entryDN  The DN of the configuration entry to retrieve.
3168       *
3169       * @return  The requested entry from the Directory Server configuration.
3170       *
3171       * @throws  ConfigException  If a problem occurs while trying to retrieve the
3172       *                           requested entry.
3173       */
3174      public static ConfigEntry getConfigEntry(DN entryDN)
3175             throws ConfigException
3176      {
3177        return directoryServer.configHandler.getConfigEntry(entryDN);
3178      }
3179    
3180    
3181    
3182      /**
3183       * Retrieves the path to the root directory for this instance of the Directory
3184       * Server.
3185       *
3186       * @return  The path to the root directory for this instance of the Directory
3187       *          Server.
3188      */
3189      public static String getServerRoot()
3190      {
3191        if (directoryServer.configHandler == null)
3192        {
3193          File serverRoot = directoryServer.environmentConfig.getServerRoot();
3194          if (serverRoot != null)
3195          {
3196            return serverRoot.getAbsolutePath();
3197          }
3198    
3199          // We don't know where the server root is, so we'll have to assume it's
3200          // the current working directory.
3201          return System.getProperty("user.dir");
3202        }
3203        else
3204        {
3205          return directoryServer.configHandler.getServerRoot();
3206        }
3207      }
3208    
3209      /**
3210       * Retrieves the time that the Directory Server was started, in milliseconds
3211       * since the epoch.
3212       *
3213       * @return  The time that the Directory Server was started, in milliseconds
3214       *          since the epoch.
3215       */
3216      public static long getStartTime()
3217      {
3218        return directoryServer.startUpTime;
3219      }
3220    
3221    
3222    
3223      /**
3224       * Retrieves the time that the Directory Server was started, formatted in UTC.
3225       *
3226       * @return  The time that the Directory Server was started, formatted in UTC.
3227       */
3228      public static String getStartTimeUTC()
3229      {
3230        return directoryServer.startTimeUTC;
3231      }
3232    
3233    
3234    
3235      /**
3236       * Retrieves a reference to the Directory Server schema.
3237       *
3238       * @return  A reference to the Directory Server schema.
3239       */
3240      public static Schema getSchema()
3241      {
3242        return directoryServer.schema;
3243      }
3244    
3245    
3246    
3247      /**
3248       * Replaces the Directory Server schema with the provided schema.
3249       *
3250       * @param  schema  The new schema to use for the Directory Server.
3251       */
3252      public static void setSchema(Schema schema)
3253      {
3254        directoryServer.schema = schema;
3255      }
3256    
3257    
3258    
3259      /**
3260       * Retrieves a list of modifications detailing any schema changes that may
3261       * have been made with the server offline (e.g., by directly editing the
3262       * schema configuration files).  Note that this information will not be
3263       * available until the server backends (and in particular, the schema backend)
3264       * have been initialized.
3265       *
3266       * @return  A list of modifications detailing any schema changes that may have
3267       *          been made with the server offline, or an empty list if no offline
3268       *          schema changes have been detected.
3269       */
3270      public static List<Modification> getOfflineSchemaChanges()
3271      {
3272        return directoryServer.offlineSchemaChanges;
3273      }
3274    
3275    
3276    
3277      /**
3278       * Specifies a list of modifications detailing any schema changes that may
3279       * have been made with the server offline.
3280       *
3281       * @param  offlineSchemaChanges  A list of modifications detailing any schema
3282       *                               changes that may have been made with the
3283       *                               server offline.  It must not be {@code null}.
3284       */
3285      public static void setOfflineSchemaChanges(List<Modification>
3286                                                      offlineSchemaChanges)
3287      {
3288        ensureNotNull(offlineSchemaChanges);
3289    
3290        directoryServer.offlineSchemaChanges = offlineSchemaChanges;
3291      }
3292    
3293    
3294    
3295      /**
3296       * Retrieves the set of matching rules registered with the Directory Server.
3297       * The mapping will be between the lowercase name or OID for each matching
3298       * rule and the matching rule implementation.  The same matching rule instance
3299       * may be included multiple times with different keys.
3300       *
3301       * @return  The set of matching rules registered with the Directory Server.
3302       */
3303      public static ConcurrentHashMap<String,MatchingRule> getMatchingRules()
3304      {
3305        return directoryServer.schema.getMatchingRules();
3306      }
3307    
3308    
3309    
3310      /**
3311       * Retrieves the set of encoded matching rules that have been defined in the
3312       * Directory Server.
3313       *
3314       * @return  The set of encoded matching rules that have been defined in the
3315       *          Directory Server.
3316       */
3317      public static LinkedHashSet<AttributeValue> getMatchingRuleSet()
3318      {
3319        return directoryServer.schema.getMatchingRuleSet();
3320      }
3321    
3322    
3323    
3324      /**
3325       * Retrieves the matching rule with the specified name or OID.
3326       *
3327       * @param  lowerName  The lowercase name or OID for the matching rule to
3328       *                    retrieve.
3329       *
3330       * @return  The requested matching rule, or <CODE>null</CODE> if no such
3331       *          matching rule has been defined in the server.
3332       */
3333      public static MatchingRule getMatchingRule(String lowerName)
3334      {
3335        return directoryServer.schema.getMatchingRule(lowerName);
3336      }
3337    
3338    
3339    
3340      /**
3341       * Registers the provided matching rule with the Directory Server.
3342       *
3343       * @param  matchingRule       The matching rule to register with the server.
3344       * @param  overwriteExisting  Indicates whether to overwrite an existing
3345       *                            mapping if there are any conflicts (i.e.,
3346       *                            another matching rule with the same OID or
3347       *                            name).
3348       *
3349       * @throws  DirectoryException  If a conflict is encountered and the
3350       *                              <CODE>overwriteExisting</CODE> flag is set to
3351       *                              <CODE>false</CODE>
3352       */
3353      public static void registerMatchingRule(MatchingRule matchingRule,
3354                                              boolean overwriteExisting)
3355             throws DirectoryException
3356      {
3357        directoryServer.schema.registerMatchingRule(matchingRule,
3358                                                    overwriteExisting);
3359      }
3360    
3361    
3362    
3363      /**
3364       * Deregisters the provided matching rule with the Directory Server.
3365       *
3366       * @param  matchingRule  The matching rule to deregister with the server.
3367       */
3368      public static void deregisterMatchingRule(MatchingRule matchingRule)
3369      {
3370        directoryServer.schema.deregisterMatchingRule(matchingRule);
3371      }
3372    
3373    
3374    
3375      /**
3376       * Retrieves the set of approximate matching rules registered with the
3377       * Directory Server.  The mapping will be between the lowercase name or OID
3378       * for each approximate matching rule and the matching rule implementation.
3379       * The same approximate matching rule instance may be included multiple times
3380       * with different keys.
3381       *
3382       * @return  The set of approximate matching rules registered with the
3383       *          Directory Server.
3384       */
3385      public static ConcurrentHashMap<String,ApproximateMatchingRule>
3386                         getApproximateMatchingRules()
3387      {
3388        return directoryServer.schema.getApproximateMatchingRules();
3389      }
3390    
3391    
3392    
3393      /**
3394       * Retrieves the approximate matching rule with the specified name or OID.
3395       *
3396       * @param  lowerName  The lowercase name or OID for the approximate matching
3397       *                    rule to retrieve.
3398       *
3399       * @return  The requested approximate matching rule, or <CODE>null</CODE> if
3400       *          no such matching rule has been defined in the server.
3401       */
3402      public static ApproximateMatchingRule
3403                         getApproximateMatchingRule(String lowerName)
3404      {
3405        return directoryServer.schema.getApproximateMatchingRule(lowerName);
3406      }
3407    
3408    
3409    
3410      /**
3411       * Registers the provided approximate matching rule with the Directory
3412       * Server.
3413       *
3414       * @param  matchingRule       The matching rule to register with the server.
3415       * @param  overwriteExisting  Indicates whether to overwrite an existing
3416       *                            mapping if there are any conflicts (i.e.,
3417       *                            another matching rule with the same OID or
3418       *                            name).
3419       *
3420       * @throws  DirectoryException  If a conflict is encountered and the
3421       *                              <CODE>overwriteExisting</CODE> flag is set to
3422       *                              <CODE>false</CODE>
3423       */
3424      public static void registerApproximateMatchingRule(ApproximateMatchingRule
3425                                                              matchingRule,
3426                                                         boolean overwriteExisting)
3427             throws DirectoryException
3428      {
3429        directoryServer.schema.registerApproximateMatchingRule(matchingRule,
3430                                                               overwriteExisting);
3431      }
3432    
3433    
3434    
3435      /**
3436       * Deregisters the provided approximate matching rule with the Directory
3437       * Server.
3438       *
3439       * @param  matchingRule  The matching rule to deregister with the server.
3440       */
3441      public static void deregisterApproximateMatchingRule(ApproximateMatchingRule
3442                                                                matchingRule)
3443      {
3444        directoryServer.schema.deregisterApproximateMatchingRule(matchingRule);
3445      }
3446    
3447    
3448    
3449      /**
3450       * Retrieves the set of equality matching rules registered with the Directory
3451       * Server.  The mapping will be between the lowercase name or OID for each
3452       * equality matching rule and the matching rule implementation. The same
3453       * equality matching rule instance may be included multiple times with
3454       * different keys.
3455       *
3456       * @return  The set of equality matching rules registered with the Directory
3457       *          Server.
3458       */
3459      public static ConcurrentHashMap<String,EqualityMatchingRule>
3460                         getEqualityMatchingRules()
3461      {
3462        return directoryServer.schema.getEqualityMatchingRules();
3463      }
3464    
3465    
3466    
3467      /**
3468       * Retrieves the equality matching rule with the specified name or OID.
3469       *
3470       * @param  lowerName  The lowercase name or OID for the equality matching rule
3471       *                    to retrieve.
3472       *
3473       * @return  The requested equality matching rule, or <CODE>null</CODE> if no
3474       *          such matching rule has been defined in the server.
3475       */
3476      public static EqualityMatchingRule getEqualityMatchingRule(String lowerName)
3477      {
3478        return directoryServer.schema.getEqualityMatchingRule(lowerName);
3479      }
3480    
3481    
3482    
3483      /**
3484       * Registers the provided equality matching rule with the Directory Server.
3485       *
3486       * @param  matchingRule       The matching rule to register with the server.
3487       * @param  overwriteExisting  Indicates whether to overwrite an existing
3488       *                            mapping if there are any conflicts (i.e.,
3489       *                            another matching rule with the same OID or
3490       *                            name).
3491       *
3492       * @throws  DirectoryException  If a conflict is encountered and the
3493       *                              <CODE>overwriteExisting</CODE> flag is set to
3494       *                              <CODE>false</CODE>
3495       */
3496      public static void registerEqualityMatchingRule(EqualityMatchingRule
3497                                                           matchingRule,
3498                                                      boolean overwriteExisting)
3499             throws DirectoryException
3500      {
3501        directoryServer.schema.registerEqualityMatchingRule(matchingRule,
3502                                                            overwriteExisting);
3503      }
3504    
3505    
3506    
3507      /**
3508       * Deregisters the provided equality matching rule with the Directory Server.
3509       *
3510       * @param  matchingRule  The matching rule to deregister with the server.
3511       */
3512      public static void deregisterEqualityMatchingRule(EqualityMatchingRule
3513                                                        matchingRule)
3514      {
3515        directoryServer.schema.deregisterEqualityMatchingRule(matchingRule);
3516      }
3517    
3518    
3519    
3520      /**
3521       * Retrieves the set of ordering matching rules registered with the Directory
3522       * Server.  The mapping will be between the lowercase name or OID for each
3523       * ordering matching rule and the matching rule implementation. The same
3524       * ordering matching rule instance may be included multiple times with
3525       * different keys.
3526       *
3527       * @return  The set of ordering matching rules registered with the Directory
3528       *          Server.
3529       */
3530      public static ConcurrentHashMap<String,OrderingMatchingRule>
3531                         getOrderingMatchingRules()
3532      {
3533        return directoryServer.schema.getOrderingMatchingRules();
3534      }
3535    
3536    
3537    
3538      /**
3539       * Retrieves the ordering matching rule with the specified name or OID.
3540       *
3541       * @param  lowerName  The lowercase name or OID for the ordering matching rule
3542       *                    to retrieve.
3543       *
3544       * @return  The requested ordering matching rule, or <CODE>null</CODE> if no
3545       *          such matching rule has been defined in the server.
3546       */
3547      public static OrderingMatchingRule getOrderingMatchingRule(String lowerName)
3548      {
3549        return directoryServer.schema.getOrderingMatchingRule(lowerName);
3550      }
3551    
3552    
3553    
3554      /**
3555       * Registers the provided ordering matching rule with the Directory Server.
3556       *
3557       * @param  matchingRule       The matching rule to register with the server.
3558       * @param  overwriteExisting  Indicates whether to overwrite an existing
3559       *                            mapping if there are any conflicts (i.e.,
3560       *                            another matching rule with the same OID or
3561       *                            name).
3562       *
3563       * @throws  DirectoryException  If a conflict is encountered and the
3564       *                              <CODE>overwriteExisting</CODE> flag is set to
3565       *                              <CODE>false</CODE>
3566       */
3567      public static void registerOrderingMatchingRule(OrderingMatchingRule
3568                                                           matchingRule,
3569                                                      boolean overwriteExisting)
3570             throws DirectoryException
3571      {
3572        directoryServer.schema.registerOrderingMatchingRule(matchingRule,
3573                                                            overwriteExisting);
3574      }
3575    
3576    
3577    
3578      /**
3579       * Deregisters the provided ordering matching rule with the Directory Server.
3580       *
3581       * @param  matchingRule  The matching rule to deregister with the server.
3582       */
3583      public static void deregisterOrderingMatchingRule(OrderingMatchingRule
3584                                                        matchingRule)
3585      {
3586        directoryServer.schema.deregisterOrderingMatchingRule(matchingRule);
3587      }
3588    
3589    
3590    
3591      /**
3592       * Retrieves the set of substring matching rules registered with the Directory
3593       * Server.  The mapping will be between the lowercase name or OID for each
3594       * substring matching rule and the matching rule implementation.  The same
3595       * substring matching rule instance may be included multiple times with
3596       * different keys.
3597       *
3598       * @return  The set of substring matching rules registered with the Directory
3599       *          Server.
3600       */
3601      public static ConcurrentHashMap<String,SubstringMatchingRule>
3602                         getSubstringMatchingRules()
3603      {
3604        return directoryServer.schema.getSubstringMatchingRules();
3605      }
3606    
3607    
3608    
3609      /**
3610       * Retrieves the substring matching rule with the specified name or OID.
3611       *
3612       * @param  lowerName  The lowercase name or OID for the substring matching
3613       *                    rule to retrieve.
3614       *
3615       * @return  The requested substring matching rule, or <CODE>null</CODE> if no
3616       *          such matching rule has been defined in the server.
3617       */
3618      public static SubstringMatchingRule getSubstringMatchingRule(String lowerName)
3619      {
3620        return directoryServer.schema.getSubstringMatchingRule(lowerName);
3621      }
3622    
3623    
3624    
3625      /**
3626       * Registers the provided substring matching rule with the Directory Server.
3627       *
3628       * @param  matchingRule       The matching rule to register with the server.
3629       * @param  overwriteExisting  Indicates whether to overwrite an existing
3630       *                            mapping if there are any conflicts (i.e.,
3631       *                            another matching rule with the same OID or
3632       *                            name).
3633       *
3634       * @throws  DirectoryException  If a conflict is encountered and the
3635       *                              <CODE>overwriteExisting</CODE> flag is set to
3636       *                              <CODE>false</CODE>
3637       */
3638      public static void registerSubstringMatchingRule(SubstringMatchingRule
3639                                                            matchingRule,
3640                                                       boolean overwriteExisting)
3641             throws DirectoryException
3642      {
3643        directoryServer.schema.registerSubstringMatchingRule(matchingRule,
3644                                                             overwriteExisting);
3645      }
3646    
3647    
3648    
3649      /**
3650       * Deregisters the provided substring matching rule with the Directory Server.
3651       *
3652       * @param  matchingRule  The matching rule to deregister with the server.
3653       */
3654      public static void deregisterSubstringMatchingRule(SubstringMatchingRule
3655                                                         matchingRule)
3656      {
3657        directoryServer.schema.deregisterSubstringMatchingRule(matchingRule);
3658      }
3659    
3660    
3661    
3662      /**
3663       * Retrieves the set of objectclasses defined in the Directory Server.
3664       *
3665       * @return  The set of objectclasses defined in the Directory Server.
3666       */
3667      public static ConcurrentHashMap<String,ObjectClass> getObjectClasses()
3668      {
3669        return directoryServer.schema.getObjectClasses();
3670      }
3671    
3672    
3673    
3674      /**
3675       * Retrieves the set of encoded objectclasses that have been defined in the
3676       * Directory Server.
3677       *
3678       * @return  The set of encoded objectclasses that have been defined in the
3679       *          Directory Server.
3680       */
3681      public static LinkedHashSet<AttributeValue> getObjectClassSet()
3682      {
3683        return directoryServer.schema.getObjectClassSet();
3684      }
3685    
3686    
3687    
3688      /**
3689       * Retrieves the objectclass for the provided lowercase name or OID.
3690       *
3691       * @param  lowerName  The lowercase name or OID for the objectclass to
3692       *                    retrieve.
3693       *
3694       * @return  The requested objectclass, or <CODE>null</CODE> if there is no
3695       *          such objectclass defined in the server schema.
3696       */
3697      public static ObjectClass getObjectClass(String lowerName)
3698      {
3699        return directoryServer.schema.getObjectClass(lowerName);
3700      }
3701    
3702    
3703    
3704      /**
3705       * Retrieves the objectclass for the provided lowercase name or OID.  It can
3706       * optionally return a generated "default" version if the requested
3707       * objectclass is not defined in the schema.
3708       *
3709       * @param  lowerName      The lowercase name or OID for the objectclass to
3710       *                        retrieve.
3711       * @param  returnDefault  Indicates whether to generate a default version if
3712       *                        the requested objectclass is not defined in the
3713       *                        server schema.
3714       *
3715       * @return  The objectclass type, or <CODE>null</CODE> if there is no
3716       *          objectclass with the specified name or OID defined in the server
3717       *          schema and a default class should not be returned.
3718       */
3719      public static ObjectClass getObjectClass(String lowerName,
3720                                               boolean returnDefault)
3721      {
3722        ObjectClass oc = directoryServer.schema.getObjectClass(lowerName);
3723        if (returnDefault && (oc == null))
3724        {
3725          oc = getDefaultObjectClass(lowerName);
3726        }
3727    
3728        return oc;
3729      }
3730    
3731    
3732    
3733      /**
3734       * Registers the provided objectclass with the Directory Server.
3735       *
3736       * @param  objectClass        The objectclass instance to register with the
3737       *                            server.
3738       * @param  overwriteExisting  Indicates whether to overwrite an existing
3739       *                            mapping if there are any conflicts (i.e.,
3740       *                            another objectclass with the same OID or
3741       *                            name).
3742       *
3743       * @throws  DirectoryException  If a conflict is encountered and the
3744       *                              <CODE>overwriteExisting</CODE> flag is set to
3745       *                              <CODE>false</CODE>
3746       */
3747      public static void registerObjectClass(ObjectClass objectClass,
3748                                             boolean overwriteExisting)
3749             throws DirectoryException
3750      {
3751        directoryServer.schema.registerObjectClass(objectClass, overwriteExisting);
3752      }
3753    
3754    
3755    
3756      /**
3757       * Deregisters the provided objectclass with the Directory Server.
3758       *
3759       * @param  objectClass  The objectclass instance to deregister with the
3760       *                      server.
3761       */
3762      public static void deregisterObjectClass(ObjectClass objectClass)
3763      {
3764        directoryServer.schema.deregisterObjectClass(objectClass);
3765      }
3766    
3767    
3768    
3769      /**
3770       * Retrieves the "top" objectClass, which should be the topmost objectclass in
3771       * the inheritance chain for most other objectclasses.  If no such objectclass
3772       * could be found, then one will be constructed.
3773       *
3774       * @return  The "top" objectClass.
3775       */
3776      public static ObjectClass getTopObjectClass()
3777      {
3778        ObjectClass objectClass =
3779             directoryServer.schema.getObjectClass(TOP_OBJECTCLASS_NAME);
3780        if (objectClass == null)
3781        {
3782          String definition =
3783               "( 2.5.6.0 NAME 'top' ABSTRACT MUST objectClass " +
3784               "X-ORIGIN 'RFC 2256' )";
3785    
3786          objectClass = new ObjectClass(definition, TOP_OBJECTCLASS_NAME,
3787                                        Collections.singleton(TOP_OBJECTCLASS_NAME),
3788                                        TOP_OBJECTCLASS_OID,
3789                                        TOP_OBJECTCLASS_DESCRIPTION, null, null,
3790                                        null, ObjectClassType.ABSTRACT, false,
3791                                        null);
3792        }
3793    
3794        return objectClass;
3795      }
3796    
3797    
3798    
3799      /**
3800       * Causes the Directory Server to construct a new objectclass
3801       * definition with the provided name and with no required or allowed
3802       * attributes. This should only be used if there is no objectclass
3803       * for the specified name. It will not register the created
3804       * objectclass with the Directory Server.
3805       *
3806       * @param name
3807       *          The name to use for the objectclass, as provided by the
3808       *          user.
3809       * @return The constructed objectclass definition.
3810       */
3811      public static ObjectClass getDefaultObjectClass(String name)
3812      {
3813        String lowerName = toLowerCase(name);
3814        ObjectClass objectClass = directoryServer.schema.getObjectClass(lowerName);
3815        if (objectClass == null)
3816        {
3817          String oid        = lowerName + "-oid";
3818          String definition = "( " + oid + " NAME '" + name + "' ABSTRACT )";
3819    
3820          objectClass = new ObjectClass(definition, name,
3821                                        Collections.singleton(name), oid, null,
3822                                        getTopObjectClass(), null, null,
3823                                        ObjectClassType.STRUCTURAL, false, null);
3824        }
3825    
3826        return objectClass;
3827      }
3828    
3829    
3830    
3831      /**
3832       * Causes the Directory Server to construct a new auxiliary objectclass
3833       * definition with the provided name and with no required or allowed
3834       * attributes. This should only be used if there is no objectclass for the
3835       * specified name. It will not register the created objectclass with the
3836       * Directory Server.
3837       *
3838       * @param  name  The name to use for the objectclass, as provided by the user.
3839       *
3840       * @return  The constructed objectclass definition.
3841       */
3842      public static ObjectClass getDefaultAuxiliaryObjectClass(String name)
3843      {
3844        String lowerName = toLowerCase(name);
3845        ObjectClass objectClass = directoryServer.schema.getObjectClass(lowerName);
3846        if (objectClass == null)
3847        {
3848          String oid        = lowerName + "-oid";
3849          String definition = "( " + oid + " NAME '" + name + "' ABSTRACT )";
3850    
3851          objectClass = new ObjectClass(definition, name,
3852                                        Collections.singleton(name), oid, null,
3853                                        getTopObjectClass(), null, null,
3854                                        ObjectClassType.AUXILIARY, false, null);
3855        }
3856    
3857        return objectClass;
3858      }
3859    
3860    
3861    
3862      /**
3863       * Retrieves the set of attribute type definitions that have been
3864       * defined in the Directory Server.
3865       *
3866       * @return The set of attribute type definitions that have been
3867       *         defined in the Directory Server.
3868       */
3869      public static ConcurrentHashMap<String,AttributeType> getAttributeTypes()
3870      {
3871        return directoryServer.schema.getAttributeTypes();
3872      }
3873    
3874    
3875    
3876      /**
3877       * Retrieves the set of encoded attribute types that have been defined in the
3878       * Directory Server.
3879       *
3880       * @return  The set of encoded attribute types that have been defined in the
3881       *          Directory Server.
3882       */
3883      public static LinkedHashSet<AttributeValue> getAttributeTypeSet()
3884      {
3885        return directoryServer.schema.getAttributeTypeSet();
3886      }
3887    
3888    
3889    
3890      /**
3891       * Retrieves the attribute type for the provided lowercase name or OID.
3892       *
3893       * @param  lowerName  The lowercase attribute name or OID for the attribute
3894       *                    type to retrieve.
3895       *
3896       * @return  The requested attribute type, or <CODE>null</CODE> if there is no
3897       *          attribute with the specified type defined in the server schema.
3898       */
3899      public static AttributeType getAttributeType(String lowerName)
3900      {
3901        return directoryServer.schema.getAttributeType(lowerName);
3902      }
3903    
3904    
3905    
3906      /**
3907       * Retrieves the attribute type for the provided lowercase name or OID.  It
3908       * can optionally return a generated "default" version if the requested
3909       * attribute type is not defined in the schema.
3910       *
3911       * @param  lowerName      The lowercase name or OID for the attribute type to
3912       *                        retrieve.
3913       * @param  returnDefault  Indicates whether to generate a default version if
3914       *                        the requested attribute type is not defined in the
3915       *                        server schema.
3916       *
3917       * @return  The requested attribute type, or <CODE>null</CODE> if there is no
3918       *          attribute with the specified type defined in the server schema and
3919       *          a default type should not be returned.
3920       */
3921      public static AttributeType getAttributeType(String lowerName,
3922                                                   boolean returnDefault)
3923      {
3924        AttributeType type = directoryServer.schema.getAttributeType(lowerName);
3925        if (returnDefault && (type == null))
3926        {
3927          type = getDefaultAttributeType(lowerName);
3928        }
3929    
3930        return type;
3931      }
3932    
3933    
3934    
3935      /**
3936       * Registers the provided attribute type with the Directory Server.
3937       *
3938       * @param  attributeType      The attribute type to register with the
3939       *                            Directory Server.
3940       * @param  overwriteExisting  Indicates whether to overwrite an existing
3941       *                            mapping if there are any conflicts (i.e.,
3942       *                            another attribute type with the same OID or
3943       *                            name).
3944       *
3945       * @throws  DirectoryException  If a conflict is encountered and the
3946       *                              <CODE>overwriteExisting</CODE> flag is set to
3947       *                              <CODE>false</CODE>
3948       */
3949      public static void registerAttributeType(AttributeType attributeType,
3950                                               boolean overwriteExisting)
3951             throws DirectoryException
3952      {
3953        directoryServer.schema.registerAttributeType(attributeType,
3954                                                     overwriteExisting);
3955      }
3956    
3957    
3958    
3959      /**
3960       * Deregisters the provided attribute type with the Directory Server.
3961       *
3962       * @param  attributeType  The attribute type to deregister with the Directory
3963       *                        Server.
3964       */
3965      public static void deregisterAttributeType(AttributeType attributeType)
3966      {
3967        directoryServer.schema.deregisterAttributeType(attributeType);
3968      }
3969    
3970    
3971    
3972      /**
3973       * Retrieves the attribute type for the "objectClass" attribute.
3974       *
3975       * @return  The attribute type for the "objectClass" attribute.
3976       */
3977      public static AttributeType getObjectClassAttributeType()
3978      {
3979        if (directoryServer.objectClassAttributeType == null)
3980        {
3981          directoryServer.objectClassAttributeType =
3982               directoryServer.schema.getAttributeType(
3983                    OBJECTCLASS_ATTRIBUTE_TYPE_NAME);
3984    
3985          if (directoryServer.objectClassAttributeType == null)
3986          {
3987            AttributeSyntax oidSyntax =
3988                 directoryServer.schema.getSyntax(SYNTAX_OID_NAME);
3989            if (oidSyntax == null)
3990            {
3991              try
3992              {
3993                OIDSyntax newOIDSyntax = new OIDSyntax();
3994                newOIDSyntax.initializeSyntax(null);
3995                oidSyntax = newOIDSyntax;
3996                directoryServer.schema.registerSyntax(oidSyntax, true);
3997              }
3998              catch (Exception e)
3999              {
4000                if (debugEnabled())
4001                {
4002                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
4003                }
4004              }
4005            }
4006    
4007            String definition =
4008                 "( 2.5.4.0 NAME 'objectClass' EQUALITY objectIdentifierMatch " +
4009                 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 X-ORIGIN 'RFC 2256' )";
4010    
4011            directoryServer.objectClassAttributeType =
4012                 new AttributeType(definition, "objectClass",
4013                                   Collections.singleton("objectClass"),
4014                                   OBJECTCLASS_ATTRIBUTE_TYPE_OID, null, null,
4015                                   oidSyntax, AttributeUsage.USER_APPLICATIONS,
4016                                   false, false, false, false);
4017            try
4018            {
4019              directoryServer.schema.registerAttributeType(
4020                     directoryServer.objectClassAttributeType, true);
4021            }
4022            catch (Exception e)
4023            {
4024              // This should never happen.
4025              if (debugEnabled())
4026              {
4027                TRACER.debugCaught(DebugLogLevel.ERROR, e);
4028              }
4029            }
4030          }
4031        }
4032    
4033        return directoryServer.objectClassAttributeType;
4034      }
4035    
4036    
4037    
4038      /**
4039       * Causes the Directory Server to construct a new attribute type definition
4040       * with the provided name and using the default attribute syntax.  This should
4041       * only be used if there is no real attribute type for the specified name.
4042       *
4043       * @param  name  The name to use for the attribute type, as provided by the
4044       *               user.
4045       *
4046       * @return  The constructed attribute type definition.
4047       */
4048      public static AttributeType getDefaultAttributeType(String name)
4049      {
4050        return getDefaultAttributeType(name, getDefaultAttributeSyntax());
4051      }
4052    
4053    
4054    
4055      /**
4056       * Causes the Directory Server to construct a new attribute type definition
4057       * with the provided name and syntax.  This should only be used if there is no
4058       * real attribute type for the specified name.
4059       *
4060       * @param  name    The name to use for the attribute type, as provided by the
4061       *                 user.
4062       * @param  syntax  The syntax to use for the attribute type.
4063       *
4064       * @return  The constructed attribute type definition.
4065       */
4066      public static AttributeType getDefaultAttributeType(String name,
4067                                                          AttributeSyntax syntax)
4068      {
4069        String oid        = toLowerCase(name) + "-oid";
4070        String definition = "( " + oid + " NAME '" + name + "' SYNTAX " +
4071                            syntax.getOID() + " )";
4072    
4073        return new AttributeType(definition, name, Collections.singleton(name),
4074                                 oid, null, null, syntax,
4075                                 AttributeUsage.USER_APPLICATIONS, false, false,
4076                                 false, false);
4077      }
4078    
4079    
4080    
4081      /**
4082       * Retrieves the set of attribute syntaxes defined in the Directory Server.
4083       *
4084       * @return  The set of attribute syntaxes defined in the Directory Server.
4085       */
4086      public static ConcurrentHashMap<String,AttributeSyntax> getAttributeSyntaxes()
4087      {
4088        return directoryServer.schema.getSyntaxes();
4089      }
4090    
4091    
4092    
4093      /**
4094       * Retrieves the set of encoded attribute syntaxes that have been defined in
4095       * the Directory Server.
4096       *
4097       * @return  The set of encoded attribute syntaxes that have been defined in
4098       *          the Directory Server.
4099       */
4100      public static LinkedHashSet<AttributeValue> getAttributeSyntaxSet()
4101      {
4102        return directoryServer.schema.getSyntaxSet();
4103      }
4104    
4105    
4106    
4107      /**
4108       * Retrieves the requested attribute syntax.
4109       *
4110       * @param  oid           The OID of the syntax to retrieve.
4111       * @param  allowDefault  Indicates whether to return the default attribute
4112       *                       syntax if the requested syntax is unknown.
4113       *
4114       * @return  The requested attribute syntax, the default syntax if the
4115       *          requested syntax is unknown and the caller has indicated that the
4116       *          default is acceptable, or <CODE>null</CODE> otherwise.
4117       */
4118      public static AttributeSyntax getAttributeSyntax(String oid,
4119                                                       boolean allowDefault)
4120      {
4121        AttributeSyntax syntax = directoryServer.schema.getSyntax(oid);
4122        if ((syntax == null) && allowDefault)
4123        {
4124          return getDefaultAttributeSyntax();
4125        }
4126    
4127        return syntax;
4128      }
4129    
4130    
4131    
4132      /**
4133       * Registers the provided attribute syntax with the Directory Server.
4134       *
4135       * @param  syntax             The attribute syntax to register with the
4136       *                            Directory Server.
4137       * @param  overwriteExisting  Indicates whether to overwrite an existing
4138       *                            mapping if there are any conflicts (i.e.,
4139       *                            another attribute syntax with the same OID or
4140       *                            name).
4141       *
4142       * @throws  DirectoryException  If a conflict is encountered and the
4143       *                              <CODE>overwriteExisting</CODE> flag is set to
4144       *                              <CODE>false</CODE>
4145       */
4146      public static void registerAttributeSyntax(AttributeSyntax syntax,
4147                                                 boolean overwriteExisting)
4148             throws DirectoryException
4149      {
4150        directoryServer.schema.registerSyntax(syntax, overwriteExisting);
4151      }
4152    
4153    
4154    
4155      /**
4156       * Deregisters the provided attribute syntax with the Directory Server.
4157       *
4158       * @param  syntax  The attribute syntax to deregister with the Directory
4159       *                 Server.
4160       */
4161      public static void deregisterAttributeSyntax(AttributeSyntax syntax)
4162      {
4163        directoryServer.schema.deregisterSyntax(syntax);
4164      }
4165    
4166    
4167    
4168      /**
4169       * Retrieves the default attribute syntax that should be used for attributes
4170       * that are not defined in the server schema.
4171       *
4172       * @return  The default attribute syntax that should be used for attributes
4173       *          that are not defined in the server schema.
4174       */
4175      public static AttributeSyntax getDefaultAttributeSyntax()
4176      {
4177        return directoryServer.defaultSyntax;
4178      }
4179    
4180    
4181    
4182      /**
4183       * Retrieves the default attribute syntax that should be used for attributes
4184       * that are not defined in the server schema and are meant to store binary
4185       * values.
4186       *
4187       * @return  The default attribute syntax that should be used for attributes
4188       *          that are not defined in the server schema and are meant to store
4189       *          binary values.
4190       */
4191      public static AttributeSyntax getDefaultBinarySyntax()
4192      {
4193        return directoryServer.defaultBinarySyntax;
4194      }
4195    
4196    
4197    
4198      /**
4199       * Retrieves the default attribute syntax that should be used for attributes
4200       * that are not defined in the server schema and are meant to store Boolean
4201       * values.
4202       *
4203       * @return  The default attribute syntax that should be used for attributes
4204       *          that are not defined in the server schema and are meant to store
4205       *          Boolean values.
4206       */
4207      public static AttributeSyntax getDefaultBooleanSyntax()
4208      {
4209        return directoryServer.defaultBooleanSyntax;
4210      }
4211    
4212    
4213    
4214      /**
4215       * Retrieves the default attribute syntax that should be used for attributes
4216       * that are not defined in the server schema and are meant to store DN values.
4217       *
4218       * @return  The default attribute syntax that should be used for attributes
4219       *          that are not defined in the server schema and are meant to store
4220       *          DN values.
4221       */
4222      public static AttributeSyntax getDefaultDNSyntax()
4223      {
4224        return directoryServer.defaultDNSyntax;
4225      }
4226    
4227    
4228    
4229      /**
4230       * Retrieves the default attribute syntax that should be used for attributes
4231       * that are not defined in the server schema and are meant to store integer
4232       * values.
4233       *
4234       * @return  The default attribute syntax that should be used for attributes
4235       *          that are not defined in the server schema and are meant to store
4236       *          integer values.
4237       */
4238      public static AttributeSyntax getDefaultIntegerSyntax()
4239      {
4240        return directoryServer.defaultIntegerSyntax;
4241      }
4242    
4243    
4244    
4245      /**
4246       * Retrieves the default attribute syntax that should be used for attributes
4247       * that are not defined in the server schema and are meant to store string
4248       * values.
4249       *
4250       * @return  The default attribute syntax that should be used for attributes
4251       *          that are not defined in the server schema and are meant to store
4252       *          string values.
4253       */
4254      public static AttributeSyntax getDefaultStringSyntax()
4255      {
4256        return directoryServer.defaultStringSyntax;
4257      }
4258    
4259    
4260    
4261      /**
4262       * Retrieves the set of matching rule uses defined in the Directory Server.
4263       *
4264       * @return  The set of matching rule uses defined in the Directory Server.
4265       */
4266      public static ConcurrentHashMap<MatchingRule,MatchingRuleUse>
4267                         getMatchingRuleUses()
4268      {
4269        return directoryServer.schema.getMatchingRuleUses();
4270      }
4271    
4272    
4273    
4274      /**
4275       * Retrieves the set of encoded matching rule uses that have been defined in
4276       * the Directory Server.
4277       *
4278       * @return  The set of encoded matching rule uses that have been defined in
4279       *          the Directory Server.
4280       */
4281      public static LinkedHashSet<AttributeValue> getMatchingRuleUseSet()
4282      {
4283        return directoryServer.schema.getMatchingRuleUseSet();
4284      }
4285    
4286    
4287    
4288      /**
4289       * Retrieves the matching rule use associated with the provided matching rule.
4290       *
4291       * @param  matchingRule  The matching rule for which to retrieve the matching
4292       *                       rule use.
4293       *
4294       * @return  The matching rule use for the provided matching rule, or
4295       *          <CODE>null</CODE> if none is defined.
4296       */
4297      public static MatchingRuleUse getMatchingRuleUse(MatchingRule matchingRule)
4298      {
4299        return directoryServer.schema.getMatchingRuleUse(matchingRule);
4300      }
4301    
4302    
4303    
4304      /**
4305       * Registers the provided matching rule use with the Directory Server.
4306       *
4307       * @param  matchingRuleUse    The matching rule use to register with the
4308       *                            server.
4309       * @param  overwriteExisting  Indicates whether to overwrite an existing
4310       *                            mapping if there are any conflicts (i.e.,
4311       *                            another matching rule use with the same matching
4312       *                            rule).
4313       *
4314       * @throws  DirectoryException  If a conflict is encountered and the
4315       *                              <CODE>overwriteExisting</CODE> flag is set to
4316       *                              <CODE>false</CODE>
4317       */
4318      public static void registerMatchingRuleUse(MatchingRuleUse matchingRuleUse,
4319                                                 boolean overwriteExisting)
4320             throws DirectoryException
4321      {
4322        directoryServer.schema.registerMatchingRuleUse(matchingRuleUse,
4323                                                       overwriteExisting);
4324      }
4325    
4326    
4327    
4328      /**
4329       * Deregisters the provided matching rule use with the Directory Server.
4330       *
4331       * @param  matchingRuleUse  The matching rule use to deregister with the
4332       *                          server.
4333       */
4334      public static void deregisterMatchingRuleUse(MatchingRuleUse matchingRuleUse)
4335      {
4336        directoryServer.schema.deregisterMatchingRuleUse(matchingRuleUse);
4337      }
4338    
4339    
4340    
4341      /**
4342       * Retrieves the set of DIT content rules defined in the Directory Server.
4343       *
4344       * @return  The set of DIT content rules defined in the Directory Server.
4345       */
4346      public static ConcurrentHashMap<ObjectClass,DITContentRule>
4347                         getDITContentRules()
4348      {
4349        return directoryServer.schema.getDITContentRules();
4350      }
4351    
4352    
4353    
4354      /**
4355       * Retrieves the set of encoded DIT content rules that have been defined in
4356       * the Directory Server.
4357       *
4358       * @return  The set of encoded DIT content rules that have been defined in the
4359       *          Directory Server.
4360       */
4361      public static LinkedHashSet<AttributeValue> getDITContentRuleSet()
4362      {
4363        return directoryServer.schema.getDITContentRuleSet();
4364      }
4365    
4366    
4367    
4368      /**
4369       * Retrieves the DIT content rule associated with the specified objectclass.
4370       *
4371       * @param  objectClass  The objectclass for which to retrieve the associated
4372       *                      DIT content rule.
4373       *
4374       * @return  The requested DIT content rule, or <CODE>null</CODE> if no such
4375       *          rule is defined in the schema.
4376       */
4377      public static DITContentRule getDITContentRule(ObjectClass objectClass)
4378      {
4379        return directoryServer.schema.getDITContentRule(objectClass);
4380      }
4381    
4382    
4383    
4384      /**
4385       * Registers the provided DIT content rule with the Directory Server.
4386       *
4387       * @param  ditContentRule     The DIT content rule to register with the
4388       *                            server.
4389       * @param  overwriteExisting  Indicates whether to overwrite an existing
4390       *                            mapping if there are any conflicts (i.e.,
4391       *                            another DIT content rule with the same
4392       *                            structural objectclass).
4393       *
4394       * @throws  DirectoryException  If a conflict is encountered and the
4395       *                              <CODE>overwriteExisting</CODE> flag is set to
4396       *                              <CODE>false</CODE>
4397       */
4398      public static void registerDITContentRule(DITContentRule ditContentRule,
4399                                                boolean overwriteExisting)
4400             throws DirectoryException
4401      {
4402        directoryServer.schema.registerDITContentRule(ditContentRule,
4403                                                      overwriteExisting);
4404      }
4405    
4406    
4407    
4408      /**
4409       * Deregisters the provided DIT content rule with the Directory Server.
4410       *
4411       * @param  ditContentRule  The DIT content rule to deregister with the server.
4412       */
4413      public static void deregisterDITContentRule(DITContentRule ditContentRule)
4414      {
4415        directoryServer.schema.deregisterDITContentRule(ditContentRule);
4416      }
4417    
4418    
4419    
4420      /**
4421       * Retrieves the set of DIT structure rules defined in the Directory Server.
4422       *
4423       * @return  The set of DIT structure rules defined in the Directory Server.
4424       */
4425      public static ConcurrentHashMap<NameForm,DITStructureRule>
4426                         getDITStructureRules()
4427      {
4428        return directoryServer.schema.getDITStructureRulesByNameForm();
4429      }
4430    
4431    
4432    
4433      /**
4434       * Retrieves the set of encoded DIT structure rules that have been defined in
4435       * the Directory Server.
4436       *
4437       * @return  The set of encoded DIT structure rules that have been defined in
4438       *          the Directory Server.
4439       */
4440      public static LinkedHashSet<AttributeValue> getDITStructureRuleSet()
4441      {
4442        return directoryServer.schema.getDITStructureRuleSet();
4443      }
4444    
4445    
4446    
4447      /**
4448       * Retrieves the DIT structure rule associated with the provided rule ID.
4449       *
4450       * @param  ruleID  The rule ID for which to retrieve the associated DIT
4451       *                 structure rule.
4452       *
4453       * @return  The requested DIT structure rule, or <CODE>null</CODE> if no such
4454       *          rule is defined.
4455       */
4456      public static DITStructureRule getDITStructureRule(int ruleID)
4457      {
4458        return directoryServer.schema.getDITStructureRule(ruleID);
4459      }
4460    
4461    
4462    
4463      /**
4464       * Retrieves the DIT structure rule associated with the provided name form.
4465       *
4466       * @param  nameForm  The name form for which to retrieve the associated DIT
4467       *                   structure rule.
4468       *
4469       * @return  The requested DIT structure rule, or <CODE>null</CODE> if no such
4470       *          rule is defined.
4471       */
4472      public static DITStructureRule getDITStructureRule(NameForm nameForm)
4473      {
4474        return directoryServer.schema.getDITStructureRule(nameForm);
4475      }
4476    
4477    
4478    
4479      /**
4480       * Registers the provided DIT structure rule with the Directory Server.
4481       *
4482       * @param  ditStructureRule   The DIT structure rule to register with the
4483       *                            server.
4484       * @param  overwriteExisting  Indicates whether to overwrite an existing
4485       *                            mapping if there are any conflicts (i.e.,
4486       *                            another DIT structure rule with the same name
4487       *                            form).
4488       *
4489       * @throws  DirectoryException  If a conflict is encountered and the
4490       *                              <CODE>overwriteExisting</CODE> flag is set to
4491       *                              <CODE>false</CODE>
4492       */
4493      public static void registerDITStructureRule(DITStructureRule ditStructureRule,
4494                                                  boolean overwriteExisting)
4495             throws DirectoryException
4496      {
4497        directoryServer.schema.registerDITStructureRule(ditStructureRule,
4498                                                        overwriteExisting);
4499      }
4500    
4501    
4502    
4503      /**
4504       * Deregisters the provided DIT structure rule with the Directory Server.
4505       *
4506       * @param  ditStructureRule  The DIT structure rule to deregister with the
4507       *                           server.
4508       */
4509      public static void deregisterDITStructureRule(DITStructureRule
4510                                                         ditStructureRule)
4511      {
4512        directoryServer.schema.deregisterDITStructureRule(ditStructureRule);
4513      }
4514    
4515    
4516    
4517      /**
4518       * Retrieves the set of name forms defined in the Directory Server.
4519       *
4520       * @return  The set of name forms defined in the Directory Server.
4521       */
4522      public static ConcurrentHashMap<ObjectClass,NameForm> getNameForms()
4523      {
4524        return directoryServer.schema.getNameFormsByObjectClass();
4525      }
4526    
4527    
4528    
4529      /**
4530       * Retrieves the set of encoded name forms that have been defined in the
4531       * Directory Server.
4532       *
4533       * @return  The set of encoded name forms that have been defined in the
4534       *          Directory Server.
4535       */
4536      public static LinkedHashSet<AttributeValue> getNameFormSet()
4537      {
4538        return directoryServer.schema.getNameFormSet();
4539      }
4540    
4541    
4542    
4543      /**
4544       * Retrieves the name form associated with the specified objectclass.
4545       *
4546       * @param  objectClass  The objectclass for which to retrieve the associated
4547       *                      name form.
4548       *
4549       * @return  The requested name form, or <CODE>null</CODE> if no such name form
4550       *          is defined in the schema.
4551       */
4552      public static NameForm getNameForm(ObjectClass objectClass)
4553      {
4554        return directoryServer.schema.getNameForm(objectClass);
4555      }
4556    
4557    
4558    
4559      /**
4560       * Retrieves the name form associated with the specified name or OID.
4561       *
4562       * @param  lowerName  The name or OID of the name form to retrieve, formatted
4563       *                    in all lowercase characters.
4564       *
4565       * @return  The requested name form, or <CODE>null</CODE> if no such name form
4566       *          is defined in the schema.
4567       */
4568      public static NameForm getNameForm(String lowerName)
4569      {
4570        return directoryServer.schema.getNameForm(lowerName);
4571      }
4572    
4573    
4574    
4575      /**
4576       * Registers the provided name form with the Directory Server.
4577       *
4578       * @param  nameForm           The name form to register with the server.
4579       * @param  overwriteExisting  Indicates whether to overwrite an existing
4580       *                            mapping if there are any conflicts (i.e.,
4581       *                            another name form with the same structural
4582       *                            objectclass).
4583       *
4584       * @throws  DirectoryException  If a conflict is encountered and the
4585       *                              <CODE>overwriteExisting</CODE> flag is set to
4586       *                              <CODE>false</CODE>
4587       */
4588      public static void registerNameForm(NameForm nameForm,
4589                                          boolean overwriteExisting)
4590             throws DirectoryException
4591      {
4592        directoryServer.schema.registerNameForm(nameForm, overwriteExisting);
4593      }
4594    
4595    
4596    
4597      /**
4598       * Deregisters the provided name form with the Directory Server.
4599       *
4600       * @param  nameForm  The name form to deregister with the server.
4601       */
4602      public static void deregisterNameForm(NameForm nameForm)
4603      {
4604        directoryServer.schema.deregisterNameForm(nameForm);
4605      }
4606    
4607    
4608    
4609      /**
4610       * Retrieves the set of virtual attribute rules registered with the Directory
4611       * Server.
4612       *
4613       * @return  The set of virtual attribute rules registered with the Directory
4614       *          Server.
4615       */
4616      public static List<VirtualAttributeRule> getVirtualAttributes()
4617      {
4618        return directoryServer.virtualAttributes;
4619      }
4620    
4621    
4622    
4623      /**
4624       * Retrieves the set of virtual attribute rules registered with the Directory
4625       * Server that are applicable to the provided entry.
4626       *
4627       * @param  entry  The entry for which to retrieve the applicable virtual
4628       *                attribute rules.
4629       *
4630       * @return  The set of virtual attribute rules registered with the Directory
4631       *          Server that apply to the given entry.  It may be an empty list if
4632       *          there are no applicable virtual attribute rules.
4633       */
4634      public static List<VirtualAttributeRule> getVirtualAttributes(Entry entry)
4635      {
4636        LinkedList<VirtualAttributeRule> ruleList =
4637             new LinkedList<VirtualAttributeRule>();
4638    
4639        for (VirtualAttributeRule rule : directoryServer.virtualAttributes)
4640        {
4641          if (rule.appliesToEntry(entry))
4642          {
4643            ruleList.add(rule);
4644          }
4645        }
4646    
4647        return ruleList;
4648      }
4649    
4650    
4651    
4652      /**
4653       * Registers the provided virtual attribute rule with the Directory Server.
4654       *
4655       * @param  rule  The virtual attribute rule to be registered.
4656       */
4657      public static void registerVirtualAttribute(VirtualAttributeRule rule)
4658      {
4659        synchronized (directoryServer.virtualAttributes)
4660        {
4661          directoryServer.virtualAttributes.add(rule);
4662        }
4663      }
4664    
4665    
4666    
4667      /**
4668       * Deregisters the provided virtual attribute rule with the Directory Server.
4669       *
4670       * @param  rule  The virutal attribute rule to be deregistered.
4671       */
4672      public static void deregisterVirtualAttribute(VirtualAttributeRule rule)
4673      {
4674        synchronized (directoryServer.virtualAttributes)
4675        {
4676          directoryServer.virtualAttributes.remove(rule);
4677        }
4678      }
4679    
4680    
4681    
4682      /**
4683       * Replaces the specified virtual attribute rule in the set of virtual
4684       * attributes registered with the Directory Server.  If the old rule cannot
4685       * be found in the list, then the set of registered virtual attributes is not
4686       * updated.
4687       *
4688       * @param  oldRule  The existing rule that should be replaced with the new
4689       *                  rule.
4690       * @param  newRule  The new rule that should be used in place of the existing
4691       *                  rule.
4692       *
4693       * @return  {@code true} if the old rule was found and replaced with the new
4694       *          version, or {@code false} if it was not.
4695       */
4696      public static boolean replaceVirtualAttribute(VirtualAttributeRule oldRule,
4697                                                    VirtualAttributeRule newRule)
4698      {
4699        synchronized (directoryServer.virtualAttributes)
4700        {
4701          int pos = directoryServer.virtualAttributes.indexOf(oldRule);
4702          if (pos >= 0)
4703          {
4704            directoryServer.virtualAttributes.set(pos, newRule);
4705            return true;
4706          }
4707          else
4708          {
4709            return false;
4710          }
4711        }
4712      }
4713    
4714    
4715    
4716      /**
4717       * Retrieves a reference to the JMX MBean server that is associated with the
4718       * Directory Server.
4719       *
4720       * @return  The JMX MBean server that is associated with the Directory Server.
4721       */
4722      public static MBeanServer getJMXMBeanServer()
4723      {
4724        return directoryServer.mBeanServer;
4725      }
4726    
4727    
4728    
4729      /**
4730       * Retrieves the set of JMX MBeans that are associated with the server.
4731       *
4732       * @return  The set of JMX MBeans that are associated with the server.
4733       */
4734      public static ConcurrentHashMap<DN,JMXMBean> getJMXMBeans()
4735      {
4736        return directoryServer.mBeans;
4737      }
4738    
4739    
4740    
4741      /**
4742       * Retrieves the JMX MBean associated with the specified entry in the
4743       * Directory Server configuration.
4744       *
4745       * @param  configEntryDN  The DN of the configuration entry for which to
4746       *                        retrieve the associated JMX MBean.
4747       *
4748       * @return  The JMX MBean associated with the specified entry in the Directory
4749       *          Server configuration, or <CODE>null</CODE> if there is no MBean
4750       *          for the specified entry.
4751       */
4752      public static JMXMBean getJMXMBean(DN configEntryDN)
4753      {
4754        return directoryServer.mBeans.get(configEntryDN);
4755      }
4756    
4757    
4758    
4759      /**
4760       * Registers the provided invokable component with the Directory Server.
4761       *
4762       * @param  component  The invokable component to register.
4763       */
4764      public static void registerInvokableComponent(InvokableComponent component)
4765      {
4766        DN componentDN = component.getInvokableComponentEntryDN();
4767        JMXMBean mBean = directoryServer.mBeans.get(componentDN);
4768        if (mBean == null)
4769        {
4770          mBean = new JMXMBean(componentDN);
4771          mBean.addInvokableComponent(component);
4772          directoryServer.mBeans.put(componentDN, mBean);
4773        }
4774        else
4775        {
4776          mBean.addInvokableComponent(component);
4777        }
4778      }
4779    
4780    
4781    
4782      /**
4783       * Deregisters the provided invokable component with the Directory Server.
4784       *
4785       * @param  component  The invokable component to deregister.
4786       */
4787      public static void deregisterInvokableComponent(InvokableComponent component)
4788      {
4789        DN componentDN = component.getInvokableComponentEntryDN();
4790        JMXMBean mBean = directoryServer.mBeans.get(componentDN);
4791        if (mBean != null)
4792        {
4793          mBean.removeInvokableComponent(component);
4794        }
4795      }
4796    
4797    
4798    
4799      /**
4800       * Registers the provided alert generator with the Directory Server.
4801       *
4802       * @param  alertGenerator  The alert generator to register.
4803       */
4804      public static void registerAlertGenerator(AlertGenerator alertGenerator)
4805      {
4806        DN componentDN = alertGenerator.getComponentEntryDN();
4807        JMXMBean mBean = directoryServer.mBeans.get(componentDN);
4808        if (mBean == null)
4809        {
4810          mBean = new JMXMBean(componentDN);
4811          mBean.addAlertGenerator(alertGenerator);
4812          directoryServer.mBeans.put(componentDN, mBean);
4813        }
4814        else
4815        {
4816          mBean.addAlertGenerator(alertGenerator);
4817        }
4818      }
4819    
4820    
4821    
4822      /**
4823       * Deregisters the provided alert generator with the Directory Server.
4824       *
4825       * @param  alertGenerator  The alert generator to deregister.
4826       */
4827      public static void deregisterAlertGenerator(AlertGenerator alertGenerator)
4828      {
4829        DN componentDN = alertGenerator.getComponentEntryDN();
4830        JMXMBean mBean = directoryServer.mBeans.get(componentDN);
4831        if (mBean != null)
4832        {
4833          mBean.removeAlertGenerator(alertGenerator);
4834        }
4835      }
4836    
4837    
4838    
4839      /**
4840       * Retrieves the set of alert handlers that have been registered with the
4841       * Directory Server.
4842       *
4843       * @return  The set of alert handlers that have been registered with the
4844       *          Directory Server.
4845       */
4846      public static CopyOnWriteArrayList<AlertHandler> getAlertHandlers()
4847      {
4848        return directoryServer.alertHandlers;
4849      }
4850    
4851    
4852    
4853      /**
4854       * Registers the provided alert handler with the Directory Server.
4855       *
4856       * @param  alertHandler  The alert handler to register.
4857       */
4858      public static void registerAlertHandler(AlertHandler alertHandler)
4859      {
4860        directoryServer.alertHandlers.add(alertHandler);
4861      }
4862    
4863    
4864    
4865      /**
4866       * Deregisters the provided alert handler with the Directory Server.
4867       *
4868       * @param  alertHandler  The alert handler to deregister.
4869       */
4870      public static void deregisterAlertHandler(AlertHandler alertHandler)
4871      {
4872        directoryServer.alertHandlers.remove(alertHandler);
4873      }
4874    
4875    
4876    
4877      /**
4878       * Sends an alert notification with the provided information.
4879       *
4880       * @param  generator     The alert generator that created the alert.
4881       * @param  alertType     The alert type name for this alert.
4882       * @param  alertMessage  A message (possibly <CODE>null</CODE>) that can
4883       */
4884      public static void sendAlertNotification(AlertGenerator generator,
4885                                               String alertType,
4886                                               Message alertMessage)
4887      {
4888        if ((directoryServer.alertHandlers == null) ||
4889            directoryServer.alertHandlers.isEmpty())
4890        {
4891          // If the Directory Server is still in the process of starting up, then
4892          // create a JMX alert handler to use for this notification.
4893          if (! directoryServer.isRunning)
4894          {
4895            try
4896            {
4897              JMXAlertHandler alertHandler = new JMXAlertHandler();
4898              alertHandler.initializeAlertHandler(null);
4899              alertHandler.sendAlertNotification(generator, alertType,
4900                                                 alertMessage);
4901            }
4902            catch (Exception e)
4903            {
4904              if (debugEnabled())
4905              {
4906                TRACER.debugCaught(DebugLogLevel.ERROR, e);
4907              }
4908            }
4909          }
4910        }
4911        else
4912        {
4913          for (AlertHandler alertHandler : directoryServer.alertHandlers)
4914          {
4915            AlertHandlerCfg config = alertHandler.getAlertHandlerConfiguration();
4916            Set<String> enabledAlerts = config.getEnabledAlertType();
4917            Set<String> disabledAlerts = config.getDisabledAlertType();
4918            if ((enabledAlerts == null) || enabledAlerts.isEmpty())
4919            {
4920              if ((disabledAlerts != null) && disabledAlerts.contains(alertType))
4921              {
4922                continue;
4923              }
4924            }
4925            else
4926            {
4927              if (enabledAlerts.contains(alertType))
4928              {
4929                if ((disabledAlerts != null) && disabledAlerts.contains(alertType))
4930                {
4931                  continue;
4932                }
4933              }
4934              else
4935              {
4936                continue;
4937              }
4938            }
4939    
4940            alertHandler.sendAlertNotification(generator, alertType, alertMessage);
4941          }
4942        }
4943    
4944    
4945        Message message = NOTE_SENT_ALERT_NOTIFICATION.get(
4946            generator.getClassName(), alertType,
4947                alertMessage != null ?
4948                        String.valueOf(alertMessage.getDescriptor().getId()) :
4949                        String.valueOf(MessageDescriptor.NULL_ID),
4950                alertMessage);
4951        logError(message);
4952      }
4953    
4954    
4955    
4956      /**
4957       * Retrieves the password storage scheme defined in the specified
4958       * configuration entry.
4959       *
4960       * @param  configEntryDN  The DN of the configuration entry that defines the
4961       *                        password storage scheme to retrieve.
4962       *
4963       * @return  The requested password storage scheme, or {@code null} if no such
4964       *          scheme is defined.
4965       */
4966      public static PasswordStorageScheme getPasswordStorageScheme(DN configEntryDN)
4967      {
4968        return directoryServer.passwordStorageSchemesByDN.get(configEntryDN);
4969      }
4970    
4971    
4972    
4973      /**
4974       * Retrieves the set of password storage schemes defined in the Directory
4975       * Server, as a mapping between the all-lowercase scheme name and the
4976       * corresponding implementation.
4977       *
4978       * @return  The set of password storage schemes defined in the Directory
4979       *          Server.
4980       */
4981      public static ConcurrentHashMap<String,PasswordStorageScheme>
4982                         getPasswordStorageSchemes()
4983      {
4984        return directoryServer.passwordStorageSchemes;
4985      }
4986    
4987    
4988    
4989      /**
4990       * Retrieves the specified password storage scheme.
4991       *
4992       * @param  lowerName  The name of the password storage scheme to retrieve,
4993       *                    formatted in all lowercase characters.
4994       *
4995       * @return  The requested password storage scheme, or <CODE>null</CODE> if no
4996       *          such scheme is defined.
4997       */
4998      public static PasswordStorageScheme getPasswordStorageScheme(String lowerName)
4999      {
5000        return directoryServer.passwordStorageSchemes.get(lowerName);
5001      }
5002    
5003    
5004    
5005      /**
5006       * Retrieves the set of authentication password storage schemes defined in the
5007       * Directory Server, as a mapping between the scheme name and the
5008       * corresponding implementation.
5009       *
5010       * @return  The set of authentication password storage schemes defined in the
5011       *          Directory Server.
5012       */
5013      public static ConcurrentHashMap<String,PasswordStorageScheme>
5014                         getAuthPasswordStorageSchemes()
5015      {
5016        return directoryServer.authPasswordStorageSchemes;
5017      }
5018    
5019    
5020    
5021      /**
5022       * Retrieves the specified authentication password storage scheme.
5023       *
5024       * @param  name  The case-sensitive name of the authentication password
5025       *               storage scheme to retrieve.
5026       *
5027       * @return  The requested authentication password storage scheme, or
5028       *          <CODE>null</CODE> if no such scheme is defined.
5029       */
5030      public static PasswordStorageScheme getAuthPasswordStorageScheme(String name)
5031      {
5032        return directoryServer.authPasswordStorageSchemes.get(name);
5033      }
5034    
5035    
5036    
5037      /**
5038       * Registers the provided password storage scheme with the Directory Server.
5039       * If an existing password storage scheme is registered with the same name,
5040       * then it will be replaced with the provided scheme.
5041       *
5042       * @param  configEntryDN  The DN of the configuration entry that defines the
5043       *                        password storage scheme.
5044       * @param  scheme         The password storage scheme to register with the
5045       *                        Directory Server.
5046       */
5047      public static void registerPasswordStorageScheme(DN configEntryDN,
5048                                                       PasswordStorageScheme scheme)
5049      {
5050        directoryServer.passwordStorageSchemesByDN.put(configEntryDN, scheme);
5051    
5052        String name = toLowerCase(scheme.getStorageSchemeName());
5053        directoryServer.passwordStorageSchemes.put(name, scheme);
5054    
5055        if (scheme.supportsAuthPasswordSyntax())
5056        {
5057          directoryServer.authPasswordStorageSchemes.put(
5058               scheme.getAuthPasswordSchemeName(), scheme);
5059        }
5060      }
5061    
5062    
5063    
5064      /**
5065       * Deregisters the specified password storage scheme with the Directory
5066       * Server.  If no scheme is registered with the specified name, then no action
5067       * will be taken.
5068       *
5069       * @param  configEntryDN  The DN of the configuration entry that defines the
5070       *                        password storage scheme.
5071       */
5072      public static void deregisterPasswordStorageScheme(DN configEntryDN)
5073      {
5074        PasswordStorageScheme scheme =
5075             directoryServer.passwordStorageSchemesByDN.remove(configEntryDN);
5076    
5077        if (scheme != null)
5078        {
5079          directoryServer.passwordStorageSchemes.remove(
5080               toLowerCase(scheme.getStorageSchemeName()));
5081    
5082          if (scheme.supportsAuthPasswordSyntax())
5083          {
5084            directoryServer.authPasswordStorageSchemes.remove(
5085                 scheme.getAuthPasswordSchemeName());
5086          }
5087        }
5088      }
5089    
5090    
5091    
5092      /**
5093       * Retrieves the set of password validators that have been registered for use
5094       * with the Directory Server as a mapping between the DN of the associated
5095       * validator configuration entry and the validator implementation.
5096       *
5097       * @return  The set of password validators that have been registered for use
5098       *          with the Directory Server.
5099       */
5100      public static
5101           ConcurrentHashMap<DN,
5102                PasswordValidator<? extends PasswordValidatorCfg>>
5103                getPasswordValidators()
5104      {
5105        return directoryServer.passwordValidators;
5106      }
5107    
5108    
5109    
5110      /**
5111       * Retrieves the password validator registered with the provided configuration
5112       * entry DN.
5113       *
5114       * @param  configEntryDN  The DN of the configuration entry for which to
5115       *                        retrieve the associated password validator.
5116       *
5117       * @return  The requested password validator, or <CODE>null</CODE> if no such
5118       *          validator is defined.
5119       */
5120      public static PasswordValidator<? extends PasswordValidatorCfg>
5121                         getPasswordValidator(DN configEntryDN)
5122      {
5123        return directoryServer.passwordValidators.get(configEntryDN);
5124      }
5125    
5126    
5127    
5128      /**
5129       * Registers the provided password validator for use with the Directory
5130       * Server.
5131       *
5132       * @param  configEntryDN  The DN of the configuration entry that defines the
5133       *                        specified password validator.
5134       * @param  validator      The password validator to register with the
5135       *                        Directory Server.
5136       */
5137      public static void
5138           registerPasswordValidator(DN configEntryDN,
5139                PasswordValidator<? extends PasswordValidatorCfg>
5140                validator)
5141      {
5142        directoryServer.passwordValidators.put(configEntryDN, validator);
5143      }
5144    
5145    
5146    
5147      /**
5148       * Deregisters the provided password validator for use with the Directory
5149       * Server.
5150       *
5151       * @param  configEntryDN  The DN of the configuration entry that defines the
5152       *                        password validator to deregister.
5153       */
5154      public static void deregisterPasswordValidator(DN configEntryDN)
5155      {
5156        directoryServer.passwordValidators.remove(configEntryDN);
5157      }
5158    
5159    
5160    
5161      /**
5162       * Retrieves the set of account status notification handlers defined in the
5163       * Directory Server, as a mapping between the DN of the configuration entry
5164       * and the notification handler implementation.
5165       *
5166       * @return  The set of account status notification handlers defined in the
5167       *          Directory Server.
5168       */
5169      public static ConcurrentHashMap<DN,AccountStatusNotificationHandler>
5170                         getAccountStatusNotificationHandlers()
5171      {
5172        return directoryServer.accountStatusNotificationHandlers;
5173      }
5174    
5175    
5176    
5177      /**
5178       * Retrieves the account status notification handler with the specified
5179       * configuration entry DN.
5180       *
5181       * @param  handlerDN  The DN of the configuration entry associated with the
5182       *                    account status notification handler to retrieve.
5183       *
5184       * @return  The requested account status notification handler, or
5185       *          <CODE>null</CODE> if no such handler is defined in the server.
5186       */
5187      public static AccountStatusNotificationHandler
5188                         getAccountStatusNotificationHandler(DN handlerDN)
5189      {
5190        return directoryServer.accountStatusNotificationHandlers.get(handlerDN);
5191      }
5192    
5193    
5194    
5195      /**
5196       * Registers the provided account status notification handler with the
5197       * Directory Server.
5198       *
5199       * @param  handlerDN  The DN of the configuration entry that defines the
5200       *                    provided account status notification handler.
5201       * @param  handler    The account status notification handler to register with
5202       *                    the Directory Server.
5203       */
5204      public static void registerAccountStatusNotificationHandler(DN handlerDN,
5205                              AccountStatusNotificationHandler handler)
5206      {
5207        directoryServer.accountStatusNotificationHandlers.put(handlerDN, handler);
5208      }
5209    
5210    
5211    
5212      /**
5213       * Deregisters the specified account status notification handler with the
5214       * Directory Server.
5215       *
5216       * @param  handlerDN  The DN of the configuration entry for the account status
5217       *                    notification handler to deregister.
5218       */
5219      public static void deregisterAccountStatusNotificationHandler(DN handlerDN)
5220      {
5221        directoryServer.accountStatusNotificationHandlers.remove(handlerDN);
5222      }
5223    
5224    
5225    
5226    
5227      /**
5228       * Retrieves the set of password generators that have been registered for use
5229       * with the Directory Server as a mapping between the DN of the associated
5230       * generator configuration entry and the generator implementation.
5231       *
5232       * @return  The set of password generators that have been registered for use
5233       *          with the Directory Server.
5234       */
5235      public static ConcurrentHashMap<DN,PasswordGenerator> getPasswordGenerators()
5236      {
5237        return directoryServer.passwordGenerators;
5238      }
5239    
5240    
5241    
5242      /**
5243       * Retrieves the password generator registered with the provided configuration
5244       * entry DN.
5245       *
5246       * @param  configEntryDN  The DN of the configuration entry for which to
5247       *                        retrieve the associated password generator.
5248       *
5249       * @return  The requested password generator, or <CODE>null</CODE> if no such
5250       *          generator is defined.
5251       */
5252      public static PasswordGenerator getPasswordGenerator(DN configEntryDN)
5253      {
5254        return directoryServer.passwordGenerators.get(configEntryDN);
5255      }
5256    
5257    
5258    
5259      /**
5260       * Registers the provided password generator for use with the Directory
5261       * Server.
5262       *
5263       * @param  configEntryDN  The DN of the configuration entry that defines the
5264       *                        specified password generator.
5265       * @param  generator      The password generator to register with the
5266       *                        Directory Server.
5267       */
5268      public static void registerPasswordGenerator(DN configEntryDN,
5269                                                   PasswordGenerator generator)
5270      {
5271        directoryServer.passwordGenerators.put(configEntryDN, generator);
5272      }
5273    
5274    
5275    
5276      /**
5277       * Deregisters the provided password generator for use with the Directory
5278       * Server.
5279       *
5280       * @param  configEntryDN  The DN of the configuration entry that defines the
5281       *                        password generator to deregister.
5282       */
5283      public static void deregisterPasswordGenerator(DN configEntryDN)
5284      {
5285        directoryServer.passwordGenerators.remove(configEntryDN);
5286      }
5287    
5288    
5289    
5290      /**
5291       * Retrieves the set of password policies registered with the Directory
5292       * Server. The references returned are to the actual password policy objects
5293       * currently in use by the directory server and the referenced objects must
5294       * not be modified.
5295       *
5296       * @return  The set of password policies registered with the Directory Server.
5297       */
5298      public static PasswordPolicy[] getPasswordPolicies()
5299      {
5300        // The password policy objects are returned in an array to prevent the
5301        // caller from modifying the map structure.
5302        PasswordPolicyConfig[] values = directoryServer.passwordPolicies.values()
5303                                              .toArray(new PasswordPolicyConfig[0]);
5304        PasswordPolicy[] policies = new PasswordPolicy[values.length];
5305        for( int i = 0 ; i < values.length; ++i)
5306        {
5307          policies[i] = values[i].getPolicy();
5308        }
5309    
5310        return policies;
5311      }
5312    
5313    
5314    
5315      /**
5316       * Retrieves the password policy registered for the provided configuration
5317       * entry.
5318       *
5319       * @param  configEntryDN  The DN of the configuration entry for which to
5320       *                        retrieve the associated password policy.
5321       *
5322       * @return  The password policy registered for the provided configuration
5323       *          entry, or <CODE>null</CODE> if there is no such policy.
5324       */
5325      public static PasswordPolicy getPasswordPolicy(DN configEntryDN)
5326      {
5327        Validator.ensureNotNull(configEntryDN);
5328    
5329        PasswordPolicyConfig config
5330                = directoryServer.passwordPolicies.get(configEntryDN);
5331        return (null == config) ? null : config.getPolicy();
5332      }
5333    
5334    
5335      /**
5336       * Retrieves the password policy registered for the provided configuration
5337       * entry.
5338       *
5339       * @param  configEntryDN  The DN of the configuration entry for which to
5340       *                        retrieve the associated password policy.
5341       *
5342       * @return  The password policy config registered for the provided
5343       *          configuration entry, or <CODE>null</CODE> if there is
5344       *          no such policy.
5345       */
5346      public static PasswordPolicyConfig getPasswordPolicyConfig(DN configEntryDN)
5347      {
5348        Validator.ensureNotNull(configEntryDN);
5349    
5350        return directoryServer.passwordPolicies.get(configEntryDN);
5351      }
5352    
5353    
5354      /**
5355       * Registers the provided password policy with the Directory Server.  If a
5356       * policy is already registered for the provided configuration entry DN, then
5357       * it will be replaced.
5358       *
5359       * @param  configEntryDN  The DN of the configuration entry that defines the
5360       *                        password policy.
5361       * @param  config         The password policy config to register with the
5362       *                        server.
5363       */
5364      public static void registerPasswordPolicy(DN configEntryDN,
5365                                                PasswordPolicyConfig config)
5366      {
5367        Validator.ensureNotNull(configEntryDN, config);
5368    
5369        directoryServer.passwordPolicies.put(configEntryDN, config);
5370      }
5371    
5372    
5373    
5374      /**
5375       * Deregisters the provided password policy with the Directory Server.  If no
5376       * such policy is registered, then no action will be taken.
5377       *
5378       * @param  configEntryDN  The DN of the configuration entry that defines the
5379       *                        password policy to deregister.
5380       */
5381      public static void deregisterPasswordPolicy(DN configEntryDN)
5382      {
5383        Validator.ensureNotNull(configEntryDN);
5384    
5385        if (directoryServer.defaultPasswordPolicyDN.equals(configEntryDN))
5386        {
5387          directoryServer.defaultPasswordPolicyConfig = null;
5388        }
5389    
5390        PasswordPolicyConfig config
5391                = directoryServer.passwordPolicies.remove(configEntryDN);
5392      }
5393    
5394    
5395    
5396      /**
5397       * Retrieves the DN of the configuration entry for the default password policy
5398       * for the Directory Server.
5399       *
5400       * @return  The DN of the configuration entry for the default password policy
5401       *          for the Directory Server.
5402       */
5403      public static DN getDefaultPasswordPolicyDN()
5404      {
5405        return directoryServer.defaultPasswordPolicyDN;
5406      }
5407    
5408    
5409    
5410      /**
5411       * Specifies the DN of the configuration entry for the default password policy
5412       * for the Directory Server. This routine does not check the registered
5413       * password policies for the specified DN, since in the case of server
5414       * initialization, the password policy entries will not yet have been loaded
5415       * from the configuration backend.
5416       *
5417       * @param  defaultPasswordPolicyDN  The DN of the configuration entry for the
5418       *                                  default password policy for the Directory
5419       *                                  Server.
5420       */
5421      public static void setDefaultPasswordPolicyDN(DN defaultPasswordPolicyDN)
5422      {
5423        directoryServer.defaultPasswordPolicyDN = defaultPasswordPolicyDN;
5424        directoryServer.defaultPasswordPolicyConfig = null;
5425      }
5426    
5427    
5428    
5429      /**
5430       * Retrieves the default password policy for the Directory Server. This method
5431       * is equivalent to invoking <CODE>getPasswordPolicy</CODE> on the DN returned
5432       * from <CODE>DirectoryServer.getDefaultPasswordPolicyDN()</CODE>.
5433       *
5434       * @return  The default password policy for the Directory Server.
5435       */
5436      public static PasswordPolicy getDefaultPasswordPolicy()
5437      {
5438        assert null != directoryServer.passwordPolicies.get(
5439                                           directoryServer.defaultPasswordPolicyDN)
5440                : "Internal Error: no default password policy defined." ;
5441    
5442        if ((directoryServer.defaultPasswordPolicyConfig == null) &&
5443            (directoryServer.defaultPasswordPolicyDN != null))
5444        {
5445          directoryServer.defaultPasswordPolicyConfig =
5446               directoryServer.passwordPolicies.get(
5447                                           directoryServer.defaultPasswordPolicyDN);
5448        }
5449        assert directoryServer.passwordPolicies.get(
5450                                           directoryServer.defaultPasswordPolicyDN)
5451                    == directoryServer.defaultPasswordPolicyConfig
5452               : "Internal Error: inconsistency between defaultPasswordPolicyConfig"
5453                 + " cache and value in passwordPolicies map.";
5454        return directoryServer.defaultPasswordPolicyConfig.getPolicy();
5455      }
5456    
5457    
5458      /**
5459       * Retrieves the log rotation policy registered for the provided configuration
5460       * entry.
5461       *
5462       * @param  configEntryDN  The DN of the configuration entry for which to
5463       *                        retrieve the associated rotation policy.
5464       *
5465       * @return  The rotation policy registered for the provided configuration
5466       *          entry, or <CODE>null</CODE> if there is no such policy.
5467       */
5468      public static RotationPolicy getRotationPolicy(DN configEntryDN)
5469      {
5470        Validator.ensureNotNull(configEntryDN);
5471    
5472        return directoryServer.rotationPolicies.get(configEntryDN);
5473      }
5474    
5475        /**
5476       * Registers the provided log rotation policy with the Directory Server.  If a
5477       * policy is already registered for the provided configuration entry DN, then
5478       * it will be replaced.
5479       *
5480       * @param  configEntryDN  The DN of the configuration entry that defines the
5481       *                        password policy.
5482       * @param  policy         The rotation policy to register with the server.
5483       */
5484      public static void registerRotationPolicy(DN configEntryDN,
5485                                                RotationPolicy policy)
5486      {
5487        Validator.ensureNotNull(configEntryDN, policy);
5488    
5489        directoryServer.rotationPolicies.put(configEntryDN, policy);
5490      }
5491    
5492    
5493    
5494      /**
5495       * Deregisters the provided log rotation policy with the Directory Server.
5496       * If no such policy is registered, then no action will be taken.
5497       *
5498       * @param  configEntryDN  The DN of the configuration entry that defines the
5499       *                        rotation policy to deregister.
5500       */
5501      public static void deregisterRotationPolicy(DN configEntryDN)
5502      {
5503        Validator.ensureNotNull(configEntryDN);
5504    
5505        directoryServer.rotationPolicies.remove(configEntryDN);
5506      }
5507    
5508      /**
5509       * Retrieves the log retention policy registered for the provided
5510       * configuration entry.
5511       *
5512       * @param  configEntryDN  The DN of the configuration entry for which to
5513       *                        retrieve the associated retention policy.
5514       *
5515       * @return  The retention policy registered for the provided configuration
5516       *          entry, or <CODE>null</CODE> if there is no such policy.
5517       */
5518      public static RetentionPolicy getRetentionPolicy(DN configEntryDN)
5519      {
5520        Validator.ensureNotNull(configEntryDN);
5521    
5522        return directoryServer.retentionPolicies.get(configEntryDN);
5523      }
5524    
5525      /**
5526       * Registers the provided log retention policy with the Directory Server.
5527       * If a policy is already registered for the provided configuration entry DN,
5528       * then it will be replaced.
5529       *
5530       * @param  configEntryDN  The DN of the configuration entry that defines the
5531       *                        password policy.
5532       * @param  policy         The retention policy to register with the server.
5533       */
5534      public static void registerRetentionPolicy(DN configEntryDN,
5535                                                RetentionPolicy policy)
5536      {
5537        Validator.ensureNotNull(configEntryDN, policy);
5538    
5539        directoryServer.retentionPolicies.put(configEntryDN, policy);
5540      }
5541    
5542    
5543    
5544      /**
5545       * Deregisters the provided log retention policy with the Directory Server.
5546       * If no such policy is registered, then no action will be taken.
5547       *
5548       * @param  configEntryDN  The DN of the configuration entry that defines the
5549       *                        retention policy to deregister.
5550       */
5551      public static void deregisterRetentionPolicy(DN configEntryDN)
5552      {
5553        Validator.ensureNotNull(configEntryDN);
5554    
5555        directoryServer.retentionPolicies.remove(configEntryDN);
5556      }
5557    
5558      /**
5559       * Retrieves the set of monitor providers that have been registered with the
5560       * Directory Server, as a mapping between the monitor name (in all lowercase
5561       * characters) and the monitor implementation.
5562       *
5563       * @return  The set of monitor providers that have been registered with the
5564       *          Directory Server.
5565       */
5566      public static ConcurrentHashMap<String,
5567                                      MonitorProvider<? extends MonitorProviderCfg>>
5568                         getMonitorProviders()
5569      {
5570        return directoryServer.monitorProviders;
5571      }
5572    
5573    
5574    
5575      /**
5576       * Retrieves the monitor provider with the specified name.
5577       *
5578       * @param  lowerName  The name of the monitor provider to retrieve, in all
5579       *                    lowercase characters.
5580       *
5581       * @return  The requested resource monitor, or <CODE>null</CODE> if none
5582       *          exists with the specified name.
5583       */
5584      public static MonitorProvider<? extends MonitorProviderCfg>
5585                         getMonitorProvider(String lowerName)
5586      {
5587        return directoryServer.monitorProviders.get(lowerName);
5588      }
5589    
5590    
5591    
5592      /**
5593       * Registers the provided monitor provider with the Directory Server.  Note
5594       * that if a monitor provider is already registered with the specified name,
5595       * then it will be replaced with the provided implementation.
5596       *
5597       * @param  monitorProvider  The monitor provider to register with the
5598       *                          Directory Server.
5599       */
5600      public static void registerMonitorProvider(
5601                              MonitorProvider<? extends MonitorProviderCfg>
5602                                   monitorProvider)
5603      {
5604        String lowerName = toLowerCase(monitorProvider.getMonitorInstanceName());
5605        directoryServer.monitorProviders.put(lowerName, monitorProvider);
5606    
5607    
5608        // Try to register this monitor provider with an appropriate JMX MBean.
5609        try
5610        {
5611          DN monitorDN = getMonitorProviderDN(monitorProvider);
5612          JMXMBean mBean = directoryServer.mBeans.get(monitorDN);
5613          if (mBean == null)
5614          {
5615            mBean = new JMXMBean(monitorDN);
5616            mBean.addMonitorProvider(monitorProvider);
5617            directoryServer.mBeans.put(monitorDN, mBean);
5618          }
5619          else
5620          {
5621            mBean.addMonitorProvider(monitorProvider);
5622          }
5623        }
5624        catch (Exception e)
5625        {
5626          if (debugEnabled())
5627          {
5628            TRACER.debugCaught(DebugLogLevel.ERROR, e);
5629          }
5630        }
5631      }
5632    
5633    
5634    
5635      /**
5636       * Deregisters the specified monitor provider from the Directory Server.  If
5637       * no such monitor provider is registered, no action will be taken.
5638       *
5639       * @param  lowerName  The name of the monitor provider to deregister, in all
5640       *                    lowercase characters.
5641       */
5642      public static void deregisterMonitorProvider(String lowerName)
5643      {
5644        MonitorProvider provider =
5645             directoryServer.monitorProviders.remove(toLowerCase(lowerName));
5646    
5647    
5648        // Try to deregister the monitor provider as an MBean.
5649        if (provider != null)
5650        {
5651          try
5652          {
5653            DN monitorDN = getMonitorProviderDN(provider);
5654            JMXMBean mBean = directoryServer.mBeans.get(monitorDN);
5655            if (mBean != null)
5656            {
5657              mBean.removeMonitorProvider(provider);
5658            }
5659          }
5660          catch (Exception e)
5661          {
5662            if (debugEnabled())
5663            {
5664              TRACER.debugCaught(DebugLogLevel.ERROR, e);
5665            }
5666          }
5667        }
5668      }
5669    
5670    
5671    
5672      /**
5673       * Retrieves the entry cache for the Directory Server.
5674       *
5675       * @return  The entry cache for the Directory Server.
5676       */
5677      public static EntryCache getEntryCache()
5678      {
5679        return directoryServer.entryCache;
5680      }
5681    
5682    
5683    
5684      /**
5685       * Specifies the entry cache that should be used by the Directory Server.
5686       * This should only be called by the entry cache configuration manager.
5687       *
5688       * @param  entryCache  The entry cache for the Directory Server.
5689       */
5690      public static void setEntryCache(EntryCache entryCache)
5691      {
5692        synchronized (directoryServer)
5693        {
5694          directoryServer.entryCache = entryCache;
5695        }
5696      }
5697    
5698    
5699    
5700      /**
5701       * Retrieves the set of key manager providers registered with the Directory
5702       * Server.
5703       *
5704       * @return  The set of key manager providers registered with the Directory
5705       *          Server.
5706       */
5707      public static Map<DN,KeyManagerProvider> getKeyManagerProviders()
5708      {
5709        return directoryServer.keyManagerProviders;
5710      }
5711    
5712    
5713    
5714      /**
5715       * Retrieves the key manager provider registered with the provided entry DN.
5716       *
5717       * @param  providerDN  The DN with which the key manager provider is
5718       *                     registered.
5719       *
5720       * @return  The key manager provider registered with the provided entry DN, or
5721       *          {@code null} if there is no such key manager provider registered
5722       *          with the server.
5723       */
5724      public static KeyManagerProvider getKeyManagerProvider(DN providerDN)
5725      {
5726        return directoryServer.keyManagerProviders.get(providerDN);
5727      }
5728    
5729    
5730    
5731      /**
5732       * Registers the provided key manager provider with the Directory Server.
5733       *
5734       * @param  providerDN  The DN with which to register the key manager provider.
5735       * @param  provider    The key manager provider to register with the server.
5736       */
5737      public static void registerKeyManagerProvider(DN providerDN,
5738                                                    KeyManagerProvider provider)
5739      {
5740        directoryServer.keyManagerProviders.put(providerDN, provider);
5741      }
5742    
5743    
5744    
5745      /**
5746       * Deregisters the specified key manager provider with the Directory Server.
5747       *
5748       * @param  providerDN  The DN with which the key manager provider is
5749       *                     registered.
5750       */
5751      public static void deregisterKeyManagerProvider(DN providerDN)
5752      {
5753        directoryServer.keyManagerProviders.remove(providerDN);
5754      }
5755    
5756    
5757    
5758      /**
5759       * Retrieves the set of trust manager providers registered with the Directory
5760       * Server.
5761       *
5762       * @return  The set of trust manager providers registered with the Directory
5763       *          Server.
5764       */
5765      public static Map<DN,TrustManagerProvider> getTrustManagerProviders()
5766      {
5767        return directoryServer.trustManagerProviders;
5768      }
5769    
5770    
5771    
5772      /**
5773       * Retrieves the trust manager provider registered with the provided entry DN.
5774       *
5775       * @param  providerDN  The DN with which the trust manager provider is
5776       *                     registered.
5777       *
5778       * @return  The trust manager provider registered with the provided entry DN,
5779       *          or {@code null} if there is no such trust manager provider
5780       *          registered with the server.
5781       */
5782      public static TrustManagerProvider getTrustManagerProvider(DN providerDN)
5783      {
5784        return directoryServer.trustManagerProviders.get(providerDN);
5785      }
5786    
5787    
5788    
5789      /**
5790       * Registers the provided trust manager provider with the Directory Server.
5791       *
5792       * @param  providerDN  The DN with which to register the trust manager
5793       *                     provider.
5794       * @param  provider    The trust manager provider to register with the server.
5795       */
5796      public static void registerTrustManagerProvider(DN providerDN,
5797                                                      TrustManagerProvider provider)
5798      {
5799        directoryServer.trustManagerProviders.put(providerDN, provider);
5800      }
5801    
5802    
5803    
5804      /**
5805       * Deregisters the specified trust manager provider with the Directory Server.
5806       *
5807       * @param  providerDN  The DN with which the trust manager provider is
5808       *                     registered.
5809       */
5810      public static void deregisterTrustManagerProvider(DN providerDN)
5811      {
5812        directoryServer.trustManagerProviders.remove(providerDN);
5813      }
5814    
5815    
5816    
5817      /**
5818       * Retrieves the set of certificate mappers registered with the Directory
5819       * Server.
5820       *
5821       * @return  The set of certificate mappers registered with the Directory
5822       *          Server.
5823       */
5824      public static Map<DN,CertificateMapper> getCertificateMappers()
5825      {
5826        return directoryServer.certificateMappers;
5827      }
5828    
5829    
5830    
5831      /**
5832       * Retrieves the certificate mapper registered with the provided entry DN.
5833       *
5834       * @param  mapperDN  The DN with which the certificate mapper is registered.
5835       *
5836       * @return  The certificate mapper registered with the provided entry DN, or
5837       *          {@code null} if there is no such certificate mapper registered
5838       *          with the server.
5839       */
5840      public static CertificateMapper getCertificateMapper(DN mapperDN)
5841      {
5842        return directoryServer.certificateMappers.get(mapperDN);
5843      }
5844    
5845    
5846    
5847      /**
5848       * Registers the provided certificate mapper with the Directory Server.
5849       *
5850       * @param  mapperDN  The DN with which to register the certificate mapper.
5851       * @param  mapper    The certificate mapper to register with the server.
5852       */
5853      public static void registerCertificateMapper(DN mapperDN,
5854                                                   CertificateMapper mapper)
5855      {
5856        directoryServer.certificateMappers.put(mapperDN, mapper);
5857      }
5858    
5859    
5860    
5861      /**
5862       * Deregisters the specified certificate mapper with the Directory Server.
5863       *
5864       * @param  mapperDN  The DN with which the certificate mapper is registered.
5865       */
5866      public static void deregisterCertificateMapper(DN mapperDN)
5867      {
5868        directoryServer.certificateMappers.remove(mapperDN);
5869      }
5870    
5871    
5872    
5873    
5874      /**
5875       * Retrieves the set of privileges that should automatically be granted to
5876       * root users when they authenticate.
5877       *
5878       * @return  The set of privileges that should automatically be granted to root
5879       *          users when they authenticate.
5880       */
5881      public static Set<Privilege> getRootPrivileges()
5882      {
5883        return directoryServer.rootDNConfigManager.getRootPrivileges();
5884      }
5885    
5886    
5887    
5888      /**
5889       * Retrieves the DNs for the root users configured in the Directory Server.
5890       * Note that this set should only contain the actual DNs for the root users
5891       * and not any alternate DNs.  Also, the contents of the returned set must not
5892       * be altered by the caller.
5893       *
5894       * @return  The DNs for the root users configured in the Directory Server.
5895       */
5896      public static CopyOnWriteArraySet<DN> getRootDNs()
5897      {
5898        return directoryServer.rootDNs;
5899      }
5900    
5901    
5902    
5903      /**
5904       * Indicates whether the provided DN is the DN for one of the root users
5905       * configured in the Directory Server.
5906       *
5907       * @param  userDN  The user DN for which to make the determination.
5908       *
5909       * @return  <CODE>true</CODE> if the provided user DN is a Directory Server
5910       *          root DN, or <CODE>false</CODE> if not.
5911       */
5912      public static boolean isRootDN(DN userDN)
5913      {
5914        return directoryServer.rootDNs.contains(userDN);
5915      }
5916    
5917    
5918    
5919      /**
5920       * Registers the provided root DN with the Directory Server.
5921       *
5922       * @param  rootDN  The root DN to register with the Directory Server.
5923       */
5924      public static void registerRootDN(DN rootDN)
5925      {
5926        directoryServer.rootDNs.add(rootDN);
5927      }
5928    
5929    
5930    
5931      /**
5932       * Deregisters the provided root DN with the Directory Server.  This will have
5933       * no effect if the provided DN is not registered as a root DN.
5934       *
5935       * @param  rootDN  The root DN to deregister.
5936       */
5937      public static void deregisterRootDN(DN rootDN)
5938      {
5939        directoryServer.rootDNs.remove(rootDN);
5940      }
5941    
5942    
5943    
5944      /**
5945       * Retrieves the set of alternate bind DNs for root users, mapped between the
5946       * alternate DN and the real DN.  The contents of the returned map must not be
5947       * altered by the caller.
5948       *
5949       * @return  The set of alternate bind DNs for root users, mapped between the
5950       *          alternate DN and the real DN.
5951       */
5952      public static ConcurrentHashMap<DN,DN> getAlternateRootBindDNs()
5953      {
5954        return directoryServer.alternateRootBindDNs;
5955      }
5956    
5957    
5958    
5959      /**
5960       * Retrieves the real entry DN for the root user with the provided alternate
5961       * bind DN.
5962       *
5963       * @param  alternateRootBindDN  The alternate root bind DN for which to
5964       *                              retrieve the real entry DN.
5965       *
5966       * @return  The real entry DN for the root user with the provided alternate
5967       *          bind DN, or <CODE>null</CODE> if no such mapping has been defined.
5968       */
5969      public static DN getActualRootBindDN(DN alternateRootBindDN)
5970      {
5971        return directoryServer.alternateRootBindDNs.get(alternateRootBindDN);
5972      }
5973    
5974    
5975    
5976      /**
5977       * Registers an alternate root bind DN using the provided information.
5978       *
5979       * @param  actualRootEntryDN    The actual DN for the root user's entry.
5980       * @param  alternateRootBindDN  The alternate DN that should be interpreted as
5981       *                              if it were the provided actual root entry DN.
5982       *
5983       * @throws  DirectoryException  If the provided alternate bind DN is already
5984       *                              in use for another root user.
5985       */
5986      public static void registerAlternateRootDN(DN actualRootEntryDN,
5987                                                 DN alternateRootBindDN)
5988             throws DirectoryException
5989      {
5990        DN existingRootEntryDN =
5991             directoryServer.alternateRootBindDNs.putIfAbsent(alternateRootBindDN,
5992                                                              actualRootEntryDN);
5993        if ((existingRootEntryDN != null) &&
5994            (! existingRootEntryDN.equals(actualRootEntryDN)))
5995        {
5996          Message message = ERR_CANNOT_REGISTER_DUPLICATE_ALTERNATE_ROOT_BIND_DN.
5997              get(String.valueOf(alternateRootBindDN),
5998                  String.valueOf(existingRootEntryDN));
5999          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
6000        }
6001      }
6002    
6003    
6004    
6005      /**
6006       * Deregisters the provided alternate root bind DN from the server.  This will
6007       * have no effect if there was no mapping defined for the provided alternate
6008       * root bind DN.
6009       *
6010       * @param  alternateRootBindDN  The alternate root bind DN to be deregistered.
6011       *
6012       * @return  The actual root entry DN to which the provided alternate bind DN
6013       *          was mapped, or <CODE>null</CODE> if there was no mapping for the
6014       *          provided DN.
6015       */
6016      public static DN deregisterAlternateRootBindDN(DN alternateRootBindDN)
6017      {
6018        return directoryServer.alternateRootBindDNs.remove(alternateRootBindDN);
6019      }
6020    
6021    
6022    
6023      /**
6024       * Retrieves the result code that should be used when the Directory Server
6025       * encounters an internal server error.
6026       *
6027       * @return  The result code that should be used when the Directory Server
6028       *          encounters an internal server error.
6029       */
6030      public static ResultCode getServerErrorResultCode()
6031      {
6032        return directoryServer.serverErrorResultCode;
6033      }
6034    
6035    
6036    
6037      /**
6038       * Specifies the result code that should be used when the Directory Server
6039       * encounters an internal server error.
6040       *
6041       * @param  serverErrorResultCode  The result code that should be used when the
6042       *                                Directory Server encounters an internal
6043       *                                server error.
6044       */
6045      public static void setServerErrorResultCode(ResultCode serverErrorResultCode)
6046      {
6047        directoryServer.serverErrorResultCode = serverErrorResultCode;
6048      }
6049    
6050    
6051    
6052      /**
6053       * Indicates whether the Directory Server should automatically add missing RDN
6054       * attributes to an entry whenever it is added.
6055       *
6056       * @return  <CODE>true</CODE> if the Directory Server should automatically add
6057       *          missing RDN attributes to an entry, or <CODE>false</CODE> if it
6058       *          should return an error to the client.
6059       */
6060      public static boolean addMissingRDNAttributes()
6061      {
6062        return directoryServer.addMissingRDNAttributes;
6063      }
6064    
6065    
6066    
6067      /**
6068       * Specifies whether the Directory Server should automatically add missing RDN
6069       * attributes to an entry whenever it is added.
6070       *
6071       * @param  addMissingRDNAttributes  Specifies whether the Directory Server
6072       *                                  should automatically add missing RDN
6073       *                                  attributes to an entry whenever it is
6074       *                                  added.
6075       */
6076      public static void setAddMissingRDNAttributes(boolean addMissingRDNAttributes)
6077      {
6078        directoryServer.addMissingRDNAttributes = addMissingRDNAttributes;
6079      }
6080    
6081    
6082    
6083      /**
6084       * Indicates whether to be more flexible in the set of characters allowed for
6085       * attribute names.  The standard requires that only ASCII alphabetic letters,
6086       * numeric digits, and hyphens be allowed, and that the name start with a
6087       * letter.  If attribute name exceptions are enabled, then underscores will
6088       * also be allowed, and the name will be allowed to start with a digit.
6089       *
6090       * @return  <CODE>true</CODE> if the server should use a more flexible
6091       *          syntax for attribute names, or <CODE>false</CODE> if not.
6092       */
6093      public static boolean allowAttributeNameExceptions()
6094      {
6095        return directoryServer.allowAttributeNameExceptions;
6096      }
6097    
6098    
6099    
6100      /**
6101       * Specifies whether to be more flexible in the set of characters allowed for
6102       * attribute names.
6103       *
6104       * @param  allowAttributeNameExceptions  Specifies whether to be more flexible
6105       *                                       in the set of characters allowed for
6106       *                                       attribute names.
6107       */
6108      public static void setAllowAttributeNameExceptions(
6109                              boolean allowAttributeNameExceptions)
6110      {
6111        directoryServer.allowAttributeNameExceptions = allowAttributeNameExceptions;
6112      }
6113    
6114    
6115    
6116      /**
6117       * Indicates whether the Directory Server should perform schema checking.
6118       *
6119       * @return  <CODE>true</CODE> if the Directory Server should perform schema
6120       *          checking, or <CODE>false</CODE> if not.
6121       */
6122      public static boolean checkSchema()
6123      {
6124        return directoryServer.checkSchema;
6125      }
6126    
6127    
6128    
6129      /**
6130       * Specifies whether the Directory Server should perform schema checking.
6131       *
6132       * @param  checkSchema  Specifies whether the Directory Server should perform
6133       *                      schema checking.
6134       */
6135      public static void setCheckSchema(boolean checkSchema)
6136      {
6137        directoryServer.checkSchema = checkSchema;
6138      }
6139    
6140    
6141    
6142      /**
6143       * Retrieves the policy that should be used regarding enforcement of a single
6144       * structural objectclass per entry.
6145       *
6146       * @return  The policy that should be used regarding enforcement of a single
6147       *          structural objectclass per entry.
6148       */
6149      public static AcceptRejectWarn getSingleStructuralObjectClassPolicy()
6150      {
6151        return directoryServer.singleStructuralClassPolicy;
6152      }
6153    
6154    
6155    
6156      /**
6157       * Specifies the policy that should be used regarding enforcement of a single
6158       * structural objectclass per entry.
6159       *
6160       * @param  singleStructuralClassPolicy  The policy that should be used
6161       *                                      regarding enforcement of a single
6162       *                                      structural objectclass per entry.
6163       */
6164      public static void setSingleStructuralObjectClassPolicy(
6165                              AcceptRejectWarn singleStructuralClassPolicy)
6166      {
6167        directoryServer.singleStructuralClassPolicy = singleStructuralClassPolicy;
6168      }
6169    
6170    
6171    
6172      /**
6173       * Retrieves the policy that should be used when an attribute value is found
6174       * that is not valid according to the associated attribute syntax.
6175       *
6176       * @return  The policy that should be used when an attribute value is found
6177       *          that is not valid according to the associated attribute syntax.
6178       */
6179      public static AcceptRejectWarn getSyntaxEnforcementPolicy()
6180      {
6181        return directoryServer.syntaxEnforcementPolicy;
6182      }
6183    
6184    
6185    
6186      /**
6187       * Retrieves the policy that should be used when an attribute value is found
6188       * that is not valid according to the associated attribute syntax.
6189       *
6190       * @param  syntaxEnforcementPolicy  The policy that should be used when an
6191       *                                  attribute value is found that is not valid
6192       *                                  according to the associated attribute
6193       *                                  syntax.
6194       */
6195      public static void setSyntaxEnforcementPolicy(
6196                              AcceptRejectWarn syntaxEnforcementPolicy)
6197      {
6198        directoryServer.syntaxEnforcementPolicy = syntaxEnforcementPolicy;
6199      }
6200    
6201    
6202    
6203      /**
6204       * Indicates whether the Directory Server should send a response to an
6205       * operation that has been abandoned.  Sending such a response is technically
6206       * a violation of the LDAP protocol specification, but not doing so in that
6207       * case can cause problems with clients that are expecting a response and may
6208       * hang until they get one.
6209       *
6210       * @return  <CODE>true</CODE> if the Directory Server should send a response
6211       *          to an operation that has been abandoned, or <CODE>false</CODE> if
6212       *          not.
6213       */
6214      public static boolean notifyAbandonedOperations()
6215      {
6216        return directoryServer.notifyAbandonedOperations;
6217      }
6218    
6219    
6220    
6221      /**
6222       * Specifies whether the Directory Server should send a response to an
6223       * operation that has been abandoned.  Sending such a response is technically
6224       * a violation of the LDAP protocol specification, but not doing so in that
6225       * case can cause problems with clients that are expecting a response and may
6226       * hang until they get one.
6227       *
6228       * @param  notifyAbandonedOperations  Indicates whether the Directory Server
6229       *                                    should send a response to an operation
6230       *                                    that has been abandoned.
6231       */
6232      public static void setNotifyAbandonedOperations(
6233                              boolean notifyAbandonedOperations)
6234      {
6235        directoryServer.notifyAbandonedOperations = notifyAbandonedOperations;
6236      }
6237    
6238    
6239    
6240      /**
6241       * Retrieves the set of backends that have been registered with the Directory
6242       * Server, as a mapping between the backend ID and the corresponding backend.
6243       *
6244       * @return  The set of backends that have been registered with the Directory
6245       *          Server.
6246       */
6247      public static Map<String,Backend> getBackends()
6248      {
6249        return directoryServer.backends;
6250      }
6251    
6252    
6253    
6254      /**
6255       * Retrieves the backend with the specified backend ID.
6256       *
6257       * @param  backendID  The backend ID of the backend to retrieve.
6258       *
6259       * @return  The backend with the specified backend ID, or {@code null} if
6260       *          there is none.
6261       */
6262      public static Backend getBackend(String backendID)
6263      {
6264        return directoryServer.backends.get(backendID);
6265      }
6266    
6267    
6268    
6269      /**
6270       * Indicates whether the Directory Server has a backend with the specified
6271       * backend ID.
6272       *
6273       * @param  backendID  The backend ID for which to make the determination.
6274       *
6275       * @return  {@code true} if the Directory Server has a backend with the
6276       *          specified backend ID, or {@code false} if not.
6277       */
6278      public static boolean hasBackend(String backendID)
6279      {
6280        return directoryServer.backends.containsKey(backendID);
6281      }
6282    
6283    
6284    
6285      /**
6286       * Registers the provided backend with the Directory Server.  Note that this
6287       * will not register the set of configured suffixes with the server, as that
6288       * must be done by the backend itself.
6289       *
6290       * @param  backend  The backend to register with the server.  Neither the
6291       *                  backend nor its backend ID may be null.
6292       *
6293       * @throws  DirectoryException  If the backend ID for the provided backend
6294       *                              conflicts with the backend ID of an existing
6295       *                              backend.
6296       */
6297      public static void registerBackend(Backend backend)
6298             throws DirectoryException
6299      {
6300        ensureNotNull(backend);
6301    
6302        String backendID = backend.getBackendID();
6303        ensureNotNull(backendID);
6304    
6305        synchronized (directoryServer)
6306        {
6307          TreeMap<String, Backend> newBackends =
6308              new TreeMap<String, Backend>(directoryServer.backends);
6309          if (newBackends.containsKey(backendID))
6310          {
6311            Message message = ERR_REGISTER_BACKEND_ALREADY_EXISTS.get(backendID);
6312            throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
6313          }
6314          else
6315          {
6316            newBackends.put(backendID, backend);
6317            directoryServer.backends = newBackends;
6318    
6319            for (String oid : backend.getSupportedControls())
6320            {
6321              registerSupportedControl(oid);
6322            }
6323    
6324            for (String oid : backend.getSupportedFeatures())
6325            {
6326              registerSupportedFeature(oid);
6327            }
6328    
6329            BackendMonitor monitor = new BackendMonitor(backend);
6330            monitor.initializeMonitorProvider(null);
6331            backend.setBackendMonitor(monitor);
6332            registerMonitorProvider(monitor);
6333          }
6334        }
6335      }
6336    
6337    
6338    
6339      /**
6340       * Deregisters the provided backend with the Directory Server.  Note that this
6341       * will not deregister the set of configured suffixes with the server, as that
6342       * must be done by the backend itself.
6343       *
6344       * @param  backend  The backend to deregister with the server.  It must not be
6345       *                  {@code null}.
6346       */
6347      public static void deregisterBackend(Backend backend)
6348      {
6349        ensureNotNull(backend);
6350    
6351        synchronized (directoryServer)
6352        {
6353          TreeMap<String,Backend> newBackends =
6354               new TreeMap<String,Backend>(directoryServer.backends);
6355          newBackends.remove(backend.getBackendID());
6356    
6357          directoryServer.backends = newBackends;
6358    
6359          // Don't need anymore the local backend workflow element so we
6360          // can remove it. We do remove the workflow element only when
6361          // the workflow configuration mode is auto because in manual
6362          // mode the config manager is doing the job.
6363          if (workflowConfigurationModeIsAuto())
6364          {
6365            LocalBackendWorkflowElement.remove(backend.getBackendID());
6366          }
6367    
6368    
6369          BackendMonitor monitor = backend.getBackendMonitor();
6370          if (monitor != null)
6371          {
6372            String instanceName = toLowerCase(monitor.getMonitorInstanceName());
6373            deregisterMonitorProvider(instanceName);
6374            monitor.finalizeMonitorProvider();
6375            backend.setBackendMonitor(null);
6376          }
6377        }
6378      }
6379    
6380    
6381    
6382      /**
6383       * This method returns a map that contains a unique offline state id,
6384       * such as checksum, for every server backend that has registered one.
6385       *
6386       * @return  <CODE>Map</CODE> backend to checksum map for offline state.
6387       */
6388      public static Map<String,Long> getOfflineBackendsStateIDs() {
6389        return Collections.unmodifiableMap(directoryServer.offlineBackendsStateIDs);
6390      }
6391    
6392    
6393    
6394      /**
6395       * This method allows any server backend to register its unique offline
6396       * state, such as checksum, in a global map other server components can
6397       * access to determine if any changes were made to given backend while
6398       * offline.
6399       *
6400       * @param  backend  As returned by <CODE>getBackendID()</CODE> method.
6401       *
6402       * @param  id       Unique offline state identifier such as checksum.
6403       */
6404      public static void registerOfflineBackendStateID(String backend, long id) {
6405        // Zero means failed checksum so just skip it.
6406        if (id != 0) {
6407          directoryServer.offlineBackendsStateIDs.put(backend, id);
6408        }
6409      }
6410    
6411    
6412    
6413      /**
6414       * Retrieves the entire set of base DNs registered with the Directory Server,
6415       * mapped from the base DN to the backend responsible for that base DN.  The
6416       * same backend may be present multiple times, mapped from different base DNs.
6417       *
6418       * @return  The entire set of base DNs registered with the Directory Server.
6419       */
6420      public static Map<DN,Backend> getBaseDNs()
6421      {
6422        return directoryServer.baseDnRegistry.getBaseDnMap();
6423      }
6424    
6425    
6426    
6427      /**
6428       * Retrieves the backend with the specified base DN.
6429       *
6430       * @param  baseDN  The DN that is registered as one of the base DNs for the
6431       *                 backend to retrieve.
6432       *
6433       * @return  The backend with the specified base DN, or {@code null} if there
6434       *          is no backend registered with the specified base DN.
6435       */
6436      public static Backend getBackendWithBaseDN(DN baseDN)
6437      {
6438        return directoryServer.baseDnRegistry.getBaseDnMap().get(baseDN);
6439      }
6440    
6441    
6442    
6443      /**
6444       * Retrieves the backend that should be used to handle operations on the
6445       * specified entry.
6446       *
6447       * @param  entryDN  The DN of the entry for which to retrieve the
6448       *                  corresponding backend.
6449       *
6450       * @return  The backend that should be used to handle operations on the
6451       *          specified entry, or {@code null} if no appropriate backend is
6452       *          registered with the server.
6453       */
6454      public static Backend getBackend(DN entryDN)
6455      {
6456        if (entryDN.isNullDN())
6457        {
6458          return directoryServer.rootDSEBackend;
6459        }
6460    
6461        Map<DN,Backend> baseDNs = directoryServer.baseDnRegistry.getBaseDnMap();
6462        Backend b = baseDNs.get(entryDN);
6463        while (b == null)
6464        {
6465          entryDN = entryDN.getParent();
6466          if (entryDN == null)
6467          {
6468            return null;
6469          }
6470    
6471          b = baseDNs.get(entryDN);
6472        }
6473    
6474        return b;
6475      }
6476    
6477    
6478      /**
6479       * Obtains a copy of the server's base DN registry.  The copy can be used
6480       * to test registration/deregistration of base DNs but cannot be used to
6481       * modify the backends.  To modify the server's live base DN to backend
6482       * mappings use {@link #registerBaseDN(DN, Backend, boolean)} and
6483       * {@link #deregisterBaseDN(DN)}.
6484       *
6485       * @return copy of the base DN regsitry
6486       */
6487      public static BaseDnRegistry copyBaseDnRegistry()
6488      {
6489        return directoryServer.baseDnRegistry.copy();
6490      }
6491    
6492    
6493      /**
6494       * Registers the provided base DN with the server.
6495       *
6496       * @param  baseDN     The base DN to register with the server.  It must not be
6497       *                    {@code null}.
6498       * @param  backend    The backend responsible for the provided base DN.  It
6499       *                    must not be {@code null}.
6500       * @param  isPrivate  Indicates whether the base DN should be considered a
6501       *                    private base DN.  If the provided base DN is a naming
6502       *                    context, then this controls whether it is public or
6503       *                    private.
6504       *
6505       * @throws  DirectoryException  If a problem occurs while attempting to
6506       *                              register the provided base DN.
6507       */
6508      public static void registerBaseDN(DN baseDN, Backend backend,
6509                                        boolean isPrivate)
6510             throws DirectoryException
6511      {
6512        ensureNotNull(baseDN, backend);
6513    
6514        synchronized (directoryServer)
6515        {
6516          List<Message> warnings =
6517                  directoryServer.baseDnRegistry.registerBaseDN(
6518                          baseDN, backend, isPrivate);
6519    
6520          // Since we've committed the changes we need to log any issues
6521          // that this registration has caused
6522          if (warnings != null) {
6523            for (Message warning : warnings) {
6524              logError(warning);
6525            }
6526          }
6527    
6528          // When a new baseDN is registered with the server we have to create
6529          // a new workflow to handle the base DN. We do not need to create
6530          // the workflow in manual mode because in that case the workflows
6531          // are created explicitely.
6532          if (workflowConfigurationModeIsAuto())
6533          {
6534            // Now create a workflow for the registered baseDN and register
6535            // the workflow with the default network group, but don't register
6536            // the workflow if the backend happens to be the configuration
6537            // backend because it's too soon for the config backend.
6538            if (! baseDN.equals(DN.decode("cn=config")))
6539            {
6540              WorkflowImpl workflowImpl = createWorkflow(baseDN, backend);
6541              registerWorkflowWithDefaultNetworkGroup(workflowImpl);
6542            }
6543          }
6544        }
6545      }
6546    
6547    
6548    
6549      /**
6550       * Deregisters the provided base DN with the server.
6551       *
6552       * @param  baseDN     The base DN to deregister with the server.  It must not
6553       *                    be {@code null}.
6554       *
6555       * @throws  DirectoryException  If a problem occurs while attempting to
6556       *                              deregister the provided base DN.
6557       */
6558      public static void deregisterBaseDN(DN baseDN)
6559             throws DirectoryException
6560      {
6561        ensureNotNull(baseDN);
6562    
6563        synchronized(directoryServer) {
6564    
6565          List<Message> warnings =
6566                  directoryServer.baseDnRegistry.deregisterBaseDN(baseDN);
6567    
6568          // Since we've committed the changes we need to log any issues
6569          // that this registration has caused
6570          if (warnings != null) {
6571            for (Message error : warnings) {
6572              logError(error);
6573            }
6574          }
6575    
6576          // Now we need to deregister the workflow that was associated with
6577          // the base DN but we can do it only when the workflow configuration
6578          // mode is auto, because in manual mode the deregistration is done
6579          // by the workflow config manager.
6580          if (workflowConfigurationModeIsAuto())
6581          {
6582            deregisterWorkflowWithDefaultNetworkGroup(baseDN);
6583          }
6584        }
6585      }
6586    
6587    
6588    
6589      /**
6590       * Retrieves the set of public naming contexts defined in the Directory
6591       * Server, mapped from the naming context DN to the corresponding backend.
6592       *
6593       * @return  The set of public naming contexts defined in the Directory Server.
6594       */
6595      public static Map<DN,Backend> getPublicNamingContexts()
6596      {
6597        return directoryServer.baseDnRegistry.getPublicNamingContextsMap();
6598      }
6599    
6600    
6601    
6602      /**
6603       * Retrieves the set of private naming contexts defined in the Directory
6604       * Server, mapped from the naming context DN to the corresponding backend.
6605       *
6606       * @return  The set of private naming contexts defined in the Directory
6607       *          Server.
6608       */
6609      public static Map<DN,Backend> getPrivateNamingContexts()
6610      {
6611        return directoryServer.baseDnRegistry.getPrivateNamingContextsMap();
6612      }
6613    
6614    
6615    
6616      /**
6617       * Indicates whether the specified DN is one of the Directory Server naming
6618       * contexts.
6619       *
6620       * @param  dn  The DN for which to make the determination.
6621       *
6622       * @return  {@code true} if the specified DN is a naming context for the
6623       *          Directory Server, or {@code false} if it is not.
6624       */
6625      public static boolean isNamingContext(DN dn)
6626      {
6627        return directoryServer.baseDnRegistry.containsNamingContext(dn);
6628      }
6629    
6630    
6631    
6632      /**
6633       * Retrieves the root DSE entry for the Directory Server.
6634       *
6635       * @return  The root DSE entry for the Directory Server.
6636       */
6637      public static Entry getRootDSE()
6638      {
6639        return directoryServer.rootDSEBackend.getRootDSE();
6640      }
6641    
6642    
6643    
6644      /**
6645       * Retrieves the root DSE backend for the Directory Server.
6646       *
6647       * @return  The root DSE backend for the Directory Server.
6648       */
6649      public static RootDSEBackend getRootDSEBackend()
6650      {
6651        return directoryServer.rootDSEBackend;
6652      }
6653    
6654    
6655    
6656      /**
6657       * Retrieves the DN of the entry containing the server schema definitions.
6658       *
6659       * @return  The DN of the entry containing the server schema definitions, or
6660       *          <CODE>null</CODE> if none has been defined (e.g., if no schema
6661       *          backend has been configured).
6662       */
6663      public static DN getSchemaDN()
6664      {
6665        return directoryServer.schemaDN;
6666      }
6667    
6668    
6669    
6670      /**
6671       * Specifies the DN of the entry containing the server schema definitions.
6672       *
6673       * @param  schemaDN  The DN of the entry containing the server schema
6674       *                   definitions.
6675       */
6676      public static void setSchemaDN(DN schemaDN)
6677      {
6678        directoryServer.schemaDN = schemaDN;
6679      }
6680    
6681    
6682    
6683      /**
6684       * Retrieves the entry with the requested DN.  It will first determine which
6685       * backend should be used for this DN and will then use that backend to
6686       * retrieve the entry.  The caller must already hold the appropriate lock on
6687       * the specified entry.
6688       *
6689       * @param  entryDN  The DN of the entry to retrieve.
6690       *
6691       * @return  The requested entry, or <CODE>null</CODE> if it does not exist.
6692       *
6693       * @throws  DirectoryException  If a problem occurs while attempting to
6694       *                              retrieve the entry.
6695       */
6696      public static Entry getEntry(DN entryDN)
6697             throws DirectoryException
6698      {
6699        // If the entry is the root DSE, then get and return that.
6700        if (entryDN.isNullDN())
6701        {
6702          return directoryServer.rootDSEBackend.getRootDSE();
6703        }
6704    
6705        // Figure out which backend should be used for the entry.  If it isn't
6706        // appropriate for any backend, then return null.
6707        Backend backend = getBackend(entryDN);
6708        if (backend == null)
6709        {
6710          return null;
6711        }
6712    
6713        // Retrieve the requested entry from the backend.
6714        return backend.getEntry(entryDN);
6715      }
6716    
6717    
6718    
6719      /**
6720       * Indicates whether the specified entry exists in the Directory Server.  The
6721       * caller is not required to hold any locks when invoking this method.
6722       *
6723       * @param  entryDN  The DN of the entry for which to make the determination.
6724       *
6725       * @return  <CODE>true</CODE> if the specified entry exists in one of the
6726       *          backends, or <CODE>false</CODE> if it does not.
6727       *
6728       * @throws  DirectoryException  If a problem occurs while attempting to
6729       *                              make the determination.
6730       */
6731      public static boolean entryExists(DN entryDN)
6732             throws DirectoryException
6733      {
6734        // If the entry is the root DSE, then it will always exist.
6735        if (entryDN.isNullDN())
6736        {
6737          return true;
6738        }
6739    
6740        // Figure out which backend should be used for the entry.  If it isn't
6741        // appropriate for any backend, then return false.
6742        Backend backend = getBackend(entryDN);
6743        if (backend == null)
6744        {
6745          return false;
6746        }
6747    
6748        // Ask the appropriate backend if the entry exists.
6749        return backend.entryExists(entryDN);
6750      }
6751    
6752    
6753    
6754      /**
6755       * Retrieves the set of supported controls registered with the Directory
6756       * Server.
6757       *
6758       * @return  The set of supported controls registered with the Directory
6759       *          Server.
6760       */
6761      public static TreeSet<String> getSupportedControls()
6762      {
6763        return directoryServer.supportedControls;
6764      }
6765    
6766    
6767    
6768      /**
6769       * Indicates whether the specified OID is registered with the Directory Server
6770       * as a supported control.
6771       *
6772       * @param  controlOID  The OID of the control for which to make the
6773       *                     determination.
6774       *
6775       * @return  <CODE>true</CODE> if the specified OID is registered with the
6776       *          server as a supported control, or <CODE>false</CODE> if not.
6777       */
6778      public static boolean isSupportedControl(String controlOID)
6779      {
6780        return directoryServer.supportedControls.contains(controlOID);
6781      }
6782    
6783    
6784    
6785      /**
6786       * Registers the provided OID as a supported control for the Directory Server.
6787       * This will have no effect if the specified control OID is already present in
6788       * the list of supported controls.
6789       *
6790       * @param  controlOID  The OID of the control to register as a supported
6791       *                     control.
6792       */
6793      public static void registerSupportedControl(String controlOID)
6794      {
6795        synchronized (directoryServer.supportedControls)
6796        {
6797          directoryServer.supportedControls.add(controlOID);
6798        }
6799      }
6800    
6801    
6802    
6803      /**
6804       * Deregisters the provided OID as a supported control for the Directory
6805       * Server.  This will have no effect if the specified control OID is not
6806       * present in the list of supported controls.
6807       *
6808       * @param  controlOID  The OID of the control to deregister as a supported
6809       *                     control.
6810       */
6811      public static void deregisterSupportedControl(String controlOID)
6812      {
6813        synchronized (directoryServer.supportedControls)
6814        {
6815          directoryServer.supportedControls.remove(controlOID);
6816        }
6817      }
6818    
6819    
6820    
6821      /**
6822       * Retrieves the set of supported features registered with the Directory
6823       * Server.
6824       *
6825       * @return  The set of supported features registered with the Directory
6826       *          Server.
6827       */
6828      public static TreeSet<String> getSupportedFeatures()
6829      {
6830        return directoryServer.supportedFeatures;
6831      }
6832    
6833    
6834    
6835      /**
6836       * Indicates whether the specified OID is registered with the Directory Server
6837       * as a supported feature.
6838       *
6839       * @param  featureOID  The OID of the feature for which to make the
6840       *                     determination.
6841       *
6842       * @return  <CODE>true</CODE> if the specified OID is registered with the
6843       *          server as a supported feature, or <CODE>false</CODE> if not.
6844       */
6845      public static boolean isSupportedFeature(String featureOID)
6846      {
6847        return directoryServer.supportedFeatures.contains(featureOID);
6848      }
6849    
6850    
6851    
6852      /**
6853       * Registers the provided OID as a supported feature for the Directory Server.
6854       * This will have no effect if the specified feature OID is already present in
6855       * the list of supported features.
6856       *
6857       * @param  featureOID  The OID of the feature to register as a supported
6858       *                     feature.
6859       */
6860      public static void registerSupportedFeature(String featureOID)
6861      {
6862        synchronized (directoryServer.supportedFeatures)
6863        {
6864          directoryServer.supportedFeatures.add(featureOID);
6865        }
6866      }
6867    
6868    
6869    
6870      /**
6871       * Deregisters the provided OID as a supported feature for the Directory
6872       * Server.  This will have no effect if the specified feature OID is not
6873       * present in the list of supported features.
6874       *
6875       * @param  featureOID  The OID of the feature to deregister as a supported
6876       *                     feature.
6877       */
6878      public static void deregisterSupportedFeature(String featureOID)
6879      {
6880        synchronized (directoryServer.supportedFeatures)
6881        {
6882          directoryServer.supportedFeatures.remove(featureOID);
6883        }
6884      }
6885    
6886    
6887    
6888      /**
6889       * Retrieves the set of extended operations that may be processed by the
6890       * Directory Server.
6891       *
6892       * @return  The set of extended operations that may be processed by the
6893       *         Directory Server.
6894       */
6895      public static ConcurrentHashMap<String,ExtendedOperationHandler>
6896                         getSupportedExtensions()
6897      {
6898        return directoryServer.extendedOperationHandlers;
6899      }
6900    
6901    
6902    
6903      /**
6904       * Retrieves the handler for the extended operation for the provided OID.
6905       *
6906       * @param  oid  The OID of the extended operation to retrieve.
6907       *
6908       * @return  The handler for the specified extended operation, or
6909       *          <CODE>null</CODE> if there is none.
6910       */
6911      public static ExtendedOperationHandler getExtendedOperationHandler(String oid)
6912      {
6913        return directoryServer.extendedOperationHandlers.get(oid);
6914      }
6915    
6916    
6917    
6918      /**
6919       * Registers the provided extended operation handler with the Directory
6920       * Server.
6921       *
6922       * @param  oid      The OID for the extended operation to register.
6923       * @param  handler  The extended operation handler to register with the
6924       *                  Directory Server.
6925       */
6926      public static void registerSupportedExtension(String oid,
6927                              ExtendedOperationHandler handler)
6928      {
6929        directoryServer.extendedOperationHandlers.put(toLowerCase(oid), handler);
6930      }
6931    
6932    
6933    
6934      /**
6935       * Deregisters the provided extended operation handler with the Directory
6936       * Server.
6937       *
6938       * @param  oid  The OID for the extended operation to deregister.
6939       */
6940      public static void deregisterSupportedExtension(String oid)
6941      {
6942        directoryServer.extendedOperationHandlers.remove(toLowerCase(oid));
6943      }
6944    
6945    
6946    
6947      /**
6948       * Retrieves the set of SASL mechanisms that are supported by the Directory
6949       * Server.
6950       *
6951       * @return  The set of SASL mechanisms that are supported by the Directory
6952       *          Server.
6953       */
6954      public static ConcurrentHashMap<String,SASLMechanismHandler>
6955                         getSupportedSASLMechanisms()
6956      {
6957        return directoryServer.saslMechanismHandlers;
6958      }
6959    
6960    
6961    
6962      /**
6963       * Retrieves the handler for the specified SASL mechanism.
6964       *
6965       * @param  name  The name of the SASL mechanism to retrieve.
6966       *
6967       * @return  The handler for the specified SASL mechanism, or <CODE>null</CODE>
6968       *          if there is none.
6969       */
6970      public static SASLMechanismHandler getSASLMechanismHandler(String name)
6971      {
6972        return directoryServer.saslMechanismHandlers.get(name);
6973      }
6974    
6975    
6976    
6977      /**
6978       * Registers the provided SASL mechanism handler with the Directory Server.
6979       *
6980       * @param  name     The name of the SASL mechanism to be registered.
6981       * @param  handler  The SASL mechanism handler to register with the Directory
6982       *                  Server.
6983       */
6984      public static void registerSASLMechanismHandler(String name,
6985                                                      SASLMechanismHandler handler)
6986      {
6987        // FIXME -- Should we force this name to be lowercase?  If so, then will
6988        // that cause the lower name to be used in the root DSE?
6989        directoryServer.saslMechanismHandlers.put(name, handler);
6990      }
6991    
6992    
6993    
6994      /**
6995       * Deregisters the provided SASL mechanism handler with the Directory Server.
6996       *
6997       * @param  name  The name of the SASL mechanism to be deregistered.
6998       */
6999      public static void deregisterSASLMechanismHandler(String name)
7000      {
7001        // FIXME -- Should we force this name to be lowercase?
7002        directoryServer.saslMechanismHandlers.remove(name);
7003      }
7004    
7005    
7006    
7007      /**
7008       * Retrieves the supported LDAP versions for the Directory Server.
7009       *
7010       * @return  The supported LDAP versions for the Directory Server.
7011       */
7012      public static Set<Integer> getSupportedLDAPVersions()
7013      {
7014        return directoryServer.supportedLDAPVersions.keySet();
7015      }
7016    
7017    
7018    
7019      /**
7020       * Registers the provided LDAP protocol version as supported within the
7021       * Directory Server.
7022       *
7023       * @param  supportedLDAPVersion  The LDAP protocol version to register as
7024       *                               supported.
7025       * @param  connectionHandler     The connection handler that supports the
7026       *                               provided LDAP version.  Note that multiple
7027       *                               connection handlers can provide support for
7028       *                               the same LDAP versions.
7029       */
7030      public static synchronized void registerSupportedLDAPVersion(
7031                                           int supportedLDAPVersion,
7032                                           ConnectionHandler connectionHandler)
7033      {
7034        List<ConnectionHandler> handlers =
7035             directoryServer.supportedLDAPVersions.get(supportedLDAPVersion);
7036        if (handlers == null)
7037        {
7038          handlers = new LinkedList<ConnectionHandler>();
7039          handlers.add(connectionHandler);
7040          directoryServer.supportedLDAPVersions.put(supportedLDAPVersion, handlers);
7041        }
7042        else
7043        {
7044          if (! handlers.contains(connectionHandler))
7045          {
7046            handlers.add(connectionHandler);
7047          }
7048        }
7049      }
7050    
7051    
7052    
7053      /**
7054       * Deregisters the provided LDAP protocol version as supported within the
7055       * Directory Server.
7056       *
7057       * @param  supportedLDAPVersion  The LDAP protocol version to deregister.
7058       * @param  connectionHandler     The connection handler that no longer
7059       *                               supports the provided LDAP version.
7060       */
7061      public static synchronized void deregisterSupportedLDAPVersion(
7062                                           int supportedLDAPVersion,
7063                                           ConnectionHandler connectionHandler)
7064      {
7065        List<ConnectionHandler> handlers =
7066             directoryServer.supportedLDAPVersions.get(supportedLDAPVersion);
7067        if (handlers != null)
7068        {
7069          handlers.remove(connectionHandler);
7070          if (handlers.isEmpty())
7071          {
7072            directoryServer.supportedLDAPVersions.remove(supportedLDAPVersion);
7073          }
7074        }
7075      }
7076    
7077    
7078    
7079    
7080      /**
7081       * Retrieves the set of identity mappers defined in the Directory Server
7082       * configuration, as a mapping between the DN of the configuration entry and
7083       * the identity mapper.
7084       *
7085       * @return  The set of identity mappers defined in the Directory Server
7086       *          configuration.
7087       */
7088      public static ConcurrentHashMap<DN,IdentityMapper> getIdentityMappers()
7089      {
7090        return directoryServer.identityMappers;
7091      }
7092    
7093    
7094    
7095      /**
7096       * Retrieves the Directory Server identity mapper whose configuration resides
7097       * in the specified configuration entry.
7098       *
7099       * @param  configEntryDN  The DN of the configuration entry for the identity
7100       *                        mapper to retrieve.
7101       *
7102       * @return  The requested identity mapper, or <CODE>null</CODE> if the
7103       *          provided entry DN is not associated with an active identity
7104       *          mapper.
7105       */
7106      public static IdentityMapper getIdentityMapper(DN configEntryDN)
7107      {
7108        return directoryServer.identityMappers.get(configEntryDN);
7109      }
7110    
7111    
7112    
7113      /**
7114       * Registers the provided identity mapper for use with the Directory Server.
7115       *
7116       * @param  configEntryDN   The DN of the configuration entry in which the
7117       *                         identity mapper definition resides.
7118       * @param  identityMapper  The identity mapper to be registered.
7119       */
7120      public static void registerIdentityMapper(DN configEntryDN,
7121                                                IdentityMapper identityMapper)
7122      {
7123        directoryServer.identityMappers.put(configEntryDN, identityMapper);
7124      }
7125    
7126    
7127    
7128      /**
7129       * Deregisters the provided identity mapper for use with the Directory Server.
7130       *
7131       * @param  configEntryDN  The DN of the configuration entry in which the
7132       *                        identity mapper definition resides.
7133       */
7134      public static void deregisterIdentityMapper(DN configEntryDN)
7135      {
7136        directoryServer.identityMappers.remove(configEntryDN);
7137      }
7138    
7139    
7140    
7141      /**
7142       * Retrieves the DN of the configuration entry for the identity mapper that
7143       * should be used in conjunction with proxied authorization V2 controls.
7144       *
7145       * @return  The DN of the configuration entry for the identity mapper that
7146       *          should be used in conjunction with proxied authorization V2
7147       *          controls, or <CODE>null</CODE> if none is defined.
7148       */
7149      public static DN getProxiedAuthorizationIdentityMapperDN()
7150      {
7151        return directoryServer.proxiedAuthorizationIdentityMapperDN;
7152      }
7153    
7154    
7155    
7156      /**
7157       * Specifies the DN of the configuration entry for the identity mapper that
7158       * should be used in conjunction with proxied authorization V2 controls.
7159       *
7160       * @param  proxiedAuthorizationIdentityMapperDN  The DN of the configuration
7161       *                                               entry for the identity mapper
7162       *                                               that should be used in
7163       *                                               conjunction with proxied
7164       *                                               authorization V2 controls.
7165       */
7166      public static void setProxiedAuthorizationIdentityMapperDN(
7167                              DN proxiedAuthorizationIdentityMapperDN)
7168      {
7169        directoryServer.proxiedAuthorizationIdentityMapperDN =
7170             proxiedAuthorizationIdentityMapperDN;
7171      }
7172    
7173    
7174    
7175      /**
7176       * Retrieves the identity mapper that should be used to resolve authorization
7177       * IDs contained in proxied authorization V2 controls.
7178       *
7179       * @return  The identity mapper that should be used to resolve authorization
7180       *          IDs contained in proxied authorization V2 controls, or
7181       *          <CODE>null</CODE> if none is defined.
7182       */
7183      public static IdentityMapper getProxiedAuthorizationIdentityMapper()
7184      {
7185        if (directoryServer.proxiedAuthorizationIdentityMapperDN == null)
7186        {
7187          return null;
7188        }
7189    
7190        return directoryServer.identityMappers.get(
7191                    directoryServer.proxiedAuthorizationIdentityMapperDN);
7192      }
7193    
7194    
7195    
7196      /**
7197       * Retrieves the set of connection handlers configured in the Directory
7198       * Server.  The returned list must not be altered.
7199       *
7200       * @return  The set of connection handlers configured in the Directory Server.
7201       */
7202      public static CopyOnWriteArrayList<ConnectionHandler> getConnectionHandlers()
7203      {
7204        return directoryServer.connectionHandlers;
7205      }
7206    
7207    
7208    
7209      /**
7210       * Registers the provided connection handler with the Directory Server.
7211       *
7212       * @param  handler  The connection handler to register with the Directory
7213       *                  Server.
7214       */
7215      public static void registerConnectionHandler(
7216                              ConnectionHandler<? extends ConnectionHandlerCfg>
7217                                   handler)
7218      {
7219        synchronized (directoryServer.connectionHandlers)
7220        {
7221          directoryServer.connectionHandlers.add(handler);
7222    
7223          ConnectionHandlerMonitor monitor = new ConnectionHandlerMonitor(handler);
7224          monitor.initializeMonitorProvider(null);
7225          handler.setConnectionHandlerMonitor(monitor);
7226          registerMonitorProvider(monitor);
7227        }
7228      }
7229    
7230    
7231    
7232      /**
7233       * Deregisters the provided connection handler with the Directory Server.
7234       *
7235       * @param  handler  The connection handler to deregister with the Directory
7236       *                  Server.
7237       */
7238      public static void deregisterConnectionHandler(ConnectionHandler handler)
7239      {
7240        synchronized (directoryServer.connectionHandlers)
7241        {
7242          directoryServer.connectionHandlers.remove(handler);
7243    
7244          ConnectionHandlerMonitor monitor = handler.getConnectionHandlerMonitor();
7245          if (monitor != null)
7246          {
7247            String instanceName = toLowerCase(monitor.getMonitorInstanceName());
7248            deregisterMonitorProvider(instanceName);
7249            monitor.finalizeMonitorProvider();
7250            handler.setConnectionHandlerMonitor(null);
7251          }
7252        }
7253      }
7254    
7255    
7256    
7257      /**
7258       * Starts the connection handlers defined in the Directory Server
7259       * Configuration.
7260       *
7261       * @throws  ConfigException If there are more than one connection handlers
7262       *                          using the same host port or no connection handler
7263       *                          are enabled or we could not bind to any of the
7264       *                          listeners.
7265       */
7266      private void startConnectionHandlers() throws ConfigException
7267      {
7268        LinkedHashSet<HostPort> usedListeners = new LinkedHashSet<HostPort>();
7269        LinkedHashSet<Message> errorMessages = new LinkedHashSet<Message>();
7270        // Check that the port specified in the connection handlers is
7271        // available.
7272        for (ConnectionHandler<?> c : connectionHandlers)
7273        {
7274          for (HostPort listener : c.getListeners())
7275          {
7276            if (usedListeners.contains(listener))
7277            {
7278              // The port was already specified: this is a configuration error,
7279              // log a message.
7280              Message message = ERR_HOST_PORT_ALREADY_SPECIFIED.get(
7281                  c.getConnectionHandlerName(), listener.toString());
7282              logError(message);
7283              errorMessages.add(message);
7284    
7285            }
7286            else
7287            {
7288              usedListeners.add(listener);
7289            }
7290          }
7291        }
7292    
7293        if (errorMessages.size() > 0)
7294        {
7295          throw new ConfigException(ERR_ERROR_STARTING_CONNECTION_HANDLERS.get());
7296        }
7297    
7298    
7299        // If there are no connection handlers log a message.
7300        if (connectionHandlers.isEmpty())
7301        {
7302          Message message = ERR_NOT_AVAILABLE_CONNECTION_HANDLERS.get();
7303          logError(message);
7304          throw new ConfigException(ERR_ERROR_STARTING_CONNECTION_HANDLERS.get());
7305        }
7306    
7307        // At this point, we should be ready to go.  Start all the connection
7308        // handlers.
7309        for (ConnectionHandler c : connectionHandlers)
7310        {
7311          c.start();
7312        }
7313      }
7314    
7315      /**
7316       * Retrieves a reference to the Directory Server work queue.
7317       *
7318       * @return  A reference to the Directory Server work queue.
7319       */
7320      public static WorkQueue getWorkQueue()
7321      {
7322        return directoryServer.workQueue;
7323      }
7324    
7325    
7326    
7327      /**
7328       * Adds the provided operation to the work queue so that it will be processed
7329       * by one of the worker threads.
7330       *
7331       * @param  operation  The operation to be added to the work queue.
7332       *
7333       * @throws  DirectoryException  If a problem prevents the operation from being
7334       *                              added to the queue (e.g., the queue is full).
7335       */
7336      public static void enqueueRequest(AbstractOperation operation)
7337             throws DirectoryException
7338      {
7339        // See if a bind is already in progress on the associated connection.  If so
7340        // then reject the operation.
7341        ClientConnection clientConnection = operation.getClientConnection();
7342        if (clientConnection.bindInProgress() &&
7343            (operation.getOperationType() != OperationType.BIND))
7344        {
7345          Message message = ERR_ENQUEUE_BIND_IN_PROGRESS.get();
7346          throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
7347        }
7348    
7349    
7350        //Reject or accept the unauthenticated requests based on the configuration
7351        // settings.
7352        if ((directoryServer.rejectUnauthenticatedRequests ||
7353             directoryServer.lockdownMode) &&
7354            !clientConnection.getAuthenticationInfo().isAuthenticated())
7355        {
7356          switch(operation.getOperationType())
7357          {
7358            case ADD:
7359            case COMPARE:
7360            case DELETE:
7361            case SEARCH:
7362            case MODIFY:
7363            case MODIFY_DN:
7364              if (directoryServer.lockdownMode)
7365              {
7366                Message message = NOTE_REJECT_OPERATION_IN_LOCKDOWN_MODE.get();
7367                throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
7368                                             message);
7369              }
7370              else
7371              {
7372                Message message = ERR_REJECT_UNAUTHENTICATED_OPERATION.get();
7373                throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
7374                                             message);
7375              }
7376    
7377            case EXTENDED:
7378             ExtendedOperationBasis extOp = (ExtendedOperationBasis) operation;
7379             String   requestOID = extOp.getRequestOID();
7380             if (!((requestOID != null) &&
7381                     requestOID.equals(OID_START_TLS_REQUEST)))
7382             {
7383               if (directoryServer.lockdownMode)
7384               {
7385                 Message message = NOTE_REJECT_OPERATION_IN_LOCKDOWN_MODE.get();
7386                 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
7387                                              message);
7388               }
7389               else
7390               {
7391                 Message message = ERR_REJECT_UNAUTHENTICATED_OPERATION.get();
7392                 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM,
7393                                              message);
7394               }
7395             }
7396             break;
7397    
7398          }
7399    
7400        }
7401    
7402    
7403        // If the associated user is required to change their password before
7404        // continuing, then make sure the associated operation is one that could
7405        // result in the password being changed.  If not, then reject it.
7406        if (clientConnection.mustChangePassword())
7407        {
7408          switch (operation.getOperationType())
7409          {
7410            case ADD:
7411            case COMPARE:
7412            case DELETE:
7413            case MODIFY_DN:
7414            case SEARCH:
7415              // See if the request included the password policy request control.
7416              // If it did, then add a corresponding response control.
7417              for (Control c : operation.getRequestControls())
7418              {
7419                if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
7420                {
7421                  operation.addResponseControl(new PasswordPolicyResponseControl(
7422                       null, 0, PasswordPolicyErrorType.CHANGE_AFTER_RESET));
7423                  break;
7424                }
7425              }
7426    
7427              Message message = ERR_ENQUEUE_MUST_CHANGE_PASSWORD.get();
7428              throw new DirectoryException(
7429                      ResultCode.CONSTRAINT_VIOLATION, message);
7430    
7431            case EXTENDED:
7432              // We will only allow the password modify and StartTLS extended
7433              // operations.
7434              ExtendedOperationBasis extOp = (ExtendedOperationBasis) operation;
7435              String            requestOID = extOp.getRequestOID();
7436              if ((requestOID == null) ||
7437                  ((! requestOID.equals(OID_PASSWORD_MODIFY_REQUEST)) &&
7438                   (! requestOID.equals(OID_START_TLS_REQUEST))))
7439              {
7440                // See if the request included the password policy request control.
7441                // If it did, then add a corresponding response control.
7442                for (Control c : operation.getRequestControls())
7443                {
7444                  if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL))
7445                  {
7446                    operation.addResponseControl(new PasswordPolicyResponseControl(
7447                         null, 0, PasswordPolicyErrorType.CHANGE_AFTER_RESET));
7448                    break;
7449                  }
7450                }
7451    
7452                message = ERR_ENQUEUE_MUST_CHANGE_PASSWORD.get();
7453                throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION,
7454                                             message);
7455              }
7456    
7457              break;
7458    
7459              // Bind, unbind, and abandon will always be allowed.
7460    
7461              // Modify may or may not be allowed, but we'll leave that
7462              // determination up to the modify operation itself.
7463          }
7464        }
7465    
7466    
7467    
7468        directoryServer.workQueue.submitOperation(operation);
7469      }
7470    
7471    
7472    
7473      /**
7474       * Retrieves the set of change notification listeners registered with the
7475       * Directory Server.
7476       *
7477       * @return  The set of change notification listeners registered with the
7478       *          Directory Server.
7479       */
7480      public static CopyOnWriteArrayList<ChangeNotificationListener>
7481                         getChangeNotificationListeners()
7482      {
7483        return directoryServer.changeNotificationListeners;
7484      }
7485    
7486    
7487    
7488      /**
7489       * Registers the provided change notification listener with the Directory
7490       * Server so that it will be notified of any add, delete, modify, or modify DN
7491       * operations that are performed.
7492       *
7493       * @param  changeListener  The change notification listener to register with
7494       *                         the Directory Server.
7495       */
7496      public static void registerChangeNotificationListener(
7497                              ChangeNotificationListener changeListener)
7498      {
7499        directoryServer.changeNotificationListeners.add(changeListener);
7500      }
7501    
7502    
7503    
7504      /**
7505       * Deregisters the provided change notification listener with the Directory
7506       * Server so that it will no longer be notified of any add, delete, modify, or
7507       * modify DN operations that are performed.
7508       *
7509       * @param  changeListener  The change notification listener to deregister with
7510       *                         the Directory Server.
7511       */
7512      public static void deregisterChangeNotificationListener(
7513                              ChangeNotificationListener changeListener)
7514      {
7515        directoryServer.changeNotificationListeners.remove(changeListener);
7516      }
7517    
7518    
7519    
7520      /**
7521       * Retrieves the set of persistent searches registered with the Directory
7522       * Server.
7523       *
7524       * @return  The set of persistent searches registered with the Directory
7525       *          Server.
7526       */
7527      public static CopyOnWriteArrayList<PersistentSearch> getPersistentSearches()
7528      {
7529        return directoryServer.persistentSearches;
7530      }
7531    
7532    
7533    
7534      /**
7535       * Registers the provided persistent search operation with the Directory
7536       * Server so that it will be notified of any add, delete, modify, or modify DN
7537       * operations that are performed.
7538       *
7539       * @param  persistentSearch  The persistent search operation to register with
7540       *                           the Directory Server.
7541       */
7542      public static void registerPersistentSearch(PersistentSearch persistentSearch)
7543      {
7544        directoryServer.persistentSearches.add(persistentSearch);
7545        persistentSearch.getSearchOperation().getClientConnection().
7546             registerPersistentSearch(persistentSearch);
7547      }
7548    
7549    
7550    
7551      /**
7552       * Deregisters the provided persistent search operation with the Directory
7553       * Server so that it will no longer be notified of any add, delete, modify, or
7554       * modify DN operations that are performed.
7555       *
7556       * @param  persistentSearch  The persistent search operation to deregister
7557       *                           with the Directory Server.
7558       */
7559      public static void deregisterPersistentSearch(PersistentSearch
7560                                                         persistentSearch)
7561      {
7562        directoryServer.persistentSearches.remove(persistentSearch);
7563        persistentSearch.getSearchOperation().getClientConnection().
7564             deregisterPersistentSearch(persistentSearch);
7565      }
7566    
7567    
7568    
7569    
7570      /**
7571       * Retrieves the set of synchronization providers that have been registered
7572       * with the Directory Server.
7573       *
7574       * @return  The set of synchronization providers that have been registered
7575       *          with the Directory Server.
7576       */
7577      public static
7578        CopyOnWriteArrayList<SynchronizationProvider<SynchronizationProviderCfg>>
7579          getSynchronizationProviders()
7580      {
7581        return directoryServer.synchronizationProviders;
7582      }
7583    
7584    
7585    
7586      /**
7587       * Registers the provided synchronization provider with the Directory Server.
7588       *
7589       * @param  provider  The synchronization provider to register.
7590       */
7591      public static void registerSynchronizationProvider(
7592          SynchronizationProvider<SynchronizationProviderCfg> provider)
7593      {
7594        directoryServer.synchronizationProviders.add(provider);
7595    
7596        provider.completeSynchronizationProvider();
7597      }
7598    
7599    
7600    
7601      /**
7602       * Deregisters the provided synchronization provider with the Directory
7603       * Server.
7604       *
7605       * @param  provider  The synchronization provider to deregister.
7606       */
7607      public static void deregisterSynchronizationProvider(SynchronizationProvider
7608                                                                provider)
7609      {
7610        directoryServer.synchronizationProviders.remove(provider);
7611      }
7612    
7613    
7614    
7615      /**
7616       * Retrieves a set containing the names of the allowed tasks that may be
7617       * invoked in the server.
7618       *
7619       * @return  A set containing the names of the allowed tasks that may be
7620       *          invoked in the server.
7621       */
7622      public static Set<String> getAllowedTasks()
7623      {
7624        return directoryServer.allowedTasks;
7625      }
7626    
7627    
7628    
7629      /**
7630       * Specifies the set of allowed tasks that may be invoked in the server.
7631       *
7632       * @param  allowedTasks  A set containing the names of the allowed tasks that
7633       *                       may be invoked in the server.
7634       */
7635      public static void setAllowedTasks(Set<String> allowedTasks)
7636      {
7637        directoryServer.allowedTasks = allowedTasks;
7638      }
7639    
7640    
7641    
7642      /**
7643       * Retrieves the set of privileges that have been disabled.
7644       *
7645       * @return  The set of privileges that have been disabled.
7646       */
7647      public static Set<Privilege> getDisabledPrivileges()
7648      {
7649        return directoryServer.disabledPrivileges;
7650      }
7651    
7652    
7653    
7654      /**
7655       * Indicates whether the specified privilege is disabled.
7656       *
7657       * @param  privilege  The privilege for which to make the determination.
7658       *
7659       * @return  {@code true} if the specified privilege is disabled, or
7660       *          {@code false} if not.
7661       */
7662      public static boolean isDisabled(Privilege privilege)
7663      {
7664        return directoryServer.disabledPrivileges.contains(privilege);
7665      }
7666    
7667    
7668    
7669      /**
7670       * Specifies the set of privileges that should be disabled in the server.
7671       *
7672       * @param  disabledPrivileges  The set of privileges that should be disabled
7673       *                             in the server.
7674       */
7675      public static void setDisabledPrivileges(Set<Privilege> disabledPrivileges)
7676      {
7677        directoryServer.disabledPrivileges = disabledPrivileges;
7678      }
7679    
7680    
7681    
7682      /**
7683       * Indicates whether responses to failed bind operations should include a
7684       * message explaining the reason for the failure.
7685       *
7686       * @return  {@code true} if bind responses should include error messages, or
7687       *          {@code false} if not.
7688       */
7689      public static boolean returnBindErrorMessages()
7690      {
7691        return directoryServer.returnBindErrorMessages;
7692      }
7693    
7694    
7695    
7696      /**
7697       * Specifies whether responses to failed bind operations should include a
7698       * message explaining the reason for the failure.
7699       *
7700       * @param  returnBindErrorMessages  Specifies whether responses to failed bind
7701       *                                  operations should include a message
7702       *                                  explaining the reason for the failure.
7703       */
7704      public static void setReturnBindErrorMessages(boolean returnBindErrorMessages)
7705      {
7706        directoryServer.returnBindErrorMessages = returnBindErrorMessages;
7707      }
7708    
7709    
7710    
7711      /**
7712       * Retrieves the maximum length of time in milliseconds that client
7713       * connections should be allowed to remain idle without being disconnected.
7714       *
7715       * @return  The maximum length of time in milliseconds that client connections
7716       *          should be allowed to remain idle without being disconnected.
7717       */
7718      public static long getIdleTimeLimit()
7719      {
7720        return directoryServer.idleTimeLimit;
7721      }
7722    
7723    
7724    
7725      /**
7726       * Specifies the maximum length of time in milliseconds that client
7727       * connections should be allowed to remain idle without being disconnected.
7728       *
7729       * @param  idleTimeLimit  The maximum length of time in milliseconds that
7730       *                        client connections should be allowed to remain idle
7731       *                        without being disconnected.
7732       */
7733      public static void setIdleTimeLimit(long idleTimeLimit)
7734      {
7735        directoryServer.idleTimeLimit = idleTimeLimit;
7736      }
7737    
7738    
7739    
7740      /**
7741       * Indicates whether the Directory Server should save a copy of its
7742       * configuration whenever it is started successfully.
7743       *
7744       * @return  {@code true} if the server should save a copy of its configuration
7745       *          whenever it is started successfully, or {@code false} if not.
7746       */
7747      public static boolean saveConfigOnSuccessfulStartup()
7748      {
7749        return directoryServer.saveConfigOnSuccessfulStartup;
7750      }
7751    
7752    
7753    
7754      /**
7755       * Specifies whether the Directory Server should save a copy of its
7756       * configuration whenever it is started successfully.
7757       *
7758       * @param  saveConfigOnSuccessfulStartup  Specifies whether the server should
7759       *                                        save a copy of its configuration
7760       *                                        whenever it is started successfully.
7761       */
7762      public static void setSaveConfigOnSuccessfulStartup(
7763                              boolean saveConfigOnSuccessfulStartup)
7764      {
7765        directoryServer.saveConfigOnSuccessfulStartup =
7766             saveConfigOnSuccessfulStartup;
7767      }
7768    
7769    
7770    
7771      /**
7772       * Registers the provided backup task listener with the Directory Server.
7773       *
7774       * @param  listener  The backup task listener to register with the Directory
7775       *                   Server.
7776       */
7777      public static void registerBackupTaskListener(BackupTaskListener listener)
7778      {
7779        directoryServer.backupTaskListeners.addIfAbsent(listener);
7780      }
7781    
7782    
7783    
7784      /**
7785       * Deregisters the provided backup task listener with the Directory Server.
7786       *
7787       * @param  listener  The backup task listener to deregister with the Directory
7788       *                   Server.
7789       */
7790      public static void deregisterBackupTaskListener(BackupTaskListener listener)
7791      {
7792        directoryServer.backupTaskListeners.remove(listener);
7793      }
7794    
7795    
7796    
7797      /**
7798       * Notifies the registered backup task listeners that the server will be
7799       * beginning a backup task with the provided information.
7800       *
7801       * @param  backend  The backend in which the backup is to be performed.
7802       * @param  config   The configuration for the backup to be performed.
7803       */
7804      public static void notifyBackupBeginning(Backend backend, BackupConfig config)
7805      {
7806        for (BackupTaskListener listener : directoryServer.backupTaskListeners)
7807        {
7808          try
7809          {
7810            listener.processBackupBegin(backend, config);
7811          }
7812          catch (Exception e)
7813          {
7814            if (debugEnabled())
7815            {
7816              TRACER.debugCaught(DebugLogLevel.ERROR, e);
7817            }
7818          }
7819        }
7820      }
7821    
7822    
7823    
7824      /**
7825       * Notifies the registered backup task listeners that the server has completed
7826       * processing on a backup task with the provided information.
7827       *
7828       * @param  backend     The backend in which the backup was performed.
7829       * @param  config      The configuration for the backup that was performed.
7830       * @param  successful  Indicates whether the backup completed successfully.
7831       */
7832      public static void notifyBackupEnded(Backend backend, BackupConfig config,
7833                                           boolean successful)
7834      {
7835        for (BackupTaskListener listener : directoryServer.backupTaskListeners)
7836        {
7837          try
7838          {
7839            listener.processBackupEnd(backend, config, successful);
7840          }
7841          catch (Exception e)
7842          {
7843            if (debugEnabled())
7844            {
7845              TRACER.debugCaught(DebugLogLevel.ERROR, e);
7846            }
7847          }
7848        }
7849      }
7850    
7851    
7852    
7853      /**
7854       * Registers the provided restore task listener with the Directory Server.
7855       *
7856       * @param  listener  The restore task listener to register with the Directory
7857       *                   Server.
7858       */
7859      public static void registerRestoreTaskListener(RestoreTaskListener listener)
7860      {
7861        directoryServer.restoreTaskListeners.addIfAbsent(listener);
7862      }
7863    
7864    
7865    
7866      /**
7867       * Deregisters the provided restore task listener with the Directory Server.
7868       *
7869       * @param  listener  The restore task listener to deregister with the
7870       *                   Directory Server.
7871       */
7872      public static void deregisterRestoreTaskListener(RestoreTaskListener listener)
7873      {
7874        directoryServer.restoreTaskListeners.remove(listener);
7875      }
7876    
7877    
7878    
7879      /**
7880       * Notifies the registered restore task listeners that the server will be
7881       * beginning a restore task with the provided information.
7882       *
7883       * @param  backend  The backend in which the restore is to be performed.
7884       * @param  config   The configuration for the restore to be performed.
7885       */
7886      public static void notifyRestoreBeginning(Backend backend,
7887                                                RestoreConfig config)
7888      {
7889        for (RestoreTaskListener listener : directoryServer.restoreTaskListeners)
7890        {
7891          try
7892          {
7893            listener.processRestoreBegin(backend, config);
7894          }
7895          catch (Exception e)
7896          {
7897            if (debugEnabled())
7898            {
7899              TRACER.debugCaught(DebugLogLevel.ERROR, e);
7900            }
7901          }
7902        }
7903      }
7904    
7905    
7906    
7907      /**
7908       * Notifies the registered restore task listeners that the server has
7909       * completed processing on a restore task with the provided information.
7910       *
7911       * @param  backend     The backend in which the restore was performed.
7912       * @param  config      The configuration for the restore that was performed.
7913       * @param  successful  Indicates whether the restore completed successfully.
7914       */
7915      public static void notifyRestoreEnded(Backend backend, RestoreConfig config,
7916                                            boolean successful)
7917      {
7918        for (RestoreTaskListener listener : directoryServer.restoreTaskListeners)
7919        {
7920          try
7921          {
7922            listener.processRestoreEnd(backend, config, successful);
7923          }
7924          catch (Exception e)
7925          {
7926            if (debugEnabled())
7927            {
7928              TRACER.debugCaught(DebugLogLevel.ERROR, e);
7929            }
7930          }
7931        }
7932      }
7933    
7934    
7935    
7936      /**
7937       * Registers the provided LDIF export task listener with the Directory Server.
7938       *
7939       * @param  listener  The export task listener to register with the Directory
7940       *                   Server.
7941       */
7942      public static void registerExportTaskListener(ExportTaskListener listener)
7943      {
7944        directoryServer.exportTaskListeners.addIfAbsent(listener);
7945      }
7946    
7947    
7948    
7949      /**
7950       * Deregisters the provided LDIF export task listener with the Directory
7951       * Server.
7952       *
7953       * @param  listener  The export task listener to deregister with the Directory
7954       *                   Server.
7955       */
7956      public static void deregisterExportTaskListener(ExportTaskListener listener)
7957      {
7958        directoryServer.exportTaskListeners.remove(listener);
7959      }
7960    
7961    
7962    
7963      /**
7964       * Notifies the registered LDIF export task listeners that the server will be
7965       * beginning an export task with the provided information.
7966       *
7967       * @param  backend  The backend in which the export is to be performed.
7968       * @param  config   The configuration for the export to be performed.
7969       */
7970      public static void notifyExportBeginning(Backend backend,
7971                                               LDIFExportConfig config)
7972      {
7973        for (ExportTaskListener listener : directoryServer.exportTaskListeners)
7974        {
7975          try
7976          {
7977            listener.processExportBegin(backend, config);
7978          }
7979          catch (Exception e)
7980          {
7981            if (debugEnabled())
7982            {
7983              TRACER.debugCaught(DebugLogLevel.ERROR, e);
7984            }
7985          }
7986        }
7987      }
7988    
7989    
7990    
7991      /**
7992       * Notifies the registered LDIF export task listeners that the server has
7993       * completed processing on an export task with the provided information.
7994       *
7995       * @param  backend     The backend in which the export was performed.
7996       * @param  config      The configuration for the export that was performed.
7997       * @param  successful  Indicates whether the export completed successfully.
7998       */
7999      public static void notifyExportEnded(Backend backend, LDIFExportConfig config,
8000                                           boolean successful)
8001      {
8002        for (ExportTaskListener listener : directoryServer.exportTaskListeners)
8003        {
8004          try
8005          {
8006            listener.processExportEnd(backend, config, successful);
8007          }
8008          catch (Exception e)
8009          {
8010            if (debugEnabled())
8011            {
8012              TRACER.debugCaught(DebugLogLevel.ERROR, e);
8013            }
8014          }
8015        }
8016      }
8017    
8018    
8019    
8020      /**
8021       * Registers the provided LDIF import task listener with the Directory Server.
8022       *
8023       * @param  listener  The import task listener to register with the Directory
8024       *                   Server.
8025       */
8026      public static void registerImportTaskListener(ImportTaskListener listener)
8027      {
8028        directoryServer.importTaskListeners.addIfAbsent(listener);
8029      }
8030    
8031    
8032    
8033      /**
8034       * Deregisters the provided LDIF import task listener with the Directory
8035       * Server.
8036       *
8037       * @param  listener  The import task listener to deregister with the Directory
8038       *                   Server.
8039       */
8040      public static void deregisterImportTaskListener(ImportTaskListener listener)
8041      {
8042        directoryServer.importTaskListeners.remove(listener);
8043      }
8044    
8045    
8046    
8047      /**
8048       * Notifies the registered LDIF import task listeners that the server will be
8049       * beginning an import task with the provided information.
8050       *
8051       * @param  backend  The backend in which the import is to be performed.
8052       * @param  config   The configuration for the import to be performed.
8053       */
8054      public static void notifyImportBeginning(Backend backend,
8055                                               LDIFImportConfig config)
8056      {
8057        for (ImportTaskListener listener : directoryServer.importTaskListeners)
8058        {
8059          try
8060          {
8061            listener.processImportBegin(backend, config);
8062          }
8063          catch (Exception e)
8064          {
8065            if (debugEnabled())
8066            {
8067              TRACER.debugCaught(DebugLogLevel.ERROR, e);
8068            }
8069          }
8070        }
8071      }
8072    
8073    
8074    
8075      /**
8076       * Notifies the registered LDIF import task listeners that the server has
8077       * completed processing on an import task with the provided information.
8078       *
8079       * @param  backend     The backend in which the import was performed.
8080       * @param  config      The configuration for the import that was performed.
8081       * @param  successful  Indicates whether the import completed successfully.
8082       */
8083      public static void notifyImportEnded(Backend backend, LDIFImportConfig config,
8084                                           boolean successful)
8085      {
8086        for (ImportTaskListener listener : directoryServer.importTaskListeners)
8087        {
8088          try
8089          {
8090            listener.processImportEnd(backend, config, successful);
8091          }
8092          catch (Exception e)
8093          {
8094            if (debugEnabled())
8095            {
8096              TRACER.debugCaught(DebugLogLevel.ERROR, e);
8097            }
8098          }
8099        }
8100      }
8101    
8102    
8103    
8104      /**
8105       * Registers the provided shutdown listener with the Directory Server so that
8106       * it will be notified when the server shuts down.
8107       *
8108       * @param  listener  The shutdown listener to register with the Directory
8109       *                   Server.
8110       */
8111      public static void registerShutdownListener(ServerShutdownListener listener)
8112      {
8113        directoryServer.shutdownListeners.add(listener);
8114      }
8115    
8116    
8117    
8118      /**
8119       * Deregisters the provided shutdown listener with the Directory Server.
8120       *
8121       * @param  listener  The shutdown listener to deregister with the Directory
8122       *                   Server.
8123       */
8124      public static void deregisterShutdownListener(ServerShutdownListener listener)
8125      {
8126        directoryServer.shutdownListeners.remove(listener);
8127      }
8128    
8129    
8130      /**
8131       * Initiates the Directory Server shutdown process.  Note that once this has
8132       * started, it should not be interrupted.
8133       *
8134       * @param  className  The fully-qualified name of the Java class that
8135       *                    initiated the shutdown.
8136       * @param  reason     The human-readable reason that the directory server is
8137       *                    shutting down.
8138       */
8139      public static void shutDown(String className, Message reason)
8140      {
8141        synchronized (directoryServer)
8142        {
8143          if (directoryServer.shuttingDown)
8144          {
8145            // We already know that the server is shutting down, so we don't need to
8146            // do anything.
8147            return;
8148          }
8149    
8150          directoryServer.shuttingDown = true;
8151        }
8152    
8153        ConfigEntry rootConfigEntry = null;
8154        try {
8155          rootConfigEntry = directoryServer.configHandler.getConfigRootEntry();
8156        } catch (Exception e) {
8157    
8158        }
8159    
8160        // Send an alert notification that the server is shutting down.
8161        Message message = NOTE_SERVER_SHUTDOWN.get(className, reason);
8162        sendAlertNotification(directoryServer, ALERT_TYPE_SERVER_SHUTDOWN,
8163                message);
8164    
8165    
8166        // Create a shutdown monitor that will watch the rest of the shutdown
8167        // process to ensure that everything goes smoothly.
8168        ServerShutdownMonitor shutdownMonitor = new ServerShutdownMonitor();
8169        shutdownMonitor.start();
8170    
8171    
8172        // Shut down the connection handlers.
8173        for (ConnectionHandler handler : directoryServer.connectionHandlers)
8174        {
8175          try
8176          {
8177    
8178            handler.finalizeConnectionHandler(
8179                    INFO_CONNHANDLER_CLOSED_BY_SHUTDOWN.get(), true);
8180          }
8181          catch (Exception e)
8182          {
8183            if (debugEnabled())
8184            {
8185              TRACER.debugCaught(DebugLogLevel.ERROR, e);
8186            }
8187          }
8188        }
8189        directoryServer.connectionHandlers.clear();
8190    
8191    
8192    
8193        // Call the shutdown plugins, and then finalize all the plugins defined in
8194        // the server.
8195        if (directoryServer.pluginConfigManager != null)
8196        {
8197          directoryServer.pluginConfigManager.invokeShutdownPlugins(reason);
8198          directoryServer.pluginConfigManager.finalizePlugins();
8199        }
8200    
8201    
8202        // shutdown the Synchronization Providers
8203        for (SynchronizationProvider provider :
8204             directoryServer.synchronizationProviders)
8205        {
8206          provider.finalizeSynchronizationProvider();
8207        }
8208    
8209        // Deregister the shutdown hook.
8210        if (directoryServer.shutdownHook != null)
8211        {
8212          try
8213          {
8214            Runtime.getRuntime().removeShutdownHook(directoryServer.shutdownHook);
8215          }
8216          catch (Exception e) {}
8217        }
8218    
8219    
8220        // Stop the work queue.
8221        if (directoryServer.workQueue != null)
8222        {
8223          directoryServer.workQueue.finalizeWorkQueue(reason);
8224        }
8225    
8226    
8227        // Notify all the shutdown listeners.
8228        for (ServerShutdownListener shutdownListener :
8229             directoryServer.shutdownListeners)
8230        {
8231          try
8232          {
8233            shutdownListener.processServerShutdown(reason);
8234          }
8235          catch (Exception e)
8236          {
8237            if (debugEnabled())
8238            {
8239              TRACER.debugCaught(DebugLogLevel.ERROR, e);
8240            }
8241          }
8242        }
8243    
8244    
8245        // Shut down all of the alert handlers.
8246        for (AlertHandler alertHandler : directoryServer.alertHandlers)
8247        {
8248          alertHandler.finalizeAlertHandler();
8249        }
8250    
8251    
8252        // Deregister all of the JMX MBeans.
8253        if (directoryServer.mBeanServer != null)
8254        {
8255          Set mBeanSet = directoryServer.mBeanServer.queryMBeans(null, null);
8256          for (Object o : mBeanSet)
8257          {
8258            if (o instanceof DirectoryServerMBean)
8259            {
8260              try
8261              {
8262                DirectoryServerMBean mBean = (DirectoryServerMBean) o;
8263                directoryServer.mBeanServer.unregisterMBean(mBean.getObjectName());
8264              }
8265              catch (Exception e)
8266              {
8267                if (debugEnabled())
8268                {
8269                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
8270                }
8271              }
8272            }
8273          }
8274        }
8275    
8276    
8277        // Finalize all of the SASL mechanism handlers.
8278        for (SASLMechanismHandler handler :
8279             directoryServer.saslMechanismHandlers.values())
8280        {
8281          try
8282          {
8283            handler.finalizeSASLMechanismHandler();
8284          }
8285          catch (Exception e)
8286          {
8287            if (debugEnabled())
8288            {
8289              TRACER.debugCaught(DebugLogLevel.ERROR, e);
8290            }
8291          }
8292        }
8293    
8294    
8295        // Finalize all of the extended operation handlers.
8296        for (ExtendedOperationHandler handler :
8297             directoryServer.extendedOperationHandlers.values())
8298        {
8299          try
8300          {
8301            handler.finalizeExtendedOperationHandler();
8302          }
8303          catch (Exception e)
8304          {
8305            if (debugEnabled())
8306            {
8307              TRACER.debugCaught(DebugLogLevel.ERROR, e);
8308            }
8309          }
8310        }
8311    
8312    
8313        // Finalize the password policy map.
8314        for (DN configEntryDN : directoryServer.passwordPolicies.keySet())
8315        {
8316          DirectoryServer.deregisterPasswordPolicy(configEntryDN);
8317        }
8318    
8319        // Finalize the access control handler
8320        AccessControlHandler accessControlHandler =
8321            AccessControlConfigManager.getInstance().getAccessControlHandler();
8322        if (accessControlHandler != null)
8323        {
8324          accessControlHandler.finalizeAccessControlHandler();
8325        }
8326    
8327        // Perform any necessary cleanup work for the group manager.
8328        if (directoryServer.groupManager != null)
8329        {
8330          directoryServer.groupManager.finalizeGroupManager();
8331        }
8332    
8333    
8334        // Shut down all the other components that may need special handling.
8335        // NYI
8336    
8337    
8338        // Shut down the monitor providers.
8339        for (MonitorProvider monitor : directoryServer.monitorProviders.values())
8340        {
8341          try
8342          {
8343            monitor.finalizeMonitorProvider();
8344          }
8345          catch (Exception e)
8346          {
8347            if (debugEnabled())
8348            {
8349              TRACER.debugCaught(DebugLogLevel.ERROR, e);
8350            }
8351          }
8352        }
8353    
8354    
8355        // Shut down the backends.
8356        for (Backend backend : directoryServer.backends.values())
8357        {
8358          try
8359          {
8360            // Deregister all the local backend workflow elements that have been
8361            // registered with the server.
8362            LocalBackendWorkflowElement.removeAll();
8363    
8364            for (BackendInitializationListener listener :
8365                 directoryServer.backendInitializationListeners)
8366            {
8367              listener.performBackendFinalizationProcessing(backend);
8368            }
8369    
8370            backend.finalizeBackend();
8371    
8372            // Remove the shared lock for this backend.
8373            try
8374            {
8375              String lockFile = LockFileManager.getBackendLockFileName(backend);
8376              StringBuilder failureReason = new StringBuilder();
8377              if (! LockFileManager.releaseLock(lockFile, failureReason))
8378              {
8379                message = WARN_SHUTDOWN_CANNOT_RELEASE_SHARED_BACKEND_LOCK.
8380                    get(backend.getBackendID(), String.valueOf(failureReason));
8381                logError(message);
8382                // FIXME -- Do we need to send an admin alert?
8383              }
8384    
8385              serverLocked = false;
8386            }
8387            catch (Exception e2)
8388            {
8389              if (debugEnabled())
8390              {
8391                TRACER.debugCaught(DebugLogLevel.ERROR, e2);
8392              }
8393    
8394              message = WARN_SHUTDOWN_CANNOT_RELEASE_SHARED_BACKEND_LOCK.
8395                  get(backend.getBackendID(), stackTraceToSingleLineString(e2));
8396              logError(message);
8397              // FIXME -- Do we need to send an admin alert?
8398            }
8399          }
8400          catch (Exception e)
8401          {
8402            if (debugEnabled())
8403            {
8404              TRACER.debugCaught(DebugLogLevel.ERROR, e);
8405            }
8406          }
8407        }
8408    
8409        // Finalize the entry cache.
8410        EntryCache ec = DirectoryServer.getEntryCache();
8411        if (ec != null)
8412        {
8413          ec.finalizeEntryCache();
8414        }
8415    
8416        // Release the exclusive lock for the Directory Server process.
8417        String lockFile = LockFileManager.getServerLockFileName();
8418        try
8419        {
8420          StringBuilder failureReason = new StringBuilder();
8421          if (! LockFileManager.releaseLock(lockFile, failureReason))
8422          {
8423            message = WARN_CANNOT_RELEASE_EXCLUSIVE_SERVER_LOCK.get(
8424                lockFile, String.valueOf(failureReason));
8425            logError(message);
8426          }
8427        }
8428        catch (Exception e)
8429        {
8430          if (debugEnabled())
8431          {
8432            TRACER.debugCaught(DebugLogLevel.ERROR, e);
8433          }
8434    
8435          message = WARN_CANNOT_RELEASE_EXCLUSIVE_SERVER_LOCK.get(
8436              lockFile, stackTraceToSingleLineString(e));
8437          logError(message);
8438        }
8439    
8440        // Deregister all workflows.
8441        WorkflowImpl.deregisterAllOnShutdown();
8442    
8443        // Deregister all network group configuration.
8444        NetworkGroup.deregisterAllOnShutdown();
8445    
8446        // Force a new InternalClientConnection to be created on restart.
8447        InternalConnectionHandler.clearRootClientConnectionAtShutdown();
8448    
8449        // Log a final message indicating that the server is stopped (which should
8450        // be true for all practical purposes), and then shut down all the error
8451        // loggers.
8452        logError(NOTE_SERVER_STOPPED.get());
8453    
8454        removeAllAccessLogPublishers();
8455        removeAllErrorLogPublishers();
8456        removeAllDebugLogPublishers();
8457    
8458        // Just in case there's something that isn't shut down properly, wait for
8459        // the monitor to give the OK to stop.
8460        shutdownMonitor.waitForMonitor();
8461    
8462    
8463        // At this point, the server is no longer running.  We should destroy the
8464        // handle to the previous instance, but we will want to get a new instance
8465        // in case the server is to be started again later in the same JVM.  Before
8466        // doing that, destroy the previous instance.
8467        DirectoryEnvironmentConfig envConfig = directoryServer.environmentConfig;
8468        directoryServer.destroy();
8469        directoryServer = getNewInstance(envConfig);
8470      }
8471    
8472    
8473    
8474      /**
8475       * Destroy key structures in the current Directory Server instance in a manner
8476       * that can help detect any inappropriate cached references to server
8477       * components.
8478       */
8479      private void destroy()
8480      {
8481        checkSchema                   = true;
8482        isBootstrapped                = false;
8483        isClientBootstrapped          = false;
8484        isRunning                     = false;
8485        lockdownMode                  = true;
8486        rejectUnauthenticatedRequests = true;
8487        shuttingDown                  = true;
8488    
8489        configClass              = null;
8490        configFile               = null;
8491        configHandler            = null;
8492        coreConfigManager        = null;
8493        compressedSchema         = null;
8494        cryptoManager            = null;
8495        defaultBinarySyntax      = null;
8496        defaultBooleanSyntax     = null;
8497        defaultDNSyntax          = null;
8498        defaultIntegerSyntax     = null;
8499        defaultStringSyntax      = null;
8500        defaultSyntax            = null;
8501        entryCache               = null;
8502        environmentConfig        = null;
8503        objectClassAttributeType = null;
8504        schemaDN                 = null;
8505        shutdownHook             = null;
8506        workQueue                = null;
8507    
8508        if (baseDnRegistry != null)
8509        {
8510          baseDnRegistry.clear();
8511          baseDnRegistry = null;
8512        }
8513    
8514        if (backends != null)
8515        {
8516          backends.clear();
8517          backends = null;
8518        }
8519    
8520        if (schema != null)
8521        {
8522          schema.destroy();
8523          schema = null;
8524        }
8525      }
8526    
8527    
8528    
8529      /**
8530       * Causes the Directory Server to perform an in-core restart.  This will
8531       * cause virtually all components of the Directory Server to shut down, and
8532       * once that has completed it will be restarted.
8533       *
8534       * @param  className  The fully-qualified name of the Java class that
8535       *                    initiated the shutdown.
8536       * @param  reason     The human-readable reason that the directory server is
8537       *                    shutting down.
8538       */
8539      public static void restart(String className, Message reason)
8540      {
8541        restart(className, reason, directoryServer.environmentConfig);
8542      }
8543    
8544    
8545    
8546      /**
8547       * Causes the Directory Server to perform an in-core restart.  This will
8548       * cause virtually all components of the Directory Server to shut down, and
8549       * once that has completed it will be restarted.
8550       *
8551       * @param  className  The fully-qualified name of the Java class that
8552       *                    initiated the shutdown.
8553       * @param  reason     The human-readable reason that the directory server is
8554       *                    shutting down.
8555       * @param  config     The environment configuration to use for the server.
8556       */
8557      public static void restart(String className, Message reason,
8558                                 DirectoryEnvironmentConfig config)
8559      {
8560        try
8561        {
8562          shutDown(className, reason);
8563          reinitialize(config);
8564          directoryServer.startServer();
8565        }
8566        catch (Exception e)
8567        {
8568          System.err.println("ERROR:  Unable to perform an in-core restart:");
8569          e.printStackTrace();
8570          System.err.println("Halting the JVM so that it must be manually " +
8571                             "restarted.");
8572    
8573          Runtime.getRuntime().halt(1);
8574        }
8575      }
8576    
8577    
8578    
8579      /**
8580       * Reinitializes the server following a shutdown, preparing it for a call to
8581       * {@code startServer}.
8582       *
8583       * @return  The new Directory Server instance created during the
8584       *          reinitialization process.
8585       *
8586       * @throws  InitializationException  If a problem occurs while trying to
8587       *                                   initialize the config handler or
8588       *                                   bootstrap that server.
8589       */
8590      public static DirectoryServer reinitialize()
8591             throws InitializationException
8592      {
8593        return reinitialize(directoryServer.environmentConfig);
8594      }
8595    
8596    
8597    
8598      /**
8599       * Reinitializes the server following a shutdown, preparing it for a call to
8600       * {@code startServer}.
8601       *
8602       * @param  config  The environment configuration for the Directory Server.
8603       *
8604       * @return  The new Directory Server instance created during the
8605       *          reinitialization process.
8606       *
8607       * @throws  InitializationException  If a problem occurs while trying to
8608       *                                   initialize the config handler or
8609       *                                   bootstrap that server.
8610       */
8611      public static DirectoryServer reinitialize(DirectoryEnvironmentConfig config)
8612             throws InitializationException
8613      {
8614        getNewInstance(config);
8615        LockManager.reinitializeLockTable();
8616        directoryServer.bootstrapServer();
8617        directoryServer.initializeConfiguration();
8618        return directoryServer;
8619      }
8620    
8621    
8622    
8623      /**
8624       * Retrieves the maximum number of concurrent client connections that may be
8625       * established.
8626       *
8627       * @return  The maximum number of concurrent client connections that may be
8628       *          established, or -1 if there is no limit.
8629       */
8630      public static long getMaxAllowedConnections()
8631      {
8632        return directoryServer.maxAllowedConnections;
8633      }
8634    
8635    
8636    
8637      /**
8638       * Specifies the maximum number of concurrent client connections that may be
8639       * established.  A value that is less than or equal to zero will indicate that
8640       * no limit should be enforced.
8641       *
8642       * @param  maxAllowedConnections  The maximum number of concurrent client
8643       *                                connections that may be established.
8644       */
8645      public static void setMaxAllowedConnections(long maxAllowedConnections)
8646      {
8647        if (maxAllowedConnections > 0)
8648        {
8649          directoryServer.maxAllowedConnections = maxAllowedConnections;
8650        }
8651        else
8652        {
8653          directoryServer.maxAllowedConnections = -1;
8654        }
8655      }
8656    
8657    
8658    
8659      /**
8660       * Indicates that a new connection has been accepted and increments the
8661       * associated counters.
8662       *
8663       * @param  clientConnection  The client connection that has been established.
8664       *
8665       * @return  The connection ID that should be used for this connection, or -1
8666       *          if the connection has been rejected for some reason (e.g., the
8667       *          maximum numberof concurrent connections have already been
8668       *          established).
8669       */
8670      public static long newConnectionAccepted(ClientConnection clientConnection)
8671      {
8672        synchronized (directoryServer.establishedConnections)
8673        {
8674          if (directoryServer.lockdownMode)
8675          {
8676            InetAddress remoteAddress = clientConnection.getRemoteAddress();
8677            if ((remoteAddress != null) && (! remoteAddress.isLoopbackAddress()))
8678            {
8679              return -1;
8680            }
8681          }
8682    
8683          if ((directoryServer.maxAllowedConnections > 0) &&
8684              (directoryServer.currentConnections >=
8685                   directoryServer.maxAllowedConnections))
8686          {
8687            return -1;
8688          }
8689    
8690          directoryServer.establishedConnections.add(clientConnection);
8691          directoryServer.currentConnections++;
8692    
8693          if (directoryServer.currentConnections > directoryServer.maxConnections)
8694          {
8695            directoryServer.maxConnections = directoryServer.currentConnections;
8696          }
8697    
8698          return directoryServer.totalConnections++;
8699        }
8700      }
8701    
8702    
8703    
8704      /**
8705       * Indicates that the specified client connection has been closed.
8706       *
8707       * @param  clientConnection  The client connection that has been closed.
8708       */
8709      public static void connectionClosed(ClientConnection clientConnection)
8710      {
8711        synchronized (directoryServer.establishedConnections)
8712        {
8713          directoryServer.establishedConnections.remove(clientConnection);
8714          directoryServer.currentConnections--;
8715        }
8716      }
8717    
8718    
8719    
8720      /**
8721       * Retrieves the number of client connections that are currently established.
8722       *
8723       * @return  The number of client connections that are currently established.
8724       */
8725      public static long getCurrentConnections()
8726      {
8727        return directoryServer.currentConnections;
8728      }
8729    
8730    
8731    
8732      /**
8733       * Retrieves the maximum number of client connections that have been
8734       * established concurrently.
8735       *
8736       * @return  The maximum number of client connections that have been
8737       *          established concurrently.
8738       */
8739      public static long getMaxConnections()
8740      {
8741        return directoryServer.maxConnections;
8742      }
8743    
8744    
8745    
8746      /**
8747       * Retrieves the total number of client connections that have been established
8748       * since the Directory Server started.
8749       *
8750       * @return  The total number of client connections that have been established
8751       *          since the Directory Server started.
8752       */
8753      public static long getTotalConnections()
8754      {
8755        return directoryServer.totalConnections;
8756      }
8757    
8758    
8759    
8760      /**
8761       * Retrieves the full version string for the Directory Server.
8762       *
8763       * @return  The full version string for the Directory Server.
8764       */
8765      public static String getVersionString()
8766      {
8767        return FULL_VERSION_STRING;
8768      }
8769    
8770      /**
8771       * Prints out the version string for the Directory Server.
8772       *
8773       *
8774       * @param  outputStream  The output stream to which the version information
8775       *                       should be written.
8776       *
8777       * @throws  IOException  If a problem occurs while attempting to write the
8778       *                       version information to the provided output stream.
8779       */
8780      public static void printVersion(OutputStream outputStream)
8781      throws IOException
8782      {
8783        outputStream.write(getBytes(PRINTABLE_VERSION_STRING));
8784        return;
8785      }
8786    
8787    
8788      /**
8789       * Retrieves the default maximum number of entries that should be returned for
8790       * a search.
8791       *
8792       * @return  The default maximum number of entries that should be returned for
8793       *          a search.
8794       */
8795      public static int getSizeLimit()
8796      {
8797        return directoryServer.sizeLimit;
8798      }
8799    
8800    
8801    
8802      /**
8803       * Specifies the default maximum number of entries that should be returned for
8804       * a search.
8805       *
8806       * @param  sizeLimit  The default maximum number of entries that should be
8807       *                    returned for a search.
8808       */
8809      public static void setSizeLimit(int sizeLimit)
8810      {
8811        directoryServer.sizeLimit = sizeLimit;
8812      }
8813    
8814    
8815    
8816      /**
8817       * Retrieves the default maximum number of entries that should checked for
8818       * matches during a search.
8819       *
8820       * @return  The default maximum number of entries that should checked for
8821       *          matches during a search.
8822       */
8823      public static int getLookthroughLimit()
8824      {
8825        return directoryServer.lookthroughLimit;
8826      }
8827    
8828    
8829    
8830      /**
8831       * Specifies the default maximum number of entries that should be checked for
8832       * matches during a search.
8833       *
8834       * @param  lookthroughLimit  The default maximum number of entries that should
8835       *                           be check for matches during a search.
8836       */
8837      public static void setLookthroughLimit(int lookthroughLimit)
8838      {
8839        directoryServer.lookthroughLimit = lookthroughLimit;
8840      }
8841    
8842    
8843    
8844      /**
8845       * Retrieves the default maximum length of time in seconds that should be
8846       * allowed when processing a search.
8847       *
8848       * @return  The default maximum length of time in seconds that should be
8849       *          allowed when processing a search.
8850       */
8851      public static int getTimeLimit()
8852      {
8853        return directoryServer.timeLimit;
8854      }
8855    
8856    
8857    
8858      /**
8859       * Specifies the default maximum length of time in seconds that should be
8860       * allowed when processing a search.
8861       *
8862       * @param  timeLimit  The default maximum length of time in seconds that
8863       *                    should be allowed when processing a search.
8864       */
8865      public static void setTimeLimit(int timeLimit)
8866      {
8867        directoryServer.timeLimit = timeLimit;
8868      }
8869    
8870    
8871    
8872      /**
8873       * Specifies whether to collect nanosecond resolution processing times for
8874       * operations.
8875       *
8876       * @param useNanoTime  <code>true</code> if nanosecond resolution times
8877       *                     should be collected or <code>false</code> to
8878       *                     only collect in millisecond resolution.
8879       */
8880      public static void setUseNanoTime(boolean useNanoTime)
8881      {
8882        directoryServer.useNanoTime = useNanoTime;
8883      }
8884    
8885    
8886    
8887      /**
8888       * Retrieves whether operation processing times should be collected with
8889       * nanosecond resolution.
8890       *
8891       * @return  <code>true</code> if nanosecond resolution times are collected
8892       *          or <code>false</code> if only millisecond resolution times are
8893       *          being collected.
8894       */
8895      public static boolean getUseNanoTime()
8896      {
8897        return directoryServer.useNanoTime;
8898      }
8899    
8900    
8901    
8902      /**
8903       * Retrieves the writability mode for the Directory Server.  This will only
8904       * be applicable for user suffixes.
8905       *
8906       * @return  The writability mode for the Directory Server.
8907       */
8908      public static WritabilityMode getWritabilityMode()
8909      {
8910        return directoryServer.writabilityMode;
8911      }
8912    
8913    
8914    
8915      /**
8916       * Specifies the writability mode for the Directory Server.  This will only
8917       * be applicable for user suffixes.
8918       *
8919       * @param writabilityMode  Specifies the writability mode for the Directory
8920       *                         Server.
8921       */
8922      public static void setWritabilityMode(WritabilityMode writabilityMode)
8923      {
8924        directoryServer.writabilityMode = writabilityMode;
8925      }
8926    
8927    
8928    
8929    
8930      /**
8931       * Indicates whether simple bind requests that contain a bind DN will also be
8932       * required to have a password.
8933       *
8934       * @return  <CODE>true</CODE> if simple bind requests containing a bind DN
8935       *          will be required to have a password, or <CODE>false</CODE> if not
8936       *          (and therefore will be treated as anonymous binds).
8937       */
8938      public static boolean bindWithDNRequiresPassword()
8939      {
8940        return directoryServer.bindWithDNRequiresPassword;
8941      }
8942    
8943    
8944    
8945      /**
8946       * Specifies whether simple bind requests that contain a bind DN will also be
8947       * required to have a password.
8948       *
8949       * @param  bindWithDNRequiresPassword  Indicates whether simple bind requests
8950       *                                     that contain a bind DN will also be
8951       *                                     required to have a password.
8952       */
8953      public static void setBindWithDNRequiresPassword(boolean
8954                              bindWithDNRequiresPassword)
8955      {
8956        directoryServer.bindWithDNRequiresPassword = bindWithDNRequiresPassword;
8957      }
8958    
8959    
8960    
8961      /**
8962       * Indicates whether an unauthenticated request should be rejected.
8963       *
8964       * @return <CODE>true</CODE>if an unauthenticated request should be
8965       *         rejected, or <CODE>false</CODE>f if not.
8966       */
8967      public static boolean rejectUnauthenticatedRequests()
8968      {
8969         return directoryServer.rejectUnauthenticatedRequests;
8970      }
8971    
8972      /**
8973       * Specifies whether an unauthenticated request should be rejected.
8974       *
8975       * @param  rejectUnauthenticatedRequests   Indicates whether an
8976       *                                        unauthenticated request should
8977       *                                        be rejected.
8978       */
8979      public static void setRejectUnauthenticatedRequests(boolean
8980                              rejectUnauthenticatedRequests)
8981      {
8982            directoryServer.rejectUnauthenticatedRequests =
8983                                      rejectUnauthenticatedRequests;
8984      }
8985    
8986    
8987    
8988      /**
8989       * Indicates whether the Directory Server is currently configured to operate
8990       * in the lockdown mode, in which all non-root requests will be rejected and
8991       * all connection attempts from non-loopback clients will be rejected.
8992       *
8993       * @return  {@code true} if the Directory Server is currently configured to
8994       *          operate in the lockdown mode, or {@code false} if not.
8995       */
8996      public static boolean lockdownMode()
8997      {
8998        return directoryServer.lockdownMode;
8999      }
9000    
9001    
9002    
9003      /**
9004       * Specifies whether the server should operate in lockdown mode.
9005       *
9006       * @param  lockdownMode  Indicates whether the Directory Server should operate
9007       *                       in lockdown mode.
9008       */
9009      public static void setLockdownMode(boolean lockdownMode)
9010      {
9011        directoryServer.lockdownMode = lockdownMode;
9012    
9013        if (lockdownMode)
9014        {
9015          Message message = WARN_DIRECTORY_SERVER_ENTERING_LOCKDOWN_MODE.get();
9016          logError(message);
9017    
9018          sendAlertNotification(directoryServer, ALERT_TYPE_ENTERING_LOCKDOWN_MODE,
9019                  message);
9020        }
9021        else
9022        {
9023          Message message = NOTE_DIRECTORY_SERVER_LEAVING_LOCKDOWN_MODE.get();
9024          logError(message);
9025    
9026          sendAlertNotification(directoryServer, ALERT_TYPE_LEAVING_LOCKDOWN_MODE,
9027                  message);
9028        }
9029      }
9030    
9031    
9032    
9033      /**
9034       * Retrieves the DN of the configuration entry with which this alert generator
9035       * is associated.
9036       *
9037       * @return  The DN of the configuration entry with which this alert generator
9038       *          is associated.
9039       */
9040      public DN getComponentEntryDN()
9041      {
9042        try
9043        {
9044          if (configHandler == null)
9045          {
9046            // The config handler hasn't been initialized yet.  Just return the DN
9047            // of the root DSE.
9048            return DN.nullDN();
9049          }
9050    
9051          return configHandler.getConfigRootEntry().getDN();
9052        }
9053        catch (Exception e)
9054        {
9055          if (debugEnabled())
9056          {
9057            TRACER.debugCaught(DebugLogLevel.ERROR, e);
9058          }
9059    
9060          // This could theoretically happen if an alert needs to be sent before the
9061          // configuration is initialized.  In that case, just return an empty DN.
9062          return DN.nullDN();
9063        }
9064      }
9065    
9066    
9067    
9068      /**
9069       * Retrieves the fully-qualified name of the Java class for this alert
9070       * generator implementation.
9071       *
9072       * @return  The fully-qualified name of the Java class for this alert
9073       *          generator implementation.
9074       */
9075      public String getClassName()
9076      {
9077        return CLASS_NAME;
9078      }
9079    
9080    
9081    
9082      /**
9083       * Retrieves information about the set of alerts that this generator may
9084       * produce.  The map returned should be between the notification type for a
9085       * particular notification and the human-readable description for that
9086       * notification.  This alert generator must not generate any alerts with types
9087       * that are not contained in this list.
9088       *
9089       * @return  Information about the set of alerts that this generator may
9090       *          produce.
9091       */
9092      public LinkedHashMap<String,String> getAlerts()
9093      {
9094        LinkedHashMap<String,String> alerts = new LinkedHashMap<String,String>();
9095    
9096        alerts.put(ALERT_TYPE_SERVER_STARTED, ALERT_DESCRIPTION_SERVER_STARTED);
9097        alerts.put(ALERT_TYPE_SERVER_SHUTDOWN, ALERT_DESCRIPTION_SERVER_SHUTDOWN);
9098        alerts.put(ALERT_TYPE_UNCAUGHT_EXCEPTION,
9099                   ALERT_DESCRIPTION_UNCAUGHT_EXCEPTION);
9100        alerts.put(ALERT_TYPE_ENTERING_LOCKDOWN_MODE,
9101                   ALERT_DESCRIPTION_ENTERING_LOCKDOWN_MODE);
9102        alerts.put(ALERT_TYPE_LEAVING_LOCKDOWN_MODE,
9103                   ALERT_DESCRIPTION_LEAVING_LOCKDOWN_MODE);
9104    
9105        return alerts;
9106      }
9107    
9108    
9109    
9110      /**
9111       * Provides a means of handling a case in which a thread is about to die
9112       * because of an unhandled exception.  This method does nothing to try to
9113       * prevent the death of that thread, but will at least log it so that it can
9114       * be available for debugging purposes.
9115       *
9116       * @param  thread     The thread that threw the exception.
9117       * @param  exception  The exception that was thrown but not properly handled.
9118       */
9119      public void uncaughtException(Thread thread, Throwable exception)
9120      {
9121        if (debugEnabled())
9122        {
9123          TRACER.debugCaught(DebugLogLevel.ERROR, exception);
9124        }
9125    
9126        Message message = ERR_UNCAUGHT_THREAD_EXCEPTION.get(
9127            thread.getName(), stackTraceToString(exception));
9128        logError(message);
9129        sendAlertNotification(this, ALERT_TYPE_UNCAUGHT_EXCEPTION, message);
9130      }
9131    
9132    
9133    
9134      /**
9135       * Indicates whether the server is currently in the process of shutting down.
9136       * @return <CODE>true</CODE> if this server is currently in the process of
9137       * shutting down and <CODE>false</CODE> otherwise.
9138       */
9139      public boolean isShuttingDown()
9140      {
9141        return shuttingDown;
9142      }
9143    
9144    
9145    
9146      /**
9147       * Parses the provided command-line arguments and uses that information to
9148       * bootstrap and start the Directory Server.
9149       *
9150       * @param  args  The command-line arguments provided to this program.
9151       */
9152      public static void main(String[] args)
9153      {
9154        // Define the arguments that may be provided to the server.
9155        BooleanArgument checkStartability      = null;
9156        BooleanArgument quietMode              = null;
9157        BooleanArgument windowsNetStart        = null;
9158        BooleanArgument displayUsage           = null;
9159        BooleanArgument fullVersion            = null;
9160        BooleanArgument noDetach               = null;
9161        BooleanArgument systemInfo             = null;
9162        BooleanArgument useLastKnownGoodConfig = null;
9163        StringArgument  configClass            = null;
9164        StringArgument  configFile             = null;
9165    
9166    
9167        // Create the command-line argument parser for use with this program.
9168        Message toolDescription = INFO_DSCORE_TOOL_DESCRIPTION.get();
9169        ArgumentParser argParser =
9170             new ArgumentParser("org.opends.server.core.DirectoryServer",
9171                                toolDescription, false);
9172    
9173    
9174        // Initialize all the command-line argument types and register them with the
9175        // parser.
9176        try
9177        {
9178          configClass = new StringArgument("configclass", 'C', "configClass",
9179                                           true, false, true,
9180                                           INFO_CONFIGCLASS_PLACEHOLDER.get(),
9181                                           ConfigFileHandler.class.getName(), null,
9182                                           INFO_DSCORE_DESCRIPTION_CONFIG_CLASS
9183                                                   .get());
9184          configClass.setHidden(true);
9185          argParser.addArgument(configClass);
9186    
9187    
9188          configFile = new StringArgument("configfile", 'f', "configFile",
9189                                          true, false, true,
9190                                          INFO_CONFIGFILE_PLACEHOLDER.get(), null,
9191                                          null,
9192                                          INFO_DSCORE_DESCRIPTION_CONFIG_FILE
9193                                                  .get());
9194          configFile.setHidden(true);
9195          argParser.addArgument(configFile);
9196    
9197    
9198          checkStartability = new BooleanArgument("checkstartability", null,
9199                                  "checkStartability",
9200                                  INFO_DSCORE_DESCRIPTION_CHECK_STARTABILITY.get());
9201          checkStartability.setHidden(true);
9202          argParser.addArgument(checkStartability);
9203    
9204          windowsNetStart = new BooleanArgument("windowsnetstart", null,
9205                                  "windowsNetStart",
9206                                  INFO_DSCORE_DESCRIPTION_WINDOWS_NET_START.get());
9207          windowsNetStart.setHidden(true);
9208          argParser.addArgument(windowsNetStart);
9209    
9210    
9211          fullVersion = new BooleanArgument("fullversion", 'F', "fullVersion",
9212                                            INFO_DSCORE_DESCRIPTION_FULLVERSION
9213                                                    .get());
9214          fullVersion.setHidden(true);
9215          argParser.addArgument(fullVersion);
9216    
9217    
9218          systemInfo = new BooleanArgument("systeminfo", 's', "systemInfo",
9219                                           INFO_DSCORE_DESCRIPTION_SYSINFO.get());
9220          argParser.addArgument(systemInfo);
9221    
9222    
9223          useLastKnownGoodConfig =
9224               new BooleanArgument("lastknowngoodconfig", 'L',
9225                                   "useLastKnownGoodConfig",
9226                                   INFO_DSCORE_DESCRIPTION_LASTKNOWNGOODCFG.get());
9227          argParser.addArgument(useLastKnownGoodConfig);
9228    
9229    
9230          noDetach = new BooleanArgument("nodetach", 'N', "nodetach",
9231                                         INFO_DSCORE_DESCRIPTION_NODETACH.get());
9232          argParser.addArgument(noDetach);
9233    
9234    
9235          quietMode = new BooleanArgument("quiet", 'Q', "quiet",
9236                                          INFO_DESCRIPTION_QUIET.get());
9237          argParser.addArgument(quietMode);
9238    
9239    
9240          displayUsage = new BooleanArgument("help", 'H', "help",
9241                                             INFO_DSCORE_DESCRIPTION_USAGE.get());
9242          argParser.addArgument(displayUsage);
9243          argParser.setUsageArgument(displayUsage);
9244        }
9245        catch (ArgumentException ae)
9246        {
9247          Message message = ERR_DSCORE_CANNOT_INITIALIZE_ARGS.get(ae.getMessage());
9248          System.err.println(message);
9249          System.exit(1);
9250        }
9251    
9252    
9253        // Parse the command-line arguments provided to this program.
9254        try
9255        {
9256          argParser.parseArguments(args);
9257        }
9258        catch (ArgumentException ae)
9259        {
9260          Message message = ERR_DSCORE_ERROR_PARSING_ARGS.get(ae.getMessage());
9261          System.err.println(message);
9262          System.err.println(argParser.getUsage());
9263          System.exit(1);
9264        }
9265    
9266    
9267        // If we should just display usage information, then print it and exit.
9268        if (checkStartability.isPresent())
9269        {
9270          // This option should only be used if a PID file already exists in the
9271          // server logs directory, and we need to check which of the following
9272          // conditions best describes the current usage:
9273          // - We're trying to start the server, but it's already running.  The
9274          //   attempt to start the server should fail, and the server process will
9275          //   exit with a result code of 98.
9276          // - We're trying to start the server and it's not already running.  We
9277          //   won't start it in this invocation, but the script used to get to this
9278          //   point should go ahead and overwrite the PID file and retry the
9279          //   startup process.  The server process will exit with a result code of
9280          //   99.
9281          // - We're not trying to start the server, but instead are trying to do
9282          //   something else like display the version number.  In that case, we
9283          //   don't need to write the PID file at all and can just execute the
9284          //   intended command.  If that command was successful, then we'll have an
9285          //   exit code of NOTHING_TO_DO (0).  Otherwise, it will have an exit code
9286          //   that is something other than NOTHING_TO_DO, SERVER_ALREADY_STARTED,
9287          //   START_AS_DETACH, START_AS_NON_DETACH, START_AS_WINDOWS_SERVICE to
9288          //   indicate that a problem occurred.
9289          if (argParser.usageOrVersionDisplayed())
9290          {
9291            // We're just trying to display usage, and that's already been done so
9292            // exit with a code of zero.
9293            System.exit(NOTHING_TO_DO);
9294          }
9295          else if (fullVersion.isPresent() || systemInfo.isPresent())
9296          {
9297            // We're not really trying to start, so rebuild the argument list
9298            // without the "--checkStartability" argument and try again.  Exit with
9299            // whatever that exits with.
9300            LinkedList<String> newArgList = new LinkedList<String>();
9301            for (String arg : args)
9302            {
9303              if (! arg.equalsIgnoreCase("--checkstartability"))
9304              {
9305                newArgList.add(arg);
9306              }
9307            }
9308            String[] newArgs = new String[newArgList.size()];
9309            newArgList.toArray(newArgs);
9310            main(newArgs);
9311            System.exit(NOTHING_TO_DO);
9312          }
9313          else
9314          {
9315            System.exit(checkStartability(argParser));
9316          }
9317        }
9318        else if (argParser.usageOrVersionDisplayed())
9319        {
9320          System.exit(0);
9321        }
9322        else if (fullVersion.isPresent())
9323        {
9324          printFullVersionInformation();
9325          return;
9326        }
9327        else if (systemInfo.isPresent())
9328        {
9329          RuntimeInformation.printInfo();
9330          return;
9331        }
9332    
9333    
9334        // At this point, we know that we're going to try to start the server.
9335        // Attempt to grab an exclusive lock for the Directory Server process.
9336        String lockFile = LockFileManager.getServerLockFileName();
9337        try
9338        {
9339          StringBuilder failureReason = new StringBuilder();
9340          if (! LockFileManager.acquireExclusiveLock(lockFile, failureReason))
9341          {
9342            Message message = ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(lockFile,
9343                                        String.valueOf(failureReason));
9344            System.err.println(message);
9345            System.exit(1);
9346          }
9347        }
9348        catch (Exception e)
9349        {
9350          if (debugEnabled())
9351          {
9352            TRACER.debugCaught(DebugLogLevel.ERROR, e);
9353          }
9354    
9355          Message message = ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(lockFile,
9356                                      stackTraceToSingleLineString(e));
9357          System.err.println(message);
9358          System.exit(1);
9359        }
9360        serverLocked = true;
9361    
9362    
9363        // Configure the JVM to delete the PID file on exit, if it exists.
9364        boolean pidFileMarkedForDeletion      = false;
9365        boolean startingFileMarkedForDeletion = false;
9366        try
9367        {
9368          String pidFilePath;
9369          String startingFilePath;
9370          String serverRoot = System.getenv(ENV_VAR_INSTANCE_ROOT);
9371          if (serverRoot == null)
9372          {
9373            pidFilePath      = "logs/server.pid";
9374            startingFilePath = "logs/server.starting";
9375          }
9376          else
9377          {
9378            pidFilePath      = serverRoot + File.separator + "logs" +
9379                               File.separator + "server.pid";
9380            startingFilePath = serverRoot + File.separator + "logs" +
9381                               File.separator + "server.starting";
9382          }
9383    
9384          File pidFile = new File(pidFilePath);
9385          if (pidFile.exists())
9386          {
9387            pidFile.deleteOnExit();
9388            pidFileMarkedForDeletion = true;
9389          }
9390    
9391          File startingFile = new File(startingFilePath);
9392          if (startingFile.exists())
9393          {
9394            startingFile.deleteOnExit();
9395            startingFileMarkedForDeletion = true;
9396          }
9397        } catch (Exception e) {}
9398    
9399    
9400        // Redirect standard output and standard error to the server.out file.  If
9401        // the server hasn't detached from the terminal, then also continue writing
9402        // to the original standard output and standard error.  Also, configure the
9403        // JVM to delete the PID and server.starting files on exit, if they exist.
9404        PrintStream serverOutStream;
9405        try
9406        {
9407          // We need to figure out where to put the file.  See if the server root
9408          // is available as an environment variable and if so then use it.
9409          // Otherwise, try to figure it out from the location of the config file.
9410          String serverRoot = System.getenv(ENV_VAR_INSTANCE_ROOT);
9411          if (serverRoot == null)
9412          {
9413            serverRoot = new File(configFile.getValue()).getParentFile().
9414                                  getParentFile().getAbsolutePath();
9415          }
9416    
9417          if (serverRoot == null)
9418          {
9419            System.err.println("WARNING:  Unable to determine server root in " +
9420                               "order to redirect standard output and standard " +
9421                               "error.");
9422          }
9423          else
9424          {
9425            File logDir = new File(serverRoot + File.separator + "logs");
9426            if (logDir.exists())
9427            {
9428              FileOutputStream fos =
9429                   new FileOutputStream(new File(logDir, "server.out"), true);
9430              serverOutStream = new PrintStream(fos);
9431    
9432              if (noDetach.isPresent())
9433              {
9434                if (! quietMode.isPresent())
9435                {
9436                  MultiOutputStream multiStream =
9437                       new MultiOutputStream(System.out, serverOutStream);
9438                  serverOutStream = new PrintStream(multiStream);
9439                }
9440              }
9441    
9442              System.setOut(serverOutStream);
9443              System.setErr(serverOutStream);
9444    
9445              if (! pidFileMarkedForDeletion)
9446              {
9447                File f = new File(logDir, "server.pid");
9448                if (f.exists())
9449                {
9450                  f.deleteOnExit();
9451                }
9452              }
9453    
9454              if (! startingFileMarkedForDeletion)
9455              {
9456                File f = new File(logDir, "server.starting");
9457                if (f.exists())
9458                {
9459                  f.deleteOnExit();
9460                }
9461              }
9462            }
9463            else
9464            {
9465              System.err.println("WARNING:  Unable to redirect standard output " +
9466                                 "and standard error because the logs directory " +
9467                                 logDir.getAbsolutePath() + " does not exist.");
9468            }
9469          }
9470        }
9471        catch (Exception e)
9472        {
9473          System.err.println("WARNING:  Unable to redirect standard output and " +
9474                             "standard error:  " + stackTraceToSingleLineString(e));
9475        }
9476    
9477    
9478        // Install the default loggers so the startup messages
9479        // will be printed.
9480        TextErrorLogPublisher startupErrorLogPublisher = null;
9481        TextDebugLogPublisher startupDebugLogPublisher = null;
9482    
9483        startupErrorLogPublisher =
9484            TextErrorLogPublisher.getStartupTextErrorPublisher(
9485                new TextWriter.STDOUT());
9486        ErrorLogger.addErrorLogPublisher(startupErrorLogPublisher);
9487    
9488        startupDebugLogPublisher =
9489            TextDebugLogPublisher.getStartupTextDebugPublisher(
9490                new TextWriter.STDOUT());
9491        DebugLogger.addDebugLogPublisher(startupDebugLogPublisher);
9492    
9493    
9494        // Create an environment configuration for the server and populate a number
9495        // of appropriate properties.
9496        DirectoryEnvironmentConfig environmentConfig =
9497             new DirectoryEnvironmentConfig();
9498        try
9499        {
9500          environmentConfig.setProperty(PROPERTY_CONFIG_CLASS,
9501                                        configClass.getValue());
9502          environmentConfig.setProperty(PROPERTY_CONFIG_FILE,
9503                                        configFile.getValue());
9504          environmentConfig.setProperty(PROPERTY_USE_LAST_KNOWN_GOOD_CONFIG,
9505               String.valueOf(useLastKnownGoodConfig.isPresent()));
9506        }
9507        catch (Exception e)
9508        {
9509          // This shouldn't happen.  For the methods we are using, the exception is
9510          // just a guard against making changes with the server running.
9511        }
9512    
9513    
9514        // Bootstrap and start the Directory Server.
9515        DirectoryServer directoryServer = DirectoryServer.getInstance();
9516        try
9517        {
9518          directoryServer.setEnvironmentConfig(environmentConfig);
9519          directoryServer.bootstrapServer();
9520          directoryServer.initializeConfiguration(configClass.getValue(),
9521                                                  configFile.getValue());
9522        }
9523        catch (InitializationException ie)
9524        {
9525          if (debugEnabled())
9526          {
9527            TRACER.debugCaught(DebugLogLevel.ERROR, ie);
9528          }
9529    
9530          Message message = ERR_DSCORE_CANNOT_BOOTSTRAP.get(ie.getMessage());
9531          System.err.println(message);
9532          System.exit(1);
9533        }
9534        catch (Exception e)
9535        {
9536          Message message = ERR_DSCORE_CANNOT_BOOTSTRAP.get(
9537                  stackTraceToSingleLineString(e));
9538          System.err.println(message);
9539          System.exit(1);
9540        }
9541    
9542        try
9543        {
9544          directoryServer.startServer();
9545        }
9546        catch (InitializationException ie)
9547        {
9548          if (debugEnabled())
9549          {
9550            TRACER.debugCaught(DebugLogLevel.ERROR, ie);
9551          }
9552    
9553          Message message = ERR_DSCORE_CANNOT_START.get(ie.getMessage());
9554          shutDown(directoryServer.getClass().getName(), message);
9555        }
9556        catch (Exception e)
9557        {
9558          Message message = ERR_DSCORE_CANNOT_START.get(
9559                  stackTraceToSingleLineString(e));
9560          shutDown(directoryServer.getClass().getName(), message);
9561        }
9562    
9563        ErrorLogger.removeErrorLogPublisher(startupErrorLogPublisher);
9564        DebugLogger.removeDebugLogPublisher(startupDebugLogPublisher);
9565      }
9566    
9567      /**
9568       * Construct the DN of a monitor provider entry.
9569       * @param provider The monitor provider for which a DN is desired.
9570       * @return The DN of the monitor provider entry.
9571       */
9572      public static DN getMonitorProviderDN(MonitorProvider provider)
9573      {
9574        String monitorName = provider.getMonitorInstanceName();
9575        AttributeType cnType = getAttributeType(ATTR_COMMON_NAME);
9576        DN monitorRootDN;
9577        try
9578        {
9579          monitorRootDN = DN.decode(DN_MONITOR_ROOT);
9580        }
9581        catch (DirectoryException e)
9582        {
9583          // Cannot reach this point.
9584          throw new RuntimeException();
9585        }
9586    
9587        RDN rdn = RDN.create(cnType, new AttributeValue(cnType, monitorName));
9588        return monitorRootDN.concat(rdn);
9589      }
9590    
9591    
9592    
9593      /**
9594       * Gets the class loader to be used with this directory server
9595       * application.
9596       * <p>
9597       * The class loader will automatically load classes from plugins
9598       * where required.
9599       *
9600       * @return Returns the class loader to be used with this directory
9601       *         server application.
9602       */
9603      public static ClassLoader getClassLoader()
9604      {
9605        return ClassLoaderProvider.getInstance().getClassLoader();
9606      }
9607    
9608    
9609    
9610      /**
9611       * Loads the named class using this directory server application's
9612       * class loader.
9613       * <p>
9614       * This method provided as a convenience and is equivalent to
9615       * calling:
9616       *
9617       * <pre>
9618       * Class.forName(name, true, DirectoryServer.getClassLoader());
9619       * </pre>
9620       *
9621       * @param name
9622       *          The fully qualified name of the desired class.
9623       * @return Returns the class object representing the desired class.
9624       * @throws LinkageError
9625       *           If the linkage fails.
9626       * @throws ExceptionInInitializerError
9627       *           If the initialization provoked by this method fails.
9628       * @throws ClassNotFoundException
9629       *           If the class cannot be located by the specified class
9630       *           loader.
9631       * @see Class#forName(String, boolean, ClassLoader)
9632       */
9633      public static Class<?> loadClass(String name) throws LinkageError,
9634          ExceptionInInitializerError, ClassNotFoundException
9635      {
9636        return Class.forName(name, true, DirectoryServer.getClassLoader());
9637      }
9638    
9639    
9640    
9641      /**
9642       * Returns the error code that we return when we are checking the startability
9643       * of the server.
9644       * If there are conflicting arguments (like asking to run the server in non
9645       * detach mode when the server is configured to run as a window service) it
9646       * returns CHECK_ERROR (1).
9647       * @param argParser the ArgumentParser with the arguments already parsed.
9648       * @return the error code that we return when we are checking the startability
9649       * of the server.
9650       */
9651      private static int checkStartability(ArgumentParser argParser)
9652      {
9653        int returnValue;
9654        boolean isServerRunning;
9655    
9656        BooleanArgument noDetach =
9657          (BooleanArgument)argParser.getArgumentForLongID("nodetach");
9658        BooleanArgument quietMode =
9659          (BooleanArgument)argParser.getArgumentForLongID("quiet");
9660        BooleanArgument windowsNetStart =
9661          (BooleanArgument)argParser.getArgumentForLongID("windowsnetstart");
9662    
9663        boolean noDetachPresent = noDetach.isPresent();
9664        boolean windowsNetStartPresent = windowsNetStart.isPresent();
9665    
9666        // We're trying to start the server, so see if it's already running by
9667        // trying to grab an exclusive lock on the server lock file.  If it
9668        // succeeds, then the server isn't running and we can try to start.
9669        // Otherwise, the server is running and this attempt should fail.
9670        String lockFile = LockFileManager.getServerLockFileName();
9671        try
9672        {
9673          StringBuilder failureReason = new StringBuilder();
9674          if (LockFileManager.acquireExclusiveLock(lockFile, failureReason))
9675          {
9676            // The server isn't running, so it can be started.
9677            LockFileManager.releaseLock(lockFile, failureReason);
9678            isServerRunning = false;
9679          }
9680          else
9681          {
9682            // The server's already running.
9683            Message message = ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(lockFile,
9684                String.valueOf(failureReason));
9685            System.err.println(message);
9686            isServerRunning = true;
9687          }
9688        }
9689        catch (Exception e)
9690        {
9691          // We'll treat this as if the server is running because we won't
9692          // be able to start it anyway.
9693          Message message = ERR_CANNOT_ACQUIRE_EXCLUSIVE_SERVER_LOCK.get(lockFile,
9694              getExceptionMessage(e));
9695          System.err.println(message);
9696          isServerRunning = true;
9697        }
9698    
9699        boolean configuredAsService = isRunningAsWindowsService();
9700    
9701        if (isServerRunning)
9702        {
9703          if (configuredAsService && !windowsNetStartPresent)
9704          {
9705            returnValue = START_AS_WINDOWS_SERVICE;
9706          }
9707          else
9708          {
9709            returnValue = SERVER_ALREADY_STARTED;
9710          }
9711        }
9712        else
9713        {
9714          if (configuredAsService)
9715          {
9716            if (noDetachPresent)
9717            {
9718              // Conflicting arguments
9719              returnValue = CHECK_ERROR;
9720              Message message = ERR_DSCORE_ERROR_NODETACH_AND_WINDOW_SERVICE.get();
9721              System.err.println(message);
9722    
9723            }
9724            else
9725            {
9726              if (windowsNetStartPresent)
9727              {
9728                // start-ds.bat is being called through net start, so return
9729                // START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE so that the batch
9730                // file actually starts the server.
9731                returnValue = START_AS_DETACH_CALLED_FROM_WINDOWS_SERVICE;
9732              }
9733              else
9734              {
9735                returnValue = START_AS_WINDOWS_SERVICE;
9736              }
9737            }
9738          }
9739          else
9740          {
9741            if (noDetachPresent)
9742            {
9743              returnValue = START_AS_NON_DETACH;
9744            }
9745            else if (quietMode.isPresent())
9746            {
9747              returnValue = START_AS_DETACH_QUIET;
9748            }
9749            else
9750            {
9751              returnValue = START_AS_DETACH;
9752            }
9753          }
9754        }
9755        return returnValue;
9756      }
9757    
9758      /**
9759       * Returns true if this server is configured to run as a windows service.
9760       * @return <CODE>true</CODE> if this server is configured to run as a windows
9761       * service and <CODE>false</CODE> otherwise.
9762       */
9763      public static boolean isRunningAsWindowsService()
9764      {
9765        boolean isRunningAsWindowsService;
9766        if (SetupUtils.isWindows())
9767        {
9768          isRunningAsWindowsService = ConfigureWindowsService.serviceState(null,
9769          null) == ConfigureWindowsService.SERVICE_STATE_ENABLED;
9770        }
9771        else
9772        {
9773          isRunningAsWindowsService = false;
9774        }
9775        return isRunningAsWindowsService;
9776      }
9777    
9778    
9779      /**
9780       * Specifies whether the workflows are configured automatically or manually.
9781       * In auto configuration mode one workflow is created for each and every
9782       * base DN in the local backends. In the auto configuration mode the
9783       * workflows are created according to their description in the configuration
9784       * file.
9785       *
9786       * @param  workflowConfigurationMode  Indicates whether the workflows are
9787       *                                    configured automatically or manually
9788       */
9789      public static void setWorkflowConfigurationMode(
9790          WorkflowConfigurationMode workflowConfigurationMode)
9791      {
9792        directoryServer.workflowConfigurationMode = workflowConfigurationMode;
9793      }
9794    
9795    
9796      /**
9797       * Indicates whether the workflow configuration mode is 'auto' or not.
9798       *
9799       * @return the workflow configuration mode
9800       */
9801      public static boolean workflowConfigurationModeIsAuto()
9802      {
9803        boolean isAuto =
9804          (directoryServer.workflowConfigurationMode
9805           == WorkflowConfigurationMode.AUTO);
9806        return isAuto;
9807      }
9808    
9809    
9810    
9811      /**
9812       * Retrieves the workflow configuration mode.
9813       *
9814       * @return the workflow configuration mode
9815       */
9816      public static WorkflowConfigurationMode getWorkflowConfigurationMode()
9817      {
9818        return directoryServer.workflowConfigurationMode;
9819      }
9820    
9821    
9822    
9823      /**
9824       * Print messages for start-ds "-F" option (full version information).
9825       */
9826    
9827      private static
9828      void printFullVersionInformation() {
9829        /**
9830         * This option is used by the upgrade to identify the server build and it
9831         * can eventually also be used to be sent to the support in case of an
9832         * issue.  Since this is not a public interface and since it is better
9833         * to always have it in English for the support team, the message is
9834         * not localized.
9835         */
9836        String separator = ": ";
9837        System.out.println(getVersionString());
9838        System.out.println(SetupUtils.BUILD_ID+separator+BUILD_ID);
9839        System.out.println(SetupUtils.MAJOR_VERSION+separator+MAJOR_VERSION);
9840        System.out.println(SetupUtils.MINOR_VERSION+separator+MINOR_VERSION);
9841        System.out.println(SetupUtils.POINT_VERSION+separator+POINT_VERSION);
9842        System.out.println(SetupUtils.VERSION_QUALIFIER+separator+
9843            VERSION_QUALIFIER);
9844        if (BUILD_NUMBER > 0)
9845        {
9846          System.out.println(SetupUtils.BUILD_NUMBER+separator+
9847                         new DecimalFormat("000").format(BUILD_NUMBER));
9848        }
9849        System.out.println(SetupUtils.REVISION_NUMBER+separator+REVISION_NUMBER);
9850        System.out.println(SetupUtils.FIX_IDS+separator+FIX_IDS);
9851        System.out.println(SetupUtils.DEBUG_BUILD+separator+DEBUG_BUILD);
9852        System.out.println(SetupUtils.BUILD_OS+separator+BUILD_OS);
9853        System.out.println(SetupUtils.BUILD_USER+separator+BUILD_USER);
9854        System.out.println(SetupUtils.BUILD_JAVA_VERSION+separator+
9855            BUILD_JAVA_VERSION);
9856        System.out.println(SetupUtils.BUILD_JAVA_VENDOR+separator+
9857            BUILD_JAVA_VENDOR);
9858        System.out.println(SetupUtils.BUILD_JVM_VERSION+separator+
9859            BUILD_JVM_VERSION);
9860        System.out.println(SetupUtils.BUILD_JVM_VENDOR+separator+BUILD_JVM_VENDOR);
9861        System.out.println(SetupUtils.INCOMPATIBILITY_EVENTS+separator+
9862            StaticUtils.listToString(
9863                VersionCompatibilityIssue.getAllEvents(), ","));
9864      }
9865    
9866    }
9867