mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Nicolas Capponi
10.43.2013 70b0e3d553e5a2a896337730b6c0540488b78f08
opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -27,20 +27,21 @@
package org.opends.server.admin.client.ldap;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NamingException;
import javax.naming.NoPermissionException;
import javax.naming.OperationNotSupportedException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import java.util.List;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.Entry;
import org.forgerock.opendj.ldap.ErrorResultException;
import org.forgerock.opendj.ldap.LinkedAttribute;
import org.forgerock.opendj.ldap.LinkedHashMapEntry;
import org.forgerock.opendj.ldap.ModificationType;
import org.forgerock.opendj.ldap.RDN;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
import org.forgerock.opendj.ldap.requests.Requests;
import org.opends.server.admin.AggregationPropertyDefinition;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.ConfigurationClient;
@@ -56,8 +57,6 @@
import org.opends.server.admin.RelationDefinition;
import org.opends.server.admin.SetRelationDefinition;
import org.opends.server.admin.UnknownPropertyDefinitionException;
import org.opends.server.admin.client.AuthorizationException;
import org.opends.server.admin.client.CommunicationException;
import org.opends.server.admin.client.ConcurrentModificationException;
import org.opends.server.admin.client.ManagedObject;
import org.opends.server.admin.client.OperationRejectedException;
@@ -67,320 +66,268 @@
import org.opends.server.admin.client.spi.Property;
import org.opends.server.admin.client.spi.PropertySet;
/**
 * A managed object bound to an LDAP connection.
 *
 * @param <T>
 *          The type of client configuration represented by the client
 *          managed object.
 *            The type of client configuration represented by the client managed
 *            object.
 */
