| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| package org.apache.directory.server.config; |
| |
| |
| import java.lang.reflect.Array; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Set; |
| |
| import javax.naming.directory.SearchControls; |
| |
| import org.apache.directory.server.config.beans.AdsBaseBean; |
| import org.apache.directory.server.config.beans.ConfigBean; |
| import org.apache.directory.server.core.partition.impl.btree.BTreePartition; |
| import org.apache.directory.server.i18n.I18n; |
| import org.apache.directory.server.xdbm.ForwardIndexEntry; |
| import org.apache.directory.server.xdbm.IndexCursor; |
| import org.apache.directory.server.xdbm.search.SearchEngine; |
| import org.apache.directory.shared.ldap.model.constants.SchemaConstants; |
| import org.apache.directory.shared.ldap.model.entry.Entry; |
| import org.apache.directory.shared.ldap.model.entry.EntryAttribute; |
| import org.apache.directory.shared.ldap.model.entry.StringValue; |
| import org.apache.directory.shared.ldap.model.entry.Value; |
| import org.apache.directory.shared.ldap.model.exception.LdapException; |
| import org.apache.directory.shared.ldap.model.exception.LdapInvalidDnException; |
| import org.apache.directory.shared.ldap.model.filter.EqualityNode; |
| import org.apache.directory.shared.ldap.model.filter.SearchScope; |
| import org.apache.directory.shared.ldap.model.message.AliasDerefMode; |
| import org.apache.directory.shared.ldap.model.name.Dn; |
| import org.apache.directory.shared.ldap.model.name.Rdn; |
| import org.apache.directory.shared.ldap.model.schema.MutableAttributeTypeImpl; |
| import org.apache.directory.shared.ldap.model.schema.ObjectClass; |
| import org.apache.directory.shared.ldap.model.schema.SchemaManager; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| |
| /** |
| * A class used for reading the configuration present in a Partition |
| * and instantiate the necessary objects like DirectoryService, Interceptors etc. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class ConfigPartitionReader |
| { |
| /** The logger for this class */ |
| private static final Logger LOG = LoggerFactory.getLogger( ConfigPartitionReader.class ); |
| |
| /** the partition which holds the configuration data */ |
| private BTreePartition<Long> configPartition; |
| |
| /** the search engine of the partition */ |
| private SearchEngine<Entry, Long> se; |
| |
| /** the schema manager set in the config partition */ |
| private SchemaManager schemaManager; |
| |
| /** The prefix for all the configuration ObjectClass names */ |
| private static final String ADS_PREFIX = "ads-"; |
| |
| /** The suffix for the bean */ |
| private static final String ADS_SUFFIX = "Bean"; |
| |
| /** Those two flags are used to tell the reader if an element of configuration is mandatory or not */ |
| private static final boolean MANDATORY = true; |
| private static final boolean OPTIONNAL = false; |
| |
| |
| /** |
| * |
| * Creates a new instance of ConfigPartitionReader. |
| * |
| * @param configPartition the non null config partition |
| */ |
| public ConfigPartitionReader( BTreePartition<Long> configPartition ) |
| { |
| if ( configPartition == null ) |
| { |
| throw new IllegalArgumentException( I18n.err( I18n.ERR_503 ) ); |
| } |
| |
| if ( !configPartition.isInitialized() ) |
| { |
| throw new IllegalStateException( I18n.err( I18n.ERR_504 ) ); |
| } |
| |
| this.configPartition = configPartition; |
| se = configPartition.getSearchEngine(); |
| this.schemaManager = configPartition.getSchemaManager(); |
| } |
| |
| |
| /** |
| * Fnd the upper objectclass in a hierarchy. All the inherited ObjectClasses |
| * will be removed. |
| */ |
| private ObjectClass findObjectClass( EntryAttribute objectClass ) throws Exception |
| { |
| Set<ObjectClass> candidates = new HashSet<ObjectClass>(); |
| |
| try |
| { |
| // Create the set of candidates |
| for ( Value<?> ocValue : objectClass ) |
| { |
| String ocName = ocValue.getString(); |
| String ocOid = schemaManager.getObjectClassRegistry().getOidByName( ocName ); |
| ObjectClass oc = ( ObjectClass ) schemaManager.getObjectClassRegistry().get( ocOid ); |
| |
| if ( oc.isStructural() ) |
| { |
| candidates.add( oc ); |
| } |
| } |
| } |
| catch ( Exception e ) |
| { |
| e.printStackTrace(); |
| throw e; |
| } |
| |
| // Now find the parent OC |
| for ( Value<?> ocValue : objectClass ) |
| { |
| String ocName = ocValue.getString(); |
| String ocOid = schemaManager.getObjectClassRegistry().getOidByName( ocName ); |
| ObjectClass oc = ( ObjectClass ) schemaManager.getObjectClassRegistry().get( ocOid ); |
| |
| for ( ObjectClass superior : oc.getSuperiors() ) |
| { |
| if ( oc.isStructural() ) |
| { |
| if ( candidates.contains( superior ) ) |
| { |
| candidates.remove( superior ); |
| } |
| } |
| } |
| } |
| |
| // The remaining OC in the candidates set is the one we are looking for |
| ObjectClass result = candidates.toArray( new ObjectClass[] |
| {} )[0]; |
| |
| LOG.debug( "The top level object class is {}", result.getName() ); |
| return result; |
| } |
| |
| |
| /** |
| * Create the base Bean from the ObjectClass name. |
| * The bean name is constructed using the OjectClass name, by |
| * removing the ADS prefix, upper casing the first letter and adding "Bean" at the end. |
| * |
| * For instance, ads-directoryService wil become DirectoryServiceBean |
| */ |
| private AdsBaseBean createBean( ObjectClass objectClass ) throws ConfigurationException |
| { |
| // The remaining OC in the candidates set is the one we are looking for |
| String objectClassName = objectClass.getName(); |
| |
| // Now, let's instanciate the associated bean. Get rid of the 'ads-' in front of the name, |
| // and uppercase the first letter. Finally add "Bean" at the end and add the package. |
| //String beanName = this.getClass().getPackage().getName() + "org.apache.directory.server.config.beans." + Character.toUpperCase( objectClassName.charAt( 4 ) ) + objectClassName.substring( 5 ) + "Bean"; |
| String beanName = this.getClass().getPackage().getName() + ".beans." + |
| Character.toUpperCase( objectClassName.charAt( ADS_PREFIX.length() ) ) + |
| objectClassName.substring( ADS_PREFIX.length() + 1 ) + ADS_SUFFIX; |
| |
| try |
| { |
| Class<?> clazz = Class.forName( beanName ); |
| Constructor<?> constructor = clazz.getConstructor(); |
| AdsBaseBean bean = ( AdsBaseBean ) constructor.newInstance(); |
| |
| LOG.debug( "Bean {} created for ObjectClass {}", beanName, objectClassName ); |
| |
| return bean; |
| } |
| catch ( ClassNotFoundException cnfe ) |
| { |
| String message = "Cannot find a Bean class for the ObjectClass name " + objectClassName; |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( SecurityException se ) |
| { |
| String message = "Cannot access to the class " + beanName; |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( NoSuchMethodException nsme ) |
| { |
| String message = "Cannot find a constructor for the class " + beanName; |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( InvocationTargetException ite ) |
| { |
| String message = "Cannot invoke the class " + beanName + ", " + ite.getMessage(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( IllegalAccessException iae ) |
| { |
| String message = "Cannot access to the constructor for class " + beanName; |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( InstantiationException ie ) |
| { |
| String message = "Cannot instanciate the class " + beanName + ", " + ie.getMessage(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| } |
| |
| |
| /** |
| * Retrieve the Field associated with an AttributeType name, if any. |
| */ |
| private static Field getField( Class<?> clazz, String attributeName, Class<?> originalClazz ) |
| throws ConfigurationException |
| { |
| // We will check all the fields, as the AT name is case insentitive |
| // when the field is case sensitive |
| Field[] fields = clazz.getDeclaredFields(); |
| |
| for ( Field field : fields ) |
| { |
| String fieldName = field.getName(); |
| |
| if ( fieldName.equalsIgnoreCase( attributeName ) ) |
| { |
| return field; |
| } |
| } |
| |
| // May be in the paren'ts class ? |
| if ( clazz.getSuperclass() != null ) |
| { |
| return getField( clazz.getSuperclass(), attributeName, originalClazz ); |
| } |
| |
| String message = "Cannot find a field named " + attributeName + " in class " + originalClazz.getName(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| |
| |
| /** |
| * Read the single entry value for an AttributeType, and feed the Bean field with this value |
| */ |
| private void readSingleValueField( AdsBaseBean bean, Field beanField, EntryAttribute fieldAttr, boolean mandatory ) |
| throws ConfigurationException |
| { |
| if ( fieldAttr == null ) |
| { |
| return; |
| } |
| |
| Value<?> value = fieldAttr.get(); |
| String valueStr = value.getString(); |
| Class<?> type = beanField.getType(); |
| |
| // Process the value accordingly to its type. |
| try |
| { |
| if ( type == String.class ) |
| { |
| beanField.set( bean, value.getString() ); |
| } |
| else if ( type == int.class ) |
| { |
| beanField.setInt( bean, Integer.parseInt( valueStr ) ); |
| } |
| else if ( type == long.class ) |
| { |
| beanField.setLong( bean, Long.parseLong( valueStr ) ); |
| } |
| else if ( type == boolean.class ) |
| { |
| beanField.setBoolean( bean, Boolean.parseBoolean( valueStr ) ); |
| } |
| else if ( type == Dn.class ) |
| { |
| try |
| { |
| Dn dn = new Dn( valueStr ); |
| beanField.set( bean, dn ); |
| } |
| catch ( LdapInvalidDnException lide ) |
| { |
| String message = "The Dn '" + valueStr + "' for attribute " + fieldAttr.getId() |
| + " is not a valid Dn"; |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| } |
| } |
| catch ( IllegalArgumentException iae ) |
| { |
| String message = "Cannot store '" + valueStr + "' into attribute " + fieldAttr.getId(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( IllegalAccessException e ) |
| { |
| String message = "Cannot store '" + valueStr + "' into attribute " + fieldAttr.getId(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| } |
| |
| |
| /** |
| * Read the multiple entry value for an AttributeType, and feed the Bean field with this value |
| */ |
| private void readMultiValuedField( AdsBaseBean bean, Field beanField, EntryAttribute fieldAttr, boolean mandatory ) |
| throws ConfigurationException |
| { |
| if ( fieldAttr == null ) |
| { |
| return; |
| } |
| |
| Class<?> type = beanField.getType(); |
| |
| String fieldName = beanField.getName(); |
| String addMethodName = "add" + Character.toUpperCase( fieldName.charAt( 0 ) ) + fieldName.substring( 1 ); |
| |
| // loop on the values and inject them in the bean |
| for ( Value<?> value : fieldAttr ) |
| { |
| String valueStr = value.getString(); |
| |
| try |
| { |
| if ( type == String.class ) |
| { |
| beanField.set( bean, value.getString() ); |
| } |
| else if ( type == int.class ) |
| { |
| beanField.setInt( bean, Integer.parseInt( valueStr ) ); |
| } |
| else if ( type == long.class ) |
| { |
| beanField.setLong( bean, Long.parseLong( valueStr ) ); |
| } |
| else if ( type == boolean.class ) |
| { |
| beanField.setBoolean( bean, Boolean.parseBoolean( valueStr ) ); |
| } |
| else if ( type == Dn.class ) |
| { |
| try |
| { |
| Dn dn = new Dn( valueStr ); |
| beanField.set( bean, dn ); |
| } |
| catch ( LdapInvalidDnException lide ) |
| { |
| String message = "The Dn '" + valueStr + "' for attribute " + fieldAttr.getId() |
| + " is not a valid Dn"; |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| } |
| else if ( type == Set.class ) |
| { |
| Type genericFieldType = beanField.getGenericType(); |
| Class<?> fieldArgClass = null; |
| |
| if ( genericFieldType instanceof ParameterizedType ) |
| { |
| ParameterizedType parameterizedType = ( ParameterizedType ) genericFieldType; |
| Type[] fieldArgTypes = parameterizedType.getActualTypeArguments(); |
| |
| for ( Type fieldArgType : fieldArgTypes ) |
| { |
| fieldArgClass = ( Class<?> ) fieldArgType; |
| } |
| } |
| |
| Method method = bean.getClass().getMethod( addMethodName, |
| Array.newInstance( fieldArgClass, 0 ).getClass() ); |
| |
| method.invoke( bean, new Object[] |
| { new String[] |
| { valueStr } } ); |
| } |
| else if ( type == List.class ) |
| { |
| Type genericFieldType = beanField.getGenericType(); |
| Class<?> fieldArgClass = null; |
| |
| if ( genericFieldType instanceof ParameterizedType ) |
| { |
| ParameterizedType parameterizedType = ( ParameterizedType ) genericFieldType; |
| Type[] fieldArgTypes = parameterizedType.getActualTypeArguments(); |
| |
| for ( Type fieldArgType : fieldArgTypes ) |
| { |
| fieldArgClass = ( Class<?> ) fieldArgType; |
| } |
| } |
| |
| Method method = bean.getClass().getMethod( addMethodName, |
| Array.newInstance( fieldArgClass, 0 ).getClass() ); |
| |
| method.invoke( bean, new Object[] |
| { new String[] |
| { valueStr } } ); |
| } |
| } |
| catch ( IllegalArgumentException iae ) |
| { |
| String message = "Cannot store '" + valueStr + "' into attribute " + fieldAttr.getId(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( IllegalAccessException e ) |
| { |
| String message = "Cannot store '" + valueStr + "' into attribute " + fieldAttr.getId(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( SecurityException se ) |
| { |
| String message = "Cannot access to the class " + bean.getClass().getName(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( NoSuchMethodException nsme ) |
| { |
| String message = "Cannot find a method " + addMethodName + " in the class " + bean.getClass().getName(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( InvocationTargetException ite ) |
| { |
| String message = "Cannot invoke the class " + bean.getClass().getName() + ", " + ite.getMessage(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| catch ( NegativeArraySizeException nase ) |
| { |
| // No way that can happen... |
| } |
| } |
| } |
| |
| |
| /** |
| * Read all the required fields (AttributeTypes) for a given Entry. |
| */ |
| private void readFields( AdsBaseBean bean, Entry entry, Set<MutableAttributeTypeImpl> attributeTypes, boolean mandatory ) |
| throws NoSuchFieldException, IllegalAccessException, Exception |
| { |
| for ( MutableAttributeTypeImpl attributeType : attributeTypes ) |
| { |
| String fieldName = attributeType.getName(); |
| String beanFieldName = fieldName; |
| |
| // Remove the "ads-" from the beginning of the field name |
| if ( fieldName.startsWith( ADS_PREFIX ) ) |
| { |
| beanFieldName = fieldName.substring( ADS_PREFIX.length() ); |
| } |
| |
| // Get the field |
| Field beanField = getField( bean.getClass(), beanFieldName, bean.getClass() ); |
| |
| // The field is private, we need to modify it to be able to access it. |
| beanField.setAccessible( true ); |
| |
| // Get the entry attribute for this field |
| EntryAttribute fieldAttr = entry.get( fieldName ); |
| |
| if ( ( fieldAttr == null ) && ( mandatory ) ) |
| { |
| String message = "Attribute " + fieldName + " is mandatory and is not present for the Entry " |
| + entry.getDn(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| |
| // Get the associated AttributeType |
| MutableAttributeTypeImpl beanAT = schemaManager.getAttributeType( fieldName ); |
| |
| // Check if this AT has the ads-compositeElement as a superior |
| MutableAttributeTypeImpl superior = beanAT.getSuperior(); |
| |
| if ( ( superior != null ) |
| && superior.getOid().equals( ConfigSchemaConstants.ADS_COMPOSITE_ELEMENT_AT.getOid() ) ) |
| { |
| // This is a composite element, we have to go one level down to read it. |
| // First, check if it's a SingleValued element |
| if ( beanAT.isSingleValued() ) |
| { |
| // Yes : get the first element |
| List<AdsBaseBean> beans = read( entry.getDn(), fieldName, SearchScope.ONELEVEL, mandatory ); |
| |
| // We may not have found an element, but if the attribute is mandatory, |
| // this is an error |
| if ( ( beans == null ) || ( beans.size() == 0 ) ) |
| { |
| if ( mandatory ) |
| { |
| // This is an error ! |
| String message = "The composite " + beanAT.getName() |
| + " is mandatory, and was not found under the " |
| + "configuration entry " + entry.getDn(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| } |
| else |
| { |
| // We must take the first element |
| AdsBaseBean readBean = beans.get( 0 ); |
| |
| if ( beans.size() > 1 ) |
| { |
| // Not allowed as the AT is singled-valued |
| String message = "We have more than one entry for " + beanAT.getName() + " under " |
| + entry.getDn(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| |
| beanField.set( bean, readBean ); |
| } |
| } |
| else |
| { |
| // No : we have to loop recursively on all the elements which are |
| // under the ou=<element-name> branch |
| Dn newBase = entry.getDn().add( "ou=" + beanFieldName ); |
| |
| // We have to remove the 's' at the end of the field name |
| String attributeName = fieldName.substring( 0, fieldName.length() - 1 ); |
| |
| // Sometime, the plural of a noun takes 'es' |
| if ( !schemaManager.getObjectClassRegistry().contains( attributeName ) ) |
| { |
| // Try by removing 'es' |
| attributeName = fieldName.substring( 0, fieldName.length() - 2 ); |
| |
| if ( !schemaManager.getObjectClassRegistry().contains( attributeName ) ) |
| { |
| String message = "Cannot find the ObjectClass named " + attributeName + " in the schema"; |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| } |
| |
| // This is a multi-valued element, it can be a Set or a List |
| Collection<AdsBaseBean> beans = read( newBase, attributeName, SearchScope.ONELEVEL, mandatory ); |
| |
| if ( ( beans == null ) || ( beans.size() == 0 ) ) |
| { |
| // If the element is mandatory, this is an error |
| if ( mandatory ) |
| { |
| String message = "The composite " + beanAT.getName() |
| + " is mandatory, and was not found under the " |
| + "configuration entry " + entry.getDn(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| } |
| else |
| { |
| // Update the field |
| beanField.set( bean, beans ); |
| } |
| } |
| } |
| else |
| // A standard AttributeType (ie, boolean, long, int or String) |
| { |
| // Process the field accordingly to its cardinality |
| if ( beanAT.isSingleValued() ) |
| { |
| readSingleValueField( bean, beanField, fieldAttr, mandatory ); |
| } |
| else |
| { |
| readMultiValuedField( bean, beanField, fieldAttr, mandatory ); |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| * Get the list of MUST AttributeTypes for an objectClass |
| */ |
| private Set<MutableAttributeTypeImpl> getAllMusts( ObjectClass objectClass ) |
| { |
| Set<MutableAttributeTypeImpl> musts = new HashSet<MutableAttributeTypeImpl>(); |
| |
| // First, gets the direct MUST |
| musts.addAll( objectClass.getMustAttributeTypes() ); |
| |
| // then add all the superiors MUST (recursively) |
| List<ObjectClass> superiors = objectClass.getSuperiors(); |
| |
| if ( superiors != null ) |
| { |
| for ( ObjectClass superior : superiors ) |
| { |
| musts.addAll( getAllMusts( superior ) ); |
| } |
| } |
| |
| return musts; |
| } |
| |
| |
| /** |
| * Get the list of MAY AttributeTypes for an objectClass |
| */ |
| private Set<MutableAttributeTypeImpl> getAllMays( ObjectClass objectClass ) |
| { |
| Set<MutableAttributeTypeImpl> mays = new HashSet<MutableAttributeTypeImpl>(); |
| |
| // First, gets the direct MAY |
| mays.addAll( objectClass.getMayAttributeTypes() ); |
| |
| // then add all the superiors MAY (recursively) |
| List<ObjectClass> superiors = objectClass.getSuperiors(); |
| |
| if ( superiors != null ) |
| { |
| for ( ObjectClass superior : superiors ) |
| { |
| mays.addAll( getAllMays( superior ) ); |
| } |
| } |
| |
| return mays; |
| } |
| |
| |
| /** |
| * Helper method to print a list of AT's names. |
| */ |
| private String dumpATs( Set<MutableAttributeTypeImpl> attributeTypes ) |
| { |
| if ( ( attributeTypes == null ) || ( attributeTypes.size() == 0 ) ) |
| { |
| return ""; |
| } |
| |
| StringBuilder sb = new StringBuilder(); |
| boolean isFirst = true; |
| sb.append( '{' ); |
| |
| for ( MutableAttributeTypeImpl attributeType : attributeTypes ) |
| { |
| if ( isFirst ) |
| { |
| isFirst = false; |
| } |
| else |
| { |
| sb.append( ", " ); |
| } |
| |
| sb.append( attributeType.getName() ); |
| } |
| |
| sb.append( '}' ); |
| |
| return sb.toString(); |
| } |
| |
| |
| /** |
| * Read some configuration element from the DIT using its name |
| */ |
| private List<AdsBaseBean> read( Dn baseDn, String name, SearchScope scope, boolean mandatory ) |
| throws ConfigurationException |
| { |
| LOG.debug( "Reading from '{}', entry {}", baseDn, name ); |
| |
| // Search for the element starting at some point in the DIT |
| // Prepare the search request |
| MutableAttributeTypeImpl adsdAt = schemaManager.getAttributeType( SchemaConstants.OBJECT_CLASS_AT ); |
| EqualityNode<?> filter = new EqualityNode( adsdAt, new StringValue( name ) ); |
| SearchControls controls = new SearchControls(); |
| controls.setSearchScope( scope.ordinal() ); |
| IndexCursor<Long, Entry, Long> cursor = null; |
| |
| // Create a container for all the read beans |
| List<AdsBaseBean> beans = new ArrayList<AdsBaseBean>(); |
| |
| try |
| { |
| // Do the search |
| cursor = se.cursor( baseDn, AliasDerefMode.NEVER_DEREF_ALIASES, filter, controls ); |
| |
| // First, check if we have some entries to process. |
| if ( !cursor.next() ) |
| { |
| if ( mandatory ) |
| { |
| cursor.close(); |
| |
| // the requested element is mandatory so let's throw an exception |
| String message = "No directoryService instance was configured under the Dn " |
| + configPartition.getSuffix(); |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| // Loop on all the found elements |
| do |
| { |
| ForwardIndexEntry<Long, Entry, Long> forwardEntry = ( ForwardIndexEntry<Long, Entry, Long> ) cursor |
| .get(); |
| |
| // Now, get the entry |
| Entry entry = configPartition.lookup( forwardEntry.getId() ); |
| LOG.debug( "Entry read : {}", entry ); |
| |
| // Let's instanciate the bean we need. The upper ObjectClass's name |
| // will be used to do that |
| EntryAttribute objectClassAttr = entry.get( SchemaConstants.OBJECT_CLASS_AT ); |
| |
| ObjectClass objectClass = findObjectClass( objectClassAttr ); |
| AdsBaseBean bean = createBean( objectClass ); |
| |
| // Now, read the AttributeTypes and store the values into the bean fields |
| // The MAY |
| Set<MutableAttributeTypeImpl> mays = getAllMays( objectClass ); |
| LOG.debug( "Fetching the following MAY attributes : {}", dumpATs( mays ) ); |
| readFields( bean, entry, mays, OPTIONNAL ); |
| |
| // The MUST |
| Set<MutableAttributeTypeImpl> musts = getAllMusts( objectClass ); |
| LOG.debug( "Fetching the following MAY attributes : {}", dumpATs( musts ) ); |
| readFields( bean, entry, musts, MANDATORY ); |
| |
| bean.setDn( entry.getDn() ); |
| |
| // Done, we can add the bean into the list |
| beans.add( bean ); |
| } |
| while ( cursor.next() ); |
| } |
| catch ( ConfigurationException ce ) |
| { |
| ce.printStackTrace(); |
| throw ce; |
| } |
| catch ( Exception e ) |
| { |
| String message = "Cannot open a cursor to read the configuration on " + baseDn; |
| LOG.error( message ); |
| throw new ConfigurationException( message ); |
| } |
| finally |
| { |
| if ( cursor != null ) |
| { |
| try |
| { |
| cursor.close(); |
| } |
| catch ( Exception e ) |
| { |
| // So ??? If the cursor can't be close, there is nothing we can do |
| // but rethrow the exception |
| throw new ConfigurationException( e.getMessage(), e.getCause() ); |
| } |
| } |
| } |
| |
| return beans; |
| |
| } |
| |
| |
| /** |
| * Read the configuration from the DIT, returning a bean containing all of it. |
| * <p> |
| * This method implicitly uses <em>"ou=config"</em> as base Dn |
| * |
| * @return The Config bean, containing the whole configuration |
| * @throws ConfigurationException If we had some issue reading the configuration |
| */ |
| public ConfigBean readConfig() throws LdapException |
| { |
| // The starting point is the DirectoryService element |
| return readConfig( new Dn( new Rdn( SchemaConstants.OU_AT, "config" ) ) ); |
| } |
| |
| |
| /** |
| * Read the configuration from the DIT, returning a bean containing all of it. |
| * |
| * @param base The base Dn in the DIT where the configuration is stored |
| * @return The Config bean, containing the whole configuration |
| * @throws ConfigurationException If we had some issue reading the configuration |
| */ |
| public ConfigBean readConfig( String baseDn ) throws LdapException |
| { |
| // The starting point is the DirectoryService element |
| return readConfig( new Dn( baseDn ), ConfigSchemaConstants.ADS_DIRECTORY_SERVICE_OC.getValue() ); |
| } |
| |
| |
| /** |
| * Read the configuration from the DIT, returning a bean containing all of it. |
| * |
| * @param base The base Dn in the DIT where the configuration is stored |
| * @return The Config bean, containing the whole configuration |
| * @throws ConfigurationException If we had some issue reading the configuration |
| */ |
| public ConfigBean readConfig( Dn baseDn ) throws ConfigurationException |
| { |
| // The starting point is the DirectoryService element |
| return readConfig( baseDn, ConfigSchemaConstants.ADS_DIRECTORY_SERVICE_OC.getValue() ); |
| } |
| |
| |
| /** |
| * Read the configuration from the DIT, returning a bean containing all of it. |
| * |
| * @param baseDn The base Dn in the DIT where the configuration is stored |
| * @param objectClass The element to read from the DIT |
| * @return The bean containing the configuration for the required element |
| * @throws ConfigurationException |
| */ |
| public ConfigBean readConfig( String baseDn, String objectClass ) throws LdapException |
| { |
| return readConfig( new Dn( baseDn ), objectClass ); |
| } |
| |
| |
| /** |
| * Read the configuration from the DIT, returning a bean containing all of it. |
| * |
| * @param baseDn The base Dn in the DIT where the configuration is stored |
| * @param objectClass The element to read from the DIT |
| * @return The bean containing the configuration for the required element |
| * @throws ConfigurationException |
| */ |
| public ConfigBean readConfig( Dn baseDn, String objectClass ) throws ConfigurationException |
| { |
| LOG.debug( "Reading configuration for the {} element, from {} ", objectClass, baseDn ); |
| ConfigBean configBean = new ConfigBean(); |
| |
| if ( baseDn == null ) |
| { |
| baseDn = configPartition.getSuffix(); |
| } |
| |
| List<AdsBaseBean> beans = read( baseDn, objectClass, SearchScope.ONELEVEL, MANDATORY ); |
| |
| if ( LOG.isDebugEnabled() ) |
| { |
| if ( ( beans == null ) || ( beans.size() == 0 ) ) |
| { |
| LOG.debug( "No {} element to read", objectClass ); |
| } |
| else |
| { |
| LOG.debug( beans.get( 0 ).toString() ); |
| } |
| } |
| |
| configBean.setDirectoryServiceBeans( beans ); |
| |
| return configBean; |
| } |
| } |