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