final class LDAPManagedObject<T extends ConfigurationClient> extends
    AbstractManagedObject<T> {
final class LDAPManagedObject<T extends ConfigurationClient> extends AbstractManagedObject<T> {
  /**
   * A visitor which is used to encode property LDAP values.
   */
  private static final class ValueEncoder extends
      PropertyValueVisitor<Object, Void> {
    /**
     * A visitor which is used to encode property LDAP values.
     */
    private static final class ValueEncoder extends PropertyValueVisitor<Object, Void> {
    // Prevent instantiation.
    private ValueEncoder() {
      // No implementation required.
        // Prevent instantiation.
        private ValueEncoder() {
            // No implementation required.
        }
        /**
         * {@inheritDoc}
         */
        @Override
        public <C extends ConfigurationClient, S extends Configuration> Object visitAggregation(
                AggregationPropertyDefinition<C, S> pd, String v, Void p) {
            // Aggregations values are stored as full DNs in LDAP, but
            // just their common name is exposed in the admin framework.
            Reference<C, S> reference = Reference.parseName(pd.getParentPath(), pd.getRelationDefinition(), v);
            return reference.toDN().toString();
        }
        /**
         * {@inheritDoc}
         */
        @Override
        public <PD> Object visitUnknown(PropertyDefinition<PD> pd, PD v, Void p)
                throws UnknownPropertyDefinitionException {
            return pd.encodeValue(v);
        }
    }
    // The LDAP management driver associated with this managed object.
    private final LDAPDriver driver;
    /**
     * Creates a new LDAP managed object instance.
     *
     * @param driver
     *            The underlying LDAP management driver.
     * @param d
     *            The managed object's definition.
     * @param path
     *            The managed object's path.
     * @param properties
     *            The managed object's properties.
     * @param existsOnServer
     *            Indicates whether or not the managed object already exists.
     * @param namingPropertyDefinition
     *            The managed object's naming property definition if there is
     *            one.
     */
    LDAPManagedObject(LDAPDriver driver, ManagedObjectDefinition<T, ? extends Configuration> d,
            ManagedObjectPath<T, ? extends Configuration> path, PropertySet properties, boolean existsOnServer,
            PropertyDefinition<?> namingPropertyDefinition) {
        super(d, path, properties, existsOnServer, namingPropertyDefinition);
        this.driver = driver;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public <C extends ConfigurationClient, S extends Configuration>
    Object visitAggregation(
        AggregationPropertyDefinition<C, S> pd, String v, Void p) {
      // Aggregations values are stored as full DNs in LDAP, but
      // just their common name is exposed in the admin framework.
      Reference<C, S> reference = Reference.parseName(pd.getParentPath(), pd
          .getRelationDefinition(), v);
      return reference.toDN().toString();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public <PD> Object visitUnknown(PropertyDefinition<PD> pd, PD v, Void p)
        throws UnknownPropertyDefinitionException {
      return pd.encodeValue(v);
    }
  }
  // The LDAP management driver associated with this managed object.
  private final LDAPDriver driver;
  /**
   * Creates a new LDAP managed object instance.
   *
   * @param driver
   *          The underlying LDAP management driver.
   * @param d
   *          The managed object's definition.
   * @param path
   *          The managed object's path.
   * @param properties
   *          The managed object's properties.
   * @param existsOnServer
   *          Indicates whether or not the managed object already
   *          exists.
   * @param namingPropertyDefinition
   *          The managed object's naming property definition if there
   *          is one.
   */
  LDAPManagedObject(LDAPDriver driver,
      ManagedObjectDefinition<T, ? extends Configuration> d,
      ManagedObjectPath<T, ? extends Configuration> path,
      PropertySet properties, boolean existsOnServer,
      PropertyDefinition<?> namingPropertyDefinition) {
    super(d, path, properties, existsOnServer, namingPropertyDefinition);
    this.driver = driver;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected void addNewManagedObject() throws AuthorizationException,
      CommunicationException, OperationRejectedException,
      ConcurrentModificationException, ManagedObjectAlreadyExistsException {
    // First make sure that the parent managed object still exists.
    ManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
    ManagedObjectPath<?, ?> path = getManagedObjectPath();
    ManagedObjectPath<?, ?> parent = path.parent();
    try {
      if (!driver.managedObjectExists(parent)) {
        throw new ConcurrentModificationException();
      }
    } catch (ManagedObjectNotFoundException e) {
      throw new ConcurrentModificationException();
    }
    // We may need to create the parent "relation" entry if this is a
    // child of an instantiable or set relation.
    RelationDefinition<?, ?> r = path.getRelationDefinition();
    if (r instanceof InstantiableRelationDefinition
        || r instanceof SetRelationDefinition) {
      // TODO: this implementation does not handle relations which
      // comprise of more than one RDN arc (this will probably never
      // be required anyway).
      LdapName dn;
      if (r instanceof InstantiableRelationDefinition) {
        dn = LDAPNameBuilder.create(parent,
            (InstantiableRelationDefinition) r, driver.getLDAPProfile());
      } else {
        dn = LDAPNameBuilder.create(parent,
            (SetRelationDefinition) r, driver.getLDAPProfile());
      }
      if (!driver.entryExists(dn)) {
        // We need to create the entry.
        Attributes attributes = new BasicAttributes();
        // Create the branch's object class attribute.
        Attribute oc = new BasicAttribute("objectClass");
        for (String objectClass : driver.getLDAPProfile()
            .getRelationObjectClasses(r)) {
          oc.add(objectClass);
        }
        attributes.put(oc);
        // Create the branch's naming attribute.
        Rdn rdn = dn.getRdn(dn.size() - 1);
        attributes.put(rdn.getType(), rdn.getValue().toString());
        // Create the entry.
        try {
          driver.getLDAPConnection().createEntry(dn, attributes);
        } catch (OperationNotSupportedException e) {
          // Unwilling to perform.
          if (e.getMessage() == null) {
            throw new OperationRejectedException(OperationType.CREATE, d
                .getUserFriendlyName());
          } else {
            LocalizableMessage m = LocalizableMessage.raw("%s", e.getMessage());
            throw new OperationRejectedException(OperationType.CREATE, d
                .getUserFriendlyName(), m);
          }
        } catch (NamingException e) {
          driver.adaptNamingException(e);
        }
      }
    }
    // Now add the entry representing this new managed object.
    LdapName dn = LDAPNameBuilder.create(path, driver.getLDAPProfile());
    Attributes attributes = new BasicAttributes(true);
    // Create the object class attribute.
    Attribute oc = new BasicAttribute("objectclass");
    ManagedObjectDefinition<?, ?> definition = getManagedObjectDefinition();
    for (String objectClass : driver.getLDAPProfile().getObjectClasses(
        definition)) {
      oc.add(objectClass);
    }
    attributes.put(oc);
    // Create the naming attribute if there is not naming property.
    PropertyDefinition<?> npd = getNamingPropertyDefinition();
    if (npd == null) {
      Rdn rdn = dn.getRdn(dn.size() - 1);
      attributes.put(rdn.getType(), rdn.getValue().toString());
    }
    // Create the remaining attributes.
    for (PropertyDefinition<?> pd : definition.getAllPropertyDefinitions()) {
      String attrID = driver.getLDAPProfile().getAttributeName(definition, pd);
      Attribute attribute = new BasicAttribute(attrID);
      encodeProperty(attribute, pd);
      if (attribute.size() != 0) {
        attributes.put(attribute);
      }
    }
    try {
      // Create the entry.
      driver.getLDAPConnection().createEntry(dn, attributes);
    } catch (NameAlreadyBoundException e) {
      throw new ManagedObjectAlreadyExistsException();
    } catch (OperationNotSupportedException e) {
      // Unwilling to perform.
      if (e.getMessage() == null) {
        throw new OperationRejectedException(OperationType.CREATE, d
            .getUserFriendlyName());
      } else {
        LocalizableMessage m = LocalizableMessage.raw("%s", e.getMessage());
        throw new OperationRejectedException(OperationType.CREATE, d
            .getUserFriendlyName(), m);
      }
    } catch (NamingException e) {
      driver.adaptNamingException(e);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected Driver getDriver() {
    return driver;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected void modifyExistingManagedObject()
      throws ConcurrentModificationException, OperationRejectedException,
      AuthorizationException, CommunicationException {
    // Build the list of modified attributes.
    Attributes mods = new BasicAttributes();
    ManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
      Property<?> p = getProperty(pd);
      if (p.isModified()) {
        String attrID = driver.getLDAPProfile().getAttributeName(d, pd);
        Attribute attribute = new BasicAttribute(attrID);
        encodeProperty(attribute, pd);
        mods.put(attribute);
      }
    }
    // Perform the LDAP modification if something has changed.
    if (mods.size() > 0) {
      try {
    protected void addNewManagedObject() throws ErrorResultException, OperationRejectedException,
            ConcurrentModificationException, ManagedObjectAlreadyExistsException {
        // First make sure that the parent managed object still exists.
        ManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
        ManagedObjectPath<?, ?> path = getManagedObjectPath();
        LdapName dn = LDAPNameBuilder.create(path, driver.getLDAPProfile());
        driver.getLDAPConnection().modifyEntry(dn, mods);
      } catch (NoPermissionException e) {
        throw new AuthorizationException(e);
      } catch (OperationNotSupportedException e) {
        // Unwilling to perform.
        if (e.getMessage() == null) {
          throw new OperationRejectedException(OperationType.MODIFY, d
              .getUserFriendlyName());
        } else {
          LocalizableMessage m = LocalizableMessage.raw("%s", e.getMessage());
          throw new OperationRejectedException(OperationType.MODIFY, d
              .getUserFriendlyName(), m);
        ManagedObjectPath<?, ?> parent = path.parent();
        try {
            if (!driver.managedObjectExists(parent)) {
                throw new ConcurrentModificationException();
            }
        } catch (ManagedObjectNotFoundException e) {
            throw new ConcurrentModificationException();
        }
      } catch (NamingException e) {
        // Just treat it as a communication problem.
        throw new CommunicationException(e);
      }
        // We may need to create the parent "relation" entry if this is a
        // child of an instantiable or set relation.
        RelationDefinition<?, ?> r = path.getRelationDefinition();
        if (r instanceof InstantiableRelationDefinition || r instanceof SetRelationDefinition) {
            // TODO: this implementation does not handle relations which
            // comprise of more than one RDN arc (this will probably never
            // be required anyway).
            DN dn;
            if (r instanceof InstantiableRelationDefinition) {
                dn = LDAPNameBuilder.create(parent, (InstantiableRelationDefinition) r, driver.getLDAPProfile());
            } else {
                dn = LDAPNameBuilder.create(parent, (SetRelationDefinition) r, driver.getLDAPProfile());
            }
            if (!driver.entryExists(dn)) {
                Entry entry = new LinkedHashMapEntry(dn);
                // Create the branch's object class attribute.
                List<String> objectClasses = driver.getLDAPProfile().getRelationObjectClasses(r);
                addObjectClassesToEntry(objectClasses, entry);
                // Create the branch's naming attribute.
                RDN rdn = dn.parent(dn.size() - 1).rdn();
                entry.addAttribute(rdn.getFirstAVA().toAttribute());
                // Create the entry.
                try {
                    driver.getLDAPConnection().createEntry(entry);
                } catch (ErrorResultException e) {
                    if (e.getResult().getResultCode() == ResultCode.UNWILLING_TO_PERFORM) {
                        LocalizableMessage m = LocalizableMessage.raw("%s", e.getLocalizedMessage());
                        throw new OperationRejectedException(OperationType.CREATE, d.getUserFriendlyName(), m);
                    } else {
                        throw e;
                    }
                }
            }
        }
        // Now add the entry representing this new managed object.
        DN dn = LDAPNameBuilder.create(path, driver.getLDAPProfile());
        Entry entry = new LinkedHashMapEntry(dn);
        // Create the object class attribute.
        ManagedObjectDefinition<?, ?> definition = getManagedObjectDefinition();
        List<String> objectClasses = driver.getLDAPProfile().getObjectClasses(definition);
        addObjectClassesToEntry(objectClasses, entry);
        // Create the naming attribute if there is not naming property.
        PropertyDefinition<?> namingPropertyDef = getNamingPropertyDefinition();
        if (namingPropertyDef == null) {
            RDN rdn = dn.parent(dn.size() - 1).rdn();
            entry.addAttribute(rdn.getFirstAVA().toAttribute());
        }
        // Create the remaining attributes.
        for (PropertyDefinition<?> propertyDef : definition.getAllPropertyDefinitions()) {
            String attrID = driver.getLDAPProfile().getAttributeName(definition, propertyDef);
            Attribute attribute = new LinkedAttribute(attrID);
            encodeProperty(attribute, propertyDef);
            if (attribute.size() != 0) {
                entry.addAttribute(attribute);
            }
        }
        try {
            // Create the entry.
            driver.getLDAPConnection().createEntry(entry);
        } catch (ErrorResultException e) {
            if (e.getResult().getResultCode() == ResultCode.ENTRY_ALREADY_EXISTS) {
                throw new ManagedObjectAlreadyExistsException();
            } else if (e.getResult().getResultCode() == ResultCode.UNWILLING_TO_PERFORM) {
                LocalizableMessage m = LocalizableMessage.raw("%s", e.getLocalizedMessage());
                throw new OperationRejectedException(OperationType.CREATE, d.getUserFriendlyName(), m);
            } else {
                throw e;
            }
        }
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected <M extends ConfigurationClient> ManagedObject<M> newInstance(
      ManagedObjectDefinition<M, ?> d, ManagedObjectPath<M, ?> path,
      PropertySet properties, boolean existsOnServer,
      PropertyDefinition<?> namingPropertyDefinition) {
    return new LDAPManagedObject<M>(driver, d, path, properties,
        existsOnServer, namingPropertyDefinition);
  }
  // Encode a property into LDAP string values.
  private <PD> void encodeProperty(Attribute attribute,
      PropertyDefinition<PD> pd) {
    PropertyValueVisitor<Object, Void> visitor = new ValueEncoder();
    Property<PD> p = getProperty(pd);
    if (pd.hasOption(PropertyOption.MANDATORY)) {
      // For mandatory properties we fall-back to the default values
      // if defined which can sometimes be the case e.g when a
      // mandatory property is overridden.
      for (PD value : p.getEffectiveValues()) {
        attribute.add(pd.accept(visitor, value, null));
      }
    } else {
      for (PD value : p.getPendingValues()) {
        attribute.add(pd.accept(visitor, value, null));
      }
    private void addObjectClassesToEntry(List<String> objectClasses, Entry entry) {
        for (String objectClass : objectClasses) {
            Attribute attr = new LinkedAttribute("objectClass");
            attr.add(ByteString.valueOf(objectClass));
            entry.addAttribute(attr);
        }
    }
  }
  /**
   * {@inheritDoc}
   */
  public boolean isModified() {
    ManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
      Property<?> p = getProperty(pd);
      if (p.isModified()) {
        return true;
      }
    /**
     * {@inheritDoc}
     */
    @Override
    protected Driver getDriver() {
        return driver;
    }
    return false;
  }
    /**
     * {@inheritDoc}
     */
    @Override
    protected void modifyExistingManagedObject() throws ConcurrentModificationException, OperationRejectedException,
            ErrorResultException {
        // Build the modify request
        ManagedObjectPath<?, ?> path = getManagedObjectPath();
        DN dn = LDAPNameBuilder.create(path, driver.getLDAPProfile());
        ModifyRequest request = Requests.newModifyRequest(dn);
        ManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
        for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
            Property<?> p = getProperty(pd);
            if (p.isModified()) {
                String attrID = driver.getLDAPProfile().getAttributeName(d, pd);
                Attribute attribute = new LinkedAttribute(attrID);
                encodeProperty(attribute, pd);
                request.addModification(ModificationType.REPLACE, attrID,
                        attribute.toArray(new Object[attribute.size()]));
            }
        }
        // Perform the LDAP modification if something has changed.
        if (!request.getModifications().isEmpty()) {
            try {
                driver.getLDAPConnection().modifyEntry(request);
            } catch (ErrorResultException e) {
                if (e.getResult().getResultCode() == ResultCode.UNWILLING_TO_PERFORM) {
                    LocalizableMessage m = LocalizableMessage.raw("%s", e.getLocalizedMessage());
                    throw new OperationRejectedException(OperationType.CREATE, d.getUserFriendlyName(), m);
                } else {
                    throw e;
                }
            }
        }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected <M extends ConfigurationClient> ManagedObject<M> newInstance(ManagedObjectDefinition<M, ?> d,
            ManagedObjectPath<M, ?> path, PropertySet properties, boolean existsOnServer,
            PropertyDefinition<?> namingPropertyDefinition) {
        return new LDAPManagedObject<M>(driver, d, path, properties, existsOnServer, namingPropertyDefinition);
    }
    // Encode a property into LDAP string values.
    private <PD> void encodeProperty(Attribute attribute, PropertyDefinition<PD> propertyDef) {
        PropertyValueVisitor<Object, Void> visitor = new ValueEncoder();
        Property<PD> property = getProperty(propertyDef);
        if (propertyDef.hasOption(PropertyOption.MANDATORY)) {
            // For mandatory properties we fall-back to the default values
            // if defined which can sometimes be the case e.g when a
            // mandatory property is overridden.
            for (PD value : property.getEffectiveValues()) {
                attribute.add(propertyDef.accept(visitor, value, null));
            }
        } else {
            for (PD value : property.getPendingValues()) {
                attribute.add(propertyDef.accept(visitor, value, null));
            }
        }
    }
    /**
     * {@inheritDoc}
     */
    public boolean isModified() {
        ManagedObjectDefinition<?, ?> d = getManagedObjectDefinition();
        for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
            Property<?> p = getProperty(pd);
            if (p.isModified()) {
                return true;
            }
        }
        return false;
    }
}