View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.directory.server.core;
21  
22  
23  import java.io.BufferedReader;
24  import java.io.File;
25  import java.io.FileNotFoundException;
26  import java.io.IOException;
27  import java.io.RandomAccessFile;
28  import java.io.StringReader;
29  import java.lang.reflect.Method;
30  import java.nio.channels.FileLock;
31  import java.nio.channels.OverlappingFileLockException;
32  import java.util.ArrayList;
33  import java.util.Arrays;
34  import java.util.HashMap;
35  import java.util.HashSet;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.Set;
39  import java.util.UUID;
40  import java.util.concurrent.ConcurrentHashMap;
41  import java.util.concurrent.locks.Lock;
42  import java.util.concurrent.locks.ReadWriteLock;
43  import java.util.concurrent.locks.ReentrantReadWriteLock;
44  
45  import javax.naming.directory.Attributes;
46  
47  import org.apache.directory.api.ldap.codec.api.LdapApiService;
48  import org.apache.directory.api.ldap.codec.api.LdapApiServiceFactory;
49  import org.apache.directory.api.ldap.model.constants.AuthenticationLevel;
50  import org.apache.directory.api.ldap.model.constants.SchemaConstants;
51  import org.apache.directory.api.ldap.model.csn.Csn;
52  import org.apache.directory.api.ldap.model.csn.CsnFactory;
53  import org.apache.directory.api.ldap.model.cursor.Cursor;
54  import org.apache.directory.api.ldap.model.entry.Attribute;
55  import org.apache.directory.api.ldap.model.entry.DefaultEntry;
56  import org.apache.directory.api.ldap.model.entry.Entry;
57  import org.apache.directory.api.ldap.model.entry.Modification;
58  import org.apache.directory.api.ldap.model.entry.Value;
59  import org.apache.directory.api.ldap.model.exception.LdapException;
60  import org.apache.directory.api.ldap.model.exception.LdapNoPermissionException;
61  import org.apache.directory.api.ldap.model.exception.LdapOperationException;
62  import org.apache.directory.api.ldap.model.ldif.ChangeType;
63  import org.apache.directory.api.ldap.model.ldif.LdifEntry;
64  import org.apache.directory.api.ldap.model.ldif.LdifReader;
65  import org.apache.directory.api.ldap.model.name.Dn;
66  import org.apache.directory.api.ldap.model.name.DnUtils;
67  import org.apache.directory.api.ldap.model.name.Rdn;
68  import org.apache.directory.api.ldap.model.schema.SchemaManager;
69  import org.apache.directory.api.ldap.util.tree.DnNode;
70  import org.apache.directory.api.util.DateUtils;
71  import org.apache.directory.api.util.Strings;
72  import org.apache.directory.api.util.exception.NotImplementedException;
73  import org.apache.directory.server.constants.ServerDNConstants;
74  import org.apache.directory.server.core.admin.AdministrativePointInterceptor;
75  import org.apache.directory.server.core.api.CacheService;
76  import org.apache.directory.server.core.api.CoreSession;
77  import org.apache.directory.server.core.api.DirectoryService;
78  import org.apache.directory.server.core.api.DnFactory;
79  import org.apache.directory.server.core.api.InstanceLayout;
80  import org.apache.directory.server.core.api.InterceptorEnum;
81  import org.apache.directory.server.core.api.LdapPrincipal;
82  import org.apache.directory.server.core.api.OperationEnum;
83  import org.apache.directory.server.core.api.OperationManager;
84  import org.apache.directory.server.core.api.ReferralManager;
85  import org.apache.directory.server.core.api.administrative.AccessControlAdministrativePoint;
86  import org.apache.directory.server.core.api.administrative.CollectiveAttributeAdministrativePoint;
87  import org.apache.directory.server.core.api.administrative.SubschemaAdministrativePoint;
88  import org.apache.directory.server.core.api.administrative.TriggerExecutionAdministrativePoint;
89  import org.apache.directory.server.core.api.changelog.ChangeLog;
90  import org.apache.directory.server.core.api.changelog.ChangeLogEvent;
91  import org.apache.directory.server.core.api.changelog.Tag;
92  import org.apache.directory.server.core.api.changelog.TaggableSearchableChangeLogStore;
93  import org.apache.directory.server.core.api.event.EventService;
94  import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
95  import org.apache.directory.server.core.api.interceptor.Interceptor;
96  import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
97  import org.apache.directory.server.core.api.interceptor.context.BindOperationContext;
98  import org.apache.directory.server.core.api.interceptor.context.HasEntryOperationContext;
99  import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
100 import org.apache.directory.server.core.api.interceptor.context.OperationContext;
101 import org.apache.directory.server.core.api.journal.Journal;
102 import org.apache.directory.server.core.api.partition.Partition;
103 import org.apache.directory.server.core.api.partition.PartitionNexus;
104 import org.apache.directory.server.core.api.schema.SchemaPartition;
105 import org.apache.directory.server.core.api.subtree.SubentryCache;
106 import org.apache.directory.server.core.api.subtree.SubtreeEvaluator;
107 import org.apache.directory.server.core.authn.AuthenticationInterceptor;
108 import org.apache.directory.server.core.authn.ppolicy.PpolicyConfigContainer;
109 import org.apache.directory.server.core.authz.AciAuthorizationInterceptor;
110 import org.apache.directory.server.core.authz.DefaultAuthorizationInterceptor;
111 import org.apache.directory.server.core.changelog.ChangeLogInterceptor;
112 import org.apache.directory.server.core.changelog.DefaultChangeLog;
113 import org.apache.directory.server.core.collective.CollectiveAttributeInterceptor;
114 import org.apache.directory.server.core.event.EventInterceptor;
115 import org.apache.directory.server.core.exception.ExceptionInterceptor;
116 import org.apache.directory.server.core.journal.DefaultJournal;
117 import org.apache.directory.server.core.journal.JournalInterceptor;
118 import org.apache.directory.server.core.normalization.NormalizationInterceptor;
119 import org.apache.directory.server.core.operational.OperationalAttributeInterceptor;
120 import org.apache.directory.server.core.referral.ReferralInterceptor;
121 import org.apache.directory.server.core.schema.SchemaInterceptor;
122 import org.apache.directory.server.core.security.TlsKeyGenerator;
123 import org.apache.directory.server.core.shared.DefaultCoreSession;
124 import org.apache.directory.server.core.shared.DefaultDnFactory;
125 import org.apache.directory.server.core.shared.partition.DefaultPartitionNexus;
126 import org.apache.directory.server.core.subtree.SubentryInterceptor;
127 import org.apache.directory.server.core.trigger.TriggerInterceptor;
128 import org.apache.directory.server.i18n.I18n;
129 import org.slf4j.Logger;
130 import org.slf4j.LoggerFactory;
131 
132 
133 /**
134  * Default implementation of {@link DirectoryService}.
135  *
136  * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
137  */
138 public class DefaultDirectoryService implements DirectoryService
139 {
140     /** The logger */
141     private static final Logger LOG = LoggerFactory.getLogger( DefaultDirectoryService.class );
142 
143     private SchemaPartition schemaPartition;
144 
145     /** A reference on the SchemaManager */
146     private SchemaManager schemaManager;
147 
148     /** The LDAP Codec Service */
149     private LdapApiService ldapCodecService = LdapApiServiceFactory.getSingleton();
150 
151     /** the root nexus */
152     private DefaultPartitionNexus partitionNexus;
153 
154     /** whether or not server is started for the first time */
155     private boolean firstStart;
156 
157     /** whether or not this instance has been shutdown */
158     private boolean started;
159 
160     /** the change log service */
161     private ChangeLog changeLog;
162 
163     /** the journal service */
164     private Journal journal;
165 
166     /**
167      * the interface used to perform various operations on this
168      * DirectoryService
169      */
170     private OperationManager operationManager = new DefaultOperationManager( this );
171 
172     /** the distinguished name of the administrative user */
173     private Dn adminDn;
174 
175     /** session used as admin for internal operations */
176     private CoreSession adminSession;
177 
178     /** The referral manager */
179     private ReferralManager referralManager;
180 
181     /** A flag to tell if the userPassword attribute's value must be hidden */
182     private boolean passwordHidden = false;
183 
184     /** The service's CSN factory */
185     private CsnFactory csnFactory;
186 
187     /** The directory instance replication ID */
188     private int replicaId;
189 
190     /** remove me after implementation is completed */
191     private static final String PARTIAL_IMPL_WARNING =
192         "WARNING: the changelog is only partially operational and will revert\n" +
193             "state without consideration of who made the original change.  All reverting " +
194             "changes are made by the admin user.\n Furthermore the used controls are not at " +
195             "all taken into account";
196 
197     /** The delay to wait between each sync on disk */
198     private long syncPeriodMillis;
199 
200     /** The default delay to wait between sync on disk : 15 seconds */
201     private static final long DEFAULT_SYNC_PERIOD = 15000;
202 
203     /** */
204     private Thread workerThread;
205 
206     /** The default timeLimit : 100 entries */
207     public static final int MAX_SIZE_LIMIT_DEFAULT = 100;
208 
209     /** The default timeLimit : 10 seconds */
210     public static final int MAX_TIME_LIMIT_DEFAULT = 10000;
211 
212     /** The instance Id */
213     private String instanceId;
214 
215     /** The server directory layout*/
216     private InstanceLayout instanceLayout;
217 
218     /**
219      * A flag used to shutdown the VM when stopping the server. Useful
220      * when the server is standalone. If the server is embedded, we don't
221      * want to shutdown the VM
222      */
223     private boolean exitVmOnShutdown = true; // allow by default
224 
225     /** A flag used to indicate that a shutdown hook has been installed */
226     private boolean shutdownHookEnabled = true; // allow by default
227 
228     /** Manage anonymous access to entries other than the RootDSE */
229     private boolean allowAnonymousAccess = false; // forbid by default
230 
231     /** Manage the basic access control checks */
232     private boolean accessControlEnabled; // off by default
233 
234     /** Manage the operational attributes denormalization */
235     private boolean denormalizeOpAttrsEnabled; // off by default
236 
237     /** The list of declared interceptors */
238     private List<Interceptor> interceptors;
239     private Map<String, Interceptor> interceptorNames;
240 
241     /** A lock to protect the interceptors List */
242     private ReadWriteLock interceptorsLock = new ReentrantReadWriteLock();
243 
244     /** The read and write locks */
245     private Lock readLock = interceptorsLock.readLock();
246     private Lock writeLock = interceptorsLock.writeLock();
247 
248     /** A map associating a list of interceptor to each operation */
249     private Map<OperationEnum, List<String>> operationInterceptors;
250 
251     /** The System partition */
252     private Partition systemPartition;
253 
254     /** The set of all declared partitions */
255     private Set<Partition> partitions = new HashSet<Partition>();
256 
257     /** A list of LDIF entries to inject at startup */
258     private List<? extends LdifEntry> testEntries = new ArrayList<LdifEntry>(); // List<Attributes>
259 
260     /** The event service */
261     private EventService eventService;
262 
263     /** The maximum size for an incoming PDU */
264     private int maxPDUSize = Integer.MAX_VALUE;
265 
266     /** the value of last successful add/update operation's CSN */
267     private String contextCsn;
268 
269     /** lock file for directory service's working directory */
270     private RandomAccessFile lockFile = null;
271 
272     private static final String LOCK_FILE_NAME = ".dirservice.lock";
273 
274     /** the ehcache based cache service */
275     private CacheService cacheService;
276 
277     /** The AccessControl AdministrativePoint cache */
278     private DnNode<AccessControlAdministrativePoint> accessControlAPCache;
279 
280     /** The CollectiveAttribute AdministrativePoint cache */
281     private DnNode<CollectiveAttributeAdministrativePoint> collectiveAttributeAPCache;
282 
283     /** The Subschema AdministrativePoint cache */
284     private DnNode<SubschemaAdministrativePoint> subschemaAPCache;
285 
286     /** The TriggerExecution AdministrativePoint cache */
287     private DnNode<TriggerExecutionAdministrativePoint> triggerExecutionAPCache;
288 
289     /** The Dn factory */
290     private DnFactory dnFactory;
291 
292     /** The Subentry cache */
293     SubentryCache subentryCache = new SubentryCache();
294 
295     /** The Subtree evaluator instance */
296     private SubtreeEvaluator evaluator;
297 
298 
299     // ------------------------------------------------------------------------
300     // Constructor
301     // ------------------------------------------------------------------------
302 
303     /**
304      * Creates a new instance of the directory service.
305      */
306     public DefaultDirectoryService() throws Exception
307     {
308         changeLog = new DefaultChangeLog();
309         journal = new DefaultJournal();
310         syncPeriodMillis = DEFAULT_SYNC_PERIOD;
311         csnFactory = new CsnFactory( replicaId );
312         evaluator = new SubtreeEvaluator( schemaManager );
313         setDefaultInterceptorConfigurations();
314     }
315 
316 
317     // ------------------------------------------------------------------------
318     // C O N F I G U R A T I O N   M E T H O D S
319     // ------------------------------------------------------------------------
320 
321     public void setInstanceId( String instanceId )
322     {
323         this.instanceId = instanceId;
324     }
325 
326 
327     public String getInstanceId()
328     {
329         return instanceId;
330     }
331 
332 
333     /**
334      * Gets the {@link Partition}s used by this DirectoryService.
335      *
336      * @return the set of partitions used
337      */
338     public Set<? extends Partition> getPartitions()
339     {
340         Set<Partition> cloned = new HashSet<Partition>();
341         cloned.addAll( partitions );
342         return cloned;
343     }
344 
345 
346     /**
347      * Sets {@link Partition}s used by this DirectoryService.
348      *
349      * @param partitions the partitions to used
350      */
351     public void setPartitions( Set<? extends Partition> partitions )
352     {
353         Set<Partition> cloned = new HashSet<Partition>();
354         cloned.addAll( partitions );
355         Set<String> names = new HashSet<String>();
356 
357         for ( Partition partition : cloned )
358         {
359             String id = partition.getId();
360 
361             if ( names.contains( id ) )
362             {
363                 LOG.warn( "Encountered duplicate partition {} identifier.", id );
364             }
365 
366             names.add( id );
367         }
368 
369         this.partitions = cloned;
370     }
371 
372 
373     /**
374      * Returns <tt>true</tt> if access control checks are enabled.
375      *
376      * @return true if access control checks are enabled, false otherwise
377      */
378     public boolean isAccessControlEnabled()
379     {
380         return accessControlEnabled;
381     }
382 
383 
384     /**
385      * Sets whether to enable basic access control checks or not.
386      *
387      * @param accessControlEnabled true to enable access control checks, false otherwise
388      */
389     public void setAccessControlEnabled( boolean accessControlEnabled )
390     {
391         this.accessControlEnabled = accessControlEnabled;
392     }
393 
394 
395     /**
396      * Returns <tt>true</tt> if anonymous access is allowed on entries besides the RootDSE.
397      * If the access control subsystem is enabled then access to some entries may not be
398      * allowed even when full anonymous access is enabled.
399      *
400      * @return true if anonymous access is allowed on entries besides the RootDSE, false
401      * if anonymous access is allowed to all entries.
402      */
403     public boolean isAllowAnonymousAccess()
404     {
405         return allowAnonymousAccess;
406     }
407 
408 
409     /**
410      * Sets whether to allow anonymous access to entries other than the RootDSE.  If the
411      * access control subsystem is enabled then access to some entries may not be allowed
412      * even when full anonymous access is enabled.
413      *
414      * @param enableAnonymousAccess true to enable anonymous access, false to disable it
415      */
416     public void setAllowAnonymousAccess( boolean enableAnonymousAccess )
417     {
418         this.allowAnonymousAccess = enableAnonymousAccess;
419     }
420 
421 
422     /**
423      * Returns interceptors in the server.
424      *
425      * @return the interceptors in the server.
426      */
427     public List<Interceptor> getInterceptors()
428     {
429         List<Interceptor> cloned = new ArrayList<Interceptor>();
430 
431         readLock.lock();
432 
433         try
434         {
435             cloned.addAll( interceptors );
436 
437             return cloned;
438         }
439         finally
440         {
441             readLock.unlock();
442         }
443     }
444 
445 
446     /**
447      * Returns interceptors in the server for a given operation.
448      *
449      * @return the interceptors in the server for the given operation.
450      */
451     public List<String> getInterceptors( OperationEnum operation )
452     {
453         List<String> cloned = new ArrayList<String>();
454 
455         readLock.lock();
456 
457         try
458         {
459             cloned.addAll( operationInterceptors.get( operation ) );
460 
461             return cloned;
462         }
463         finally
464         {
465             readLock.unlock();
466         }
467 
468     }
469 
470 
471     /**
472      * Compute the list of  to call for each operation
473      */
474     private void initOperationsList()
475     {
476         writeLock.lock();
477 
478         try
479         {
480             operationInterceptors = new ConcurrentHashMap<OperationEnum, List<String>>();
481 
482             for ( OperationEnum operation : OperationEnum.getOperations() )
483             {
484                 List<String> operationList = new ArrayList<String>();
485 
486                 for ( Interceptor interceptor : interceptors )
487                 {
488                     gatherInterceptors( interceptor, interceptor.getClass(), operation, operationList );
489                 }
490 
491                 operationInterceptors.put( operation, operationList );
492             }
493         }
494         finally
495         {
496             writeLock.unlock();
497         }
498     }
499 
500 
501     /**
502      * Recursively checks if the given interceptor can be added to the list of interceptors for a given
503      * operation and adds to the list of interceptors if it implements the respective operation
504      * 
505      * @param interceptor the instance of the interceptor
506      * @param interceptorClz the class of the interceptor
507      * @param operation type of operation
508      * @param selectedInterceptorList the list of selected interceptors
509      */
510     private void gatherInterceptors( Interceptor interceptor, Class<?> interceptorClz, OperationEnum operation,
511         List<String> selectedInterceptorList )
512     {
513         // We stop recursing when we reach the Base class
514         if ( ( interceptorClz == null ) || ( interceptorClz == BaseInterceptor.class ) )
515         {
516             return;
517         }
518 
519         Method[] methods = interceptorClz.getDeclaredMethods();
520 
521         for ( Method method : methods )
522         {
523             Class<?>[] param = method.getParameterTypes();
524             boolean hasCorrestSig = false;
525 
526             // check for the correct signature
527             if ( ( param == null ) || ( param.length > 1 ) || ( param.length == 0 ) )
528             {
529                 continue;
530             }
531 
532             if ( OperationContext.class.isAssignableFrom( param[0] ) )
533             {
534                 hasCorrestSig = true;
535             }
536             else
537             {
538                 continue;
539             }
540 
541             if ( hasCorrestSig && method.getName().equals( operation.getMethodName() ) )
542             {
543                 selectedInterceptorList.add( interceptor.getName() );
544                 break;
545             }
546         }
547 
548         gatherInterceptors( interceptor, interceptorClz.getSuperclass(), operation, selectedInterceptorList );
549     }
550 
551 
552     /**
553      * Add an interceptor to the list of interceptors to call for each operation
554      * @throws LdapException
555      */
556     private void addInterceptor( Interceptor interceptor, int position ) throws LdapException
557     {
558         // First, init the interceptor
559         interceptor.init( this );
560 
561         writeLock.lock();
562 
563         try
564         {
565             for ( OperationEnum operation : OperationEnum.getOperations() )
566             {
567                 List<String> operationList = operationInterceptors.get( operation );
568 
569                 Method[] methods = interceptor.getClass().getDeclaredMethods();
570 
571                 for ( Method method : methods )
572                 {
573                     if ( method.getName().equals( operation.getMethodName() ) )
574                     {
575                         if ( position == -1 )
576                         {
577                             operationList.add( interceptor.getName() );
578                         }
579                         else
580                         {
581                             operationList.add( position, interceptor.getName() );
582                         }
583 
584                         break;
585                     }
586                 }
587             }
588 
589             interceptorNames.put( interceptor.getName(), interceptor );
590 
591             if ( position == -1 )
592             {
593                 interceptors.add( interceptor );
594             }
595             else
596             {
597                 interceptors.add( position, interceptor );
598             }
599         }
600         finally
601         {
602             writeLock.unlock();
603         }
604     }
605 
606 
607     /**
608      * Remove an interceptor to the list of interceptors to call for each operation
609      */
610     private void removeOperationsList( String interceptorName )
611     {
612         Interceptor interceptor = interceptorNames.get( interceptorName );
613 
614         writeLock.lock();
615 
616         try
617         {
618             for ( OperationEnum operation : OperationEnum.getOperations() )
619             {
620                 List<String> operationList = operationInterceptors.get( operation );
621 
622                 Method[] methods = interceptor.getClass().getDeclaredMethods();
623 
624                 for ( Method method : methods )
625                 {
626                     if ( method.getName().equals( operation.getMethodName() ) )
627                     {
628                         operationList.remove( interceptor.getName() );
629 
630                         break;
631                     }
632                 }
633             }
634 
635             interceptorNames.remove( interceptorName );
636             interceptors.remove( interceptor );
637         }
638         finally
639         {
640             writeLock.unlock();
641         }
642     }
643 
644 
645     /**
646      * Sets the interceptors in the server.
647      *
648      * @param interceptors the interceptors to be used in the server.
649      */
650     public void setInterceptors( List<Interceptor> interceptors )
651     {
652         Map<String, Interceptor> interceptorNames = new HashMap<String, Interceptor>();
653 
654         // Check if we don't have duplicate names in the interceptors list
655         for ( Interceptor interceptor : interceptors )
656         {
657             if ( interceptorNames.containsKey( interceptor.getName() ) )
658             {
659                 LOG.warn( "Encountered duplicate definitions for {} interceptor", interceptor.getName() );
660                 continue;
661             }
662 
663             interceptorNames.put( interceptor.getName(), interceptor );
664         }
665 
666         this.interceptors = interceptors;
667         this.interceptorNames = interceptorNames;
668 
669         // Now update the Map that connect each operation with the list of interceptors.
670         initOperationsList();
671     }
672 
673 
674     /**
675      * Initialize the interceptors
676      */
677     private void initInterceptors() throws LdapException
678     {
679         for ( Interceptor interceptor : interceptors )
680         {
681             interceptor.init( this );
682         }
683     }
684 
685 
686     /**
687      * Returns test directory entries({@link LdifEntry}) to be loaded while
688      * bootstrapping.
689      *
690      * @return test entries to load during bootstrapping
691      */
692     public List<LdifEntry> getTestEntries()
693     {
694         List<LdifEntry> cloned = new ArrayList<LdifEntry>();
695         cloned.addAll( testEntries );
696 
697         return cloned;
698     }
699 
700 
701     /**
702      * Sets test directory entries({@link Attributes}) to be loaded while
703      * bootstrapping.
704      *
705      * @param testEntries the test entries to load while bootstrapping
706      */
707     public void setTestEntries( List<? extends LdifEntry> testEntries )
708     {
709         //noinspection MismatchedQueryAndUpdateOfCollection
710         List<LdifEntry> cloned = new ArrayList<LdifEntry>();
711         cloned.addAll( testEntries );
712         this.testEntries = testEntries;
713     }
714 
715 
716     /**
717      * {@inheritDoc}
718      */
719     public InstanceLayout getInstanceLayout()
720     {
721         return instanceLayout;
722     }
723 
724 
725     /**
726      * {@inheritDoc}
727      */
728     public void setInstanceLayout( InstanceLayout instanceLayout ) throws IOException
729     {
730         this.instanceLayout = instanceLayout;
731 
732         // Create the directories if they are missing
733         if ( !instanceLayout.getInstanceDirectory().exists() )
734         {
735             if ( !instanceLayout.getInstanceDirectory().mkdirs() )
736             {
737                 throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECORY,
738                     instanceLayout.getInstanceDirectory() ) );
739             }
740         }
741 
742         if ( !instanceLayout.getLogDirectory().exists() )
743         {
744             if ( !instanceLayout.getLogDirectory().mkdirs() )
745             {
746                 throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECORY,
747                     instanceLayout.getLogDirectory() ) );
748             }
749         }
750 
751         if ( !instanceLayout.getRunDirectory().exists() )
752         {
753             if ( !instanceLayout.getRunDirectory().mkdirs() )
754             {
755                 throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECORY,
756                     instanceLayout.getRunDirectory() ) );
757             }
758         }
759 
760         if ( !instanceLayout.getPartitionsDirectory().exists() )
761         {
762             if ( !instanceLayout.getPartitionsDirectory().mkdirs() )
763             {
764                 throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECORY,
765                     instanceLayout.getPartitionsDirectory() ) );
766             }
767         }
768 
769         if ( !instanceLayout.getConfDirectory().exists() )
770         {
771             if ( !instanceLayout.getConfDirectory().mkdirs() )
772             {
773                 throw new IOException( I18n.err( I18n.ERR_112_COULD_NOT_CREATE_DIRECORY,
774                     instanceLayout.getConfDirectory() ) );
775             }
776         }
777     }
778 
779 
780     public void setShutdownHookEnabled( boolean shutdownHookEnabled )
781     {
782         this.shutdownHookEnabled = shutdownHookEnabled;
783     }
784 
785 
786     public boolean isShutdownHookEnabled()
787     {
788         return shutdownHookEnabled;
789     }
790 
791 
792     public void setExitVmOnShutdown( boolean exitVmOnShutdown )
793     {
794         this.exitVmOnShutdown = exitVmOnShutdown;
795     }
796 
797 
798     public boolean isExitVmOnShutdown()
799     {
800         return exitVmOnShutdown;
801     }
802 
803 
804     public void setSystemPartition( Partition systemPartition )
805     {
806         this.systemPartition = systemPartition;
807     }
808 
809 
810     public Partition getSystemPartition()
811     {
812         return systemPartition;
813     }
814 
815 
816     /**
817      * return true if the operational attributes must be normalized when returned
818      */
819     public boolean isDenormalizeOpAttrsEnabled()
820     {
821         return denormalizeOpAttrsEnabled;
822     }
823 
824 
825     /**
826      * Sets whether the operational attributes are denormalized when returned
827      * @param denormalizeOpAttrsEnabled The flag value
828      */
829     public void setDenormalizeOpAttrsEnabled( boolean denormalizeOpAttrsEnabled )
830     {
831         this.denormalizeOpAttrsEnabled = denormalizeOpAttrsEnabled;
832     }
833 
834 
835     /**
836      * {@inheritDoc}
837      */
838     public ChangeLog getChangeLog()
839     {
840         return changeLog;
841     }
842 
843 
844     /**
845      * {@inheritDoc}
846      */
847     public Journal getJournal()
848     {
849         return journal;
850     }
851 
852 
853     /**
854      * {@inheritDoc}
855      */
856     public void setChangeLog( ChangeLog changeLog )
857     {
858         this.changeLog = changeLog;
859     }
860 
861 
862     /**
863      * {@inheritDoc}
864      */
865     public void setJournal( Journal journal )
866     {
867         this.journal = journal;
868     }
869 
870 
871     public void addPartition( Partition partition ) throws Exception
872     {
873         partition.setSchemaManager( schemaManager );
874 
875         try
876         {
877             // can be null when called before starting up
878             if ( partitionNexus != null )
879             {
880                 partitionNexus.addContextPartition( partition );
881             }
882         }
883         catch ( LdapException le )
884         {
885             // We've got an exception, we cannot add the partition to the partitions
886             throw le;
887         }
888 
889         // Now, add the partition to the set of managed partitions
890         partitions.add( partition );
891     }
892 
893 
894     public void removePartition( Partition partition ) throws Exception
895     {
896         // Do the backend cleanup first
897         try
898         {
899             // can be null when called before starting up
900             if ( partitionNexus != null )
901             {
902                 partitionNexus.removeContextPartition( partition.getSuffixDn() );
903             }
904         }
905         catch ( LdapException le )
906         {
907             // Bad ! We can't go any further
908             throw le;
909         }
910 
911         // And update the set of managed partitions
912         partitions.remove( partition );
913     }
914 
915 
916     // ------------------------------------------------------------------------
917     // BackendSubsystem Interface Method Implementations
918     // ------------------------------------------------------------------------
919     /**
920      * Define a default list of interceptors that has to be used if no other
921      * configuration is defined.
922      */
923     private void setDefaultInterceptorConfigurations()
924     {
925         // Set default interceptor chains
926         List<Interceptor> list = new ArrayList<Interceptor>();
927 
928         list.add( new NormalizationInterceptor() );
929         list.add( new AuthenticationInterceptor() );
930         list.add( new ReferralInterceptor() );
931         list.add( new AciAuthorizationInterceptor() );
932         list.add( new DefaultAuthorizationInterceptor() );
933         list.add( new AdministrativePointInterceptor() );
934         list.add( new ExceptionInterceptor() );
935         list.add( new SchemaInterceptor() );
936         list.add( new OperationalAttributeInterceptor() );
937         list.add( new CollectiveAttributeInterceptor() );
938         list.add( new SubentryInterceptor() );
939         list.add( new EventInterceptor() );
940         list.add( new TriggerInterceptor() );
941         list.add( new ChangeLogInterceptor() );
942         list.add( new JournalInterceptor() );
943 
944         setInterceptors( list );
945     }
946 
947 
948     public CoreSession getAdminSession()
949     {
950         return adminSession;
951     }
952 
953 
954     /**
955      * Get back an anonymous session
956      */
957     public CoreSession getSession()
958     {
959         return new DefaultCoreSession( new LdapPrincipal( schemaManager ), this );
960     }
961 
962 
963     /** 
964      * Get back a session for a given principal
965      */
966     public CoreSession getSession( LdapPrincipal principal )
967     {
968         return new DefaultCoreSession( principal, this );
969     }
970 
971 
972     /**
973      * Get back a session for the give user and credentials bound with Simple Bind
974      */
975     public CoreSession getSession( Dn principalDn, byte[] credentials ) throws LdapException
976     {
977         if ( !started )
978         {
979             throw new IllegalStateException( "Service has not started." );
980         }
981 
982         BindOperationContext bindContext = new BindOperationContext( null );
983         bindContext.setCredentials( credentials );
984         bindContext.setDn( principalDn.apply( schemaManager ) );
985         bindContext.setInterceptors( getInterceptors( OperationEnum.BIND ) );
986 
987         operationManager.bind( bindContext );
988 
989         return bindContext.getSession();
990     }
991 
992 
993     /**
994      * Get back a session for a given user bound with SASL Bind
995      */
996     public CoreSession getSession( Dn principalDn, byte[] credentials, String saslMechanism, String saslAuthId )
997         throws Exception
998     {
999         if ( !started )
1000         {
1001             throw new IllegalStateException( "Service has not started." );
1002         }
1003 
1004         BindOperationContext bindContext = new BindOperationContext( null );
1005         bindContext.setCredentials( credentials );
1006         bindContext.setDn( principalDn.apply( schemaManager ) );
1007         bindContext.setSaslMechanism( saslMechanism );
1008         bindContext.setInterceptors( getInterceptors( OperationEnum.BIND ) );
1009 
1010         operationManager.bind( bindContext );
1011 
1012         return bindContext.getSession();
1013     }
1014 
1015 
1016     public long revert() throws LdapException
1017     {
1018         if ( changeLog == null || !changeLog.isEnabled() )
1019         {
1020             throw new IllegalStateException( I18n.err( I18n.ERR_310 ) );
1021         }
1022 
1023         Tag latest = changeLog.getLatest();
1024 
1025         if ( null != latest )
1026         {
1027             if ( latest.getRevision() < changeLog.getCurrentRevision() )
1028             {
1029                 return revert( latest.getRevision() );
1030             }
1031             else
1032             {
1033                 LOG.info( "Ignoring request to revert without changes since the latest tag." );
1034                 return changeLog.getCurrentRevision();
1035             }
1036         }
1037 
1038         throw new IllegalStateException( I18n.err( I18n.ERR_311 ) );
1039     }
1040 
1041 
1042     /**
1043      * We handle the ModDN/ModRDN operation for the revert here.
1044      */
1045     private void moddn( Dn oldDn, Dn newDn, boolean delOldRdn ) throws LdapException
1046     {
1047         if ( oldDn.size() == 0 )
1048         {
1049             throw new LdapNoPermissionException( I18n.err( I18n.ERR_312 ) );
1050         }
1051 
1052         // calculate parents
1053         Dn oldBase = oldDn.getParent();
1054         Dn newBase = newDn.getParent();
1055 
1056         // Compute the Rdn for each of the Dn
1057         Rdn newRdn = newDn.getRdn();
1058         Rdn oldRdn = oldDn.getRdn();
1059 
1060         /*
1061          * We need to determine if this rename operation corresponds to a simple
1062          * Rdn name change or a move operation.  If the two names are the same
1063          * except for the Rdn then it is a simple modifyRdn operation.  If the
1064          * names differ in size or have a different baseDN then the operation is
1065          * a move operation.  Furthermore if the Rdn in the move operation
1066          * changes it is both an Rdn change and a move operation.
1067          */
1068         if ( ( oldDn.size() == newDn.size() ) && oldBase.equals( newBase ) )
1069         {
1070             adminSession.rename( oldDn, newRdn, delOldRdn );
1071         }
1072         else
1073         {
1074             Dn target = newDn.getParent();
1075 
1076             if ( newRdn.equals( oldRdn ) )
1077             {
1078                 adminSession.move( oldDn, target );
1079             }
1080             else
1081             {
1082                 adminSession.moveAndRename( oldDn, target, new Rdn( newRdn ), delOldRdn );
1083             }
1084         }
1085     }
1086 
1087 
1088     public long revert( long revision ) throws LdapException
1089     {
1090         if ( changeLog == null || !changeLog.isEnabled() )
1091         {
1092             throw new IllegalStateException( I18n.err( I18n.ERR_310 ) );
1093         }
1094 
1095         if ( revision < 0 )
1096         {
1097             throw new IllegalArgumentException( I18n.err( I18n.ERR_239 ) );
1098         }
1099 
1100         if ( revision >= changeLog.getChangeLogStore().getCurrentRevision() )
1101         {
1102             throw new IllegalArgumentException( I18n.err( I18n.ERR_314 ) );
1103         }
1104 
1105         Cursor<ChangeLogEvent> cursor = changeLog.getChangeLogStore().findAfter( revision );
1106 
1107         /*
1108          * BAD, BAD, BAD!!!
1109          *
1110          * No synchronization no nothing.  Just getting this to work for now
1111          * so we can revert tests.  Any production grade use of this feature
1112          * needs to synchronize on all changes while the revert is in progress.
1113          *
1114          * How about making this operation transactional?
1115          *
1116          * First of all just stop using JNDI and construct the operations to
1117          * feed into the interceptor pipeline.
1118          *
1119          * TODO review this code.
1120          */
1121 
1122         try
1123         {
1124             LOG.warn( PARTIAL_IMPL_WARNING );
1125             cursor.afterLast();
1126 
1127             while ( cursor.previous() ) // apply ldifs in reverse order
1128             {
1129                 ChangeLogEvent event = cursor.get();
1130                 List<LdifEntry> reverses = event.getReverseLdifs();
1131 
1132                 for ( LdifEntry reverse : reverses )
1133                 {
1134                     switch ( reverse.getChangeType().getChangeType() )
1135                     {
1136                         case ChangeType.ADD_ORDINAL:
1137                             adminSession.add(
1138                                 new DefaultEntry( schemaManager, reverse.getEntry() ), true );
1139                             break;
1140 
1141                         case ChangeType.DELETE_ORDINAL:
1142                             adminSession.delete( reverse.getDn(), true );
1143                             break;
1144 
1145                         case ChangeType.MODIFY_ORDINAL:
1146                             List<Modification> mods = reverse.getModifications();
1147 
1148                             adminSession.modify( reverse.getDn(), mods, true );
1149                             break;
1150 
1151                         case ChangeType.MODDN_ORDINAL:
1152                             // NO BREAK - both ModDN and ModRDN handling is the same
1153 
1154                         case ChangeType.MODRDN_ORDINAL:
1155                             Dn forwardDn = event.getForwardLdif().getDn();
1156                             Dn reverseDn = reverse.getDn();
1157 
1158                             moddn( reverseDn, forwardDn, reverse.isDeleteOldRdn() );
1159 
1160                             break;
1161 
1162                         default:
1163                             LOG.error( I18n.err( I18n.ERR_75 ) );
1164                             throw new NotImplementedException( I18n.err( I18n.ERR_76, reverse.getChangeType() ) );
1165                     }
1166                 }
1167             }
1168         }
1169         catch ( IOException e )
1170         {
1171             String message = I18n.err( I18n.ERR_77, revision );
1172             LOG.error( message );
1173             throw new LdapException( message );
1174         }
1175         catch ( Exception e )
1176         {
1177             throw new LdapOperationException( e.getMessage(), e );
1178         }
1179         finally
1180         {
1181             try
1182             {
1183                 cursor.close();
1184             }
1185             catch ( Exception e )
1186             {
1187                 throw new LdapOperationException( e.getMessage(), e );
1188             }
1189         }
1190 
1191         return changeLog.getCurrentRevision();
1192     }
1193 
1194 
1195     public OperationManager getOperationManager()
1196     {
1197         return operationManager;
1198     }
1199 
1200 
1201     /**
1202      * @throws Exception if the LDAP server cannot be started
1203      */
1204     public synchronized void startup() throws Exception
1205     {
1206         if ( started )
1207         {
1208             return;
1209         }
1210 
1211         lockWorkDir();
1212 
1213         if ( shutdownHookEnabled )
1214         {
1215             Runtime.getRuntime().addShutdownHook( new Thread( new Runnable()
1216             {
1217                 public void run()
1218                 {
1219                     try
1220                     {
1221                         shutdown();
1222                     }
1223                     catch ( Exception e )
1224                     {
1225                         LOG.warn( "Failed to shut down the directory service: "
1226                             + DefaultDirectoryService.this.instanceId, e );
1227                     }
1228                 }
1229             }, "ApacheDS Shutdown Hook (" + instanceId + ')' ) );
1230 
1231             LOG.info( "ApacheDS shutdown hook has been registered with the runtime." );
1232         }
1233         else if ( LOG.isWarnEnabled() )
1234         {
1235             LOG.warn( "ApacheDS shutdown hook has NOT been registered with the runtime."
1236                 + "  This default setting for standalone operation has been overriden." );
1237         }
1238 
1239         initialize();
1240         showSecurityWarnings();
1241 
1242         // load the last stored valid CSN value
1243         LookupOperationContext loc = new LookupOperationContext( getAdminSession(), systemPartition.getSuffixDn(),
1244             SchemaConstants.ALL_ATTRIBUTES_ARRAY );
1245 
1246         Entry entry = systemPartition.lookup( loc );
1247 
1248         Attribute cntextCsnAt = entry.get( SchemaConstants.CONTEXT_CSN_AT );
1249 
1250         if ( cntextCsnAt != null )
1251         {
1252             // this is a multivalued attribute but current syncrepl provider implementation stores only ONE value at ou=system
1253             contextCsn = cntextCsnAt.getString();
1254         }
1255 
1256         started = true;
1257 
1258         if ( !testEntries.isEmpty() )
1259         {
1260             createTestEntries();
1261         }
1262     }
1263 
1264 
1265     public synchronized void sync() throws Exception
1266     {
1267         if ( !started )
1268         {
1269             return;
1270         }
1271 
1272         this.changeLog.sync();
1273         this.partitionNexus.sync();
1274     }
1275 
1276 
1277     public synchronized void shutdown() throws Exception
1278     {
1279         LOG.debug( "+++ DirectoryService Shutdown required" );
1280 
1281         if ( !started )
1282         {
1283             return;
1284         }
1285 
1286         // --------------------------------------------------------------------
1287         // Shutdown the sync thread
1288         // --------------------------------------------------------------------
1289         LOG.debug( "--- Syncing the nexus " );
1290         partitionNexus.sync();
1291 
1292         // --------------------------------------------------------------------
1293         // Shutdown the changelog
1294         // --------------------------------------------------------------------
1295         LOG.debug( "--- Syncing the changeLog " );
1296         changeLog.sync();
1297         changeLog.destroy();
1298 
1299         // --------------------------------------------------------------------
1300         // Shutdown the journal if enabled
1301         // --------------------------------------------------------------------
1302         if ( journal.isEnabled() )
1303         {
1304             LOG.debug( "--- Destroying the journal " );
1305             journal.destroy();
1306         }
1307 
1308         // --------------------------------------------------------------------
1309         // Shutdown the partition
1310         // --------------------------------------------------------------------
1311 
1312         LOG.debug( "--- Destroying the nexus" );
1313         partitionNexus.destroy();
1314 
1315         // Last flush...
1316         LOG.debug( "--- Flushing everything before quitting" );
1317         getOperationManager().lockWrite();
1318         partitionNexus.sync();
1319         getOperationManager().unlockWrite();
1320 
1321         // --------------------------------------------------------------------
1322         // And shutdown the server
1323         // --------------------------------------------------------------------
1324         LOG.debug( "--- Deleting the cache service" );
1325         cacheService.destroy();
1326 
1327         if ( lockFile != null )
1328         {
1329             try
1330             {
1331                 lockFile.close();
1332                 // no need to delete the lock file
1333             }
1334             catch ( IOException e )
1335             {
1336                 LOG.warn( "couldn't delete the lock file {}", LOCK_FILE_NAME );
1337             }
1338         }
1339 
1340         LOG.debug( "+++ DirectoryService stopped" );
1341         started = false;
1342     }
1343 
1344 
1345     /**
1346      * @return The referral manager
1347      */
1348     public ReferralManager getReferralManager()
1349     {
1350         return referralManager;
1351     }
1352 
1353 
1354     /**
1355      * Set the referralManager
1356      * @param referralManager The initialized referralManager
1357      */
1358     public void setReferralManager( ReferralManager referralManager )
1359     {
1360         this.referralManager = referralManager;
1361     }
1362 
1363 
1364     /**
1365      * @return the SchemaManager
1366      */
1367     public SchemaManager getSchemaManager()
1368     {
1369         return schemaManager;
1370     }
1371 
1372 
1373     /**
1374      * Set the SchemaManager instance.
1375      *
1376      * @param schemaManager The server schemaManager
1377      */
1378     public void setSchemaManager( SchemaManager schemaManager )
1379     {
1380         this.schemaManager = schemaManager;
1381     }
1382 
1383 
1384     public LdapApiService getLdapCodecService()
1385     {
1386         return ldapCodecService;
1387     }
1388 
1389 
1390     /**
1391      * {@inheritDoc}
1392      */
1393     public SchemaPartition getSchemaPartition()
1394     {
1395         return schemaPartition;
1396     }
1397 
1398 
1399     /**
1400      * {@inheritDoc}
1401      */
1402     public void setSchemaPartition( SchemaPartition schemaPartition )
1403     {
1404         this.schemaPartition = schemaPartition;
1405     }
1406 
1407 
1408     public DefaultPartitionNexus getPartitionNexus()
1409     {
1410         return partitionNexus;
1411     }
1412 
1413 
1414     public boolean isFirstStart()
1415     {
1416         return firstStart;
1417     }
1418 
1419 
1420     public boolean isStarted()
1421     {
1422         return started;
1423     }
1424 
1425 
1426     public Entry newEntry( Dn dn )
1427     {
1428         return new DefaultEntry( schemaManager, dn );
1429     }
1430 
1431 
1432     /**
1433      * Returns true if we had to create the bootstrap entries on the first
1434      * start of the server.  Otherwise if all entries exist, meaning none
1435      * had to be created, then we are not starting for the first time.
1436      *
1437      * @return true if the bootstrap entries had to be created, false otherwise
1438      * @throws Exception if entries cannot be created
1439      */
1440     private boolean createBootstrapEntries() throws Exception
1441     {
1442         boolean firstStart = false;
1443 
1444         // -------------------------------------------------------------------
1445         // create admin entry
1446         // -------------------------------------------------------------------
1447 
1448         /*
1449          * If the admin entry is there, then the database was already created
1450          */
1451         if ( !partitionNexus.hasEntry( new HasEntryOperationContext( adminSession, adminDn ) ) )
1452         {
1453             firstStart = true;
1454 
1455             Entry serverEntry = new DefaultEntry( schemaManager, adminDn );
1456 
1457             serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1458                 SchemaConstants.TOP_OC,
1459                 SchemaConstants.PERSON_OC,
1460                 SchemaConstants.ORGANIZATIONAL_PERSON_OC,
1461                 SchemaConstants.INET_ORG_PERSON_OC );
1462 
1463             serverEntry.put( SchemaConstants.UID_AT, PartitionNexus.ADMIN_UID );
1464             serverEntry.put( SchemaConstants.USER_PASSWORD_AT, PartitionNexus.ADMIN_PASSWORD_BYTES );
1465             serverEntry.put( SchemaConstants.DISPLAY_NAME_AT, "Directory Superuser" );
1466             serverEntry.put( SchemaConstants.CN_AT, "system administrator" );
1467             serverEntry.put( SchemaConstants.SN_AT, "administrator" );
1468             serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1469             serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1470             serverEntry.put( SchemaConstants.DISPLAY_NAME_AT, "Directory Superuser" );
1471             serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1472             serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1473 
1474             TlsKeyGenerator.addKeyPair( serverEntry );
1475             partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1476         }
1477 
1478         // -------------------------------------------------------------------
1479         // create system users area
1480         // -------------------------------------------------------------------
1481 
1482         Dn userDn = getDnFactory().create( ServerDNConstants.USERS_SYSTEM_DN );
1483 
1484         if ( !partitionNexus.hasEntry( new HasEntryOperationContext( adminSession, userDn ) ) )
1485         {
1486             firstStart = true;
1487 
1488             Entry serverEntry = new DefaultEntry( schemaManager, userDn );
1489 
1490             serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1491                 SchemaConstants.TOP_OC,
1492                 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1493 
1494             serverEntry.put( SchemaConstants.OU_AT, "users" );
1495             serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1496             serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1497             serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1498             serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1499 
1500             partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1501         }
1502 
1503         // -------------------------------------------------------------------
1504         // create system groups area
1505         // -------------------------------------------------------------------
1506 
1507         Dn groupDn = getDnFactory().create( ServerDNConstants.GROUPS_SYSTEM_DN );
1508 
1509         if ( !partitionNexus.hasEntry( new HasEntryOperationContext( adminSession, groupDn ) ) )
1510         {
1511             firstStart = true;
1512 
1513             Entry serverEntry = new DefaultEntry( schemaManager, groupDn );
1514 
1515             serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1516                 SchemaConstants.TOP_OC,
1517                 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1518 
1519             serverEntry.put( SchemaConstants.OU_AT, "groups" );
1520             serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1521             serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1522             serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1523             serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1524 
1525             partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1526         }
1527 
1528         // -------------------------------------------------------------------
1529         // create administrator group
1530         // -------------------------------------------------------------------
1531 
1532         Dn name = getDnFactory().create( ServerDNConstants.ADMINISTRATORS_GROUP_DN );
1533 
1534         if ( !partitionNexus.hasEntry( new HasEntryOperationContext( adminSession, name ) ) )
1535         {
1536             firstStart = true;
1537 
1538             Entry serverEntry = new DefaultEntry( schemaManager, name );
1539 
1540             serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1541                 SchemaConstants.TOP_OC,
1542                 SchemaConstants.GROUP_OF_UNIQUE_NAMES_OC );
1543 
1544             serverEntry.put( SchemaConstants.CN_AT, "Administrators" );
1545             serverEntry.put( SchemaConstants.UNIQUE_MEMBER_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1546             serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1547             serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1548             serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1549             serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1550 
1551             partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1552         }
1553 
1554         // -------------------------------------------------------------------
1555         // create system configuration area
1556         // -------------------------------------------------------------------
1557 
1558         Dn configurationDn = getDnFactory().create( "ou=configuration,ou=system" );
1559 
1560         if ( !partitionNexus.hasEntry( new HasEntryOperationContext( adminSession, configurationDn ) ) )
1561         {
1562             firstStart = true;
1563 
1564             Entry serverEntry = new DefaultEntry( schemaManager, configurationDn );
1565             serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
1566                 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1567 
1568             serverEntry.put( SchemaConstants.OU_AT, "configuration" );
1569             serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1570             serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1571             serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1572             serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1573 
1574             partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1575         }
1576 
1577         // -------------------------------------------------------------------
1578         // create system configuration area for partition information
1579         // -------------------------------------------------------------------
1580 
1581         Dn partitionsDn = getDnFactory().create( "ou=partitions,ou=configuration,ou=system" );
1582 
1583         if ( !partitionNexus.hasEntry( new HasEntryOperationContext( adminSession, partitionsDn ) ) )
1584         {
1585             firstStart = true;
1586 
1587             Entry serverEntry = new DefaultEntry( schemaManager, partitionsDn );
1588             serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
1589                 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1590             serverEntry.put( SchemaConstants.OU_AT, "partitions" );
1591             serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1592             serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1593             serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1594             serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1595 
1596             partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1597         }
1598 
1599         // -------------------------------------------------------------------
1600         // create system configuration area for services
1601         // -------------------------------------------------------------------
1602 
1603         Dn servicesDn = getDnFactory().create( "ou=services,ou=configuration,ou=system" );
1604 
1605         if ( !partitionNexus.hasEntry( new HasEntryOperationContext( adminSession, servicesDn ) ) )
1606         {
1607             firstStart = true;
1608 
1609             Entry serverEntry = new DefaultEntry( schemaManager, servicesDn );
1610             serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
1611                 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1612 
1613             serverEntry.put( SchemaConstants.OU_AT, "services" );
1614             serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1615             serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1616             serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1617             serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1618 
1619             partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1620         }
1621 
1622         // -------------------------------------------------------------------
1623         // create system configuration area for interceptors
1624         // -------------------------------------------------------------------
1625 
1626         Dn interceptorsDn = getDnFactory().create( "ou=interceptors,ou=configuration,ou=system" );
1627 
1628         if ( !partitionNexus.hasEntry( new HasEntryOperationContext( adminSession, interceptorsDn ) ) )
1629         {
1630             firstStart = true;
1631 
1632             Entry serverEntry = new DefaultEntry( schemaManager, interceptorsDn );
1633             serverEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
1634                 SchemaConstants.ORGANIZATIONAL_UNIT_OC );
1635 
1636             serverEntry.put( SchemaConstants.OU_AT, "interceptors" );
1637             serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1638             serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1639             serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1640             serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1641 
1642             partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1643         }
1644 
1645         // -------------------------------------------------------------------
1646         // create system preferences area
1647         // -------------------------------------------------------------------
1648 
1649         Dn sysPrefRootDn = getDnFactory().create( ServerDNConstants.SYSPREFROOT_SYSTEM_DN );
1650 
1651         if ( !partitionNexus.hasEntry( new HasEntryOperationContext( adminSession, sysPrefRootDn ) ) )
1652         {
1653             firstStart = true;
1654 
1655             Entry serverEntry = new DefaultEntry( schemaManager, sysPrefRootDn );
1656             serverEntry.put( SchemaConstants.OBJECT_CLASS_AT,
1657                 SchemaConstants.TOP_OC,
1658                 SchemaConstants.ORGANIZATIONAL_UNIT_OC,
1659                 SchemaConstants.EXTENSIBLE_OBJECT_OC );
1660 
1661             serverEntry.put( "prefNodeName", "sysPrefRoot" );
1662             serverEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN_NORMALIZED );
1663             serverEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1664             serverEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1665             serverEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1666 
1667             partitionNexus.add( new AddOperationContext( adminSession, serverEntry ) );
1668         }
1669 
1670         return firstStart;
1671     }
1672 
1673 
1674     /**
1675      * Displays security warning messages if any possible secutiry issue is found.
1676      * @throws Exception if there are failures parsing and accessing internal structures
1677      */
1678     private void showSecurityWarnings() throws Exception
1679     {
1680         // Warn if the default password is not changed.
1681         boolean needToChangeAdminPassword = false;
1682 
1683         Dn adminDn = getDnFactory().create( ServerDNConstants.ADMIN_SYSTEM_DN );
1684 
1685         Entry adminEntry = partitionNexus.lookup( new LookupOperationContext( adminSession, adminDn ) );
1686         Value<?> userPassword = adminEntry.get( SchemaConstants.USER_PASSWORD_AT ).get();
1687         needToChangeAdminPassword = Arrays.equals( PartitionNexus.ADMIN_PASSWORD_BYTES, userPassword.getBytes() );
1688 
1689         if ( needToChangeAdminPassword )
1690         {
1691             LOG.warn( "You didn't change the admin password of directory service " + "instance '" + instanceId + "'.  "
1692                 + "Please update the admin password as soon as possible " + "to prevent a possible security breach." );
1693         }
1694     }
1695 
1696 
1697     /**
1698      * Adds test entries into the core.
1699      *
1700      * @todo this may no longer be needed when JNDI is not used for bootstrapping
1701      *
1702      * @throws Exception if the creation of test entries fails.
1703      */
1704     private void createTestEntries() throws Exception
1705     {
1706         for ( LdifEntry testEntry : testEntries )
1707         {
1708             try
1709             {
1710                 LdifEntry ldifEntry = testEntry.clone();
1711                 Entry entry = ldifEntry.getEntry();
1712                 String dn = ldifEntry.getDn().getName();
1713 
1714                 try
1715                 {
1716                     getAdminSession().add( new DefaultEntry( schemaManager, entry ) );
1717                 }
1718                 catch ( Exception e )
1719                 {
1720                     LOG.warn( dn + " test entry already exists.", e );
1721                 }
1722             }
1723             catch ( CloneNotSupportedException cnse )
1724             {
1725                 LOG.warn( "Cannot clone the entry ", cnse );
1726             }
1727         }
1728     }
1729 
1730 
1731     private void initializeSystemPartition() throws Exception
1732     {
1733         Partition system = getSystemPartition();
1734 
1735         // Add root context entry for system partition
1736         Dn systemSuffixDn = getDnFactory().create( ServerDNConstants.SYSTEM_DN );
1737         CoreSession adminSession = getAdminSession();
1738 
1739         if ( !system.hasEntry( new HasEntryOperationContext( adminSession, systemSuffixDn ) ) )
1740         {
1741             Entry systemEntry = new DefaultEntry( schemaManager, systemSuffixDn );
1742 
1743             // Add the ObjectClasses
1744             systemEntry.put( SchemaConstants.OBJECT_CLASS_AT, SchemaConstants.TOP_OC,
1745                 SchemaConstants.ORGANIZATIONAL_UNIT_OC, SchemaConstants.EXTENSIBLE_OBJECT_OC );
1746 
1747             // Add some operational attributes
1748             systemEntry.put( SchemaConstants.CREATORS_NAME_AT, ServerDNConstants.ADMIN_SYSTEM_DN );
1749             systemEntry.put( SchemaConstants.CREATE_TIMESTAMP_AT, DateUtils.getGeneralizedTime() );
1750             systemEntry.add( SchemaConstants.ENTRY_CSN_AT, getCSN().toString() );
1751             systemEntry.add( SchemaConstants.ENTRY_UUID_AT, UUID.randomUUID().toString() );
1752             systemEntry.put( DnUtils.getRdnAttributeType( ServerDNConstants.SYSTEM_DN ), DnUtils
1753                 .getRdnValue( ServerDNConstants.SYSTEM_DN ) );
1754 
1755             AddOperationContext addOperationContext = new AddOperationContext( adminSession, systemEntry );
1756             system.add( addOperationContext );
1757         }
1758     }
1759 
1760 
1761     /**
1762      * Kicks off the initialization of the entire system.
1763      *
1764      * @throws Exception if there are problems along the way
1765      */
1766     private void initialize() throws Exception
1767     {
1768         if ( LOG.isDebugEnabled() )
1769         {
1770             LOG.debug( "---> Initializing the DefaultDirectoryService " );
1771         }
1772 
1773         csnFactory.setReplicaId( replicaId );
1774 
1775         // If no interceptor list is defined, setup a default list
1776         if ( interceptors == null )
1777         {
1778             setDefaultInterceptorConfigurations();
1779         }
1780 
1781         if ( cacheService != null )
1782         {
1783             cacheService.initialize( instanceLayout );
1784         }
1785 
1786         // Initialize the AP caches
1787         accessControlAPCache = new DnNode<AccessControlAdministrativePoint>();
1788         collectiveAttributeAPCache = new DnNode<CollectiveAttributeAdministrativePoint>();
1789         subschemaAPCache = new DnNode<SubschemaAdministrativePoint>();
1790         triggerExecutionAPCache = new DnNode<TriggerExecutionAdministrativePoint>();
1791 
1792         dnFactory = new DefaultDnFactory( schemaManager, cacheService.getCache( "dnCache" ) );
1793 
1794         // triggers partition to load schema fully from schema partition
1795         schemaPartition.setCacheService( cacheService );
1796         schemaPartition.initialize();
1797         partitions.add( schemaPartition );
1798         systemPartition.setCacheService( cacheService );
1799         systemPartition.getSuffixDn().apply( schemaManager );
1800 
1801         adminDn = getDnFactory().create( ServerDNConstants.ADMIN_SYSTEM_DN );
1802         adminSession = new DefaultCoreSession( new LdapPrincipal( schemaManager, adminDn, AuthenticationLevel.STRONG ),
1803             this );
1804 
1805         // @TODO - NOTE: Need to find a way to instantiate without dependency on DPN
1806         partitionNexus = new DefaultPartitionNexus( new DefaultEntry( schemaManager, Dn.ROOT_DSE ) );
1807         partitionNexus.setDirectoryService( this );
1808         partitionNexus.initialize();
1809 
1810         initializeSystemPartition();
1811 
1812         // --------------------------------------------------------------------
1813         // Create all the bootstrap entries before initializing chain
1814         // --------------------------------------------------------------------
1815 
1816         firstStart = createBootstrapEntries();
1817 
1818         // Initialize the interceptors
1819         initInterceptors();
1820 
1821         // --------------------------------------------------------------------
1822         // Initialize the changeLog if it's enabled
1823         // --------------------------------------------------------------------
1824 
1825         if ( changeLog.isEnabled() )
1826         {
1827             changeLog.init( this );
1828 
1829             if ( changeLog.isExposed() && changeLog.isTagSearchSupported() )
1830             {
1831                 String clSuffix = ( ( TaggableSearchableChangeLogStore ) changeLog.getChangeLogStore() ).getPartition()
1832                     .getSuffixDn().getName();
1833                 partitionNexus.getRootDse( null ).add( SchemaConstants.CHANGELOG_CONTEXT_AT, clSuffix );
1834             }
1835         }
1836 
1837         // --------------------------------------------------------------------
1838         // Initialize the journal if it's enabled
1839         // --------------------------------------------------------------------
1840         if ( journal.isEnabled() )
1841         {
1842             journal.init( this );
1843         }
1844 
1845         if ( LOG.isDebugEnabled() )
1846         {
1847             LOG.debug( "<--- DefaultDirectoryService initialized" );
1848         }
1849     }
1850 
1851 
1852     /**
1853      * Read an entry (without Dn)
1854      *
1855      * @param text The ldif format file
1856      * @return An entry.
1857      */
1858     // This will suppress PMD.EmptyCatchBlock warnings in this method
1859     @SuppressWarnings("PMD.EmptyCatchBlock")
1860     private Entry readEntry( String text )
1861     {
1862         StringReader strIn = new StringReader( text );
1863         BufferedReader in = new BufferedReader( strIn );
1864 
1865         String line = null;
1866         Entry entry = new DefaultEntry();
1867 
1868         try
1869         {
1870             while ( ( line = in.readLine() ) != null )
1871             {
1872                 if ( line.length() == 0 )
1873                 {
1874                     continue;
1875                 }
1876 
1877                 String addedLine = line.trim();
1878 
1879                 if ( Strings.isEmpty( addedLine ) )
1880                 {
1881                     continue;
1882                 }
1883 
1884                 Attribute attribute = LdifReader.parseAttributeValue( addedLine );
1885                 Attribute oldAttribute = entry.get( attribute.getId() );
1886 
1887                 if ( oldAttribute != null )
1888                 {
1889                     try
1890                     {
1891                         oldAttribute.add( attribute.get() );
1892                         entry.put( oldAttribute );
1893                     }
1894                     catch ( LdapException ne )
1895                     {
1896                         // Do nothing
1897                     }
1898                 }
1899                 else
1900                 {
1901                     try
1902                     {
1903                         entry.put( attribute );
1904                     }
1905                     catch ( LdapException ne )
1906                     {
1907                         // TODO do nothing ...
1908                     }
1909                 }
1910             }
1911         }
1912         catch ( IOException ioe )
1913         {
1914             // Do nothing : we can't reach this point !
1915         }
1916 
1917         return entry;
1918     }
1919 
1920 
1921     /**
1922      * Create a new Entry
1923      *
1924      * @param ldif The String representing the attributes, as a LDIF file
1925      * @param dn The Dn for this new entry
1926      */
1927     public Entry newEntry( String ldif, String dn )
1928     {
1929         try
1930         {
1931             Entry entry = readEntry( ldif );
1932             Dn newDn = getDnFactory().create( dn );
1933 
1934             entry.setDn( newDn );
1935 
1936             // TODO Let's get rid of this Attributes crap
1937             Entry serverEntry = new DefaultEntry( schemaManager, entry );
1938             return serverEntry;
1939         }
1940         catch ( Exception e )
1941         {
1942             LOG.error( I18n.err( I18n.ERR_78, ldif, dn ) );
1943             // do nothing
1944             return null;
1945         }
1946     }
1947 
1948 
1949     public EventService getEventService()
1950     {
1951         return eventService;
1952     }
1953 
1954 
1955     public void setEventService( EventService eventService )
1956     {
1957         this.eventService = eventService;
1958     }
1959 
1960 
1961     /**
1962      * {@inheritDoc}
1963      */
1964     public boolean isPasswordHidden()
1965     {
1966         return passwordHidden;
1967     }
1968 
1969 
1970     /**
1971      * {@inheritDoc}
1972      */
1973     public void setPasswordHidden( boolean passwordHidden )
1974     {
1975         this.passwordHidden = passwordHidden;
1976     }
1977 
1978 
1979     /**
1980      * @return The maximum allowed size for an incoming PDU
1981      */
1982     public int getMaxPDUSize()
1983     {
1984         return maxPDUSize;
1985     }
1986 
1987 
1988     /**
1989      * Set the maximum allowed size for an incoming PDU
1990      * @param maxPDUSize A positive number of bytes for the PDU. A negative or
1991      * null value will be transformed to {@link Integer#MAX_VALUE}
1992      */
1993     public void setMaxPDUSize( int maxPDUSize )
1994     {
1995         if ( maxPDUSize <= 0 )
1996         {
1997             maxPDUSize = Integer.MAX_VALUE;
1998         }
1999 
2000         this.maxPDUSize = maxPDUSize;
2001     }
2002 
2003 
2004     /**
2005      * {@inheritDoc}
2006      */
2007     public Interceptor getInterceptor( String interceptorName )
2008     {
2009         readLock.lock();
2010 
2011         try
2012         {
2013             return interceptorNames.get( interceptorName );
2014         }
2015         finally
2016         {
2017             readLock.unlock();
2018         }
2019     }
2020 
2021 
2022     /**
2023      * {@inheritDoc}
2024      * @throws LdapException
2025      */
2026     public void addFirst( Interceptor interceptor ) throws LdapException
2027     {
2028         addInterceptor( interceptor, 0 );
2029     }
2030 
2031 
2032     /**
2033      * {@inheritDoc}
2034      * @throws LdapException
2035      */
2036     public void addLast( Interceptor interceptor ) throws LdapException
2037     {
2038         addInterceptor( interceptor, -1 );
2039     }
2040 
2041 
2042     /**
2043      * {@inheritDoc}
2044      */
2045     public void addAfter( String interceptorName, Interceptor interceptor )
2046     {
2047         writeLock.lock();
2048 
2049         try
2050         {
2051             int position = 0;
2052 
2053             // Find the position
2054             for ( Interceptor inter : interceptors )
2055             {
2056                 if ( interceptorName.equals( inter.getName() ) )
2057                 {
2058                     break;
2059                 }
2060 
2061                 position++;
2062             }
2063 
2064             if ( position == interceptors.size() )
2065             {
2066                 interceptors.add( interceptor );
2067             }
2068             else
2069             {
2070                 interceptors.add( position, interceptor );
2071             }
2072         }
2073         finally
2074         {
2075             writeLock.unlock();
2076         }
2077     }
2078 
2079 
2080     /**
2081      * {@inheritDoc}
2082      */
2083     public void remove( String interceptorName )
2084     {
2085         removeOperationsList( interceptorName );
2086     }
2087 
2088 
2089     /**
2090      * Get a new CSN
2091      * @return The CSN generated for this directory service
2092      */
2093     public Csn getCSN()
2094     {
2095         return csnFactory.newInstance();
2096     }
2097 
2098 
2099     /**
2100      * @return the replicaId
2101      */
2102     public int getReplicaId()
2103     {
2104         return replicaId;
2105     }
2106 
2107 
2108     /**
2109      * @param replicaId the replicaId to set
2110      */
2111     public void setReplicaId( int replicaId )
2112     {
2113         if ( ( replicaId < 0 ) || ( replicaId > 999 ) )
2114         {
2115             LOG.error( I18n.err( I18n.ERR_79 ) );
2116             this.replicaId = 0;
2117         }
2118         else
2119         {
2120             this.replicaId = replicaId;
2121         }
2122     }
2123 
2124 
2125     /**
2126      * {@inheritDoc}
2127      */
2128     public long getSyncPeriodMillis()
2129     {
2130         return syncPeriodMillis;
2131     }
2132 
2133 
2134     /**
2135      * {@inheritDoc}
2136      */
2137     public void setSyncPeriodMillis( long syncPeriodMillis )
2138     {
2139         this.syncPeriodMillis = syncPeriodMillis;
2140     }
2141 
2142 
2143     /**
2144      * {@inheritDoc}
2145      */
2146     public String getContextCsn()
2147     {
2148         return contextCsn;
2149     }
2150 
2151 
2152     /**
2153      * {@inheritDoc}
2154      */
2155     public void setContextCsn( String lastKnownCsn )
2156     {
2157         this.contextCsn = lastKnownCsn;
2158     }
2159 
2160 
2161     /**
2162      * checks if the working directory is already in use by some other directory service, if yes
2163      * then throws a runtime exception else will obtain the lock on the working directory
2164      */
2165     private void lockWorkDir()
2166     {
2167         FileLock fileLock = null;
2168 
2169         try
2170         {
2171             lockFile = new RandomAccessFile( new File( instanceLayout.getInstanceDirectory(), LOCK_FILE_NAME ), "rw" );
2172             try
2173             {
2174                 fileLock = lockFile.getChannel().tryLock( 0, 1, false );
2175             }
2176             catch ( IOException e )
2177             {
2178                 // shoudn't happen, but log
2179                 LOG.error( "failed to lock the work directory", e );
2180             }
2181             catch ( OverlappingFileLockException e ) // thrown if we can't get a lock
2182             {
2183                 fileLock = null;
2184             }
2185         }
2186         catch ( FileNotFoundException e )
2187         {
2188             // shouldn't happen, but log anyway
2189             LOG.error( "failed to lock the work directory", e );
2190         }
2191 
2192         if ( ( fileLock == null ) || ( !fileLock.isValid() ) )
2193         {
2194             String message = "the working directory " + instanceLayout.getRunDirectory()
2195                 + " has been locked by another directory service.";
2196             LOG.error( message );
2197             throw new RuntimeException( message );
2198         }
2199 
2200     }
2201 
2202 
2203     /**
2204      * {@inheritDoc}
2205      */
2206     public CacheService getCacheService()
2207     {
2208         return cacheService;
2209     }
2210 
2211 
2212     /**
2213      * {@inheritDoc}
2214      */
2215     public DnNode<AccessControlAdministrativePoint> getAccessControlAPCache()
2216     {
2217         return accessControlAPCache;
2218     }
2219 
2220 
2221     /**
2222      * {@inheritDoc}
2223      */
2224     public DnNode<CollectiveAttributeAdministrativePoint> getCollectiveAttributeAPCache()
2225     {
2226         return collectiveAttributeAPCache;
2227     }
2228 
2229 
2230     /**
2231      * {@inheritDoc}
2232      */
2233     public DnNode<SubschemaAdministrativePoint> getSubschemaAPCache()
2234     {
2235         return subschemaAPCache;
2236     }
2237 
2238 
2239     /**
2240      * {@inheritDoc}
2241      */
2242     public DnNode<TriggerExecutionAdministrativePoint> getTriggerExecutionAPCache()
2243     {
2244         return triggerExecutionAPCache;
2245     }
2246 
2247 
2248     /**
2249      * {@inheritDoc}
2250      */
2251     public boolean isPwdPolicyEnabled()
2252     {
2253         AuthenticationInterceptor authenticationInterceptor = ( AuthenticationInterceptor ) getInterceptor( InterceptorEnum.AUTHENTICATION_INTERCEPTOR
2254             .getName() );
2255 
2256         if ( authenticationInterceptor == null )
2257         {
2258             return false;
2259         }
2260 
2261         PpolicyConfigContainer pwdPolicyContainer = authenticationInterceptor.getPwdPolicyContainer();
2262 
2263         return ( ( pwdPolicyContainer != null )
2264         && ( ( pwdPolicyContainer.getDefaultPolicy() != null )
2265         || ( pwdPolicyContainer.hasCustomConfigs() ) ) );
2266     }
2267 
2268 
2269     /**
2270      * {@inheritDoc}
2271      */
2272     public DnFactory getDnFactory()
2273     {
2274         return dnFactory;
2275     }
2276 
2277 
2278     /**
2279      * {@inheritDoc}
2280      */
2281     public SubentryCache getSubentryCache()
2282     {
2283         return subentryCache;
2284     }
2285 
2286 
2287     /**
2288      * {@inheritDoc}
2289      */
2290     public SubtreeEvaluator getEvaluator()
2291     {
2292         return evaluator;
2293     }
2294 
2295 
2296     /**
2297      * {@inheritDoc}
2298      */
2299     public void setCacheService( CacheService cacheService )
2300     {
2301         this.cacheService = cacheService;
2302     }
2303 
2304 }