/*
* 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.
*
* 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.
*
* 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.
*
* The string representation of a managed object path is similar in
* principle to a UNIX file-system path and is defined as follows:
*
* - the root element is represented by the string
/
* - subordinate elements are arranged in big-endian order
* separated by a forward slash
/ character
* - an element representing a managed object associated with a
* one-to-one (singleton) or one-to-zero-or-one (optional) relation
* has the form
relation=relation
* [+type=definition], where
* relation is the name of the relation and definition
* is the name of the referenced managed object's definition if
* required (usually this is implied by the relation itself)
* - an element representing a managed object associated with a
* one-to-many (instantiable) relation has the form
*
relation=relation[+type=
* definition]+name=name,
* where relation is the name of the relation and
* definition is the name of the referenced managed object's
* definition if required (usually this is implied by the relation
* itself), and name is the name of the managed object
* instance
* - an element representing a managed object associated with a
* one-to-many (set) relation has the form
*
relation=relation[+type=
* definition],
* where relation is the name of the relation and
* definition is the name of the referenced managed object's
* definition.
*
* The following path string representation identifies a connection
* handler instance (note that the type is not
* specified indicating that the path identifies a connection handler
* called my handler which can be any type of connection
* handler):
*
*
* /relation=connection-handler+name=my handler
*
*
* If the identified connection handler must be an LDAP connection
* handler then the above path should include the type:
*
*
* /relation=connection-handler+type=ldap-connection-handler+name=my handler
*
*
* The final example identifies the global configuration:
*
*
* /relation=global-configuration
*
*
* @param
* The type of client managed object configuration that this
* path references.
* @param
* The type of server managed object configuration that this
* path references.
*/
public final class ManagedObjectPath {
/**
* 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
void appendManagedObjectPathElement(
InstantiableRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition 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
void appendManagedObjectPathElement(
SetRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition 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
void appendManagedObjectPathElement(
OptionalRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition d) {
// Add the RDN sequence representing the relation.
appendManagedObjectPathElement(r);
}
/**
* {@inheritDoc}
*/
public
void appendManagedObjectPathElement(
SingletonRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition 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 {
// The type of managed object referenced by this element.
private final AbstractManagedObjectDefinition definition;
/**
* Protected constructor.
*
* @param definition
* The type of managed object referenced by this element.
*/
protected Element(AbstractManagedObjectDefinition 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
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
extends Element {
// Factory method.
private static final
InstantiableElement create(
InstantiableRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition d, String name) {
return new InstantiableElement(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 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
extends Element {
// Factory method.
private static final OptionalElement create(
OptionalRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition d) {
return new OptionalElement(r, d);
}
// The optional relation.
private final OptionalRelationDefinition super C, ? super S> r;
// Private constructor.
private OptionalElement(OptionalRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition 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
extends Element {
// Factory method.
private static final
SetElement create(
SetRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition d) {
return new SetElement(r, d);
}
// The set relation.
private final SetRelationDefinition super C, ? super S> r;
// Private constructor.
private SetElement(
SetRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition 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
extends Element {
// Factory method.
private static final SingletonElement create(
SingletonRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition d) {
return new SingletonElement(r, d);
}
// The singleton relation.
private final SingletonRelationDefinition super C, ? super S> r;
// Private constructor.
private SingletonElement(
SingletonRelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition 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
void appendManagedObjectPathElement(
InstantiableRelationDefinition super M, ? super N> r,
AbstractManagedObjectDefinition 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
void appendManagedObjectPathElement(
OptionalRelationDefinition super M, ? super N> r,
AbstractManagedObjectDefinition d) {
serializeElement(r, d);
}
/**
* {@inheritDoc}
*/
public
void appendManagedObjectPathElement(
SingletonRelationDefinition super M, ? super N> r,
AbstractManagedObjectDefinition d) {
serializeElement(r, d);
}
/**
* {@inheritDoc}
*/
public
void appendManagedObjectPathElement(
SetRelationDefinition super M, ? super N> r,
AbstractManagedObjectDefinition d) {
serializeElement(r, d);
}
// Common element serialization.
private 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>(), 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 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> elements = new LinkedList>();
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
ManagedObjectPath create(
LinkedList> elements, Element lastElement) {
return new ManagedObjectPath(elements, lastElement
.getRelationDefinition(), lastElement.getManagedObjectDefinition());
}
// Decode an element.
private static
Element extends C, ? extends S> createElement(
RelationDefinition 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 ir =
(InstantiableRelationDefinition) 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 ir = (SetRelationDefinition) 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 or =
(OptionalRelationDefinition) 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 sr =
(SingletonRelationDefinition) 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 d;
// The list of path elements in this path.
private final List> elements;
// The last relation definition in this path.
private final RelationDefinition super C, ? super S> r;
// Private constructor.
private ManagedObjectPath(LinkedList> elements,
RelationDefinition super C, ? super S> r,
AbstractManagedObjectDefinition 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
* The type of client managed object configuration that
* this path will reference.
* @param
* 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 ManagedObjectPath asSubType(
AbstractManagedObjectDefinition 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
* The type of client managed object configuration that the
* child path references.
* @param
* 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
ManagedObjectPath child(
InstantiableRelationDefinition super M, ? super N> r,
AbstractManagedObjectDefinition d, String name)
throws IllegalArgumentException {
if (name.trim().length() == 0) {
throw new IllegalArgumentException(
"Empty or blank managed object names are not allowed");
}
LinkedList> celements = new LinkedList>(
elements);
celements.add(new InstantiableElement(r, d, name));
return new ManagedObjectPath(celements, r, d);
}
/**
* Creates a new child managed object path beneath the provided
* parent path using the relation's child managed object definition.
*
* @param
* The type of client managed object configuration that the
* child path references.
* @param
* 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
ManagedObjectPath child(
InstantiableRelationDefinition 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
* The type of client managed object configuration that the
* child path references.
* @param
* 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
ManagedObjectPath child(
OptionalRelationDefinition super M, ? super N> r,
AbstractManagedObjectDefinition d) {
LinkedList> celements = new LinkedList>(
elements);
celements.add(new OptionalElement(r, d));
return new ManagedObjectPath(celements, r, d);
}
/**
* Creates a new child managed object path beneath the provided
* parent path using the relation's child managed object definition.
*
* @param
* The type of client managed object configuration that the
* child path references.
* @param
* 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) {
return child(r, r.getChildDefinition());
}
/**
* Creates a new child managed object path beneath the provided
* parent path having the specified managed object definition.
*
* @param
* The type of client managed object configuration that the
* child path references.
* @param
* 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
ManagedObjectPath child(
SingletonRelationDefinition super M, ? super N> r,
AbstractManagedObjectDefinition d) {
LinkedList> celements = new LinkedList>(
elements);
celements.add(new SingletonElement(r, d));
return new ManagedObjectPath(celements, r, d);
}
/**
* Creates a new child managed object path beneath the provided
* parent path using the relation's child managed object definition.
*
* @param
* The type of client managed object configuration that the
* child path references.
* @param
* 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) {
return child(r, r.getChildDefinition());
}
/**
* Creates a new child managed object path beneath the provided
* parent path having the specified managed object definition.
*
* @param
* The type of client managed object configuration that the
* child path references.
* @param
* 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
ManagedObjectPath child(
SetRelationDefinition super M, ? super N> r,
AbstractManagedObjectDefinition d)
throws IllegalArgumentException {
LinkedList> celements = new LinkedList>(
elements);
celements.add(new SetElement(r, d));
return new ManagedObjectPath(celements, r, d);
}
/**
* Creates a new child managed object path beneath the provided parent
* path having the managed object definition indicated by
* name.
*
* @param
* The type of client managed object configuration that the
* path references.
* @param
* 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
ManagedObjectPath extends M, ? extends N> child(
SetRelationDefinition r,
String name)
throws IllegalArgumentException {
AbstractManagedObjectDefinition 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
* The type of client managed object configuration that the
* child path references.
* @param
* 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
ManagedObjectPath child(
SetRelationDefinition 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.
*
* 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 getManagedObjectDefinition() {
return d;
}
/**
* Get the name of the managed object referred to by this path if
* applicable.
*
* If there path does not refer to an instantiable managed object
* null is returned.
*
* @return Returns the name of the managed object referred to by
* this path, or null 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.
*
* When the path is empty, the null is returned.
*
* @return Returns the relation definition of the managed object
* referred to by this path, or the null 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 true 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.
*
* This method differs from equals in that it ignores
* sub-type definitions.
*
* @param other
* The managed object path to be compared.
* @return Returns true 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
* parent(1).
*
* @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> celements = new LinkedList>(
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 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.
*
* 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);
}
}
}