001/*
002 *   Licensed to the Apache Software Foundation (ASF) under one
003 *   or more contributor license agreements.  See the NOTICE file
004 *   distributed with this work for additional information
005 *   regarding copyright ownership.  The ASF licenses this file
006 *   to you under the Apache License, Version 2.0 (the
007 *   "License"); you may not use this file except in compliance
008 *   with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *   Unless required by applicable law or agreed to in writing,
013 *   software distributed under the License is distributed on an
014 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *   KIND, either express or implied.  See the License for the
016 *   specific language governing permissions and limitations
017 *   under the License.
018 *
019 */
020
021package org.apache.directory.server.config;
022
023
024import java.lang.reflect.Array;
025import java.lang.reflect.Constructor;
026import java.lang.reflect.Field;
027import java.lang.reflect.InvocationTargetException;
028import java.lang.reflect.Method;
029import java.lang.reflect.ParameterizedType;
030import java.lang.reflect.Type;
031import java.util.ArrayList;
032import java.util.Collection;
033import java.util.HashSet;
034import java.util.List;
035import java.util.Set;
036
037import org.apache.directory.api.ldap.model.constants.SchemaConstants;
038import org.apache.directory.api.ldap.model.cursor.Cursor;
039import org.apache.directory.api.ldap.model.entry.Attribute;
040import org.apache.directory.api.ldap.model.entry.Entry;
041import org.apache.directory.api.ldap.model.entry.Value;
042import org.apache.directory.api.ldap.model.exception.LdapException;
043import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
044import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
045import org.apache.directory.api.ldap.model.filter.EqualityNode;
046import org.apache.directory.api.ldap.model.message.AliasDerefMode;
047import org.apache.directory.api.ldap.model.message.SearchScope;
048import org.apache.directory.api.ldap.model.name.Dn;
049import org.apache.directory.api.ldap.model.name.Rdn;
050import org.apache.directory.api.ldap.model.schema.AttributeType;
051import org.apache.directory.api.ldap.model.schema.ObjectClass;
052import org.apache.directory.api.ldap.model.schema.SchemaManager;
053import org.apache.directory.server.config.beans.AdsBaseBean;
054import org.apache.directory.server.config.beans.ConfigBean;
055import org.apache.directory.server.core.api.interceptor.context.SearchOperationContext;
056import org.apache.directory.server.core.api.partition.PartitionTxn;
057import org.apache.directory.server.core.partition.impl.btree.AbstractBTreePartition;
058import org.apache.directory.server.i18n.I18n;
059import org.apache.directory.server.xdbm.IndexEntry;
060import org.apache.directory.server.xdbm.search.PartitionSearchResult;
061import org.apache.directory.server.xdbm.search.SearchEngine;
062import org.slf4j.Logger;
063import org.slf4j.LoggerFactory;
064
065
066/**
067 * A class used for reading the configuration present in a Partition
068 * and instantiate the necessary objects like DirectoryService, Interceptors etc.
069 *
070 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
071 */
072public class ConfigPartitionReader
073{
074    /** The logger for this class */
075    private static final Logger LOG = LoggerFactory.getLogger( ConfigPartitionReader.class );
076
077    /** the partition which holds the configuration data */
078    private AbstractBTreePartition configPartition;
079
080    /** the search engine of the partition */
081    private SearchEngine se;
082
083    /** the schema manager set in the config partition */
084    private SchemaManager schemaManager;
085
086    /** The prefix for all the configuration ObjectClass names */
087    private static final String ADS_PREFIX = "ads-";
088
089    /** The suffix for the bean */
090    private static final String ADS_SUFFIX = "Bean";
091
092
093    /**
094     * 
095     * Creates a new instance of ConfigPartitionReader.
096     *
097     * @param configPartition the non null config partition
098     */
099    public ConfigPartitionReader( AbstractBTreePartition configPartition )
100    {
101        if ( configPartition == null )
102        {
103            throw new IllegalArgumentException( I18n.err( I18n.ERR_503 ) );
104        }
105
106        if ( !configPartition.isInitialized() )
107        {
108            throw new IllegalStateException( I18n.err( I18n.ERR_504 ) );
109        }
110
111        this.configPartition = configPartition;
112        se = configPartition.getSearchEngine();
113        this.schemaManager = configPartition.getSchemaManager();
114    }
115
116
117    /**
118     * Find the upper objectclass in a hierarchy. All the inherited ObjectClasses
119     * will be removed.
120     */
121    private ObjectClass findObjectClass( Attribute objectClass ) throws Exception
122    {
123        Set<ObjectClass> candidates = new HashSet<ObjectClass>();
124
125        try
126        {
127            // Create the set of candidates
128            for ( Value ocValue : objectClass )
129            {
130                String ocName = ocValue.getValue();
131                String ocOid = schemaManager.getObjectClassRegistry().getOidByName( ocName );
132                ObjectClass oc = schemaManager.getObjectClassRegistry().get( ocOid );
133
134                if ( oc.isStructural() )
135                {
136                    candidates.add( oc );
137                }
138            }
139        }
140        catch ( Exception e )
141        {
142            throw e;
143        }
144
145        // Now find the parent OC
146        for ( Value ocValue : objectClass )
147        {
148            String ocName = ocValue.getValue();
149            String ocOid = schemaManager.getObjectClassRegistry().getOidByName( ocName );
150            ObjectClass oc = schemaManager.getObjectClassRegistry().get( ocOid );
151
152            for ( ObjectClass superior : oc.getSuperiors() )
153            {
154                if ( oc.isStructural() )
155                {
156                    if ( candidates.contains( superior ) )
157                    {
158                        candidates.remove( superior );
159                    }
160                }
161            }
162        }
163
164        // The remaining OC in the candidates set is the one we are looking for
165        ObjectClass result = candidates.toArray( new ObjectClass[]
166            {} )[0];
167
168        LOG.debug( "The top level object class is {}", result.getName() );
169        return result;
170    }
171
172
173    /**
174     * Create the base Bean from the ObjectClass name.
175     * The bean name is constructed using the OjectClass name, by
176     * removing the ADS prefix, upper casing the first letter and adding "Bean" at the end.
177     * 
178     * For instance, ads-directoryService wil become DirectoryServiceBean
179     */
180    private AdsBaseBean createBean( ObjectClass objectClass ) throws ConfigurationException
181    {
182        // The remaining OC in the candidates set is the one we are looking for
183        String objectClassName = objectClass.getName();
184
185        // Now, let's instantiate the associated bean. Get rid of the 'ads-' in front of the name,
186        // and uppercase the first letter. Finally add "Bean" at the end and add the package.
187        //String beanName = this.getClass().getPackage().getName() + "org.apache.directory.server.config.beans." + Character.toUpperCase( objectClassName.charAt( 4 ) ) + objectClassName.substring( 5 ) + "Bean";
188        String beanName = this.getClass().getPackage().getName() + ".beans."
189            + Character.toUpperCase( objectClassName.charAt( ADS_PREFIX.length() ) )
190            + objectClassName.substring( ADS_PREFIX.length() + 1 ) + ADS_SUFFIX;
191
192        try
193        {
194            Class<?> clazz = Class.forName( beanName );
195            Constructor<?> constructor = clazz.getConstructor();
196            AdsBaseBean bean = ( AdsBaseBean ) constructor.newInstance();
197
198            LOG.debug( "Bean {} created for ObjectClass {}", beanName, objectClassName );
199
200            return bean;
201        }
202        catch ( ClassNotFoundException cnfe )
203        {
204            String message = "Cannot find a Bean class for the ObjectClass name " + objectClassName;
205            LOG.error( message );
206            throw new ConfigurationException( message );
207        }
208        catch ( SecurityException se )
209        {
210            String message = "Cannot access to the class " + beanName;
211            LOG.error( message );
212            throw new ConfigurationException( message );
213        }
214        catch ( NoSuchMethodException nsme )
215        {
216            String message = "Cannot find a constructor for the class " + beanName;
217            LOG.error( message );
218            throw new ConfigurationException( message );
219        }
220        catch ( InvocationTargetException ite )
221        {
222            String message = "Cannot invoke the class " + beanName + ", " + ite.getMessage();
223            LOG.error( message );
224            throw new ConfigurationException( message );
225        }
226        catch ( IllegalAccessException iae )
227        {
228            String message = "Cannot access to the constructor for class " + beanName;
229            LOG.error( message );
230            throw new ConfigurationException( message );
231        }
232        catch ( InstantiationException ie )
233        {
234            String message = "Cannot instantiate the class " + beanName + ", " + ie.getMessage();
235            LOG.error( message );
236            throw new ConfigurationException( message );
237        }
238    }
239
240
241    /**
242     * Read the single entry value for an AttributeType, and feed the Bean field with this value
243     */
244    private void readSingleValueField( AdsBaseBean bean, Field beanField, Attribute fieldAttr )
245        throws ConfigurationException
246    {
247        if ( fieldAttr == null )
248        {
249            return;
250        }
251        
252        
253        Value value = fieldAttr.get();
254        String valueStr = ""; 
255        
256        if ( value != null )
257        {
258            valueStr = value.getValue();
259        }
260
261        Class<?> type = beanField.getType();
262
263        // Process the value accordingly to its type.
264        try
265        {
266            if ( type == String.class )
267            {
268                beanField.set( bean, valueStr );
269            }
270            else if ( type == byte[].class )
271            {
272                beanField.set( bean, value.getBytes() );
273            }
274            else if ( type == int.class )
275            {
276                beanField.setInt( bean, Integer.parseInt( valueStr ) );
277            }
278            else if ( type == long.class )
279            {
280                beanField.setLong( bean, Long.parseLong( valueStr ) );
281            }
282            else if ( type == boolean.class )
283            {
284                beanField.setBoolean( bean, Boolean.parseBoolean( valueStr ) );
285            }
286            else if ( type == Dn.class )
287            {
288                try
289                {
290                    Dn dn = new Dn( valueStr );
291                    beanField.set( bean, dn );
292                }
293                catch ( LdapInvalidDnException lide )
294                {
295                    String message = "The Dn '" + valueStr + "' for attribute " + fieldAttr.getId()
296                        + " is not a valid Dn";
297                    LOG.error( message );
298                    throw new ConfigurationException( message );
299                }
300            }
301        }
302        catch ( IllegalArgumentException iae )
303        {
304            String message = "Cannot store '" + valueStr + "' into attribute " + fieldAttr.getId();
305            LOG.error( message );
306            throw new ConfigurationException( message );
307        }
308        catch ( IllegalAccessException e )
309        {
310            String message = "Cannot store '" + valueStr + "' into attribute " + fieldAttr.getId();
311            LOG.error( message );
312            throw new ConfigurationException( message );
313        }
314    }
315
316
317    /**
318     * Read the multiple entry value for an AttributeType, and feed the Bean field with this value
319     */
320    private void readMultiValuedField( AdsBaseBean bean, Field field, Attribute attribute )
321        throws ConfigurationException
322    {
323        if ( attribute == null )
324        {
325            return;
326        }
327
328        Class<?> type = field.getType();
329
330        String fieldName = field.getName();
331        String addMethodName = "add" + Character.toUpperCase( fieldName.charAt( 0 ) ) + fieldName.substring( 1 );
332
333        // loop on the values and inject them in the bean
334        for ( Value value : attribute )
335        {
336            String valueStr = value.getValue();
337
338            try
339            {
340                if ( type == String.class )
341                {
342                    field.set( bean, valueStr );
343                }
344                else if ( type == int.class )
345                {
346                    field.setInt( bean, Integer.parseInt( valueStr ) );
347                }
348                else if ( type == long.class )
349                {
350                    field.setLong( bean, Long.parseLong( valueStr ) );
351                }
352                else if ( type == boolean.class )
353                {
354                    field.setBoolean( bean, Boolean.parseBoolean( valueStr ) );
355                }
356                else if ( type == Dn.class )
357                {
358                    try
359                    {
360                        Dn dn = new Dn( valueStr );
361                        field.set( bean, dn );
362                    }
363                    catch ( LdapInvalidDnException lide )
364                    {
365                        String message = "The Dn '" + valueStr + "' for attribute " + attribute.getId()
366                            + " is not a valid Dn";
367                        LOG.error( message );
368                        throw new ConfigurationException( message );
369                    }
370                }
371                else if ( type == Set.class )
372                {
373                    Type genericFieldType = field.getGenericType();
374                    Class<?> fieldArgClass = null;
375
376                    if ( genericFieldType instanceof ParameterizedType )
377                    {
378                        ParameterizedType parameterizedType = ( ParameterizedType ) genericFieldType;
379                        Type[] fieldArgTypes = parameterizedType.getActualTypeArguments();
380
381                        for ( Type fieldArgType : fieldArgTypes )
382                        {
383                            fieldArgClass = ( Class<?> ) fieldArgType;
384                        }
385                    }
386
387                    Method method = bean.getClass().getMethod( addMethodName,
388                        Array.newInstance( fieldArgClass, 0 ).getClass() );
389
390                    method.invoke( bean, new Object[]
391                        { new String[]
392                            { valueStr } } );
393                }
394                else if ( type == List.class )
395                {
396                    Type genericFieldType = field.getGenericType();
397                    Class<?> fieldArgClass = null;
398
399                    if ( genericFieldType instanceof ParameterizedType )
400                    {
401                        ParameterizedType parameterizedType = ( ParameterizedType ) genericFieldType;
402                        Type[] fieldArgTypes = parameterizedType.getActualTypeArguments();
403
404                        for ( Type fieldArgType : fieldArgTypes )
405                        {
406                            fieldArgClass = ( Class<?> ) fieldArgType;
407                        }
408                    }
409
410                    Method method = bean.getClass().getMethod( addMethodName,
411                        Array.newInstance( fieldArgClass, 0 ).getClass() );
412
413                    method.invoke( bean, new Object[]
414                        { new String[]
415                            { valueStr } } );
416                }
417            }
418            catch ( IllegalArgumentException iae )
419            {
420                String message = "Cannot store '" + valueStr + "' into attribute " + attribute.getId();
421                LOG.error( message );
422                throw new ConfigurationException( message );
423            }
424            catch ( IllegalAccessException e )
425            {
426                String message = "Cannot store '" + valueStr + "' into attribute " + attribute.getId();
427                LOG.error( message );
428                throw new ConfigurationException( message );
429            }
430            catch ( SecurityException se )
431            {
432                String message = "Cannot access to the class " + bean.getClass().getName();
433                LOG.error( message );
434                throw new ConfigurationException( message );
435            }
436            catch ( NoSuchMethodException nsme )
437            {
438                String message = "Cannot find a method " + addMethodName + " in the class " + bean.getClass().getName();
439                LOG.error( message );
440                throw new ConfigurationException( message );
441            }
442            catch ( InvocationTargetException ite )
443            {
444                String message = "Cannot invoke the class " + bean.getClass().getName() + ", " + ite.getMessage();
445                LOG.error( message );
446                throw new ConfigurationException( message );
447            }
448            catch ( NegativeArraySizeException nase )
449            {
450                // No way that can happen...
451            }
452        }
453    }
454
455
456    private void readFieldValue( AdsBaseBean bean, Field field, Entry entry, String attributeTypeName, boolean mandatory )
457        throws ConfigurationException
458    {
459        // Get the entry attribute for this attribute type
460        Attribute attribute = entry.get( attributeTypeName );
461
462        if ( attribute != null )
463        {
464            if ( attribute.size() > 0 )
465            {
466                if ( !isMultiple( field.getType() ) )
467                {
468                    readSingleValueField( bean, field, attribute );
469                }
470                else
471                {
472                    readMultiValuedField( bean, field, attribute );
473                }
474            }
475            else if ( attribute.size() == 0 )
476            {
477                // No value ? May be valid
478                readSingleValueField( bean, field, attribute );
479            }
480            else if ( mandatory )
481            {
482                // the requested element is mandatory so let's throw an exception
483                String message = "No value was configured for entry with DN '"
484                    + entry.getDn() + "' and attribute type '" + attributeTypeName + "'.";
485                LOG.error( message );
486                throw new ConfigurationException( message );
487            }
488        }
489        else
490        {
491            if ( mandatory )
492            {
493                // the requested element is mandatory so let's throw an exception
494                String message = "No value was configured for entry with DN '"
495                    + entry.getDn() + "' and attribute type '" + attributeTypeName + "'.";
496                LOG.error( message );
497                throw new ConfigurationException( message );
498            }
499        }
500    }
501
502
503    /**
504     * Read some configuration element from the DIT using its name
505     * 
506     * @param baseDn The base Dn in the DIT where the configuration is stored
507     * @param name The element to read
508     * @param scope The search scope
509     * @param mandatory If the element is mandatory or not
510     * @return The list of beans read
511     * @throws ConfigurationException If the configuration cannot be read 
512     */
513    public List<AdsBaseBean> read( Dn baseDn, String name, SearchScope scope, boolean mandatory )
514        throws ConfigurationException
515    {
516        LOG.debug( "Reading from '{}', objectClass '{}'", baseDn, name );
517
518        // Search for the element starting at some point in the DIT
519        // Prepare the search request
520        AttributeType ocAt = schemaManager.getAttributeType( SchemaConstants.OBJECT_CLASS_AT );
521        EqualityNode<String> filter = null;
522        
523        try
524        {
525            filter = new EqualityNode<>( ocAt, new Value( ocAt, name ) );
526        }
527        catch ( LdapInvalidAttributeValueException liave )
528        {
529            throw new ConfigurationException( liave.getMessage() );
530        }
531        
532        Cursor<IndexEntry<String, String>> cursor = null;
533
534        // Create a container for all the read beans
535        List<AdsBaseBean> beansList = new ArrayList<>();
536
537        try
538        {
539            // Do the search
540            
541            try ( PartitionTxn partitionTxn = configPartition.beginReadTransaction() )
542            {
543                SearchOperationContext searchContext = new SearchOperationContext( null );
544                searchContext.setAliasDerefMode( AliasDerefMode.NEVER_DEREF_ALIASES );
545                searchContext.setDn( baseDn );
546                searchContext.setFilter( filter );
547                searchContext.setScope( scope );
548                searchContext.setPartition( configPartition );
549                searchContext.setTransaction( partitionTxn );
550                PartitionSearchResult searchResult = se.computeResult( partitionTxn, schemaManager, searchContext );
551    
552                cursor = searchResult.getResultSet();
553    
554                // First, check if we have some entries to process.
555                if ( !cursor.next() )
556                {
557                    if ( mandatory )
558                    {
559                        cursor.close();
560    
561                        // the requested element is mandatory so let's throw an exception
562                        String message = "No instance was configured under the DN '"
563                            + baseDn + "' for the objectClass '" + name + "'.";
564                        LOG.error( message );
565                        throw new ConfigurationException( message );
566                    }
567                    else
568                    {
569                        return null;
570                    }
571                }
572    
573                // Loop on all the found elements
574                do
575                {
576                    IndexEntry<String, String> forwardEntry = cursor.get();
577    
578                    // Now, get the entry
579                    Entry entry = configPartition.fetch( partitionTxn, forwardEntry.getId() );
580                    LOG.debug( "Entry read : {}", entry );
581    
582                    AdsBaseBean bean = readConfig( entry );
583                    // Adding the bean to the list
584                    beansList.add( bean );
585                }
586                while ( cursor.next() );
587            }
588        }
589        catch ( ConfigurationException ce )
590        {
591            throw ce;
592        }
593        catch ( Exception e )
594        {
595            String message = "An error occured while reading the configuration DN '"
596                + baseDn + "' for the objectClass '" + name + "':\n" + e.getMessage();
597            LOG.error( message );
598            throw new ConfigurationException( message, e );
599        }
600        finally
601        {
602            if ( cursor != null )
603            {
604                try
605                {
606                    cursor.close();
607                }
608                catch ( Exception e )
609                {
610                    // So ??? If the cursor can't be close, there is nothing we can do
611                    // but rethrow the exception
612                    throw new ConfigurationException( e.getMessage(), e.getCause() );
613                }
614            }
615        }
616
617        return beansList;
618    }
619
620
621    /**
622     * Creates a configuration bean from the given entry.
623     * 
624     * @param entry any configuration entry of the type "ads-base"
625     * @return The ApacheDS base configuration
626     * @throws Exception If the configuration cannot be read
627     */
628    public AdsBaseBean readConfig( Entry entry ) throws Exception
629    {
630        // Let's instantiate the bean we need. The upper ObjectClass's name
631        // will be used to do that
632        ObjectClass objectClass = findObjectClass( entry.get( SchemaConstants.OBJECT_CLASS_AT ) );
633
634        // Instantiating the bean
635        AdsBaseBean bean = createBean( objectClass );
636
637        // Setting its DN
638        bean.setDn( entry.getDn() );
639
640        // Getting the class of the bean
641        Class<?> beanClass = bean.getClass();
642
643        // A flag to know when we reached the 'AdsBaseBean' class when 
644        // looping on the class hierarchy of the bean
645        boolean adsBaseBeanClassFound = false;
646
647        // Looping until the 'AdsBaseBean' class has been found
648        while ( !adsBaseBeanClassFound )
649        {
650            // Checking if we reached the 'AdsBaseBean' class
651            if ( beanClass == AdsBaseBean.class )
652            {
653                adsBaseBeanClassFound = true;
654            }
655
656            // Looping on all fields of the bean
657            Field[] fields = beanClass.getDeclaredFields();
658            for ( Field field : fields )
659            {
660                // Making the field accessible (we get an exception if we don't do that)
661                field.setAccessible( true );
662
663                // Getting the class of the field
664                Class<?> fieldClass = field.getType();
665
666                // Looking for the @ConfigurationElement annotation
667                ConfigurationElement configurationElement = field.getAnnotation( ConfigurationElement.class );
668                if ( configurationElement != null )
669                {
670                    // Getting the annotation's values
671                    String fieldAttributeType = configurationElement.attributeType();
672                    String fieldObjectClass = configurationElement.objectClass();
673                    String container = configurationElement.container();
674                    boolean isOptional = configurationElement.isOptional();
675
676                    // Checking if we have a value for the attribute type
677                    if ( ( fieldAttributeType != null ) && ( !"".equals( fieldAttributeType ) ) )
678                    {
679                        readFieldValue( bean, field, entry, fieldAttributeType, !isOptional );
680                    }
681                    // Checking if we have a value for the object class
682                    else if ( ( fieldObjectClass != null ) && ( !"".equals( fieldObjectClass ) ) )
683                    {
684                        // Checking if this is a multi-valued field (which values are stored in a container)
685                        if ( isMultiple( fieldClass ) && ( container != null )
686                            && ( !"".equals( container ) ) )
687                        {
688                            // Creating the DN of the container
689                            Dn newBase = entry.getDn().add( "ou=" + container );
690
691                            // Looking for the field values
692                            Collection<AdsBaseBean> fieldValues = read( newBase, fieldObjectClass,
693                                SearchScope.ONELEVEL, !isOptional );
694
695                            // Setting the values to the field
696                            if ( ( fieldValues != null ) && ( fieldValues.size() > 0 ) )
697                            {
698                                field.set( bean, fieldValues );
699                            }
700                        }
701                        // This is a single-value field
702                        else
703                        {
704                            // Looking for the field values
705                            List<AdsBaseBean> fieldValues = read( entry.getDn(), fieldObjectClass,
706                                SearchScope.ONELEVEL, !isOptional );
707
708                            // Setting the value to the field
709                            if ( ( fieldValues != null ) && ( fieldValues.size() > 0 ) )
710                            {
711                                field.set( bean, fieldValues.get( 0 ) );
712                            }
713                        }
714                    }
715                }
716            }
717
718            // Moving to the upper class in the class hierarchy
719            beanClass = beanClass.getSuperclass();
720        }
721        
722        return bean;
723    }
724    
725    
726    /**
727     * Indicates the given type is multiple.
728     *
729     * @param clazz
730     *      the class
731     * @return
732     *      <code>true</code> if the given is multiple,
733     *      <code>false</code> if not.
734     */
735    private boolean isMultiple( Class<?> clazz )
736    {
737        return Collection.class.isAssignableFrom( clazz );
738    }
739
740
741    /**
742     * Read the configuration from the DIT, returning a bean containing all of it.
743     * <p>
744     * This method implicitly uses <em>"ou=config"</em> as base Dn
745     * 
746     * @return The Config bean, containing the whole configuration
747     * @throws ConfigurationException If we had some issue reading the configuration
748     */
749    public ConfigBean readConfig() throws LdapException
750    {
751        // The starting point is the DirectoryService element
752        return readConfig( new Dn( new Rdn( SchemaConstants.OU_AT, "config" ) ) );
753    }
754
755
756    /**
757     * Read the configuration from the DIT, returning a bean containing all of it.
758     * 
759     * @param baseDn The base Dn in the DIT where the configuration is stored
760     * @return The Config bean, containing the whole configuration
761     * @throws ConfigurationException If we had some issue reading the configuration
762     */
763    public ConfigBean readConfig( String baseDn ) throws LdapException
764    {
765        // The starting point is the DirectoryService element
766        return readConfig( new Dn( baseDn ) );
767    }
768
769
770    /**
771     * Read the configuration from the DIT, returning a bean containing all of it.
772     * 
773     * @param baseDn The base Dn in the DIT where the configuration is stored
774     * @return The Config bean, containing the whole configuration
775     * @throws ConfigurationException If we had some issue reading the configuration
776     */
777    public ConfigBean readConfig( Dn baseDn ) throws ConfigurationException
778    {
779        // The starting point is the DirectoryService element
780        return readConfig( baseDn, ConfigSchemaConstants.ADS_DIRECTORY_SERVICE_OC.getValue() );
781    }
782
783
784    /**
785     * Read the configuration from the DIT, returning a bean containing all of it.
786     * 
787     * @param baseDn The base Dn in the DIT where the configuration is stored
788     * @param objectClass The element to read from the DIT
789     * @return The bean containing the configuration for the required element
790     * @throws ConfigurationException If the configuration cannot be read
791     */
792    public ConfigBean readConfig( String baseDn, String objectClass ) throws LdapException
793    {
794        return readConfig( new Dn( baseDn ), objectClass );
795    }
796
797
798    /**
799     * Read the configuration from the DIT, returning a bean containing all of it.
800     * 
801     * @param baseDn The base Dn in the DIT where the configuration is stored
802     * @param objectClass The element to read from the DIT
803     * @return The bean containing the configuration for the required element
804     * @throws ConfigurationException If the configuration cannot be read
805     */
806    public ConfigBean readConfig( Dn baseDn, String objectClass ) throws ConfigurationException
807    {
808        LOG.debug( "Reading configuration for the {} element, from {} ", objectClass, baseDn );
809        ConfigBean configBean = new ConfigBean();
810
811        if ( baseDn == null )
812        {
813            baseDn = configPartition.getSuffixDn();
814        }
815
816        List<AdsBaseBean> beans = read( baseDn, objectClass, SearchScope.ONELEVEL, true );
817
818        if ( LOG.isDebugEnabled() )
819        {
820            if ( ( beans == null ) || ( beans.size() == 0 ) )
821            {
822                LOG.debug( "No {} element to read", objectClass );
823            }
824            else
825            {
826                LOG.debug( beans.get( 0 ).toString() );
827            }
828        }
829
830        configBean.setDirectoryServiceBeans( beans );
831
832        return configBean;
833    }
834}