/*
|
* 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 legal-notices/CDDLv1_0.txt
|
* or http://forgerock.org/license/CDDLv1.0.html.
|
* 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 legal-notices/CDDLv1_0.txt.
|
* 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-2014 ForgeRock AS
|
*/
|
|
package org.opends.server.admin;
|
|
|
|
import java.util.Collections;
|
import java.util.LinkedList;
|
import java.util.List;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
|
import org.opends.server.admin.std.client.RootCfgClient;
|
import org.opends.server.admin.std.meta.RootCfgDefn;
|
import org.opends.server.admin.std.server.RootCfg;
|
import org.opends.server.core.DirectoryServer;
|
import org.opends.server.types.*;
|
|
|
/**
|
* A path which can be used to determine the location of a managed
|
* object instance.
|
* <p>
|
* A path is made up of zero or more elements each of which represents
|
* a managed object. Managed objects are arranged hierarchically with
|
* the root configuration being the top-most managed object. Elements
|
* are ordered such that the root configuration managed object is the
|
* first element and subsequent elements representing managed objects
|
* further down the hierarchy.
|
* <p>
|
* A path can be encoded into a string representation using the
|
* {@link #toString()} and {@link #toString(StringBuilder)} methods.
|
* Conversely, this string representation can be parsed using the
|
* {@link #valueOf(String)} method.
|
* <p>
|
* The string representation of a managed object path is similar in
|
* principle to a UNIX file-system path and is defined as follows:
|
* <ul>
|
* <li>the root element is represented by the string <code>/</code>
|
* <li>subordinate elements are arranged in big-endian order
|
* separated by a forward slash <code>/</code> character
|
* <li>an element representing a managed object associated with a
|
* one-to-one (singleton) or one-to-zero-or-one (optional) relation
|
* has the form <code>relation=</code><i>relation</i>
|
* <code>[+type=</code><i>definition</i><code>]</code>, where
|
* <i>relation</i> is the name of the relation and <i>definition</i>
|
* is the name of the referenced managed object's definition if
|
* required (usually this is implied by the relation itself)
|
* <li>an element representing a managed object associated with a
|
* one-to-many (instantiable) relation has the form
|
* <code>relation=</code><i>relation</i><code>[+type=</code>
|
* <i>definition</i><code>]</code><code>+name=</code><i>name</i>,
|
* where <i>relation</i> is the name of the relation and
|
* <i>definition</i> is the name of the referenced managed object's
|
* definition if required (usually this is implied by the relation
|
* itself), and <i>name</i> is the name of the managed object
|
* instance
|
* <li>an element representing a managed object associated with a
|
* one-to-many (set) relation has the form
|
* <code>relation=</code><i>relation</i><code>[+type=</code>
|
* <i>definition</i><code>]</code>,
|
* where <i>relation</i> is the name of the relation and
|
* <i>definition</i> is the name of the referenced managed object's
|
* definition.
|
* </ul>
|
* The following path string representation identifies a connection
|
* handler instance (note that the <code>type</code> is not
|
* specified indicating that the path identifies a connection handler
|
* called <i>my handler</i> which can be any type of connection
|
* handler):
|
*
|
* <pre>
|
* /relation=connection-handler+name=my handler
|
* </pre>
|
*
|
* If the identified connection handler must be an LDAP connection
|
* handler then the above path should include the <code>type</code>:
|
*
|
* <pre>
|
* /relation=connection-handler+type=ldap-connection-handler+name=my handler
|
* </pre>
|
*
|
* The final example identifies the global configuration:
|
*
|
* <pre>
|
* /relation=global-configuration
|
* </pre>
|
*
|
* @param <C>
|
* The type of client managed object configuration that this
|
* path references.
|
* @param <S>
|
* The type of server managed object configuration that this
|
* path references.
|
*/
|
public final class ManagedObjectPath<C extends ConfigurationClient,
|
S extends Configuration> {
|
|
/**
|
* A serialize which is used to generate the toDN representation.
|
*/
|
private static final class DNSerializer implements
|
ManagedObjectPathSerializer {
|
|
// The current DN.
|
private DN dn;
|
|
// The LDAP profile.
|
private final LDAPProfile profile;
|
|
|
|
// Create a new DN builder.
|
private DNSerializer() {
|
this.dn = DN.rootDN();
|
this.profile = LDAPProfile.getInstance();
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public <C extends ConfigurationClient, S extends Configuration>
|
void appendManagedObjectPathElement(
|
InstantiableRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d, String name) {
|
// Add the RDN sequence representing the relation.
|
appendManagedObjectPathElement(r);
|
|
// Now add the single RDN representing the named instance.
|
String type = profile.getRelationChildRDNType(r);
|
AttributeType atype = DirectoryServer.getAttributeType(
|
type.toLowerCase(), true);
|
AttributeValue avalue = AttributeValues.create(atype, name);
|
dn = dn.child(RDN.create(atype, avalue));
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public <C extends ConfigurationClient, S extends Configuration>
|
void appendManagedObjectPathElement(
|
SetRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d) {
|
// Add the RDN sequence representing the relation.
|
appendManagedObjectPathElement(r);
|
|
// Now add the single RDN representing the instance.
|
String type = profile.getRelationChildRDNType(r);
|
AttributeType atype = DirectoryServer.getAttributeType(
|
type.toLowerCase(), true);
|
AttributeValue avalue = AttributeValues.create(atype, d.getName());
|
dn = dn.child(RDN.create(atype, avalue));
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public <C extends ConfigurationClient, S extends Configuration>
|
void appendManagedObjectPathElement(
|
OptionalRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d) {
|
// Add the RDN sequence representing the relation.
|
appendManagedObjectPathElement(r);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public <C extends ConfigurationClient, S extends Configuration>
|
void appendManagedObjectPathElement(
|
SingletonRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d) {
|
// Add the RDN sequence representing the relation.
|
appendManagedObjectPathElement(r);
|
}
|
|
|
|
// Appends the RDN sequence representing the provided relation.
|
private void appendManagedObjectPathElement(RelationDefinition<?, ?> r) {
|
// Add the RDN sequence representing the relation.
|
try {
|
DN localName = DN.valueOf(profile.getRelationRDNSequence(r));
|
dn = dn.child(localName);
|
} catch (DirectoryException e) {
|
throw new RuntimeException(e);
|
}
|
}
|
|
|
|
// Gets the serialized DN value.
|
private DN toDN() {
|
return dn;
|
}
|
}
|
|
|
|
/**
|
* Abstract path element.
|
*/
|
private static abstract class Element<C extends ConfigurationClient,
|
S extends Configuration> {
|
|
// The type of managed object referenced by this element.
|
private final AbstractManagedObjectDefinition<C, S> definition;
|
|
|
|
/**
|
* Protected constructor.
|
*
|
* @param definition
|
* The type of managed object referenced by this element.
|
*/
|
protected Element(AbstractManagedObjectDefinition<C, S> definition) {
|
this.definition = definition;
|
}
|
|
|
|
/**
|
* Get the managed object definition associated with this element.
|
*
|
* @return Returns the managed object definition associated with
|
* this element.
|
*/
|
public final AbstractManagedObjectDefinition<C, S>
|
getManagedObjectDefinition() {
|
return definition;
|
}
|
|
|
|
/**
|
* Get the name associated with this element if applicable.
|
*
|
* @return Returns the name associated with this element if
|
* applicable.
|
*/
|
public String getName() {
|
return null;
|
}
|
|
|
|
/**
|
* Get the relation definition associated with this element.
|
*
|
* @return Returns the relation definition associated with this
|
* element.
|
*/
|
public abstract RelationDefinition<? super C, ? super S>
|
getRelationDefinition();
|
|
|
|
/**
|
* Serialize this path element using the provided serialization
|
* strategy.
|
*
|
* @param serializer
|
* The managed object path serialization strategy.
|
*/
|
public abstract void serialize(ManagedObjectPathSerializer serializer);
|
}
|
|
|
|
/**
|
* A path element representing an instantiable managed object.
|
*/
|
private static final class InstantiableElement
|
<C extends ConfigurationClient, S extends Configuration>
|
extends Element<C, S> {
|
|
// Factory method.
|
private static final <C extends ConfigurationClient,
|
S extends Configuration>
|
InstantiableElement<C, S> create(
|
InstantiableRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d, String name) {
|
return new InstantiableElement<C, S>(r, d, name);
|
}
|
|
// The name of the managed object.
|
private final String name;
|
|
// The instantiable relation.
|
private final InstantiableRelationDefinition<? super C, ? super S> r;
|
|
|
|
// Private constructor.
|
private InstantiableElement(
|
InstantiableRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d, String name) {
|
super(d);
|
this.r = r;
|
this.name = name;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public String getName() {
|
return name;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public InstantiableRelationDefinition<? super C, ? super S>
|
getRelationDefinition() {
|
return r;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public void serialize(ManagedObjectPathSerializer serializer) {
|
serializer.appendManagedObjectPathElement(r,
|
getManagedObjectDefinition(), name);
|
}
|
}
|
|
|
|
/**
|
* A path element representing an optional managed object.
|
*/
|
private static final class OptionalElement
|
<C extends ConfigurationClient, S extends Configuration>
|
extends Element<C, S> {
|
|
// Factory method.
|
private static final <C extends ConfigurationClient,
|
S extends Configuration> OptionalElement<C, S> create(
|
OptionalRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d) {
|
return new OptionalElement<C, S>(r, d);
|
}
|
|
// The optional relation.
|
private final OptionalRelationDefinition<? super C, ? super S> r;
|
|
|
|
// Private constructor.
|
private OptionalElement(OptionalRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d) {
|
super(d);
|
this.r = r;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public OptionalRelationDefinition<? super C, ? super S>
|
getRelationDefinition() {
|
return r;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public void serialize(ManagedObjectPathSerializer serializer) {
|
serializer
|
.appendManagedObjectPathElement(r, getManagedObjectDefinition());
|
}
|
}
|
|
|
|
/**
|
* A path element representing an set managed object.
|
*/
|
private static final class SetElement
|
<C extends ConfigurationClient, S extends Configuration>
|
extends Element<C, S> {
|
|
// Factory method.
|
private static final <C extends ConfigurationClient,
|
S extends Configuration>
|
SetElement<C, S> create(
|
SetRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d) {
|
return new SetElement<C, S>(r, d);
|
}
|
|
// The set relation.
|
private final SetRelationDefinition<? super C, ? super S> r;
|
|
|
|
// Private constructor.
|
private SetElement(
|
SetRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d) {
|
super(d);
|
this.r = r;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public SetRelationDefinition<? super C, ? super S>
|
getRelationDefinition() {
|
return r;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public void serialize(ManagedObjectPathSerializer serializer) {
|
serializer.appendManagedObjectPathElement(r,
|
getManagedObjectDefinition());
|
}
|
}
|
|
|
|
/**
|
* A path element representing a singleton managed object.
|
*/
|
private static final class SingletonElement
|
<C extends ConfigurationClient, S extends Configuration>
|
extends Element<C, S> {
|
|
// Factory method.
|
private static final <C extends ConfigurationClient,
|
S extends Configuration> SingletonElement<C, S> create(
|
SingletonRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d) {
|
return new SingletonElement<C, S>(r, d);
|
}
|
|
// The singleton relation.
|
private final SingletonRelationDefinition<? super C, ? super S> r;
|
|
|
|
// Private constructor.
|
private SingletonElement(
|
SingletonRelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d) {
|
super(d);
|
this.r = r;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public SingletonRelationDefinition<? super C, ? super S>
|
getRelationDefinition() {
|
return r;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public void serialize(ManagedObjectPathSerializer serializer) {
|
serializer
|
.appendManagedObjectPathElement(r, getManagedObjectDefinition());
|
}
|
}
|
|
|
|
/**
|
* A serialize which is used to generate the toString
|
* representation.
|
*/
|
private static final class StringSerializer implements
|
ManagedObjectPathSerializer {
|
|
// Serialize to this string builder.
|
private final StringBuilder builder;
|
|
|
|
// Private constructor.
|
private StringSerializer(StringBuilder builder) {
|
this.builder = builder;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
void appendManagedObjectPathElement(
|
InstantiableRelationDefinition<? super M, ? super N> r,
|
AbstractManagedObjectDefinition<M, N> d, String name) {
|
serializeElement(r, d);
|
|
// Be careful to escape any forward slashes in the name.
|
builder.append("+name=");
|
builder.append(name.replace("/", "//"));
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
void appendManagedObjectPathElement(
|
OptionalRelationDefinition<? super M, ? super N> r,
|
AbstractManagedObjectDefinition<M, N> d) {
|
serializeElement(r, d);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
void appendManagedObjectPathElement(
|
SingletonRelationDefinition<? super M, ? super N> r,
|
AbstractManagedObjectDefinition<M, N> d) {
|
serializeElement(r, d);
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
void appendManagedObjectPathElement(
|
SetRelationDefinition<? super M, ? super N> r,
|
AbstractManagedObjectDefinition<M, N> d) {
|
serializeElement(r, d);
|
}
|
|
|
|
// Common element serialization.
|
private <M, N> void serializeElement(RelationDefinition<?, ?> r,
|
AbstractManagedObjectDefinition<?, ?> d) {
|
// Always specify the relation name.
|
builder.append("/relation=");
|
builder.append(r.getName());
|
|
// Only specify the type if it is a sub-type of the relation's
|
// type.
|
if (r.getChildDefinition() != d) {
|
builder.append("+type=");
|
builder.append(d.getName());
|
}
|
}
|
}
|
|
// Single instance of a root path.
|
private static final ManagedObjectPath<RootCfgClient, RootCfg> EMPTY_PATH =
|
new ManagedObjectPath<RootCfgClient, RootCfg>(
|
new LinkedList<Element<?, ?>>(), null, RootCfgDefn.getInstance());
|
|
// A regular expression used to parse path elements.
|
private static final Pattern PE_REGEXP = Pattern
|
.compile("^\\s*relation=\\s*([^+]+)\\s*"
|
+ "(\\+\\s*type=\\s*([^+]+)\\s*)?"
|
+ "(\\+\\s*name=\\s*([^+]+)\\s*)?$");
|
|
|
|
/**
|
* Creates a new managed object path representing the configuration
|
* root.
|
*
|
* @return Returns a new managed object path representing the
|
* configuration root.
|
*/
|
public static ManagedObjectPath<RootCfgClient, RootCfg> emptyPath() {
|
return EMPTY_PATH;
|
}
|
|
|
|
/**
|
* Returns a managed object path holding the value of the specified
|
* string.
|
*
|
* @param s
|
* The string to be parsed.
|
* @return Returns a managed object path holding the value of the
|
* specified string.
|
* @throws IllegalArgumentException
|
* If the string could not be parsed.
|
*/
|
public static ManagedObjectPath<?, ?> valueOf(String s)
|
throws IllegalArgumentException {
|
String ns = s.trim();
|
|
// Check for root special case.
|
if (ns.equals("/")) {
|
return EMPTY_PATH;
|
}
|
|
// Parse the elements.
|
LinkedList<Element<?, ?>> elements = new LinkedList<Element<?, ?>>();
|
Element<?, ?> lastElement = null;
|
AbstractManagedObjectDefinition<?, ?> definition = RootCfgDefn
|
.getInstance();
|
|
if (!ns.startsWith("/")) {
|
throw new IllegalArgumentException("Invalid path \"" + ns
|
+ "\": must begin with a \"/\"");
|
}
|
|
int start = 1;
|
while (true) {
|
// Get the next path element.
|
int end;
|
for (end = start; end < ns.length(); end++) {
|
char c = ns.charAt(end);
|
if (c == '/') {
|
if (end == (ns.length() - 1)) {
|
throw new IllegalArgumentException("Invalid path \"" + ns
|
+ "\": must not end with a trailing \"/\"");
|
}
|
|
if (ns.charAt(end + 1) == '/') {
|
// Found an escaped forward slash.
|
end++;
|
} else {
|
// Found the end of this path element.
|
break;
|
}
|
}
|
}
|
|
// Get the next element.
|
String es = ns.substring(start, end);
|
|
Matcher m = PE_REGEXP.matcher(es);
|
if (!m.matches()) {
|
throw new IllegalArgumentException("Invalid path element \"" + es
|
+ "\" in path \"" + ns + "\"");
|
}
|
|
// Mandatory.
|
String relation = m.group(1);
|
|
// Optional.
|
String type = m.group(3);
|
|
// Mandatory if relation is instantiable.
|
String name = m.group(5);
|
|
// Get the relation definition.
|
RelationDefinition<?, ?> r;
|
try {
|
r = definition.getRelationDefinition(relation);
|
} catch (IllegalArgumentException e) {
|
throw new IllegalArgumentException("Invalid path element \"" + es
|
+ "\" in path \"" + ns + "\": unknown relation \"" + relation
|
+ "\"");
|
}
|
|
// Append the next element.
|
lastElement = createElement(r, ns, es, type, name);
|
elements.add(lastElement);
|
definition = lastElement.getManagedObjectDefinition();
|
|
// Update start to point to the beginning of the next element.
|
if (end < ns.length()) {
|
// Skip to the beginning of the next element
|
start = end + 1;
|
} else {
|
// We reached the end of the string.
|
break;
|
}
|
}
|
|
// Construct the new path.
|
return create(elements, lastElement);
|
}
|
|
|
|
// Factory method required in order to allow generic wild-card
|
// construction of new paths.
|
private static <C extends ConfigurationClient, S extends Configuration>
|
ManagedObjectPath<C, S> create(
|
LinkedList<Element<?, ?>> elements, Element<C, S> lastElement) {
|
return new ManagedObjectPath<C, S>(elements, lastElement
|
.getRelationDefinition(), lastElement.getManagedObjectDefinition());
|
}
|
|
|
|
// Decode an element.
|
private static <C extends ConfigurationClient, S extends Configuration>
|
Element<? extends C, ? extends S> createElement(
|
RelationDefinition<C, S> r, String path, String element, String type,
|
String name) {
|
// First determine the managed object definition.
|
AbstractManagedObjectDefinition<? extends C, ? extends S> d = null;
|
|
if (type != null) {
|
for (AbstractManagedObjectDefinition<? extends C, ? extends S> child : r
|
.getChildDefinition().getAllChildren()) {
|
if (child.getName().equals(type)) {
|
d = child;
|
break;
|
}
|
}
|
|
if (d == null) {
|
throw new IllegalArgumentException("Invalid path element \"" + element
|
+ "\" in path \"" + path + "\": unknown sub-type \"" + type + "\"");
|
}
|
} else {
|
d = r.getChildDefinition();
|
}
|
|
if (r instanceof InstantiableRelationDefinition) {
|
InstantiableRelationDefinition<C, S> ir =
|
(InstantiableRelationDefinition<C, S>) r;
|
|
if (name == null) {
|
throw new IllegalArgumentException("Invalid path element \"" + element
|
+ "\" in path \"" + path
|
+ "\": no instance name for instantiable relation");
|
}
|
|
return InstantiableElement.create(ir, d, name);
|
} else if (r instanceof SetRelationDefinition) {
|
SetRelationDefinition<C, S> ir = (SetRelationDefinition<C, S>) r;
|
|
if (name != null) {
|
throw new IllegalArgumentException("Invalid path element \"" + element
|
+ "\" in path \"" + path
|
+ "\": instance name specified for set relation");
|
}
|
|
return SetElement.create(ir, d);
|
} else if (r instanceof OptionalRelationDefinition) {
|
OptionalRelationDefinition<C, S> or =
|
(OptionalRelationDefinition<C, S>) r;
|
|
if (name != null) {
|
throw new IllegalArgumentException("Invalid path element \"" + element
|
+ "\" in path \"" + path
|
+ "\": instance name specified for optional relation");
|
}
|
|
return OptionalElement.create(or, d);
|
} else if (r instanceof SingletonRelationDefinition) {
|
SingletonRelationDefinition<C, S> sr =
|
(SingletonRelationDefinition<C, S>) r;
|
|
if (name != null) {
|
throw new IllegalArgumentException("Invalid path element \"" + element
|
+ "\" in path \"" + path
|
+ "\": instance name specified for singleton relation");
|
}
|
|
return SingletonElement.create(sr, d);
|
} else {
|
throw new IllegalArgumentException("Invalid path element \"" + element
|
+ "\" in path \"" + path + "\": unsupported relation type");
|
}
|
}
|
|
// The managed object definition in this path.
|
private final AbstractManagedObjectDefinition<C, S> d;
|
|
// The list of path elements in this path.
|
private final List<Element<?, ?>> elements;
|
|
// The last relation definition in this path.
|
private final RelationDefinition<? super C, ? super S> r;
|
|
|
|
// Private constructor.
|
private ManagedObjectPath(LinkedList<Element<?, ?>> elements,
|
RelationDefinition<? super C, ? super S> r,
|
AbstractManagedObjectDefinition<C, S> d) {
|
this.elements = Collections.unmodifiableList(elements);
|
this.r = r;
|
this.d = d;
|
}
|
|
|
|
/**
|
* Creates a new managed object path which has the same structure as
|
* this path except that the final path element is associated with
|
* the specified managed object definition.
|
*
|
* @param <CC>
|
* The type of client managed object configuration that
|
* this path will reference.
|
* @param <SS>
|
* The type of server managed object configuration that
|
* this path will reference.
|
* @param nd
|
* The new managed object definition.
|
* @return Returns a new managed object path which has the same
|
* structure as this path except that the final path element
|
* is associated with the specified managed object
|
* definition.
|
*/
|
@SuppressWarnings("unchecked")
|
public <CC extends C, SS extends S> ManagedObjectPath<CC, SS> asSubType(
|
AbstractManagedObjectDefinition<CC, SS> nd) {
|
if (r instanceof InstantiableRelationDefinition) {
|
InstantiableRelationDefinition<? super C, ? super S> ir =
|
(InstantiableRelationDefinition<? super C, ? super S>) r;
|
if (elements.size() == 0) {
|
return parent().child(ir, nd, "null");
|
} else {
|
return parent().child(ir, nd,
|
elements.get(elements.size() - 1).getName());
|
}
|
} else if (r instanceof SetRelationDefinition) {
|
SetRelationDefinition<? super C, ? super S> sr =
|
(SetRelationDefinition<? super C, ? super S>) r;
|
return parent().child(sr, nd);
|
} else if (r instanceof OptionalRelationDefinition) {
|
OptionalRelationDefinition<? super C, ? super S> or =
|
(OptionalRelationDefinition<? super C, ? super S>) r;
|
return parent().child(or, nd);
|
} else {
|
SingletonRelationDefinition<? super C, ? super S> sr =
|
(SingletonRelationDefinition<? super C, ? super S>) r;
|
return parent().child(sr, nd);
|
}
|
}
|
|
|
|
/**
|
* Creates a new child managed object path beneath the provided
|
* parent path having the specified managed object definition.
|
*
|
* @param <M>
|
* The type of client managed object configuration that the
|
* child path references.
|
* @param <N>
|
* The type of server managed object configuration that the
|
* child path references.
|
* @param r
|
* The instantiable relation referencing the child.
|
* @param d
|
* The managed object definition associated with the child
|
* (must be a sub-type of the relation).
|
* @param name
|
* The relative name of the child managed object.
|
* @return Returns a new child managed object path beneath the
|
* provided parent path.
|
* @throws IllegalArgumentException
|
* If the provided name is empty or blank.
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
ManagedObjectPath<M, N> child(
|
InstantiableRelationDefinition<? super M, ? super N> r,
|
AbstractManagedObjectDefinition<M, N> d, String name)
|
throws IllegalArgumentException {
|
if (name.trim().length() == 0) {
|
throw new IllegalArgumentException(
|
"Empty or blank managed object names are not allowed");
|
}
|
LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
|
elements);
|
celements.add(new InstantiableElement<M, N>(r, d, name));
|
return new ManagedObjectPath<M, N>(celements, r, d);
|
}
|
|
|
|
/**
|
* Creates a new child managed object path beneath the provided
|
* parent path using the relation's child managed object definition.
|
*
|
* @param <M>
|
* The type of client managed object configuration that the
|
* child path references.
|
* @param <N>
|
* The type of server managed object configuration that the
|
* child path references.
|
* @param r
|
* The instantiable relation referencing the child.
|
* @param name
|
* The relative name of the child managed object.
|
* @return Returns a new child managed object path beneath the
|
* provided parent path.
|
* @throws IllegalArgumentException
|
* If the provided name is empty or blank.
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
ManagedObjectPath<M, N> child(
|
InstantiableRelationDefinition<M, N> r, String name)
|
throws IllegalArgumentException {
|
return child(r, r.getChildDefinition(), name);
|
}
|
|
|
|
/**
|
* Creates a new child managed object path beneath the provided
|
* parent path having the specified managed object definition.
|
*
|
* @param <M>
|
* The type of client managed object configuration that the
|
* child path references.
|
* @param <N>
|
* The type of server managed object configuration that the
|
* child path references.
|
* @param r
|
* The optional relation referencing the child.
|
* @param d
|
* The managed object definition associated with the child
|
* (must be a sub-type of the relation).
|
* @return Returns a new child managed object path beneath the
|
* provided parent path.
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
ManagedObjectPath<M, N> child(
|
OptionalRelationDefinition<? super M, ? super N> r,
|
AbstractManagedObjectDefinition<M, N> d) {
|
LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
|
elements);
|
celements.add(new OptionalElement<M, N>(r, d));
|
return new ManagedObjectPath<M, N>(celements, r, d);
|
}
|
|
|
|
/**
|
* Creates a new child managed object path beneath the provided
|
* parent path using the relation's child managed object definition.
|
*
|
* @param <M>
|
* The type of client managed object configuration that the
|
* child path references.
|
* @param <N>
|
* The type of server managed object configuration that the
|
* child path references.
|
* @param r
|
* The optional relation referencing the child.
|
* @return Returns a new child managed object path beneath the
|
* provided parent path.
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
ManagedObjectPath<M, N> child(OptionalRelationDefinition<M, N> r) {
|
return child(r, r.getChildDefinition());
|
}
|
|
|
|
/**
|
* Creates a new child managed object path beneath the provided
|
* parent path having the specified managed object definition.
|
*
|
* @param <M>
|
* The type of client managed object configuration that the
|
* child path references.
|
* @param <N>
|
* The type of server managed object configuration that the
|
* child path references.
|
* @param r
|
* The singleton relation referencing the child.
|
* @param d
|
* The managed object definition associated with the child
|
* (must be a sub-type of the relation).
|
* @return Returns a new child managed object path beneath the
|
* provided parent path.
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
ManagedObjectPath<M, N> child(
|
SingletonRelationDefinition<? super M, ? super N> r,
|
AbstractManagedObjectDefinition<M, N> d) {
|
LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
|
elements);
|
celements.add(new SingletonElement<M, N>(r, d));
|
return new ManagedObjectPath<M, N>(celements, r, d);
|
}
|
|
|
|
/**
|
* Creates a new child managed object path beneath the provided
|
* parent path using the relation's child managed object definition.
|
*
|
* @param <M>
|
* The type of client managed object configuration that the
|
* child path references.
|
* @param <N>
|
* The type of server managed object configuration that the
|
* child path references.
|
* @param r
|
* The singleton relation referencing the child.
|
* @return Returns a new child managed object path beneath the
|
* provided parent path.
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
ManagedObjectPath<M, N> child(SingletonRelationDefinition<M, N> r) {
|
return child(r, r.getChildDefinition());
|
}
|
|
|
|
/**
|
* Creates a new child managed object path beneath the provided
|
* parent path having the specified managed object definition.
|
*
|
* @param <M>
|
* The type of client managed object configuration that the
|
* child path references.
|
* @param <N>
|
* The type of server managed object configuration that the
|
* child path references.
|
* @param r
|
* The set relation referencing the child.
|
* @param d
|
* The managed object definition associated with the child
|
* (must be a sub-type of the relation).
|
* @return Returns a new child managed object path beneath the
|
* provided parent path.
|
* @throws IllegalArgumentException
|
* If the provided name is empty or blank.
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
ManagedObjectPath<M, N> child(
|
SetRelationDefinition<? super M, ? super N> r,
|
AbstractManagedObjectDefinition<M, N> d)
|
throws IllegalArgumentException {
|
LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
|
elements);
|
celements.add(new SetElement<M, N>(r, d));
|
return new ManagedObjectPath<M, N>(celements, r, d);
|
}
|
|
|
|
/**
|
* Creates a new child managed object path beneath the provided parent
|
* path having the managed object definition indicated by
|
* <code>name</code>.
|
*
|
* @param <M>
|
* The type of client managed object configuration that the
|
* path references.
|
* @param <N>
|
* The type of server managed object configuration that the
|
* path references.
|
* @param r
|
* The set relation referencing the child.
|
* @param name
|
* The name of the managed object definition associated with
|
* the child (must be a sub-type of the relation).
|
* @return Returns a new child managed object path beneath the
|
* provided parent path.
|
* @throws IllegalArgumentException
|
* If the provided name is empty or blank or specifies a
|
* managed object definition which is not a sub-type of the
|
* relation's child definition.
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
ManagedObjectPath<? extends M, ? extends N> child(
|
SetRelationDefinition<M, N> r,
|
String name)
|
throws IllegalArgumentException {
|
AbstractManagedObjectDefinition<M, N> d = r.getChildDefinition();
|
return child(r, d.getChild(name));
|
}
|
|
|
|
/**
|
* Creates a new child managed object path beneath the provided
|
* parent path using the relation's child managed object definition.
|
*
|
* @param <M>
|
* The type of client managed object configuration that the
|
* child path references.
|
* @param <N>
|
* The type of server managed object configuration that the
|
* child path references.
|
* @param r
|
* The set relation referencing the child.
|
* @return Returns a new child managed object path beneath the
|
* provided parent path.
|
* @throws IllegalArgumentException
|
* If the provided name is empty or blank.
|
*/
|
public <M extends ConfigurationClient, N extends Configuration>
|
ManagedObjectPath<M, N> child(
|
SetRelationDefinition<M, N> r)
|
throws IllegalArgumentException {
|
return child(r, r.getChildDefinition());
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public boolean equals(Object obj) {
|
if (obj == this) {
|
return true;
|
} else if (obj instanceof ManagedObjectPath) {
|
ManagedObjectPath<?, ?> other = (ManagedObjectPath<?, ?>) obj;
|
return toString().equals(other.toString());
|
} else {
|
return false;
|
}
|
}
|
|
|
|
/**
|
* Get the definition of the managed object referred to by this
|
* path.
|
* <p>
|
* When the path is empty, the {@link RootCfgDefn} is returned.
|
*
|
* @return Returns the definition of the managed object referred to
|
* by this path, or the {@link RootCfgDefn} if the path is
|
* empty.
|
*/
|
public AbstractManagedObjectDefinition<C, S> getManagedObjectDefinition() {
|
return d;
|
}
|
|
|
|
/**
|
* Get the name of the managed object referred to by this path if
|
* applicable.
|
* <p>
|
* If there path does not refer to an instantiable managed object
|
* <code>null</code> is returned.
|
*
|
* @return Returns the name of the managed object referred to by
|
* this path, or <code>null</code> if the managed object
|
* does not have a name.
|
*/
|
public String getName() {
|
if (elements.isEmpty()) {
|
return null;
|
} else {
|
return elements.get(elements.size() - 1).getName();
|
}
|
}
|
|
|
|
/**
|
* Get the relation definition of the managed object referred to by
|
* this path.
|
* <p>
|
* When the path is empty, the <code>null</code> is returned.
|
*
|
* @return Returns the relation definition of the managed object
|
* referred to by this path, or the <code>null</code> if
|
* the path is empty.
|
*/
|
public RelationDefinition<? super C, ? super S> getRelationDefinition() {
|
return r;
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public int hashCode() {
|
return toString().hashCode();
|
}
|
|
|
|
/**
|
* Determine whether or not this path contains any path elements.
|
*
|
* @return Returns <code>true</code> if this path does not contain
|
* any path elements.
|
*/
|
public boolean isEmpty() {
|
return elements.isEmpty();
|
}
|
|
|
|
/**
|
* Determines whether this managed object path references the same
|
* location as the provided managed object path.
|
* <p>
|
* This method differs from <code>equals</code> in that it ignores
|
* sub-type definitions.
|
*
|
* @param other
|
* The managed object path to be compared.
|
* @return Returns <code>true</code> if this managed object path
|
* references the same location as the provided managed
|
* object path.
|
*/
|
public boolean matches(ManagedObjectPath<?, ?> other) {
|
DN thisDN = toDN();
|
DN otherDN = other.toDN();
|
return thisDN.equals(otherDN);
|
}
|
|
|
|
/**
|
* Creates a new parent managed object path representing the
|
* immediate parent of this path. This method is a short-hand for
|
* <code>parent(1)</code>.
|
*
|
* @return Returns a new parent managed object path representing the
|
* immediate parent of this path.
|
* @throws IllegalArgumentException
|
* If this path does not have a parent (i.e. it is the
|
* empty path).
|
*/
|
public ManagedObjectPath<?, ?> parent() throws IllegalArgumentException {
|
return parent(1);
|
}
|
|
|
|
/**
|
* Creates a new parent managed object path the specified number of
|
* path elements above this path.
|
*
|
* @param offset
|
* The number of path elements (0 - means no offset, 1
|
* means the parent, and 2 means the grand-parent).
|
* @return Returns a new parent managed object path the specified
|
* number of path elements above this path.
|
* @throws IllegalArgumentException
|
* If the offset is less than 0, or greater than the
|
* number of path elements in this path.
|
*/
|
public ManagedObjectPath<?, ?> parent(int offset)
|
throws IllegalArgumentException {
|
if (offset < 0) {
|
throw new IllegalArgumentException("Negative offset");
|
}
|
|
if (offset > elements.size()) {
|
throw new IllegalArgumentException(
|
"Offset is greater than the number of path elements");
|
}
|
|
// An offset of 0 leaves the path unchanged.
|
if (offset == 0) {
|
return this;
|
}
|
|
// Return the empty path if the parent has zero elements.
|
if (elements.size() == offset) {
|
return emptyPath();
|
}
|
|
LinkedList<Element<?, ?>> celements = new LinkedList<Element<?, ?>>(
|
elements.subList(0, elements.size() - offset));
|
return create(celements, celements.getLast());
|
}
|
|
|
|
/**
|
* Creates a new managed object path which has the same structure as
|
* this path except that the final path element is renamed. The
|
* final path element must comprise of an instantiable relation.
|
*
|
* @param newName
|
* The new name of the final path element.
|
* @return Returns a new managed object path which has the same
|
* structure as this path except that the final path element
|
* is renamed.
|
* @throws IllegalStateException
|
* If this managed object path is empty or if its final
|
* path element does not comprise of an instantiable
|
* relation.
|
*/
|
@SuppressWarnings("unchecked")
|
public ManagedObjectPath<C, S> rename(String newName)
|
throws IllegalStateException {
|
if (elements.size() == 0) {
|
throw new IllegalStateException("Cannot rename an empty path");
|
}
|
|
if (r instanceof InstantiableRelationDefinition) {
|
InstantiableRelationDefinition<? super C, ? super S> ir =
|
(InstantiableRelationDefinition<? super C, ? super S>) r;
|
return parent().child(ir, d, newName);
|
} else {
|
throw new IllegalStateException("Not an instantiable relation");
|
}
|
}
|
|
|
|
/**
|
* Serialize this managed object path using the provided
|
* serialization strategy.
|
* <p>
|
* The path elements will be passed to the serializer in big-endian
|
* order: starting from the root element and proceeding down to the
|
* leaf.
|
*
|
* @param serializer
|
* The managed object path serialization strategy.
|
*/
|
public void serialize(ManagedObjectPathSerializer serializer) {
|
for (Element<?, ?> element : elements) {
|
element.serialize(serializer);
|
}
|
}
|
|
|
|
/**
|
* Get the number of path elements in this managed object path.
|
*
|
* @return Returns the number of path elements (0 - means no offset,
|
* 1 means the parent, and 2 means the grand-parent).
|
*/
|
public int size() {
|
return elements.size();
|
}
|
|
|
|
/**
|
* Creates a DN representation of this managed object path.
|
*
|
* @return Returns a DN representation of this managed object path.
|
*/
|
public DN toDN() {
|
// Use a simple serializer to create the contents.
|
DNSerializer serializer = new DNSerializer();
|
serialize(serializer);
|
return serializer.toDN();
|
}
|
|
|
|
/**
|
* {@inheritDoc}
|
*/
|
@Override
|
public String toString() {
|
StringBuilder builder = new StringBuilder();
|
toString(builder);
|
return builder.toString();
|
}
|
|
|
|
/**
|
* Appends a string representation of this managed object path to
|
* the provided string builder.
|
*
|
* @param builder
|
* Append the string representation to this builder.
|
* @see #toString()
|
*/
|
public void toString(final StringBuilder builder) {
|
if (isEmpty()) {
|
// Special treatment of root configuration paths.
|
builder.append('/');
|
} else {
|
// Use a simple serializer to create the contents.
|
ManagedObjectPathSerializer serializer = new StringSerializer(builder);
|
serialize(serializer);
|
}
|
}
|
|
}
|