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

matthew_swift
03.37.2007 747224b472c37b0f1325344918fcc08265bb1b09
Three introspection related changes required in order to support the CLI:

* support storing the managed object definition in managed object path elements (this can be a sub-type of the definition referenced by the element's relation). Also make managed object paths generic on the type of managed object they reference.

* add support for retrieving the properties/relations defined by a managed object definition not including those that are inherited

* add a convenience method to managed object definitions for recursively retrieving all the child definitions.

1 files added
12 files modified
1258 ■■■■ changed files
opendj-sdk/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java 231 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectPath.java 618 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectPathSerializer.java 67 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/client/ExampleIntrospection.java 24 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/client/ManagedObject.java 6 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/client/PropertySet.java 8 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java 11 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPNameBuilder.java 21 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java 2 ●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java 2 ●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/server/DNBuilder.java 21 ●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java 7 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ManagedObjectPathTest.java 240 ●●●●● patch | view | raw | blame | history
opendj-sdk/opends/src/server/org/opends/server/admin/AbstractManagedObjectDefinition.java
@@ -29,9 +29,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
@@ -90,52 +92,15 @@
      AbstractManagedObjectDefinition<? super C, ? super S> parent) {
    this.name = name;
    this.parent = parent;
    this.propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
    this.relationDefinitions = new HashMap<String, RelationDefinition<?,?>>();
    this.children = new HashMap<String,
      AbstractManagedObjectDefinition<? extends C, ? extends S>>();
    // If we have a parent definition then inherit its features.
    if (parent != null) {
      this.propertyDefinitions = new HashMap<String, PropertyDefinition<?>>(
          parent.propertyDefinitions);
      this.relationDefinitions = new HashMap<String, RelationDefinition<?,?>>(
          parent.relationDefinitions);
      parent.children.put(name, this);
    } else {
      this.propertyDefinitions = new HashMap<String, PropertyDefinition<?>>();
      this.relationDefinitions = new HashMap<String, RelationDefinition<?,?>>();
    }
    this.children = new HashMap<String,
      AbstractManagedObjectDefinition<? extends C, ? extends S>>();
  }
  /**
   * Get the named child managed object definition which inherits from this
   * managed object definition.
   *
   * @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) {
      throw new IllegalArgumentException("managed object definition \"" + name
          + "\" not found");
    }
    return d;
  }
@@ -149,6 +114,121 @@
   *         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 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() {
    if (parent == null) {
      return getPropertyDefinitions();
    } else {
      List<PropertyDefinition<?>> list = new ArrayList<PropertyDefinition<?>>(
          propertyDefinitions.values());
      list.addAll(parent.getAllPropertyDefinitions());
      return Collections.unmodifiableCollection(list);
    }
  }
  /**
   * 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() {
    if (parent == null) {
      return getRelationDefinitions();
    } else {
      List<RelationDefinition<?, ?>> list =
        new ArrayList<RelationDefinition<?, ?>>(relationDefinitions.values());
      list.addAll(parent.getAllRelationDefinitions());
      return Collections.unmodifiableCollection(list);
    }
  }
  /**
   * 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());
  }
@@ -216,16 +296,17 @@
  /**
   * Get the specified property definition associated with this type of managed
   * object.
   * 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.
   * @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.
   *           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 {
@@ -234,9 +315,14 @@
    }
    PropertyDefinition d = propertyDefinitions.get(name);
    if (d == null) {
      throw new IllegalArgumentException("property definition \"" + name
          + "\" not found");
      if (parent != null) {
        return parent.getPropertyDefinition(name);
      } else {
        throw new IllegalArgumentException("property definition \"" + name
            + "\" not found");
      }
    }
    return d;
@@ -245,12 +331,13 @@
  /**
   * Get all the property definitions associated with this type of
   * managed object.
   * 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 all the
   *         property definitions associated with this type of managed
   *         object.
   * @return Returns an unmodifiable collection containing the
   *         property definitions defined by this managed object
   *         definition.
   */
  public final Collection<PropertyDefinition<?>> getPropertyDefinitions() {
    return Collections.unmodifiableCollection(propertyDefinitions
@@ -260,16 +347,17 @@
  /**
   * Get the specified relation definition associated with this type of managed
   * object.
   * 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.
   * @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.
   *           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 {
@@ -278,9 +366,14 @@
    }
    RelationDefinition d = relationDefinitions.get(name);
    if (d == null) {
      throw new IllegalArgumentException("relation definition \"" + name
          + "\" not found");
      if (parent != null) {
        return parent.getRelationDefinition(name);
      } else {
        throw new IllegalArgumentException("relation definition \"" + name
            + "\" not found");
      }
    }
    return d;
@@ -289,16 +382,16 @@
  /**
   * Get all the relation definitions associated with this type of
   * managed object.
   * 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 all the
   *         relation definitions associated with this type of managed
   *         object.
   * @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());
    return Collections.unmodifiableCollection(relationDefinitions.values());
  }
opendj-sdk/opends/src/server/org/opends/server/admin/ManagedObjectPath.java
@@ -32,38 +32,62 @@
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;
/**
 * A path which can be used to determine the location of a managed
 * object instance.
 *
 * @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 {
public final class ManagedObjectPath
    <C extends ConfigurationClient, S extends Configuration> {
  /**
   * Abstract path element.
   */
  private static abstract class 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() {
      // No implementation required.
    protected Element(AbstractManagedObjectDefinition<C, S> definition) {
      this.definition = definition;
    }
    /**
     * Get the relation definition associated with this element.
     * Get the managed object definition associated with this element.
     *
     * @return Returns the relation definition associated with this
     *         element.
     * @return Returns the managed object definition associated with
     *         this element.
     */
    public abstract RelationDefinition<?, ?> getRelation();
    public final AbstractManagedObjectDefinition<C, S>
        getManagedObjectDefinition() {
      return definition;
    }
@@ -74,8 +98,7 @@
     * @param serializer
     *          The managed object path serialization strategy.
     */
    public abstract void serialize(
        ManagedObjectPathSerializer serializer);
    public abstract void serialize(ManagedObjectPathSerializer serializer);
  }
@@ -83,19 +106,32 @@
  /**
   * A path element representing an instantiable managed object.
   */
  private static final class InstantiableElement extends Element {
  private static final class InstantiableElement
      <C extends ConfigurationClient, S extends Configuration>
      extends Element<C, S> {
    // The instantiable relation.
    private final InstantiableRelationDefinition<?, ?> r;
    // 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<?, ?> r, String name) {
        InstantiableRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d, String name) {
      super(d);
      this.r = r;
      this.name = name;
    }
@@ -106,20 +142,10 @@
     * {@inheritDoc}
     */
    @Override
    public RelationDefinition<?, ?> getRelation() {
      return r;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void serialize(ManagedObjectPathSerializer serializer) {
      serializer.appendManagedObjectPathElement(r, name);
      serializer.appendManagedObjectPathElement(r,
          getManagedObjectDefinition(), name);
    }
  }
@@ -127,15 +153,28 @@
  /**
   * A path element representing an optional managed object.
   */
  private static final class OptionalElement extends Element {
  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<?, ?> r;
    private final OptionalRelationDefinition<? super C, ? super S> r;
    // Private constructor.
    private OptionalElement(OptionalRelationDefinition<?, ?> r) {
    private OptionalElement(OptionalRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      super(d);
      this.r = r;
    }
@@ -145,18 +184,9 @@
     * {@inheritDoc}
     */
    @Override
    public RelationDefinition<?, ?> getRelation() {
      return r;
    }
    /**
     * {@inheritDoc}
     */
    @Override
    public void serialize(ManagedObjectPathSerializer serializer) {
      serializer.appendManagedObjectPathElement(r);
      serializer
          .appendManagedObjectPathElement(r, getManagedObjectDefinition());
    }
  }
@@ -165,15 +195,29 @@
  /**
   * A path element representing a singleton managed object.
   */
  private static final class SingletonElement extends Element {
  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<?, ?> r;
    private final SingletonRelationDefinition<? super C, ? super S> r;
    // Private constructor.
    private SingletonElement(SingletonRelationDefinition<?, ?> r) {
    private SingletonElement(
        SingletonRelationDefinition<? super C, ? super S> r,
        AbstractManagedObjectDefinition<C, S> d) {
      super(d);
      this.r = r;
    }
@@ -183,8 +227,29 @@
     * {@inheritDoc}
     */
    @Override
    public RelationDefinition<?, ?> getRelation() {
      return r;
    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;
    }
@@ -192,15 +257,69 @@
    /**
     * {@inheritDoc}
     */
    @Override
    public void serialize(ManagedObjectPathSerializer serializer) {
      serializer.appendManagedObjectPathElement(r);
    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);
    }
    // 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 EMPTY_PATH = new ManagedObjectPath(
      new LinkedList<Element>());
  private static final ManagedObjectPath<RootCfgClient, RootCfg> EMPTY_PATH =
    new ManagedObjectPath<RootCfgClient, RootCfg>(
      new LinkedList<Element<?, ?>>(), 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*)?$");
@@ -211,11 +330,12 @@
   * @return Returns a new managed object path representing the
   *         configuration root.
   */
  public static ManagedObjectPath emptyPath() {
  public static ManagedObjectPath<RootCfgClient, RootCfg> emptyPath() {
    return EMPTY_PATH;
  }
  /**
   * Returns a managed object path holding the value of the specified
   * string.
@@ -227,29 +347,226 @@
   * @throws IllegalArgumentException
   *           If the string could not be parsed.
   */
  public static ManagedObjectPath valueOf(String s)
  public static ManagedObjectPath<?, ?> valueOf(String s)
      throws IllegalArgumentException {
    return null;
    String ns = s.trim();
    // Check for root special case.
    if (ns.equals("/")) {
      return EMPTY_PATH;
    }
    // Parse the elements.
    LinkedList<Element<?, ?>> elements = new LinkedList<Element<?, ?>>();
    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 + "\"");
      }
      String relation = m.group(1); // Mandatory.
      String type = m.group(3); // Optional.
      String name = m.group(5); // Mandatory if relation is
      // instantiable.
      // 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.
      Element<?, ?> e = createElement(r, ns, es, type, name);
      elements.add(e);
      definition = e.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, definition);
  }
  // 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,
      AbstractManagedObjectDefinition<C, S> definition) {
    return new ManagedObjectPath<C, S>(elements, definition);
  }
  // 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 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 last element in this path.
  private final AbstractManagedObjectDefinition<C, S> definition;
  // The list of path elements in this path.
  private final List<Element> elements;
  private final List<Element<?, ?>> elements;
  // Private constructor.
  private ManagedObjectPath(LinkedList<Element> elements) {
  private ManagedObjectPath(LinkedList<Element<?, ?>> elements,
      AbstractManagedObjectDefinition<C, S> definition) {
    this.elements = Collections.unmodifiableList(elements);
    this.definition = definition;
  }
  /**
   * Creates a new child managed object path beneath the provided
   * parent path.
   * 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.
   */
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(
      InstantiableRelationDefinition<? super M, ? super N> r,
      AbstractManagedObjectDefinition<M, N> d, String name) {
    LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
        elements);
    celements.add(new InstantiableElement<M, N>(r, d, name));
    return new ManagedObjectPath<M, N>(celements, 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
@@ -257,45 +574,116 @@
   * @return Returns a new child managed object path beneath the
   *         provided parent path.
   */
  public ManagedObjectPath child(
      InstantiableRelationDefinition<?, ?> r, String name) {
    LinkedList<Element> celements = new LinkedList<Element>(elements);
    celements.add(new InstantiableElement(r, name));
    return new ManagedObjectPath(celements);
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(
      InstantiableRelationDefinition<M, N> r, String name) {
    return child(r, r.getChildDefinition(), name);
  }
  /**
   * Creates a new child managed object path beneath the provided
   * parent path.
   * 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, 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 ManagedObjectPath child(OptionalRelationDefinition<?, ?> r) {
    LinkedList<Element> celements = new LinkedList<Element>(elements);
    celements.add(new OptionalElement(r));
    return new ManagedObjectPath(celements);
  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.
   * 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, 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 ManagedObjectPath child(SingletonRelationDefinition<?, ?> r) {
    LinkedList<Element> celements = new LinkedList<Element>(elements);
    celements.add(new SingletonElement(r));
    return new ManagedObjectPath(celements);
  public <M extends ConfigurationClient, N extends Configuration>
      ManagedObjectPath<M, N> child(
      SingletonRelationDefinition<M, N> r) {
    return child(r, r.getChildDefinition());
  }
@@ -321,20 +709,14 @@
   * Get the definition of the managed object referred to by this
   * path.
   * <p>
   * When the path is empty, the {@link RootCfgDefn}
   * is returned.
   * 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.
   *         by this path, or the {@link RootCfgDefn} if the path is
   *         empty.
   */
  public AbstractManagedObjectDefinition<?, ?> getManagedObjectDefinition() {
    if (elements.isEmpty()) {
      return RootCfgDefn.getInstance();
    } else {
      Element e = elements.get(elements.size() - 1);
      return e.getRelation().getChildDefinition();
    }
  public AbstractManagedObjectDefinition<C, S> getManagedObjectDefinition() {
    return definition;
  }
@@ -362,6 +744,23 @@
  /**
   * 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.
   *
@@ -374,7 +773,7 @@
   *           If the offset is less than 0, or greater than the
   *           number of path elements in this path.
   */
  public ManagedObjectPath parent(int offset)
  public ManagedObjectPath<?, ?> parent(int offset)
      throws IllegalArgumentException {
    if (offset < 0) {
      throw new IllegalArgumentException("Negative offset");
@@ -390,9 +789,16 @@
      return this;
    }
    LinkedList<Element> celements = new LinkedList<Element>(elements
        .subList(0, elements.size() - offset));
    return new ManagedObjectPath(celements);
    // 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));
    AbstractManagedObjectDefinition<?, ?> definition = celements.getLast()
        .getManagedObjectDefinition();
    return create(celements, definition);
  }
@@ -409,7 +815,7 @@
   *          The managed object path serialization strategy.
   */
  public void serialize(ManagedObjectPathSerializer serializer) {
    for (Element element : elements) {
    for (Element<?, ?> element : elements) {
      element.serialize(serializer);
    }
  }
@@ -449,36 +855,14 @@
   * @see #toString()
   */
  public void toString(final StringBuilder builder) {
    // Use a simple serializer to create the contents.
    ManagedObjectPathSerializer serializer = new ManagedObjectPathSerializer() {
      public void appendManagedObjectPathElement(
          InstantiableRelationDefinition<?, ?> r, String name) {
        builder.append('/');
        builder.append(r.getName());
        builder.append('/');
        builder.append(name);
      }
      public void appendManagedObjectPathElement(
          OptionalRelationDefinition<?, ?> r) {
        builder.append('/');
        builder.append(r.getName());
      }
      public void appendManagedObjectPathElement(
          SingletonRelationDefinition<?, ?> r) {
        builder.append('/');
        builder.append(r.getName());
      }
    };
    serialize(serializer);
    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-sdk/opends/src/server/org/opends/server/admin/ManagedObjectPathSerializer.java
@@ -31,48 +31,83 @@
/**
 * 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.
 * 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.
 * 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.
   * 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.
   */
  void appendManagedObjectPathElement(InstantiableRelationDefinition<?, ?> r,
      String 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 a optional relation.
   * 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.
   */
  void appendManagedObjectPathElement(OptionalRelationDefinition<?, ?> r);
  <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.
   * 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.
   */
  void appendManagedObjectPathElement(SingletonRelationDefinition<?, ?> r);
  <C extends ConfigurationClient, S extends Configuration>
      void appendManagedObjectPathElement(
      SingletonRelationDefinition<? super C, ? super S> r,
      AbstractManagedObjectDefinition<C, S> d);
}
opendj-sdk/opends/src/server/org/opends/server/admin/client/ExampleIntrospection.java
@@ -32,17 +32,14 @@
import static org.opends.server.util.ServerConstants.PROPERTY_SERVER_ROOT;
import java.io.File;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.ClassLoaderProvider;
import org.opends.server.admin.AggregationRelationDefinition;
import org.opends.server.admin.AttributeTypePropertyDefinition;
import org.opends.server.admin.ClassLoaderProvider;
import org.opends.server.admin.ClassPropertyDefinition;
import org.opends.server.admin.InstantiableRelationDefinition;
import org.opends.server.admin.ManagedObjectDefinition;
@@ -136,7 +133,7 @@
    RootCfgDefn d = RootCfgDefn.getInstance();
    String operands = "";
    for (RelationDefinition<?, ?> r : d.getRelationDefinitions()) {
    for (RelationDefinition<?, ?> r : d.getAllRelationDefinitions()) {
      r.accept(this, operands);
    }
  }
@@ -316,22 +313,7 @@
  private void processManagedObjectDefinition(
      AbstractManagedObjectDefinition<?, ?> parent,
      AbstractManagedObjectDefinition<?, ?> child, String operands) {
    Set<RelationDefinition<?, ?>> parentRelations;
    Set<RelationDefinition<?, ?>> childRelations;
    if (parent != null) {
      parentRelations = new HashSet<RelationDefinition<?, ?>>(parent
          .getRelationDefinitions());
    } else {
      parentRelations = Collections.emptySet();
    }
    // Only process relations not defined in parent.
    childRelations = new HashSet<RelationDefinition<?, ?>>(child
        .getRelationDefinitions());
    childRelations.removeAll(parentRelations);
    for (RelationDefinition<?, ?> r : childRelations) {
    for (RelationDefinition<?, ?> r : child.getRelationDefinitions()) {
      r.accept(this, operands);
    }
opendj-sdk/opends/src/server/org/opends/server/admin/client/ManagedObject.java
@@ -154,8 +154,7 @@
   *           If an attempt was made to remove a mandatory property.
   * @throws IllegalArgumentException
   *           If the specified property definition is not associated
   *           with this managed object, or if the property is
   *           read-only.
   *           with this managed object.
   */
  public <T> void setPropertyValue(PropertyDefinition<T> d, T value)
      throws IllegalPropertyValueException,
@@ -191,8 +190,7 @@
   *           If an attempt was made to remove a mandatory property.
   * @throws IllegalArgumentException
   *           If the specified property definition is not associated
   *           with this managed object, or if the property is
   *           read-only.
   *           with this managed object.
   */
  public <T> void setPropertyValues(PropertyDefinition<T> d,
      Collection<T> values) throws IllegalPropertyValueException,
opendj-sdk/opends/src/server/org/opends/server/admin/client/PropertySet.java
@@ -434,7 +434,7 @@
      new HashMap<PropertyDefinition, MyProperty>();
    // Copy the properties from the provider.
    for (PropertyDefinition<?> pd : d.getPropertyDefinitions()) {
    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
      createProperty(pd, p, i, properties, exceptions);
    }
@@ -472,7 +472,7 @@
      new HashMap<PropertyDefinition, MyProperty>();
    // Copy the properties from the provider.
    for (PropertyDefinition<?> pd : d.getPropertyDefinitions()) {
    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
      createProperty(pd, p, i, properties, exceptions);
    }
@@ -692,7 +692,7 @@
   *           If an attempt was made to remove a mandatory property.
   * @throws IllegalArgumentException
   *           If the specified property definition is not associated with this
   *           managed object, or if the property is read-only.
   *           managed object.
   */
  public <T> void setPropertyValue(PropertyDefinition<T> d, T value)
      throws IllegalPropertyValueException, PropertyIsReadOnlyException,
@@ -732,7 +732,7 @@
   *           If an attempt was made to remove a mandatory property.
   * @throws IllegalArgumentException
   *           If the specified property definition is not associated with this
   *           managed object, or if the property is read-only.
   *           managed object.
   */
  public <T> void setPropertyValues(PropertyDefinition<T> d,
      Collection<T> values) throws IllegalPropertyValueException,
opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPManagedObject.java
@@ -128,7 +128,8 @@
    public Collection<?> getDefaultPropertyValues(
        ManagedObjectPath path, String propertyName)
        throws OperationsException, PropertyNotFoundException {
      ManagedObject<?> mo = readEntry(dirContext, path, path
      ManagedObjectPath<?, ?> tmp = path;
      ManagedObject<?> mo = readEntry(dirContext, tmp, tmp
          .getManagedObjectDefinition());
      ManagedObjectDefinition<?, ?> mod = mo
          .getManagedObjectDefinition();
@@ -202,7 +203,7 @@
      ManagedObjectDefinition<?, ?> d) {
    ArrayList<String> attrIds = new ArrayList<String>();
    for (PropertyDefinition<?> pd : d.getPropertyDefinitions()) {
    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
      String attrId = LDAPProfile.getInstance().getAttributeName(d,
          pd);
      attrIds.add(attrId);
@@ -348,7 +349,7 @@
  private final DirContext dirContext;
  // The path associated with this managed object.
  private final ManagedObjectPath path;
  private final ManagedObjectPath<?, ?> path;
  // LDAP profile associated with this connection.
  private final LDAPProfile profile;
@@ -382,7 +383,7 @@
    ManagedObjectDefinition<C, ?> d = getManagedObjectDefinition();
    LDAPChangeBuilder builder = new LDAPChangeBuilder(dirContext,
        path, d);
    for (PropertyDefinition<?> pd : d.getPropertyDefinitions()) {
    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
      // FIXME: should throw an error when there are missing mandatory
      // properties.
      Property<?> p = properties.getProperty(pd);
@@ -696,7 +697,7 @@
    attributes.put(rdn.getType(), rdn.getValue().toString());
    // Create the remaining attributes.
    for (PropertyDefinition<?> pd : d.getPropertyDefinitions()) {
    for (PropertyDefinition<?> pd : d.getAllPropertyDefinitions()) {
      String attrID = profile.getAttributeName(d, pd);
      Attribute attribute = new BasicAttribute(attrID);
      encodeProperty(attribute, pd, properties);
opendj-sdk/opends/src/server/org/opends/server/admin/client/ldap/LDAPNameBuilder.java
@@ -35,6 +35,9 @@
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.ConfigurationClient;
import org.opends.server.admin.InstantiableRelationDefinition;
import org.opends.server.admin.LDAPProfile;
import org.opends.server.admin.ManagedObjectPath;
@@ -106,8 +109,10 @@
  /**
   * {@inheritDoc}
   */
  public void appendManagedObjectPathElement(
      InstantiableRelationDefinition<?, ?> r, String name) {
  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((RelationDefinition) r);
@@ -146,8 +151,10 @@
  /**
   * {@inheritDoc}
   */
  public void appendManagedObjectPathElement(
      OptionalRelationDefinition<?, ?> r) {
  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((RelationDefinition) r);
  }
@@ -157,8 +164,10 @@
  /**
   * {@inheritDoc}
   */
  public void appendManagedObjectPathElement(
      SingletonRelationDefinition<?, ?> r) {
  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((RelationDefinition) r);
  }
opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigAddListenerAdaptor.java
@@ -58,7 +58,7 @@
    AbstractConfigListenerAdaptor implements ConfigAddListener {
  // The managed object path of the parent.
  private final ManagedObjectPath path;
  private final ManagedObjectPath<?, ?> path;
  // The instantiable relation.
  private final InstantiableRelationDefinition<?, S> instantiableRelation;
opendj-sdk/opends/src/server/org/opends/server/admin/server/ConfigDeleteListenerAdaptor.java
@@ -60,7 +60,7 @@
    ConfigDeleteListener {
  // The managed object path of the parent.
  private final ManagedObjectPath path;
  private final ManagedObjectPath<?, ?> path;
  // The instantiable relation.
  private final InstantiableRelationDefinition<?, S> instantiableRelation;
opendj-sdk/opends/src/server/org/opends/server/admin/server/DNBuilder.java
@@ -29,6 +29,9 @@
import org.opends.server.admin.AbstractManagedObjectDefinition;
import org.opends.server.admin.Configuration;
import org.opends.server.admin.ConfigurationClient;
import org.opends.server.admin.InstantiableRelationDefinition;
import org.opends.server.admin.LDAPProfile;
import org.opends.server.admin.ManagedObjectPath;
@@ -120,8 +123,10 @@
  /**
   * {@inheritDoc}
   */
  public void appendManagedObjectPathElement(
      InstantiableRelationDefinition<?, ?> r, String name) {
  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((RelationDefinition) r);
@@ -155,8 +160,10 @@
  /**
   * {@inheritDoc}
   */
  public void appendManagedObjectPathElement(
      OptionalRelationDefinition<?, ?> r) {
  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((RelationDefinition) r);
  }
@@ -166,8 +173,10 @@
  /**
   * {@inheritDoc}
   */
  public void appendManagedObjectPathElement(
      SingletonRelationDefinition<?, ?> r) {
  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((RelationDefinition) r);
  }
opendj-sdk/opends/src/server/org/opends/server/admin/server/ServerManagedObject.java
@@ -96,7 +96,7 @@
      InheritedDefaultValueProvider {
    // The base path.
    private final ManagedObjectPath path;
    private final ManagedObjectPath<?, ?> path;
@@ -131,7 +131,8 @@
        throw new ManagedObjectNotFoundException();
      }
      ServerManagedObject<?> mo = decode(path, path
      ManagedObjectPath<?, ?> tmp = path;
      ServerManagedObject<?> mo = decode(tmp, tmp
          .getManagedObjectDefinition(), configEntry);
      ManagedObjectDefinition<?, ?> mod = mo
          .getManagedObjectDefinition();
@@ -295,7 +296,7 @@
  // The managed object path identifying this managed object's
  // location.
  private final ManagedObjectPath path;
  private final ManagedObjectPath<?, ?> path;
  // The managed object's properties.
  private final PropertySet properties;
opendj-sdk/opends/tests/unit-tests-testng/src/server/org/opends/server/admin/ManagedObjectPathTest.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
 *
 *
 *      Portions Copyright 2007 Sun Microsystems, Inc.
 */
package org.opends.server.admin;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
import org.opends.server.TestCaseUtils;
import org.opends.server.admin.std.client.ConnectionHandlerCfgClient;
import org.opends.server.admin.std.client.GlobalCfgClient;
import org.opends.server.admin.std.client.LDAPConnectionHandlerCfgClient;
import org.opends.server.admin.std.meta.ConnectionHandlerCfgDefn;
import org.opends.server.admin.std.meta.GlobalCfgDefn;
import org.opends.server.admin.std.meta.LDAPConnectionHandlerCfgDefn;
import org.opends.server.admin.std.meta.MultimasterDomainCfgDefn;
import org.opends.server.admin.std.meta.MultimasterSynchronizationProviderCfgDefn;
import org.opends.server.admin.std.meta.RootCfgDefn;
import org.opends.server.admin.std.server.ConnectionHandlerCfg;
import org.opends.server.admin.std.server.GlobalCfg;
import org.opends.server.admin.std.server.LDAPConnectionHandlerCfg;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
/**
 * ManagedObjectPath test cases.
 */
public class ManagedObjectPathTest {
  /**
   * Sets up tests
   *
   * @throws Exception
   *           If the server could not be initialized.
   */
  @BeforeClass
  public void setUp() throws Exception {
    // This test suite depends on having the schema available, so
    // we'll start the server.
    TestCaseUtils.startServer();
  }
  /**
   * Tests that the empty path is empty.
   */
  @Test
  public void testEmptyPathIsEmpty() {
    ManagedObjectPath<?, ?> path = ManagedObjectPath.emptyPath();
    assertTrue(path.isEmpty());
  }
  /**
   * Tests that the empty path has a size of zero.
   */
  @Test
  public void testEmptyPathHasZeroElements() {
    ManagedObjectPath<?, ?> path = ManagedObjectPath.emptyPath();
    assertEquals(path.size(), 0);
  }
  /**
   * Tests that the empty path has no parent.
   */
  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testEmptyPathHasNoParent() {
    ManagedObjectPath<?, ?> path = ManagedObjectPath.emptyPath();
    path.parent();
  }
  /**
   * Tests that the empty path represents the root configuration.
   */
  @Test
  public void testEmptyPathIsRootConfiguration() {
    ManagedObjectPath<?, ?> path = ManagedObjectPath.emptyPath();
    assertEquals(path.getManagedObjectDefinition(), RootCfgDefn.getInstance());
  }
  /**
   * Tests that the empty path has a string representation of "/".
   */
  @Test
  public void testEmptyPathString() {
    ManagedObjectPath<?, ?> path = ManagedObjectPath.emptyPath();
    assertEquals(path.toString(), "/");
  }
  /**
   * Tests that the empty path can be decoded.
   */
  @Test
  public void testEmptyPathDecode() {
    ManagedObjectPath<?, ?> path = ManagedObjectPath.valueOf("/");
    assertEquals(path, ManagedObjectPath.emptyPath());
  }
  /**
   * Tests singleton child creation.
   */
  @Test
  public void testSingletonChild() {
    ManagedObjectPath<?, ?> path = ManagedObjectPath.emptyPath();
    ManagedObjectPath<GlobalCfgClient, GlobalCfg> child = path
        .child(RootCfgDefn.getInstance()
            .getGlobalConfigurationRelationDefinition());
    assertFalse(child.isEmpty());
    assertEquals(child.size(), 1);
    assertEquals(child.parent(), path);
    assertEquals(child.getManagedObjectDefinition(), GlobalCfgDefn
        .getInstance());
    assertEquals(child.toString(), "/relation=global-configuration");
    assertEquals(child, ManagedObjectPath
        .valueOf("/relation=global-configuration"));
  }
  /**
   * Tests instantiable child creation.
   */
  @Test
  public void testInstantiableChild() {
    ManagedObjectPath<?, ?> path = ManagedObjectPath.emptyPath();
    ManagedObjectPath<ConnectionHandlerCfgClient, ConnectionHandlerCfg> child = path
        .child(RootCfgDefn.getInstance()
            .getConnectionHandlersRelationDefinition(),
            "LDAP connection handler");
    assertFalse(child.isEmpty());
    assertEquals(child.size(), 1);
    assertEquals(child.parent(), path);
    assertEquals(child.getManagedObjectDefinition(), ConnectionHandlerCfgDefn
        .getInstance());
    assertEquals(child.toString(),
        "/relation=connection-handler+name=LDAP connection handler");
    assertEquals(child, ManagedObjectPath
        .valueOf("/relation=connection-handler+name=LDAP connection handler"));
  }
  /**
   * Tests instantiable child creation with specific sub-type.
   */
  @Test
  public void testInstantiableChildWithSubtype() {
    ManagedObjectPath<?, ?> path = ManagedObjectPath.emptyPath();
    ManagedObjectPath<LDAPConnectionHandlerCfgClient, LDAPConnectionHandlerCfg> child = path
        .child(RootCfgDefn.getInstance()
            .getConnectionHandlersRelationDefinition(),
            LDAPConnectionHandlerCfgDefn.getInstance(),
            "LDAP connection handler");
    assertFalse(child.isEmpty());
    assertEquals(child.size(), 1);
    assertEquals(child.parent(), path);
    assertEquals(child.getManagedObjectDefinition(),
        LDAPConnectionHandlerCfgDefn.getInstance());
    assertEquals(
        child.toString(),
        "/relation=connection-handler+type=ldap-connection-handler+name=LDAP connection handler");
    assertEquals(
        child,
        ManagedObjectPath
            .valueOf("/relation=connection-handler+type=ldap-connection-handler+name=LDAP connection handler"));
  }
  /**
   * Tests instantiable child creation with multiple levels.
   */
  @Test
  public void testInstantiableMultipleLevels() {
    ManagedObjectPath<?, ?> root = ManagedObjectPath.emptyPath();
    ManagedObjectPath<?, ?> mmr = root.child(RootCfgDefn.getInstance()
        .getSynchronizationProvidersRelationDefinition(),
        MultimasterSynchronizationProviderCfgDefn.getInstance(), "MMR");
    ManagedObjectPath<?, ?> domain = mmr.child(
        MultimasterSynchronizationProviderCfgDefn.getInstance()
            .getMultimasterDomainsRelationDefinition(), "Domain");
    assertFalse(domain.isEmpty());
    assertEquals(domain.size(), 2);
    assertEquals(domain.parent(), mmr);
    assertEquals(domain.parent(2), root);
    assertEquals(domain.getManagedObjectDefinition(), MultimasterDomainCfgDefn
        .getInstance());
    assertEquals(
        domain.toString(),
        "/relation=synchronization-provider+type=multimaster-synchronization-provider+name=MMR/relation=multimaster-domain+name=Domain");
    assertEquals(
        domain,
        ManagedObjectPath
            .valueOf("/relation=synchronization-provider+type=multimaster-synchronization-provider+name=MMR/relation=multimaster-domain+name=Domain"));
  }
}