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

Nicolas Capponi
27.42.2013 1d62ce980388e01ab7f28e54e7b9e70dcd0bd64f
OpenDJ 3 : config framework

* add admin classes from opendj server, with original package names

132 files added
33894 ■■■■■ changed files
opendj-admin/src/main/java/org/opends/server/admin/ACIPropertyDefinition.java 151 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/AbsoluteInheritedDefaultBehaviorProvider.java 131 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/AbstractManagedObjectDefinition.java 1158 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/AdminException.java 73 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/AdminRuntimeException.java 91 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/AdministrationConnector.java 804 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/AdministrationDataSync.java 353 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/AdministratorAction.java 191 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java 1204 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/AliasDefaultBehaviorProvider.java 115 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/AttributeTypePropertyDefinition.java 215 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/BooleanPropertyDefinition.java 182 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ClassLoaderProvider.java 830 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ClassPropertyDefinition.java 382 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/Configuration.java 55 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ConfigurationClient.java 100 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/Constraint.java 122 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DNPropertyDefinition.java 240 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DecodingException.java 58 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DefaultBehaviorException.java 69 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DefaultBehaviorProvider.java 104 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DefaultBehaviorProviderVisitor.java 116 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DefaultManagedObject.java 200 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DefinedDefaultBehaviorProvider.java 93 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DefinitionDecodingException.java 136 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DefinitionResolver.java 72 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DurationPropertyDefinition.java 609 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/DurationUnit.java 385 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/EnumPropertyDefinition.java 275 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/GenericConstraint.java 223 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/IPAddressMaskPropertyDefinition.java 166 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/IPAddressPropertyDefinition.java 188 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/IllegalPropertyValueException.java 88 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/IllegalPropertyValueStringException.java 89 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/InstantiableRelationDefinition.java 304 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/IntegerPropertyDefinition.java 394 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/LDAPProfile.java 423 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectAlreadyExistsException.java 56 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectDefinition.java 105 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java 346 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectDefinitionResource.java 156 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectNotFoundException.java 67 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectOption.java 49 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectPath.java 1445 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectPathSerializer.java 135 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/OperationsException.java 72 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/OptionalRelationDefinition.java 183 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyDefinition.java 675 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyDefinitionUsageBuilder.java 378 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyDefinitionVisitor.java 297 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyException.java 99 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyIsMandatoryException.java 58 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyIsReadOnlyException.java 58 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyIsSingleValuedException.java 58 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyNotFoundException.java 75 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyOption.java 71 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyProvider.java 89 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/PropertyValueVisitor.java 337 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/Reference.java 245 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/RelationDefinition.java 421 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/RelationDefinitionVisitor.java 130 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/RelationOption.java 49 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/RelativeInheritedDefaultBehaviorProvider.java 150 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/SetRelationDefinition.java 289 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/SingletonRelationDefinition.java 184 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/SizePropertyDefinition.java 410 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/SizeUnit.java 394 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/StringPropertyDefinition.java 335 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/Tag.java 212 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/TopCfgDefn.java 74 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/UndefinedDefaultBehaviorProvider.java 59 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/UnknownPropertyDefinitionException.java 78 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/AdminClientException.java 80 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/AdminSecurityException.java 74 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/AuthenticationException.java 97 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/AuthenticationNotSupportedException.java 99 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/AuthorizationException.java 98 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ClientConstraintHandler.java 165 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/CommunicationException.java 100 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ConcurrentModificationException.java 100 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/IllegalManagedObjectNameException.java 143 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ManagedObject.java 938 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ManagedObjectDecodingException.java 146 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ManagementContext.java 528 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/MissingMandatoryPropertiesException.java 173 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/OperationRejectedException.java 243 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ldap/JNDIDirContextAdaptor.java 337 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPConnection.java 149 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPDriver.java 706 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPManagedObject.java 386 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPManagementContext.java 77 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPNameBuilder.java 246 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/ldap/package-info.java 40 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/package-info.java 39 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/spi/AbstractManagedObject.java 1048 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/spi/Driver.java 809 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/spi/Property.java 140 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/spi/PropertySet.java 371 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/client/spi/package-info.java 39 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/condition/ANDCondition.java 112 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/condition/Condition.java 94 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/condition/Conditions.java 237 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/condition/ContainsCondition.java 214 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/condition/IsPresentCondition.java 104 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/condition/NOTCondition.java 97 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/condition/ORCondition.java 112 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/condition/package-info.java 36 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/doc/ConfigGuideGeneration.java 1627 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/doc/package-info.java 38 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/package-info.java 39 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java 72 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java 281 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java 492 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java 302 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ConfigExceptionFactory.java 148 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationAddListener.java 76 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationChangeListener.java 77 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationDeleteListener.java 76 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ConstraintViolationException.java 179 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/DNBuilder.java 90 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java 191 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ServerConstraintHandler.java 193 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java 1692 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectAddListener.java 78 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectAddListenerAdaptor.java 100 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectChangeListener.java 80 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectChangeListenerAdaptor.java 102 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDecodingException.java 148 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDeleteListener.java 80 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDeleteListenerAdaptor.java 101 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java 986 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/server/package-info.java 41 ●●●●● patch | view | raw | blame | history
opendj-admin/src/main/java/org/opends/server/admin/ACIPropertyDefinition.java
New file
@@ -0,0 +1,151 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.server.authorization.dseecompat.Aci;
import org.opends.server.authorization.dseecompat.AciException;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.types.ByteString;
import static org.opends.server.util.Validator.ensureNotNull;
import java.util.EnumSet;
/**
 * ACI property definition.
 */
public class ACIPropertyDefinition extends PropertyDefinition<Aci> {
  /**
   * An interface for incrementally constructing ACI property
   * definitions.
   */
  public static class Builder extends
      AbstractBuilder<Aci, ACIPropertyDefinition> {
    // Private constructor
    private Builder(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
      super(d, propertyName);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected ACIPropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d,
        String propertyName, EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<Aci> defaultBehavior) {
      return new ACIPropertyDefinition(d, propertyName, options,
          adminAction, defaultBehavior);
    }
  }
  /**
   * Create a ACI property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new ACI property definition builder.
   */
  public static Builder createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder(d, propertyName);
  }
  // Private constructor.
  private ACIPropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<Aci> defaultBehavior) {
    super(d, Aci.class, propertyName, options, adminAction,
        defaultBehavior);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(Aci value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    // No additional validation required.
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public Aci decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    try {
      return Aci.decode(ByteString.valueOf(value), DN.NULL_DN);
    } catch (AciException e) {
      // TODO: it would be nice to throw the cause.
      throw new IllegalPropertyValueStringException(this, value);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitACI(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, Aci value, P p) {
    return v.visitACI(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int compare(Aci o1, Aci o2) {
    return o1.toString().compareTo(o2.toString());
  }
}
opendj-admin/src/main/java/org/opends/server/admin/AbsoluteInheritedDefaultBehaviorProvider.java
New file
@@ -0,0 +1,131 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * A default behavior provider which retrieves default values from a
 * managed object in an absolute location. It should be used by
 * properties which inherit their default value(s) from properties
 * held in an other managed object.
 *
 * @param <T>
 *          The type of values represented by this provider.
 */
public final class AbsoluteInheritedDefaultBehaviorProvider<T> extends
    DefaultBehaviorProvider<T> {
  // The absolute path to the managed object containing the property.
  private ManagedObjectPath<?, ?> path = null;
  // The string representation of the managed object path specifying
  // the absolute location of the managed object.
  private final String pathString;
  // The name of the property containing the inherited default values.
  private final String propertyName;
  /**
   * Create an absolute inherited default behavior provider associated
   * with the managed object at the specified absolute location.
   *
   * @param pathString
   *          The string representation of the managed object path
   *          specifying the absolute location of the managed object.
   * @param propertyName
   *          The name of the property containing the inherited
   *          default values.
   */
  public AbsoluteInheritedDefaultBehaviorProvider(String pathString,
      String propertyName) {
    this.pathString = pathString;
    this.propertyName = propertyName;
  }
  /**
   * {@inheritDoc}
   */
  public <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p) {
    return v.visitAbsoluteInherited(this, p);
  }
  /**
   * Get the definition of the parent managed object containing the
   * inherited default values.
   *
   * @return Returns the definition of the parent managed object
   *         containing the inherited default values.
   */
  public AbstractManagedObjectDefinition<?, ?> getManagedObjectDefinition() {
    return path.getManagedObjectDefinition();
  }
  /**
   * Get the absolute path of the managed object containing the
   * property which has the default values.
   *
   * @return Returns the absolute path of the managed object
   *         containing the property which has the default values.
   */
  public ManagedObjectPath<?, ?> getManagedObjectPath() {
    return path;
  }
  /**
   * Gets the name of the property containing the inherited default
   * values.
   *
   * @return Returns the name of the property containing the inherited
   *         default values.
   */
  public String getPropertyName() {
    return propertyName;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected void initialize() throws Exception {
    // Decode the path.
    path = ManagedObjectPath.valueOf(pathString);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/AbstractManagedObjectDefinition.java
New file
@@ -0,0 +1,1158 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2007-2010 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Set;
import java.util.Vector;
import org.forgerock.i18n.LocalizableMessage;
import org.opends.server.admin.DefinitionDecodingException.Reason;
/**
 * Defines the structure of an abstract managed object. Abstract managed objects
 * cannot be instantiated.
 * <p>
 * Applications can query a managed object definition in order to determine the
 * overall configuration model of an application.
 *
 * @param <C>
 *          The type of client managed object configuration that this definition
 *          represents.
 * @param <S>
 *          The type of server managed object configuration that this definition
 *          represents.
 */
public abstract class AbstractManagedObjectDefinition
    <C extends ConfigurationClient, S extends Configuration> {
  // The name of the definition.
  private final String name;
  // The parent managed object definition if applicable.
  private final AbstractManagedObjectDefinition<? super C, ? super S> parent;
  // The set of constraints associated with this managed object
  // definition.
  private final Collection<Constraint> constraints;
  // The set of property definitions applicable to this managed object
  // definition.
  private final Map<String, PropertyDefinition<?>> propertyDefinitions;
  // The set of relation definitions applicable to this managed object
  // definition.
  private final Map<String, RelationDefinition<?, ?>> relationDefinitions;
  // The set of relation definitions directly referencing this managed
  // object definition.
  private final Set<RelationDefinition<C, S>> reverseRelationDefinitions;
  // The set of all property definitions associated with this managed
  // object definition including inherited property definitions.
  private final Map<String, PropertyDefinition<?>> allPropertyDefinitions;
  // The set of all relation definitions associated with this managed
  // object definition including inherited relation definitions.
  private final Map<String, RelationDefinition<?, ?>> allRelationDefinitions;
  // The set of aggregation property definitions applicable to this
  // managed object definition.
  private final Map<String, AggregationPropertyDefinition<?, ?>>
    aggregationPropertyDefinitions;
  // The set of aggregation property definitions directly referencing this
  // managed object definition.
  private final Vector<AggregationPropertyDefinition<?, ?>>
    reverseAggregationPropertyDefinitions;
  // The set of all aggregation property definitions associated with this
  // managed object definition including inherited relation definitions.
  private final Map<String, AggregationPropertyDefinition<?, ?>>
    allAggregationPropertyDefinitions;
  // The set of tags associated with this managed object.
  private final Set<Tag> allTags;
  // Options applicable to this definition.
  private final Set<ManagedObjectOption> options;
  // The set of managed object definitions which inherit from this definition.
  private final Map<String,
    AbstractManagedObjectDefinition<? extends C, ? extends S>> children;
  /**
   * Create a new abstract managed object definition.
   *
   * @param name
   *          The name of the definition.
   * @param parent
   *          The parent definition, or <code>null</code> if there
   *          is no parent (only the {@link TopCfgDefn} should have a
   *          <code>null</code> parent, unless the definition is
   *          being used for testing).
   */
  protected AbstractManagedObjectDefinition(String name,
      AbstractManagedObjectDefinition<? super C, ? super S> parent) {
    this.name = name;
    this.parent = parent;
    this.constraints = new LinkedList<Constraint>();
    this.propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
    this.relationDefinitions = new HashMap<String, RelationDefinition<?,?>>();
    this.reverseRelationDefinitions = new HashSet<RelationDefinition<C,S>>();
    this.allPropertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
    this.allRelationDefinitions =
      new HashMap<String, RelationDefinition<?, ?>>();
    this.aggregationPropertyDefinitions =
      new HashMap<String, AggregationPropertyDefinition<?,?>>();
    this.reverseAggregationPropertyDefinitions =
      new Vector<AggregationPropertyDefinition<?,?>>();
    this.allAggregationPropertyDefinitions =
      new HashMap<String, AggregationPropertyDefinition<?, ?>>();
    this.allTags = new HashSet<Tag>();
    this.options = EnumSet.noneOf(ManagedObjectOption.class);
    this.children = new HashMap<String,
        AbstractManagedObjectDefinition<? extends C, ? extends S>>();
    // If we have a parent definition then inherit its features.
    if (parent != null) {
      registerInParent();
      for (PropertyDefinition<?> pd : parent.getAllPropertyDefinitions()) {
        allPropertyDefinitions.put(pd.getName(), pd);
      }
      for (RelationDefinition<?, ?> rd : parent.getAllRelationDefinitions()) {
        allRelationDefinitions.put(rd.getName(), rd);
      }
      for (AggregationPropertyDefinition<?, ?> apd :
        parent.getAllAggregationPropertyDefinitions()) {
        allAggregationPropertyDefinitions.put(apd.getName(), apd);
      }
      // Tag inheritance is performed during preprocessing.
    }
  }
  /**
   * Get all the child managed object definitions which inherit from
   * this managed object definition.
   *
   * @return Returns an unmodifiable collection containing all the
   *         subordinate managed object definitions which inherit from
   *         this managed object definition.
   */
  public final Collection<AbstractManagedObjectDefinition
      <? extends C, ? extends S>> getAllChildren() {
    List<AbstractManagedObjectDefinition<? extends C, ? extends S>> list =
      new ArrayList<AbstractManagedObjectDefinition<? extends C, ? extends S>>(
        children.values());
    for (AbstractManagedObjectDefinition<? extends C, ? extends S> child :
        children.values()) {
      list.addAll(child.getAllChildren());
    }
    return Collections.unmodifiableCollection(list);
  }
  /**
   * Get all the constraints associated with this type of managed
   * object. The returned collection will contain inherited
   * constraints.
   *
   * @return Returns a collection containing all the constraints
   *         associated with this type of managed object. The caller
   *         is free to modify the collection if required.
   */
  public final Collection<Constraint> getAllConstraints() {
    // This method does not used a cached set of constraints because
    // constraints may be updated after child definitions have been
    // defined.
    List<Constraint> allConstraints = new LinkedList<Constraint>();
    if (parent != null) {
      allConstraints.addAll(parent.getAllConstraints());
    }
    allConstraints.addAll(constraints);
    return allConstraints;
  }
  /**
   * Get all the property definitions associated with this type of
   * managed object. The returned collection will contain inherited
   * property definitions.
   *
   * @return Returns an unmodifiable collection containing all the
   *         property definitions associated with this type of managed
   *         object.
   */
  public final Collection<PropertyDefinition<?>> getAllPropertyDefinitions() {
    return Collections.unmodifiableCollection(allPropertyDefinitions.values());
  }
  /**
   * Get all the relation definitions associated with this type of
   * managed object. The returned collection will contain inherited
   * relation definitions.
   *
   * @return Returns an unmodifiable collection containing all the
   *         relation definitions associated with this type of managed
   *         object.
   */
  public final Collection<RelationDefinition<?, ?>>
      getAllRelationDefinitions() {
    return Collections.unmodifiableCollection(allRelationDefinitions.values());
  }
  /**
   * Get all the relation definitions which refer to this managed
   * object definition. The returned collection will contain relation
   * definitions which refer to parents of this managed object
   * definition.
   *
   * @return Returns a collection containing all the relation
   *         definitions which refer to this managed object
   *         definition. The caller is free to modify the collection
   *         if required.
   */
  public final Collection<RelationDefinition<? super C, ? super S>>
  getAllReverseRelationDefinitions() {
    // This method does not used a cached set of relations because
    // relations may be updated after child definitions have been
    // defined.
    List<RelationDefinition<? super C, ? super S>> rdlist =
      new LinkedList<RelationDefinition<? super C, ? super S>>();
    if (parent != null) {
      rdlist.addAll(parent.getAllReverseRelationDefinitions());
    }
    rdlist.addAll(reverseRelationDefinitions);
    return rdlist;
  }
  /**
   * Get all the aggregation property definitions associated with this type of
   * managed object. The returned collection will contain inherited
   * aggregation property definitions.
   *
   * @return Returns an unmodifiable collection containing all the
   *         aggregation property definitions associated with this type of
   *         managed object.
   */
  public final Collection<AggregationPropertyDefinition<?, ?>>
      getAllAggregationPropertyDefinitions() {
    return Collections.unmodifiableCollection(
      allAggregationPropertyDefinitions.values());
  }
  /**
   * Get all the aggregation property definitions which refer to this managed
   * object definition. The returned collection will contain aggregation
   * property definitions which refer to parents of this managed object
   * definition.
   *
   * @return Returns a collection containing all the aggregation property
   *         definitions which refer to this managed object
   *         definition. The caller is free to modify the collection
   *         if required.
   */
  public final Collection<AggregationPropertyDefinition<?, ?>>
  getAllReverseAggregationPropertyDefinitions() {
    // This method does not used a cached set of aggregation properties because
    // aggregation properties may be updated after child definitions have been
    // defined.
    List<AggregationPropertyDefinition<?, ?>> apdlist =
      new LinkedList<AggregationPropertyDefinition<?, ?>>();
    if (parent != null) {
      apdlist.addAll(parent.getAllReverseAggregationPropertyDefinitions());
    }
    apdlist.addAll(reverseAggregationPropertyDefinitions);
    return apdlist;
  }
  /**
   * Get all the tags associated with this type of managed object. The
   * returned collection will contain inherited tags.
   *
   * @return Returns an unmodifiable collection containing all the
   *         tags associated with this type of managed object.
   */
  public final Collection<Tag> getAllTags() {
    return Collections.unmodifiableCollection(allTags);
  }
  /**
   * Get the named child managed object definition which inherits from
   * this managed object definition. This method will recursively
   * search down through the inheritance hierarchy.
   *
   * @param name
   *          The name of the managed object definition sub-type.
   * @return Returns the named child managed object definition which
   *         inherits from this managed object definition.
   * @throws IllegalArgumentException
   *           If the specified managed object definition name was
   *           null or empty or if the requested subordinate managed
   *           object definition was not found.
   */
  public final AbstractManagedObjectDefinition<? extends C, ? extends S>
      getChild(String name) throws IllegalArgumentException {
    if ((name == null) || (name.length() == 0)) {
      throw new IllegalArgumentException("null or empty managed object name");
    }
    AbstractManagedObjectDefinition<? extends C, ? extends S> d = children
        .get(name);
    if (d == null) {
      // Recursively search.
      for (AbstractManagedObjectDefinition<? extends C, ? extends S> child :
          children.values()) {
        try {
          d = child.getChild(name);
          break;
        } catch (IllegalArgumentException e) {
          // Try the next child.
        }
      }
    }
    if (d == null) {
      throw new IllegalArgumentException("child managed object definition \""
          + name + "\" not found");
    }
    return d;
  }
  /**
   * Get the child managed object definitions which inherit directly
   * from this managed object definition.
   *
   * @return Returns an unmodifiable collection containing the
   *         subordinate managed object definitions which inherit
   *         directly from this managed object definition.
   */
  public final Collection<AbstractManagedObjectDefinition
      <? extends C, ? extends S>> getChildren() {
    return Collections.unmodifiableCollection(children.values());
  }
  /**
   * Get the constraints defined by this managed object definition.
   * The returned collection will not contain inherited constraints.
   *
   * @return Returns an unmodifiable collection containing the
   *         constraints defined by this managed object definition.
   */
  public final Collection<Constraint> getConstraints() {
    return Collections.unmodifiableCollection(constraints);
  }
  /**
   * Gets the optional description of this managed object definition
   * in the default locale.
   *
   * @return Returns the description of this managed object definition
   *         in the default locale, or <code>null</code> if there is
   *         no description.
   * @throws UnsupportedOperationException
   *           If this managed object definition is the
   *           {@link TopCfgDefn}.
   */
  public final Message getDescription() throws UnsupportedOperationException {
    return getDescription(Locale.getDefault());
  }
  /**
   * Gets the optional description of this managed object definition
   * in the specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the description of this managed object definition
   *         in the specified locale, or <code>null</code> if there
   *         is no description.
   * @throws UnsupportedOperationException
   *           If this managed object definition is the
   *           {@link TopCfgDefn}.
   */
  public final Message getDescription(Locale locale)
      throws UnsupportedOperationException {
    try {
      return ManagedObjectDefinitionI18NResource.getInstance()
        .getMessage(this, "description", locale);
    } catch (MissingResourceException e) {
      return null;
    }
  }
  /**
   * Get the name of the definition.
   *
   * @return Returns the name of the definition.
   */
  public final String getName() {
    return name;
  }
  /**
   * Get the parent managed object definition, if applicable.
   *
   * @return Returns the parent of this managed object definition, or
   *         <code>null</code> if this definition is the
   *         {@link TopCfgDefn}.
   */
  public final AbstractManagedObjectDefinition<? super C,
      ? super S> getParent() {
    return parent;
  }
  /**
   * Get the specified property definition associated with this type
   * of managed object. The search will include any inherited property
   * definitions.
   *
   * @param name
   *          The name of the property definition to be retrieved.
   * @return Returns the specified property definition associated with
   *         this type of managed object.
   * @throws IllegalArgumentException
   *           If the specified property name was null or empty or if
   *           the requested property definition was not found.
   */
  public final PropertyDefinition<?> getPropertyDefinition(String name)
      throws IllegalArgumentException {
    if ((name == null) || (name.length() == 0)) {
      throw new IllegalArgumentException("null or empty property name");
    }
    PropertyDefinition<?> d = allPropertyDefinitions.get(name);
    if (d == null) {
      throw new IllegalArgumentException("property definition \"" + name
          + "\" not found");
    }
    return d;
  }
  /**
   * Get the property definitions defined by this managed object
   * definition. The returned collection will not contain inherited
   * property definitions.
   *
   * @return Returns an unmodifiable collection containing the
   *         property definitions defined by this managed object
   *         definition.
   */
  public final Collection<PropertyDefinition<?>> getPropertyDefinitions() {
    return Collections.unmodifiableCollection(propertyDefinitions
        .values());
  }
  /**
   * Get the specified relation definition associated with this type
   * of managed object.The search will include any inherited relation
   * definitions.
   *
   * @param name
   *          The name of the relation definition to be retrieved.
   * @return Returns the specified relation definition associated with
   *         this type of managed object.
   * @throws IllegalArgumentException
   *           If the specified relation name was null or empty or if
   *           the requested relation definition was not found.
   */
  public final RelationDefinition<?, ?> getRelationDefinition(String name)
      throws IllegalArgumentException {
    if ((name == null) || (name.length() == 0)) {
      throw new IllegalArgumentException("null or empty relation name");
    }
    RelationDefinition<?, ?> d = allRelationDefinitions.get(name);
    if (d == null) {
      throw new IllegalArgumentException("relation definition \"" + name
          + "\" not found");
    }
    return d;
  }
  /**
   * Get the relation definitions defined by this managed object
   * definition. The returned collection will not contain inherited
   * relation definitions.
   *
   * @return Returns an unmodifiable collection containing the
   *         relation definitions defined by this managed object
   *         definition.
   */
  public final Collection<RelationDefinition<?,?>> getRelationDefinitions() {
    return Collections.unmodifiableCollection(relationDefinitions.values());
  }
  /**
   * Get the relation definitions which refer directly to this managed
   * object definition. The returned collection will not contain
   * relation definitions which refer to parents of this managed
   * object definition.
   *
   * @return Returns an unmodifiable collection containing the
   *         relation definitions which refer directly to this managed
   *         object definition.
   */
  public final Collection<RelationDefinition<C, S>>
      getReverseRelationDefinitions() {
    return Collections.unmodifiableCollection(reverseRelationDefinitions);
  }
  /**
   * Get the specified aggregation property definition associated with this type
   * of managed object.The search will include any inherited aggregation
   * property definitions.
   *
   * @param name
   *          The name of the aggregation property definition to be retrieved.
   * @return Returns the specified aggregation property definition associated
   *         with this type of managed object.
   * @throws IllegalArgumentException
   *           If the specified aggregation property name was null or empty or
   *           if the requested aggregation property definition was not found.
   */
  public final AggregationPropertyDefinition<?, ?>
    getAggregationPropertyDefinition(String name)
    throws IllegalArgumentException {
    if ((name == null) || (name.length() == 0)) {
      throw new IllegalArgumentException(
        "null or empty aggregation property name");
    }
    AggregationPropertyDefinition<?, ?> d =
      allAggregationPropertyDefinitions.get(name);
    if (d == null) {
      throw new IllegalArgumentException("aggregation property definition \""
        + name + "\" not found");
    }
    return d;
  }
  /**
   * Get the aggregation property definitions defined by this managed object
   * definition. The returned collection will not contain inherited
   * aggregation property definitions.
   *
   * @return Returns an unmodifiable collection containing the
   *         aggregation property definitions defined by this managed object
   *         definition.
   */
  public final Collection<AggregationPropertyDefinition<?, ?>>
    getAggregationPropertyDefinitions() {
    return Collections.unmodifiableCollection(
      aggregationPropertyDefinitions.values());
  }
  /**
   * Get the aggregation property definitions which refer directly to this
   * managed object definition. The returned collection will not contain
   * aggregation property definitions which refer to parents of this managed
   * object definition.
   *
   * @return Returns an unmodifiable collection containing the
   *         aggregation property definitions which refer directly to this
   *         managed object definition.
   */
  public final Collection<AggregationPropertyDefinition<?, ?>>
    getReverseAggregationPropertyDefinitions() {
    return Collections.unmodifiableCollection(
      reverseAggregationPropertyDefinitions);
  }
  /**
   * Gets the synopsis of this managed object definition in the
   * default locale.
   *
   * @return Returns the synopsis of this managed object definition in
   *         the default locale.
   * @throws UnsupportedOperationException
   *           If this managed object definition is the
   *           {@link TopCfgDefn}.
   */
  public final Message getSynopsis() throws UnsupportedOperationException {
    return getSynopsis(Locale.getDefault());
  }
  /**
   * Gets the synopsis of this managed object definition in the
   * specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the synopsis of this managed object definition in
   *         the specified locale.
   * @throws UnsupportedOperationException
   *           If this managed object definition is the
   *           {@link TopCfgDefn}.
   */
  public final Message getSynopsis(Locale locale)
      throws UnsupportedOperationException {
    return ManagedObjectDefinitionI18NResource.getInstance()
        .getMessage(this, "synopsis", locale);
  }
  /**
   * Gets the user friendly name of this managed object definition in
   * the default locale.
   *
   * @return Returns the user friendly name of this managed object
   *         definition in the default locale.
   * @throws UnsupportedOperationException
   *           If this managed object definition is the
   *           {@link TopCfgDefn}.
   */
  public final Message getUserFriendlyName()
      throws UnsupportedOperationException {
    return getUserFriendlyName(Locale.getDefault());
  }
  /**
   * Gets the user friendly name of this managed object definition in
   * the specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the user friendly name of this managed object
   *         definition in the specified locale.
   * @throws UnsupportedOperationException
   *           If this managed object definition is the
   *           {@link TopCfgDefn}.
   */
  public final Message getUserFriendlyName(Locale locale)
      throws UnsupportedOperationException {
    // TODO: have admin framework getMessage return a Message
    return Message.raw(ManagedObjectDefinitionI18NResource.getInstance()
        .getMessage(this, "user-friendly-name", locale));
  }
  /**
   * Gets the user friendly plural name of this managed object
   * definition in the default locale.
   *
   * @return Returns the user friendly plural name of this managed
   *         object definition in the default locale.
   * @throws UnsupportedOperationException
   *           If this managed object definition is the
   *           {@link TopCfgDefn}.
   */
  public final Message getUserFriendlyPluralName()
      throws UnsupportedOperationException {
    return getUserFriendlyPluralName(Locale.getDefault());
  }
  /**
   * Gets the user friendly plural name of this managed object
   * definition in the specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the user friendly plural name of this managed
   *         object definition in the specified locale.
   * @throws UnsupportedOperationException
   *           If this managed object definition is the
   *           {@link TopCfgDefn}.
   */
  public final Message getUserFriendlyPluralName(Locale locale)
      throws UnsupportedOperationException {
    return ManagedObjectDefinitionI18NResource.getInstance()
        .getMessage(this, "user-friendly-plural-name", locale);
  }
  /**
   * Determine whether there are any child managed object definitions which
   * inherit from this managed object definition.
   *
   * @return Returns <code>true</code> if this type of managed object has any
   *         child managed object definitions, <code>false</code> otherwise.
   */
  public final boolean hasChildren() {
    return !children.isEmpty();
  }
  /**
   * Determines whether or not this managed object definition has the
   * specified option.
   *
   * @param option
   *          The option to test.
   * @return Returns <code>true</code> if the option is set, or
   *         <code>false</code> otherwise.
   */
  public final boolean hasOption(ManagedObjectOption option) {
    return options.contains(option);
  }
  /**
   * Determines whether or not this managed object definition has the
   * specified tag.
   *
   * @param t
   *          The tag definition.
   * @return Returns <code>true</code> if this managed object
   *         definition has the specified tag.
   */
  public final boolean hasTag(Tag t) {
    return allTags.contains(t);
  }
  /**
   * Determines whether or not this managed object definition is a
   * sub-type of the provided managed object definition. This managed
   * object definition is a sub-type of the provided managed object
   * definition if they are both the same or if the provided managed
   * object definition can be obtained by recursive invocations of the
   * {@link #getParent()} method.
   *
   * @param d
   *          The managed object definition to be checked.
   * @return Returns <code>true</code> if this managed object
   *         definition is a sub-type of the provided managed object
   *         definition.
   */
  public final boolean isChildOf(AbstractManagedObjectDefinition<?, ?> d) {
    AbstractManagedObjectDefinition<?, ?> i;
    for (i = this; i != null; i = i.parent) {
      if (i == d) {
        return true;
      }
    }
    return false;
  }
  /**
   * Determines whether or not this managed object definition is a
   * super-type of the provided managed object definition. This
   * managed object definition is a super-type of the provided managed
   * object definition if they are both the same or if the provided
   * managed object definition is a member of the set of children
   * returned from {@link #getAllChildren()}.
   *
   * @param d
   *          The managed object definition to be checked.
   * @return Returns <code>true</code> if this managed object
   *         definition is a super-type of the provided managed object
   *         definition.
   */
  public final boolean isParentOf(AbstractManagedObjectDefinition<?, ?> d) {
    return d.isChildOf(this);
  }
  /**
   * Determines whether or not this managed object definition is the
   * {@link TopCfgDefn}.
   *
   * @return Returns <code>true</code> if this managed object
   *         definition is the {@link TopCfgDefn}.
   */
  public final boolean isTop() {
    return (this instanceof TopCfgDefn);
  }
  /**
   * Finds a sub-type of this managed object definition which most closely
   * corresponds to the matching criteria of the provided definition resolver.
   *
   * @param r
   *          The definition resolver.
   * @return Returns the sub-type of this managed object definition which most
   *         closely corresponds to the matching criteria of the provided
   *         definition resolver.
   * @throws DefinitionDecodingException
   *           If no matching sub-type could be found or if the resolved
   *           definition was abstract.
   * @see DefinitionResolver
   */
  @SuppressWarnings("unchecked")
  public final ManagedObjectDefinition<? extends C, ? extends S>
      resolveManagedObjectDefinition(
      DefinitionResolver r) throws DefinitionDecodingException {
    AbstractManagedObjectDefinition<? extends C, ? extends S> rd;
    rd = resolveManagedObjectDefinitionAux(this, r);
    if (rd == null) {
      // Unable to resolve the definition.
      throw new DefinitionDecodingException(this,
          Reason.WRONG_TYPE_INFORMATION);
    } else if (rd instanceof ManagedObjectDefinition) {
      return (ManagedObjectDefinition<? extends C, ? extends S>) rd;
    } else {
      // Resolved definition was abstract.
      throw new DefinitionDecodingException(this,
          Reason.ABSTRACT_TYPE_INFORMATION);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public final String toString() {
    StringBuilder builder = new StringBuilder();
    toString(builder);
    return builder.toString();
  }
  /**
   * Append a string representation of the managed object definition to the
   * provided string builder.
   *
   * @param builder
   *          The string builder where the string representation should be
   *          appended.
   */
  public final void toString(StringBuilder builder) {
    builder.append(getName());
  }
  /**
   * Initializes all of the components associated with this managed
   * object definition.
   *
   * @throws Exception
   *           If this managed object definition could not be
   *           initialized.
   */
  protected final void initialize() throws Exception {
    for (PropertyDefinition<?> pd : getAllPropertyDefinitions()) {
      pd.initialize();
      pd.getDefaultBehaviorProvider().initialize();
    }
    for (RelationDefinition<?, ?> rd : getAllRelationDefinitions()) {
      rd.initialize();
    }
    for (AggregationPropertyDefinition<?, ?> apd :
      getAllAggregationPropertyDefinitions()) {
      apd.initialize();
      // Now register the aggregation property in the referenced managed object
      // definition for reverse lookups.
      registerReverseAggregationPropertyDefinition(apd);
    }
    for (Constraint constraint : getAllConstraints()) {
      constraint.initialize();
    }
  }
  /**
   * Register a constraint with this managed object definition.
   * <p>
   * This method <b>must not</b> be called by applications.
   *
   * @param constraint
   *          The constraint to be registered.
   */
  protected final void registerConstraint(Constraint constraint) {
    constraints.add(constraint);
  }
  /**
   * Register a property definition with this managed object definition,
   * overriding any existing property definition with the same name.
   * <p>
   * This method <b>must not</b> be called by applications.
   *
   * @param d
   *          The property definition to be registered.
   */
  protected final void registerPropertyDefinition(PropertyDefinition<?> d) {
    String propName = d.getName();
    propertyDefinitions.put(propName, d);
    allPropertyDefinitions.put(propName, d);
    if (d instanceof AggregationPropertyDefinition<?,?>) {
      AggregationPropertyDefinition<?, ?> apd =
        (AggregationPropertyDefinition<?, ?>) d;
      aggregationPropertyDefinitions.put(propName, apd);
      // The key must also contain the managed object name, since several MOs
      // in an inheritance tree may aggregate the same aggregation property name
      allAggregationPropertyDefinitions.put(
        apd.getManagedObjectDefinition().getName() + ":" + propName, apd);
    }
  }
  /**
   * Register a relation definition with this managed object definition,
   * overriding any existing relation definition with the same name.
   * <p>
   * This method <b>must not</b> be called by applications.
   *
   * @param d
   *          The relation definition to be registered.
   */
  protected final void registerRelationDefinition(RelationDefinition<?, ?> d) {
    // Register the relation in this managed object definition.
    String relName = d.getName();
    relationDefinitions.put(relName, d);
    allRelationDefinitions.put(relName, d);
    // Now register the relation in the referenced managed object
    // definition for reverse lookups.
    registerReverseRelationDefinition(d);
  }
  /**
   * Register an option with this managed object definition.
   * <p>
   * This method <b>must not</b> be called by applications.
   *
   * @param option
   *          The option to be registered.
   */
  protected final void registerOption(ManagedObjectOption option) {
    options.add(option);
  }
  /**
   * Register a tag with this managed object definition.
   * <p>
   * This method <b>must not</b> be called by applications.
   *
   * @param tag
   *          The tag to be registered.
   */
  protected final void registerTag(Tag tag) {
    allTags.add(tag);
  }
  /**
   * Deregister a constraint from the managed object definition.
   * <p>
   * This method <b>must not</b> be called by applications and is
   * only intended for internal testing.
   *
   * @param constraint
   *          The constraint to be deregistered.
   */
  final void deregisterConstraint(Constraint constraint) {
    if (!constraints.remove(constraint)) {
      throw new RuntimeException("Failed to deregister a constraint");
    }
  }
  /**
   * Deregister a relation definition from the managed object
   * definition.
   * <p>
   * This method <b>must not</b> be called by applications and is
   * only intended for internal testing.
   *
   * @param d
   *          The relation definition to be deregistered.
   */
  final void deregisterRelationDefinition(
      RelationDefinition<?, ?> d) {
   // Deregister the relation from this managed object definition.
    String relName = d.getName();
    relationDefinitions.remove(relName);
    allRelationDefinitions.remove(relName);
    // Now deregister the relation from the referenced managed object
    // definition for reverse lookups.
    d.getChildDefinition().reverseRelationDefinitions.remove(d);
  }
  /**
   * Register this managed object definition in its parent.
   * <p>
   * This method <b>must not</b> be called by applications and is
   * only intended for internal testing.
   */
  final void registerInParent() {
    if (parent != null) {
      parent.children.put(name, this);
    }
  }
  // Register a relation definition in the referenced managed object
  // definition's reverse lookup table.
  private <CC extends ConfigurationClient, SS extends Configuration>
  void registerReverseRelationDefinition(RelationDefinition<CC, SS> rd) {
    rd.getChildDefinition().reverseRelationDefinitions.add(rd);
  }
  // Register a aggregation property definition in the referenced managed object
  // definition's reverse lookup table.
  private void registerReverseAggregationPropertyDefinition(
    AggregationPropertyDefinition<?, ?> apd) {
    apd.getRelationDefinition().getChildDefinition().
      reverseAggregationPropertyDefinitions.add(apd);
  }
  // Recursively descend definition hierarchy to find the best match definition.
  private AbstractManagedObjectDefinition<? extends C, ? extends S>
      resolveManagedObjectDefinitionAux(
      AbstractManagedObjectDefinition<? extends C, ? extends S> d,
      DefinitionResolver r) {
    if (!r.matches(d)) {
      return null;
    }
    for (AbstractManagedObjectDefinition<? extends C, ? extends S> child : d
        .getChildren()) {
      AbstractManagedObjectDefinition<? extends C, ? extends S> rd =
        resolveManagedObjectDefinitionAux(child, r);
      if (rd != null) {
        return rd;
      }
    }
    return d;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/AdminException.java
New file
@@ -0,0 +1,73 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import org.opends.server.types.OpenDsException;
/**
 * Exceptions thrown when interacting with administration framework.
 */
public abstract class AdminException extends OpenDsException {
  /**
   * Fake serialization ID.
   */
  private static final long serialVersionUID = 1L;
  /**
   * Create an admin exception with a message and cause.
   *
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  protected AdminException(Message message, Throwable cause) {
    super(message, cause);
  }
  /**
   * Create an admin exception with a message.
   *
   * @param message
   *          The message.
   */
  protected AdminException(Message message) {
    super(message);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/AdminRuntimeException.java
New file
@@ -0,0 +1,91 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
/**
 * Exceptions thrown when interacting with administration framework
 * that applications are not expected to catch.
 */
public abstract class AdminRuntimeException extends RuntimeException {
  /**
   * Fake serialization ID.
   */
  private static final long serialVersionUID = 1L;
  // Message that explains the problem.
  private final Message message;
  /**
   * Create an admin runtime exception with a message and cause.
   *
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  protected AdminRuntimeException(Message message, Throwable cause) {
    super(message.toString(), cause);
    this.message = message;
  }
  /**
   * Create an admin runtime exception with a message.
   *
   * @param message
   *          The message.
   */
  protected AdminRuntimeException(Message message) {
    super(message.toString());
    this.message = message;
  }
  /**
   * Returns the message that explains the problem that occurred.
   *
   * @return Returns the message describing the problem that occurred
   *         (never <code>null</code>).
   */
  public Message getMessageObject() {
    return this.message;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/AdministrationConnector.java
New file
@@ -0,0 +1,804 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2010 Sun Microsystems, Inc.
 *      Portions copyright 2011-2013 ForgeRock AS
 */
package org.opends.server.admin;
import static org.opends.server.loggers.ErrorLogger.logError;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.messages.AdminMessages.*;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.naming.ldap.Rdn;
import org.opends.messages.Message;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.server.ServerManagementContext;
import org.opends.server.admin.std.meta.LDAPConnectionHandlerCfgDefn.
  SSLClientAuthPolicy;
import org.opends.server.admin.std.server.AdministrationConnectorCfg;
import org.opends.server.admin.std.server.ConnectionHandlerCfg;
import org.opends.server.admin.std.server.KeyManagerProviderCfg;
import org.opends.server.admin.std.server.FileBasedKeyManagerProviderCfg;
import org.opends.server.admin.std.server.FileBasedTrustManagerProviderCfg;
import org.opends.server.admin.std.server.LDAPConnectionHandlerCfg;
import org.opends.server.admin.std.server.RootCfg;
import org.opends.server.config.ConfigException;
import org.opends.server.core.SynchronousStrategy;
import org.opends.server.protocols.ldap.LDAPConnectionHandler;
import org.opends.server.types.AddressMask;
import org.opends.server.types.ConfigChangeResult;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.types.InitializationException;
import org.opends.server.types.ResultCode;
import org.opends.server.util.CertificateManager;
import org.opends.server.util.SetupUtils;
import org.opends.server.admin.std.server.TrustManagerProviderCfg;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.ErrorLogger;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.FilePermission;
/**
 * This class is a wrapper on top of LDAPConnectionHandler to manage
 * the administration connector, which is an LDAPConnectionHandler
 * with specific (limited) configuration properties.
 */
public final class AdministrationConnector implements
    ConfigurationChangeListener<AdministrationConnectorCfg>
{
  /**
   * Default Administration Connector port.
   */
  public static final int DEFAULT_ADMINISTRATION_CONNECTOR_PORT = 4444;
  /**
   * Validity (in days) of the generated certificate.
   */
  public static final int ADMIN_CERT_VALIDITY = 20 * 365;
  // Friendly name of the administration connector
  private static final String FRIENDLY_NAME = "Administration Connector";
  // The tracer object for the debug logger.
  private static final DebugTracer TRACER = getTracer();
  private LDAPConnectionHandler adminConnectionHandler;
  private AdministrationConnectorCfg config; //
  // Predefined values for Administration Connector configuration
  //
  private static final String ADMIN_CLASS_NAME =
    "org.opends.server.protocols.ldap.LDAPConnectionHandler";
  private static final boolean ADMIN_ALLOW_LDAP_V2 = false;
  private static final boolean ADMIN_ALLOW_START_TLS = false;
  private static final SortedSet<AddressMask> ADMIN_ALLOWED_CLIENT =
    new TreeSet<AddressMask>();
  private static final SortedSet<AddressMask> ADMIN_DENIED_CLIENT =
    new TreeSet<AddressMask>();
  private static final boolean ADMIN_ENABLED = true;
  private static final boolean ADMIN_KEEP_STATS = true;
  private static final boolean ADMIN_USE_SSL = true;
  private static final int ADMIN_ACCEPT_BACKLOG = 128;
  private static final boolean ADMIN_ALLOW_TCP_REUSE_ADDRESS = true;
  private static final long ADMIN_MAX_BLOCKED_WRITE_TIME_LIMIT = 120000; // 2mn
  private static final int ADMIN_MAX_REQUEST_SIZE = 5000000; // 5 Mb
  private static final int ADMIN_WRITE_BUFFER_SIZE = 4096;
  private static final int ADMIN_NUM_REQUEST_HANDLERS = 1;
  private static final boolean ADMIN_SEND_REJECTION_NOTICE = true;
  private static final boolean ADMIN_USE_TCP_KEEP_ALIVE = true;
  private static final boolean ADMIN_USE_TCP_NO_DELAY = true;
  private static final SSLClientAuthPolicy ADMIN_SSL_CLIENT_AUTH_POLICY =
    SSLClientAuthPolicy.DISABLED;
  private static final SortedSet<String> ADMIN_SSL_CIPHER_SUITE =
    new TreeSet<String>();
  private static final SortedSet<String> ADMIN_SSL_PROTOCOL =
    new TreeSet<String>();
  /**
   * Initializes this administration connector provider based on the
   * information in the provided administration connector
   * configuration.
   *
   * @param configuration
   *          The connection handler configuration that contains the
   *          information to use to initialize this connection
   *          handler.
   * @throws ConfigException
   *           If an unrecoverable problem arises in the process of
   *           performing the initialization as a result of the server
   *           configuration.
   * @throws InitializationException
   *           If a problem occurs during initialization that is not
   *           related to the server configuration.
   */
  public void initializeAdministrationConnector(
      AdministrationConnectorCfg configuration) throws ConfigException,
      InitializationException
  {
    this.config = configuration;
    // Create a fake LDAP connection handler configuration
    LDAPConnectionHandlerCfg ldapConnectionHandlerCfg =
      new FakeLDAPConnectionHandlerCfg(config);
    // Administration Connector uses the LDAP connection handler
    // implementation
    adminConnectionHandler = new LDAPConnectionHandler(
        new SynchronousStrategy(), FRIENDLY_NAME);
    adminConnectionHandler
        .initializeConnectionHandler(ldapConnectionHandlerCfg);
    adminConnectionHandler.setAdminConnectionHandler();
    // Register this as a change listener.
    config.addChangeListener(this);
  }
  /**
   * Create an instance of the administration connector.
   */
  public AdministrationConnector()
  {
    // Do nothing.
  }
  /**
   * Retrieves the connection handler linked to this administration
   * connector.
   *
   * @return The connection handler linked to this administration
   *         connector.
   */
  public LDAPConnectionHandler getConnectionHandler()
  {
    return adminConnectionHandler;
  }
  /**
   * {@inheritDoc}
   */
  public boolean isConfigurationChangeAcceptable(
      AdministrationConnectorCfg configuration,
      List<Message> unacceptableReasons)
  {
    LDAPConnectionHandlerCfg cfg = new FakeLDAPConnectionHandlerCfg(
        configuration);
    return adminConnectionHandler.isConfigurationAcceptable(cfg,
        unacceptableReasons);
  }
  /**
   * {@inheritDoc}
   */
  public ConfigChangeResult applyConfigurationChange(
      AdministrationConnectorCfg configuration)
  {
    return new ConfigChangeResult(ResultCode.SUCCESS, true,
        new ArrayList<Message>());
  }
  /**
   * This private class implements a fake LDAP connection Handler
   * configuration. This allows to re-use the LDAPConnectionHandler as
   * it is.
   */
  private static class FakeLDAPConnectionHandlerCfg implements
      LDAPConnectionHandlerCfg
  {
    private final AdministrationConnectorCfg config;
    public FakeLDAPConnectionHandlerCfg(AdministrationConnectorCfg config)
    {
      this.config = config;
    }
    /**
     * {@inheritDoc}
     */
    public Class<? extends LDAPConnectionHandlerCfg> configurationClass()
    {
      return LDAPConnectionHandlerCfg.class;
    }
    /**
     * {@inheritDoc}
     */
    public void addLDAPChangeListener(
        ConfigurationChangeListener<LDAPConnectionHandlerCfg> listener)
    {
      // do nothing. change listener already added.
    }
    /**
     * {@inheritDoc}
     */
    public void removeLDAPChangeListener(
        ConfigurationChangeListener<LDAPConnectionHandlerCfg> listener)
    {
      // do nothing. change listener already added.
    }
    /**
     * {@inheritDoc}
     */
    public int getAcceptBacklog()
    {
      return ADMIN_ACCEPT_BACKLOG;
    }
    /**
     * {@inheritDoc}
     */
    public boolean isAllowLDAPV2()
    {
      return ADMIN_ALLOW_LDAP_V2;
    }
    /**
     * {@inheritDoc}
     */
    public boolean isAllowStartTLS()
    {
      return ADMIN_ALLOW_START_TLS;
    }
    /**
     * {@inheritDoc}
     */
    public boolean isAllowTCPReuseAddress()
    {
      return ADMIN_ALLOW_TCP_REUSE_ADDRESS;
    }
    /**
     * {@inheritDoc}
     */
    public String getJavaClass()
    {
      return ADMIN_CLASS_NAME;
    }
    /**
     * {@inheritDoc}
     */
    public boolean isKeepStats()
    {
      return ADMIN_KEEP_STATS;
    }
    /**
     * {@inheritDoc}
     */
    public String getKeyManagerProvider()
    {
      return config.getKeyManagerProvider();
    }
    /**
     * {@inheritDoc}
     */
    public DN getKeyManagerProviderDN()
    {
      return config.getKeyManagerProviderDN();
    }
    /**
     * {@inheritDoc}
     */
    public SortedSet<InetAddress> getListenAddress()
    {
      return config.getListenAddress();
    }
    /**
     * {@inheritDoc}
     */
    public int getListenPort()
    {
      return config.getListenPort();
    }
    /**
     * {@inheritDoc}
     */
    public long getMaxBlockedWriteTimeLimit()
    {
      return ADMIN_MAX_BLOCKED_WRITE_TIME_LIMIT;
    }
    /**
     * {@inheritDoc}
     */
    public long getMaxRequestSize()
    {
      return ADMIN_MAX_REQUEST_SIZE;
    }
    /**
     * {@inheritDoc}
     */
    public long getBufferSize()
    {
      return ADMIN_WRITE_BUFFER_SIZE;
    }
    /**
     * {@inheritDoc}
     */
    public Integer getNumRequestHandlers()
    {
      return ADMIN_NUM_REQUEST_HANDLERS;
    }
    /**
     * {@inheritDoc}
     */
    public boolean isSendRejectionNotice()
    {
      return ADMIN_SEND_REJECTION_NOTICE;
    }
    /**
     * {@inheritDoc}
     */
    public String getSSLCertNickname()
    {
      return config.getSSLCertNickname();
    }
    /**
     * {@inheritDoc}
     */
    public SortedSet<String> getSSLCipherSuite()
    {
      return config.getSSLCipherSuite();
    }
    /**
     * {@inheritDoc}
     */
    public SSLClientAuthPolicy getSSLClientAuthPolicy()
    {
      return ADMIN_SSL_CLIENT_AUTH_POLICY;
    }
    /**
     * {@inheritDoc}
     */
    public SortedSet<String> getSSLProtocol()
    {
      return config.getSSLProtocol();
    }
    /**
     * {@inheritDoc}
     */
    public String getTrustManagerProvider()
    {
      return config.getTrustManagerProvider();
    }
    /**
     * {@inheritDoc}
     */
    public DN getTrustManagerProviderDN()
    {
      return config.getTrustManagerProviderDN();
    }
    /**
     * {@inheritDoc}
     */
    public boolean isUseSSL()
    {
      return ADMIN_USE_SSL;
    }
    /**
     * {@inheritDoc}
     */
    public boolean isUseTCPKeepAlive()
    {
      return ADMIN_USE_TCP_KEEP_ALIVE;
    }
    /**
     * {@inheritDoc}
     */
    public boolean isUseTCPNoDelay()
    {
      return ADMIN_USE_TCP_NO_DELAY;
    }
    /**
     * {@inheritDoc}
     */
    public void addChangeListener(
        ConfigurationChangeListener<ConnectionHandlerCfg> listener)
    {
      // do nothing. change listener already added.
    }
    /**
     * {@inheritDoc}
     */
    public void removeChangeListener(
        ConfigurationChangeListener<ConnectionHandlerCfg> listener)
    {
      // do nothing. change listener already added.
    }
    /**
     * {@inheritDoc}
     */
    public SortedSet<AddressMask> getAllowedClient()
    {
      return ADMIN_ALLOWED_CLIENT;
    }
    /**
     * {@inheritDoc}
     */
    public SortedSet<AddressMask> getDeniedClient()
    {
      return ADMIN_DENIED_CLIENT;
    }
    /**
     * {@inheritDoc}
     */
    public boolean isEnabled()
    {
      return ADMIN_ENABLED;
    }
    /**
     * {@inheritDoc}
     */
    public DN dn()
    {
      return config.dn();
    }
  }
  /**
   * Creates a self-signed JKS certificate if needed.
   *
   * @throws InitializationException
   *           If an unexpected error occurred whilst trying to create the
   *           certificate.
   */
  public static void createSelfSignedCertificateIfNeeded()
      throws InitializationException
  {
    try
    {
      RootCfg root = ServerManagementContext.getInstance()
          .getRootConfiguration();
      AdministrationConnectorCfg config = root.getAdministrationConnector();
      // Check if certificate generation is needed
      String certAlias = config.getSSLCertNickname();
      KeyManagerProviderCfg keyMgrConfig = root.getKeyManagerProvider(config
          .getKeyManagerProvider());
      TrustManagerProviderCfg trustMgrConfig = root
          .getTrustManagerProvider(config.getTrustManagerProvider());
      if (hasDefaultConfigChanged(keyMgrConfig, trustMgrConfig))
      {
        // nothing to do
        return;
      }
      FileBasedKeyManagerProviderCfg fbKeyManagerConfig =
        (FileBasedKeyManagerProviderCfg) keyMgrConfig;
      String keystorePath = getFullPath(fbKeyManagerConfig.getKeyStoreFile());
      FileBasedTrustManagerProviderCfg fbTrustManagerConfig =
        (FileBasedTrustManagerProviderCfg) trustMgrConfig;
      String truststorePath = getFullPath(fbTrustManagerConfig
          .getTrustStoreFile());
      String pinFilePath = getFullPath(fbKeyManagerConfig.getKeyStorePinFile());
      // Check that either we do not have any file,
      // or we have the 3 required files (keystore, truststore, pin
      // file)
      boolean keystore = false;
      boolean truststore = false;
      boolean pinFile = false;
      int nbFiles = 0;
      if (new File(keystorePath).exists())
      {
        keystore = true;
        nbFiles++;
      }
      if (new File(truststorePath).exists())
      {
        truststore = true;
        nbFiles++;
      }
      if (new File(pinFilePath).exists())
      {
        pinFile = true;
        nbFiles++;
      }
      if (nbFiles == 3)
      {
        // nothing to do
        return;
      }
      if (nbFiles != 0)
      {
        // 1 or 2 files are missing : error
        String err = "";
        if (!keystore)
        {
          err += keystorePath + " ";
        }
        if (!truststore)
        {
          err += truststorePath + " ";
        }
        if (!pinFile)
        {
          err += pinFilePath + " ";
        }
        Message message = ERR_ADMIN_CERTIFICATE_GENERATION_MISSING_FILES
            .get(err);
        logError(message);
        throw new InitializationException(message);
      }
      // Generate a password
      String pwd = new String(SetupUtils.createSelfSignedCertificatePwd());
      // Generate a self-signed certificate
      CertificateManager certManager = new CertificateManager(
          getFullPath(fbKeyManagerConfig.getKeyStoreFile()), fbKeyManagerConfig
              .getKeyStoreType(), pwd);
      String hostName =
        SetupUtils.getHostNameForCertificate(DirectoryServer.getServerRoot());
      String subjectDN = "cn="
          + Rdn.escapeValue(hostName) + ",O="
          + FRIENDLY_NAME + " Self-Signed Certificate";
      certManager.generateSelfSignedCertificate(certAlias, subjectDN,
          ADMIN_CERT_VALIDITY);
      // Export the certificate
      String tempCertPath = getFullPath("config" + File.separator
          + "admin-cert.txt");
      SetupUtils.exportCertificate(certManager, certAlias, tempCertPath);
      // Create a new trust store and import the server certificate
      // into it
      CertificateManager trustManager = new CertificateManager(truststorePath,
          CertificateManager.KEY_STORE_TYPE_JKS, pwd);
      trustManager.addCertificate(certAlias, new File(tempCertPath));
      // Generate a password file
      if (!new File(pinFilePath).exists())
      {
        FileWriter file = new FileWriter(pinFilePath);
        PrintWriter out = new PrintWriter(file);
        out.println(pwd);
        out.flush();
        out.close();
        file.close();
      }
      // Change the password file permission if possible
      if (FilePermission.canSetPermissions())
      {
        try
        {
          if (!FilePermission.setPermissions(new File(pinFilePath),
              new FilePermission(0600)))
          {
            // Log a warning that the permissions were not set.
            Message message = WARN_ADMIN_SET_PERMISSIONS_FAILED
                .get(pinFilePath);
            ErrorLogger.logError(message);
          }
        }
        catch (DirectoryException e)
        {
          // Log a warning that the permissions were not set.
          Message message = WARN_ADMIN_SET_PERMISSIONS_FAILED.get(pinFilePath);
          ErrorLogger.logError(message);
        }
      }
      // Delete the exported certificate
      File f = new File(tempCertPath);
      f.delete();
    }
    catch (InitializationException e)
    {
      throw e;
    }
    catch (Exception e)
    {
      if (debugEnabled())
      {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_ADMIN_CERTIFICATE_GENERATION.get(e.getMessage());
      logError(message);
      throw new InitializationException(message);
    }
  }
  /**
   * Check if default configuration for administrator's key manager and trust
   * manager provider has changed.
   *
   * @param keyConfig
   *          key manager provider configuration
   * @param trustConfig
   *          trust manager provider configuration
   * @return true if default configuration has changed, false otherwise
   */
  private static boolean hasDefaultConfigChanged(
      KeyManagerProviderCfg keyConfig, TrustManagerProviderCfg trustConfig)
  {
    if (keyConfig.isEnabled()
        && (keyConfig instanceof FileBasedKeyManagerProviderCfg)
        && trustConfig.isEnabled()
        && (trustConfig instanceof FileBasedTrustManagerProviderCfg))
    {
      FileBasedKeyManagerProviderCfg fileKeyConfig =
          (FileBasedKeyManagerProviderCfg) keyConfig;
      boolean pinIsProvidedByFileOnly =
          (fileKeyConfig.getKeyStorePinFile() != null)
              && (fileKeyConfig.getKeyStorePin() == null)
              && (fileKeyConfig.getKeyStorePinEnvironmentVariable() == null)
              && (fileKeyConfig.getKeyStorePinProperty() == null);
      return !pinIsProvidedByFileOnly;
    }
    return true;
  }
  private static String getFullPath(String path)
  {
    File file = new File(path);
    if (!file.isAbsolute())
    {
      path = DirectoryServer.getInstanceRoot() + File.separator + path;
    }
    return path;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/AdministrationDataSync.java
New file
@@ -0,0 +1,353 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2006-2008 Sun Microsystems, Inc.
 *      Portions Copyright 2012 ForgeRock AS
 */
package org.opends.server.admin;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import org.opends.server.core.DirectoryServer;
import org.opends.server.protocols.internal.InternalClientConnection;
import org.opends.server.protocols.internal.InternalSearchOperation;
import org.opends.server.protocols.ldap.LDAPFilter;
import org.opends.server.schema.DirectoryStringSyntax;
import org.opends.server.types.Attribute;
import org.opends.server.types.AttributeType;
import org.opends.server.types.Attributes;
import org.opends.server.types.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.types.DereferencePolicy;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.Entry;
import org.opends.server.types.LDAPException;
import org.opends.server.types.Modification;
import org.opends.server.types.ModificationType;
import org.opends.server.types.ResultCode;
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchScope;
/**
 * Check if information found in "cn=admin data" is coherent with
 * cn=config. If and inconsistency is detected, we log a warning
 * message and update "cn=admin data"
 */
public final class AdministrationDataSync
{
  /**
   * The root connection.
   */
  private InternalClientConnection internalConnection;
  /**
   * The attribute name used to store the port. TODO Use the default
   * one.
   */
  private static final String LDAP_PORT = "ds-cfg-listen-port";
  /**
   * Create an object that will syncrhonize configuration and the
   * admin data.
   *
   * @param internalConnection
   *          The root connection.
   */
  public AdministrationDataSync(InternalClientConnection internalConnection)
  {
    this.internalConnection = internalConnection;
  }
  /**
   * Check if information found in "cn=admin data" is coherent with
   * cn=config. If and inconsistancy is detected, we log a warning
   * message and update "cn=admin data"
   */
  public void synchronize()
  {
    // Check if the admin connector is in sync
    checkAdminConnector();
  }
  /**
   * Check if the admin connector is in sync. The desynchronization
   * could occurs after the upgrade from 1.0.
   */
  private void checkAdminConnector()
  {
    // Look for the server registration in "cn=admin data"
    DN serverEntryDN = searchServerEntry();
    if (serverEntryDN == null)
    {
      // Nothing to do
      return;
    }
    // Get the admin port
    String adminPort = getAttr("cn=Administration Connector,cn=config",
        LDAP_PORT);
    if (adminPort == null)
    {
      // best effort.
      return;
    }
    LinkedList<Modification> mods = new LinkedList<Modification>();
    // adminport
    String attName = "adminport";
    AttributeType attrType = DirectoryServer.getAttributeType(attName
        .toLowerCase());
    if (attrType == null)
    {
      attrType = DirectoryServer.getDefaultAttributeType(attName.toLowerCase());
    }
    mods.add(new Modification(ModificationType.REPLACE, Attributes.create(
        attrType, adminPort)));
    // adminEnabled
    attName = "adminEnabled";
    attrType = DirectoryServer.getAttributeType(attName.toLowerCase());
    if (attrType == null)
    {
      attrType = DirectoryServer.getDefaultAttributeType(attName.toLowerCase());
    }
    mods.add(new Modification(ModificationType.REPLACE, Attributes.create(
        attrType, "true")));
    // Process modification
    internalConnection.processModify(serverEntryDN, mods);
  }
  /**
   * Look for the DN of the local register server. Assumption: default
   * Connection Handler naming is used.
   *
   * @return The DN of the local register server or null.
   */
  private DN searchServerEntry()
  {
    DN returnDN = null;
    // Get the LDAP and LDAPS port
    String ldapPort = getAttr(
        "cn=LDAP Connection Handler,cn=Connection Handlers,cn=config",
        LDAP_PORT);
    String ldapsPort = getAttr(
        "cn=LDAPS Connection Handler,cn=Connection Handlers,cn=config",
        LDAP_PORT);
    boolean ldapsPortEnable = false;
    String val = getAttr(
        "cn=LDAPS Connection Handler,cn=Connection Handlers,cn=config",
        "ds-cfg-enabled");
    if (val != null)
    {
      ldapsPortEnable = val.toLowerCase().equals("true");
    }
    if ((ldapPort == null) && (ldapsPort == null))
    {
      // best effort (see assumption)
      return null;
    }
    // Get the IP address of the local host.
    String hostName;
    try
    {
      hostName = java.net.InetAddress.getLocalHost().getCanonicalHostName();
    }
    catch (Throwable t)
    {
      // best effort.
      return null;
    }
    // Look for a local server with the Ldap Port.
    String attrName = "hostname";
    AttributeType hostnameType = DirectoryServer.getAttributeType(attrName);
    if (hostnameType == null)
    {
      hostnameType = DirectoryServer.getDefaultAttributeType(attrName);
    }
    try
    {
      InternalSearchOperation op = internalConnection.processSearch(
          "cn=Servers,cn=admin data",
          SearchScope.SINGLE_LEVEL, "objectclass=*");
      if (op.getResultCode() == ResultCode.SUCCESS)
      {
        Entry entry = null;
        for (Entry currentEntry : op.getSearchEntries())
        {
          String currentHostname = currentEntry.getAttributeValue(hostnameType,
              DirectoryStringSyntax.DECODER);
          try
          {
            String currentIPAddress = java.net.InetAddress.getByName(
                currentHostname).getCanonicalHostName();
            if (currentIPAddress.equals(hostName))
            {
              // Check if one of the port match
              attrName = "ldapport";
              AttributeType portType = DirectoryServer
                  .getAttributeType(attrName);
              if (portType == null)
              {
                portType = DirectoryServer.getDefaultAttributeType(attrName);
              }
              String currentport = currentEntry.getAttributeValue(portType,
                  DirectoryStringSyntax.DECODER);
              if (currentport.equals(ldapPort))
              {
                entry = currentEntry;
                break;
              }
              if (ldapsPortEnable)
              {
                attrName = "ldapsport";
                portType = DirectoryServer.getAttributeType(attrName);
                if (portType == null)
                {
                  portType = DirectoryServer.getDefaultAttributeType(attrName);
                }
                currentport = currentEntry.getAttributeValue(portType,
                    DirectoryStringSyntax.DECODER);
                if (currentport.equals(ldapsPort))
                {
                  entry = currentEntry;
                  break;
                }
              }
            }
          }
          catch (Exception e)
          {
            // best effort.
            continue;
          }
        }
        if (entry != null)
        {
          returnDN = entry.getDN();
        }
      }
    }
    catch (DirectoryException e)
    {
      // never happens because the filter is always valid.
      return null;
    }
    return returnDN;
  }
  /**
   * Gets an attribute value from an entry.
   *
   * @param DN
   *          The DN of the entry.
   * @param attrName
   *          The attribute name.
   * @return The attribute value or {@code null} if the value could
   *         not be retrieved.
   */
  private String getAttr(String baseDN, String attrName)
  {
    // Prepare the ldap search
    LDAPFilter filter;
    try
    {
      filter = LDAPFilter.decode("objectclass=*");
    }
    catch (LDAPException e)
    {
      // can not happen
      // best effort.
      // TODO Log an Error.
      return null;
    }
    LinkedHashSet<String> attributes = new LinkedHashSet<String>(1);
    attributes.add(attrName);
    InternalSearchOperation search = internalConnection.processSearch(
        ByteString.valueOf(baseDN), SearchScope.BASE_OBJECT,
        DereferencePolicy.DEREF_ALWAYS, 0, 0, false, filter, attributes);
    if ((search.getResultCode() != ResultCode.SUCCESS))
    {
      // can not happen
      // best effort.
      // TODO Log an Error.
      return null;
    }
    SearchResultEntry adminConnectorEntry = null;
    /*
     * Read the port from the PORT attribute
     */
    LinkedList<SearchResultEntry> result = search.getSearchEntries();
    if (!result.isEmpty())
    {
      adminConnectorEntry = result.getFirst();
    }
    AttributeType attrType = DirectoryServer.getAttributeType(attrName);
    if (attrType == null)
    {
      attrType = DirectoryServer.getDefaultAttributeType(attrName);
    }
    List<Attribute> attrs = adminConnectorEntry.getAttribute(attrType);
    if (attrs == null)
    {
      // can not happen
      // best effort.
      // TODO Log an Error.
      return null;
    }
    // Get the attribute value
    return attrs.get(0).iterator().next().toString();
  }
}
opendj-admin/src/main/java/org/opends/server/admin/AdministratorAction.java
New file
@@ -0,0 +1,191 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import java.util.Locale;
import java.util.MissingResourceException;
/**
 * Defines an optional action which administators must perform after
 * they have modified a property. By default modifications to
 * properties are assumed to take effect immediately and require no
 * additional administrative action. Developers should be aware that,
 * where feasible, they should implement components such that property
 * modifications require no additional administrative action. This is
 * required in order to minimize server downtime during administration
 * and provide a more user-friendly experience.
 */
public final class AdministratorAction {
  /**
   * Specifies the type of administrator action which must be
   * performed in order for pending changes to take effect.
   */
  public static enum Type {
    /**
     * Used when modifications to a property require a component
     * restart in order to take effect (usually by disabling and
     * re-enabling the component). May have a description describing
     * any additional administrator action that is required when the
     * component is restarted.
     */
    COMPONENT_RESTART("component-restart"),
    /**
     * Used when modifications to a property take effect immediately,
     * and no additional administrator action is required. May have a
     * description describing how changes to the modified property
     * will take effect.
     */
    NONE("none"),
    /**
     * Used when modifications to a property require an additional
     * administrative action in order to take effect. This should be
     * used when neither a server restart nor a component restart are
     * applicable. Always has a description which describes the
     * additional administrator action which is required when the
     * property is modified.
     */
    OTHER("other"),
    /**
     * Used when modifications to a property require a server restart
     * in order to take effect. May have a description describing any
     * additional administrator action that is required when the
     * component is restarted.
     */
    SERVER_RESTART("server-restart");
    // The user-friendly name of the type.
    private final String name;
    // Private constructor.
    private Type(String name) {
      this.name = name;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
      return name;
    }
  }
  // The managed object definition associated with this administrator
  // action.
  private final AbstractManagedObjectDefinition<?, ?> definition;
  // The name of the property definition associated with this
  // administrator action.
  private final String propertyName;
  // The type of administration action.
  private final Type type;
  /**
   * Create a new administrator action.
   *
   * @param type
   *          The type of this administration action.
   * @param d
   *          The managed object definition associated with this
   *          administrator action.
   * @param propertyName
   *          The name of the property definition associated with this
   *          administrator action.
   */
  public AdministratorAction(Type type,
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    this.type = type;
    this.definition = d;
    this.propertyName = propertyName;
  }
  /**
   * Gets the synopsis of this administrator action in the default
   * locale.
   *
   * @return Returns the synopsis of this administrator action in the
   *         default locale, or <code>null</code> if there is no
   *         synopsis defined.
   */
  public final Message getSynopsis() {
    return getSynopsis(Locale.getDefault());
  }
  /**
   * Gets the synopsis of this administrator action in the specified
   * locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the synopsis of this administrator action in the
   *         specified locale, or <code>null</code> if there is no
   *         synopsis defined.
   */
  public final Message getSynopsis(Locale locale) {
    ManagedObjectDefinitionI18NResource resource =
      ManagedObjectDefinitionI18NResource.getInstance();
    String property = "property." + propertyName
        + ".requires-admin-action.synopsis";
    try {
      return resource.getMessage(definition, property, locale);
    } catch (MissingResourceException e) {
      return null;
    }
  }
  /**
   * Gets the type of this administrator action.
   *
   * @return Returns the type of this administrator action.
   */
  public final Type getType() {
    return type;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/AggregationPropertyDefinition.java
New file
@@ -0,0 +1,1204 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2007-2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.Validator.*;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.SortedSet;
import org.opends.messages.Message;
import org.opends.server.admin.client.AuthorizationException;
import org.opends.server.admin.client.ClientConstraintHandler;
import org.opends.server.admin.client.CommunicationException;
import org.opends.server.admin.client.ManagedObject;
import org.opends.server.admin.client.ManagedObjectDecodingException;
import org.opends.server.admin.client.ManagementContext;
import org.opends.server.admin.condition.Condition;
import org.opends.server.admin.condition.Conditions;
import org.opends.server.admin.server.ConfigurationDeleteListener;
import org.opends.server.admin.server.ServerConstraintHandler;
import org.opends.server.admin.server.ServerManagedObject;
import org.opends.server.admin.server.ServerManagedObjectChangeListener;
import org.opends.server.admin.server.ServerManagementContext;
import org.opends.server.admin.std.meta.RootCfgDefn;
import org.opends.server.config.ConfigException;
import org.opends.server.loggers.ErrorLogger;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.ConfigChangeResult;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.ResultCode;
import org.opends.server.util.StaticUtils;
/**
 * Aggregation property definition.
 * <p>
 * An aggregation property names one or more managed objects which are
 * required by the managed object associated with this property. An
 * aggregation property definition takes care to perform referential
 * integrity checks: referenced managed objects cannot be deleted. Nor
 * can an aggregation reference non-existent managed objects.
 * Referential integrity checks are <b>not</b> performed during value
 * validation. Instead they are performed when changes to the managed
 * object are committed.
 * <p>
 * An aggregation property definition can optionally identify two
 * properties:
 * <ul>
 * <li>an <code>enabled</code> property in the aggregated managed
 * object - the property must be a {@link BooleanPropertyDefinition}
 * and indicate whether the aggregated managed object is enabled or
 * not. If specified, the administration framework will prevent the
 * aggregated managed object from being disabled while it is
 * referenced
 * <li>an <code>enabled</code> property in this property's managed
 * object - the property must be a {@link BooleanPropertyDefinition}
 * and indicate whether this property's managed object is enabled or
 * not. If specified, and as long as there is an equivalent
 * <code>enabled</code> property defined for the aggregated managed
 * object, the <code>enabled</code> property in the aggregated
 * managed object will only be checked when this property is true.
 * </ul>
 * In other words, these properties can be used to make sure that
 * referenced managed objects are not disabled while they are
 * referenced.
 *
 * @param <C>
 *          The type of client managed object configuration that this
 *          aggregation property definition refers to.
 * @param <S>
 *          The type of server managed object configuration that this
 *          aggregation property definition refers to.
 */
public final class AggregationPropertyDefinition
    <C extends ConfigurationClient, S extends Configuration>
    extends PropertyDefinition<String> {
  /**
   * An interface for incrementally constructing aggregation property
   * definitions.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this aggregation property definition refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this aggregation property definition refers to.
   */
  public static class Builder
      <C extends ConfigurationClient, S extends Configuration>
      extends AbstractBuilder<String, AggregationPropertyDefinition<C, S>> {
    // The string representation of the managed object path specifying
    // the parent of the aggregated managed objects.
    private String parentPathString = null;
    // The name of a relation in the parent managed object which
    // contains the aggregated managed objects.
    private String rdName = null;
    // The condition which is used to determine if a referenced
    // managed object is enabled.
    private Condition targetIsEnabledCondition = Conditions.TRUE;
    // The condition which is used to determine whether or not
    // referenced managed objects need to be enabled.
    private Condition targetNeedsEnablingCondition = Conditions.TRUE;
    // Private constructor
    private Builder(AbstractManagedObjectDefinition<?, ?> d,
        String propertyName) {
      super(d, propertyName);
    }
    /**
     * Sets the name of the managed object which is the parent of the
     * aggregated managed objects.
     * <p>
     * This must be defined before the property definition can be
     * built.
     *
     * @param pathString
     *          The string representation of the managed object path
     *          specifying the parent of the aggregated managed
     *          objects.
     */
    public final void setParentPath(String pathString) {
      this.parentPathString = pathString;
    }
    /**
     * Sets the relation in the parent managed object which contains
     * the aggregated managed objects.
     * <p>
     * This must be defined before the property definition can be
     * built.
     *
     * @param rdName
     *          The name of a relation in the parent managed object
     *          which contains the aggregated managed objects.
     */
    public final void setRelationDefinition(String rdName) {
      this.rdName = rdName;
    }
    /**
     * Sets the condition which is used to determine if a referenced
     * managed object is enabled. By default referenced managed
     * objects are assumed to always be enabled.
     *
     * @param condition
     *          The condition which is used to determine if a
     *          referenced managed object is enabled.
     */
    public final void setTargetIsEnabledCondition(Condition condition) {
      this.targetIsEnabledCondition = condition;
    }
    /**
     * Sets the condition which is used to determine whether or not
     * referenced managed objects need to be enabled. By default
     * referenced managed objects must always be enabled.
     *
     * @param condition
     *          The condition which is used to determine whether or
     *          not referenced managed objects need to be enabled.
     */
    public final void setTargetNeedsEnablingCondition(Condition condition) {
      this.targetNeedsEnablingCondition = condition;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected AggregationPropertyDefinition<C, S> buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options, AdministratorAction adminAction,
        DefaultBehaviorProvider<String> defaultBehavior) {
      // Make sure that the parent path has been defined.
      if (parentPathString == null) {
        throw new IllegalStateException("Parent path undefined");
      }
      // Make sure that the relation definition has been defined.
      if (rdName == null) {
        throw new IllegalStateException("Relation definition undefined");
      }
      return new AggregationPropertyDefinition<C, S>(d, propertyName, options,
          adminAction, defaultBehavior, parentPathString, rdName,
          targetNeedsEnablingCondition, targetIsEnabledCondition);
    }
  }
  /**
   * A change listener which prevents the named component from being
   * disabled.
   */
  private class ReferentialIntegrityChangeListener implements
      ServerManagedObjectChangeListener<S> {
    // The error message which should be returned if an attempt is
    // made to disable the referenced component.
    private final Message message;
    // The path of the referenced component.
    private final ManagedObjectPath<C, S> path;
    // Creates a new referential integrity delete listener.
    private ReferentialIntegrityChangeListener(ManagedObjectPath<C, S> path,
        Message message) {
      this.path = path;
      this.message = message;
    }
    /**
     * {@inheritDoc}
     */
    public ConfigChangeResult applyConfigurationChange(
        ServerManagedObject<? extends S> mo) {
      try {
        if (targetIsEnabledCondition.evaluate(mo)) {
          return new ConfigChangeResult(ResultCode.SUCCESS, false);
        }
      } catch (ConfigException e) {
        // This should not happen - ignore it and throw an exception
        // anyway below.
      }
      // This should not happen - the previous call-back should have
      // trapped this.
      throw new IllegalStateException("Attempting to disable a referenced "
          + relationDefinition.getChildDefinition().getUserFriendlyName());
    }
    /**
     * {@inheritDoc}
     */
    public boolean isConfigurationChangeAcceptable(
        ServerManagedObject<? extends S> mo,
        List<Message> unacceptableReasons) {
      // Always prevent the referenced component from being
      // disabled.
      try {
        if (!targetIsEnabledCondition.evaluate(mo)) {
          unacceptableReasons.add(message);
          return false;
        } else {
          return true;
        }
      } catch (ConfigException e) {
        // The condition could not be evaluated.
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_REFINT_UNABLE_TO_EVALUATE_TARGET_CONDITION.get(mo
            .getManagedObjectDefinition().getUserFriendlyName(), String
            .valueOf(mo.getDN()), StaticUtils.getExceptionMessage(e));
        ErrorLogger.logError(message);
        unacceptableReasons.add(message);
        return false;
      }
    }
    // Gets the path associated with this listener.
    private ManagedObjectPath<C, S> getManagedObjectPath() {
      return path;
    }
  }
  /**
   * A delete listener which prevents the named component from being
   * deleted.
   */
  private class ReferentialIntegrityDeleteListener implements
      ConfigurationDeleteListener<S> {
    // The DN of the referenced configuration entry.
    private final DN dn;
    // The error message which should be returned if an attempt is
    // made to delete the referenced component.
    private final Message message;
    // Creates a new referential integrity delete listener.
    private ReferentialIntegrityDeleteListener(DN dn, Message message) {
      this.dn = dn;
      this.message = message;
    }
    /**
     * {@inheritDoc}
     */
    public ConfigChangeResult applyConfigurationDelete(S configuration) {
      // This should not happen - the
      // isConfigurationDeleteAcceptable() call-back should have
      // trapped this.
      if (configuration.dn().equals(dn)) {
        // This should not happen - the
        // isConfigurationDeleteAcceptable() call-back should have
        // trapped this.
        throw new IllegalStateException("Attempting to delete a referenced "
            + relationDefinition.getChildDefinition().getUserFriendlyName());
      } else {
        return new ConfigChangeResult(ResultCode.SUCCESS, false);
      }
    }
    /**
     * {@inheritDoc}
     */
    public boolean isConfigurationDeleteAcceptable(S configuration,
        List<Message> unacceptableReasons) {
      if (configuration.dn().equals(dn)) {
        // Always prevent deletion of the referenced component.
        unacceptableReasons.add(message);
        return false;
      }
      return true;
    }
  }
  /**
   * The server-side constraint handler implementation.
   */
  private class ServerHandler extends ServerConstraintHandler {
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isUsable(ServerManagedObject<?> managedObject,
        Collection<Message> unacceptableReasons) throws ConfigException {
      SortedSet<String> names = managedObject
          .getPropertyValues(AggregationPropertyDefinition.this);
      ServerManagementContext context = ServerManagementContext.getInstance();
      Message thisUFN = managedObject.getManagedObjectDefinition()
          .getUserFriendlyName();
      String thisDN = managedObject.getDN().toString();
      Message thatUFN = getRelationDefinition().getUserFriendlyName();
      boolean isUsable = true;
      boolean needsEnabling = targetNeedsEnablingCondition
          .evaluate(managedObject);
      for (String name : names) {
        ManagedObjectPath<C, S> path = getChildPath(name);
        String thatDN = path.toDN().toString();
        if (!context.managedObjectExists(path)) {
          Message msg = ERR_SERVER_REFINT_DANGLING_REFERENCE.get(name,
              getName(), thisUFN, thisDN, thatUFN, thatDN);
          unacceptableReasons.add(msg);
          isUsable = false;
        } else if (needsEnabling) {
          // Check that the referenced component is enabled if
          // required.
          ServerManagedObject<? extends S> ref = context.getManagedObject(path);
          if (!targetIsEnabledCondition.evaluate(ref)) {
            Message msg = ERR_SERVER_REFINT_TARGET_DISABLED.get(name,
                getName(), thisUFN, thisDN, thatUFN, thatDN);
            unacceptableReasons.add(msg);
            isUsable = false;
          }
        }
      }
      return isUsable;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void performPostAdd(ServerManagedObject<?> managedObject)
        throws ConfigException {
      // First make sure existing listeners associated with this
      // managed object are removed. This is required in order to
      // prevent multiple change listener registrations from
      // occurring, for example if this call-back is invoked multiple
      // times after the same add event.
      performPostDelete(managedObject);
      // Add change and delete listeners against all referenced
      // components.
      Message thisUFN = managedObject.getManagedObjectDefinition()
          .getUserFriendlyName();
      String thisDN = managedObject.getDN().toString();
      Message thatUFN = getRelationDefinition().getUserFriendlyName();
      // Referenced managed objects will only need a change listener
      // if they have can be disabled.
      boolean needsChangeListeners = targetNeedsEnablingCondition
          .evaluate(managedObject);
      // Delete listeners need to be registered against the parent
      // entry of the referenced components.
      ServerManagementContext context = ServerManagementContext.getInstance();
      ManagedObjectPath<?, ?> parentPath = getParentPath();
      ServerManagedObject<?> parent = context.getManagedObject(parentPath);
      // Create entries in the listener tables.
      List<ReferentialIntegrityDeleteListener> dlist =
        new LinkedList<ReferentialIntegrityDeleteListener>();
      deleteListeners.put(managedObject.getDN(), dlist);
      List<ReferentialIntegrityChangeListener> clist =
        new LinkedList<ReferentialIntegrityChangeListener>();
      changeListeners.put(managedObject.getDN(), clist);
      for (String name : managedObject
          .getPropertyValues(AggregationPropertyDefinition.this)) {
        ManagedObjectPath<C, S> path = getChildPath(name);
        DN dn = path.toDN();
        String thatDN = dn.toString();
        // Register the delete listener.
        Message msg = ERR_SERVER_REFINT_CANNOT_DELETE.get(thatUFN, thatDN,
            getName(), thisUFN, thisDN);
        ReferentialIntegrityDeleteListener dl =
          new ReferentialIntegrityDeleteListener(dn, msg);
        parent.registerDeleteListener(getRelationDefinition(), dl);
        dlist.add(dl);
        // Register the change listener if required.
        if (needsChangeListeners) {
          ServerManagedObject<? extends S> ref = context.getManagedObject(path);
          msg = ERR_SERVER_REFINT_CANNOT_DISABLE.get(thatUFN, thatDN,
              getName(), thisUFN, thisDN);
          ReferentialIntegrityChangeListener cl =
            new ReferentialIntegrityChangeListener(path, msg);
          ref.registerChangeListener(cl);
          clist.add(cl);
        }
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void performPostDelete(ServerManagedObject<?> managedObject)
        throws ConfigException {
      // Remove any registered delete and change listeners.
      ServerManagementContext context = ServerManagementContext.getInstance();
      DN dn = managedObject.getDN();
      // Delete listeners need to be deregistered against the parent
      // entry of the referenced components.
      ManagedObjectPath<?, ?> parentPath = getParentPath();
      ServerManagedObject<?> parent = context.getManagedObject(parentPath);
      if (deleteListeners.containsKey(dn)) {
        for (ReferentialIntegrityDeleteListener dl : deleteListeners.get(dn)) {
          parent.deregisterDeleteListener(getRelationDefinition(), dl);
        }
        deleteListeners.remove(dn);
      }
      // Change listeners need to be deregistered from their
      // associated referenced component.
      if (changeListeners.containsKey(dn)) {
        for (ReferentialIntegrityChangeListener cl : changeListeners.get(dn)) {
          ManagedObjectPath<C, S> path = cl.getManagedObjectPath();
          ServerManagedObject<? extends S> ref = context.getManagedObject(path);
          ref.deregisterChangeListener(cl);
        }
        changeListeners.remove(dn);
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void performPostModify(ServerManagedObject<?> managedObject)
        throws ConfigException {
      // Remove all the constraints associated with this managed
      // object and then re-register them.
      performPostDelete(managedObject);
      performPostAdd(managedObject);
    }
  }
  /**
   * The client-side constraint handler implementation which enforces
   * referential integrity when aggregating managed objects are added
   * or modified.
   */
  private class SourceClientHandler extends ClientConstraintHandler {
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isAddAcceptable(ManagementContext context,
        ManagedObject<?> managedObject, Collection<Message> unacceptableReasons)
        throws AuthorizationException, CommunicationException {
      // If all of this managed object's "enabled" properties are true
      // then any referenced managed objects must also be enabled.
      boolean needsEnabling = targetNeedsEnablingCondition.evaluate(context,
          managedObject);
      // Check the referenced managed objects exist and, if required,
      // are enabled.
      boolean isAcceptable = true;
      Message ufn = getRelationDefinition().getUserFriendlyName();
      for (String name : managedObject
          .getPropertyValues(AggregationPropertyDefinition.this)) {
        // Retrieve the referenced managed object and make sure it
        // exists.
        ManagedObjectPath<?, ?> path = getChildPath(name);
        ManagedObject<?> ref;
        try {
          ref = context.getManagedObject(path);
        } catch (DefinitionDecodingException e) {
          Message msg = ERR_CLIENT_REFINT_TARGET_INVALID.get(ufn, name,
              getName(), e.getMessageObject());
          unacceptableReasons.add(msg);
          isAcceptable = false;
          continue;
        } catch (ManagedObjectDecodingException e) {
          Message msg = ERR_CLIENT_REFINT_TARGET_INVALID.get(ufn, name,
              getName(), e.getMessageObject());
          unacceptableReasons.add(msg);
          isAcceptable = false;
          continue;
        } catch (ManagedObjectNotFoundException e) {
          Message msg = ERR_CLIENT_REFINT_TARGET_DANGLING_REFERENCE.get(ufn,
              name, getName());
          unacceptableReasons.add(msg);
          isAcceptable = false;
          continue;
        }
        // Make sure the reference managed object is enabled.
        if (needsEnabling) {
          if (!targetIsEnabledCondition.evaluate(context, ref)) {
            Message msg = ERR_CLIENT_REFINT_TARGET_DISABLED.get(ufn, name,
                getName());
            unacceptableReasons.add(msg);
            isAcceptable = false;
          }
        }
      }
      return isAcceptable;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isModifyAcceptable(ManagementContext context,
        ManagedObject<?> managedObject, Collection<Message> unacceptableReasons)
        throws AuthorizationException, CommunicationException {
      // The same constraint applies as for adds.
      return isAddAcceptable(context, managedObject, unacceptableReasons);
    }
  }
  /**
   * The client-side constraint handler implementation which enforces
   * referential integrity when aggregated managed objects are deleted
   * or modified.
   */
  private class TargetClientHandler extends ClientConstraintHandler {
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isDeleteAcceptable(ManagementContext context,
        ManagedObjectPath<?, ?> path, Collection<Message> unacceptableReasons)
        throws AuthorizationException, CommunicationException {
      // Any references to the deleted managed object should cause a
      // constraint violation.
      boolean isAcceptable = true;
      for (ManagedObject<?> mo : findReferences(context,
          getManagedObjectDefinition(), path.getName())) {
        String name = mo.getManagedObjectPath().getName();
        if (name == null) {
          Message msg = ERR_CLIENT_REFINT_CANNOT_DELETE_WITHOUT_NAME.get(
              getName(), mo.getManagedObjectDefinition().getUserFriendlyName(),
              getManagedObjectDefinition().getUserFriendlyName());
          unacceptableReasons.add(msg);
        } else {
          Message msg = ERR_CLIENT_REFINT_CANNOT_DELETE_WITH_NAME.get(
              getName(), mo.getManagedObjectDefinition().getUserFriendlyName(),
              name, getManagedObjectDefinition().getUserFriendlyName());
          unacceptableReasons.add(msg);
        }
        isAcceptable = false;
      }
      return isAcceptable;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isModifyAcceptable(ManagementContext context,
        ManagedObject<?> managedObject, Collection<Message> unacceptableReasons)
        throws AuthorizationException, CommunicationException {
      // If the modified managed object is disabled and there are some
      // active references then refuse the change.
      if (targetIsEnabledCondition.evaluate(context, managedObject)) {
        return true;
      }
      // The referenced managed object is disabled. Need to check for
      // active references.
      boolean isAcceptable = true;
      for (ManagedObject<?> mo : findReferences(context,
          getManagedObjectDefinition(), managedObject.getManagedObjectPath()
              .getName())) {
        if (targetNeedsEnablingCondition.evaluate(context, mo)) {
          String name = mo.getManagedObjectPath().getName();
          if (name == null) {
            Message msg = ERR_CLIENT_REFINT_CANNOT_DISABLE_WITHOUT_NAME.get(
                managedObject.getManagedObjectDefinition()
                    .getUserFriendlyName(), getName(), mo
                    .getManagedObjectDefinition().getUserFriendlyName());
            unacceptableReasons.add(msg);
          } else {
            Message msg = ERR_CLIENT_REFINT_CANNOT_DISABLE_WITH_NAME.get(
                managedObject.getManagedObjectDefinition()
                    .getUserFriendlyName(), getName(), mo
                    .getManagedObjectDefinition().getUserFriendlyName(), name);
            unacceptableReasons.add(msg);
          }
          isAcceptable = false;
        }
      }
      return isAcceptable;
    }
    // Find all managed objects which reference the named managed
    // object using this property.
    private <CC extends ConfigurationClient>
        List<ManagedObject<? extends CC>> findReferences(
        ManagementContext context, AbstractManagedObjectDefinition<CC, ?> mod,
        String name) throws AuthorizationException, CommunicationException {
      List<ManagedObject<? extends CC>> instances = findInstances(context, mod);
      Iterator<ManagedObject<? extends CC>> i = instances.iterator();
      while (i.hasNext()) {
        ManagedObject<? extends CC> mo = i.next();
        boolean hasReference = false;
        for (String value : mo
            .getPropertyValues(AggregationPropertyDefinition.this)) {
          if (compare(value, name) == 0) {
            hasReference = true;
            break;
          }
        }
        if (!hasReference) {
          i.remove();
        }
      }
      return instances;
    }
    // Find all instances of a specific type of managed object.
    @SuppressWarnings("unchecked")
    private <CC extends ConfigurationClient>
        List<ManagedObject<? extends CC>> findInstances(
        ManagementContext context, AbstractManagedObjectDefinition<CC, ?> mod)
        throws AuthorizationException, CommunicationException {
      List<ManagedObject<? extends CC>> instances =
        new LinkedList<ManagedObject<? extends CC>>();
      if (mod == RootCfgDefn.getInstance()) {
        instances.add((ManagedObject<? extends CC>) context
            .getRootConfigurationManagedObject());
      } else {
        for (RelationDefinition<? super CC, ?> rd : mod
            .getAllReverseRelationDefinitions()) {
          for (ManagedObject<?> parent : findInstances(context, rd
              .getParentDefinition())) {
            try {
              if (rd instanceof SingletonRelationDefinition) {
                SingletonRelationDefinition<? super CC, ?> srd =
                  (SingletonRelationDefinition<? super CC, ?>) rd;
                ManagedObject<?> mo = parent.getChild(srd);
                if (mo.getManagedObjectDefinition().isChildOf(mod)) {
                  instances.add((ManagedObject<? extends CC>) mo);
                }
              } else if (rd instanceof OptionalRelationDefinition) {
                OptionalRelationDefinition<? super CC, ?> ord =
                  (OptionalRelationDefinition<? super CC, ?>) rd;
                ManagedObject<?> mo = parent.getChild(ord);
                if (mo.getManagedObjectDefinition().isChildOf(mod)) {
                  instances.add((ManagedObject<? extends CC>) mo);
                }
              } else if (rd instanceof InstantiableRelationDefinition) {
                InstantiableRelationDefinition<? super CC, ?> ird =
                  (InstantiableRelationDefinition<? super CC, ?>) rd;
                for (String name : parent.listChildren(ird)) {
                  ManagedObject<?> mo = parent.getChild(ird, name);
                  if (mo.getManagedObjectDefinition().isChildOf(mod)) {
                    instances.add((ManagedObject<? extends CC>) mo);
                  }
                }
              }
            } catch (OperationsException e) {
              // Ignore all operations exceptions.
            }
          }
        }
      }
      return instances;
    }
  }
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = getTracer();
  /**
   * Creates an aggregation property definition builder.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this aggregation property definition refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this aggregation property definition refers to.
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new aggregation property definition builder.
   */
  public static <C extends ConfigurationClient, S extends Configuration>
      Builder<C, S> createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder<C, S>(d, propertyName);
  }
  // The active server-side referential integrity change listeners
  // associated with this property.
  private final Map<DN, List<ReferentialIntegrityChangeListener>>
    changeListeners = new HashMap<DN,
      List<ReferentialIntegrityChangeListener>>();
  // The active server-side referential integrity delete listeners
  // associated with this property.
  private final Map<DN, List<ReferentialIntegrityDeleteListener>>
    deleteListeners = new HashMap<DN,
      List<ReferentialIntegrityDeleteListener>>();
  // The name of the managed object which is the parent of the
  // aggregated managed objects.
  private ManagedObjectPath<?, ?> parentPath;
  // The string representation of the managed object path specifying
  // the parent of the aggregated managed objects.
  private final String parentPathString;
  // The name of a relation in the parent managed object which
  // contains the aggregated managed objects.
  private final String rdName;
  // The relation in the parent managed object which contains the
  // aggregated managed objects.
  private InstantiableRelationDefinition<C, S> relationDefinition;
  // The source constraint.
  private final Constraint sourceConstraint;
  // The condition which is used to determine if a referenced managed
  // object is enabled.
  private final Condition targetIsEnabledCondition;
  // The condition which is used to determine whether or not
  // referenced managed objects need to be enabled.
  private final Condition targetNeedsEnablingCondition;
  // Private constructor.
  private AggregationPropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options, AdministratorAction adminAction,
      DefaultBehaviorProvider<String> defaultBehavior, String parentPathString,
      String rdName, Condition targetNeedsEnablingCondition,
      Condition targetIsEnabledCondition) {
    super(d, String.class, propertyName, options, adminAction, defaultBehavior);
    this.parentPathString = parentPathString;
    this.rdName = rdName;
    this.targetNeedsEnablingCondition = targetNeedsEnablingCondition;
    this.targetIsEnabledCondition = targetIsEnabledCondition;
    this.sourceConstraint = new Constraint() {
      /**
       * {@inheritDoc}
       */
      public Collection<ClientConstraintHandler> getClientConstraintHandlers() {
        ClientConstraintHandler handler = new SourceClientHandler();
        return Collections.singleton(handler);
      }
      /**
       * {@inheritDoc}
       */
      public Collection<ServerConstraintHandler> getServerConstraintHandlers() {
        ServerConstraintHandler handler = new ServerHandler();
        return Collections.singleton(handler);
      }
    };
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitAggregation(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, String value, P p) {
    return v.visitAggregation(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    try {
      validateValue(value);
      return value;
    } catch (IllegalPropertyValueException e) {
      throw new IllegalPropertyValueStringException(this, value);
    }
  }
  /**
   * Constructs a DN for a referenced managed object having the
   * provided name. This method is implemented by first calling
   * {@link #getChildPath(String)} and then invoking
   * {@code ManagedObjectPath.toDN()} on the returned path.
   *
   * @param name
   *          The name of the child managed object.
   * @return Returns a DN for a referenced managed object having the
   *         provided name.
   */
  public final DN getChildDN(String name) {
    return getChildPath(name).toDN();
  }
  /**
   * Constructs a managed object path for a referenced managed object
   * having the provided name.
   *
   * @param name
   *          The name of the child managed object.
   * @return Returns a managed object path for a referenced managed
   *         object having the provided name.
   */
  public final ManagedObjectPath<C, S> getChildPath(String name) {
    return parentPath.child(relationDefinition, name);
  }
  /**
   * Gets the name of the managed object which is the parent of the
   * aggregated managed objects.
   *
   * @return Returns the name of the managed object which is the
   *         parent of the aggregated managed objects.
   */
  public final ManagedObjectPath<?, ?> getParentPath() {
    return parentPath;
  }
  /**
   * Gets the relation in the parent managed object which contains the
   * aggregated managed objects.
   *
   * @return Returns the relation in the parent managed object which
   *         contains the aggregated managed objects.
   */
  public final InstantiableRelationDefinition<C, S> getRelationDefinition() {
    return relationDefinition;
  }
  /**
   * Gets the constraint which should be enforced on the aggregating
   * managed object.
   *
   * @return Returns the constraint which should be enforced on the
   *         aggregating managed object.
   */
  public final Constraint getSourceConstraint() {
    return sourceConstraint;
  }
  /**
   * Gets the optional constraint synopsis of this aggregation
   * property definition in the default locale. The constraint
   * synopsis describes when and how referenced managed objects must
   * be enabled. When there are no constraints between the source
   * managed object and the objects it references through this
   * aggregation, <code>null</code> is returned.
   *
   * @return Returns the optional constraint synopsis of this
   *         aggregation property definition in the default locale, or
   *         <code>null</code> if there is no constraint synopsis.
   */
  public final Message getSourceConstraintSynopsis() {
    return getSourceConstraintSynopsis(Locale.getDefault());
  }
  /**
   * Gets the optional constraint synopsis of this aggregation
   * property definition in the specified locale.The constraint
   * synopsis describes when and how referenced managed objects must
   * be enabled. When there are no constraints between the source
   * managed object and the objects it references through this
   * aggregation, <code>null</code> is returned.
   *
   * @param locale
   *          The locale.
   * @return Returns the optional constraint synopsis of this
   *         aggregation property definition in the specified locale,
   *         or <code>null</code> if there is no constraint
   *         synopsis.
   */
  public final Message getSourceConstraintSynopsis(Locale locale) {
    ManagedObjectDefinitionI18NResource resource =
      ManagedObjectDefinitionI18NResource.getInstance();
    String property = "property." + getName()
        + ".syntax.aggregation.constraint-synopsis";
    try {
      return resource
          .getMessage(getManagedObjectDefinition(), property, locale);
    } catch (MissingResourceException e) {
      return null;
    }
  }
  /**
   * Gets the condition which is used to determine if a referenced
   * managed object is enabled.
   *
   * @return Returns the condition which is used to determine if a
   *         referenced managed object is enabled.
   */
  public final Condition getTargetIsEnabledCondition() {
    return targetIsEnabledCondition;
  }
  /**
   * Gets the condition which is used to determine whether or not
   * referenced managed objects need to be enabled.
   *
   * @return Returns the condition which is used to determine whether
   *         or not referenced managed objects need to be enabled.
   */
  public final Condition getTargetNeedsEnablingCondition() {
    return targetNeedsEnablingCondition;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String normalizeValue(String value)
      throws IllegalPropertyValueException {
    try {
      Reference<C, S> reference = Reference.parseName(parentPath,
          relationDefinition, value);
      return reference.getNormalizedName();
    } catch (IllegalArgumentException e) {
      throw new IllegalPropertyValueException(this, value);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void toString(StringBuilder builder) {
    super.toString(builder);
    builder.append(" parentPath=");
    builder.append(parentPath);
    builder.append(" relationDefinition=");
    builder.append(relationDefinition.getName());
    builder.append(" targetNeedsEnablingCondition=");
    builder.append(String.valueOf(targetNeedsEnablingCondition));
    builder.append(" targetIsEnabledCondition=");
    builder.append(String.valueOf(targetIsEnabledCondition));
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(String value) throws IllegalPropertyValueException {
    try {
      Reference.parseName(parentPath, relationDefinition, value);
    } catch (IllegalArgumentException e) {
      throw new IllegalPropertyValueException(this, value);
    }
  }
  /**
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  @Override
  public void initialize() throws Exception {
    // Decode the path.
    parentPath = ManagedObjectPath.valueOf(parentPathString);
    // Decode the relation definition.
    AbstractManagedObjectDefinition<?, ?> parent = parentPath
        .getManagedObjectDefinition();
    RelationDefinition<?, ?> rd = parent.getRelationDefinition(rdName);
    relationDefinition = (InstantiableRelationDefinition<C, S>) rd;
    // Now decode the conditions.
    targetNeedsEnablingCondition.initialize(getManagedObjectDefinition());
    targetIsEnabledCondition.initialize(rd.getChildDefinition());
    // Register a client-side constraint with the referenced
    // definition. This will be used to enforce referential integrity
    // for actions performed against referenced managed objects.
    Constraint constraint = new Constraint() {
      /**
       * {@inheritDoc}
       */
      public Collection<ClientConstraintHandler> getClientConstraintHandlers() {
        ClientConstraintHandler handler = new TargetClientHandler();
        return Collections.singleton(handler);
      }
      /**
       * {@inheritDoc}
       */
      public Collection<ServerConstraintHandler> getServerConstraintHandlers() {
        return Collections.emptyList();
      }
    };
    rd.getChildDefinition().registerConstraint(constraint);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/AliasDefaultBehaviorProvider.java
New file
@@ -0,0 +1,115 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import java.util.Locale;
/**
 * A default behavior provider which indicates special behavior. It should be
 * used by properties which have a default behavior which cannot be directly
 * represented using real values of the property. For example, a property
 * containing a set of user names might default to "all users" when no values
 * are provided. This meaning cannot be represented using a finite set of
 * values.
 *
 * @param <T>
 *          The type of values represented by this provider.
 */
public final class AliasDefaultBehaviorProvider<T> extends
    DefaultBehaviorProvider<T> {
  // The managed object definition associated with this default
  // behavior.
  private final AbstractManagedObjectDefinition<?, ?> definition;
  // The name of the property definition associated with this default
  // behavior.
  private final String propertyName;
  /**
   * Create an alias default behavior provider.
   *
   * @param d
   *          The managed object definition associated with this
   *          default behavior.
   * @param propertyName
   *          The name of the property definition associated with this
   *          default behavior.
   */
  public AliasDefaultBehaviorProvider(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    this.definition = d;
    this.propertyName = propertyName;
  }
  /**
   * {@inheritDoc}
   */
  public <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p) {
    return v.visitAlias(this, p);
  }
  /**
   * Gets the synopsis of this alias default behavior in the
   * default locale.
   *
   * @return Returns the synopsis of this alias default behavior in
   *         the default locale.
   */
  public final Message getSynopsis() {
    return getSynopsis(Locale.getDefault());
  }
  /**
   * Gets the synopsis of this alias default behavior in the specified
   * locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the synopsis of this alias default behavior in
   *         the specified locale.
   */
  public final Message getSynopsis(Locale locale) {
    ManagedObjectDefinitionI18NResource resource =
      ManagedObjectDefinitionI18NResource.getInstance();
    String property = "property." + propertyName
        + ".default-behavior.alias.synopsis";
    return resource.getMessage(definition, property, locale);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/AttributeTypePropertyDefinition.java
New file
@@ -0,0 +1,215 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.EnumSet;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.opends.server.core.DirectoryServer;
/**
 * Attribute type property definition.
 */
public final class AttributeTypePropertyDefinition extends
    PropertyDefinition<AttributeType> {
  /**
   * An interface for incrementally constructing attribute type
   * property definitions.
   */
  public static class Builder extends
      AbstractBuilder<AttributeType, AttributeTypePropertyDefinition> {
    // Private constructor
    private Builder(AbstractManagedObjectDefinition<?, ?> d,
        String propertyName) {
      super(d, propertyName);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected AttributeTypePropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<AttributeType> defaultBehavior) {
      return new AttributeTypePropertyDefinition(d, propertyName,
          options, adminAction, defaultBehavior);
    }
  }
  // Flag indicating whether or not attribute type names should be
  // validated against the schema.
  private static boolean isCheckSchema = true;
  /**
   * Create a attribute type property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new attribute type property definition
   *         builder.
   */
  public static Builder createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder(d, propertyName);
  }
  /**
   * Determines whether or not attribute type names should be
   * validated against the schema.
   *
   * @return Returns <code>true</code> if attribute type names
   *         should be validated against the schema.
   */
  public static boolean isCheckSchema() {
    return isCheckSchema;
  }
  /**
   * Specify whether or not attribute type names should be validated
   * against the schema.
   * <p>
   * By default validation is switched on.
   *
   * @param value
   *          <code>true</code> if attribute type names should be
   *          validated against the schema.
   */
  public static void setCheckSchema(boolean value) {
    isCheckSchema = value;
  }
  // Private constructor.
  private AttributeTypePropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<AttributeType> defaultBehavior) {
    super(d, AttributeType.class, propertyName, options,
        adminAction, defaultBehavior);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitAttributeType(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v,
      AttributeType value, P p) {
    return v.visitAttributeType(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int compare(AttributeType o1, AttributeType o2) {
    return o1.getNameOrOID().compareToIgnoreCase(o2.getNameOrOID());
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public AttributeType decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    String name = value.trim().toLowerCase();
    AttributeType type = DirectoryServer.getAttributeType(name,
        !isCheckSchema);
    if (type == null) {
      throw new IllegalPropertyValueStringException(this, value);
    } else {
      try {
        validateValue(type);
        return type;
      } catch (IllegalPropertyValueException e) {
        throw new IllegalPropertyValueStringException(this, value);
      }
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String encodeValue(AttributeType value)
      throws IllegalPropertyValueException {
    return value.getNameOrOID();
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(AttributeType value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    // No implementation required.
  }
}
opendj-admin/src/main/java/org/opends/server/admin/BooleanPropertyDefinition.java
New file
@@ -0,0 +1,182 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.server.util.Validator.ensureNotNull;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
/**
 * Boolean property definition.
 */
public final class BooleanPropertyDefinition extends
    PropertyDefinition<Boolean> {
  /**
   * Mapping used for parsing boolean values. This mapping is more flexible than
   * the standard boolean string parser and supports common true/false synonyms
   * used in configuration.
   */
  private static final Map<String, Boolean> VALUE_MAP;
  static {
    VALUE_MAP = new HashMap<String, Boolean>();
    // We could have more possibilities but decided against in issue 1960.
    VALUE_MAP.put("false", Boolean.FALSE);
    VALUE_MAP.put("true", Boolean.TRUE);
  }
  /**
   * An interface for incrementally constructing boolean property definitions.
   */
  public static class Builder extends
      AbstractBuilder<Boolean, BooleanPropertyDefinition> {
    // Private constructor
    private Builder(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
      super(d, propertyName);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected BooleanPropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<Boolean> defaultBehavior) {
      return new BooleanPropertyDefinition(d, propertyName, options,
          adminAction, defaultBehavior);
    }
  }
  /**
   * Create a boolean property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new boolean property definition builder.
   */
  public static Builder createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder(d, propertyName);
  }
  // Private constructor.
  private BooleanPropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<Boolean> defaultBehavior) {
    super(d, Boolean.class, propertyName, options, adminAction,
        defaultBehavior);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(Boolean value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    // No additional validation required.
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public Boolean decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    String nvalue = value.trim().toLowerCase();
    Boolean b = VALUE_MAP.get(nvalue);
    if (b == null) {
      throw new IllegalPropertyValueStringException(this, value);
    } else {
      return b;
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitBoolean(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, Boolean value, P p) {
    return v.visitBoolean(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int compare(Boolean o1, Boolean o2) {
    return o1.compareTo(o2);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/ClassLoaderProvider.java
New file
@@ -0,0 +1,830 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 *      Portions copyright 2012 ForgeRock AS.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.loggers.ErrorLogger.*;
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.StaticUtils.*;
import static org.opends.server.util.ServerConstants.EOL;
import java.io.ByteArrayOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import org.opends.messages.Message;
import org.opends.server.admin.std.meta.RootCfgDefn;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.DebugLogLevel;
import org.opends.server.types.InitializationException;
import org.opends.server.util.Validator;
/**
 * Manages the class loader which should be used for loading
 * configuration definition classes and associated extensions.
 * <p>
 * For extensions which define their own extended configuration
 * definitions, the class loader will make sure that the configuration
 * definition classes are loaded and initialized.
 * <p>
 * Initially the class loader provider is disabled, and calls to the
 * {@link #getClassLoader()} will return the system default class
 * loader.
 * <p>
 * Applications <b>MUST NOT</b> maintain persistent references to the
 * class loader as it can change at run-time.
 */
public final class ClassLoaderProvider {
  /**
   * The tracer object for the debug logger.
   */
  private static final DebugTracer TRACER = getTracer();
  /**
   * Private URLClassLoader implementation. This is only required so
   * that we can provide access to the addURL method.
   */
  private static final class MyURLClassLoader extends URLClassLoader {
    /**
     * Create a class loader with the default parent class loader.
     */
    public MyURLClassLoader() {
      super(new URL[0]);
    }
    /**
     * Create a class loader with the provided parent class loader.
     *
     * @param parent
     *          The parent class loader.
     */
    public MyURLClassLoader(ClassLoader parent) {
      super(new URL[0], parent);
    }
    /**
     * Add a Jar file to this class loader.
     *
     * @param jarFile
     *          The name of the Jar file.
     * @throws MalformedURLException
     *           If a protocol handler for the URL could not be found,
     *           or if some other error occurred while constructing
     *           the URL.
     * @throws SecurityException
     *           If a required system property value cannot be
     *           accessed.
     */
    public void addJarFile(File jarFile) throws SecurityException,
        MalformedURLException {
      addURL(jarFile.toURI().toURL());
    }
  }
  // The name of the manifest file listing the core configuration
  // definition classes.
  private static final String CORE_MANIFEST = "core.manifest";
  // The name of the manifest file listing a extension's configuration
  // definition classes.
  private static final String EXTENSION_MANIFEST = "extension.manifest";
  // The name of the lib directory.
  private static final String LIB_DIR = "lib";
  // The name of the extensions directory.
  private static final String EXTENSIONS_DIR = "extensions";
  // The singleton instance.
  private static final ClassLoaderProvider INSTANCE = new ClassLoaderProvider();
  // Attribute name in jar's MANIFEST corresponding to the revision number.
  private static final String REVISION_NUMBER = "Revision-Number";
  // The attribute names for build information is name, version and revision
  // number
  private static final String[] BUILD_INFORMATION_ATTRIBUTE_NAMES =
                 new String[]{Attributes.Name.EXTENSION_NAME.toString(),
                              Attributes.Name.IMPLEMENTATION_VERSION.toString(),
                              REVISION_NUMBER};
  /**
   * Get the single application wide class loader provider instance.
   *
   * @return Returns the single application wide class loader provider
   *         instance.
   */
  public static ClassLoaderProvider getInstance() {
    return INSTANCE;
  }
  // Set of registered Jar files.
  private Set<File> jarFiles = new HashSet<File>();
  // Underlying class loader used to load classes and resources (null
  // if disabled).
  //
  // We contain a reference to the URLClassLoader rather than
  // sub-class it so that it is possible to replace the loader at
  // run-time. For example, when removing or replacing extension Jar
  // files (the URLClassLoader only supports adding new
  // URLs, not removal).
  private MyURLClassLoader loader = null;
  // Private constructor.
  private ClassLoaderProvider() {
    // No implementation required.
  }
  /**
   * Add the named extensions to this class loader provider.
   *
   * @param extensions
   *          The names of the extensions to be loaded. The names
   *          should not contain any path elements and must be located
   *          within the extensions folder.
   * @throws InitializationException
   *           If one of the extensions could not be loaded and
   *           initialized.
   * @throws IllegalStateException
   *           If this class loader provider is disabled.
   * @throws IllegalArgumentException
   *           If one of the extension names was not a single relative
   *           path name element or was an absolute path.
   */
  public synchronized void addExtension(String... extensions)
      throws InitializationException, IllegalStateException,
      IllegalArgumentException {
    Validator.ensureNotNull(extensions);
    if (loader == null) {
      throw new IllegalStateException(
          "Class loader provider is disabled.");
    }
    File libPath = new File(DirectoryServer.getInstanceRoot(), LIB_DIR);
    File extensionsPath = new File(libPath, EXTENSIONS_DIR);
    ArrayList<File> files = new ArrayList<File>(extensions.length);
    for (String extension : extensions) {
      File file = new File(extensionsPath, extension);
      // For security reasons we need to make sure that the file name
      // passed in did not contain any path elements and names a file
      // in the extensions folder.
      // Can handle potential null parent.
      if (!extensionsPath.equals(file.getParentFile())) {
        throw new IllegalArgumentException("Illegal file name: "
            + extension);
      }
      // The file is valid.
      files.add(file);
    }
    // Add the extensions.
    addExtension(files.toArray(new File[files.size()]));
  }
  /**
   * Disable this class loader provider and removed any registered
   * extensions.
   *
   * @throws IllegalStateException
   *           If this class loader provider is already disabled.
   */
  public synchronized void disable() throws IllegalStateException {
    if (loader == null) {
      throw new IllegalStateException(
          "Class loader provider already disabled.");
    }
    loader = null;
    jarFiles = new HashSet<File>();
  }
  /**
   * Enable this class loader provider using the application's
   * class loader as the parent class loader.
   *
   * @throws InitializationException
   *           If the class loader provider could not initialize
   *           successfully.
   * @throws IllegalStateException
   *           If this class loader provider is already enabled.
   */
  public synchronized void enable() throws InitializationException,
      IllegalStateException {
    enable(RootCfgDefn.class.getClassLoader());
  }
  /**
   * Enable this class loader provider using the provided parent class
   * loader.
   *
   * @param parent
   *          The parent class loader.
   * @throws InitializationException
   *           If the class loader provider could not initialize
   *           successfully.
   * @throws IllegalStateException
   *           If this class loader provider is already enabled.
   */
  public synchronized void enable(ClassLoader parent)
      throws InitializationException, IllegalStateException {
    if (loader != null) {
      throw new IllegalStateException(
          "Class loader provider already enabled.");
    }
    if (parent != null) {
      loader = new MyURLClassLoader(parent);
    } else {
      loader = new MyURLClassLoader();
    }
    // Forcefully load all configuration definition classes in
    // OpenDS.jar.
    initializeCoreComponents();
    // Put extensions jars into the class loader and load all
    // configuration definition classes in that they contain.
    // First load the extension from the install directory, then
    // from the instance directory.
    File libDir ;
    File installExtensionsPath ;
    File instanceExtensionsPath ;
    // load install dir extension
    libDir = new File(DirectoryServer.getServerRoot(), LIB_DIR);
    try
    {
      installExtensionsPath =
        new File(libDir, EXTENSIONS_DIR).getCanonicalFile();
    }
    catch (Exception e)
    {
      installExtensionsPath = new File(libDir, EXTENSIONS_DIR);
    }
    initializeAllExtensions(installExtensionsPath);
    // load instance dir extension
    libDir = new File(DirectoryServer.getInstanceRoot(),LIB_DIR);
    try
    {
      instanceExtensionsPath =
        new File(libDir, EXTENSIONS_DIR).getCanonicalFile();
    }
    catch (Exception e)
    {
      instanceExtensionsPath = new File(libDir, EXTENSIONS_DIR);
    }
    if (! installExtensionsPath.getAbsolutePath().equals(
        instanceExtensionsPath.getAbsolutePath()))
    {
      initializeAllExtensions(instanceExtensionsPath);
    }
  }
  /**
   * Gets the class loader which should be used for loading classes
   * and resources. When this class loader provider is disabled, the
   * system default class loader will be returned by default.
   * <p>
   * Applications <b>MUST NOT</b> maintain persistent references to
   * the class loader as it can change at run-time.
   *
   * @return Returns the class loader which should be used for loading
   *         classes and resources.
   */
  public synchronized ClassLoader getClassLoader() {
    if (loader != null) {
      return loader;
    } else {
      return ClassLoader.getSystemClassLoader();
    }
  }
  /**
   * Indicates whether this class loader provider is enabled.
   *
   * @return Returns <code>true</code> if this class loader provider
   *         is enabled.
   */
  public synchronized boolean isEnabled() {
    return loader != null;
  }
  /**
   * Add the named extensions to this class loader.
   *
   * @param extensions
   *          The names of the extensions to be loaded.
   * @throws InitializationException
   *           If one of the extensions could not be loaded and
   *           initialized.
   */
  private synchronized void addExtension(File... extensions)
      throws InitializationException {
    // First add the Jar files to the class loader.
    List<JarFile> jars = new LinkedList<JarFile>();
    for (File extension : extensions) {
      if (jarFiles.contains(extension)) {
        // Skip this file as it is already loaded.
        continue;
      }
      // Attempt to load it.
      jars.add(loadJarFile(extension));
      // Register the Jar file with the class loader.
      try {
        loader.addJarFile(extension);
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_ADMIN_CANNOT_OPEN_JAR_FILE.
            get(extension.getName(), extension.getParent(),
                stackTraceToSingleLineString(e));
        throw new InitializationException(message);
      }
      jarFiles.add(extension);
    }
    // Now forcefully load the configuration definition classes.
    for (JarFile jar : jars) {
      initializeExtension(jar);
    }
  }
  /**
   * Prints out all information about extensions.
   *
   * @return a String instance representing all information about extensions;
   *         <code>null</code> if there is no information available.
   */
  public String printExtensionInformation() {
    File extensionsPath =
            new File(new StringBuilder(DirectoryServer.getServerRoot()).
                                append(File.separator).
                                append(LIB_DIR).
                                append(File.separator).
                                append(EXTENSIONS_DIR).
                                toString());
    if (!extensionsPath.exists() || !extensionsPath.isDirectory()) {
      // no extensions' directory
      return null;
    }
    File[] extensions = extensionsPath.listFiles(new FileFilter(){
      public boolean accept(File pathname) {
        // only files with names ending with ".jar"
        return pathname.isFile() && pathname.getName().endsWith(".jar");
      }
    });
    if ( extensions.length == 0 ) {
      return null;
    }
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    PrintStream ps = new PrintStream(baos);
    // prints:
    // --
    //            Name                 Build number         Revision number
    ps.printf("--%s           %-20s %-20s %-20s%s",
              EOL,
              "Name",
              "Build number",
              "Revision number",
              EOL);
    for(File extension : extensions) {
      // retrieve MANIFEST entry and display name, build number and revision
      // number
      try {
        JarFile jarFile = new JarFile(extension);
        JarEntry entry = jarFile.getJarEntry("admin/" + EXTENSION_MANIFEST);
        if (entry == null)
        {
          continue;
        }
        String[] information = getBuildInformation(jarFile);
        ps.append("Extension: ");
        boolean addBlank = false;
        for(String name : information) {
          if ( addBlank ) {
            ps.append(addBlank ? " " : ""); // add blank if not first append
          } else {
            addBlank = true;
          }
          ps.printf("%-20s", name);
        }
        ps.append(EOL);
      } catch(Exception e) {
        // ignore extra information for this extension
      }
    }
    return baos.toString();
  }
  /**
   * Returns a String array with the following information :
   * <br>index 0: the name of the extension.
   * <br>index 1: the build number of the extension.
   * <br>index 2: the revision number of the extension.
   *
   * @param extension the jar file of the extension
   * @return a String array containing the name, the build number and the
   *         revision number of the extension given in argument
   * @throws java.io.IOException thrown if the jar file has been closed.
   */
  private String[] getBuildInformation(JarFile extension) throws IOException {
    String[] result = new String[3];
    // retrieve MANIFEST entry and display name, version and revision
    Manifest manifest = extension.getManifest();
    if ( manifest != null ) {
      Attributes attributes = manifest.getMainAttributes();
      int index = 0;
      for(String name : BUILD_INFORMATION_ATTRIBUTE_NAMES) {
        String value = attributes.getValue(name);
        if ( value == null ) {
          value = "<unknown>";
        }
        result[index++] = value;
      }
    }
    return result;
  }
  /**
   * Put extensions jars into the class loader and load all
   * configuration definition classes in that they contain.
   * @param extensionsPath Indicates where extensions are located.
   *
   * @throws InitializationException
   *           If the extensions folder could not be accessed or if a
   *           extension jar file could not be accessed or if one of
   *           the configuration definition classes could not be
   *           initialized.
   */
  private void initializeAllExtensions(File extensionsPath)
      throws InitializationException {
    try {
      if (!extensionsPath.exists()) {
        // The extensions directory does not exist. This is not a
        // critical problem.
        Message message = ERR_ADMIN_NO_EXTENSIONS_DIR.get(
                String.valueOf(extensionsPath));
        logError(message);
        return;
      }
      if (!extensionsPath.isDirectory()) {
        // The extensions directory is not a directory. This is more
        // critical.
        Message message =
            ERR_ADMIN_EXTENSIONS_DIR_NOT_DIRECTORY.get(
                    String.valueOf(extensionsPath));
        throw new InitializationException(message);
      }
      // Get each extension file name.
      FileFilter filter = new FileFilter() {
        /**
         * Must be a Jar file.
         */
        public boolean accept(File pathname) {
          if (!pathname.isFile()) {
            return false;
          }
          String name = pathname.getName();
          return name.endsWith(".jar");
        }
      };
      // Add and initialize the extensions.
      addExtension(extensionsPath.listFiles(filter));
    } catch (InitializationException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      throw e;
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_ADMIN_EXTENSIONS_CANNOT_LIST_FILES.get(
          String.valueOf(extensionsPath), stackTraceToSingleLineString(e));
      throw new InitializationException(message, e);
    }
  }
  /**
   * Make sure all core configuration definitions are loaded.
   *
   * @throws InitializationException
   *           If the core manifest file could not be read or if one
   *           of the configuration definition classes could not be
   *           initialized.
   */
  private void initializeCoreComponents()
      throws InitializationException {
    InputStream is = RootCfgDefn.class.getResourceAsStream("/admin/"
        + CORE_MANIFEST);
    if (is == null) {
      Message message = ERR_ADMIN_CANNOT_FIND_CORE_MANIFEST.get(CORE_MANIFEST);
      throw new InitializationException(message);
    }
    try {
      loadDefinitionClasses(is);
    } catch (InitializationException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_CLASS_LOADER_CANNOT_LOAD_CORE.get(CORE_MANIFEST,
          stackTraceToSingleLineString(e));
      throw new InitializationException(message);
    }
  }
  /**
   * Make sure all the configuration definition classes in a extension
   * are loaded.
   *
   * @param jarFile
   *          The extension's Jar file.
   * @throws InitializationException
   *           If the extension jar file could not be accessed or if
   *           one of the configuration definition classes could not
   *           be initialized.
   */
  private void initializeExtension(JarFile jarFile)
      throws InitializationException {
    JarEntry entry = jarFile.getJarEntry("admin/"
        + EXTENSION_MANIFEST);
    if (entry != null) {
      InputStream is;
      try {
        is = jarFile.getInputStream(entry);
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_ADMIN_CANNOT_READ_EXTENSION_MANIFEST.get(
            EXTENSION_MANIFEST, jarFile.getName(),
            stackTraceToSingleLineString(e));
        throw new InitializationException(message);
      }
      try {
        loadDefinitionClasses(is);
      } catch (InitializationException e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
        Message message = ERR_CLASS_LOADER_CANNOT_LOAD_EXTENSION.get(jarFile
            .getName(), EXTENSION_MANIFEST, stackTraceToSingleLineString(e));
        throw new InitializationException(message);
      }
      try {
        // Log build information of extensions in the error log
        String[] information = getBuildInformation(jarFile);
        logError(
          NOTE_LOG_EXTENSION_INFORMATION.
            get(jarFile.getName(),
                information[1],
                information[2]));
      } catch(Exception e) {
        // Do not log information for that extension
      }
    }
  }
  /**
   * Forcefully load configuration definition classes named in a
   * manifest file.
   *
   * @param is
   *          The manifest file input stream.
   * @throws InitializationException
   *           If the definition classes could not be loaded and
   *           initialized.
   */
  private void loadDefinitionClasses(InputStream is)
      throws InitializationException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(
        is));
    List<AbstractManagedObjectDefinition<?, ?>> definitions =
      new LinkedList<AbstractManagedObjectDefinition<?,?>>();
    while (true) {
      String className;
      try {
        className = reader.readLine();
      } catch (IOException e) {
        Message msg = ERR_CLASS_LOADER_CANNOT_READ_MANIFEST_FILE.get(String
            .valueOf(e.getMessage()));
        throw new InitializationException(msg, e);
      }
      // Break out when the end of the manifest is reached.
      if (className == null) {
        break;
      }
      // Skip blank lines.
      className = className.trim();
      if (className.length() == 0) {
        continue;
      }
      // Skip lines beginning with #.
      if (className.startsWith("#")) {
        continue;
      }
      TRACER.debugMessage(DebugLogLevel.INFO, "Loading class " + className);
      // Load the class and get an instance of it if it is a definition.
      Class<?> theClass;
      try {
        theClass = Class.forName(className, true, loader);
      } catch (Exception e) {
        Message msg = ERR_CLASS_LOADER_CANNOT_LOAD_CLASS.get(className, String
            .valueOf(e.getMessage()));
        throw new InitializationException(msg, e);
      }
      if (AbstractManagedObjectDefinition.class.isAssignableFrom(theClass)) {
        // We need to instantiate it using its getInstance() static method.
        Method method;
        try {
          method = theClass.getMethod("getInstance");
        } catch (Exception e) {
          Message msg = ERR_CLASS_LOADER_CANNOT_FIND_GET_INSTANCE_METHOD.get(
              className, String.valueOf(e.getMessage()));
          throw new InitializationException(msg, e);
        }
        // Get the definition instance.
        AbstractManagedObjectDefinition<?, ?> d;
        try {
          d = (AbstractManagedObjectDefinition<?, ?>) method.invoke(null);
        } catch (Exception e) {
          Message msg = ERR_CLASS_LOADER_CANNOT_INVOKE_GET_INSTANCE_METHOD.get(
              className, String.valueOf(e.getMessage()));
          throw new InitializationException(msg, e);
        }
        definitions.add(d);
      }
    }
    // Initialize any definitions that were loaded.
    for (AbstractManagedObjectDefinition<?, ?> d : definitions) {
      try {
        d.initialize();
      } catch (Exception e) {
        Message msg = ERR_CLASS_LOADER_CANNOT_INITIALIZE_DEFN.get(d.getName(),
            d.getClass().getName(), String.valueOf(e.getMessage()));
        throw new InitializationException(msg, e);
      }
    }
  }
  /**
   * Load the named Jar file.
   *
   * @param jar
   *          The name of the Jar file to load.
   * @return Returns the loaded Jar file.
   * @throws InitializationException
   *           If the Jar file could not be loaded.
   */
  private JarFile loadJarFile(File jar)
      throws InitializationException {
    JarFile jarFile;
    try {
      // Load the extension jar file.
      jarFile = new JarFile(jar);
    } catch (Exception e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_ADMIN_CANNOT_OPEN_JAR_FILE.get(
          jar.getName(), jar.getParent(), stackTraceToSingleLineString(e));
      throw new InitializationException(message);
    }
    return jarFile;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/ClassPropertyDefinition.java
New file
@@ -0,0 +1,382 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.server.util.Validator.ensureNotNull;
import java.util.Collections;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
/**
 * Class property definition.
 * <p>
 * A class property definition defines a property whose values
 * represent a Java class. It is possible to restrict the type of java
 * class by specifying "instance of" constraints.
 * <p>
 * Note that in a client/server environment, the client is probably
 * not capable of validating the Java class (e.g. it will not be able
 * to load it nor have access to the interfaces it is supposed to
 * implement). For this reason, it is possible to switch off
 * validation in the client by calling the static method
 * {@link #setAllowClassValidation(boolean)}.
 */
public final class ClassPropertyDefinition extends PropertyDefinition<String> {
  /**
   * An interface for incrementally constructing class property
   * definitions.
   */
  public static class Builder extends
      AbstractBuilder<String, ClassPropertyDefinition> {
    // List of interfaces which property values must implement.
    private List<String> instanceOfInterfaces;
    // Private constructor
    private Builder(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
      super(d, propertyName);
      this.instanceOfInterfaces = new LinkedList<String>();
    }
    /**
     * Add an class name which property values must implement.
     *
     * @param className
     *          The name of a class which property values must
     *          implement.
     */
    public final void addInstanceOf(String className) {
      ensureNotNull(className);
      // Do some basic checks to make sure the string representation
      // is valid.
      String value = className.trim();
      if (!value.matches(CLASS_RE)) {
        throw new IllegalArgumentException("\"" + value
            + "\" is not a valid Java class name");
      }
      // If possible try and load the class in order to perform
      // additional
      // validation.
      if (isAllowClassValidation()) {
        // Check that the class can be loaded so that validation can
        // be
        // performed.
        try {
          loadClass(value);
        } catch (ClassNotFoundException e) {
          // TODO: can we do something better here?
          throw new RuntimeException(e);
        }
      }
      instanceOfInterfaces.add(value);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected ClassPropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d,
        String propertyName, EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<String> defaultBehavior) {
      return new ClassPropertyDefinition(d, propertyName, options,
          adminAction, defaultBehavior, instanceOfInterfaces);
    }
  }
  // Regular expression for validating class names.
  private static final String CLASS_RE =
    "^([A-Za-z][A-Za-z0-9_]*\\.)*[A-Za-z][A-Za-z0-9_]*(\\$[A-Za-z0-9_]+)*$";
  // Flag indicating whether class property values should be
  // validated.
  private static boolean allowClassValidation = true;
  /**
   * Create a class property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new class property definition builder.
   */
  public static Builder createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder(d, propertyName);
  }
  /**
   * Determine whether or not class property definitions should
   * validate class name property values. Validation involves checking
   * that the class exists and that it implements the required
   * interfaces.
   *
   * @return Returns <code>true</code> if class property definitions
   *         should validate class name property values.
   */
  public static boolean isAllowClassValidation() {
    return allowClassValidation;
  }
  /**
   * Specify whether or not class property definitions should validate
   * class name property values. Validation involves checking that the
   * class exists and that it implements the required interfaces.
   * <p>
   * By default validation is switched on.
   *
   * @param value
   *          <code>true</code> if class property definitions should
   *          validate class name property values.
   */
  public static void setAllowClassValidation(boolean value) {
    allowClassValidation = value;
  }
  // Load a named class.
  private static Class<?> loadClass(String className)
      throws ClassNotFoundException, LinkageError {
    return Class.forName(className, true, ClassLoaderProvider
        .getInstance().getClassLoader());
  }
  // List of interfaces which property values must implement.
  private final List<String> instanceOfInterfaces;
  // Private constructor.
  private ClassPropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<String> defaultBehavior,
      List<String> instanceOfInterfaces) {
    super(d, String.class, propertyName, options, adminAction, defaultBehavior);
    this.instanceOfInterfaces = Collections
        .unmodifiableList(new LinkedList<String>(instanceOfInterfaces));
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitClass(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, String value, P p) {
    return v.visitClass(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    try {
      validateValue(value);
    } catch (IllegalPropertyValueException e) {
      throw new IllegalPropertyValueStringException(this, value);
    }
    return value;
  }
  /**
   * Get an unmodifiable list of classes which values of this property
   * must implement.
   *
   * @return Returns an unmodifiable list of classes which values of
   *         this property must implement.
   */
  public List<String> getInstanceOfInterface() {
    return instanceOfInterfaces;
  }
  /**
   * Validate and load the named class, and cast it to a subclass of
   * the specified class.
   *
   * @param <T>
   *          The requested type.
   * @param className
   *          The name of the class to validate and load.
   * @param instanceOf
   *          The class representing the requested type.
   * @return Returns the named class cast to a subclass of the
   *         specified class.
   * @throws IllegalPropertyValueException
   *           If the named class was invalid, could not be loaded, or
   *           did not implement the required interfaces.
   * @throws ClassCastException
   *           If the referenced class does not implement the
   *           requested type.
   */
  public <T> Class<? extends T> loadClass(String className,
      Class<T> instanceOf) throws IllegalPropertyValueException,
      ClassCastException {
    ensureNotNull(className, instanceOf);
    // Make sure that the named class is valid.
    validateClassName(className);
    Class<?> theClass = validateClassInterfaces(className);
    // Cast it to the required type.
    return theClass.asSubclass(instanceOf);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String normalizeValue(String value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    return value.trim();
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(String value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    // Always make sure the name is a valid class name.
    validateClassName(value);
    // If additional validation is enabled then attempt to load the
    // class and
    // check the interfaces that it implements/extends.
    if (allowClassValidation) {
      validateClassInterfaces(value);
    }
  }
  // Make sure that named class implements the interfaces named by
  // this
  // definition.
  private Class<?> validateClassInterfaces(String className)
      throws IllegalPropertyValueException {
    String nvalue = className.trim();
    Class<?> theClass;
    try {
      theClass = loadClass(nvalue);
    } catch (Exception e) {
      // If the class cannot be loaded then it is an invalid value.
      throw new IllegalPropertyValueException(this, className);
    }
    for (String i : instanceOfInterfaces) {
      try {
        Class<?> instanceOfClass = loadClass(i);
        if (!instanceOfClass.isAssignableFrom(theClass)) {
          throw new IllegalPropertyValueException(this, className);
        }
      } catch (Exception e) {
        // Should not happen because the class was validated when the
        // property
        // definition was constructed.
        throw new IllegalPropertyValueException(this, className);
      }
    }
    return theClass;
  }
  // Do some basic checks to make sure the string representation is
  // valid.
  private void validateClassName(String className)
      throws IllegalPropertyValueException {
    String nvalue = className.trim();
    if (!nvalue.matches(CLASS_RE)) {
      throw new IllegalPropertyValueException(this, className);
    }
  }
}
opendj-admin/src/main/java/org/opends/server/admin/Configuration.java
New file
@@ -0,0 +1,55 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2007-2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.forgerock.opendj.ldap.DN;
/**
 * A common base interface for all server managed object
 * configurations.
 */
public interface Configuration {
  /**
   * Gets the DN of the LDAP entry associated with this configuration.
   *
   * @return Returns the DN of the LDAP entry associated with this
   *         configuration.
   */
  DN dn();
  /**
   * Gets the configuration class associated with this configuration.
   *
   * @return Returns the configuration class associated with this
   *         configuration.
   */
  Class<? extends Configuration> configurationClass();
}
opendj-admin/src/main/java/org/opends/server/admin/ConfigurationClient.java
New file
@@ -0,0 +1,100 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
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.MissingMandatoryPropertiesException;
import org.opends.server.admin.client.OperationRejectedException;
/**
 * A common base interface for all managed object configuration
 * clients.
 */
public interface ConfigurationClient {
  /**
   * Get the configuration definition associated with this
   * configuration.
   *
   * @return Returns the configuration definition associated with this
   *         configuration.
   */
  ManagedObjectDefinition<? extends ConfigurationClient,
      ? extends Configuration> definition();
  /**
   * Get a property provider view of this configuration.
   *
   * @return Returns a property provider view of this configuration.
   */
  PropertyProvider properties();
  /**
   * If this is a new configuration this method will attempt to add it
   * to the server, otherwise it will commit any changes made to this
   * configuration.
   *
   * @throws ManagedObjectAlreadyExistsException
   *           If this is a new configuration but it could not be
   *           added to the server because it already exists.
   * @throws MissingMandatoryPropertiesException
   *           If this configuration contains some mandatory
   *           properties which have been left undefined.
   * @throws ConcurrentModificationException
   *           If this is a new configuration which is being added to
   *           the server but its parent has been removed by another
   *           client, or if this configuration is being modified but
   *           it has been removed from the server by another client.
   * @throws OperationRejectedException
   *           If the server refuses to add or modify this
   *           configuration due to some server-side constraint which
   *           cannot be satisfied.
   * @throws AuthorizationException
   *           If the server refuses to add or modify this
   *           configuration because the client does not have the
   *           correct privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  void commit() throws ManagedObjectAlreadyExistsException,
      MissingMandatoryPropertiesException, ConcurrentModificationException,
      OperationRejectedException, AuthorizationException,
      CommunicationException;
}
opendj-admin/src/main/java/org/opends/server/admin/Constraint.java
New file
@@ -0,0 +1,122 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.Collection;
import java.util.Collections;
import org.opends.server.admin.client.ClientConstraintHandler;
import org.opends.server.admin.server.ServerConstraintHandler;
/**
 * An interface for enforcing constraints and dependencies between
 * managed objects and their properties. Constraints express
 * relationships between managed objects and their properties, for
 * example:
 * <ul>
 * <li>referential integrity: where one managed object references
 * another a constraint can enforce referential integrity. The
 * constraint can prevent creation of references to non-existent
 * managed objects, and also prevent deletion of referenced managed
 * objects
 * <li>property dependencies: for example, when a boolean property is
 * <code>true</code>, one or more additional properties must be
 * specified. This is useful for features like SSL, which when
 * enabled, requires that various SSL related configuration options
 * are specified
 * <li>property constraints: for example, when an upper limit
 * property must not have a value which is less than the lower limit
 * property.
 * </ul>
 * On the client-side constraints are enforced immediately before a
 * write operation is performed. That is to say, immediately before a
 * new managed object is created, changes to a managed object are
 * applied, or an existing managed object is deleted.
 */
public abstract class Constraint {
  /**
   * Creates a new constraint.
   */
  protected Constraint() {
    // No implementation required.
  }
  /**
   * Gets the client-side constraint handlers which will be used to
   * enforce this constraint in client applications. The default
   * implementation is to return an empty set of client constraint
   * handlers.
   *
   * @return Returns the client-side constraint handlers which will be
   *         used to enforce this constraint in client applications.
   *         The returned collection must not be <code>null</code>
   *         but maybe empty (indicating that the constraint can only
   *         be enforced on the server-side).
   */
  public Collection<ClientConstraintHandler> getClientConstraintHandlers() {
    return Collections.emptySet();
  }
  /**
   * Gets the server-side constraint handlers which will be used to
   * enforce this constraint within the server. The default
   * implementation is to return an empty set of server constraint
   * handlers.
   *
   * @return Returns the server-side constraint handlers which will be
   *         used to enforce this constraint within the server. The
   *         returned collection must not be <code>null</code> and
   *         must not be empty, since constraints must always be
   *         enforced on the server.
   */
  public Collection<ServerConstraintHandler> getServerConstraintHandlers() {
    return Collections.emptySet();
  }
  /**
   * Initializes this constraint. The default implementation is to do
   * nothing.
   *
   * @throws Exception
   *           If this constraint could not be initialized.
   */
  protected void initialize() throws Exception {
    // Default implementation is to do nothing.
  }
}
opendj-admin/src/main/java/org/opends/server/admin/DNPropertyDefinition.java
New file
@@ -0,0 +1,240 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.server.util.Validator.ensureNotNull;
import java.util.EnumSet;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.types.DirectoryException;
/**
 * DN property definition.
 */
public final class DNPropertyDefinition extends PropertyDefinition<DN> {
  // Optional base DN which all valid values must be immediately
  // subordinate to.
  private final DN baseDN;
  /**
   * An interface for incrementally constructing DN property
   * definitions.
   */
  public static class Builder extends
      AbstractBuilder<DN, DNPropertyDefinition> {
    // Optional base DN which all valid values must be immediately
    // subordinate to.
    private DN baseDN = null;
    // Private constructor
    private Builder(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
      super(d, propertyName);
    }
    /**
     * Set the base DN which all valid values must be immediately
     * subordinate to. By default there is no based DN.
     *
     * @param baseDN
     *          The string representation of the base DN.
     * @throws IllegalArgumentException
     *           If the provided string is not a valid DN string
     *           representation.
     */
    public void setBaseDN(String baseDN)
        throws IllegalArgumentException {
      if (baseDN == null) {
        setBaseDN((DN) null);
      } else {
        try {
          setBaseDN(DN.decode(baseDN));
        } catch (DirectoryException e) {
          throw new IllegalArgumentException(e);
        }
      }
    }
    /**
     * Set the base DN which all valid values must be immediately
     * subordinate to. By default there is no based DN.
     *
     * @param baseDN
     *          The base DN.
     */
    public void setBaseDN(DN baseDN) {
      this.baseDN = baseDN;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected DNPropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<DN> defaultBehavior) {
      return new DNPropertyDefinition(d, propertyName, options,
          adminAction, defaultBehavior, baseDN);
    }
  }
  /**
   * Create a DN property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new boolean property definition builder.
   */
  public static Builder createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder(d, propertyName);
  }
  // Private constructor.
  private DNPropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<DN> defaultBehavior, DN baseDN) {
    super(d, DN.class, propertyName, options, adminAction, defaultBehavior);
    this.baseDN = baseDN;
  }
  /**
   * Get the base DN which all valid values must be immediately
   * subordinate to, or <code>null</code> if there is no based DN.
   *
   * @return Returns the base DN which all valid values must be
   *         immediately subordinate to.
   */
  public DN getBaseDN() {
    return baseDN;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(DN value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    if (baseDN != null) {
      DN parent = value.getParent();
      if (parent == null) {
        parent = DN.nullDN();
      }
      if (!parent.equals(baseDN)) {
        throw new IllegalPropertyValueException(this, value);
      }
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public DN decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    try {
      DN dn = DN.decode(value);
      validateValue(dn);
      return dn;
    } catch (DirectoryException e) {
      throw new IllegalPropertyValueStringException(this, value);
    } catch (IllegalPropertyValueException e) {
      throw new IllegalPropertyValueStringException(this, value);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitDN(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, DN value, P p) {
    return v.visitDN(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int compare(DN o1, DN o2) {
    return o1.compareTo(o2);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/DecodingException.java
New file
@@ -0,0 +1,58 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
/**
 * The requested managed object was found but it could not be decoded.
 */
public abstract class DecodingException extends OperationsException {
  /**
   * Fake serialization ID.
   */
  private static final long serialVersionUID = 1L;
  /**
   * Create a decoding exception with a message.
   *
   * @param message
   *          The message.
   */
  protected DecodingException(Message message) {
    super(message);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/DefaultBehaviorException.java
New file
@@ -0,0 +1,69 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
/**
 * This exception is thrown when a property's default values cannot be
 * determined. This can occur in the following situations:
 * <ul>
 * <li>the property has a well-defined set of default values but they
 * are invalid according to the property's syntax
 * <li>the property inherits its default values from another managed
 * object but they could not be retrieved, perhaps because of a
 * communication problem.
 * </ul>
 */
public class DefaultBehaviorException extends PropertyException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = -2542117466747573053L;
  /**
   * Create a new default behavior exception with a cause.
   *
   * @param pd
   *          The property definition whose default values could not
   *          be determined.
   * @param cause
   *          The exception that prevented the default values from
   *          being determined.
   */
  public DefaultBehaviorException(PropertyDefinition<?> pd, Throwable cause) {
    super(pd, ERR_DEFAULT_BEHAVIOR_PROPERTY_EXCEPTION.get(pd.getName()), cause);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/DefaultBehaviorProvider.java
New file
@@ -0,0 +1,104 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * An interface for determining the default behavior of a property. A
 * property exhibits default behavior when it has no values defined.
 * There are four different types of default behavior:
 * <ol>
 * <li>there is no default behavior - e.g. leaving a "description"
 * unset has no side-effects. This default behavior is represented
 * using the {@link UndefinedDefaultBehaviorProvider} implementation
 * <li>the property defaults to one or more real values of the
 * property. This default behavior is represented using the
 * {@link DefinedDefaultBehaviorProvider} implementation
 * <li>the property defaults to some special behavior that cannot be
 * represented using real property values. This default behavior is
 * represented using the {@link AliasDefaultBehaviorProvider}
 * implementation
 * <li>the property inherits its values from property held in another
 * managed object (e.g. the parent managed object). This default
 * behavior is represented using the
 * {@link AbsoluteInheritedDefaultBehaviorProvider} and
 * {@link RelativeInheritedDefaultBehaviorProvider} implementations.
 * </ol>
 * An application can perform actions based on the type of the default
 * behavior by implementing the {@link DefaultBehaviorProviderVisitor}
 * interface.
 *
 * @param <T>
 *          The type of values represented by this provider.
 */
public abstract class DefaultBehaviorProvider<T> {
  /**
   * Creates a new default behavior provider.
   */
  protected DefaultBehaviorProvider() {
    // No implementation required.
  }
  /**
   * Apply a visitor to this default behavior provider.
   *
   * @param <R>
   *          The return type of the visitor's methods.
   * @param <P>
   *          The type of the additional parameters to the visitor's
   *          methods.
   * @param v
   *          The default behavior visitor.
   * @param p
   *          Optional additional visitor parameter.
   * @return Returns a result as specified by the visitor.
   */
  public abstract <R, P>
  R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p);
  /**
   * Performs any run-time initialization required by this default
   * behavior provider. This may include resolving managed object
   * paths and property names.
   * <p>
   * The default implementation is to do nothing.
   *
   * @throws Exception
   *           If this default behavior provider could not be
   *           initialized.
   */
  protected void initialize() throws Exception {
    // Default implementation is to do nothing.
  }
}
opendj-admin/src/main/java/org/opends/server/admin/DefaultBehaviorProviderVisitor.java
New file
@@ -0,0 +1,116 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * A visitor of default behavior providers, in the style of the visitor design
 * pattern. Classes implementing this interface can query default behavior
 * providers in a type-safe manner when the kind of default behavior provider
 * is unknown at compile time. When a visitor is passed to a default behavior
 * provider's accept method, the corresponding visit method most applicable to
 * that default behavior provider is invoked.
 *
 * @param <T>
 *          The type of values represented by the default value provider.
 * @param <R>
 *          The return type of this visitor's methods. Use
 *          {@link java.lang.Void} for visitors that do not need to return
 *          results.
 * @param <P>
 *          The type of the additional parameter to this visitor's methods. Use
 *          {@link java.lang.Void} for visitors that do not need an additional
 *          parameter.
 */
public interface DefaultBehaviorProviderVisitor<T, R, P> {
  /**
   * Visit an absolute inherited default behavior provider.
   *
   * @param d
   *          The absolute inherited default behavior provider to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  R visitAbsoluteInherited(AbsoluteInheritedDefaultBehaviorProvider<T> d, P p);
  /**
   * Visit an alias default behavior provider.
   *
   * @param d
   *          The alias default behavior provider to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  R visitAlias(AliasDefaultBehaviorProvider<T> d, P p);
  /**
   * Visit an defined default behavior provider.
   *
   * @param d
   *          The defined default behavior provider to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  R visitDefined(DefinedDefaultBehaviorProvider<T> d, P p);
  /**
   * Visit a relative inherited default behavior provider.
   *
   * @param d
   *          The relative inherited default behavior provider to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  R visitRelativeInherited(RelativeInheritedDefaultBehaviorProvider<T> d, P p);
  /**
   * Visit an undefined default behavior provider.
   *
   * @param d
   *          The undefined default behavior provider to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  R visitUndefined(UndefinedDefaultBehaviorProvider<T> d, P p);
}
opendj-admin/src/main/java/org/opends/server/admin/DefaultManagedObject.java
New file
@@ -0,0 +1,200 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
/**
 * A default managed object which should be created when a parent
 * managed object is created. Default managed objects are associated
 * with a {@link RelationDefinition}.
 *
 * @param <C>
 *          The type of client default managed object configuration.
 * @param <S>
 *          The type of server default managed object configuration.
 */
public final class DefaultManagedObject
    <C extends ConfigurationClient, S extends Configuration>
    implements PropertyProvider {
  /**
   * An interface for incrementally constructing default managed
   * objects.
   *
   * @param <C>
   *          The type of client default managed object configuration.
   * @param <S>
   *          The type of server default managed object configuration.
   */
  public static final class Builder
      <C extends ConfigurationClient, S extends Configuration> {
    // The default managed object's definition.
    private final ManagedObjectDefinition<C, S> definition;
    // The string encoded default managed object's properties.
    private final Map<String, List<String>> propertyStringValues =
      new HashMap<String, List<String>>();
    /**
     * Creates a new default managed object builder.
     *
     * @param definition
     *          The default managed object's definition.
     */
    public Builder(ManagedObjectDefinition<C, S> definition) {
      this.definition = definition;
    }
    /**
     * Construct a default managed object based on the properties of
     * this builder.
     *
     * @return Returns the new default managed object.
     */
    public DefaultManagedObject<C, S> getInstance() {
      return new DefaultManagedObject<C, S>(definition, propertyStringValues);
    }
    /**
     * Defines a property's values for the default managed object.
     *
     * @param name
     *          The name of the property.
     * @param values
     *          One or more property values in the string
     *          representation.
     */
    public void setPropertyValues(String name, String... values) {
      if (values == null || values.length == 0) {
        throw new IllegalArgumentException(
            "null or empty values specified for property " + name);
      }
      propertyStringValues.put(name, Arrays.asList(values));
    }
  }
  // The default managed object's definition.
  private final ManagedObjectDefinition<C, S> definition;
  // The string encoded default managed object's properties.
  private final Map<String, List<String>> propertyStringValues;
  // Private constructor.
  private DefaultManagedObject(ManagedObjectDefinition<C, S> definition,
      Map<String, List<String>> propertyStringValues) {
    this.definition = definition;
    this.propertyStringValues = propertyStringValues;
  }
  /**
   * Gets the managed object definition associated with this default
   * managed object.
   *
   * @return Returns the managed object definition associated with
   *         this default managed object.
   */
  public ManagedObjectDefinition<C, S> getManagedObjectDefinition() {
    return definition;
  }
  /**
   * Gets a mutable copy of the set of property values for the
   * specified property.
   *
   * @param <T>
   *          The type of the property to be retrieved.
   * @param pd
   *          The property to be retrieved.
   * @return Returns a newly allocated set containing a copy of the
   *         property's values. An empty set indicates that the
   *         property has no values defined and any default behavior
   *         is applicable.
   * @throws IllegalArgumentException
   *           If the property definition is not associated with this
   *           managed object's definition.
   */
  public <T> SortedSet<T> getPropertyValues(PropertyDefinition<T> pd)
      throws IllegalArgumentException {
    // Validate the property definition.
    definition.getPropertyDefinition(pd.getName());
    // Do a defensive copy.
    SortedSet<T> values = new TreeSet<T>(pd);
    List<String> stringValues = propertyStringValues.get(pd.getName());
    if (stringValues != null) {
      for (String stringValue : stringValues) {
        values.add(pd.decodeValue(stringValue));
      }
    }
    return values;
  }
  /**
   * Performs run-time initialization of properties.
   *
   * @throws Exception
   *           If this default managed object could not be
   *           initialized.
   */
  void initialize() throws Exception {
    // FIXME: it would be nice if we could decode all property values
    // at this point. However this is not possible on the server side
    // since some properties will be determined to be invalid since
    // the schema is not loaded.
    // Validate provided property names.
    for (String name : propertyStringValues.keySet()) {
      definition.getPropertyDefinition(name);
    }
  }
}
opendj-admin/src/main/java/org/opends/server/admin/DefinedDefaultBehaviorProvider.java
New file
@@ -0,0 +1,93 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
/**
 * A default behavior provider which represents a well-defined set of default
 * values. It should be used by properties which have default value(s) which are
 * valid value(s) according to the constraints of the property's definition.
 *
 * @param <T>
 *          The type of values represented by this provider.
 */
public final class DefinedDefaultBehaviorProvider<T> extends
    DefaultBehaviorProvider<T> {
  // The collection of default values.
  private final Collection<String> values;
  /**
   * Create a new defined default behavior provider associated with the
   * specified list of values.
   *
   * @param values
   *          The list of values (must be non-<code>null</code> and not
   *          empty) in their string representation.
   * @throws IllegalArgumentException
   *           If the list of values was <code>null</code> or empty.
   */
  public DefinedDefaultBehaviorProvider(String... values)
      throws IllegalArgumentException {
    if (values == null || values.length == 0) {
      throw new IllegalArgumentException(
          "Null or empty list of default values");
    }
    this.values = Arrays.asList(values);
  }
  /**
   * {@inheritDoc}
   */
  public <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p) {
    return v.visitDefined(this, p);
  }
  /**
   * Get a copy of the default values.
   *
   * @return Returns a newly allocated collection containing a copy of the
   *         default values.
   */
  public Collection<String> getDefaultValues() {
    return new ArrayList<String>(values);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/DefinitionDecodingException.java
New file
@@ -0,0 +1,136 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
import org.opends.messages.Message;
/**
 * The requested managed object was found but its type could not be
 * determined.
 */
public class DefinitionDecodingException extends DecodingException {
  /**
   * An enumeration defining the reasons why the definition could not
   * be resolved.
   */
  public static enum Reason {
    /**
     * The managed object could be found but its type resolved to an
     * abstract managed object definition.
     */
    ABSTRACT_TYPE_INFORMATION(),
    /**
     * The managed object could be found but did not contain any type
     * information (eg missing object classes in LDAP).
     */
    NO_TYPE_INFORMATION(),
    /**
     * The managed object could be found but did not contain the
     * expected type information (eg incorrect object classes in
     * LDAP).
     */
    WRONG_TYPE_INFORMATION();
  }
  /**
   * Version ID required by serializable classes.
   */
  private static final long serialVersionUID = 3459033551415663416L;
  // Create the message.
  private static Message createMessage(AbstractManagedObjectDefinition<?, ?> d,
      Reason reason) {
    Message ufn = d.getUserFriendlyName();
    switch (reason) {
    case NO_TYPE_INFORMATION:
      return ERR_DECODING_EXCEPTION_NO_TYPE_INFO.get(ufn);
    case WRONG_TYPE_INFORMATION:
      return ERR_DECODING_EXCEPTION_WRONG_TYPE_INFO.get(ufn);
    default:
      return ERR_DECODING_EXCEPTION_ABSTRACT_TYPE_INFO.get(ufn);
    }
  }
  // The expected type of managed object.
  private final AbstractManagedObjectDefinition<?, ?> d;
  // The reason why the definition could not be determined.
  private final Reason reason;
  /**
   * Create a new definition decoding exception.
   *
   * @param d
   *          The expected type of managed object.
   * @param reason
   *          The reason why the definition could not be determined.
   */
  public DefinitionDecodingException(AbstractManagedObjectDefinition<?, ?> d,
      Reason reason) {
    super(createMessage(d, reason));
    this.d = d;
    this.reason = reason;
  }
  /**
   * Gets the expected managed object definition.
   *
   * @return Returns the expected managed object definition.
   */
  public AbstractManagedObjectDefinition<?, ?> getManagedObjectDefinition() {
    return d;
  }
  /**
   * Gets the reason why the definition could not be determined.
   *
   * @return Returns the reason why the definition could not be
   *         determined.
   */
  public Reason getReason() {
    return reason;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/DefinitionResolver.java
New file
@@ -0,0 +1,72 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * This interface is used to determine the "best match" managed object
 * definition in a definition hierarchy.
 * <p>
 * Managed object definitions, like Java classes, are arranged in an
 * inheritance hierarchy. When managed objects are decoded (e.g. from
 * LDAP entries), the driver implementation is provided with an
 * "expected managed object definition". However, the actual decoded
 * managed object is often an instance of a sub-type of this
 * definition. For example, when decoding a connection handler managed
 * object, the actual type can never be a connection handler because
 * it is an abstract managed object type. Instead, the decoded managed
 * object must be a "concrete" sub-type: an LDAP connection handler or
 * JMX connection handler.
 * <p>
 * This resolution process is coordinated by the
 * <code>resolveManagedObjectDefinition</code> method in managed
 * object definitions, where it is passed a
 * <code>DefinitionResolver</code> implementation. The
 * <code>resolveManagedObjectDefinition</code> method takes care of
 * recursively descending through the definition hierarchy and invokes
 * the {@link #matches(AbstractManagedObjectDefinition)} method
 * against each potential sub-type. It is the job of the resolver to
 * indicate whether the provided managed object definition is a
 * candidate definition. For example, the LDAP driver provides a
 * definition resolver which uses the decoded LDAP entry's object
 * classes to determine the final appropriate managed object
 * definition.
 */
public interface DefinitionResolver {
  /**
   * Determines whether or not the provided managed object definition matches
   * this resolver's criteria.
   *
   * @param d
   *          The managed object definition.
   * @return Returns <code>true</code> if the the provided managed object
   *         definition matches this resolver's criteria.
   */
  boolean matches(AbstractManagedObjectDefinition<?, ?> d);
}
opendj-admin/src/main/java/org/opends/server/admin/DurationPropertyDefinition.java
New file
@@ -0,0 +1,609 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.server.util.Validator.*;
import java.util.EnumSet;
/**
 * Duration property definition.
 * <p>
 * A duration property definition comprises of:
 * <ul>
 * <li>a <i>base unit</i> - specifies the minimum granularity which
 * can be used to specify duration property values. For example, if
 * the base unit is in seconds then values represented in milliseconds
 * will not be permitted. The default base unit is seconds
 * <li>an optional <i>maximum unit</i> - specifies the biggest
 * duration unit which can be used to specify duration property
 * values. Values presented in units greater than this unit will not
 * be permitted. There is no default maximum unit
 * <li><i>lower limit</i> - specifies the smallest duration
 * permitted by the property. The default lower limit is 0 and can
 * never be less than 0
 * <li>an optional <i>upper limit</i> - specifies the biggest
 * duration permitted by the property. By default, there is no upper
 * limit
 * <li>support for <i>unlimited</i> durations - when permitted users
 * can specify "unlimited" durations. These are represented using the
 * decoded value, -1, or the encoded string value "unlimited". By
 * default, unlimited durations are not permitted. In addition, it is
 * not possible to define an upper limit and support unlimited values.
 * </ul>
 * Decoded values are represented using <code>long</code> values in
 * the base unit defined for the duration property definition.
 */
public final class DurationPropertyDefinition extends PropertyDefinition<Long> {
  // String used to represent unlimited durations.
  private static final String UNLIMITED = "unlimited";
  // The base unit for this property definition.
  private final DurationUnit baseUnit;
  // The optional maximum unit for this property definition.
  private final DurationUnit maximumUnit;
  // The lower limit of the property value in milli-seconds.
  private final long lowerLimit;
  // The optional upper limit of the property value in milli-seconds.
  private final Long upperLimit;
  // Indicates whether this property allows the use of the "unlimited"
  // duration value (represented using a -1L or the string
  // "unlimited").
  private final boolean allowUnlimited;
  /**
   * An interface for incrementally constructing duration property
   * definitions.
   */
  public static class Builder extends
      AbstractBuilder<Long, DurationPropertyDefinition> {
    // The base unit for this property definition.
    private DurationUnit baseUnit = DurationUnit.SECONDS;
    // The optional maximum unit for this property definition.
    private DurationUnit maximumUnit = null;
    // The lower limit of the property value in milli-seconds.
    private long lowerLimit = 0L;
    // The optional upper limit of the property value in
    // milli-seconds.
    private Long upperLimit = null;
    // Indicates whether this property allows the use of the
    // "unlimited" duration value (represented using a -1L or the
    // string "unlimited").
    private boolean allowUnlimited = false;
    // Private constructor
    private Builder(AbstractManagedObjectDefinition<?, ?> d,
        String propertyName) {
      super(d, propertyName);
    }
    /**
     * Set the base unit for this property definition (values
     * including limits are specified in this unit). By default a
     * duration property definition uses seconds.
     *
     * @param unit
     *          The string representation of the base unit (must not
     *          be <code>null</code>).
     * @throws IllegalArgumentException
     *           If the provided unit name did not correspond to a
     *           known duration unit, or if the base unit is bigger
     *           than the maximum unit.
     */
    public final void setBaseUnit(String unit) throws IllegalArgumentException {
      ensureNotNull(unit);
      setBaseUnit(DurationUnit.getUnit(unit));
    }
    /**
     * Set the base unit for this property definition (values
     * including limits are specified in this unit). By default a
     * duration property definition uses seconds.
     *
     * @param unit
     *          The base unit (must not be <code>null</code>).
     * @throws IllegalArgumentException
     *           If the provided base unit is bigger than the maximum
     *           unit.
     */
    public final void setBaseUnit(DurationUnit unit)
        throws IllegalArgumentException {
      ensureNotNull(unit);
      // Make sure that the base unit is not bigger than the maximum
      // unit.
      if (maximumUnit != null) {
        if (unit.getDuration() > maximumUnit.getDuration()) {
          throw new IllegalArgumentException(
              "Base unit greater than maximum unit");
        }
      }
      this.baseUnit = unit;
    }
    /**
     * Set the maximum unit for this property definition. By default
     * there is no maximum unit.
     *
     * @param unit
     *          The string representation of the maximum unit, or
     *          <code>null</code> if there should not be a maximum
     *          unit.
     * @throws IllegalArgumentException
     *           If the provided unit name did not correspond to a
     *           known duration unit, or if the maximum unit is
     *           smaller than the base unit.
     */
    public final void setMaximumUnit(String unit)
        throws IllegalArgumentException {
      if (unit == null) {
        setMaximumUnit((DurationUnit) null);
      } else {
        setMaximumUnit(DurationUnit.getUnit(unit));
      }
    }
    /**
     * Set the maximum unit for this property definition. By default
     * there is no maximum unit.
     *
     * @param unit
     *          The maximum unit, or <code>null</code> if there
     *          should not be a maximum unit.
     * @throws IllegalArgumentException
     *           If the provided maximum unit is smaller than the base
     *           unit.
     */
    public final void setMaximumUnit(DurationUnit unit)
        throws IllegalArgumentException {
      if (unit != null) {
        // Make sure that the maximum unit is not smaller than the
        // base unit.
        if (unit.getDuration() < baseUnit.getDuration()) {
          throw new IllegalArgumentException(
              "Maximum unit smaller than base unit");
        }
      }
      this.maximumUnit = unit;
    }
    /**
     * Set the lower limit in milli-seconds.
     *
     * @param lowerLimit
     *          The new lower limit (must be >= 0) in milli-seconds.
     * @throws IllegalArgumentException
     *           If a negative lower limit was specified, or the lower
     *           limit is greater than the upper limit.
     */
    public final void setLowerLimit(long lowerLimit)
        throws IllegalArgumentException {
      if (lowerLimit < 0) {
        throw new IllegalArgumentException("Negative lower limit");
      }
      if (upperLimit != null && lowerLimit > upperLimit) {
        throw new IllegalArgumentException(
            "Lower limit greater than upper limit");
      }
      this.lowerLimit = lowerLimit;
    }
    /**
     * Set the lower limit using a string representation of the limit.
     * If the string does not specify a unit, the current base unit
     * will be used.
     *
     * @param lowerLimit
     *          The string representation of the new lower limit.
     * @throws IllegalArgumentException
     *           If the lower limit could not be parsed, or if a
     *           negative lower limit was specified, or the lower
     *           limit is greater than the upper limit.
     */
    public final void setLowerLimit(String lowerLimit)
        throws IllegalArgumentException {
      setLowerLimit(DurationUnit.parseValue(lowerLimit, baseUnit));
    }
    /**
     * Set the upper limit in milli-seconds.
     *
     * @param upperLimit
     *          The new upper limit in milli-seconds, or
     *          <code>null</code> if there is no upper limit.
     * @throws IllegalArgumentException
     *           If a negative upper limit was specified, or the lower
     *           limit is greater than the upper limit or unlimited
     *           durations are permitted.
     */
    public final void setUpperLimit(Long upperLimit)
        throws IllegalArgumentException {
      if (upperLimit != null) {
        if (upperLimit < 0) {
          throw new IllegalArgumentException("Negative upper limit");
        }
        if (lowerLimit > upperLimit) {
          throw new IllegalArgumentException(
              "Lower limit greater than upper limit");
        }
        if (allowUnlimited) {
          throw new IllegalArgumentException(
              "Upper limit specified when unlimited durations are permitted");
        }
      }
      this.upperLimit = upperLimit;
    }
    /**
     * Set the upper limit using a string representation of the limit.
     * If the string does not specify a unit, the current base unit
     * will be used.
     *
     * @param upperLimit
     *          The string representation of the new upper limit, or
     *          <code>null</code> if there is no upper limit.
     * @throws IllegalArgumentException
     *           If the upper limit could not be parsed, or if the
     *           lower limit is greater than the upper limit.
     */
    public final void setUpperLimit(String upperLimit)
        throws IllegalArgumentException {
      if (upperLimit == null) {
        setUpperLimit((Long) null);
      } else {
        setUpperLimit(DurationUnit.parseValue(upperLimit, baseUnit));
      }
    }
    /**
     * Specify whether or not this property definition will allow
     * unlimited values (default is false).
     *
     * @param allowUnlimited
     *          <code>true</code> if the property will allow
     *          unlimited values, or <code>false</code> otherwise.
     * @throws IllegalArgumentException
     *           If unlimited values are to be permitted but there is
     *           an upper limit specified.
     */
    public final void setAllowUnlimited(boolean allowUnlimited)
        throws IllegalArgumentException {
      if (allowUnlimited && upperLimit != null) {
        throw new IllegalArgumentException(
            "Upper limit specified when unlimited durations are permitted");
      }
      this.allowUnlimited = allowUnlimited;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected DurationPropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<Long> defaultBehavior) {
      return new DurationPropertyDefinition(d, propertyName, options,
          adminAction, defaultBehavior, baseUnit, maximumUnit, lowerLimit,
          upperLimit, allowUnlimited);
    }
  }
  /**
   * Create a duration property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new integer property definition builder.
   */
  public static Builder createBuilder(AbstractManagedObjectDefinition<?, ?> d,
      String propertyName) {
    return new Builder(d, propertyName);
  }
  // Private constructor.
  private DurationPropertyDefinition(AbstractManagedObjectDefinition<?, ?> d,
      String propertyName, EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<Long> defaultBehavior, DurationUnit baseUnit,
      DurationUnit maximumUnit, Long lowerLimit, Long upperLimit,
      boolean allowUnlimited) {
    super(d, Long.class, propertyName, options, adminAction, defaultBehavior);
    this.baseUnit = baseUnit;
    this.maximumUnit = maximumUnit;
    this.lowerLimit = lowerLimit;
    this.upperLimit = upperLimit;
    this.allowUnlimited = allowUnlimited;
  }
  /**
   * Get the base unit for this property definition (values including
   * limits are specified in this unit).
   *
   * @return Returns the base unit for this property definition
   *         (values including limits are specified in this unit).
   */
  public DurationUnit getBaseUnit() {
    return baseUnit;
  }
  /**
   * Get the maximum unit for this property definition if specified.
   *
   * @return Returns the maximum unit for this property definition, or
   *         <code>null</code> if there is no maximum unit.
   */
  public DurationUnit getMaximumUnit() {
    return maximumUnit;
  }
  /**
   * Get the lower limit in milli-seconds.
   *
   * @return Returns the lower limit in milli-seconds.
   */
  public long getLowerLimit() {
    return lowerLimit;
  }
  /**
   * Get the upper limit in milli-seconds.
   *
   * @return Returns the upper limit in milli-seconds, or
   *         <code>null</code> if there is no upper limit.
   */
  public Long getUpperLimit() {
    return upperLimit;
  }
  /**
   * Determine whether this property allows unlimited durations.
   *
   * @return Returns <code>true</code> if this this property allows
   *         unlimited durations.
   */
  public boolean isAllowUnlimited() {
    return allowUnlimited;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(Long value) throws IllegalPropertyValueException {
    ensureNotNull(value);
    long nvalue = baseUnit.toMilliSeconds(value);
    if (!allowUnlimited && nvalue < lowerLimit) {
      throw new IllegalPropertyValueException(this, value);
      // unlimited allowed
    } else if (nvalue >= 0 && nvalue < lowerLimit) {
      throw new IllegalPropertyValueException(this, value);
    }
    if ((upperLimit != null) && (nvalue > upperLimit)) {
      throw new IllegalPropertyValueException(this, value);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String encodeValue(Long value) throws IllegalPropertyValueException {
    ensureNotNull(value);
    // Make sure that we correctly encode negative values as
    // "unlimited".
    if (allowUnlimited) {
      if (value < 0) {
        return UNLIMITED;
      }
    }
    // Encode the size value using the base unit.
    StringBuilder builder = new StringBuilder();
    builder.append(value);
    builder.append(' ');
    builder.append(baseUnit.toString());
    return builder.toString();
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public Long decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    // First check for the special "unlimited" value when necessary.
    if (allowUnlimited) {
      if (value.trim().equalsIgnoreCase(UNLIMITED)) {
        return -1L;
      }
    }
    // Parse the string representation.
    long ms;
    try {
      ms = DurationUnit.parseValue(value);
    } catch (NumberFormatException e) {
      throw new IllegalPropertyValueStringException(this, value);
    }
    // Check the unit is in range - values must not be more granular
    // than the base unit.
    if ((ms % baseUnit.getDuration()) != 0) {
      throw new IllegalPropertyValueStringException(this, value);
    }
    // Convert the value a long in the property's required unit.
    Long i = (long) baseUnit.fromMilliSeconds(ms);
    try {
      validateValue(i);
    } catch (IllegalPropertyValueException e) {
      throw new IllegalPropertyValueStringException(this, value);
    }
    return i;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitDuration(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, Long value, P p) {
    return v.visitDuration(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void toString(StringBuilder builder) {
    super.toString(builder);
    builder.append(" baseUnit=");
    builder.append(baseUnit);
    if (maximumUnit != null) {
      builder.append(" maximumUnit=");
      builder.append(maximumUnit);
    }
    builder.append(" lowerLimit=");
    builder.append(lowerLimit);
    builder.append("ms");
    if (upperLimit != null) {
      builder.append(" upperLimit=");
      builder.append(upperLimit);
      builder.append("ms");
    }
    builder.append(" allowUnlimited=");
    builder.append(allowUnlimited);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int compare(Long o1, Long o2) {
    return o1.compareTo(o2);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/DurationUnit.java
New file
@@ -0,0 +1,385 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * This enumeration defines various duration units.
 */
public enum DurationUnit {
  /**
   * A day unit.
   */
  DAYS((long) 24 * 60 * 60 * 1000, "d", "days"),
  /**
   * An hour unit.
   */
  HOURS((long) 60 * 60 * 1000, "h", "hours"),
  /**
   * A millisecond unit.
   */
  MILLI_SECONDS(1L, "ms", "milliseconds"),
  /**
   * A minute unit.
   */
  MINUTES((long) 60 * 1000, "m", "minutes"),
  /**
   * A second unit.
   */
  SECONDS(1000L, "s", "seconds"),
  /**
   * A week unit.
   */
  WEEKS((long) 7 * 24 * 60 * 60 * 1000, "w", "weeks");
  // A lookup table for resolving a unit from its name.
  private static final Map<String, DurationUnit> nameToUnit;
  static {
    nameToUnit = new HashMap<String, DurationUnit>();
    for (DurationUnit unit : DurationUnit.values()) {
      nameToUnit.put(unit.shortName, unit);
      nameToUnit.put(unit.longName, unit);
    }
  }
  /**
   * Get the unit corresponding to the provided unit name.
   *
   * @param s
   *          The name of the unit. Can be the abbreviated or long
   *          name and can contain white space and mixed case
   *          characters.
   * @return Returns the unit corresponding to the provided unit name.
   * @throws IllegalArgumentException
   *           If the provided name did not correspond to a known
   *           duration unit.
   */
  public static DurationUnit getUnit(String s) throws IllegalArgumentException {
    DurationUnit unit = nameToUnit.get(s.trim().toLowerCase());
    if (unit == null) {
      throw new IllegalArgumentException("Illegal duration unit \"" + s + "\"");
    }
    return unit;
  }
  /**
   * Parse the provided duration string and return its equivalent
   * duration in milliseconds. The duration string must specify the
   * unit e.g. "10s". This method will parse duration string
   * representations produced from the {@link #toString(long)} method.
   * Therefore, a duration can comprise of multiple duration
   * specifiers, for example <code>1d15m25s</code>.
   *
   * @param s
   *          The duration string to be parsed.
   * @return Returns the parsed duration in milliseconds.
   * @throws NumberFormatException
   *           If the provided duration string could not be parsed.
   * @see #toString(long)
   */
  public static long parseValue(String s) throws NumberFormatException {
    return parseValue(s, null);
  }
  /**
   * Parse the provided duration string and return its equivalent
   * duration in milliseconds. This method will parse duration string
   * representations produced from the {@link #toString(long)} method.
   * Therefore, a duration can comprise of multiple duration
   * specifiers, for example <code>1d15m25s</code>.
   *
   * @param s
   *          The duration string to be parsed.
   * @param defaultUnit
   *          The default unit to use if there is no unit specified in
   *          the duration string, or <code>null</code> if the
   *          string must always contain a unit.
   * @return Returns the parsed duration in milliseconds.
   * @throws NumberFormatException
   *           If the provided duration string could not be parsed.
   * @see #toString(long)
   */
  public static long parseValue(String s, DurationUnit defaultUnit)
      throws NumberFormatException {
    String ns = s.trim();
    if (ns.length() == 0) {
      throw new NumberFormatException("Empty duration value \"" + s + "\"");
    }
    Pattern p1 = Pattern.compile("^\\s*((\\d+)\\s*w)?" + "\\s*((\\d+)\\s*d)?"
        + "\\s*((\\d+)\\s*h)?" + "\\s*((\\d+)\\s*m)?" + "\\s*((\\d+)\\s*s)?"
        + "\\s*((\\d+)\\s*ms)?\\s*$", Pattern.CASE_INSENSITIVE);
    Matcher m1 = p1.matcher(ns);
    if (m1.matches()) {
      // Value must be of the form produced by toString(long).
      String weeks = m1.group(2);
      String days = m1.group(4);
      String hours = m1.group(6);
      String minutes = m1.group(8);
      String seconds = m1.group(10);
      String ms = m1.group(12);
      long duration = 0;
      try {
        if (weeks != null) {
          duration += Long.valueOf(weeks) * WEEKS.getDuration();
        }
        if (days != null) {
          duration += Long.valueOf(days) * DAYS.getDuration();
        }
        if (hours != null) {
          duration += Long.valueOf(hours) * HOURS.getDuration();
        }
        if (minutes != null) {
          duration += Long.valueOf(minutes) * MINUTES.getDuration();
        }
        if (seconds != null) {
          duration += Long.valueOf(seconds) * SECONDS.getDuration();
        }
        if (ms != null) {
          duration += Long.valueOf(ms) * MILLI_SECONDS.getDuration();
        }
      } catch (NumberFormatException e) {
        throw new NumberFormatException("Invalid duration value \"" + s + "\"");
      }
      return duration;
    } else {
      // Value must be a floating point number followed by a unit.
      Pattern p2 = Pattern.compile("^\\s*(\\d+(\\.\\d+)?)\\s*(\\w+)?\\s*$");
      Matcher m2 = p2.matcher(ns);
      if (!m2.matches()) {
        throw new NumberFormatException("Invalid duration value \"" + s + "\"");
      }
      // Group 1 is the float.
      double d;
      try {
        d = Double.valueOf(m2.group(1));
      } catch (NumberFormatException e) {
        throw new NumberFormatException("Invalid duration value \"" + s + "\"");
      }
      // Group 3 is the unit.
      String unitString = m2.group(3);
      DurationUnit unit;
      if (unitString == null) {
        if (defaultUnit == null) {
          throw new NumberFormatException("Invalid duration value \"" + s
              + "\"");
        } else {
          unit = defaultUnit;
        }
      } else {
        try {
          unit = getUnit(unitString);
        } catch (IllegalArgumentException e) {
          throw new NumberFormatException("Invalid duration value \"" + s
              + "\"");
        }
      }
      return unit.toMilliSeconds(d);
    }
  }
  /**
   * Returns a string representation of the provided duration. The
   * string representation can be parsed using the
   * {@link #parseValue(String)} method. The string representation is
   * comprised of one or more of the number of weeks, days, hours,
   * minutes, seconds, and milliseconds. Here are some examples:
   *
   * <pre>
   * toString(0)       // 0 ms
   * toString(999)     // 999 ms
   * toString(1000)    // 1 s
   * toString(1500)    // 1 s 500 ms
   * toString(3650000) // 1 h 50 s
   * toString(3700000) // 1 h 1 m 40 s
   * </pre>
   *
   * @param duration
   *          The duration in milliseconds.
   * @return Returns a string representation of the provided duration.
   * @throws IllegalArgumentException
   *           If the provided duration is negative.
   * @see #parseValue(String)
   * @see #parseValue(String, DurationUnit)
   */
  public static String toString(long duration) throws IllegalArgumentException {
    if (duration < 0) {
      throw new IllegalArgumentException("Negative duration " + duration);
    }
    if (duration == 0) {
      return "0 ms";
    }
    DurationUnit[] units = new DurationUnit[] { WEEKS, DAYS, HOURS, MINUTES,
        SECONDS, MILLI_SECONDS };
    long remainder = duration;
    StringBuilder builder = new StringBuilder();
    boolean isFirst = true;
    for (DurationUnit unit : units) {
      long count = remainder / unit.getDuration();
      if (count > 0) {
        if (!isFirst) {
          builder.append(' ');
        }
        builder.append(count);
        builder.append(' ');
        builder.append(unit.getShortName());
        remainder = remainder - (count * unit.getDuration());
        isFirst = false;
      }
    }
    return builder.toString();
  }
  // The long name of the unit.
  private final String longName;
  // The abbreviation of the unit.
  private final String shortName;
  // The size of the unit in milliseconds.
  private final long sz;
  // Private constructor.
  private DurationUnit(long sz, String shortName, String longName) {
    this.sz = sz;
    this.shortName = shortName;
    this.longName = longName;
  }
  /**
   * Converts the specified duration in milliseconds to this unit.
   *
   * @param duration
   *          The duration in milliseconds.
   * @return Returns milliseconds in this unit.
   */
  public double fromMilliSeconds(long duration) {
    return ((double) duration / sz);
  }
  /**
   * Get the number of milliseconds that this unit represents.
   *
   * @return Returns the number of milliseconds that this unit
   *         represents.
   */
  public long getDuration() {
    return sz;
  }
  /**
   * Get the long name of this unit.
   *
   * @return Returns the long name of this unit.
   */
  public String getLongName() {
    return longName;
  }
  /**
   * Get the abbreviated name of this unit.
   *
   * @return Returns the abbreviated name of this unit.
   */
  public String getShortName() {
    return shortName;
  }
  /**
   * Converts the specified duration in this unit to milliseconds.
   *
   * @param duration
   *          The duration as a quantity of this unit.
   * @return Returns the number of milliseconds that the duration
   *         represents.
   */
  public long toMilliSeconds(double duration) {
    return (long) (sz * duration);
  }
  /**
   * {@inheritDoc}
   * <p>
   * This implementation returns the abbreviated name of this duration
   * unit.
   */
  @Override
  public String toString() {
    return shortName;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/EnumPropertyDefinition.java
New file
@@ -0,0 +1,275 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import static org.opends.server.util.Validator.ensureNotNull;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
/**
 * Enumeration property definition.
 *
 * @param <E>
 *          The enumeration that should be used for values of this
 *          property definition.
 */
public final class EnumPropertyDefinition<E extends Enum<E>> extends
    PropertyDefinition<E> {
  /**
   * An interface for incrementally constructing enumeration property
   * definitions.
   *
   * @param <E>
   *          The enumeration that should be used for values of this
   *          property definition.
   */
  public static class Builder<E extends Enum<E>> extends
      AbstractBuilder<E, EnumPropertyDefinition<E>> {
    // The enumeration class.
    private Class<E> enumClass;
    // Private constructor
    private Builder(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
      super(d, propertyName);
      this.enumClass = null;
    }
    /**
     * Set the enumeration class which should be used for values of
     * this property definition.
     *
     * @param enumClass
     *          The enumeration class which should be used for values
     *          of this property definition.
     */
    public final void setEnumClass(Class<E> enumClass) {
      this.enumClass = enumClass;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected EnumPropertyDefinition<E> buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<E> defaultBehavior) {
      // Make sure that the enumeration class has been defined.
      if (enumClass == null) {
        throw new IllegalStateException("Enumeration class undefined");
      }
      return new EnumPropertyDefinition<E>(d, propertyName, options,
          adminAction, defaultBehavior, enumClass);
    }
  }
  /**
   * Create an enumeration property definition builder.
   *
   * @param <E>
   *          The enumeration that should be used for values of this
   *          property definition.
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new enumeration property definition builder.
   */
  public static <E extends Enum<E>> Builder<E> createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder<E>(d, propertyName);
  }
  // The enumeration class.
  private final Class<E> enumClass;
  // Map used for decoding values.
  private final Map<String, E> decodeMap;
  // Private constructor.
  private EnumPropertyDefinition(AbstractManagedObjectDefinition<?, ?> d,
      String propertyName, EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<E> defaultBehavior, Class<E> enumClass) {
    super(d, enumClass, propertyName, options, adminAction, defaultBehavior);
    this.enumClass = enumClass;
    // Initialize the decoding map.
    this.decodeMap = new HashMap<String, E>();
    for (E value : EnumSet.<E> allOf(enumClass)) {
      String s = value.toString().trim().toLowerCase();
      this.decodeMap.put(s, value);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitEnum(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, E value, P p) {
    return v.visitEnum(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public E decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    String nvalue = value.trim().toLowerCase();
    E eValue = decodeMap.get(nvalue);
    if (eValue == null) {
      throw new IllegalPropertyValueStringException(this, value);
    } else {
      return eValue;
    }
  }
  /**
   * Get the enumeration class used for values of this property.
   *
   * @return Returns the enumeration class used for values of this
   *         property.
   */
  public Class<E> getEnumClass() {
    return enumClass;
  }
  /**
   * Gets the synopsis of the specified enumeration value of this
   * enumeration property definition in the default locale.
   *
   * @param value
   *          The enumeration value.
   * @return Returns the synopsis of the specified enumeration value
   *         of this enumeration property definition in the default
   *         locale.
   */
  public final Message getValueSynopsis(E value) {
    return getValueSynopsis(Locale.getDefault(), value);
  }
  /**
   * Gets the synopsis of the specified enumeration value of this
   * enumeration property definition in the specified locale.
   *
   * @param value
   *          The enumeration value.
   * @param locale
   *          The locale.
   * @return Returns the synopsis of the specified enumeration value
   *         of this enumeration property definition in the specified
   *         locale.
   */
  public final Message getValueSynopsis(Locale locale, E value) {
    ManagedObjectDefinitionI18NResource resource =
      ManagedObjectDefinitionI18NResource.getInstance();
    String property = "property." + getName()
        + ".syntax.enumeration.value." + value.toString()
        + ".synopsis";
    try {
      return resource.getMessage(getManagedObjectDefinition(),
          property, locale);
    } catch (MissingResourceException e) {
      return null;
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String normalizeValue(E value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    return value.toString().trim().toLowerCase();
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(E value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    // No additional validation required.
  }
}
opendj-admin/src/main/java/org/opends/server/admin/GenericConstraint.java
New file
@@ -0,0 +1,223 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import org.opends.messages.Message;
import org.opends.server.admin.client.AuthorizationException;
import org.opends.server.admin.client.ClientConstraintHandler;
import org.opends.server.admin.client.CommunicationException;
import org.opends.server.admin.client.ManagedObject;
import org.opends.server.admin.client.ManagementContext;
import org.opends.server.admin.condition.Condition;
import org.opends.server.admin.server.ServerConstraintHandler;
import org.opends.server.admin.server.ServerManagedObject;
import org.opends.server.config.ConfigException;
/**
 * A generic constraint which comprises of an underlying condition and
 * a description. The condition must evaluate to <code>true</code>
 * in order for a new managed object to be created or modified.
 */
public class GenericConstraint extends Constraint {
  /**
   * The client-side constraint handler.
   */
  private class ClientHandler extends ClientConstraintHandler {
    // Private constructor.
    private ClientHandler() {
      // No implementation required.
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isAddAcceptable(ManagementContext context,
        ManagedObject<?> managedObject, Collection<Message> unacceptableReasons)
        throws AuthorizationException, CommunicationException {
      if (!condition.evaluate(context, managedObject)) {
        unacceptableReasons.add(getSynopsis());
        return false;
      } else {
        return true;
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isModifyAcceptable(ManagementContext context,
        ManagedObject<?> managedObject, Collection<Message> unacceptableReasons)
        throws AuthorizationException, CommunicationException {
      if (!condition.evaluate(context, managedObject)) {
        unacceptableReasons.add(getSynopsis());
        return false;
      } else {
        return true;
      }
    }
  };
  /**
   * The server-side constraint handler.
   */
  private class ServerHandler extends ServerConstraintHandler {
    // Private constructor.
    private ServerHandler() {
      // No implementation required.
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean isUsable(ServerManagedObject<?> managedObject,
        Collection<Message> unacceptableReasons) throws ConfigException {
      if (!condition.evaluate(managedObject)) {
        unacceptableReasons.add(getSynopsis());
        return false;
      } else {
        return true;
      }
    }
  };
  // The client-side constraint handler.
  private final ClientConstraintHandler clientHandler = new ClientHandler();
  // The condition associated with this constraint.
  private final Condition condition;
  // The managed object definition associated with this constraint.
  private final AbstractManagedObjectDefinition<?, ?> definition;
  // The constraint ID.
  private final int id;
  // The server-side constraint handler.
  private final ServerConstraintHandler serverHandler = new ServerHandler();
  /**
   * Creates a new generic constraint.
   *
   * @param definition
   *          The managed object definition associated with this
   *          constraint.
   * @param id
   *          The constraint ID.
   * @param condition
   *          The condition associated with this constraint.
   */
  public GenericConstraint(AbstractManagedObjectDefinition<?, ?> definition,
      int id, Condition condition) {
    this.definition = definition;
    this.id = id;
    this.condition = condition;
  }
  /**
   * {@inheritDoc}
   */
  public Collection<ClientConstraintHandler> getClientConstraintHandlers() {
    return Collections.singleton(clientHandler);
  }
  /**
   * {@inheritDoc}
   */
  public Collection<ServerConstraintHandler> getServerConstraintHandlers() {
    return Collections.singleton(serverHandler);
  }
  /**
   * Gets the synopsis of this constraint in the default locale.
   *
   * @return Returns the synopsis of this constraint in the default
   *         locale.
   */
  public final Message getSynopsis() {
    return getSynopsis(Locale.getDefault());
  }
  /**
   * Gets the synopsis of this constraint in the specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the synopsis of this constraint in the specified
   *         locale.
   */
  public final Message getSynopsis(Locale locale) {
    ManagedObjectDefinitionI18NResource resource =
      ManagedObjectDefinitionI18NResource.getInstance();
    String property = "constraint." + id + ".synopsis";
    return resource.getMessage(definition, property, locale);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected void initialize() throws Exception {
    condition.initialize(definition);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/IPAddressMaskPropertyDefinition.java
New file
@@ -0,0 +1,166 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.server.util.Validator.ensureNotNull;
import java.util.EnumSet;
import org.opends.server.config.ConfigException;
import org.opends.server.types.AddressMask;
/**
 * IP address mask property definition.
 */
public final class IPAddressMaskPropertyDefinition extends
    PropertyDefinition<AddressMask> {
  /**
   * An interface for incrementally constructing IP address mask property
   * definitions.
   */
  public static class Builder extends
      AbstractBuilder<AddressMask, IPAddressMaskPropertyDefinition> {
    // Private constructor
    private Builder(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
      super(d, propertyName);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected IPAddressMaskPropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d,
        String propertyName, EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<AddressMask> defaultBehavior) {
      return new IPAddressMaskPropertyDefinition(d, propertyName, options,
          adminAction, defaultBehavior);
    }
  }
  /**
   * Create a IP address mask property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new IP address mask property definition builder.
   */
  public static Builder createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder(d, propertyName);
  }
  // Private constructor.
  private IPAddressMaskPropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<AddressMask> defaultBehavior) {
    super(d, AddressMask.class, propertyName, options, adminAction,
        defaultBehavior);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(AddressMask value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    // No additional validation required.
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public AddressMask decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    try {
      return AddressMask.decode(value);
    } catch (ConfigException e) {
      // TODO: it would be nice to throw the cause.
      throw new IllegalPropertyValueStringException(this, value);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitIPAddressMask(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, AddressMask value, P p) {
    return v.visitIPAddressMask(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int compare(AddressMask o1, AddressMask o2) {
    return o1.toString().compareTo(o2.toString());
  }
}
opendj-admin/src/main/java/org/opends/server/admin/IPAddressPropertyDefinition.java
New file
@@ -0,0 +1,188 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.server.util.Validator.ensureNotNull;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.EnumSet;
/**
 * IP address property definition.
 */
public final class IPAddressPropertyDefinition extends
    PropertyDefinition<InetAddress> {
  /**
   * An interface for incrementally constructing IP address property
   * definitions.
   */
  public static class Builder extends
      AbstractBuilder<InetAddress, IPAddressPropertyDefinition> {
    // Private constructor
    private Builder(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
      super(d, propertyName);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected IPAddressPropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<InetAddress> defaultBehavior) {
      return new IPAddressPropertyDefinition(d, propertyName, options,
          adminAction, defaultBehavior);
    }
  }
  /**
   * Create a IP address property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new IP address property definition builder.
   */
  public static Builder createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder(d, propertyName);
  }
  // Private constructor.
  private IPAddressPropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<InetAddress> defaultBehavior) {
    super(d, InetAddress.class, propertyName, options, adminAction,
        defaultBehavior);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(InetAddress value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    // No additional validation required.
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public InetAddress decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    try {
      return InetAddress.getByName(value);
    } catch (UnknownHostException e) {
      // TODO: it would be nice to throw the cause.
      throw new IllegalPropertyValueStringException(this, value);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String encodeValue(InetAddress value)
      throws IllegalPropertyValueException {
    // We should return the host name if it is available, or the IP
    // address if not.
    // Unforunately, there is no InetAddress method for doing this, so
    // we have to resort to hacking at the toString() encoding.
    String s = value.toString();
    int i = s.indexOf('/');
    if (i > 0) {
      // Host address is before the forward slash.
      return s.substring(0, i);
    } else {
      return value.getHostAddress();
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitIPAddress(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, InetAddress value, P p) {
    return v.visitIPAddress(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int compare(InetAddress o1, InetAddress o2) {
    return o1.getHostAddress().compareTo(o2.getHostAddress());
  }
}
opendj-admin/src/main/java/org/opends/server/admin/IllegalPropertyValueException.java
New file
@@ -0,0 +1,88 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
import org.opends.messages.Message;
/**
 * Thrown to indicate that a property value was invalid according to
 * its associated property definition.
 */
public class IllegalPropertyValueException extends PropertyException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = -3145632074909281823L;
  // The illegal property value.
  private final Object value;
  /**
   * Create a new illegal property value exception.
   *
   * @param pd
   *          The property definition.
   * @param value
   *          The illegal property value.
   */
  public IllegalPropertyValueException(PropertyDefinition<?> pd, Object value) {
    super(pd, createMessage(pd, value));
    this.value = value;
  }
  /**
   * Get the illegal property value that caused the exception.
   *
   * @return Returns the illegal property value.
   */
  public final Object getIllegalValue() {
    return value;
  }
  // Create the message.
  private static Message createMessage(PropertyDefinition<?> pd, Object value) {
    PropertyDefinitionUsageBuilder builder = new PropertyDefinitionUsageBuilder(
        true);
    return ERR_ILLEGAL_PROPERTY_VALUE_EXCEPTION.get(String.valueOf(value), pd
        .getName(), builder.getUsage(pd));
  }
}
opendj-admin/src/main/java/org/opends/server/admin/IllegalPropertyValueStringException.java
New file
@@ -0,0 +1,89 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
import org.opends.messages.Message;
/**
 * Thrown to indicate that a property value string was invalid
 * according to its associated property definition.
 */
public class IllegalPropertyValueStringException extends PropertyException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = -3145632074909281823L;
  // The illegal property value string.
  private final String value;
  /**
   * Create a new illegal property value string exception.
   *
   * @param pd
   *          The property definition.
   * @param value
   *          The illegal property value string.
   */
  public IllegalPropertyValueStringException(PropertyDefinition<?> pd,
      String value) {
    super(pd, createMessage(pd, value));
    this.value = value;
  }
  /**
   * Get the illegal property value string that caused the exception.
   *
   * @return Returns the illegal property value string.
   */
  public final String getIllegalValueString() {
    return value;
  }
  // Create the message.
  private static Message createMessage(PropertyDefinition<?> pd, String value) {
    PropertyDefinitionUsageBuilder builder = new PropertyDefinitionUsageBuilder(
        true);
    return ERR_ILLEGAL_PROPERTY_VALUE_STRING_EXCEPTION.get(value, pd.getName(),
        builder.getUsage(pd));
  }
}
opendj-admin/src/main/java/org/opends/server/admin/InstantiableRelationDefinition.java
New file
@@ -0,0 +1,304 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import static org.opends.server.util.Validator.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
/**
 * A managed object composite relationship definition which represents
 * a composition of zero or more managed objects.
 *
 * @param <C>
 *          The type of client managed object configuration that this
 *          relation definition refers to.
 * @param <S>
 *          The type of server managed object configuration that this
 *          relation definition refers to.
 */
public final class InstantiableRelationDefinition
    <C extends ConfigurationClient, S extends Configuration>
    extends RelationDefinition<C, S> {
  /**
   * An interface for incrementally constructing instantiable relation
   * definitions.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this relation definition refers to.
   */
  public static final class Builder
      <C extends ConfigurationClient, S extends Configuration>
      extends AbstractBuilder<C, S, InstantiableRelationDefinition<C, S>> {
    // The optional naming property definition.
    private PropertyDefinition<?> namingPropertyDefinition = null;
    // The plural name of the relation.
    private final String pluralName;
    // The optional default managed objects associated with this
    // instantiable relation definition.
    private final Map<String, DefaultManagedObject<? extends C, ? extends S>>
      defaultManagedObjects = new HashMap<String,
        DefaultManagedObject<? extends C, ? extends S>>();
    /**
     * Creates a new builder which can be used to incrementally build
     * an instantiable relation definition.
     *
     * @param pd
     *          The parent managed object definition.
     * @param name
     *          The name of the relation.
     * @param pluralName
     *          The plural name of the relation.
     * @param cd
     *          The child managed object definition.
     */
    public Builder(AbstractManagedObjectDefinition<?, ?> pd, String name,
        String pluralName, AbstractManagedObjectDefinition<C, S> cd) {
      super(pd, name, cd);
      this.pluralName = pluralName;
    }
    /**
     * Adds the named default managed object to this instantiable
     * relation definition.
     *
     * @param name
     *          The name of the default managed object.
     * @param defaultManagedObject
     *          The default managed object.
     */
    public void setDefaultManagedObject(String name,
        DefaultManagedObject<? extends C, ? extends S> defaultManagedObject) {
      this.defaultManagedObjects.put(name, defaultManagedObject);
    }
    /**
     * Sets the naming property for the instantiable relation
     * definition.
     *
     * @param namingPropertyDefinition
     *          The property of the child managed object definition
     *          which should be used for naming, or <code>null</code>
     *          if this relation does not use a property for naming.
     */
    public void setNamingProperty(
        PropertyDefinition<?> namingPropertyDefinition) {
      ensureNotNull(namingPropertyDefinition);
      this.namingPropertyDefinition = namingPropertyDefinition;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected InstantiableRelationDefinition<C, S> buildInstance(
        Common<C, S> common) {
      return new InstantiableRelationDefinition<C, S>(common, pluralName,
          namingPropertyDefinition, defaultManagedObjects);
    }
  }
  // The optional naming property definition.
  private final PropertyDefinition<?> namingPropertyDefinition;
  // The plural name of the relation.
  private final String pluralName;
  // The optional default managed objects associated with this
  // instantiable relation definition.
  private final Map<String, DefaultManagedObject<? extends C, ? extends S>>
    defaultManagedObjects;
  // Private constructor.
  private InstantiableRelationDefinition(Common<C, S> common,
      String pluralName,
      PropertyDefinition<?> namingPropertyDefinition,
      Map<String, DefaultManagedObject<? extends C, ? extends S>>
        defaultManagedObjects) {
    super(common);
    this.pluralName = pluralName;
    this.namingPropertyDefinition = namingPropertyDefinition;
    this.defaultManagedObjects = defaultManagedObjects;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p) {
    return v.visitInstantiable(this, p);
  }
  /**
   * Gets the named default managed object associated with this
   * instantiable relation definition.
   *
   * @param name
   *          The name of the default managed object.
   * @return Returns the named default managed object.
   * @throws IllegalArgumentException
   *           If there is no default managed object associated with
   *           the provided name.
   */
  public DefaultManagedObject<? extends C, ? extends S> getDefaultManagedObject(
      String name) throws IllegalArgumentException {
    if (!defaultManagedObjects.containsKey(name)) {
      throw new IllegalArgumentException(
          "unrecognized default managed object \"" + name + "\"");
    }
    return defaultManagedObjects.get(name);
  }
  /**
   * Gets the names of the default managed objects associated with
   * this instantiable relation definition.
   *
   * @return Returns an unmodifiable set containing the names of the
   *         default managed object.
   */
  public Set<String> getDefaultManagedObjectNames() {
    return Collections.unmodifiableSet(defaultManagedObjects.keySet());
  }
  /**
   * Get the property of the child managed object definition which
   * should be used for naming children.
   *
   * @return Returns the property of the child managed object
   *         definition which should be used for naming, or
   *         <code>null</code> if this relation does not use a
   *         property for naming.
   */
  public PropertyDefinition<?> getNamingPropertyDefinition() {
    return namingPropertyDefinition;
  }
  /**
   * Get the plural name of the relation.
   *
   * @return Returns the plural name of the relation.
   */
  public String getPluralName() {
    return pluralName;
  }
  /**
   * Gets the user friendly plural name of this relation definition in
   * the default locale.
   *
   * @return Returns the user friendly plural name of this relation
   *         definition in the default locale.
   */
  public Message getUserFriendlyPluralName() {
    return getUserFriendlyPluralName(Locale.getDefault());
  }
  /**
   * Gets the user friendly plural name of this relation definition in
   * the specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the user friendly plural name of this relation
   *         definition in the specified locale.
   */
  public Message getUserFriendlyPluralName(Locale locale) {
    String property = "relation." + getName() + ".user-friendly-plural-name";
    return ManagedObjectDefinitionI18NResource.getInstance().getMessage(
        getParentDefinition(), property, locale);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void toString(StringBuilder builder) {
    builder.append("name=");
    builder.append(getName());
    builder.append(" type=collection parent=");
    builder.append(getParentDefinition().getName());
    builder.append(" child=");
    builder.append(getChildDefinition().getName());
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected void initialize() throws Exception {
    for (DefaultManagedObject<?, ?> dmo : defaultManagedObjects.values()) {
      dmo.initialize();
    }
  }
}
opendj-admin/src/main/java/org/opends/server/admin/IntegerPropertyDefinition.java
New file
@@ -0,0 +1,394 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import static org.opends.server.util.Validator.ensureNotNull;
import java.util.EnumSet;
import java.util.Locale;
import java.util.MissingResourceException;
/**
 * Integer property definition.
 * <p>
 * All values must be zero or positive and within the lower/upper limit
 * constraints. Support is provided for "unlimited" values. These are
 * represented using a negative value or using the string "unlimited".
 */
public final class IntegerPropertyDefinition extends
    PropertyDefinition<Integer> {
  // String used to represent unlimited.
  private static final String UNLIMITED = "unlimited";
  // The lower limit of the property value.
  private final int lowerLimit;
  // The optional upper limit of the property value.
  private final Integer upperLimit;
  // Indicates whether this property allows the use of the "unlimited" value
  // (represented using a -1 or the string "unlimited").
  private final boolean allowUnlimited;
  /**
   * An interface for incrementally constructing integer property definitions.
   */
  public static class Builder extends
      AbstractBuilder<Integer, IntegerPropertyDefinition> {
    // The lower limit of the property value.
    private int lowerLimit = 0;
    // The optional upper limit of the property value.
    private Integer upperLimit = null;
    // Indicates whether this property allows the use of the "unlimited" value
    // (represented using a -1 or the string "unlimited").
    private boolean allowUnlimited = false;
    // Private constructor
    private Builder(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
      super(d, propertyName);
    }
    /**
     * Set the lower limit.
     *
     * @param lowerLimit
     *          The new lower limit (must be >= 0).
     * @throws IllegalArgumentException
     *           If a negative lower limit was specified or the lower limit is
     *           greater than the upper limit.
     */
    public final void setLowerLimit(int lowerLimit)
        throws IllegalArgumentException {
      if (lowerLimit < 0) {
        throw new IllegalArgumentException("Negative lower limit");
      }
      if (upperLimit != null && lowerLimit > upperLimit) {
        throw new IllegalArgumentException(
            "Lower limit greater than upper limit");
      }
      this.lowerLimit = lowerLimit;
    }
    /**
     * Set the upper limit.
     *
     * @param upperLimit
     *          The new upper limit or <code>null</code> if there is no upper
     *          limit.
     */
    public final void setUpperLimit(Integer upperLimit) {
      if (upperLimit != null) {
        if (upperLimit < 0) {
          throw new IllegalArgumentException("Negative lower limit");
        }
        if (lowerLimit > upperLimit) {
          throw new IllegalArgumentException(
              "Lower limit greater than upper limit");
        }
      }
      this.upperLimit = upperLimit;
    }
    /**
     * Specify whether or not this property definition will allow unlimited
     * values (default is false).
     *
     * @param allowUnlimited
     *          <code>true</code> if the property will allow unlimited values,
     *          or <code>false</code> otherwise.
     */
    public final void setAllowUnlimited(boolean allowUnlimited) {
      this.allowUnlimited = allowUnlimited;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected IntegerPropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<Integer> defaultBehavior) {
      return new IntegerPropertyDefinition(d, propertyName, options,
          adminAction, defaultBehavior, lowerLimit, upperLimit, allowUnlimited);
    }
  }
  /**
   * Create an integer property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new integer property definition builder.
   */
  public static Builder createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder(d, propertyName);
  }
  // Private constructor.
  private IntegerPropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<Integer> defaultBehavior, int lowerLimit,
      Integer upperLimit, boolean allowUnlimited) {
    super(d, Integer.class, propertyName, options, adminAction,
        defaultBehavior);
    this.lowerLimit = lowerLimit;
    this.upperLimit = upperLimit;
    this.allowUnlimited = allowUnlimited;
  }
  /**
   * Get the lower limit.
   *
   * @return Returns the lower limit.
   */
  public int getLowerLimit() {
    return lowerLimit;
  }
  /**
   * Get the upper limit.
   *
   * @return Returns the upper limit or <code>null</code> if there is no upper
   *         limit.
   */
  public Integer getUpperLimit() {
    return upperLimit;
  }
  /**
   * Gets the optional unit synopsis of this integer property
   * definition in the default locale.
   *
   * @return Returns the unit synopsis of this integer property
   *         definition in the default locale, or <code>null</code>
   *         if there is no unit synopsis.
   */
  public Message getUnitSynopsis() {
    return getUnitSynopsis(Locale.getDefault());
  }
  /**
   * Gets the optional unit synopsis of this integer property
   * definition in the specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the unit synopsis of this integer property
   *         definition in the specified locale, or <code>null</code>
   *         if there is no unit synopsis.
   */
  public Message getUnitSynopsis(Locale locale) {
    ManagedObjectDefinitionI18NResource resource =
      ManagedObjectDefinitionI18NResource.getInstance();
    String property = "property." + getName() + ".syntax.integer.unit-synopsis";
    try {
      return resource.getMessage(getManagedObjectDefinition(),
          property, locale);
    } catch (MissingResourceException e) {
      return null;
    }
  }
  /**
   * Determine whether this property allows unlimited values.
   *
   * @return Returns <code>true</code> if this this property allows unlimited
   *         values.
   */
  public boolean isAllowUnlimited() {
    return allowUnlimited;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(Integer value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    if (!allowUnlimited && value < lowerLimit) {
      throw new IllegalPropertyValueException(this, value);
    // unlimited allowed
    } else if (value >= 0 && value < lowerLimit) {
      throw new IllegalPropertyValueException(this, value);
    }
    if ((upperLimit != null) && (value > upperLimit)) {
      throw new IllegalPropertyValueException(this, value);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String encodeValue(Integer value)
          throws IllegalPropertyValueException {
    ensureNotNull(value);
    // Make sure that we correctly encode negative values as "unlimited".
    if (allowUnlimited) {
      if (value < 0) {
        return UNLIMITED;
      }
    }
    return value.toString();
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public Integer decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    if (allowUnlimited) {
      if (value.trim().equalsIgnoreCase(UNLIMITED)) {
        return -1;
      }
    }
    Integer i;
    try {
      i = Integer.valueOf(value);
    } catch (NumberFormatException e) {
      throw new IllegalPropertyValueStringException(this, value);
    }
    try {
      validateValue(i);
    } catch (IllegalPropertyValueException e) {
      throw new IllegalPropertyValueStringException(this, value);
    }
    return i;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitInteger(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, Integer value, P p) {
    return v.visitInteger(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void toString(StringBuilder builder) {
    super.toString(builder);
    builder.append(" lowerLimit=");
    builder.append(lowerLimit);
    if (upperLimit != null) {
      builder.append(" upperLimit=");
      builder.append(upperLimit);
    }
    builder.append(" allowUnlimited=");
    builder.append(allowUnlimited);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int compare(Integer o1, Integer o2) {
    return o1.compareTo(o2);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/LDAPProfile.java
New file
@@ -0,0 +1,423 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.MissingResourceException;
import java.util.NoSuchElementException;
import java.util.Set;
/**
 * This class is used to map configuration elements to their LDAP
 * schema names.
 * <p>
 * It is possible to augment the core LDAP profile with additional
 * profile mappings at run-time using instances of {@link Wrapper}.
 * This is useful for unit tests which need to add and remove mock
 * components.
 */
public final class LDAPProfile {
  /**
   * LDAP profile wrappers can be used to provide temporary LDAP
   * profile information for components which do not have LDAP profile
   * property files. These components are typically "mock" components
   * used in unit-tests.
   */
  public static abstract class Wrapper {
    /**
     * Default constructor.
     */
    protected Wrapper() {
      // No implementation required.
    }
    /**
     * Get the name of the LDAP attribute associated with the
     * specified property definition.
     * <p>
     * The default implementation of this method is to return
     * <code>null</code>.
     *
     * @param d
     *          The managed object definition.
     * @param pd
     *          The property definition.
     * @return Returns the name of the LDAP attribute associated with
     *         the specified property definition, or <code>null</code>
     *         if the property definition is not handled by this LDAP
     *         profile wrapper.
     */
    public String getAttributeName(AbstractManagedObjectDefinition<?, ?> d,
        PropertyDefinition<?> pd) {
      return null;
    }
    /**
     * Gets the LDAP RDN attribute type for child entries of an
     * instantiable relation.
     * <p>
     * The default implementation of this method is to return
     * <code>null</code>.
     *
     * @param r
     *          The instantiable relation.
     * @return Returns the LDAP RDN attribute type for child entries
     *         of an instantiable relation, or <code>null</code> if
     *         the instantiable relation is not handled by this LDAP
     *         profile wrapper.
     */
    public String getRelationChildRDNType(
        InstantiableRelationDefinition<?, ?> r) {
      return null;
    }
    /**
     * Gets the LDAP RDN attribute type for child entries of an set
     * relation.
     * <p>
     * The default implementation of this method is to return
     * <code>null</code>.
     *
     * @param r
     *          The set relation.
     * @return Returns the LDAP RDN attribute type for child entries of
     *         an set relation, or <code>null</code> if the set relation
     *         is not handled by this LDAP profile wrapper.
     */
    public String getRelationChildRDNType(SetRelationDefinition<?, ?> r)
    {
      return null;
    }
    /**
     * Get the principle object class associated with the specified
     * definition.
     * <p>
     * The default implementation of this method is to return
     * <code>null</code>.
     *
     * @param d
     *          The managed object definition.
     * @return Returns the principle object class associated with the
     *         specified definition, or <code>null</code> if the
     *         managed object definition is not handled by this LDAP
     *         profile wrapper.
     */
    public String getObjectClass(AbstractManagedObjectDefinition<?, ?> d) {
      return null;
    }
    /**
     * Get an LDAP RDN sequence associatied with a relation.
     * <p>
     * The default implementation of this method is to return
     * <code>null</code>.
     *
     * @param r
     *          The relation.
     * @return Returns the LDAP RDN sequence associatied with a
     *         relation, or <code>null</code> if the relation is not
     *         handled by this LDAP profile wrapper.
     */
    public String getRelationRDNSequence(RelationDefinition<?, ?> r) {
      return null;
    }
  }
  // The singleton instance.
  private static final LDAPProfile INSTANCE = new LDAPProfile();
  /**
   * Get the global LDAP profile instance.
   *
   * @return Returns the global LDAP profile instance.
   */
  public static LDAPProfile getInstance() {
    return INSTANCE;
  }
  // The list of profile wrappers.
  private final LinkedList<Wrapper> profiles = new LinkedList<Wrapper>();;
  // The LDAP profile property table.
  private final ManagedObjectDefinitionResource resource =
    ManagedObjectDefinitionResource.createForProfile("ldap");
  // Prevent construction.
  private LDAPProfile() {
    // No implementation required.
  }
  /**
   * Get the name of the LDAP attribute associated with the specified
   * property definition.
   *
   * @param d
   *          The managed object definition.
   * @param pd
   *          The property definition.
   * @return Returns the name of the LDAP attribute associated with
   *         the specified property definition.
   * @throws MissingResourceException
   *           If the LDAP profile properties file associated with the
   *           provided managed object definition could not be loaded.
   */
  public String getAttributeName(AbstractManagedObjectDefinition<?, ?> d,
      PropertyDefinition<?> pd) throws MissingResourceException {
    for (Wrapper profile : profiles) {
      String attributeName = profile.getAttributeName(d, pd);
      if (attributeName != null) {
        return attributeName;
      }
    }
    return resource.getString(d, "attribute." + pd.getName());
  }
  /**
   * Gets the LDAP RDN attribute type for child entries of an
   * instantiable relation.
   *
   * @param r
   *          The instantiable relation.
   * @return Returns the LDAP RDN attribute type for child entries of
   *         an instantiable relation.
   * @throws MissingResourceException
   *           If the LDAP profile properties file associated with the
   *           provided managed object definition could not be loaded.
   */
  public String getRelationChildRDNType(
      InstantiableRelationDefinition<?, ?> r) throws MissingResourceException {
    if (r.getNamingPropertyDefinition() != null) {
      // Use the attribute associated with the naming property.
      return getAttributeName(r.getChildDefinition(), r
          .getNamingPropertyDefinition());
    } else {
      for (Wrapper profile : profiles) {
        String rdnType = profile.getRelationChildRDNType(r);
        if (rdnType != null) {
          return rdnType;
        }
      }
      return resource.getString(r.getParentDefinition(), "naming-attribute."
          + r.getName());
    }
  }
  /**
   * Gets the LDAP object classes associated with an instantiable or set
   * relation branch. The branch is the parent entry of child managed
   * objects.
   *
   * @param r
   *          The instantiable or set relation.
   * @return Returns the LDAP object classes associated with an
   *         instantiable or set relation branch.
   */
  public List<String> getRelationObjectClasses(
      RelationDefinition<?, ?> r) {
    return Arrays.asList(new String[] { "top", "ds-cfg-branch" });
  }
  /**
   * Gets the LDAP RDN attribute type for child entries of an set
   * relation.
   *
   * @param r
   *          The set relation.
   * @return Returns the LDAP RDN attribute type for child entries of an
   *         set relation.
   * @throws MissingResourceException
   *           If the LDAP profile properties file associated with the
   *           provided managed object definition could not be loaded.
   */
  public String getRelationChildRDNType(SetRelationDefinition<?, ?> r)
      throws MissingResourceException
  {
    for (Wrapper profile : profiles)
    {
      String rdnType = profile.getRelationChildRDNType(r);
      if (rdnType != null)
      {
        return rdnType;
      }
    }
    return resource.getString(r.getParentDefinition(),
        "naming-attribute." + r.getName());
  }
  /**
   * Get the principle object class associated with the specified
   * definition.
   *
   * @param d
   *          The managed object definition.
   * @return Returns the principle object class associated with the
   *         specified definition.
   * @throws MissingResourceException
   *           If the LDAP profile properties file associated with the
   *           provided managed object definition could not be loaded.
   */
  public String getObjectClass(AbstractManagedObjectDefinition<?, ?> d)
      throws MissingResourceException {
    if (d.isTop()) {
      return "top";
    }
    for (Wrapper profile : profiles) {
      String objectClass = profile.getObjectClass(d);
      if (objectClass != null) {
        return objectClass;
      }
    }
    return resource.getString(d, "objectclass");
  }
  /**
   * Get all the object classes associated with the specified
   * definition.
   * <p>
   * The returned list is ordered such that the uppermost object
   * classes appear first (e.g. top).
   *
   * @param d
   *          The managed object definition.
   * @return Returns all the object classes associated with the
   *         specified definition.
   * @throws MissingResourceException
   *           If the LDAP profile properties file associated with the
   *           provided managed object definition could not be loaded.
   */
  public List<String> getObjectClasses(AbstractManagedObjectDefinition<?, ?> d)
      throws MissingResourceException {
    LinkedList<String> objectClasses = new LinkedList<String>();
    Set<String> s = new HashSet<String>();
    // Add the object classes from the parent hierarchy.
    while (d != null) {
      String oc = getObjectClass(d);
      if (!s.contains(oc)) {
        objectClasses.addFirst(oc);
        s.add(oc);
      }
      d = d.getParent();
    }
    if (!s.contains("top")) {
      objectClasses.addFirst("top");
    }
    return objectClasses;
  }
  /**
   * Get an LDAP RDN sequence associatied with a relation.
   *
   * @param r
   *          The relation.
   * @return Returns the LDAP RDN sequence associatied with a
   *         relation.
   * @throws MissingResourceException
   *           If the LDAP profile properties file associated with the
   *           provided managed object definition could not be loaded.
   */
  public String getRelationRDNSequence(RelationDefinition<?, ?> r)
      throws MissingResourceException {
    for (Wrapper profile : profiles) {
      String rdnSequence = profile.getRelationRDNSequence(r);
      if (rdnSequence != null) {
        return rdnSequence;
      }
    }
    return resource.getString(r.getParentDefinition(), "rdn." + r.getName());
  }
  /**
   * Removes the last LDAP profile wrapper added using
   * {@link #pushWrapper(org.opends.server.admin.LDAPProfile.Wrapper)}.
   *
   * @throws NoSuchElementException
   *           If there are no LDAP profile wrappers.
   */
  public void popWrapper() throws NoSuchElementException {
    profiles.removeFirst();
  }
  /**
   * Decorates the core LDAP profile with the provided LDAP profile
   * wrapper. All profile requests will be directed to the provided
   * wrapper before being forwarded onto the core profile if the
   * request could not be satisfied.
   *
   * @param wrapper
   *          The LDAP profile wrapper.
   */
  public void pushWrapper(Wrapper wrapper) {
    profiles.addFirst(wrapper);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectAlreadyExistsException.java
New file
@@ -0,0 +1,56 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
/**
 * A managed object could not be created because there is an existing
 * managed object with the same name.
 */
public final class ManagedObjectAlreadyExistsException extends
    OperationsException {
  /**
   * Version ID required by serializable classes.
   */
  private static final long serialVersionUID = -2344653674171609366L;
  /**
   * Create a managed object already exists exception.
   */
  public ManagedObjectAlreadyExistsException() {
    super(ERR_MANAGED_OBJECT_ALREADY_EXISTS_EXCEPTION.get());
  }
}
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectDefinition.java
New file
@@ -0,0 +1,105 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.server.admin.client.ManagedObject;
import org.opends.server.admin.server.ServerManagedObject;
/**
 * Defines the structure of a managed object which can be
 * instantiated.
 *
 * @param <C>
 *          The type of client managed object configuration that this
 *          definition represents.
 * @param <S>
 *          The type of server managed object configuration that this
 *          definition represents.
 */
public abstract class ManagedObjectDefinition
    <C extends ConfigurationClient, S extends Configuration>
    extends AbstractManagedObjectDefinition<C, S> {
  /**
   * Create a new managed object definition.
   *
   * @param name
   *          The name of the definition.
   * @param parent
   *          The parent definition, or <code>null</code> if there
   *          is no parent.
   */
  protected ManagedObjectDefinition(String name,
      AbstractManagedObjectDefinition<? super C, ? super S> parent) {
    super(name, parent);
  }
  /**
   * Creates a client configuration view of the provided managed
   * object. Modifications made to the underlying managed object will
   * be reflected in the client configuration view and vice versa.
   *
   * @param managedObject
   *          The managed object.
   * @return Returns a client configuration view of the provided
   *         managed object.
   */
  public abstract C createClientConfiguration(
      ManagedObject<? extends C> managedObject);
  /**
   * Creates a server configuration view of the provided server
   * managed object.
   *
   * @param managedObject
   *          The server managed object.
   * @return Returns a server configuration view of the provided
   *         server managed object.
   */
  public abstract S createServerConfiguration(
      ServerManagedObject<? extends S> managedObject);
  /**
   * Gets the server configuration class instance associated with this
   * managed object definition.
   *
   * @return Returns the server configuration class instance
   *         associated with this managed object definition.
   */
  public abstract Class<S> getServerConfigurationClass();
}
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectDefinitionI18NResource.java
New file
@@ -0,0 +1,346 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.forgerock.i18n.LocalizableMessage;
/**
 * A class for retrieving internationalized resource properties
 * associated with a managed object definition.
 * <p>
 * I18N resource properties are not available for the
 * {@link TopCfgDefn}.
 */
public final class ManagedObjectDefinitionI18NResource {
  // Application-wide set of instances.
  private static final Map<String, ManagedObjectDefinitionI18NResource>
    INSTANCES = new HashMap<String, ManagedObjectDefinitionI18NResource>();
  /**
   * Gets the internationalized resource instance which can be used to
   * retrieve the localized descriptions for the managed objects and
   * their associated properties and relations.
   *
   * @return Returns the I18N resource instance.
   */
  public static ManagedObjectDefinitionI18NResource getInstance() {
    return getInstance("admin.messages");
  }
  /**
   * Gets the internationalized resource instance for the named
   * profile.
   *
   * @param profile
   *          The name of the profile.
   * @return Returns the I18N resource instance for the named profile.
   */
  public static ManagedObjectDefinitionI18NResource getInstanceForProfile(
      String profile) {
    return getInstance("admin.profiles." + profile);
  }
  // Get a resource instance creating it if necessary.
  private synchronized static ManagedObjectDefinitionI18NResource getInstance(
      String prefix) {
    ManagedObjectDefinitionI18NResource instance = INSTANCES
        .get(prefix);
    if (instance == null) {
      instance = new ManagedObjectDefinitionI18NResource(prefix);
      INSTANCES.put(prefix, instance);
    }
    return instance;
  }
  // Mapping from definition to locale-based resource bundle.
  private final Map<AbstractManagedObjectDefinition<?, ?>,
    Map<Locale, ResourceBundle>> resources;
  // The resource name prefix.
  private final String prefix;
  // Private constructor.
  private ManagedObjectDefinitionI18NResource(String prefix) {
    this.resources = new HashMap<AbstractManagedObjectDefinition<?, ?>,
      Map<Locale, ResourceBundle>>();
    this.prefix = prefix;
  }
  /**
   * Get the internationalized message associated with the specified
   * key in the default locale.
   *
   * @param d
   *          The managed object definition.
   * @param key
   *          The resource key.
   * @return Returns the internationalized message associated with the
   *         specified key in the default locale.
   * @throws MissingResourceException
   *           If the key was not found.
   * @throws UnsupportedOperationException
   *           If the provided managed object definition was the
   *           {@link TopCfgDefn}.
   */
  public LocalizableMessage getLocalizableMessage(AbstractManagedObjectDefinition<?, ?> d, String key)
      throws MissingResourceException, UnsupportedOperationException {
    return getLocalizableMessage(d, key, Locale.getDefault(), (String[]) null);
  }
  /**
   * Get the internationalized message associated with the specified
   * key and locale.
   *
   * @param d
   *          The managed object definition.
   * @param key
   *          The resource key.
   * @param locale
   *          The locale.
   * @return Returns the internationalized message associated with the
   *         specified key and locale.
   * @throws MissingResourceException
   *           If the key was not found.
   * @throws UnsupportedOperationException
   *           If the provided managed object definition was the
   *           {@link TopCfgDefn}.
   */
  public LocalizableMessage getLocalizableMessage(AbstractManagedObjectDefinition<?, ?> d,
      String key, Locale locale) throws MissingResourceException,
      UnsupportedOperationException {
    return getLocalizableMessage(d, key, locale, (String[]) null);
  }
  /**
   * Get the parameterized internationalized message associated with
   * the specified key and locale.
   *
   * @param d
   *          The managed object definition.
   * @param key
   *          The resource key.
   * @param locale
   *          The locale.
   * @param args
   *          Arguments that should be inserted into the retrieved
   *          message.
   * @return Returns the internationalized message associated with the
   *         specified key and locale.
   * @throws MissingResourceException
   *           If the key was not found.
   * @throws UnsupportedOperationException
   *           If the provided managed object definition was the
   *           {@link TopCfgDefn}.
   */
  public LocalizableMessage getLocalizableMessage(AbstractManagedObjectDefinition<?, ?> d,
      String key, Locale locale, String... args)
      throws MissingResourceException, UnsupportedOperationException {
    ResourceBundle resource = getResourceBundle(d, locale);
    // TODO: use message framework directly
    if (args == null) {
      return LocalizableMessage.raw(resource.getString(key));
    } else {
      return LocalizableMessage.raw(resource.getString(key), (Object[]) args);
    }
  }
  /**
   * Get the parameterized internationalized message associated with
   * the specified key in the default locale.
   *
   * @param d
   *          The managed object definition.
   * @param key
   *          The resource key.
   * @param args
   *          Arguments that should be inserted into the retrieved
   *          message.
   * @return Returns the internationalized message associated with the
   *         specified key in the default locale.
   * @throws MissingResourceException
   *           If the key was not found.
   * @throws UnsupportedOperationException
   *           If the provided managed object definition was the
   *           {@link TopCfgDefn}.
   */
  public LocalizableMessage getLocalizableMessage(AbstractManagedObjectDefinition<?, ?> d,
      String key, String... args) throws MissingResourceException,
      UnsupportedOperationException {
    return getLocalizableMessage(d, key, Locale.getDefault(), args);
  }
  /**
   * Forcefully removes any resource bundles associated with the
   * provided definition and using the default locale.
   * <p>
   * This method is intended for internal testing only.
   *
   * @param d
   *          The managed object definition.
   */
  synchronized void removeResourceBundle(
      AbstractManagedObjectDefinition<?, ?> d) {
    removeResourceBundle(d, Locale.getDefault());
  }
  /**
   * Forcefully removes any resource bundles associated with the
   * provided definition and locale.
   * <p>
   * This method is intended for internal testing only.
   *
   * @param d
   *          The managed object definition.
   * @param locale
   *          The locale.
   */
  synchronized void removeResourceBundle(
      AbstractManagedObjectDefinition<?, ?> d, Locale locale) {
    // Get the locale resource mapping.
    Map<Locale, ResourceBundle> map = resources.get(d);
    if (map != null) {
      map.remove(locale);
    }
  }
  /**
   * Forcefully adds the provided resource bundle to this I18N
   * resource for the default locale.
   * <p>
   * This method is intended for internal testing only.
   *
   * @param d
   *          The managed object definition.
   * @param resoureBundle
   *          The resource bundle to be used.
   */
  synchronized void setResourceBundle(AbstractManagedObjectDefinition<?, ?> d,
      ResourceBundle resoureBundle) {
    setResourceBundle(d, Locale.getDefault(), resoureBundle);
  }
  /**
   * Forcefully adds the provided resource bundle to this I18N
   * resource.
   * <p>
   * This method is intended for internal testing only.
   *
   * @param d
   *          The managed object definition.
   * @param locale
   *          The locale.
   * @param resoureBundle
   *          The resource bundle to be used.
   */
  synchronized void setResourceBundle(AbstractManagedObjectDefinition<?, ?> d,
      Locale locale, ResourceBundle resoureBundle) {
    // First get the locale-resource mapping, creating it if
    // necessary.
    Map<Locale, ResourceBundle> map = resources.get(d);
    if (map == null) {
      map = new HashMap<Locale, ResourceBundle>();
      resources.put(d, map);
    }
    // Add the resource bundle.
    map.put(locale, resoureBundle);
  }
  // Retrieve the resource bundle associated with a managed object and
  // locale, lazily loading it if necessary.
  private synchronized ResourceBundle getResourceBundle(
      AbstractManagedObjectDefinition<?, ?> d, Locale locale)
      throws MissingResourceException, UnsupportedOperationException {
    if (d.isTop()) {
      throw new UnsupportedOperationException(
          "I18n resources are not available for the "
              + "Top configuration definition");
    }
    // First get the locale-resource mapping, creating it if
    // necessary.
    Map<Locale, ResourceBundle> map = resources.get(d);
    if (map == null) {
      map = new HashMap<Locale, ResourceBundle>();
      resources.put(d, map);
    }
    // Now get the resource based on the locale, loading it if
    // necessary.
    ResourceBundle resourceBundle = map.get(locale);
    if (resourceBundle == null) {
      String baseName = prefix + "." + d.getClass().getName();
      resourceBundle = ResourceBundle.getBundle(baseName, locale,
          ClassLoaderProvider.getInstance().getClassLoader());
      map.put(locale, resourceBundle);
    }
    return resourceBundle;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectDefinitionResource.java
New file
@@ -0,0 +1,156 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.Properties;
/**
 * A class for retrieving non-internationalized resource properties
 * associated with a managed object definition.
 * <p>
 * Resource properties are not available for the {@link TopCfgDefn}.
 */
public final class ManagedObjectDefinitionResource {
  // Mapping from definition to property tables.
  private final Map<AbstractManagedObjectDefinition<?, ?>,
      Properties> properties;
  // The resource name prefix.
  private final String prefix;
  /**
   * Creates a new resource instance for the named profile.
   *
   * @param profile
   *          The name of the profile.
   * @return Returns the resource instance for the named profile.
   */
  public static ManagedObjectDefinitionResource createForProfile(
      String profile) {
    return new ManagedObjectDefinitionResource("admin.profiles."
        + profile);
  }
  // Private constructor.
  private ManagedObjectDefinitionResource(String prefix) {
    this.properties =
      new HashMap<AbstractManagedObjectDefinition<?, ?>, Properties>();
    this.prefix = prefix;
  }
  /**
   * Get the resource value associated with the specified key.
   *
   * @param d
   *          The managed object definition.
   * @param key
   *          The resource key.
   * @return Returns the resource value associated with the specified
   *         key.
   * @throws MissingResourceException
   *           If the key was not found.
   * @throws UnsupportedOperationException
   *           If the provided managed object definition was the
   *           {@link TopCfgDefn}.
   */
  public String getString(AbstractManagedObjectDefinition<?, ?> d, String key)
      throws MissingResourceException, UnsupportedOperationException {
    if (d.isTop()) {
      throw new UnsupportedOperationException(
          "Profile resources are not available for the "
              + "Top configuration definition");
    }
    Properties p = getProperties(d);
    String result = p.getProperty(key);
    if (result == null) {
      String baseName = prefix + "." + d.getClass().getName();
      String path = baseName.replace('.', '/') + ".properties";
      throw new MissingResourceException("Can't find resource "
          + path + ", key " + key, baseName, key);
    }
    return result;
  }
  // Retrieve the properties table associated with a managed object,
  // lazily loading it if necessary.
  private synchronized Properties getProperties(
      AbstractManagedObjectDefinition<?, ?> d)
      throws MissingResourceException {
    Properties p = properties.get(d);
    if (p == null) {
      // Load the resource file.
      String baseName = prefix + "." + d.getClass().getName();
      String path = baseName.replace('.', '/') + ".properties";
      InputStream stream = ClassLoaderProvider.getInstance()
          .getClassLoader().getResourceAsStream(path);
      if (stream == null) {
        throw new MissingResourceException("Can't find resource "
            + path, baseName, "");
      }
      p = new Properties();
      try {
        p.load(new BufferedInputStream(stream));
      } catch (IOException e) {
        throw new MissingResourceException("Can't load resource "
            + path + " due to IO exception: " + e.getMessage(),
            baseName, "");
      }
      // Cache the resource.
      properties.put(d, p);
    }
    return p;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectNotFoundException.java
New file
@@ -0,0 +1,67 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
/**
 * The requested managed object could not be located.
 */
public class ManagedObjectNotFoundException extends OperationsException {
  /**
   * Version ID required by serializable classes.
   */
  private static final long serialVersionUID = -477551786551892978L;
  /**
   * Create a managed object not found exception.
   */
  public ManagedObjectNotFoundException() {
    super(ERR_MANAGED_OBJECT_NOT_FOUND_EXCEPTION.get());
  }
  /**
   * Create a managed object not found exception with the specified
   * cause.
   *
   * @param cause
   *          The cause of this exception.
   */
  public ManagedObjectNotFoundException(Throwable cause) {
    super(ERR_MANAGED_OBJECT_NOT_FOUND_EXCEPTION.get(), cause);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectOption.java
New file
@@ -0,0 +1,49 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * This enumeration contains various options that can be associated
 * with managed object definitions.
 */
public enum ManagedObjectOption {
  /**
   * Use this option to identify managed object types which should be
   * considered as advanced and should not be exposed by default in
   * client applications.
   */
  ADVANCED,
  /**
   * Use this option to identify managed object types which must not
   * be directly exposed in client applications.
   */
  HIDDEN;
}
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectPath.java
New file
@@ -0,0 +1,1445 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 *      Portions Copyright 2011 ForgeRock AS
 */
package org.opends.server.admin;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.opends.server.admin.std.client.RootCfgClient;
import org.opends.server.admin.std.meta.RootCfgDefn;
import org.opends.server.admin.std.server.RootCfg;
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.*;
/**
 * A path which can be used to determine the location of a managed
 * object instance.
 * <p>
 * A path is made up of zero or more elements each of which represents
 * a managed object. Managed objects are arranged hierarchically with
 * the root configuration being the top-most managed object. Elements
 * are ordered such that the root configuration managed object is the
 * first element and subsequent elements representing managed objects
 * further down the hierarchy.
 * <p>
 * A path can be encoded into a string representation using the
 * {@link #toString()} and {@link #toString(StringBuilder)} methods.
 * Conversely, this string representation can be parsed using the
 * {@link #valueOf(String)} method.
 * <p>
 * The string representation of a managed object path is similar in
 * principle to a UNIX file-system path and is defined as follows:
 * <ul>
 * <li>the root element is represented by the string <code>/</code>
 * <li>subordinate elements are arranged in big-endian order
 * separated by a forward slash <code>/</code> character
 * <li>an element representing a managed object associated with a
 * one-to-one (singleton) or one-to-zero-or-one (optional) relation
 * has the form <code>relation=</code><i>relation</i>
 * <code>[+type=</code><i>definition</i><code>]</code>, where
 * <i>relation</i> is the name of the relation and <i>definition</i>
 * is the name of the referenced managed object's definition if
 * required (usually this is implied by the relation itself)
 * <li>an element representing a managed object associated with a
 * one-to-many (instantiable) relation has the form
 * <code>relation=</code><i>relation</i><code>[+type=</code>
 * <i>definition</i><code>]</code><code>+name=</code><i>name</i>,
 * where <i>relation</i> is the name of the relation and
 * <i>definition</i> is the name of the referenced managed object's
 * definition if required (usually this is implied by the relation
 * itself), and <i>name</i> is the name of the managed object
 * instance
 * <li>an element representing a managed object associated with a
 * one-to-many (set) relation has the form
 * <code>relation=</code><i>relation</i><code>[+type=</code>
 * <i>definition</i><code>]</code>,
 * where <i>relation</i> is the name of the relation and
 * <i>definition</i> is the name of the referenced managed object's
 * definition.
 * </ul>
 * The following path string representation identifies a connection
 * handler instance (note that the <code>type</code> is not
 * specified indicating that the path identifies a connection handler
 * called <i>my handler</i> which can be any type of connection
 * handler):
 *
 * <pre>
 *  /relation=connection-handler+name=my handler
 * </pre>
 *
 * If the identified connection handler must be an LDAP connection
 * handler then the above path should include the <code>type</code>:
 *
 * <pre>
 *  /relation=connection-handler+type=ldap-connection-handler+name=my handler
 * </pre>
 *
 * The final example identifies the global configuration:
 *
 * <pre>
 *  /relation=global-configuration
 * </pre>
 *
 * @param <C>
 *          The type of client managed object configuration that this
 *          path references.
 * @param <S>
 *          The type of server managed object configuration that this
 *          path references.
 */
public final class ManagedObjectPath<C extends ConfigurationClient,
    S extends Configuration> {
  /**
   * A serialize which is used to generate the toDN representation.
   */
  private static final class DNSerializer implements
      ManagedObjectPathSerializer {
    // The current DN.
    private DN dn;
    // The LDAP profile.
    private final LDAPProfile profile;
    // Create a new DN builder.
    private DNSerializer() {
      this.dn = DN.nullDN();
      this.profile = LDAPProfile.getInstance();
    }
    /**
     * {@inheritDoc}
     */
    public <C extends ConfigurationClient, S extends Configuration>
    void appendManagedObjectPathElement(
        InstantiableRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d, String name) {
      // Add the RDN sequence representing the relation.
      appendManagedObjectPathElement(r);
      // Now add the single RDN representing the named instance.
      String type = profile.getRelationChildRDNType(r);
      AttributeType atype = DirectoryServer.getAttributeType(
          type.toLowerCase(), true);
      AttributeValue avalue = AttributeValues.create(atype, name);
      dn = dn.concat(RDN.create(atype, avalue));
    }
    /**
     * {@inheritDoc}
     */
    public <C extends ConfigurationClient, S extends Configuration>
    void appendManagedObjectPathElement(
        SetRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      // Add the RDN sequence representing the relation.
      appendManagedObjectPathElement(r);
      // Now add the single RDN representing the instance.
      String type = profile.getRelationChildRDNType(r);
      AttributeType atype = DirectoryServer.getAttributeType(
          type.toLowerCase(), true);
      AttributeValue avalue = AttributeValues.create(atype, d.getName());
      dn = dn.concat(RDN.create(atype, avalue));
    }
    /**
     * {@inheritDoc}
     */
    public <C extends ConfigurationClient, S extends Configuration>
    void appendManagedObjectPathElement(
        OptionalRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      // Add the RDN sequence representing the relation.
      appendManagedObjectPathElement(r);
    }
    /**
     * {@inheritDoc}
     */
    public <C extends ConfigurationClient, S extends Configuration>
    void appendManagedObjectPathElement(
        SingletonRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      // Add the RDN sequence representing the relation.
      appendManagedObjectPathElement(r);
    }
    // Appends the RDN sequence representing the provided relation.
    private void appendManagedObjectPathElement(RelationDefinition<?, ?> r) {
      // Add the RDN sequence representing the relation.
      try {
        DN localName = DN.decode(profile.getRelationRDNSequence(r));
        dn = dn.concat(localName);
      } catch (DirectoryException e) {
        throw new RuntimeException(e);
      }
    }
    // Gets the serialized DN value.
    private DN toDN() {
      return dn;
    }
  }
  /**
   * Abstract path element.
   */
  private static abstract class Element<C extends ConfigurationClient,
      S extends Configuration> {
    // The type of managed object referenced by this element.
    private final AbstractManagedObjectDefinition<C, S> definition;
    /**
     * Protected constructor.
     *
     * @param definition
     *          The type of managed object referenced by this element.
     */
    protected Element(AbstractManagedObjectDefinition<C, S> definition) {
      this.definition = definition;
    }
    /**
     * Get the managed object definition associated with this element.
     *
     * @return Returns the managed object definition associated with
     *         this element.
     */
    public final AbstractManagedObjectDefinition<C, S>
        getManagedObjectDefinition() {
      return definition;
    }
    /**
     * Get the name associated with this element if applicable.
     *
     * @return Returns the name associated with this element if
     *         applicable.
     */
    public String getName() {
      return null;
    }
    /**
     * Get the relation definition associated with this element.
     *
     * @return Returns the relation definition associated with this
     *         element.
     */
    public abstract RelationDefinition<? super C, ? super S>
        getRelationDefinition();
    /**
     * Serialize this path element using the provided serialization
     * strategy.
     *
     * @param serializer
     *          The managed object path serialization strategy.
     */
    public abstract void serialize(ManagedObjectPathSerializer serializer);
  }
  /**
   * A path element representing an instantiable managed object.
   */
  private static final class InstantiableElement
      <C extends ConfigurationClient, S extends Configuration>
      extends Element<C, S> {
    // Factory method.
    private static final <C extends ConfigurationClient,
        S extends Configuration>
        InstantiableElement<C, S> create(
        InstantiableRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d, String name) {
      return new InstantiableElement<C, S>(r, d, name);
    }
    // The name of the managed object.
    private final String name;
    // The instantiable relation.
    private final InstantiableRelationDefinition<? super C, ? super S> r;
    // Private constructor.
    private InstantiableElement(
        InstantiableRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d, String name) {
      super(d);
      this.r = r;
      this.name = name;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public String getName() {
      return name;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public InstantiableRelationDefinition<? super C, ? super S>
        getRelationDefinition() {
      return r;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void serialize(ManagedObjectPathSerializer serializer) {
      serializer.appendManagedObjectPathElement(r,
          getManagedObjectDefinition(), name);
    }
  }
  /**
   * A path element representing an optional managed object.
   */
  private static final class OptionalElement
      <C extends ConfigurationClient, S extends Configuration>
      extends Element<C, S> {
    // Factory method.
    private static final <C extends ConfigurationClient,
        S extends Configuration> OptionalElement<C, S> create(
        OptionalRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      return new OptionalElement<C, S>(r, d);
    }
    // The optional relation.
    private final OptionalRelationDefinition<? super C, ? super S> r;
    // Private constructor.
    private OptionalElement(OptionalRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      super(d);
      this.r = r;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public OptionalRelationDefinition<? super C, ? super S>
        getRelationDefinition() {
      return r;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void serialize(ManagedObjectPathSerializer serializer) {
      serializer
          .appendManagedObjectPathElement(r, getManagedObjectDefinition());
    }
  }
  /**
   * A path element representing an set managed object.
   */
  private static final class SetElement
      <C extends ConfigurationClient, S extends Configuration>
      extends Element<C, S> {
    // Factory method.
    private static final <C extends ConfigurationClient,
        S extends Configuration>
        SetElement<C, S> create(
        SetRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      return new SetElement<C, S>(r, d);
    }
    // The set relation.
    private final SetRelationDefinition<? super C, ? super S> r;
    // Private constructor.
    private SetElement(
        SetRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      super(d);
      this.r = r;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public SetRelationDefinition<? super C, ? super S>
        getRelationDefinition() {
      return r;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void serialize(ManagedObjectPathSerializer serializer) {
      serializer.appendManagedObjectPathElement(r,
          getManagedObjectDefinition());
    }
  }
  /**
   * A path element representing a singleton managed object.
   */
  private static final class SingletonElement
      <C extends ConfigurationClient, S extends Configuration>
      extends Element<C, S> {
    // Factory method.
    private static final <C extends ConfigurationClient,
        S extends Configuration> SingletonElement<C, S> create(
        SingletonRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      return new SingletonElement<C, S>(r, d);
    }
    // The singleton relation.
    private final SingletonRelationDefinition<? super C, ? super S> r;
    // Private constructor.
    private SingletonElement(
        SingletonRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      super(d);
      this.r = r;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public SingletonRelationDefinition<? super C, ? super S>
        getRelationDefinition() {
      return r;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void serialize(ManagedObjectPathSerializer serializer) {
      serializer
          .appendManagedObjectPathElement(r, getManagedObjectDefinition());
    }
  }
  /**
   * A serialize which is used to generate the toString
   * representation.
   */
  private static final class StringSerializer implements
      ManagedObjectPathSerializer {
    // Serialize to this string builder.
    private final StringBuilder builder;
    // Private constructor.
    private StringSerializer(StringBuilder builder) {
      this.builder = builder;
    }
    /**
     * {@inheritDoc}
     */
    public <M extends ConfigurationClient, N extends Configuration>
        void appendManagedObjectPathElement(
        InstantiableRelationDefinition<? super M, ? super N> r,
        AbstractManagedObjectDefinition<M, N> d, String name) {
      serializeElement(r, d);
      // Be careful to escape any forward slashes in the name.
      builder.append("+name=");
      builder.append(name.replace("/", "//"));
    }
    /**
     * {@inheritDoc}
     */
    public <M extends ConfigurationClient, N extends Configuration>
        void appendManagedObjectPathElement(
        OptionalRelationDefinition<? super M, ? super N> r,
        AbstractManagedObjectDefinition<M, N> d) {
      serializeElement(r, d);
    }
    /**
     * {@inheritDoc}
     */
    public <M extends ConfigurationClient, N extends Configuration>
        void appendManagedObjectPathElement(
        SingletonRelationDefinition<? super M, ? super N> r,
        AbstractManagedObjectDefinition<M, N> d) {
      serializeElement(r, d);
    }
    /**
     * {@inheritDoc}
     */
    public <M extends ConfigurationClient, N extends Configuration>
        void appendManagedObjectPathElement(
        SetRelationDefinition<? super M, ? super N> r,
        AbstractManagedObjectDefinition<M, N> d) {
      serializeElement(r, d);
    }
    // Common element serialization.
    private <M, N> void serializeElement(RelationDefinition<?, ?> r,
        AbstractManagedObjectDefinition<?, ?> d) {
      // Always specify the relation name.
      builder.append("/relation=");
      builder.append(r.getName());
      // Only specify the type if it is a sub-type of the relation's
      // type.
      if (r.getChildDefinition() != d) {
        builder.append("+type=");
        builder.append(d.getName());
      }
    }
  }
  // Single instance of a root path.
  private static final ManagedObjectPath<RootCfgClient, RootCfg> EMPTY_PATH =
      new ManagedObjectPath<RootCfgClient, RootCfg>(
      new LinkedList<Element<?, ?>>(), null, RootCfgDefn.getInstance());
  // A regular expression used to parse path elements.
  private static final Pattern PE_REGEXP = Pattern
      .compile("^\\s*relation=\\s*([^+]+)\\s*"
          + "(\\+\\s*type=\\s*([^+]+)\\s*)?"
          + "(\\+\\s*name=\\s*([^+]+)\\s*)?$");
  /**
   * Creates a new managed object path representing the configuration
   * root.
   *
   * @return Returns a new managed object path representing the
   *         configuration root.
   */
  public static ManagedObjectPath<RootCfgClient, RootCfg> emptyPath() {
    return EMPTY_PATH;
  }
  /**
   * Returns a managed object path holding the value of the specified
   * string.
   *
   * @param s
   *          The string to be parsed.
   * @return Returns a managed object path holding the value of the
   *         specified string.
   * @throws IllegalArgumentException
   *           If the string could not be parsed.
   */
  public static ManagedObjectPath<?, ?> valueOf(String s)
      throws IllegalArgumentException {
    String ns = s.trim();
    // Check for root special case.
    if (ns.equals("/")) {
      return EMPTY_PATH;
    }
    // Parse the elements.
    LinkedList<Element<?, ?>> elements = new LinkedList<Element<?, ?>>();
    Element<?, ?> lastElement = null;
    AbstractManagedObjectDefinition<?, ?> definition = RootCfgDefn
        .getInstance();
    if (!ns.startsWith("/")) {
      throw new IllegalArgumentException("Invalid path \"" + ns
          + "\": must begin with a \"/\"");
    }
    int start = 1;
    while (true) {
      // Get the next path element.
      int end;
      for (end = start; end < ns.length(); end++) {
        char c = ns.charAt(end);
        if (c == '/') {
          if (end == (ns.length() - 1)) {
            throw new IllegalArgumentException("Invalid path \"" + ns
                + "\": must not end with a trailing \"/\"");
          }
          if (ns.charAt(end + 1) == '/') {
            // Found an escaped forward slash.
            end++;
          } else {
            // Found the end of this path element.
            break;
          }
        }
      }
      // Get the next element.
      String es = ns.substring(start, end);
      Matcher m = PE_REGEXP.matcher(es);
      if (!m.matches()) {
        throw new IllegalArgumentException("Invalid path element \"" + es
            + "\" in path \"" + ns + "\"");
      }
      // Mandatory.
      String relation = m.group(1);
      // Optional.
      String type = m.group(3);
      // Mandatory if relation is instantiable.
      String name = m.group(5);
      // Get the relation definition.
      RelationDefinition<?, ?> r;
      try {
        r = definition.getRelationDefinition(relation);
      } catch (IllegalArgumentException e) {
        throw new IllegalArgumentException("Invalid path element \"" + es
            + "\" in path \"" + ns + "\": unknown relation \"" + relation
            + "\"");
      }
      // Append the next element.
      lastElement = createElement(r, ns, es, type, name);
      elements.add(lastElement);
      definition = lastElement.getManagedObjectDefinition();
      // Update start to point to the beginning of the next element.
      if (end < ns.length()) {
        // Skip to the beginning of the next element
        start = end + 1;
      } else {
        // We reached the end of the string.
        break;
      }
    }
    // Construct the new path.
    return create(elements, lastElement);
  }
  // Factory method required in order to allow generic wild-card
  // construction of new paths.
  private static <C extends ConfigurationClient, S extends Configuration>
      ManagedObjectPath<C, S> create(
      LinkedList<Element<?, ?>> elements, Element<C, S> lastElement) {
    return new ManagedObjectPath<C, S>(elements, lastElement
        .getRelationDefinition(), lastElement.getManagedObjectDefinition());
  }
  // Decode an element.
  private static <C extends ConfigurationClient, S extends Configuration>
      Element<? extends C, ? extends S> createElement(
      RelationDefinition<C, S> r, String path, String element, String type,
      String name) {
    // First determine the managed object definition.
    AbstractManagedObjectDefinition<? extends C, ? extends S> d = null;
    if (type != null) {
      for (AbstractManagedObjectDefinition<? extends C, ? extends S> child : r
          .getChildDefinition().getAllChildren()) {
        if (child.getName().equals(type)) {
          d = child;
          break;
        }
      }
      if (d == null) {
        throw new IllegalArgumentException("Invalid path element \"" + element
            + "\" in path \"" + path + "\": unknown sub-type \"" + type + "\"");
      }
    } else {
      d = r.getChildDefinition();
    }
    if (r instanceof InstantiableRelationDefinition) {
      InstantiableRelationDefinition<C, S> ir =
        (InstantiableRelationDefinition<C, S>) r;
      if (name == null) {
        throw new IllegalArgumentException("Invalid path element \"" + element
            + "\" in path \"" + path
            + "\": no instance name for instantiable relation");
      }
      return InstantiableElement.create(ir, d, name);
    } else if (r instanceof SetRelationDefinition) {
      SetRelationDefinition<C, S> ir = (SetRelationDefinition<C, S>) r;
      if (name != null) {
        throw new IllegalArgumentException("Invalid path element \"" + element
            + "\" in path \"" + path
            + "\": instance name specified for set relation");
      }
      return SetElement.create(ir, d);
    } else if (r instanceof OptionalRelationDefinition) {
      OptionalRelationDefinition<C, S> or =
        (OptionalRelationDefinition<C, S>) r;
      if (name != null) {
        throw new IllegalArgumentException("Invalid path element \"" + element
            + "\" in path \"" + path
            + "\": instance name specified for optional relation");
      }
      return OptionalElement.create(or, d);
    } else if (r instanceof SingletonRelationDefinition) {
      SingletonRelationDefinition<C, S> sr =
        (SingletonRelationDefinition<C, S>) r;
      if (name != null) {
        throw new IllegalArgumentException("Invalid path element \"" + element
            + "\" in path \"" + path
            + "\": instance name specified for singleton relation");
      }
      return SingletonElement.create(sr, d);
    } else {
      throw new IllegalArgumentException("Invalid path element \"" + element
          + "\" in path \"" + path + "\": unsupported relation type");
    }
  }
  // The managed object definition in this path.
  private final AbstractManagedObjectDefinition<C, S> d;
  // The list of path elements in this path.
  private final List<Element<?, ?>> elements;
  // The last relation definition in this path.
  private final RelationDefinition<? super C, ? super S> r;
  // Private constructor.
  private ManagedObjectPath(LinkedList<Element<?, ?>> elements,
      RelationDefinition<? super C, ? super S> r,
      AbstractManagedObjectDefinition<C, S> d) {
    this.elements = Collections.unmodifiableList(elements);
    this.r = r;
    this.d = d;
  }
  /**
   * Creates a new managed object path which has the same structure as
   * this path except that the final path element is associated with
   * the specified managed object definition.
   *
   * @param <CC>
   *          The type of client managed object configuration that
   *          this path will reference.
   * @param <SS>
   *          The type of server managed object configuration that
   *          this path will reference.
   * @param nd
   *          The new managed object definition.
   * @return Returns a new managed object path which has the same
   *         structure as this path except that the final path element
   *         is associated with the specified managed object
   *         definition.
   */
  @SuppressWarnings("unchecked")
  public <CC extends C, SS extends S> ManagedObjectPath<CC, SS> asSubType(
      AbstractManagedObjectDefinition<CC, SS> nd) {
    if (r instanceof InstantiableRelationDefinition) {
      InstantiableRelationDefinition<? super C, ? super S> ir =
        (InstantiableRelationDefinition<? super C, ? super S>) r;
      if (elements.size() == 0) {
        return parent().child(ir, nd, "null");
      } else {
        return parent().child(ir, nd,
            elements.get(elements.size() - 1).getName());
      }
    } else if (r instanceof SetRelationDefinition) {
      SetRelationDefinition<? super C, ? super S> sr =
        (SetRelationDefinition<? super C, ? super S>) r;
      return parent().child(sr, nd);
    } else if (r instanceof OptionalRelationDefinition) {
      OptionalRelationDefinition<? super C, ? super S> or =
        (OptionalRelationDefinition<? super C, ? super S>) r;
      return parent().child(or, nd);
    } else {
      SingletonRelationDefinition<? super C, ? super S> sr =
        (SingletonRelationDefinition<? super C, ? super S>) r;
      return parent().child(sr, nd);
    }
  }
  /**
   * Creates a new child managed object path beneath the provided
   * parent path having the specified managed object definition.
   *
   * @param <M>
   *          The type of client managed object configuration that the
   *          child path references.
   * @param <N>
   *          The type of server managed object configuration that the
   *          child path references.
   * @param r
   *          The instantiable relation referencing the child.
   * @param d
   *          The managed object definition associated with the child
   *          (must be a sub-type of the relation).
   * @param name
   *          The relative name of the child managed object.
   * @return Returns a new child managed object path beneath the
   *         provided parent path.
   * @throws IllegalArgumentException
   *           If the provided name is empty or blank.
   */
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(
      InstantiableRelationDefinition<? super M, ? super N> r,
      AbstractManagedObjectDefinition<M, N> d, String name)
      throws IllegalArgumentException {
    if (name.trim().length() == 0) {
      throw new IllegalArgumentException(
          "Empty or blank managed object names are not allowed");
    }
    LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
        elements);
    celements.add(new InstantiableElement<M, N>(r, d, name));
    return new ManagedObjectPath<M, N>(celements, r, d);
  }
  /**
   * Creates a new child managed object path beneath the provided
   * parent path using the relation's child managed object definition.
   *
   * @param <M>
   *          The type of client managed object configuration that the
   *          child path references.
   * @param <N>
   *          The type of server managed object configuration that the
   *          child path references.
   * @param r
   *          The instantiable relation referencing the child.
   * @param name
   *          The relative name of the child managed object.
   * @return Returns a new child managed object path beneath the
   *         provided parent path.
   * @throws IllegalArgumentException
   *           If the provided name is empty or blank.
   */
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(
      InstantiableRelationDefinition<M, N> r, String name)
      throws IllegalArgumentException {
    return child(r, r.getChildDefinition(), name);
  }
  /**
   * Creates a new child managed object path beneath the provided
   * parent path having the specified managed object definition.
   *
   * @param <M>
   *          The type of client managed object configuration that the
   *          child path references.
   * @param <N>
   *          The type of server managed object configuration that the
   *          child path references.
   * @param r
   *          The optional relation referencing the child.
   * @param d
   *          The managed object definition associated with the child
   *          (must be a sub-type of the relation).
   * @return Returns a new child managed object path beneath the
   *         provided parent path.
   */
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(
      OptionalRelationDefinition<? super M, ? super N> r,
      AbstractManagedObjectDefinition<M, N> d) {
    LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
        elements);
    celements.add(new OptionalElement<M, N>(r, d));
    return new ManagedObjectPath<M, N>(celements, r, d);
  }
  /**
   * Creates a new child managed object path beneath the provided
   * parent path using the relation's child managed object definition.
   *
   * @param <M>
   *          The type of client managed object configuration that the
   *          child path references.
   * @param <N>
   *          The type of server managed object configuration that the
   *          child path references.
   * @param r
   *          The optional relation referencing the child.
   * @return Returns a new child managed object path beneath the
   *         provided parent path.
   */
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(OptionalRelationDefinition<M, N> r) {
    return child(r, r.getChildDefinition());
  }
  /**
   * Creates a new child managed object path beneath the provided
   * parent path having the specified managed object definition.
   *
   * @param <M>
   *          The type of client managed object configuration that the
   *          child path references.
   * @param <N>
   *          The type of server managed object configuration that the
   *          child path references.
   * @param r
   *          The singleton relation referencing the child.
   * @param d
   *          The managed object definition associated with the child
   *          (must be a sub-type of the relation).
   * @return Returns a new child managed object path beneath the
   *         provided parent path.
   */
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(
      SingletonRelationDefinition<? super M, ? super N> r,
      AbstractManagedObjectDefinition<M, N> d) {
    LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
        elements);
    celements.add(new SingletonElement<M, N>(r, d));
    return new ManagedObjectPath<M, N>(celements, r, d);
  }
  /**
   * Creates a new child managed object path beneath the provided
   * parent path using the relation's child managed object definition.
   *
   * @param <M>
   *          The type of client managed object configuration that the
   *          child path references.
   * @param <N>
   *          The type of server managed object configuration that the
   *          child path references.
   * @param r
   *          The singleton relation referencing the child.
   * @return Returns a new child managed object path beneath the
   *         provided parent path.
   */
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(SingletonRelationDefinition<M, N> r) {
    return child(r, r.getChildDefinition());
  }
  /**
   * Creates a new child managed object path beneath the provided
   * parent path having the specified managed object definition.
   *
   * @param <M>
   *          The type of client managed object configuration that the
   *          child path references.
   * @param <N>
   *          The type of server managed object configuration that the
   *          child path references.
   * @param r
   *          The set relation referencing the child.
   * @param d
   *          The managed object definition associated with the child
   *          (must be a sub-type of the relation).
   * @return Returns a new child managed object path beneath the
   *         provided parent path.
   * @throws IllegalArgumentException
   *           If the provided name is empty or blank.
   */
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(
      SetRelationDefinition<? super M, ? super N> r,
      AbstractManagedObjectDefinition<M, N> d)
      throws IllegalArgumentException {
    LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
        elements);
    celements.add(new SetElement<M, N>(r, d));
    return new ManagedObjectPath<M, N>(celements, r, d);
  }
  /**
   * Creates a new child managed object path beneath the provided parent
   * path having the managed object definition indicated by
   * <code>name</code>.
   *
   * @param <M>
   *          The type of client managed object configuration that the
   *          path references.
   * @param <N>
   *          The type of server managed object configuration that the
   *          path references.
   * @param r
   *          The set relation referencing the child.
   * @param name
   *          The name of the managed object definition associated with
   *          the child (must be a sub-type of the relation).
   * @return Returns a new child managed object path beneath the
   *         provided parent path.
   * @throws IllegalArgumentException
   *           If the provided name is empty or blank or specifies a
   *           managed object definition which is not a sub-type of the
   *           relation's child definition.
   */
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<? extends M, ? extends N> child(
      SetRelationDefinition<M, N> r,
      String name)
      throws IllegalArgumentException {
    AbstractManagedObjectDefinition<M, N> d = r.getChildDefinition();
    return child(r, d.getChild(name));
  }
  /**
   * Creates a new child managed object path beneath the provided
   * parent path using the relation's child managed object definition.
   *
   * @param <M>
   *          The type of client managed object configuration that the
   *          child path references.
   * @param <N>
   *          The type of server managed object configuration that the
   *          child path references.
   * @param r
   *          The set relation referencing the child.
   * @return Returns a new child managed object path beneath the
   *         provided parent path.
   * @throws IllegalArgumentException
   *           If the provided name is empty or blank.
   */
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(
      SetRelationDefinition<M, N> r)
      throws IllegalArgumentException {
    return child(r, r.getChildDefinition());
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public boolean equals(Object obj) {
    if (obj == this) {
      return true;
    } else if (obj instanceof ManagedObjectPath) {
      ManagedObjectPath<?, ?> other = (ManagedObjectPath<?, ?>) obj;
      return toString().equals(other.toString());
    } else {
      return false;
    }
  }
  /**
   * Get the definition of the managed object referred to by this
   * path.
   * <p>
   * When the path is empty, the {@link RootCfgDefn} is returned.
   *
   * @return Returns the definition of the managed object referred to
   *         by this path, or the {@link RootCfgDefn} if the path is
   *         empty.
   */
  public AbstractManagedObjectDefinition<C, S> getManagedObjectDefinition() {
    return d;
  }
  /**
   * Get the name of the managed object referred to by this path if
   * applicable.
   * <p>
   * If there path does not refer to an instantiable managed object
   * <code>null</code> is returned.
   *
   * @return Returns the name of the managed object referred to by
   *         this path, or <code>null</code> if the managed object
   *         does not have a name.
   */
  public String getName() {
    if (elements.isEmpty()) {
      return null;
    } else {
      return elements.get(elements.size() - 1).getName();
    }
  }
  /**
   * Get the relation definition of the managed object referred to by
   * this path.
   * <p>
   * When the path is empty, the <code>null</code> is returned.
   *
   * @return Returns the relation definition of the managed object
   *         referred to by this path, or the <code>null</code> if
   *         the path is empty.
   */
  public RelationDefinition<? super C, ? super S> getRelationDefinition() {
    return r;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int hashCode() {
    return toString().hashCode();
  }
  /**
   * Determine whether or not this path contains any path elements.
   *
   * @return Returns <code>true</code> if this path does not contain
   *         any path elements.
   */
  public boolean isEmpty() {
    return elements.isEmpty();
  }
  /**
   * Determines whether this managed object path references the same
   * location as the provided managed object path.
   * <p>
   * This method differs from <code>equals</code> in that it ignores
   * sub-type definitions.
   *
   * @param other
   *          The managed object path to be compared.
   * @return Returns <code>true</code> if this managed object path
   *         references the same location as the provided managed
   *         object path.
   */
  public boolean matches(ManagedObjectPath<?, ?> other) {
    DN thisDN = toDN();
    DN otherDN = other.toDN();
    return thisDN.equals(otherDN);
  }
  /**
   * Creates a new parent managed object path representing the
   * immediate parent of this path. This method is a short-hand for
   * <code>parent(1)</code>.
   *
   * @return Returns a new parent managed object path representing the
   *         immediate parent of this path.
   * @throws IllegalArgumentException
   *           If this path does not have a parent (i.e. it is the
   *           empty path).
   */
  public ManagedObjectPath<?, ?> parent() throws IllegalArgumentException {
    return parent(1);
  }
  /**
   * Creates a new parent managed object path the specified number of
   * path elements above this path.
   *
   * @param offset
   *          The number of path elements (0 - means no offset, 1
   *          means the parent, and 2 means the grand-parent).
   * @return Returns a new parent managed object path the specified
   *         number of path elements above this path.
   * @throws IllegalArgumentException
   *           If the offset is less than 0, or greater than the
   *           number of path elements in this path.
   */
  public ManagedObjectPath<?, ?> parent(int offset)
      throws IllegalArgumentException {
    if (offset < 0) {
      throw new IllegalArgumentException("Negative offset");
    }
    if (offset > elements.size()) {
      throw new IllegalArgumentException(
          "Offset is greater than the number of path elements");
    }
    // An offset of 0 leaves the path unchanged.
    if (offset == 0) {
      return this;
    }
    // Return the empty path if the parent has zero elements.
    if (elements.size() == offset) {
      return emptyPath();
    }
    LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
        elements.subList(0, elements.size() - offset));
    return create(celements, celements.getLast());
  }
  /**
   * Creates a new managed object path which has the same structure as
   * this path except that the final path element is renamed. The
   * final path element must comprise of an instantiable relation.
   *
   * @param newName
   *          The new name of the final path element.
   * @return Returns a new managed object path which has the same
   *         structure as this path except that the final path element
   *         is renamed.
   * @throws IllegalStateException
   *           If this managed object path is empty or if its final
   *           path element does not comprise of an instantiable
   *           relation.
   */
  @SuppressWarnings("unchecked")
  public ManagedObjectPath<C, S> rename(String newName)
      throws IllegalStateException {
    if (elements.size() == 0) {
      throw new IllegalStateException("Cannot rename an empty path");
    }
    if (r instanceof InstantiableRelationDefinition) {
      InstantiableRelationDefinition<? super C, ? super S> ir =
        (InstantiableRelationDefinition<? super C, ? super S>) r;
      return parent().child(ir, d, newName);
    } else {
      throw new IllegalStateException("Not an instantiable relation");
    }
  }
  /**
   * Serialize this managed object path using the provided
   * serialization strategy.
   * <p>
   * The path elements will be passed to the serializer in big-endian
   * order: starting from the root element and proceeding down to the
   * leaf.
   *
   * @param serializer
   *          The managed object path serialization strategy.
   */
  public void serialize(ManagedObjectPathSerializer serializer) {
    for (Element<?, ?> element : elements) {
      element.serialize(serializer);
    }
  }
  /**
   * Get the number of path elements in this managed object path.
   *
   * @return Returns the number of path elements (0 - means no offset,
   *         1 means the parent, and 2 means the grand-parent).
   */
  public int size() {
    return elements.size();
  }
  /**
   * Creates a DN representation of this managed object path.
   *
   * @return Returns a DN representation of this managed object path.
   */
  public DN toDN() {
    // Use a simple serializer to create the contents.
    DNSerializer serializer = new DNSerializer();
    serialize(serializer);
    return serializer.toDN();
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {
    StringBuilder builder = new StringBuilder();
    toString(builder);
    return builder.toString();
  }
  /**
   * Appends a string representation of this managed object path to
   * the provided string builder.
   *
   * @param builder
   *          Append the string representation to this builder.
   * @see #toString()
   */
  public void toString(final StringBuilder builder) {
    if (isEmpty()) {
      // Special treatment of root configuration paths.
      builder.append('/');
    } else {
      // Use a simple serializer to create the contents.
      ManagedObjectPathSerializer serializer = new StringSerializer(builder);
      serialize(serializer);
    }
  }
}
opendj-admin/src/main/java/org/opends/server/admin/ManagedObjectPathSerializer.java
New file
@@ -0,0 +1,135 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * A strategy for serializing managed object paths.
 * <p>
 * This interface provides a generic means for serializing managed
 * object paths into application specific forms. For example, a JNDI
 * client would use this interface to construct <code>LdapName</code>
 * objects from a path. Similarly, on the server side, a serialization
 * strategy is used to construct <code>DN</code> instances from a
 * path.
 * <p>
 * During serialization the serializer is invoked for each element in
 * the managed object path in big-endian order, starting from the root
 * and proceeding down to the leaf element.
 */
public interface ManagedObjectPathSerializer {
  /**
   * Append a managed object path element identified by an
   * instantiable relation and an instance name.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this path element references.
   * @param <S>
   *          The type of server managed object configuration that
   *          this path element references.
   * @param r
   *          The instantiable relation.
   * @param d
   *          The managed object definition.
   * @param name
   *          The instance name.
   */
  <C extends ConfigurationClient, S extends Configuration>
      void appendManagedObjectPathElement(
      InstantiableRelationDefinition<? super C, ? super S> r,
      AbstractManagedObjectDefinition<C, S> d, String name);
  /**
   * Append a managed object path element identified by an optional
   * relation.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this path element references.
   * @param <S>
   *          The type of server managed object configuration that
   *          this path element references.
   * @param r
   *          The optional relation.
   * @param d
   *          The managed object definition.
   */
  <C extends ConfigurationClient, S extends Configuration>
      void appendManagedObjectPathElement(
      OptionalRelationDefinition<? super C, ? super S> r,
      AbstractManagedObjectDefinition<C, S> d);
  /**
   * Append a managed object path element identified by a singleton
   * relation.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this path element references.
   * @param <S>
   *          The type of server managed object configuration that
   *          this path element references.
   * @param r
   *          The singleton relation.
   * @param d
   *          The managed object definition.
   */
  <C extends ConfigurationClient, S extends Configuration>
      void appendManagedObjectPathElement(
      SingletonRelationDefinition<? super C, ? super S> r,
      AbstractManagedObjectDefinition<C, S> d);
  /**
   * Append a managed object path element identified by a
   * set relation.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this path element references.
   * @param <S>
   *          The type of server managed object configuration that
   *          this path element references.
   * @param r
   *          The set relation.
   * @param d
   *          The managed object definition.
   */
  <C extends ConfigurationClient, S extends Configuration>
      void appendManagedObjectPathElement(
      SetRelationDefinition<? super C, ? super S> r,
      AbstractManagedObjectDefinition<C, S> d);
}
opendj-admin/src/main/java/org/opends/server/admin/OperationsException.java
New file
@@ -0,0 +1,72 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
/**
 * Exceptions thrown as a result of errors that occurred when reading,
 * listing, and modifying managed objects.
 */
public abstract class OperationsException extends AdminException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = 6329910102360262187L;
  /**
   * Create an operations exception with a message and cause.
   *
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  protected OperationsException(Message message, Throwable cause) {
    super(message, cause);
  }
  /**
   * Create an operations exception with a message.
   *
   * @param message
   *          The message.
   */
  protected OperationsException(Message message) {
    super(message);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/OptionalRelationDefinition.java
New file
@@ -0,0 +1,183 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * A managed object composite relationship definition which represents
 * a composition of an optional single managed object (i.e. the
 * referenced managed object may or may not be present).
 *
 * @param <C>
 *          The type of client managed object configuration that this
 *          relation definition refers to.
 * @param <S>
 *          The type of server managed object configuration that this
 *          relation definition refers to.
 */
public final class OptionalRelationDefinition
    <C extends ConfigurationClient, S extends Configuration>
    extends RelationDefinition<C, S> {
  /**
   * An interface for incrementally constructing optional relation
   * definitions.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this relation definition refers to.
   */
  public static final class Builder
      <C extends ConfigurationClient, S extends Configuration>
      extends AbstractBuilder<C, S, OptionalRelationDefinition<C, S>> {
    // The optional default managed object associated with this
    // optional relation.
    private DefaultManagedObject<? extends C, ? extends S>
      defaultManagedObject = null;
    /**
     * Creates a new builder which can be used to incrementally build
     * an optional relation definition.
     *
     * @param pd
     *          The parent managed object definition.
     * @param name
     *          The name of the relation.
     * @param cd
     *          The child managed object definition.
     */
    public Builder(AbstractManagedObjectDefinition<?, ?> pd, String name,
        AbstractManagedObjectDefinition<C, S> cd) {
      super(pd, name, cd);
    }
    /**
     * Sets the optional default managed object associated with this
     * optional relation definition.
     *
     * @param defaultManagedObject
     *          The default managed object or <code>null</code> if
     *          there is no default managed object defined for this
     *          relation definition.
     */
    public void setDefaultManagedObject(
        DefaultManagedObject<? extends C, ? extends S> defaultManagedObject) {
      this.defaultManagedObject = defaultManagedObject;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected OptionalRelationDefinition<C, S> buildInstance(
        Common<C, S> common) {
      return new OptionalRelationDefinition<C, S>(common, defaultManagedObject);
    }
  }
  // The optional default managed object associated with this
  // optional relation.
  private final DefaultManagedObject<? extends C, ? extends S>
    defaultManagedObject;
  // Private constructor.
  private OptionalRelationDefinition(Common<C, S> common,
      DefaultManagedObject<? extends C, ? extends S> defaultManagedObject) {
    super(common);
    this.defaultManagedObject = defaultManagedObject;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p) {
    return v.visitOptional(this, p);
  }
  /**
   * Gets the optional default managed object associated with this
   * optional relation definition.
   *
   * @return Returns the default managed object or <code>null</code>
   *         if there is no default managed object defined for this
   *         relation definition.
   */
  public DefaultManagedObject<? extends C, ? extends S>
      getDefaultManagedObject() {
    return defaultManagedObject;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void toString(StringBuilder builder) {
    builder.append("name=");
    builder.append(getName());
    builder.append(" type=optional parent=");
    builder.append(getParentDefinition().getName());
    builder.append(" child=");
    builder.append(getChildDefinition().getName());
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected void initialize() throws Exception {
    if (defaultManagedObject != null) {
      defaultManagedObject.initialize();
    }
  }
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyDefinition.java
New file
@@ -0,0 +1,675 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static com.forgerock.opendj.util.Validator.*;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Set;
import org.forgerock.i18n.LocalizableMessage;
/**
 * An interface for querying generic property definition features.
 * <p>
 * Property definitions are analogous to ConfigAttributes in the
 * current model and will play a similar role. Eventually these will
 * replace them.
 * <p>
 * Implementations <b>must</b> take care to implement the various
 * comparison methods.
 *
 * @param <T>
 *          The data-type of values of the property.
 */
public abstract class PropertyDefinition<T> implements Comparator<T>,
    Comparable<PropertyDefinition<?>> {
  /**
   * An interface for incrementally constructing property definitions.
   *
   * @param <T>
   *          The data-type of values of the property.
   * @param <D>
   *          The type of property definition constructed by this
   *          builder.
   */
  protected abstract static class AbstractBuilder
      <T, D extends PropertyDefinition<T>> {
    // The administrator action.
    private AdministratorAction adminAction;
    // The default behavior provider.
    private DefaultBehaviorProvider<T> defaultBehavior;
    // The abstract managed object
    private final AbstractManagedObjectDefinition<?, ?> definition;
    // The options applicable to this definition.
    private final EnumSet<PropertyOption> options;
    // The name of this property definition.
    private final String propertyName;
    /**
     * Create a property definition builder.
     *
     * @param d
     *          The managed object definition associated with this
     *          property definition.
     * @param propertyName
     *          The property name.
     */
    protected AbstractBuilder(AbstractManagedObjectDefinition<?, ?> d,
        String propertyName) {
      this.definition = d;
      this.propertyName = propertyName;
      this.options = EnumSet.noneOf(PropertyOption.class);
      this.adminAction = new AdministratorAction(AdministratorAction.Type.NONE,
          d, propertyName);
      this.defaultBehavior = new UndefinedDefaultBehaviorProvider<T>();
    }
    /**
     * Construct a property definition based on the properties of this
     * builder.
     *
     * @return The new property definition.
     */
    public final D getInstance() {
      return buildInstance(definition, propertyName, options, adminAction,
          defaultBehavior);
    }
    /**
     * Set the administrator action.
     *
     * @param adminAction
     *          The administrator action.
     */
    public final void setAdministratorAction(AdministratorAction adminAction) {
      ensureNotNull(adminAction);
      this.adminAction = adminAction;
    }
    /**
     * Set the default behavior provider.
     *
     * @param defaultBehavior
     *          The default behavior provider.
     */
    public final void setDefaultBehaviorProvider(
        DefaultBehaviorProvider<T> defaultBehavior) {
      ensureNotNull(defaultBehavior);
      this.defaultBehavior = defaultBehavior;
    }
    /**
     * Add a property definition option.
     *
     * @param option
     *          The property option.
     */
    public final void setOption(PropertyOption option) {
      ensureNotNull(option);
      options.add(option);
    }
    /**
     * Build a property definition based on the properties of this
     * builder.
     *
     * @param d
     *          The managed object definition associated with this
     *          property definition.
     * @param propertyName
     *          The property name.
     * @param options
     *          Options applicable to this definition.
     * @param adminAction
     *          The administrator action.
     * @param defaultBehavior
     *          The default behavior provider.
     * @return The new property definition.
     */
    protected abstract D buildInstance(AbstractManagedObjectDefinition<?, ?> d,
        String propertyName, EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<T> defaultBehavior);
  }
  // The administrator action.
  private final AdministratorAction adminAction;
  // The default behavior provider.
  private final DefaultBehaviorProvider<T> defaultBehavior;
  // The abstract managed object
  private final AbstractManagedObjectDefinition<?, ?> definition;
  // Options applicable to this definition.
  private final Set<PropertyOption> options;
  // The property name.
  private final String propertyName;
  // The property value class.
  private final Class<T> theClass;
  /**
   * Create a property definition.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param theClass
   *          The property value class.
   * @param propertyName
   *          The property name.
   * @param options
   *          Options applicable to this definition.
   * @param adminAction
   *          The administrator action.
   * @param defaultBehavior
   *          The default behavior provider.
   */
  protected PropertyDefinition(AbstractManagedObjectDefinition<?, ?> d,
      Class<T> theClass, String propertyName, EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<T> defaultBehavior) {
    ensureNotNull(d, theClass, propertyName);
    ensureNotNull(options, adminAction, defaultBehavior);
    this.definition = d;
    this.theClass = theClass;
    this.propertyName = propertyName;
    this.options = EnumSet.copyOf(options);
    this.adminAction = adminAction;
    this.defaultBehavior = defaultBehavior;
  }
  /**
   * Apply a visitor to this property definition.
   *
   * @param <R>
   *          The return type of the visitor's methods.
   * @param <P>
   *          The type of the additional parameters to the visitor's
   *          methods.
   * @param v
   *          The property definition visitor.
   * @param p
   *          Optional additional visitor parameter.
   * @return Returns a result as specified by the visitor.
   */
  public abstract <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p);
  /**
   * Apply a visitor to a property value associated with this property
   * definition.
   *
   * @param <R>
   *          The return type of the visitor's methods.
   * @param <P>
   *          The type of the additional parameters to the visitor's
   *          methods.
   * @param v
   *          The property value visitor.
   * @param value
   *          The property value.
   * @param p
   *          Optional additional visitor parameter.
   * @return Returns a result as specified by the visitor.
   */
  public abstract <R, P> R accept(PropertyValueVisitor<R, P> v, T value, P p);
  /**
   * Cast the provided value to the type associated with this property
   * definition.
   * <p>
   * This method only casts the object to the required type; it does
   * not validate the value once it has been cast. Subsequent
   * validation should be performed using the method
   * {@link #validateValue(Object)}.
   * <p>
   * This method guarantees the following expression is always
   * <code>true</code>:
   *
   * <pre>
   *  PropertyDefinition d;
   *  x == d.cast(x);
   * </pre>
   *
   * @param object
   *          The property value to be cast (can be <code>null</code>).
   * @return Returns the property value cast to the correct type.
   * @throws ClassCastException
   *           If the provided property value did not have the correct
   *           type.
   */
  public final T castValue(Object object) throws ClassCastException {
    return theClass.cast(object);
  }
  /**
   * Compares two property values for order. Returns a negative
   * integer, zero, or a positive integer as the first argument is
   * less than, equal to, or greater than the second.
   * <p>
   * This default implementation normalizes both values using
   * {@link #normalizeValue(Object)} and then performs a
   * case-sensitive string comparison.
   *
   * @param o1
   *          the first object to be compared.
   * @param o2
   *          the second object to be compared.
   * @return a negative integer, zero, or a positive integer as the
   *         first argument is less than, equal to, or greater than
   *         the second.
   */
  public int compare(T o1, T o2) {
    ensureNotNull(o1, o2);
    String s1 = normalizeValue(o1);
    String s2 = normalizeValue(o2);
    return s1.compareTo(s2);
  }
  /**
   * Compares this property definition with the specified property
   * definition for order. Returns a negative integer, zero, or a
   * positive integer if this property definition is less than, equal
   * to, or greater than the specified property definition.
   * <p>
   * The ordering must be determined first from the property name and
   * then base on the underlying value type.
   *
   * @param o
   *          The reference property definition with which to compare.
   * @return Returns a negative integer, zero, or a positive integer
   *         if this property definition is less than, equal to, or
   *         greater than the specified property definition.
   */
  public final int compareTo(PropertyDefinition<?> o) {
    int rc = propertyName.compareTo(o.propertyName);
    if (rc == 0) {
      rc = theClass.getName().compareTo(o.theClass.getName());
    }
    return rc;
  }
  /**
   * Parse and validate a string representation of a property value.
   *
   * @param value
   *          The property string value (must not be <code>null</code>).
   * @return Returns the decoded property value.
   * @throws IllegalPropertyValueStringException
   *           If the property value string is invalid.
   */
  public abstract T decodeValue(String value)
      throws IllegalPropertyValueStringException;
  /**
   * Encode the provided property value into its string
   * representation.
   * <p>
   * This default implementation simply returns invokes the
   * {@link Object#toString()} method on the provided value.
   *
   * @param value
   *          The property value (must not be <code>null</code>).
   * @return Returns the encoded property string value.
   * @throws IllegalPropertyValueException
   *           If the property value is invalid.
   */
  public String encodeValue(T value) throws IllegalPropertyValueException {
    ensureNotNull(value);
    return value.toString();
  }
  /**
   * Indicates whether some other object is &quot;equal to&quot; this
   * property definition. This method must obey the general contract
   * of <tt>Object.equals(Object)</tt>. Additionally, this method
   * can return <tt>true</tt> <i>only</i> if the specified Object
   * is also a property definition and it has the same name, as
   * returned by {@link #getName()}, and also is deemed to be
   * &quot;compatible&quot; with this property definition.
   * Compatibility means that the two property definitions share the
   * same underlying value type and provide similar comparator
   * implementations.
   *
   * @param o
   *          The reference object with which to compare.
   * @return Returns <code>true</code> only if the specified object
   *         is also a property definition and it has the same name
   *         and is compatible with this property definition.
   * @see java.lang.Object#equals(java.lang.Object)
   * @see java.lang.Object#hashCode()
   */
  @Override
  public final boolean equals(Object o) {
    if (this == o) {
      return true;
    } else if (o instanceof PropertyDefinition) {
      PropertyDefinition<?> other = (PropertyDefinition<?>) o;
      if (propertyName.equals(other.propertyName)) {
        if (theClass.equals(other.theClass)) {
          return true;
        }
      }
      return false;
    } else {
      return false;
    }
  }
  /**
   * Get the administrator action associated with this property
   * definition. The administrator action describes any action which
   * the administrator must perform in order for changes to this
   * property to take effect.
   *
   * @return Returns the administrator action associated with this
   *         property definition.
   */
  public final AdministratorAction getAdministratorAction() {
    return adminAction;
  }
  /**
   * Get the default behavior provider associated with this property
   * definition.
   *
   * @return Returns the default behavior provider associated with
   *         this property definition.
   */
  public final DefaultBehaviorProvider<T> getDefaultBehaviorProvider() {
    return defaultBehavior;
  }
  /**
   * Gets the optional description of this property definition in the
   * default locale.
   *
   * @return Returns the description of this property definition in
   *         the default locale, or <code>null</code> if there is no
   *         description.
   */
  public final LocalizableMessage getDescription() {
    return getDescription(Locale.getDefault());
  }
  /**
   * Gets the optional description of this property definition in the
   * specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the description of this property definition in
   *         the specified locale, or <code>null</code> if there is
   *         no description.
   */
  public final LocalizableMessage getDescription(Locale locale) {
    ManagedObjectDefinitionI18NResource resource =
      ManagedObjectDefinitionI18NResource.getInstance();
    String property = "property." + propertyName + ".description";
    try {
      return resource.getLocalizableMessage(definition, property, locale);
    } catch (MissingResourceException e) {
      return null;
    }
  }
  /**
   * Gets the managed object definition associated with this property
   * definition.
   *
   * @return Returns the managed object definition associated with
   *         this property definition.
   */
  public final AbstractManagedObjectDefinition<?, ?>
      getManagedObjectDefinition() {
    return definition;
  }
  /**
   * Get the name of the property.
   *
   * @return Returns the name of the property.
   */
  public final String getName() {
    return propertyName;
  }
  /**
   * Gets the synopsis of this property definition in the default
   * locale.
   *
   * @return Returns the synopsis of this property definition in the
   *         default locale.
   */
  public final LocalizableMessage getSynopsis() {
    return getSynopsis(Locale.getDefault());
  }
  /**
   * Gets the synopsis of this property definition in the specified
   * locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the synopsis of this property definition in the
   *         specified locale.
   */
  public final LocalizableMessage getSynopsis(Locale locale) {
    ManagedObjectDefinitionI18NResource resource =
      ManagedObjectDefinitionI18NResource.getInstance();
    String property = "property." + propertyName + ".synopsis";
    return resource.getLocalizableMessage(definition, property, locale);
  }
  /**
   * Returns a hash code value for this property definition. The hash
   * code should be derived from the property name and the type of
   * values handled by this property definition.
   *
   * @return Returns the hash code value for this property definition.
   */
  @Override
  public final int hashCode() {
    int rc = 17 + propertyName.hashCode();
    return 37 * rc + theClass.hashCode();
  }
  /**
   * Check if the specified option is set for this property
   * definition.
   *
   * @param option
   *          The option to test.
   * @return Returns <code>true</code> if the option is set, or
   *         <code>false</code> otherwise.
   */
  public final boolean hasOption(PropertyOption option) {
    return options.contains(option);
  }
  /**
   * Get a normalized string representation of a property value. This
   * can then be used for comparisons and for generating hash-codes.
   * <p>
   * This method may throw an exception if the provided value is
   * invalid. However, applications should not assume that
   * implementations of this method will always validate a value. This
   * task is the responsibility of {@link #validateValue(Object)}.
   * <p>
   * This default implementation simply returns the string
   * representation of the provided value. Sub-classes might want to
   * override this method if this behavior is insufficient (for
   * example, a string property definition might strip white-space and
   * convert characters to lower-case).
   *
   * @param value
   *          The property value to be normalized.
   * @return Returns the normalized property value.
   * @throws IllegalPropertyValueException
   *           If the property value is invalid.
   */
  public String normalizeValue(T value) throws IllegalPropertyValueException {
    ensureNotNull(value);
    return encodeValue(value);
  }
  /**
   * Returns a string representation of this property definition.
   *
   * @return Returns a string representation of this property
   *         definition.
   * @see Object#toString()
   */
  @Override
  public final String toString() {
    StringBuilder builder = new StringBuilder();
    toString(builder);
    return builder.toString();
  }
  /**
   * Append a string representation of the property definition to the
   * provided string builder.
   * <p>
   * This simple implementation just outputs the propertyName of the
   * property definition. Sub-classes should override this method to
   * provide more complete string representations.
   *
   * @param builder
   *          The string builder where the string representation
   *          should be appended.
   */
  public void toString(StringBuilder builder) {
    builder.append(propertyName);
  }
  /**
   * Determine if the provided property value is valid according to
   * this property definition.
   *
   * @param value
   *          The property value (must not be <code>null</code>).
   * @throws IllegalPropertyValueException
   *           If the property value is invalid.
   */
  public abstract void validateValue(T value)
      throws IllegalPropertyValueException;
  /**
   * Performs any run-time initialization required by this property
   * definition. This may include resolving managed object paths and
   * property names.
   *
   * @throws Exception
   *           If this property definition could not be initialized.
   */
  protected void initialize() throws Exception {
    // No implementation required.
  }
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyDefinitionUsageBuilder.java
New file
@@ -0,0 +1,378 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import org.opends.messages.MessageBuilder;
import java.text.NumberFormat;
import java.util.EnumSet;
import java.util.Set;
import java.util.TreeSet;
/**
 * A property definition visitor which can be used to generate syntax
 * usage information.
 */
public final class PropertyDefinitionUsageBuilder {
  /**
   * Underlying implementation.
   */
  private class MyPropertyDefinitionVisitor extends
      PropertyDefinitionVisitor<Message, Void> {
    // Flag indicating whether detailed syntax information will be
    // generated.
    private final boolean isDetailed;
    // The formatter to use for numeric values.
    private final NumberFormat numberFormat;
    // Private constructor.
    private MyPropertyDefinitionVisitor(boolean isDetailed) {
      this.isDetailed = isDetailed;
      this.numberFormat = NumberFormat.getNumberInstance();
      this.numberFormat.setGroupingUsed(true);
      this.numberFormat.setMaximumFractionDigits(2);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public <C extends ConfigurationClient, S extends Configuration>
    Message visitAggregation(AggregationPropertyDefinition<C, S> d, Void p) {
      return Message.raw("NAME");
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitAttributeType(AttributeTypePropertyDefinition d,
        Void p) {
      return Message.raw("OID");
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitACI(ACIPropertyDefinition d,
        Void p) {
      return Message.raw("ACI");
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitBoolean(BooleanPropertyDefinition d, Void p) {
      if (isDetailed) {
        return Message.raw("false | true");
      } else {
        return Message.raw("BOOLEAN");
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitClass(ClassPropertyDefinition d, Void p) {
      if (isDetailed && !d.getInstanceOfInterface().isEmpty()) {
        return Message.raw("CLASS <= " + d.getInstanceOfInterface().get(0));
      } else {
        return Message.raw("CLASS");
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitDN(DNPropertyDefinition d, Void p) {
      if (isDetailed && d.getBaseDN() != null) {
        return Message.raw("DN <= " + d.getBaseDN());
      } else {
        return Message.raw("DN");
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitDuration(DurationPropertyDefinition d, Void p) {
      MessageBuilder builder = new MessageBuilder();
      DurationUnit unit = d.getBaseUnit();
      if (isDetailed && d.getLowerLimit() > 0) {
        builder.append(DurationUnit.toString(d.getLowerLimit()));
        builder.append(" <= ");
      }
      builder.append("DURATION (");
      builder.append(unit.getShortName());
      builder.append(")");
      if (isDetailed) {
        if (d.getUpperLimit() != null) {
          builder.append(" <= ");
          builder.append(DurationUnit.toString(d.getUpperLimit()));
        }
        if (d.isAllowUnlimited()) {
          builder.append(" | unlimited");
        }
      }
      return builder.toMessage();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public <E extends Enum<E>> Message visitEnum(EnumPropertyDefinition<E> d,
        Void p) {
      if (!isDetailed) {
        // Use the last word in the property name.
        String name = d.getName();
        int i = name.lastIndexOf('-');
        if (i == -1 || i == (name.length() - 1)) {
          return Message.raw(name.toUpperCase());
        } else {
          return Message.raw(name.substring(i + 1).toUpperCase());
        }
      } else {
        Set<String> values = new TreeSet<String>();
        for (Object value : EnumSet.allOf(d.getEnumClass())) {
          values.add(value.toString().trim().toLowerCase());
        }
        boolean isFirst = true;
        MessageBuilder builder = new MessageBuilder();
        for (String s : values) {
          if (!isFirst) {
            builder.append(" | ");
          }
          builder.append(s);
          isFirst = false;
        }
        return builder.toMessage();
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitInteger(IntegerPropertyDefinition d, Void p) {
      MessageBuilder builder = new MessageBuilder();
      if (isDetailed) {
        builder.append(String.valueOf(d.getLowerLimit()));
        builder.append(" <= ");
      }
      builder.append("INTEGER");
      if (isDetailed) {
        if (d.getUpperLimit() != null) {
          builder.append(" <= ");
          builder.append(String.valueOf(d.getUpperLimit()));
        } else if (d.isAllowUnlimited()) {
          builder.append(" | unlimited");
        }
      }
      return builder.toMessage();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitIPAddress(IPAddressPropertyDefinition d, Void p) {
      return Message.raw("HOST_NAME");
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitIPAddressMask(IPAddressMaskPropertyDefinition d,
        Void p) {
      return Message.raw("IP_ADDRESS_MASK");
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitSize(SizePropertyDefinition d, Void p) {
      MessageBuilder builder = new MessageBuilder();
      if (isDetailed && d.getLowerLimit() > 0) {
        SizeUnit unit = SizeUnit.getBestFitUnitExact(d.getLowerLimit());
        builder.append(numberFormat.format(unit.fromBytes(d.getLowerLimit())));
        builder.append(' ');
        builder.append(unit.getShortName());
        builder.append(" <= ");
      }
      builder.append("SIZE");
      if (isDetailed) {
        if (d.getUpperLimit() != null) {
          long upperLimit = d.getUpperLimit();
          SizeUnit unit = SizeUnit.getBestFitUnitExact(upperLimit);
          // Quite often an upper limit is some power of 2 minus 1. In those
          // cases lets use a "less than" relation rather than a "less than
          // or equal to" relation. This will result in a much more readable
          // quantity.
          if (unit == SizeUnit.BYTES && upperLimit < Long.MAX_VALUE) {
            unit = SizeUnit.getBestFitUnitExact(upperLimit + 1);
            if (unit != SizeUnit.BYTES) {
              upperLimit += 1;
              builder.append(" < ");
            } else {
              builder.append(" <= ");
            }
          } else {
            builder.append(" <= ");
          }
          builder.append(numberFormat.format(unit.fromBytes(upperLimit)));
          builder.append(' ');
          builder.append(unit.getShortName());
        }
        if (d.isAllowUnlimited()) {
          builder.append(" | unlimited");
        }
      }
      return builder.toMessage();
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public Message visitString(StringPropertyDefinition d, Void p) {
      if (d.getPattern() != null) {
        if (isDetailed) {
          MessageBuilder builder = new MessageBuilder();
          builder.append(d.getPatternUsage());
          builder.append(" - ");
          builder.append(d.getPatternSynopsis());
          return builder.toMessage();
        } else {
          return Message.raw(d.getPatternUsage());
        }
      } else {
        return Message.raw("STRING");
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public <T> Message visitUnknown(PropertyDefinition<T> d, Void p)
        throws UnknownPropertyDefinitionException {
      return Message.raw("?");
    }
  }
  // Underlying implementation.
  private final MyPropertyDefinitionVisitor pimpl;
  /**
   * Creates a new property usage builder.
   *
   * @param isDetailed
   *          Indicates whether or not the generated usage should
   *          contain detailed information such as constraints.
   */
  public PropertyDefinitionUsageBuilder(boolean isDetailed) {
    this.pimpl = new MyPropertyDefinitionVisitor(isDetailed);
  }
  /**
   * Generates the usage information for the provided property
   * definition.
   *
   * @param pd
   *          The property definitions.
   * @return Returns the usage information for the provided property
   *         definition.
   */
  public Message getUsage(PropertyDefinition<?> pd) {
    return pd.accept(pimpl, null);
  };
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyDefinitionVisitor.java
New file
@@ -0,0 +1,297 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * A visitor of property definitions, in the style of the visitor
 * design pattern. Classes implementing this interface can query
 * property definitions in a type-safe manner when the kind of
 * property definition is unknown at compile time. When a visitor is
 * passed to a property definition's accept method, the corresponding
 * visit method most applicable to that property definition is
 * invoked.
 * <p>
 * Each <code>visitXXX</code> method is provided with a default
 * implementation which calls
 * {@link #visitUnknown(PropertyDefinition, Object)}. Sub-classes can
 * override any or all of the methods to provide their own
 * type-specific behavior.
 *
 * @param <R>
 *          The return type of this visitor's methods. Use
 *          {@link java.lang.Void} for visitors that do not need to
 *          return results.
 * @param <P>
 *          The type of the additional parameter to this visitor's
 *          methods. Use {@link java.lang.Void} for visitors that do
 *          not need an additional parameter.
 */
public abstract class PropertyDefinitionVisitor<R, P> {
  /**
   * Default constructor.
   */
  protected PropertyDefinitionVisitor() {
    // No implementation required.
  }
  /**
   * Visit a dseecompat Global ACI property definition.
   *
   * @param pd
   *          The Global ACI property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitACI(ACIPropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit an aggregation property definition.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this aggregation property definition refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this aggregation property definition refers to.
   * @param pd
   *          The aggregation property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public <C extends ConfigurationClient, S extends Configuration>
  R visitAggregation(AggregationPropertyDefinition<C, S> pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit an attribute type property definition.
   *
   * @param pd
   *          The attribute type property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitAttributeType(AttributeTypePropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit a boolean property definition.
   *
   * @param pd
   *          The boolean property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitBoolean(BooleanPropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit a class property definition.
   *
   * @param pd
   *          The class property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitClass(ClassPropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit a DN property definition.
   *
   * @param pd
   *          The DN property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitDN(DNPropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit a duration property definition.
   *
   * @param pd
   *          The duration property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitDuration(DurationPropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit an enumeration property definition.
   *
   * @param <E>
   *          The enumeration that should be used for values of the
   *          property definition.
   * @param pd
   *          The enumeration property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public <E extends Enum<E>> R visitEnum(EnumPropertyDefinition<E> pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit an integer property definition.
   *
   * @param pd
   *          The integer property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitInteger(IntegerPropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit a IP address property definition.
   *
   * @param pd
   *          The IP address property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitIPAddress(IPAddressPropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit a IP address mask property definition.
   *
   * @param pd
   *          The IP address mask property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitIPAddressMask(IPAddressMaskPropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit a size property definition.
   *
   * @param pd
   *          The size property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitSize(SizePropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit a string property definition.
   *
   * @param pd
   *          The string property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitString(StringPropertyDefinition pd, P p) {
    return visitUnknown(pd, p);
  }
  /**
   * Visit an unknown type of property definition. Implementations of
   * this method can provide default behavior for unknown property
   * definition types.
   * <p>
   * The default implementation of this method throws an
   * {@link UnknownPropertyDefinitionException}. Sub-classes can
   * override this method with their own default behavior.
   *
   * @param <T>
   *          The type of the underlying property.
   * @param pd
   *          The property definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   * @throws UnknownPropertyDefinitionException
   *           Visitor implementations may optionally throw this
   *           exception.
   */
  public <T> R visitUnknown(PropertyDefinition<T> pd, P p)
      throws UnknownPropertyDefinitionException {
    throw new UnknownPropertyDefinitionException(pd, p);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyException.java
New file
@@ -0,0 +1,99 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
/**
 * Exceptions thrown as a result of errors that occurred when decoding
 * and modifying property values.
 */
public abstract class PropertyException extends AdminRuntimeException {
  /**
   * Version ID required by serializable classes.
   */
  private static final long serialVersionUID = -8465109598081914482L;
  // The property definition associated with the property that caused
  // the exception.
  private final PropertyDefinition<?> pd;
  /**
   * Creates property exception without a cause.
   *
   * @param pd
   *          The property definition associated with the property
   *          that caused the exception.
   * @param message
   *          The message.
   */
  protected PropertyException(PropertyDefinition<?> pd, Message message) {
    super(message);
    this.pd = pd;
  }
  /**
   * Creates property exception with a cause.
   *
   * @param pd
   *          The property definition associated with the property
   *          that caused the exception.
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  protected PropertyException(PropertyDefinition<?> pd, Message message,
      Throwable cause) {
    super(message, cause);
    this.pd = pd;
  }
  /**
   * Get the property definition associated with the property that
   * caused the exception.
   *
   * @return Returns the property definition associated with the
   *         property that caused the exception.
   */
  public final PropertyDefinition<?> getPropertyDefinition() {
    return pd;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyIsMandatoryException.java
New file
@@ -0,0 +1,58 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
/**
 * Thrown when an attempt is made to remove a mandatory property.
 */
public class PropertyIsMandatoryException extends PropertyException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = 5328211711156565625L;
  /**
   * Create a new property is mandatory exception.
   *
   * @param pd
   *          The property definition.
   */
  public PropertyIsMandatoryException(PropertyDefinition<?> pd) {
    super(pd, ERR_PROPERTY_IS_MANDATORY_EXCEPTION.get(pd.getName()));
  }
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyIsReadOnlyException.java
New file
@@ -0,0 +1,58 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
/**
 * Thrown when an attempt is made to modify a read-only property.
 */
public class PropertyIsReadOnlyException extends PropertyException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = 5315348044141024459L;
  /**
   * Create a new property is read-only exception.
   *
   * @param pd
   *          The property definition.
   */
  public PropertyIsReadOnlyException(PropertyDefinition<?> pd) {
    super(pd, ERR_PROPERTY_IS_READ_ONLY_EXCEPTION.get(pd.getName()));
  }
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyIsSingleValuedException.java
New file
@@ -0,0 +1,58 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
/**
 * Thrown when an attempt is made to add more than value to a
 * single-valued property.
 */
public class PropertyIsSingleValuedException extends PropertyException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = -8056602690887917027L;
  /**
   * Create a new property is single valued exception.
   *
   * @param pd
   *          The property definition.
   */
  public PropertyIsSingleValuedException(PropertyDefinition<?> pd) {
    super(pd, ERR_PROPERTY_IS_SINGLE_VALUED_EXCEPTION.get(pd.getName()));
  }
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyNotFoundException.java
New file
@@ -0,0 +1,75 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
/**
 * Thrown when an attempt is made to retrieve a property using its name but the
 * name was not recognized.
 * <p>
 * This exception can occur when attempt is made to retrieve inherited default
 * values from a managed object.
 */
public class PropertyNotFoundException extends OperationsException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = -895548482881819610L;
  // The name of the property that could not be found.
  private final String propertyName;
  /**
   * Create a new property not found exception.
   *
   * @param propertyName
   *          The name of the property that could not be found.
   */
  public PropertyNotFoundException(String propertyName) {
    super(ERR_PROPERTY_NOT_FOUND_EXCEPTION.get(propertyName));
    this.propertyName = propertyName;
  }
  /**
   * Get the name of the property that could not be found.
   *
   * @return Returns the name of the property that could not be found.
   */
  public String getPropertyName() {
    return propertyName;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyOption.java
New file
@@ -0,0 +1,71 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * This enumeration contains various options that can be associated
 * with property definitions.
 */
public enum PropertyOption {
  /**
   * Use this option to identify properties which should be considered
   * as advanced and should not be exposed by default in client
   * applications.
   */
  ADVANCED,
  /**
   * Use this option to identify properties which must not be directly
   * exposed in client applications.
   */
  HIDDEN,
  /**
   * Use this option to identify properties which must have a value.
   */
  MANDATORY,
  /**
   * Use this option to identify properties which are multi-valued.
   */
  MULTI_VALUED,
  /**
   * Use this option to identify properties which can be initialized
   * once only and are read-only thereafter.
   */
  READ_ONLY,
  /**
   * Use this option to identify properties which are for monitoring
   * purposes only and are generated automatically by the server..
   */
  MONITORING;
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyProvider.java
New file
@@ -0,0 +1,89 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.Collection;
import java.util.Collections;
/**
 * An interface which can be used to initialize the contents of a managed
 * object.
 */
public interface PropertyProvider {
  /**
   * A property provider which always returns empty property values, indicating
   * default behavior.
   */
  public static final PropertyProvider DEFAULT_PROVIDER =
    new PropertyProvider() {
    /**
     * {@inheritDoc}
     */
    public <T> Collection<T> getPropertyValues(PropertyDefinition<T> d)
        throws IllegalArgumentException {
      return Collections.<T> emptySet();
    }
  };
  /**
   * Get the property values associated with the specified property definition.
   * <p>
   * Implementations are not required to validate the values that they provide.
   * Specifically:
   * <ul>
   * <li>they do not need to guarantee that the provided values are valid
   * according to the property's syntax
   * <li>they do not need to provide values for mandatory properties
   * <li>they do not need to ensure that single-valued properties do contain at
   * most one value.
   * </ul>
   * The returned set of values is allowed to contain duplicates.
   *
   * @param <T>
   *          The underlying type of the property.
   * @param d
   *          The Property definition.
   * @return Returns a newly allocated set containing a copy of the property's
   *         values. An empty set indicates that the property has no values
   *         defined and any default behavior is applicable.
   * @throws IllegalArgumentException
   *           If this property provider does not recognise the requested
   *           property definition.
   */
  <T> Collection<T> getPropertyValues(PropertyDefinition<T> d)
      throws IllegalArgumentException;
}
opendj-admin/src/main/java/org/opends/server/admin/PropertyValueVisitor.java
New file
@@ -0,0 +1,337 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.net.InetAddress;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.schema.AttributeType;
import org.opends.server.authorization.dseecompat.Aci;
import org.opends.server.types.AddressMask;
/**
 * A visitor of property values, in the style of the visitor design
 * pattern. Classes implementing this interface can query a property a
 * value and its associated property definition in a type-safe manner
 * when the kind of property value is unknown at compile time. When a
 * visitor is passed to a property definition's accept method, the
 * corresponding visit method most applicable to that property
 * definition is invoked.
 * <p>
 * Each <code>visitXXX</code> method is provided with a default
 * implementation which calls
 * {@link #visitUnknown(PropertyDefinition, Object, Object)}.
 * Sub-classes can override any or all of the methods to provide their
 * own type-specific behavior.
 *
 * @param <R>
 *          The return type of this visitor's methods. Use
 *          {@link java.lang.Void} for visitors that do not need to
 *          return results.
 * @param <P>
 *          The type of the additional parameter to this visitor's
 *          methods. Use {@link java.lang.Void} for visitors that do
 *          not need an additional parameter.
 */
public abstract class PropertyValueVisitor<R, P> {
  /**
   * Default constructor.
   */
  protected PropertyValueVisitor() {
    // No implementation required.
  }
  /**
   * Visit a dseecompat ACI.
   *
   * @param pd
   *          The dseecompat ACI property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitACI(ACIPropertyDefinition pd, Aci v,
      P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit an aggregation property value.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this aggregation property definition refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this aggregation property definition refers to.
   * @param pd
   *          The aggregation property definition to visit.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public <C extends ConfigurationClient, S extends Configuration>
  R visitAggregation(
      AggregationPropertyDefinition<C, S> pd, String v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit an attribute type.
   *
   * @param pd
   *          The attribute type property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitAttributeType(AttributeTypePropertyDefinition pd,
      AttributeType v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit a boolean.
   *
   * @param pd
   *          The boolean property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitBoolean(BooleanPropertyDefinition pd, Boolean v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit a class.
   *
   * @param pd
   *          The class property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitClass(ClassPropertyDefinition pd, String v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit a DN.
   *
   * @param pd
   *          The DN property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitDN(DNPropertyDefinition pd, DN v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit a duration.
   *
   * @param pd
   *          The duration property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitDuration(DurationPropertyDefinition pd, Long v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit an enumeration.
   *
   * @param <E>
   *          The enumeration that should be used for values of the
   *          property definition.
   * @param pd
   *          The enumeration property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public <E extends Enum<E>>
  R visitEnum(EnumPropertyDefinition<E> pd, E v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit an integer.
   *
   * @param pd
   *          The integer property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitInteger(IntegerPropertyDefinition pd, Integer v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit a IP address.
   *
   * @param pd
   *          The IP address property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitIPAddress(IPAddressPropertyDefinition pd, InetAddress v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit a IP address mask.
   *
   * @param pd
   *          The IP address mask property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitIPAddressMask(IPAddressMaskPropertyDefinition pd, AddressMask v,
      P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit a size.
   *
   * @param pd
   *          The size property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitSize(SizePropertyDefinition pd, Long v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit a string.
   *
   * @param pd
   *          The string property definition.
   * @param v
   *          The property value to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  public R visitString(StringPropertyDefinition pd, String v, P p) {
    return visitUnknown(pd, v, p);
  }
  /**
   * Visit an unknown type of property value. Implementations of this
   * method can provide default behavior for unknown types of
   * property.
   * <p>
   * The default implementation of this method throws an
   * {@link UnknownPropertyDefinitionException}. Sub-classes can
   * override this method with their own default behavior.
   *
   * @param <T>
   *          The type of property value to visit.
   * @param pd
   *          The property definition.
   * @param v
   *          The property value.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   * @throws UnknownPropertyDefinitionException
   *           Visitor implementations may optionally throw this
   *           exception.
   */
  public <T> R visitUnknown(PropertyDefinition<T> pd, T v, P p)
      throws UnknownPropertyDefinitionException {
    throw new UnknownPropertyDefinitionException(pd, p);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/Reference.java
New file
@@ -0,0 +1,245 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.server.types.AttributeValue;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.RDN;
import org.opends.server.util.StaticUtils;
/**
 * A reference to another managed object.
 *
 * @param <C>
 *          The type of client managed object configuration that this
 *          reference refers to.
 * @param <S>
 *          The type of server managed object configuration that this
 *          reference refers to.
 */
public final class Reference<C extends ConfigurationClient,
                             S extends Configuration> {
  /**
   * Parses a DN string value as a reference using the provided
   * managed object path and relation definition.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this reference refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this reference refers to.
   * @param p
   *          The path of the referenced managed object's parent.
   * @param rd
   *          The instantiable relation in the parent which contains
   *          the referenced managed object.
   * @param s
   *          The DN string value.
   * @return Returns the new reference based on the provided DN string
   *         value.
   * @throws IllegalArgumentException
   *           If the DN string value could not be decoded as a DN or
   *           if the provided DN did not correspond to the provided
   *           path and relation.
   */
  public static <C extends ConfigurationClient, S extends Configuration>
  Reference<C, S> parseDN(
      ManagedObjectPath<?, ?> p, InstantiableRelationDefinition<C, S> rd,
      String s) throws IllegalArgumentException {
    AbstractManagedObjectDefinition<?, ?> d = p.getManagedObjectDefinition();
    RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName());
    if (tmp != rd) {
      throw new IllegalArgumentException("The relation \"" + rd.getName()
          + "\" is not associated with the definition \"" + d.getName() + "\"");
    }
    DN dn;
    try {
      dn = DN.decode(s);
    } catch (DirectoryException e) {
      throw new IllegalArgumentException("Unabled to decode the DN string: \""
          + s + "\"");
    }
    RDN rdn = dn.getRDN();
    if (rdn == null) {
      throw new IllegalArgumentException("Unabled to decode the DN string: \""
          + s + "\"");
    }
    AttributeValue av = rdn.getAttributeValue(0);
    if (av == null) {
      throw new IllegalArgumentException("Unabled to decode the DN string: \""
          + s + "\"");
    }
    String name = av.getValue().toString();
    // Check that the DN was valid.
    DN expected = p.child(rd, name).toDN();
    if (!dn.equals(expected)) {
      throw new IllegalArgumentException("Unabled to decode the DN string: \""
          + s + "\"");
    }
    return new Reference<C, S>(p, rd, name);
  }
  /**
   * Parses a name as a reference using the provided managed object
   * path and relation definition.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this reference refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this reference refers to.
   * @param p
   *          The path of the referenced managed object's parent.
   * @param rd
   *          The instantiable relation in the parent which contains
   *          the referenced managed object.
   * @param s
   *          The name of the referenced managed object.
   * @return Returns the new reference based on the provided name.
   * @throws IllegalArgumentException
   *           If the relation is not associated with the provided
   *           parent's definition, or if the provided name is empty.
   */
  public static <C extends ConfigurationClient, S extends Configuration>
  Reference<C, S> parseName(
      ManagedObjectPath<?, ?> p, InstantiableRelationDefinition<C, S> rd,
      String s) throws IllegalArgumentException {
    // Sanity checks.
    AbstractManagedObjectDefinition<?, ?> d = p.getManagedObjectDefinition();
    RelationDefinition<?, ?> tmp = d.getRelationDefinition(rd.getName());
    if (tmp != rd) {
      throw new IllegalArgumentException("The relation \"" + rd.getName()
          + "\" is not associated with the definition \"" + d.getName() + "\"");
    }
    if (s.trim().length() == 0) {
      throw new IllegalArgumentException("Empty names are not allowed");
    }
    return new Reference<C, S>(p, rd, s);
  }
  // The name of the referenced managed object.
  private final String name;
  // The path of the referenced managed object.
  private final ManagedObjectPath<C, S> path;
  // The instantiable relation in the parent which contains the
  // referenced managed object.
  private final InstantiableRelationDefinition<C, S> relation;
  // Private constructor.
  private Reference(ManagedObjectPath<?, ?> parent,
      InstantiableRelationDefinition<C, S> relation, String name)
      throws IllegalArgumentException {
    this.relation = relation;
    this.name = name;
    this.path = parent.child(relation, name);
  }
  /**
   * Gets the name of the referenced managed object.
   *
   * @return Returns the name of the referenced managed object.
   */
  public String getName() {
    return name;
  }
  /**
   * Gets the normalized name of the referenced managed object.
   *
   * @return Returns the normalized name of the referenced managed
   *         object.
   */
  public String getNormalizedName() {
    PropertyDefinition<?> pd = relation.getNamingPropertyDefinition();
    return normalizeName(pd);
  }
  /**
   * Gets the DN of the referenced managed object.
   *
   * @return Returns the DN of the referenced managed object.
   */
  public DN toDN() {
    return path.toDN();
  }
  /**
   * {@inheritDoc}
   */
  public String toString() {
    return name;
  }
  // Normalize a value using the specified naming property definition
  // if defined.
  private <T> String normalizeName(PropertyDefinition<T> pd) {
    if (pd != null) {
      try {
        T tvalue = pd.decodeValue(name);
        return pd.normalizeValue(tvalue);
      } catch (IllegalPropertyValueStringException e) {
        // Fall through to default normalization.
      }
    }
    // FIXME: should really use directory string normalizer.
    String s = name.trim().replaceAll(" +", " ");
    return StaticUtils.toLowerCase(s);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/RelationDefinition.java
New file
@@ -0,0 +1,421 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import static org.opends.server.util.Validator.*;
import java.util.EnumSet;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.Set;
/**
 * Relation definitions define relationships between types of managed
 * objects. In addition they define the ownership model:
 * <ul>
 * <li>composition - referenced managed objects are owned by the
 * parent managed object and are deleted when the parent is deleted
 * <li>aggregation - referenced managed objects are not owned by the
 * parent managed object. Instead they are shared by other managed
 * objects.
 * </ul>
 * Relations define how clients interact with the configuration. For
 * example, clients manage aggregated managed objects in a shared
 * location and attach them to parent managed objects. Composed
 * managed objects, on the other hand, would be created directly
 * beneath the parent managed object and destroyed with it too.
 * <p>
 * Within the server, listeners can choose to request notification of
 * managed objects being added or removed from relations.
 * <p>
 * In LDAP, compositions are represented as follows:
 * <ul>
 * <li>singleton relations (one to one): a referenced managed object
 * is represented using a child entry directly beneath the parent
 * <li>optional relations (one to zero or one): a referenced managed
 * object is represented using a child entry directly beneath the
 * parent
 * <li>instantiable relations (one to many): the relation is
 * represented using a child entry directly beneath the parent.
 * Referenced managed objects are represented using child entries of
 * this "relation entry" and are named by the user
 * <li>set relations (one to many): the relation is
 * represented using a child entry directly beneath the parent.
 * Referenced managed objects are represented using child entries of
 * this "relation entry" whose name is the type of the managed object.
 * </ul>
 * Whereas, aggregations are represented by storing the DNs of the
 * referenced managed objects in an attribute of the aggregating
 * managed object.
 *
 * @param <C>
 *          The type of client managed object configuration that this
 *          relation definition refers to.
 * @param <S>
 *          The type of server managed object configuration that this
 *          relation definition refers to.
 */
public abstract class RelationDefinition
    <C extends ConfigurationClient, S extends Configuration> {
  /**
   * An interface for incrementally constructing relation definitions.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this relation definition refers to.
   * @param <D>
   *          The type of relation definition constructed by this
   *          builder.
   */
  protected abstract static class AbstractBuilder
      <C extends ConfigurationClient, S extends Configuration,
       D extends RelationDefinition<C, S>> {
    // Common fields.
    private final Common<C, S> common;
    /**
     * Create a property definition builder.
     *
     * @param pd
     *          The parent managed object definition.
     * @param name
     *          The name of the relation.
     * @param cd
     *          The child managed object definition.
     */
    protected AbstractBuilder(AbstractManagedObjectDefinition<?, ?> pd,
        String name, AbstractManagedObjectDefinition<C, S> cd) {
      this.common = new Common<C, S>(pd, name, cd);
    }
    /**
     * Construct a relation definition based on the properties of this
     * builder.
     *
     * @return The new relation definition.
     */
    public final D getInstance() {
      return buildInstance(common);
    }
    /**
     * Add a relation definition option.
     *
     * @param option
     *          The relation option.
     */
    public final void setOption(RelationOption option) {
      ensureNotNull(option);
      common.options.add(option);
    }
    /**
     * Build a relation definition based on the properties of this
     * builder.
     *
     * @param common
     *          The common fields of the new relation definition.
     * @return The new relation definition.
     */
    protected abstract D buildInstance(Common<C, S> common);
  }
  /**
   * Opaque structure containing fields common to all relation
   * definition types.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this relation definition refers to.
   */
  protected static final class Common
    <C extends ConfigurationClient, S extends Configuration> {
    // The definition of the child managed object.
    private final AbstractManagedObjectDefinition<C, S> cd;
    // The name of the relation.
    private final String name;
    // Options applicable to this definition.
    private final Set<RelationOption> options;
    // The definition of the parent managed object.
    private final AbstractManagedObjectDefinition<?, ?> pd;
    // Private constructor.
    private Common(AbstractManagedObjectDefinition<?, ?> pd, String name,
        AbstractManagedObjectDefinition<C, S> cd) {
      this.name = name;
      this.pd = pd;
      this.cd = cd;
      this.options = EnumSet.noneOf(RelationOption.class);
    }
  }
  // Common fields.
  private final Common<C, S> common;
  /**
   * Create a new managed object relation definition with the
   * specified common fields.
   *
   * @param common
   *          The common fields of the new relation definition.
   */
  protected RelationDefinition(Common<C, S> common) {
    this.common = common;
  }
  /**
   * Apply a visitor to this relation definition.
   *
   * @param <R>
   *          The return type of the visitor's methods.
   * @param <P>
   *          The type of the additional parameters to the visitor's
   *          methods.
   * @param v
   *          The relation definition visitor.
   * @param p
   *          Optional additional visitor parameter.
   * @return Returns a result as specified by the visitor.
   */
  public abstract <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p);
  /**
   * Get the definition of the child managed object.
   *
   * @return Returns the definition of the child managed object.
   */
  public final AbstractManagedObjectDefinition<C, S> getChildDefinition() {
    return common.cd;
  }
  /**
   * Gets the optional description of this relation definition in the
   * default locale.
   *
   * @return Returns the description of this relation definition in
   *         the default locale, or <code>null</code> if there is no
   *         description.
   */
  public final Message getDescription() {
    return getDescription(Locale.getDefault());
  }
  /**
   * Gets the optional description of this relation definition in the
   * specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the description of this relation definition in
   *         the specified locale, or <code>null</code> if there is
   *         no description.
   */
  public final Message getDescription(Locale locale) {
    try {
      String property = "relation." + common.name + ".description";
      return ManagedObjectDefinitionI18NResource.getInstance().getMessage(
          getParentDefinition(), property, locale);
    } catch (MissingResourceException e) {
      return null;
    }
  }
  /**
   * Get the name of the relation.
   *
   * @return Returns the name of the relation.
   */
  public final String getName() {
    return common.name;
  }
  /**
   * Get the definition of the parent managed object.
   *
   * @return Returns the definition of the parent managed object.
   */
  public final AbstractManagedObjectDefinition<?, ?> getParentDefinition() {
    return common.pd;
  }
  /**
   * Gets the synopsis of this relation definition in the default
   * locale.
   *
   * @return Returns the synopsis of this relation definition in the
   *         default locale.
   */
  public final Message getSynopsis() {
    return getSynopsis(Locale.getDefault());
  }
  /**
   * Gets the synopsis of this relation definition in the specified
   * locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the synopsis of this relation definition in the
   *         specified locale.
   */
  public final Message getSynopsis(Locale locale) {
    String property = "relation." + common.name + ".synopsis";
    return ManagedObjectDefinitionI18NResource.getInstance().getMessage(
        getParentDefinition(), property, locale);
  }
  /**
   * Gets the user friendly name of this relation definition in the
   * default locale.
   *
   * @return Returns the user friendly name of this relation
   *         definition in the default locale.
   */
  public final Message getUserFriendlyName() {
    return getUserFriendlyName(Locale.getDefault());
  }
  /**
   * Gets the user friendly name of this relation definition in the
   * specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the user friendly name of this relation
   *         definition in the specified locale.
   */
  public final Message getUserFriendlyName(Locale locale) {
    String property = "relation." + common.name + ".user-friendly-name";
    return ManagedObjectDefinitionI18NResource.getInstance().getMessage(
        getParentDefinition(), property, locale);
  }
  /**
   * Check if the specified option is set for this relation
   * definition.
   *
   * @param option
   *          The option to test.
   * @return Returns <code>true</code> if the option is set, or
   *         <code>false</code> otherwise.
   */
  public final boolean hasOption(RelationOption option) {
    return common.options.contains(option);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public final String toString() {
    StringBuilder builder = new StringBuilder();
    toString(builder);
    return builder.toString();
  }
  /**
   * Append a string representation of the managed object relation to
   * the provided string builder.
   *
   * @param builder
   *          The string builder where the string representation
   *          should be appended.
   */
  public abstract void toString(StringBuilder builder);
  /**
   * Performs any run-time initialization required by this relation
   * definition. This may include resolving managed object paths and
   * property names.
   *
   * @throws Exception
   *           If this relation definition could not be initialized.
   */
  protected void initialize() throws Exception {
    // No implementation required.
  }
}
opendj-admin/src/main/java/org/opends/server/admin/RelationDefinitionVisitor.java
New file
@@ -0,0 +1,130 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * A visitor of relation definitions, in the style of the visitor
 * design pattern. Classes implementing this interface can query
 * relation definitions in a type-safe manner when the kind of
 * relation definition is unknown at compile time. When a visitor is
 * passed to a relation definition's accept method, the corresponding
 * visit method most applicable to that relation definition is
 * invoked.
 *
 * @param <R>
 *          The return type of this visitor's methods. Use
 *          {@link java.lang.Void} for visitors that do not need to
 *          return results.
 * @param <P>
 *          The type of the additional parameter to this visitor's
 *          methods. Use {@link java.lang.Void} for visitors that do
 *          not need an additional parameter.
 */
public interface RelationDefinitionVisitor<R, P> {
  /**
   * Visit an instantiable relation definition.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param rd
   *          The instantiable relation definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  <C extends ConfigurationClient, S extends Configuration> R visitInstantiable(
      InstantiableRelationDefinition<C, S> rd, P p);
  /**
   * Visit a set relation definition.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param rd
   *          The set relation definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  <C extends ConfigurationClient, S extends Configuration> R visitSet(
      SetRelationDefinition<C, S> rd, P p);
  /**
   * Visit an optional relation definition.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param rd
   *          The optional relation definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  <C extends ConfigurationClient, S extends Configuration> R visitOptional(
      OptionalRelationDefinition<C, S> rd, P p);
  /**
   * Visit a singleton relation definition.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param rd
   *          The singleton relation definition to visit.
   * @param p
   *          A visitor specified parameter.
   * @return Returns a visitor specified result.
   */
  <C extends ConfigurationClient, S extends Configuration> R visitSingleton(
      SingletonRelationDefinition<C, S> rd, P p);
}
opendj-admin/src/main/java/org/opends/server/admin/RelationOption.java
New file
@@ -0,0 +1,49 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * This enumeration contains various options that can be associated
 * with relation definitions.
 */
public enum RelationOption {
  /**
   * Use this option to identify relations which should be considered
   * as advanced and should not be exposed by default in client
   * applications.
   */
  ADVANCED,
  /**
   * Use this option to identify relations which must not be directly
   * exposed in client applications.
   */
  HIDDEN;
}
opendj-admin/src/main/java/org/opends/server/admin/RelativeInheritedDefaultBehaviorProvider.java
New file
@@ -0,0 +1,150 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * A default behavior provider which retrieves default values from a
 * parent managed object. It should be used by properties which
 * inherit their default value(s) from properties held in an other
 * managed object.
 *
 * @param <T>
 *          The type of values represented by this provider.
 */
public final class RelativeInheritedDefaultBehaviorProvider<T> extends
    DefaultBehaviorProvider<T> {
  // The type of managed object expected at the relative offset.
  private final AbstractManagedObjectDefinition<?, ?> d;
  // The relative offset (where 1 = parent, 2 = grandparent) of the
  // managed object containing the property.
  private final int offset;
  // The name of the property containing the inherited default values.
  private final String propertyName;
  /**
   * Create a relative inherited default behavior provider associated
   * with a parent managed object.
   *
   * @param d
   *          The type of parent managed object expected at the
   *          relative location.
   * @param propertyName
   *          The name of the property containing the inherited
   *          default values.
   * @param offset
   *          The relative location of the parent managed object
   *          (where 0 is the managed object itself, 1 is the parent,
   *          and 2 is the grand-parent).
   * @throws IllegalArgumentException
   *           If the offset is less than 0.
   */
  public RelativeInheritedDefaultBehaviorProvider(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName, int offset)
      throws IllegalArgumentException {
    // We do not decode the property name now because the property
    // might not have been constructed at this point (e.g. when the
    // offset is 0).
    if (offset < 0) {
      throw new IllegalArgumentException("Negative offset");
    }
    this.d = d;
    this.propertyName = propertyName;
    this.offset = offset;
  }
  /**
   * {@inheritDoc}
   */
  public <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p) {
    return v.visitRelativeInherited(this, p);
  }
  /**
   * Get the definition of the parent managed object containing the
   * inherited default values.
   *
   * @return Returns the definition of the parent managed object
   *         containing the inherited default values.
   */
  public AbstractManagedObjectDefinition<?, ?> getManagedObjectDefinition() {
    return d;
  }
  /**
   * Get the absolute path of the managed object containing the
   * property which has the default values.
   *
   * @param path
   *          The path of the current managed object from which the
   *          relative path should be determined.
   * @return Returns the absolute path of the managed object
   *         containing the property which has the default values.
   */
  public ManagedObjectPath<?, ?> getManagedObjectPath(
      ManagedObjectPath<?, ?> path) {
    return path.parent(offset);
  }
  /**
   * Gets the name of the property containing the inherited default
   * values.
   *
   * @return Returns the name of the property containing the inherited
   *         default values.
   */
  public String getPropertyName() {
    return propertyName;
  }
  /**
   * Get the relative location of the parent managed object.
   *
   * @return Returns the relative location of the parent managed
   *         object (where 0 is the managed object itself, 1 is the
   *         parent, and 2 is the grand-parent).
   */
  public int getRelativeOffset() {
    return offset;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/SetRelationDefinition.java
New file
@@ -0,0 +1,289 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.opends.messages.Message;
/**
 * A managed object composite relationship definition which represents a
 * composition of zero or more managed objects each of which must have a
 * different type. The manage objects are named using their type name.
 *
 * @param <C>
 *          The type of client managed object configuration that this
 *          relation definition refers to.
 * @param <S>
 *          The type of server managed object configuration that this
 *          relation definition refers to.
 */
public final class SetRelationDefinition
    <C extends ConfigurationClient, S extends Configuration>
    extends RelationDefinition<C, S>
{
  /**
   * An interface for incrementally constructing set relation
   * definitions.
   *
   * @param <C>
   *          The type of client managed object configuration that this
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that this
   *          relation definition refers to.
   */
  public static final class Builder
      <C extends ConfigurationClient, S extends Configuration>
      extends AbstractBuilder<C, S, SetRelationDefinition<C, S>>
  {
    // The plural name of the relation.
    private final String pluralName;
    // The optional default managed objects associated with this
    // set relation definition.
    private final Map<String,
                      DefaultManagedObject<? extends C, ? extends S>>
      defaultManagedObjects =
        new HashMap<String, DefaultManagedObject<? extends C, ? extends S>>();
    /**
     * Creates a new builder which can be used to incrementally build a
     * set relation definition.
     *
     * @param pd
     *          The parent managed object definition.
     * @param name
     *          The name of the relation.
     * @param pluralName
     *          The plural name of the relation.
     * @param cd
     *          The child managed object definition.
     */
    public Builder(AbstractManagedObjectDefinition<?, ?> pd,
        String name, String pluralName,
        AbstractManagedObjectDefinition<C, S> cd)
    {
      super(pd, name, cd);
      this.pluralName = pluralName;
    }
    /**
     * Adds the default managed object to this set relation definition.
     *
     * @param defaultManagedObject
     *          The default managed object.
     */
    public void setDefaultManagedObject(
        DefaultManagedObject<? extends C, ? extends S> defaultManagedObject)
    {
      this.defaultManagedObjects
          .put(defaultManagedObject.getManagedObjectDefinition()
              .getName(), defaultManagedObject);
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected SetRelationDefinition<C, S> buildInstance(
        Common<C, S> common)
    {
      return new SetRelationDefinition<C, S>(common, pluralName,
          defaultManagedObjects);
    }
  }
  // The plural name of the relation.
  private final String pluralName;
  // The optional default managed objects associated with this
  // set relation definition.
  private final Map<String,
                    DefaultManagedObject<? extends C, ? extends S>>
    defaultManagedObjects;
  // Private constructor.
  private SetRelationDefinition(
      Common<C, S> common,
      String pluralName,
      Map<String,
          DefaultManagedObject<? extends C, ? extends S>> defaultManagedObjects)
  {
    super(common);
    this.pluralName = pluralName;
    this.defaultManagedObjects = defaultManagedObjects;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p)
  {
    return v.visitSet(this, p);
  }
  /**
   * Gets the named default managed object associated with this set
   * relation definition.
   *
   * @param name
   *          The name of the default managed object (for set relations
   *          this is the type of the default managed object).
   * @return The named default managed object.
   * @throws IllegalArgumentException
   *           If there is no default managed object associated with the
   *           provided name.
   */
  public DefaultManagedObject<? extends C, ? extends S> getDefaultManagedObject(
      String name) throws IllegalArgumentException
  {
    if (!defaultManagedObjects.containsKey(name))
    {
      throw new IllegalArgumentException(
          "unrecognized default managed object \"" + name + "\"");
    }
    return defaultManagedObjects.get(name);
  }
  /**
   * Gets the names of the default managed objects associated with this
   * set relation definition.
   *
   * @return An unmodifiable set containing the names of the default
   *         managed object.
   */
  public Set<String> getDefaultManagedObjectNames()
  {
    return Collections.unmodifiableSet(defaultManagedObjects.keySet());
  }
  /**
   * Gets the plural name of the relation.
   *
   * @return The plural name of the relation.
   */
  public String getPluralName()
  {
    return pluralName;
  }
  /**
   * Gets the user friendly plural name of this relation definition in
   * the default locale.
   *
   * @return Returns the user friendly plural name of this relation
   *         definition in the default locale.
   */
  public Message getUserFriendlyPluralName()
  {
    return getUserFriendlyPluralName(Locale.getDefault());
  }
  /**
   * Gets the user friendly plural name of this relation definition in
   * the specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the user friendly plural name of this relation
   *         definition in the specified locale.
   */
  public Message getUserFriendlyPluralName(Locale locale)
  {
    String property =
        "relation." + getName() + ".user-friendly-plural-name";
    return ManagedObjectDefinitionI18NResource.getInstance()
        .getMessage(getParentDefinition(), property, locale);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void toString(StringBuilder builder)
  {
    builder.append("name=");
    builder.append(getName());
    builder.append(" type=set parent=");
    builder.append(getParentDefinition().getName());
    builder.append(" child=");
    builder.append(getChildDefinition().getName());
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected void initialize() throws Exception
  {
    for (DefaultManagedObject<?, ?> dmo : defaultManagedObjects
        .values())
    {
      dmo.initialize();
    }
  }
}
opendj-admin/src/main/java/org/opends/server/admin/SingletonRelationDefinition.java
New file
@@ -0,0 +1,184 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * A managed object composite relationship definition which represents
 * a composition of a single managed object (i.e. the managed object
 * must be present).
 *
 * @param <C>
 *          The type of client managed object configuration that this
 *          relation definition refers to.
 * @param <S>
 *          The type of server managed object configuration that this
 *          relation definition refers to.
 */
public final class SingletonRelationDefinition
    <C extends ConfigurationClient, S extends Configuration>
    extends RelationDefinition<C, S> {
  /**
   * An interface for incrementally constructing singleton relation
   * definitions.
   *
   * @param <C>
   *          The type of client managed object configuration that
   *          this relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that
   *          this relation definition refers to.
   */
  public static final class Builder
      <C extends ConfigurationClient, S extends Configuration>
      extends AbstractBuilder<C, S, SingletonRelationDefinition<C, S>> {
    // The optional default managed object associated with this
    // singleton relation.
    private DefaultManagedObject<? extends C, ? extends S>
      defaultManagedObject = null;
    /**
     * Creates a new builder which can be used to incrementally build
     * an singleton relation definition.
     *
     * @param pd
     *          The parent managed object definition.
     * @param name
     *          The name of the relation.
     * @param cd
     *          The child managed object definition.
     */
    public Builder(AbstractManagedObjectDefinition<?, ?> pd, String name,
        AbstractManagedObjectDefinition<C, S> cd) {
      super(pd, name, cd);
    }
    /**
     * Sets the optional default managed object associated with this
     * singleton relation definition.
     *
     * @param defaultManagedObject
     *          The default managed object or <code>null</code> if
     *          there is no default managed object defined for this
     *          relation definition.
     */
    public void setDefaultManagedObject(
        DefaultManagedObject<? extends C, ? extends S> defaultManagedObject) {
      this.defaultManagedObject = defaultManagedObject;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected SingletonRelationDefinition<C, S> buildInstance(
        Common<C, S> common) {
      return new SingletonRelationDefinition<C, S>(common,
          defaultManagedObject);
    }
  }
  // The optional default managed object associated with this
  // singleton relation.
  private final DefaultManagedObject<? extends C, ? extends S>
    defaultManagedObject;
  // Private constructor.
  private SingletonRelationDefinition(Common<C, S> common,
      DefaultManagedObject<? extends C, ? extends S> defaultManagedObject) {
    super(common);
    this.defaultManagedObject = defaultManagedObject;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(RelationDefinitionVisitor<R, P> v, P p) {
    return v.visitSingleton(this, p);
  }
  /**
   * Gets the optional default managed object associated with this
   * singleton relation definition.
   *
   * @return Returns the default managed object or <code>null</code>
   *         if there is no default managed object defined for this
   *         relation definition.
   */
  public DefaultManagedObject<? extends C, ? extends S>
      getDefaultManagedObject() {
    return defaultManagedObject;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void toString(StringBuilder builder) {
    builder.append("name=");
    builder.append(getName());
    builder.append(" type=singleton parent=");
    builder.append(getParentDefinition().getName());
    builder.append(" child=");
    builder.append(getChildDefinition().getName());
  }
  /**
   * {@inheritDoc}
   */
  @Override
  protected void initialize() throws Exception {
    if (defaultManagedObject != null) {
      defaultManagedObject.initialize();
    }
  }
}
opendj-admin/src/main/java/org/opends/server/admin/SizePropertyDefinition.java
New file
@@ -0,0 +1,410 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.server.util.Validator.ensureNotNull;
import java.util.EnumSet;
/**
 * Memory size property definition.
 * <p>
 * All memory size property values are represented in bytes using longs.
 * <p>
 * All values must be zero or positive and within the lower/upper limit
 * constraints. Support is provided for "unlimited" memory sizes. These are
 * represented using a negative memory size value or using the string
 * "unlimited".
 */
public final class SizePropertyDefinition extends PropertyDefinition<Long> {
  // String used to represent unlimited memory sizes.
  private static final String UNLIMITED = "unlimited";
  // The lower limit of the property value in bytes.
  private final long lowerLimit;
  // The optional upper limit of the property value in bytes.
  private final Long upperLimit;
  // Indicates whether this property allows the use of the "unlimited" memory
  // size value (represented using a -1L or the string "unlimited").
  private final boolean allowUnlimited;
  /**
   * An interface for incrementally constructing memory size property
   * definitions.
   */
  public static class Builder extends
      AbstractBuilder<Long, SizePropertyDefinition> {
    // The lower limit of the property value in bytes.
    private long lowerLimit = 0L;
    // The optional upper limit of the property value in bytes.
    private Long upperLimit = null;
    // Indicates whether this property allows the use of the "unlimited" memory
    // size value (represented using a -1L or the string "unlimited").
    private boolean allowUnlimited = false;
    // Private constructor
    private Builder(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
      super(d, propertyName);
    }
    /**
     * Set the lower limit in bytes.
     *
     * @param lowerLimit
     *          The new lower limit (must be >= 0) in bytes.
     * @throws IllegalArgumentException
     *           If a negative lower limit was specified, or if the lower limit
     *           is greater than the upper limit.
     */
    public final void setLowerLimit(long lowerLimit)
        throws IllegalArgumentException {
      if (lowerLimit < 0) {
        throw new IllegalArgumentException("Negative lower limit");
      }
      if (upperLimit != null && lowerLimit > upperLimit) {
        throw new IllegalArgumentException(
            "Lower limit greater than upper limit");
      }
      this.lowerLimit = lowerLimit;
    }
    /**
     * Set the lower limit using a string representation of the limit.
     *
     * @param lowerLimit
     *          The string representation of the new lower limit.
     * @throws IllegalArgumentException
     *           If the lower limit could not be parsed, or if a negative lower
     *           limit was specified, or the lower limit is greater than the
     *           upper limit.
     */
    public final void setLowerLimit(String lowerLimit)
        throws IllegalArgumentException {
      setLowerLimit(SizeUnit.parseValue(lowerLimit, SizeUnit.BYTES));
    }
    /**
     * Set the upper limit in bytes.
     *
     * @param upperLimit
     *          The new upper limit in bytes or <code>null</code> if there is
     *          no upper limit.
     * @throws IllegalArgumentException
     *           If the lower limit is greater than the upper limit.
     */
    public final void setUpperLimit(Long upperLimit)
        throws IllegalArgumentException {
      if (upperLimit != null) {
        if (upperLimit < 0) {
          throw new IllegalArgumentException("Negative upper limit");
        }
        if (lowerLimit > upperLimit) {
          throw new IllegalArgumentException(
              "Lower limit greater than upper limit");
        }
      }
      this.upperLimit = upperLimit;
    }
    /**
     * Set the upper limit using a string representation of the limit.
     *
     * @param upperLimit
     *          The string representation of the new upper limit, or
     *          <code>null</code> if there is no upper limit.
     * @throws IllegalArgumentException
     *           If the upper limit could not be parsed, or if the lower limit
     *           is greater than the upper limit.
     */
    public final void setUpperLimit(String upperLimit)
        throws IllegalArgumentException {
      if (upperLimit == null) {
        setUpperLimit((Long) null);
      } else {
        setUpperLimit(SizeUnit.parseValue(upperLimit, SizeUnit.BYTES));
      }
    }
    /**
     * Specify whether or not this property definition will allow unlimited
     * values (default is false).
     *
     * @param allowUnlimited
     *          <code>true</code> if the property will allow unlimited values,
     *          or <code>false</code> otherwise.
     */
    public final void setAllowUnlimited(boolean allowUnlimited) {
      this.allowUnlimited = allowUnlimited;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected SizePropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<Long> defaultBehavior) {
      return new SizePropertyDefinition(d, propertyName, options, adminAction,
          defaultBehavior, lowerLimit, upperLimit, allowUnlimited);
    }
  }
  /**
   * Create an memory size property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new integer property definition builder.
   */
  public static Builder createBuilder(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName) {
    return new Builder(d, propertyName);
  }
  // Private constructor.
  private SizePropertyDefinition(
      AbstractManagedObjectDefinition<?, ?> d, String propertyName,
      EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<Long> defaultBehavior, Long lowerLimit,
      Long upperLimit, boolean allowUnlimited) {
    super(d, Long.class, propertyName, options, adminAction,
        defaultBehavior);
    this.lowerLimit = lowerLimit;
    this.upperLimit = upperLimit;
    this.allowUnlimited = allowUnlimited;
  }
  /**
   * Get the lower limit in bytes.
   *
   * @return Returns the lower limit in bytes.
   */
  public long getLowerLimit() {
    return lowerLimit;
  }
  /**
   * Get the upper limit in bytes.
   *
   * @return Returns the upper limit in bytes or <code>null</code> if there is
   *         no upper limit.
   */
  public Long getUpperLimit() {
    return upperLimit;
  }
  /**
   * Determine whether this property allows unlimited memory sizes.
   *
   * @return Returns <code>true</code> if this this property allows unlimited
   *         memory sizes.
   */
  public boolean isAllowUnlimited() {
    return allowUnlimited;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(Long value) throws IllegalPropertyValueException {
    ensureNotNull(value);
    if (!allowUnlimited && value < lowerLimit) {
      throw new IllegalPropertyValueException(this, value);
    // unlimited allowed
    } else if (value >= 0 && value < lowerLimit) {
      throw new IllegalPropertyValueException(this, value);
    }
    if ((upperLimit != null) && (value > upperLimit)) {
      throw new IllegalPropertyValueException(this, value);
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String encodeValue(Long value) throws IllegalPropertyValueException {
    ensureNotNull(value);
    // Make sure that we correctly encode negative values as "unlimited".
    if (allowUnlimited) {
      if (value < 0) {
        return UNLIMITED;
      }
    }
    // Encode the size value using the best-fit unit.
    StringBuilder builder = new StringBuilder();
    SizeUnit unit = SizeUnit.getBestFitUnitExact(value);
    // Cast to a long to remove fractional part (which should not be there
    // anyway as the best-fit unit should result in an exact conversion).
    builder.append((long) unit.fromBytes(value));
    builder.append(' ');
    builder.append(unit.toString());
    return builder.toString();
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public Long decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    // First check for the special "unlimited" value when necessary.
    if (allowUnlimited) {
      if (value.trim().equalsIgnoreCase(UNLIMITED)) {
        return -1L;
      }
    }
    // Decode the value.
    Long i;
    try {
      i = SizeUnit.parseValue(value, SizeUnit.BYTES);
    } catch (NumberFormatException e) {
      throw new IllegalPropertyValueStringException(this, value);
    }
    try {
      validateValue(i);
    } catch (IllegalPropertyValueException e) {
      throw new IllegalPropertyValueStringException(this, value);
    }
    return i;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitSize(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, Long value, P p) {
    return v.visitSize(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void toString(StringBuilder builder) {
    super.toString(builder);
    builder.append(" lowerLimit=");
    builder.append(lowerLimit);
    if (upperLimit != null) {
      builder.append(" upperLimit=");
      builder.append(upperLimit);
    }
    builder.append(" allowUnlimited=");
    builder.append(allowUnlimited);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public int compare(Long o1, Long o2) {
    return o1.compareTo(o2);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/SizeUnit.java
New file
@@ -0,0 +1,394 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * This enumeration defines various memory size units.
 */
public enum SizeUnit {
  /**
   * A byte unit.
   */
  BYTES(1L, "b", "bytes"),
  /**
   * A gibi-byte unit.
   */
  GIBI_BYTES((long) 1024 * 1024 * 1024, "gib", "gibibytes"),
  /**
   * A giga-byte unit.
   */
  GIGA_BYTES((long) 1000 * 1000 * 1000, "gb", "gigabytes"),
  /**
   * A kibi-byte unit.
   */
  KIBI_BYTES(1024L, "kib", "kibibytes"),
  /**
   * A kilo-byte unit.
   */
  KILO_BYTES(1000L, "kb", "kilobytes"),
  /**
   * A mebi-byte unit.
   */
  MEBI_BYTES((long) 1024 * 1024, "mib", "mebibytes"),
  /**
   * A mega-byte unit.
   */
  MEGA_BYTES((long) 1000 * 1000, "mb", "megabytes"),
  /**
   * A tebi-byte unit.
   */
  TEBI_BYTES((long) 1024 * 1024 * 1024 * 1024, "tib", "tebibytes"),
  /**
   * A tera-byte unit.
   */
  TERA_BYTES((long) 1000 * 1000 * 1000 * 1000, "tb", "terabytes");
  // A lookup table for resolving a unit from its name.
  private static final Map<String, SizeUnit> nameToUnit;
  static {
    nameToUnit = new HashMap<String, SizeUnit>();
    for (SizeUnit unit : SizeUnit.values()) {
      nameToUnit.put(unit.shortName, unit);
      nameToUnit.put(unit.longName, unit);
    }
  }
  /**
   * Gets the best-fit unit for the specified number of bytes. The
   * returned unit will be able to represent the number of bytes using
   * a decimal number comprising of an integer part which is greater
   * than zero. Bigger units are chosen in preference to smaller units
   * and binary units are only returned if they are an exact fit. If
   * the number of bytes is zero then the {@link #BYTES} unit is
   * always returned. For example:
   *
   * <pre>
   * getBestFitUnit(0)       // BYTES
   * getBestFitUnit(999)     // BYTES
   * getBestFitUnit(1000)    // KILO_BYTES
   * getBestFitUnit(1024)    // KIBI_BYTES
   * getBestFitUnit(1025)    // KILO_BYTES
   * getBestFitUnit(999999)  // KILO_BYTES
   * getBestFitUnit(1000000) // MEGA_BYTES
   * </pre>
   *
   * @param bytes
   *          The number of bytes.
   * @return Returns the best fit unit.
   * @throws IllegalArgumentException
   *           If <code>bytes</code> is negative.
   * @see #getBestFitUnitExact(long)
   */
  public static SizeUnit getBestFitUnit(long bytes)
      throws IllegalArgumentException {
    if (bytes < 0) {
      throw new IllegalArgumentException("negative number of bytes: " + bytes);
    } else if (bytes == 0) {
      // Always use bytes for zero values.
      return BYTES;
    } else {
      // Determine best fit: prefer non-binary units unless binary
      // fits exactly.
      SizeUnit[] nonBinary = new SizeUnit[] { TERA_BYTES, GIGA_BYTES,
          MEGA_BYTES, KILO_BYTES };
      SizeUnit[] binary = new SizeUnit[] { TEBI_BYTES, GIBI_BYTES, MEBI_BYTES,
          KIBI_BYTES };
      for (int i = 0; i < nonBinary.length; i++) {
        if ((bytes % binary[i].getSize()) == 0) {
          return binary[i];
        } else if ((bytes / nonBinary[i].getSize()) > 0) {
          return nonBinary[i];
        }
      }
      return BYTES;
    }
  }
  /**
   * Gets the best-fit unit for the specified number of bytes which
   * can represent the provided value using an integral value. Bigger
   * units are chosen in preference to smaller units. If the number of
   * bytes is zero then the {@link #BYTES} unit is always returned.
   * For example:
   *
   * <pre>
   * getBestFitUnitExact(0)       // BYTES
   * getBestFitUnitExact(999)     // BYTES
   * getBestFitUnitExact(1000)    // KILO_BYTES
   * getBestFitUnitExact(1024)    // KIBI_BYTES
   * getBestFitUnitExact(1025)    // BYTES
   * getBestFitUnitExact(999999)  // BYTES
   * getBestFitUnitExact(1000000) // MEGA_BYTES
   * </pre>
   *
   * @param bytes
   *          The number of bytes.
   * @return Returns the best fit unit can represent the provided
   *         value using an integral value.
   * @throws IllegalArgumentException
   *           If <code>bytes</code> is negative.
   * @see #getBestFitUnit(long)
   */
  public static SizeUnit getBestFitUnitExact(long bytes)
      throws IllegalArgumentException {
    if (bytes < 0) {
      throw new IllegalArgumentException("negative number of bytes: " + bytes);
    } else if (bytes == 0) {
      // Always use bytes for zero values.
      return BYTES;
    } else {
      // Determine best fit.
      SizeUnit[] units = new SizeUnit[] { TEBI_BYTES, TERA_BYTES, GIBI_BYTES,
          GIGA_BYTES, MEBI_BYTES, MEGA_BYTES, KIBI_BYTES, KILO_BYTES };
      for (SizeUnit unit : units) {
        if ((bytes % unit.getSize()) == 0) {
          return unit;
        }
      }
      return BYTES;
    }
  }
  /**
   * Get the unit corresponding to the provided unit name.
   *
   * @param s
   *          The name of the unit. Can be the abbreviated or long
   *          name and can contain white space and mixed case
   *          characters.
   * @return Returns the unit corresponding to the provided unit name.
   * @throws IllegalArgumentException
   *           If the provided name did not correspond to a known
   *           memory size unit.
   */
  public static SizeUnit getUnit(String s) throws IllegalArgumentException {
    SizeUnit unit = nameToUnit.get(s.trim().toLowerCase());
    if (unit == null) {
      throw new IllegalArgumentException("Illegal memory size unit \"" + s
          + "\"");
    }
    return unit;
  }
  /**
   * Parse the provided size string and return its equivalent size in
   * bytes. The size string must specify the unit e.g. "10kb".
   *
   * @param s
   *          The size string to be parsed.
   * @return Returns the parsed duration in bytes.
   * @throws NumberFormatException
   *           If the provided size string could not be parsed.
   */
  public static long parseValue(String s) throws NumberFormatException {
    return parseValue(s, null);
  }
  /**
   * Parse the provided size string and return its equivalent size in
   * bytes.
   *
   * @param s
   *          The size string to be parsed.
   * @param defaultUnit
   *          The default unit to use if there is no unit specified in
   *          the size string, or <code>null</code> if the string
   *          must always contain a unit.
   * @return Returns the parsed size in bytes.
   * @throws NumberFormatException
   *           If the provided size string could not be parsed.
   */
  public static long parseValue(String s, SizeUnit defaultUnit)
      throws NumberFormatException {
    // Value must be a floating point number followed by a unit.
    Pattern p = Pattern.compile("^\\s*(\\d+(\\.\\d+)?)\\s*(\\w+)?\\s*$");
    Matcher m = p.matcher(s);
    if (!m.matches()) {
      throw new NumberFormatException("Invalid size value \"" + s + "\"");
    }
    // Group 1 is the float.
    double d;
    try {
      d = Double.valueOf(m.group(1));
    } catch (NumberFormatException e) {
      throw new NumberFormatException("Invalid size value \"" + s + "\"");
    }
    // Group 3 is the unit.
    String unitString = m.group(3);
    SizeUnit unit;
    if (unitString == null) {
      if (defaultUnit == null) {
        throw new NumberFormatException("Invalid size value \"" + s + "\"");
      } else {
        unit = defaultUnit;
      }
    } else {
      try {
        unit = getUnit(unitString);
      } catch (IllegalArgumentException e) {
        throw new NumberFormatException("Invalid size value \"" + s + "\"");
      }
    }
    return unit.toBytes(d);
  }
  // The long name of the unit.
  private final String longName;
  // The abbreviation of the unit.
  private final String shortName;
  // The size of the unit in bytes.
  private final long sz;
  // Private constructor.
  private SizeUnit(long sz, String shortName, String longName) {
    this.sz = sz;
    this.shortName = shortName;
    this.longName = longName;
  }
  /**
   * Converts the specified size in bytes to this unit.
   *
   * @param amount
   *          The size in bytes.
   * @return Returns size in this unit.
   */
  public double fromBytes(long amount) {
    return ((double) amount / sz);
  }
  /**
   * Get the long name of this unit.
   *
   * @return Returns the long name of this unit.
   */
  public String getLongName() {
    return longName;
  }
  /**
   * Get the abbreviated name of this unit.
   *
   * @return Returns the abbreviated name of this unit.
   */
  public String getShortName() {
    return shortName;
  }
  /**
   * Get the number of bytes that this unit represents.
   *
   * @return Returns the number of bytes that this unit represents.
   */
  public long getSize() {
    return sz;
  }
  /**
   * Converts the specified size in this unit to bytes.
   *
   * @param amount
   *          The size as a quantity of this unit.
   * @return Returns the number of bytes that the size represents.
   *
   * @throws NumberFormatException
   *           If the provided size exceeded long.MAX_VALUE.
   */
  public long toBytes(double amount) throws NumberFormatException {
    double value =  sz * amount;
    if (value > Long.MAX_VALUE)
    {
      throw new NumberFormatException
        ("number too big (exceeded long.MAX_VALUE");
    }
    return (long) (value);
  }
  /**
   * {@inheritDoc}
   * <p>
   * This implementation returns the abbreviated name of this size
   * unit.
   */
  @Override
  public String toString() {
    return shortName;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/StringPropertyDefinition.java
New file
@@ -0,0 +1,335 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import static org.opends.server.util.Validator.ensureNotNull;
import java.util.EnumSet;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
 * String property definition.
 */
public final class StringPropertyDefinition extends PropertyDefinition<String> {
  /**
   * An interface for incrementally constructing string property
   * definitions.
   */
  public static class Builder extends
      AbstractBuilder<String, StringPropertyDefinition> {
    // Flag indicating whether values of this property are
    // case-insensitive.
    private boolean isCaseInsensitive = true;
    // Optional pattern which values of this property must match.
    private Pattern pattern = null;
    // Pattern usage which provides a user-friendly summary of the
    // pattern if present.
    private String patternUsage = null;
    // Private constructor
    private Builder(AbstractManagedObjectDefinition<?, ?> d,
        String propertyName) {
      super(d, propertyName);
    }
    /**
     * Set a flag indicating whether values of this property are
     * case-insensitive.
     *
     * @param value
     *          <code>true</code> if values are case-insensitive, or
     *          <code>false</code> otherwise.
     */
    public final void setCaseInsensitive(boolean value) {
      isCaseInsensitive = value;
    }
    /**
     * Set the regular expression pattern which values of this
     * property must match. By default there is no pattern defined.
     *
     * @param pattern
     *          The regular expression pattern string, or
     *          <code>null</code> if there is no pattern.
     * @param patternUsage
     *          A user-friendly usage string representing the pattern
     *          which can be used in error messages and help (e.g. for
     *          patterns which match a host/port combination, the
     *          usage string "HOST:PORT" would be appropriate).
     * @throws PatternSyntaxException
     *           If the provided regular expression pattern has an
     *           invalid syntax.
     */
    public final void setPattern(String pattern, String patternUsage)
        throws PatternSyntaxException {
      if (pattern == null) {
        this.pattern = null;
        this.patternUsage = null;
      } else {
        this.pattern = Pattern.compile(pattern);
        this.patternUsage = patternUsage;
      }
    }
    /**
     * {@inheritDoc}
     */
    @Override
    protected StringPropertyDefinition buildInstance(
        AbstractManagedObjectDefinition<?, ?> d, String propertyName,
        EnumSet<PropertyOption> options,
        AdministratorAction adminAction,
        DefaultBehaviorProvider<String> defaultBehavior) {
      return new StringPropertyDefinition(d, propertyName, options,
          adminAction, defaultBehavior, isCaseInsensitive, pattern,
          patternUsage);
    }
  }
  /**
   * Create a string property definition builder.
   *
   * @param d
   *          The managed object definition associated with this
   *          property definition.
   * @param propertyName
   *          The property name.
   * @return Returns the new string property definition builder.
   */
  public static Builder createBuilder(AbstractManagedObjectDefinition<?, ?> d,
      String propertyName) {
    return new Builder(d, propertyName);
  }
  // Flag indicating whether values of this property are
  // case-insensitive.
  private final boolean isCaseInsensitive;
  // Optional pattern which values of this property must match.
  private final Pattern pattern;
  // Pattern usage which provides a user-friendly summary of the
  // pattern if present.
  private final String patternUsage;
  // Private constructor.
  private StringPropertyDefinition(AbstractManagedObjectDefinition<?, ?> d,
      String propertyName, EnumSet<PropertyOption> options,
      AdministratorAction adminAction,
      DefaultBehaviorProvider<String> defaultBehavior,
      boolean isCaseInsensitive, Pattern pattern, String patternUsage) {
    super(d, String.class, propertyName, options, adminAction,
        defaultBehavior);
    this.isCaseInsensitive = isCaseInsensitive;
    this.pattern = pattern;
    this.patternUsage = patternUsage;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyDefinitionVisitor<R, P> v, P p) {
    return v.visitString(this, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public <R, P> R accept(PropertyValueVisitor<R, P> v, String value, P p) {
    return v.visitString(this, value, p);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String decodeValue(String value)
      throws IllegalPropertyValueStringException {
    ensureNotNull(value);
    try {
      validateValue(value);
    } catch (IllegalPropertyValueException e) {
      throw new IllegalPropertyValueStringException(this, value);
    }
    return value;
  }
  /**
   * Gets the optional regular expression pattern which values of this
   * property must match.
   *
   * @return Returns the optional regular expression pattern which
   *         values of this property must match, or <code>null</code>
   *         if there is no pattern.
   */
  public Pattern getPattern() {
    return pattern;
  }
  /**
   * Gets the pattern synopsis of this string property definition in
   * the default locale.
   *
   * @return Returns the pattern synopsis of this string property
   *         definition in the default locale, or <code>null</code>
   *         if there is no pattern synopsis (which is the case when
   *         there is no pattern matching defined for this string
   *         property definition).
   */
  public Message getPatternSynopsis() {
    return getPatternSynopsis(Locale.getDefault());
  }
  /**
   * Gets the optional pattern synopsis of this string property
   * definition in the specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the pattern synopsis of this string property
   *         definition in the specified locale, or <code>null</code>
   *         if there is no pattern synopsis (which is the case when
   *         there is no pattern matching defined for this string
   *         property definition).
   */
  public Message getPatternSynopsis(Locale locale) {
    ManagedObjectDefinitionI18NResource resource =
      ManagedObjectDefinitionI18NResource.getInstance();
    String property = "property." + getName()
        + ".syntax.string.pattern.synopsis";
    try {
      return resource
          .getMessage(getManagedObjectDefinition(), property, locale);
    } catch (MissingResourceException e) {
      return null;
    }
  }
  /**
   * Gets a user-friendly usage string representing the pattern which
   * can be used in error messages and help (e.g. for patterns which
   * match a host/port combination, the usage string "HOST:PORT" would
   * be appropriate).
   *
   * @return Returns the user-friendly pattern usage string, or
   *         <code>null</code> if there is no pattern.
   */
  public String getPatternUsage() {
    return patternUsage;
  }
  /**
   * Query whether values of this property are case-insensitive.
   *
   * @return Returns <code>true</code> if values are
   *         case-insensitive, or <code>false</code> otherwise.
   */
  public boolean isCaseInsensitive() {
    return isCaseInsensitive;
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public String normalizeValue(String value)
      throws IllegalPropertyValueException {
    ensureNotNull(value);
    if (isCaseInsensitive()) {
      return value.trim().toLowerCase();
    } else {
      return value.trim();
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public void validateValue(String value) throws IllegalPropertyValueException {
    ensureNotNull(value);
    if (pattern != null) {
      Matcher matcher = pattern.matcher(value);
      if (!matcher.matches()) {
        throw new IllegalPropertyValueException(this, value);
      }
    }
  }
}
opendj-admin/src/main/java/org/opends/server/admin/Tag.java
New file
@@ -0,0 +1,212 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import org.opends.messages.Message;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import org.opends.server.admin.std.meta.RootCfgDefn;
import org.opends.server.util.Validator;
/**
 * An interface for querying the properties of a tag.
 * <p>
 * Tags are used to group related managed objects together into
 * categories.
 */
public final class Tag implements Comparable<Tag> {
  // All the tags.
  private static final Map<String, Tag> tags = new HashMap<String, Tag>();
  /**
   * Defines a new tag with the specified name.
   *
   * @param name
   *          The name of the new tag.
   */
  public static void define(String name) {
    Tag tag = new Tag(name);
    // Register the tag.
    tags.put(name, tag);
  }
  /**
   * Returns the tag associated with the specified name.
   *
   * @param name
   *          The name of the tag.
   * @return Returns the tag associated with the specified name.
   * @throws IllegalArgumentException
   *           If the tag name was not recognized.
   */
  public static Tag valueOf(String name) throws IllegalArgumentException {
    Validator.ensureNotNull(name);
    // Hack to force initialization of the tag definitions.
    RootCfgDefn.getInstance();
    Tag tag = tags.get(name.toLowerCase());
    if (tag == null) {
      throw new IllegalArgumentException("Unknown tag \"" + name + "\"");
    }
    return tag;
  }
  /**
   * Returns an unmodifiable collection view of the set of registered
   * tags.
   *
   * @return Returns an unmodifiable collection view of the set of
   *         registered tags.
   */
  public static Collection<Tag> values() {
    // Hack to force initialization of the tag definitions.
    RootCfgDefn.getInstance();
    return Collections.unmodifiableCollection(tags.values());
  }
  // The name of the tag.
  private final String name;
  // Private constructor.
  private Tag(String name) {
    this.name = name;
  }
  /**
   * {@inheritDoc}
   */
  public final int compareTo(Tag o) {
    return name.compareTo(o.name);
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public final boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj instanceof Tag) {
      Tag other = (Tag) obj;
      return other.name.equals(this.name);
    }
    return false;
  }
  /**
   * Gets the name of this tag.
   *
   * @return Returns the name of this tag.
   */
  public final String getName() {
    return name;
  }
  /**
   * Gets the synopsis of this tag in the default locale.
   *
   * @return Returns the synopsis of this tag in the default locale.
   */
  public final Message getSynopsis() {
    return getSynopsis(Locale.getDefault());
  }
  /**
   * Gets the synopsis of this tag in the specified locale.
   *
   * @param locale
   *          The locale.
   * @return Returns the synopsis of this tag in the specified locale.
   */
  public final Message getSynopsis(Locale locale) {
    ManagedObjectDefinitionI18NResource resource =
      ManagedObjectDefinitionI18NResource.getInstance();
    String property = "tag." + name + ".synopsis";
    try {
      return resource.getMessage(RootCfgDefn.getInstance(), property, locale);
    } catch (MissingResourceException e) {
      return null;
    }
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public final int hashCode() {
    return name.hashCode();
  }
  /**
   * {@inheritDoc}
   */
  @Override
  public final String toString() {
    return name;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/TopCfgDefn.java
New file
@@ -0,0 +1,74 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * Configuration definition <code>TopCfgDefn</code> is the root of
 * the configuration definition hierarchy. Every configuration has
 * <code>TopCfgDefn</code> as a superclass.
 * <p>
 * The <code>TopCfgDefn</code> has no properties or relations.
 * However, it can be used to determine all the configuration
 * definitions currently available to the administration framework
 * using the {@link #getAllChildren()}.
 * <p>
 * <b>NOTE:</b> it is not possible to retrieve I18N related
 * information or profile information for this managed object
 * definition. In particular, calls to the methods
 * {@link #getSynopsis()}, {@link #getDescription()},
 * {@link #getUserFriendlyName()}, and
 * {@link #getUserFriendlyPluralName()} will not work.
 */
public final class TopCfgDefn extends
    AbstractManagedObjectDefinition<ConfigurationClient, Configuration> {
  // The singleton configuration definition instance.
  private static final TopCfgDefn INSTANCE = new TopCfgDefn();
  /**
   * Get the Top configuration definition singleton.
   *
   * @return Returns the Top configuration definition singleton.
   */
  public static TopCfgDefn getInstance() {
    return INSTANCE;
  }
  /**
   * Private constructor.
   */
  private TopCfgDefn() {
    super("top", null);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/UndefinedDefaultBehaviorProvider.java
New file
@@ -0,0 +1,59 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
/**
 * A default behavior provider which indicates undefined behavior. It should
 * be used by properties which have no default values or behavior as such. For
 * example, a description property, when left unset, has no default value and no
 * side-effects.
 *
 * @param <T>
 *          The type of values represented by this provider.
 */
public final class UndefinedDefaultBehaviorProvider<T> extends
    DefaultBehaviorProvider<T> {
  /**
   * Create an undefined default behavior provider.
   */
  public UndefinedDefaultBehaviorProvider() {
    // No implementation required.
  }
  /**
   * {@inheritDoc}
   */
  public <R, P> R accept(DefaultBehaviorProviderVisitor<T, R, P> v, P p) {
    return v.visitUndefined(this, p);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/UnknownPropertyDefinitionException.java
New file
@@ -0,0 +1,78 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.opends.messages.AdminMessages.*;
/**
 * Indicates that an unknown type of property definition was
 * encountered. This can occur as the management prototype develops
 * and new kinds of property definitions are added.
 */
public final class UnknownPropertyDefinitionException
    extends PropertyException {
  // Generated serialization ID.
  private static final long serialVersionUID = 7042646409131322385L;
  // The visitor parameter if there was one.
  private Object parameter;
  /**
   * Creates a new unknown property definition exception.
   *
   * @param pd
   *          The unknown property definition.
   * @param p
   *          The visitor parameter if there was one.
   */
  public UnknownPropertyDefinitionException(PropertyDefinition<?> pd,
      Object p) {
    super(pd, ERR_UNKNOWN_PROPERTY_DEFINITION_EXCEPTION.get(pd.getName(), pd
        .getClass().getName()));
    this.parameter = p;
  }
  /**
   * Get the visitor parameter if there was one.
   *
   * @return Returns the visitor parameter if there was one.
   */
  public Object getParameter() {
    return parameter;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/client/AdminClientException.java
New file
@@ -0,0 +1,80 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import org.opends.messages.Message;
import org.opends.server.admin.AdminException;
/**
 * Administration client exceptions represent non-operational problems
 * which occur whilst interacting with the administration framework.
 * They provide clients with a transport independent interface for
 * handling transport related exceptions.
 * <p>
 * Client exceptions represent communications problems, security
 * problems, and service related problems.
 */
public abstract class AdminClientException extends AdminException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = 4044747533980824456L;
  /**
   * Create an administration client exception with a message and
   * cause.
   *
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  protected AdminClientException(Message message, Throwable cause) {
    super(message, cause);
  }
  /**
   * Create an administration client exception with a message.
   *
   * @param message
   *          The message.
   */
  protected AdminClientException(Message message) {
    super(message);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/client/AdminSecurityException.java
New file
@@ -0,0 +1,74 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import org.opends.messages.Message;
/**
 * This exception is thrown when a security related problem occurs
 * whilst interacting with the Directory Server. These fall broadly
 * into two categories: authentication problems and authorization
 * problems.
 */
public abstract class AdminSecurityException extends AdminClientException {
  /**
   * Fake serialization ID.
   */
  private static final long serialVersionUID = 1L;
  /**
   * Create a security exception with a message and cause.
   *
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  protected AdminSecurityException(Message message, Throwable cause) {
    super(message, cause);
  }
  /**
   * Create a security exception with a message.
   *
   * @param message
   *          The message.
   */
  protected AdminSecurityException(Message message) {
    super(message);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/client/AuthenticationException.java
New file
@@ -0,0 +1,97 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import static org.opends.messages.AdminMessages.*;
import org.opends.messages.Message;
/**
 * This exception is thrown when an authentication error occurs while
 * connecting to the Directory Server. An authentication error can
 * happen, for example, when the client credentials are invalid.
 */
public class AuthenticationException extends AdminSecurityException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = 3544797197747686958L;
  /**
   * Creates an authentication exception with a default message.
   */
  public AuthenticationException() {
    super(ERR_AUTHENTICATION_EXCEPTION_DEFAULT.get());
  }
  /**
   * Create an authentication exception with a cause and a default
   * message.
   *
   * @param cause
   *          The cause.
   */
  public AuthenticationException(Throwable cause) {
    super(ERR_AUTHENTICATION_EXCEPTION_DEFAULT.get(), cause);
  }
  /**
   * Create an authentication exception with a message and cause.
   *
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  public AuthenticationException(Message message, Throwable cause) {
    super(message, cause);
  }
  /**
   * Create an authentication exception with a message.
   *
   * @param message
   *          The message.
   */
  public AuthenticationException(Message message) {
    super(message);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/client/AuthenticationNotSupportedException.java
New file
@@ -0,0 +1,99 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import static org.opends.messages.AdminMessages.*;
import org.opends.messages.Message;
/**
 * This exception is thrown when the particular flavor of
 * authentication requested is not supported by the Directory Server.
 */
public class AuthenticationNotSupportedException
    extends AdminSecurityException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = 7387834052676291793L;
  /**
   * Creates an authentication not supported exception with a default
   * message.
   */
  public AuthenticationNotSupportedException() {
    super(ERR_AUTHENTICATION_NOT_SUPPORTED_EXCEPTION_DEFAULT.get());
  }
  /**
   * Creates an authentication not supported exception with a cause
   * and a default message.
   *
   * @param cause
   *          The cause.
   */
  public AuthenticationNotSupportedException(Throwable cause) {
    super(ERR_AUTHENTICATION_NOT_SUPPORTED_EXCEPTION_DEFAULT.get(), cause);
  }
  /**
   * Create an authentication not supported exception with a message
   * and cause.
   *
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  public AuthenticationNotSupportedException(Message message, Throwable cause) {
    super(message, cause);
  }
  /**
   * Create an authentication not supported exception with a message.
   *
   * @param message
   *          The message.
   */
  public AuthenticationNotSupportedException(Message message) {
    super(message);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/client/AuthorizationException.java
New file
@@ -0,0 +1,98 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import static org.opends.messages.AdminMessages.*;
import org.opends.messages.Message;
/**
 * This exception is thrown when an authorization error occurs while
 * interacting with the Directory Server. Authorization errors can
 * occur when a client attempts to perform an administrative operation
 * which they are not permitted to perform.
 */
public class AuthorizationException extends AdminSecurityException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = 8414248362572933814L;
  /**
   * Create an authorization exception with a default message.
   */
  public AuthorizationException() {
    super(ERR_AUTHORIZATION_EXCEPTION_DEFAULT.get());
  }
  /**
   * Create an authorization exception with a cause and a default
   * message.
   *
   * @param cause
   *          The cause.
   */
  public AuthorizationException(Throwable cause) {
    super(ERR_AUTHORIZATION_EXCEPTION_DEFAULT.get(), cause);
  }
  /**
   * Create an authorization exception with a message and cause.
   *
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  public AuthorizationException(Message message, Throwable cause) {
    super(message, cause);
  }
  /**
   * Create an authorization exception with a message.
   *
   * @param message
   *          The message.
   */
  public AuthorizationException(Message message) {
    super(message);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/client/ClientConstraintHandler.java
New file
@@ -0,0 +1,165 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import java.util.Collection;
import org.opends.messages.Message;
import org.opends.server.admin.ManagedObjectPath;
/**
 * An interface for performing client-side constraint validation.
 * <p>
 * Constraints are evaluated immediately before the client performs a
 * write operation. If one or more constraints fails, the write
 * operation is refused and fails with an
 * {@link OperationRejectedException}.
 * <p>
 * A client constraint handler must override at least one of the
 * provided methods.
 *
 * @see org.opends.server.admin.Constraint
 */
public abstract class ClientConstraintHandler {
  /**
   * Creates a new client constraint handler.
   */
  protected ClientConstraintHandler() {
    // No implementation required.
  }
  /**
   * Determines whether or not the newly created managed object which
   * is about to be added to the server configuration satisfies this
   * constraint.
   * <p>
   * If the constraint is not satisfied, the implementation must
   * return <code>false</code> and add a message describing why the
   * constraint was not satisfied.
   * <p>
   * The default implementation is to return <code>true</code>.
   *
   * @param context
   *          The management context.
   * @param managedObject
   *          The new managed object.
   * @param unacceptableReasons
   *          A list of messages to which error messages should be
   *          added.
   * @return Returns <code>true</code> if this constraint is
   *         satisfied, or <code>false</code> if it is not.
   * @throws AuthorizationException
   *           If an authorization failure prevented this constraint
   *           from being evaluated.
   * @throws CommunicationException
   *           If a communications problem prevented this constraint
   *           from being evaluated.
   */
  public boolean isAddAcceptable(ManagementContext context,
      ManagedObject<?> managedObject, Collection<Message> unacceptableReasons)
      throws AuthorizationException, CommunicationException {
    return true;
  }
  /**
   * Determines whether or not the changes to an existing managed
   * object which are about to be committed to the server
   * configuration satisfies this constraint.
   * <p>
   * If the constraint is not satisfied, the implementation must
   * return <code>false</code> and add a message describing why the
   * constraint was not satisfied.
   * <p>
   * The default implementation is to return <code>true</code>.
   *
   * @param context
   *          The management context.
   * @param managedObject
   *          The modified managed object.
   * @param unacceptableReasons
   *          A list of messages to which error messages should be
   *          added.
   * @return Returns <code>true</code> if this modify is satisfied,
   *         or <code>false</code> if it is not.
   * @throws AuthorizationException
   *           If an authorization failure prevented this constraint
   *           from being evaluated.
   * @throws CommunicationException
   *           If a communications problem prevented this constraint
   *           from being evaluated.
   */
  public boolean isModifyAcceptable(ManagementContext context,
      ManagedObject<?> managedObject, Collection<Message> unacceptableReasons)
      throws AuthorizationException, CommunicationException {
    return true;
  }
  /**
   * Determines whether or not the existing managed object which is
   * about to be deleted from the server configuration satisfies this
   * constraint.
   * <p>
   * If the constraint is not satisfied, the implementation must
   * return <code>false</code> and add a message describing why the
   * constraint was not satisfied.
   * <p>
   * The default implementation is to return <code>true</code>.
   *
   * @param context
   *          The management context.
   * @param path
   *          The path of the managed object which is about to be
   *          deleted.
   * @param unacceptableReasons
   *          A list of messages to which error messages should be
   *          added.
   * @return Returns <code>true</code> if this constraint is
   *         satisfied, or <code>false</code> if it is not.
   * @throws AuthorizationException
   *           If an authorization failure prevented this constraint
   *           from being evaluated.
   * @throws CommunicationException
   *           If a communications problem prevented this constraint
   *           from being evaluated.
   */
  public boolean isDeleteAcceptable(ManagementContext context,
      ManagedObjectPath<?, ?> path, Collection<Message> unacceptableReasons)
      throws AuthorizationException, CommunicationException {
    return true;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/client/CommunicationException.java
New file
@@ -0,0 +1,100 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import static org.opends.messages.AdminMessages.*;
import org.opends.messages.Message;
/**
 * This exception is thrown when a communications related problem
 * occurs whilst interacting with the Directory Server. This may be
 * caused by problems such as network partitioning, the unavailability
 * of the Directory Server, or other failures on the client or server
 * side.
 */
public class CommunicationException extends AdminClientException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = 9093195928501281027L;
  /**
   * Create a communication exception with a default message.
   */
  public CommunicationException() {
    super(ERR_COMMUNICATION_EXCEPTION_DEFAULT.get());
  }
  /**
   * Create a communication exception with a cause and a default
   * message.
   *
   * @param cause
   *          The cause.
   */
  public CommunicationException(Throwable cause) {
    super(ERR_COMMUNICATION_EXCEPTION_DEFAULT_CAUSE.get(cause.getMessage()),
        cause);
  }
  /**
   * Create a communication exception with a message and cause.
   *
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  public CommunicationException(Message message, Throwable cause) {
    super(message, cause);
  }
  /**
   * Create a communication exception with a message.
   *
   * @param message
   *          The message.
   */
  public CommunicationException(Message message) {
    super(message);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/client/ConcurrentModificationException.java
New file
@@ -0,0 +1,100 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import static org.opends.messages.AdminMessages.*;
import org.opends.messages.Message;
import org.opends.server.admin.OperationsException;
/**
 * This exception is thrown when a critical concurrent modification is
 * detected by the client. This may be caused by another client
 * application removing a managed object whilst it is being managed.
 */
public class ConcurrentModificationException extends OperationsException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = -1467024486347612820L;
  /**
   * Create a concurrent modification exception with a default
   * message.
   */
  public ConcurrentModificationException() {
    super(ERR_CONCURRENT_MODIFICATION_EXCEPTION_DEFAULT.get());
  }
  /**
   * Create a concurrent modification exception with a cause and a
   * default message.
   *
   * @param cause
   *          The cause.
   */
  public ConcurrentModificationException(Throwable cause) {
    super(ERR_CONCURRENT_MODIFICATION_EXCEPTION_DEFAULT.get(), cause);
  }
  /**
   * Create a concurrent modification exception with a message and
   * cause.
   *
   * @param message
   *          The message.
   * @param cause
   *          The cause.
   */
  public ConcurrentModificationException(Message message, Throwable cause) {
    super(message, cause);
  }
  /**
   * Create a concurrent modification exception with a message.
   *
   * @param message
   *          The message.
   */
  public ConcurrentModificationException(Message message) {
    super(message);
  }
}
opendj-admin/src/main/java/org/opends/server/admin/client/IllegalManagedObjectNameException.java
New file
@@ -0,0 +1,143 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2008 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import static org.opends.messages.AdminMessages.*;
import org.opends.messages.Message;
import org.opends.server.admin.IllegalPropertyValueStringException;
import org.opends.server.admin.OperationsException;
import org.opends.server.admin.PropertyDefinition;
import org.opends.server.admin.PropertyDefinitionUsageBuilder;
/**
 * Thrown when an attempt is made to create a new managed object with
 * an illegal name.
 * <p>
 * This exception can occur when a new managed object is given a name
 * which is either an empty string, a string containing just
 * white-spaces, or a string which is invalid according to the managed
 * object's naming property (if it has one).
 */
public class IllegalManagedObjectNameException extends OperationsException {
  /**
   * Serialization ID.
   */
  private static final long serialVersionUID = 7491748228684293291L;
  // Create the message
  private static Message createMessage(String illegalName,
      PropertyDefinition<?> namingPropertyDefinition) {
    if (illegalName.length() == 0) {
      return ERR_ILLEGAL_MANAGED_OBJECT_NAME_EXCEPTION_EMPTY.get();
    } else if (illegalName.trim().length() == 0) {
      return ERR_ILLEGAL_MANAGED_OBJECT_NAME_EXCEPTION_BLANK.get();
    } else if (namingPropertyDefinition != null) {
      try {
        namingPropertyDefinition.decodeValue(illegalName);
      } catch (IllegalPropertyValueStringException e) {
        PropertyDefinitionUsageBuilder builder =
          new PropertyDefinitionUsageBuilder(true);
        return ERR_ILLEGAL_MANAGED_OBJECT_NAME_EXCEPTION_SYNTAX.get(
            illegalName, namingPropertyDefinition.getName(), builder
                .getUsage(namingPropertyDefinition));
      }
    }
    return ERR_ILLEGAL_MANAGED_OBJECT_NAME_EXCEPTION_OTHER.get(illegalName);
  }
  // The illegal name.
  private final String illegalName;
  // The naming property definition if applicable.
  private final PropertyDefinition<?> namingPropertyDefinition;
  /**
   * Create a new illegal name exception and no naming property
   * definition.
   *
   * @param illegalName
   *          The illegal managed object name.
   */
  public IllegalManagedObjectNameException(String illegalName) {
    this(illegalName, null);
  }
  /**
   * Create a new illegal name exception and a naming property
   * definition.
   *
   * @param illegalName
   *          The illegal managed object name.
   * @param namingPropertyDefinition
   *          The naming property definition.
   */
  public IllegalManagedObjectNameException(String illegalName,
      PropertyDefinition<?> namingPropertyDefinition) {
    super(createMessage(illegalName, namingPropertyDefinition));
    this.illegalName = illegalName;
    this.namingPropertyDefinition = namingPropertyDefinition;
  }
  /**
   * Get the illegal managed object name.
   *
   * @return Returns the illegal managed object name.
   */
  public String getIllegalName() {
    return illegalName;
  }
  /**
   * Get the naming property definition if applicable.
   *
   * @return Returns naming property definition, or <code>null</code>
   *         if none was specified.
   */
  public PropertyDefinition<?> getNamingPropertyDefinition() {
    return namingPropertyDefinition;
  }
}
opendj-admin/src/main/java/org/opends/server/admin/client/ManagedObject.java
New file
@@ -0,0 +1,938 @@
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at
 * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
 * add the following below this CDDL HEADER, with the fields enclosed
 * by brackets "[]" replaced with your own identifying information:
 *      Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 *
 *      Copyright 2007-2009 Sun Microsystems, Inc.
 */
package org.opends.server.admin.client;
import java.util.Collection;
import java.util.SortedSet;
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.DefaultBehaviorException;
import org.opends.server.admin.DefinitionDecodingException;
import org.opends.server.admin.IllegalPropertyValueException;
import org.opends.server.admin.InstantiableRelationDefinition;
import org.opends.server.admin.ManagedObjectAlreadyExistsException;
import org.opends.server.admin.ManagedObjectDefinition;
import org.opends.server.admin.ConfigurationClient;
import org.opends.server.admin.ManagedObjectNotFoundException;
import org.opends.server.admin.ManagedObjectPath;
import org.opends.server.admin.OptionalRelationDefinition;
import org.opends.server.admin.PropertyDefinition;
import org.opends.server.admin.PropertyIsMandatoryException;
import org.opends.server.admin.PropertyIsReadOnlyException;
import org.opends.server.admin.PropertyIsSingleValuedException;
import org.opends.server.admin.PropertyProvider;
import org.opends.server.admin.SetRelationDefinition;
import org.opends.server.admin.SingletonRelationDefinition;
/**
 * A generic interface for accessing client-side managed objects.
 * <p>
 * A managed object comprises of zero or more properties. A property
 * has associated with it three sets of property value(s). These are:
 * <ul>
 * <li><i>default value(s)</i> - these value(s) represent the
 * default behavior for the property when it has no active values.
 * When a property inherits its default value(s) from elsewhere (i.e.
 * a property in another managed object), the default value(s)
 * represent the active value(s) of the inherited property at the time
 * the managed object was retrieved
 * <li><i>active value(s)</i> - these value(s) represent the state
 * of the property at the time the managed object was retrieved
 * <li><i>pending value(s)</i> - these value(s) represent any
 * modifications made to the property's value(s) since the managed
 * object object was retrieved and before the changes have been
 * committed using the {@link #commit()} method, the pending values
 * can be empty indicating that the property should be modified back
 * to its default values.
 * </ul>
 * In addition, a property has an <i>effective state</i> defined by
 * its <i>effective values</i> which are derived by evaluating the
 * following rules in the order presented:
 * <ul>
 * <li>the <i>pending values</i> if defined and non-empty
 * <li>or, the <i>default values</i> if the pending values are
 * defined but are empty
 * <li>or, the <i>active values</i> if defined and non-empty
 * <li>or, the <i>default values</i> if there are no active values
 * <li>or, an empty set of values, if there are no default values.
 * </ul>
 *
 * @param <T>
 *          The type of client configuration represented by the client
 *          managed object.
 */
public interface ManagedObject<T extends ConfigurationClient> extends
    PropertyProvider {
  /**
   * Adds this managed object to the server or commits any changes
   * made to it depending on whether or not the managed object already
   * exists on the server. Pending property values will be committed
   * to the managed object. If successful, the pending values will
   * become active values.
   * <p>
   * See the class description for more information regarding pending
   * and active values.
   *
   * @throws ManagedObjectAlreadyExistsException
   *           If the managed object cannot be added to the server
   *           because it already exists.
   * @throws MissingMandatoryPropertiesException
   *           If the managed object contains some mandatory
   *           properties which have been left undefined.
   * @throws ConcurrentModificationException
   *           If the managed object is being added to the server but
   *           its parent has been removed by another client, or if
   *           this managed object is being modified but it has been
   *           removed from the server by another client.
   * @throws OperationRejectedException
   *           If this managed object cannot be added or modified due
   *           to some client-side or server-side constraint which
   *           cannot be satisfied.
   * @throws AuthorizationException
   *           If the server refuses to add or modify this managed
   *           object because the client does not have the correct
   *           privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  void commit() throws ManagedObjectAlreadyExistsException,
      MissingMandatoryPropertiesException, ConcurrentModificationException,
      OperationRejectedException, AuthorizationException,
      CommunicationException;
  /**
   * Determines whether or not this managed object has been modified since it
   * was constructed.
   * In other words, whether or not the set of pending values differs from
   * the set of active values.
   *
   * @return Returns <code>true</code> if this managed object has been
   *         modified since it was constructed.
   */
  boolean isModified();
  /**
   * Creates a new child managed object bound to the specified
   * instantiable relation. The new managed object will initially not
   * contain any property values (including mandatory properties).
   * Once the managed object has been configured it can be added to
   * the server using the {@link #commit()} method.
   *
   * @param <C>
   *          The expected type of the child managed object
   *          configuration client.
   * @param <S>
   *          The expected type of the child managed object
   *          server configuration.
   * @param <CC>
   *          The actual type of the added managed object
   *          configuration client.
   * @param r
   *          The instantiable relation definition.
   * @param d
   *          The definition of the managed object to be created.
   * @param name
   *          The name of the child managed object.
   * @param exceptions
   *          A collection in which to place any
   *          {@link DefaultBehaviorException}s that occurred whilst
   *          attempting to determine the managed object's default
   *          values.
   * @return Returns a new child managed object bound to the specified
   *         instantiable relation.
   * @throws IllegalManagedObjectNameException
   *           If the name of the child managed object is invalid.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   */
  <C extends ConfigurationClient, S extends Configuration, CC extends C>
  ManagedObject<CC> createChild(InstantiableRelationDefinition<C, S> r,
      ManagedObjectDefinition<CC, ? extends S> d, String name,
      Collection<DefaultBehaviorException> exceptions)
      throws IllegalManagedObjectNameException, IllegalArgumentException;
  /**
   * Creates a new child managed object bound to the specified
   * optional relation. The new managed object will initially not
   * contain any property values (including mandatory properties).
   * Once the managed object has been configured it can be added to
   * the server using the {@link #commit()} method.
   *
   * @param <C>
   *          The expected type of the child managed object
   *          configuration client.
   * @param <S>
   *          The expected type of the child managed object
   *          server configuration.
   * @param <CC>
   *          The actual type of the added managed object
   *          configuration client.
   * @param r
   *          The optional relation definition.
   * @param d
   *          The definition of the managed object to be created.
   * @param exceptions
   *          A collection in which to place any
   *          {@link DefaultBehaviorException}s that occurred whilst
   *          attempting to determine the managed object's default
   *          values.
   * @return Returns a new child managed object bound to the specified
   *         optional relation.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   */
  <C extends ConfigurationClient, S extends Configuration, CC extends C>
  ManagedObject<CC> createChild(OptionalRelationDefinition<C, S> r,
      ManagedObjectDefinition<CC, ? extends S> d,
      Collection<DefaultBehaviorException> exceptions)
      throws IllegalArgumentException;
  /**
   * Creates a new child managed object bound to the specified
   * set relation. The new managed object will initially not
   * contain any property values (including mandatory properties).
   * Once the managed object has been configured it can be added to
   * the server using the {@link #commit()} method.
   *
   * @param <C>
   *          The expected type of the child managed object
   *          configuration client.
   * @param <S>
   *          The expected type of the child managed object
   *          server configuration.
   * @param <CC>
   *          The actual type of the added managed object
   *          configuration client.
   * @param r
   *          The set relation definition.
   * @param d
   *          The definition of the managed object to be created.
   * @param exceptions
   *          A collection in which to place any
   *          {@link DefaultBehaviorException}s that occurred whilst
   *          attempting to determine the managed object's default
   *          values.
   * @return Returns a new child managed object bound to the specified
   *         set relation.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   */
  <C extends ConfigurationClient, S extends Configuration, CC extends C>
  ManagedObject<CC> createChild(SetRelationDefinition<C, S> r,
      ManagedObjectDefinition<CC, ? extends S> d,
      Collection<DefaultBehaviorException> exceptions)
      throws IllegalArgumentException;
  /**
   * Retrieves an instantiable child managed object.
   *
   * @param <C>
   *          The requested type of the child managed object
   *          configuration client.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The instantiable relation definition.
   * @param name
   *          The name of the child managed object.
   * @return Returns the instantiable child managed object.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws DefinitionDecodingException
   *           If the managed object was found but its type could not
   *           be determined.
   * @throws ManagedObjectDecodingException
   *           If the managed object was found but one or more of its
   *           properties could not be decoded.
   * @throws ManagedObjectNotFoundException
   *           If the requested managed object could not be found on
   *           the server.
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to retrieve the managed object
   *           because the client does not have the correct
   *           privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  ManagedObject<? extends C> getChild(InstantiableRelationDefinition<C, S> r,
      String name) throws IllegalArgumentException, DefinitionDecodingException,
      ManagedObjectDecodingException, ManagedObjectNotFoundException,
      ConcurrentModificationException, AuthorizationException,
      CommunicationException;
  /**
   * Retrieves an optional child managed object.
   *
   * @param <C>
   *          The requested type of the child managed object
   *          configuration client.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The optional relation definition.
   * @return Returns the optional child managed object.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws DefinitionDecodingException
   *           If the managed object was found but its type could not
   *           be determined.
   * @throws ManagedObjectDecodingException
   *           If the managed object was found but one or more of its
   *           properties could not be decoded.
   * @throws ManagedObjectNotFoundException
   *           If the requested managed object could not be found on
   *           the server.
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to retrieve the managed object
   *           because the client does not have the correct
   *           privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  ManagedObject<? extends C> getChild(OptionalRelationDefinition<C, S> r)
      throws IllegalArgumentException, DefinitionDecodingException,
      ManagedObjectDecodingException, ManagedObjectNotFoundException,
      ConcurrentModificationException, AuthorizationException,
      CommunicationException;
  /**
   * Retrieves a singleton child managed object.
   *
   * @param <C>
   *          The requested type of the child managed object
   *          configuration client.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The singleton relation definition.
   * @return Returns the singleton child managed object.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws DefinitionDecodingException
   *           If the managed object was found but its type could not
   *           be determined.
   * @throws ManagedObjectDecodingException
   *           If the managed object was found but one or more of its
   *           properties could not be decoded.
   * @throws ManagedObjectNotFoundException
   *           If the requested managed object could not be found on
   *           the server.
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to retrieve the managed object
   *           because the client does not have the correct
   *           privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  ManagedObject<? extends C> getChild(SingletonRelationDefinition<C, S> r)
      throws IllegalArgumentException, DefinitionDecodingException,
      ManagedObjectDecodingException, ManagedObjectNotFoundException,
      ConcurrentModificationException, AuthorizationException,
      CommunicationException;
  /**
   * Retrieves a set child managed object.
   *
   * @param <C>
   *          The requested type of the child managed object
   *          configuration client.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The set relation definition.
   * @param name
   *          The name of the child managed object.
   * @return Returns the set child managed object.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws DefinitionDecodingException
   *           If the managed object was found but its type could not
   *           be determined.
   * @throws ManagedObjectDecodingException
   *           If the managed object was found but one or more of its
   *           properties could not be decoded.
   * @throws ManagedObjectNotFoundException
   *           If the requested managed object could not be found on
   *           the server.
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to retrieve the managed object
   *           because the client does not have the correct
   *           privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  ManagedObject<? extends C> getChild(SetRelationDefinition<C, S> r,
      String name) throws IllegalArgumentException, DefinitionDecodingException,
      ManagedObjectDecodingException, ManagedObjectNotFoundException,
      ConcurrentModificationException, AuthorizationException,
      CommunicationException;
  /**
   * Creates a client configuration view of this managed object.
   * Modifications made to this managed object will be reflected in
   * the client configuration view and vice versa.
   *
   * @return Returns a client configuration view of this managed
   *         object.
   */
  T getConfiguration();
  /**
   * Gets the definition associated with this managed object.
   *
   * @return Returns the definition associated with this managed
   *         object.
   */
  ManagedObjectDefinition<T, ? extends Configuration>
    getManagedObjectDefinition();
  /**
   * Gets the path of this managed object.
   *
   * @return Returns the path of this managed object.
   */
  ManagedObjectPath<T, ? extends Configuration> getManagedObjectPath();
  /**
   * Gets a mutable copy of the set of default values for the
   * specified property.
   *
   * @param <PD>
   *          The type of the property to be retrieved.
   * @param pd
   *          The property to be retrieved.
   * @return Returns the property's default values, or an empty set if
   *         there are no default values defined.
   * @throws IllegalArgumentException
   *           If the property definition is not associated with this
   *           managed object's definition.
   */
  <PD> SortedSet<PD> getPropertyDefaultValues(PropertyDefinition<PD> pd)
      throws IllegalArgumentException;
  /**
   * Gets the effective value of the specified property.
   * <p>
   * See the class description for more information about how the
   * effective property value is derived.
   *
   * @param <PD>
   *          The type of the property to be retrieved.
   * @param pd
   *          The property to be retrieved.
   * @return Returns the property's effective value, or
   *         <code>null</code> if there is no effective value
   *         defined.
   * @throws IllegalArgumentException
   *           If the property definition is not associated with this
   *           managed object's definition.
   */
  <PD> PD getPropertyValue(PropertyDefinition<PD> pd)
      throws IllegalArgumentException;
  /**
   * Gets a mutable copy of the set of effective values for the
   * specified property.
   * <p>
   * See the class description for more information about how the
   * effective property values are derived.
   *
   * @param <PD>
   *          The type of the property to be retrieved.
   * @param pd
   *          The property to be retrieved.
   * @return Returns the property's effective values, or an empty set
   *         if there are no effective values defined.
   * @throws IllegalArgumentException
   *           If the property definition is not associated with this
   *           managed object's definition.
   */
  <PD> SortedSet<PD> getPropertyValues(PropertyDefinition<PD> pd)
      throws IllegalArgumentException;
  /**
   * Determines whether or not the specified property is set. If the
   * property is unset, then any default behavior associated with the
   * property applies.
   *
   * @param pd
   *          The property definition.
   * @return Returns <code>true</code> if the property has been set,
   *         or <code>false</code> if it is unset and any default
   *         behavior associated with the property applies.
   * @throws IllegalArgumentException
   *           If the property definition is not associated with this
   *           managed object's definition.
   */
  boolean isPropertyPresent(PropertyDefinition<?> pd)
      throws IllegalArgumentException;
  /**
   * Determines whether or not the optional managed object associated
   * with the specified optional relations exists.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The optional relation definition.
   * @return Returns <code>true</code> if the optional managed
   *         object exists, <code>false</code> otherwise.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to make the determination because
   *           the client does not have the correct privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  boolean hasChild(OptionalRelationDefinition<C, S> r)
      throws IllegalArgumentException, ConcurrentModificationException,
      AuthorizationException, CommunicationException;
  /**
   * Lists the child managed objects associated with the specified
   * instantiable relation.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The instantiable relation definition.
   * @return Returns the names of the child managed objects.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to list the managed objects
   *           because the client does not have the correct
   *           privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  String[] listChildren(InstantiableRelationDefinition<C, S> r)
      throws IllegalArgumentException, ConcurrentModificationException,
      AuthorizationException, CommunicationException;
  /**
   * Lists the child managed objects associated with the specified
   * instantiable relation which are a sub-type of the specified
   * managed object definition.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The instantiable relation definition.
   * @param d
   *          The managed object definition.
   * @return Returns the names of the child managed objects which are
   *         a sub-type of the specified managed object definition.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to list the managed objects
   *           because the client does not have the correct
   *           privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  String[] listChildren(InstantiableRelationDefinition<C, S> r,
      AbstractManagedObjectDefinition<? extends C, ? extends S> d)
      throws IllegalArgumentException, ConcurrentModificationException,
      AuthorizationException, CommunicationException;
  /**
   * Lists the child managed objects associated with the specified set
   * relation.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The set relation definition.
   * @return Returns the names of the child managed objects which for
   *         set relations are the definition names of each managed
   *         object.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to list the managed objects because
   *           the client does not have the correct privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  String[] listChildren(SetRelationDefinition<C, S> r)
      throws IllegalArgumentException, ConcurrentModificationException,
      AuthorizationException, CommunicationException;
  /**
   * Lists the child managed objects associated with the specified set
   * relation which are a sub-type of the specified managed object
   * definition.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The set relation definition.
   * @param d
   *          The managed object definition.
   * @return Returns the names of the child managed objects which for
   *         set relations are the definition names of each managed
   *         object.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to list the managed objects because
   *           the client does not have the correct privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  String[] listChildren(SetRelationDefinition<C, S> r,
      AbstractManagedObjectDefinition<? extends C, ? extends S> d)
      throws IllegalArgumentException, ConcurrentModificationException,
      AuthorizationException, CommunicationException;
  /**
   * Removes the named instantiable child managed object.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The instantiable relation definition.
   * @param name
   *          The name of the child managed object to be removed.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws ManagedObjectNotFoundException
   *           If the managed object could not be removed because it
   *           could not found on the server.
   * @throws OperationRejectedException
   *           If the managed object cannot be removed due to some
   *           client-side or server-side constraint which cannot be
   *           satisfied (for example, if it is referenced by another
   *           managed object).
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to remove the managed objects
   *           because the client does not have the correct
   *           privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  void removeChild(InstantiableRelationDefinition<C, S> r, String name)
      throws IllegalArgumentException, ManagedObjectNotFoundException,
      OperationRejectedException, ConcurrentModificationException,
      AuthorizationException, CommunicationException;
  /**
   * Removes an optional child managed object.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The optional relation definition.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws ManagedObjectNotFoundException
   *           If the managed object could not be removed because it
   *           could not found on the server.
   * @throws OperationRejectedException
   *           If the managed object cannot be removed due to some
   *           client-side or server-side constraint which cannot be
   *           satisfied (for example, if it is referenced by another
   *           managed object).
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to remove the managed objects
   *           because the client does not have the correct
   *           privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  void removeChild(OptionalRelationDefinition<C, S> r)
      throws IllegalArgumentException, ManagedObjectNotFoundException,
      OperationRejectedException, ConcurrentModificationException,
      AuthorizationException, CommunicationException;
  /**
   * Removes s set child managed object.
   *
   * @param <C>
   *          The type of client managed object configuration that the
   *          relation definition refers to.
   * @param <S>
   *          The type of server managed object configuration that the
   *          relation definition refers to.
   * @param r
   *          The set relation definition.
   * @param name
   *          The name of the child managed object to be removed.
   * @throws IllegalArgumentException
   *           If the relation definition is not associated with this
   *           managed object's definition.
   * @throws ManagedObjectNotFoundException
   *           If the managed object could not be removed because it
   *           could not found on the server.
   * @throws OperationRejectedException
   *           If the managed object cannot be removed due to some
   *           client-side or server-side constraint which cannot be
   *           satisfied (for example, if it is referenced by another
   *           managed object).
   * @throws ConcurrentModificationException
   *           If this managed object has been removed from the server
   *           by another client.
   * @throws AuthorizationException
   *           If the server refuses to remove the managed objects
   *           because the client does not have the correct
   *           privileges.
   * @throws CommunicationException
   *           If the client cannot contact the server due to an
   *           underlying communication problem.
   */
  <C extends ConfigurationClient, S extends Configuration>
  void removeChild(SetRelationDefinition<C, S> r, String name)
      throws IllegalArgumentException, ManagedObjectNotFoundException,
      OperationRejectedException, ConcurrentModificationException,
      AuthorizationException, CommunicationException;
  /**
   * Sets a new pending value for the specified property.
   * <p>
   * See the class description for more information regarding pending
   * values.
   *
   * @param <PD>
   *          The type of the property to be modified.
   * @param pd
   *          The property to be modified.
   * @param value
   *          The new pending value for the property, or
   *          <code>null</code> if the property should be reset to
   *          its default behavior.
   * @throws IllegalPropertyValueException
   *           If the new pending value is deemed to be invalid
   *           according to the property definition.
   * @throws PropertyIsReadOnlyException
   *           If this is not a new managed object and the property is
   *           read-only or for monitoring purposes.
   * @throws PropertyIsMandatoryException
   *           If an attempt was made to remove a mandatory property.
   * @throws IllegalArgumentException
   *           If the specified property definition is not associated
   *           with this managed object.
   */
  <PD> void setPropertyValue(PropertyDefinition<PD> pd, PD value)
      throws IllegalPropertyValueException, PropertyIsReadOnlyException,
      PropertyIsMandatoryException, IllegalArgumentException;
  /**
   * Sets a new pending values for the specified property.
   * <p>
   * See the class description for more information regarding pending
   * values.
   *
   * @param <PD>
   *          The type of the property to be modified.
   * @param pd
   *          The property to be modified.
   * @param values
   *          A non-<code>null</code> set of new pending values for
   *          the property (an empty set indicates that the property
   *          should be reset to its default behavior). The set will
   *          not be referenced by this managed object.
   * @throws IllegalPropertyValueException
   *           If a new pending value is deemed to be invalid
   *           according to the property definition.
   * @throws PropertyIsSingleValuedException
   *           If an attempt was made to add multiple pending values
   *           to a single-valued property.
   * @throws PropertyIsReadOnlyException
   *           If this is not a new managed object and the property is
   *           read-only or for monitoring purposes.
   * @throws PropertyIsMandatoryException
   *           If an attempt was made to remove a mandatory property.
   * @throws IllegalArgumentException
   *           If the specified property definition is not associated
   *           with this managed object.
   */
  <PD> void setPropertyValues(PropertyDefinition<PD> pd, Collection<PD> values)
      throws IllegalPropertyValueException, PropertyIsSingleValuedException,
      PropertyIsReadOnlyException, PropertyIsMandatoryException,
      IllegalArgumentException;
}
Diff truncated after the above file
opendj-admin/src/main/java/org/opends/server/admin/client/ManagedObjectDecodingException.java opendj-admin/src/main/java/org/opends/server/admin/client/ManagementContext.java opendj-admin/src/main/java/org/opends/server/admin/client/MissingMandatoryPropertiesException.java opendj-admin/src/main/java/org/opends/server/admin/client/OperationRejectedException.java opendj-admin/src/main/java/org/opends/server/admin/client/ldap/JNDIDirContextAdaptor.java opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPConnection.java opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPDriver.java opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPManagedObject.java opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPManagementContext.java opendj-admin/src/main/java/org/opends/server/admin/client/ldap/LDAPNameBuilder.java opendj-admin/src/main/java/org/opends/server/admin/client/ldap/package-info.java opendj-admin/src/main/java/org/opends/server/admin/client/package-info.java opendj-admin/src/main/java/org/opends/server/admin/client/spi/AbstractManagedObject.java opendj-admin/src/main/java/org/opends/server/admin/client/spi/Driver.java opendj-admin/src/main/java/org/opends/server/admin/client/spi/Property.java opendj-admin/src/main/java/org/opends/server/admin/client/spi/PropertySet.java opendj-admin/src/main/java/org/opends/server/admin/client/spi/package-info.java opendj-admin/src/main/java/org/opends/server/admin/condition/ANDCondition.java opendj-admin/src/main/java/org/opends/server/admin/condition/Condition.java opendj-admin/src/main/java/org/opends/server/admin/condition/Conditions.java opendj-admin/src/main/java/org/opends/server/admin/condition/ContainsCondition.java opendj-admin/src/main/java/org/opends/server/admin/condition/IsPresentCondition.java opendj-admin/src/main/java/org/opends/server/admin/condition/NOTCondition.java opendj-admin/src/main/java/org/opends/server/admin/condition/ORCondition.java opendj-admin/src/main/java/org/opends/server/admin/condition/package-info.java opendj-admin/src/main/java/org/opends/server/admin/doc/ConfigGuideGeneration.java opendj-admin/src/main/java/org/opends/server/admin/doc/package-info.java opendj-admin/src/main/java/org/opends/server/admin/package-info.java opendj-admin/src/main/java/org/opends/server/admin/server/AbstractConfigListenerAdaptor.java opendj-admin/src/main/java/org/opends/server/admin/server/ConfigAddListenerAdaptor.java opendj-admin/src/main/java/org/opends/server/admin/server/ConfigChangeListenerAdaptor.java opendj-admin/src/main/java/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java opendj-admin/src/main/java/org/opends/server/admin/server/ConfigExceptionFactory.java opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationAddListener.java opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationChangeListener.java opendj-admin/src/main/java/org/opends/server/admin/server/ConfigurationDeleteListener.java opendj-admin/src/main/java/org/opends/server/admin/server/ConstraintViolationException.java opendj-admin/src/main/java/org/opends/server/admin/server/DNBuilder.java opendj-admin/src/main/java/org/opends/server/admin/server/DelayedConfigAddListener.java opendj-admin/src/main/java/org/opends/server/admin/server/ServerConstraintHandler.java opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObject.java opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectAddListener.java opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectAddListenerAdaptor.java opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectChangeListener.java opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectChangeListenerAdaptor.java opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDecodingException.java opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDeleteListener.java opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagedObjectDeleteListenerAdaptor.java opendj-admin/src/main/java/org/opends/server/admin/server/ServerManagementContext.java opendj-admin/src/main/java/org/opends/server/admin/server/package-info.java