001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2007-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2015 ForgeRock AS.
026 */
027package org.forgerock.opendj.config;
028
029import java.util.ArrayList;
030import java.util.Collection;
031import java.util.Collections;
032import java.util.EnumSet;
033import java.util.HashMap;
034import java.util.HashSet;
035import java.util.LinkedList;
036import java.util.List;
037import java.util.Locale;
038import java.util.Map;
039import java.util.MissingResourceException;
040import java.util.Set;
041import java.util.Vector;
042
043import org.forgerock.i18n.LocalizableMessage;
044import org.forgerock.opendj.config.DefinitionDecodingException.Reason;
045
046/**
047 * Defines the structure of an abstract managed object. Abstract managed objects
048 * cannot be instantiated.
049 * <p>
050 * Applications can query a managed object definition in order to determine the
051 * overall configuration model of an application.
052 *
053 * @param <C>
054 *            The type of client managed object configuration that this
055 *            definition represents.
056 * @param <S>
057 *            The type of server managed object configuration that this
058 *            definition represents.
059 */
060public abstract class AbstractManagedObjectDefinition<C extends ConfigurationClient, S extends Configuration> {
061
062    /** The name of the definition. */
063    private final String name;
064
065    /** The parent managed object definition if applicable. */
066    private final AbstractManagedObjectDefinition<? super C, ? super S> parent;
067
068    /** The set of constraints associated with this managed object definition. */
069    private final Collection<Constraint> constraints = new LinkedList<>();
070    /** The set of property definitions applicable to this managed object definition. */
071    private final Map<String, PropertyDefinition<?>> propertyDefinitions = new HashMap<>();
072    /** The set of relation definitions applicable to this managed object definition. */
073    private final Map<String, RelationDefinition<?, ?>> relationDefinitions = new HashMap<>();
074    /** The set of relation definitions directly referencing this managed object definition. */
075    private final Set<RelationDefinition<C, S>> reverseRelationDefinitions = new HashSet<>();
076
077    /**
078     * The set of all property definitions associated with this managed
079     * object definition including inherited property definitions.
080     */
081    private final Map<String, PropertyDefinition<?>> allPropertyDefinitions = new HashMap<>();
082    /**
083     * The set of all relation definitions associated with this managed
084     * object definition including inherited relation definitions.
085     */
086    private final Map<String, RelationDefinition<?, ?>> allRelationDefinitions = new HashMap<>();
087
088    /** The set of aggregation property definitions applicable to this managed object definition. */
089    private final Map<String, AggregationPropertyDefinition<?, ?>> aggregationPropertyDefinitions = new HashMap<>();
090
091    /** The set of aggregation property definitions directly referencing this managed object definition. */
092    private final Vector<AggregationPropertyDefinition<?, ?>> reverseAggregationPropertyDefinitions = new Vector<>();
093
094    /**
095     * The set of all aggregation property definitions associated with this
096     * managed object definition including inherited relation definitions.
097     */
098    private final Map<String, AggregationPropertyDefinition<?, ?>> allAggregationPropertyDefinitions = new HashMap<>();
099
100    /** The set of tags associated with this managed object. */
101    private final Set<Tag> allTags = new HashSet<>();
102
103    /** Options applicable to this definition. */
104    private final Set<ManagedObjectOption> options = EnumSet.noneOf(ManagedObjectOption.class);
105
106    /** The set of managed object definitions which inherit from this definition. */
107    private final Map<String, AbstractManagedObjectDefinition<? extends C, ? extends S>> children = new HashMap<>();
108
109    /**
110     * Create a new abstract managed object definition.
111     *
112     * @param name
113     *            The name of the definition.
114     * @param parent
115     *            The parent definition, or <code>null</code> if there is no
116     *            parent (only the {@link TopCfgDefn} should have a
117     *            <code>null</code> parent, unless the definition is being used
118     *            for testing).
119     */
120    protected AbstractManagedObjectDefinition(String name,
121        AbstractManagedObjectDefinition<? super C, ? super S> parent) {
122        this.name = name;
123        this.parent = parent;
124
125        // If we have a parent definition then inherit its features.
126        if (parent != null) {
127            registerInParent();
128
129            for (PropertyDefinition<?> pd : parent.getAllPropertyDefinitions()) {
130                allPropertyDefinitions.put(pd.getName(), pd);
131            }
132
133            for (RelationDefinition<?, ?> rd : parent.getAllRelationDefinitions()) {
134                allRelationDefinitions.put(rd.getName(), rd);
135            }
136
137            for (AggregationPropertyDefinition<?, ?> apd : parent.getAllAggregationPropertyDefinitions()) {
138                allAggregationPropertyDefinitions.put(apd.getName(), apd);
139            }
140            // Tag inheritance is performed during preprocessing.
141        }
142    }
143
144    /**
145     * Get all the child managed object definitions which inherit from this
146     * managed object definition.
147     *
148     * @return Returns an unmodifiable collection containing all the subordinate
149     *         managed object definitions which inherit from this managed object
150     *         definition.
151     */
152    public final Collection<AbstractManagedObjectDefinition<? extends C, ? extends S>> getAllChildren() {
153        List<AbstractManagedObjectDefinition<? extends C, ? extends S>> list = new ArrayList<>(children.values());
154
155        for (AbstractManagedObjectDefinition<? extends C, ? extends S> child : children.values()) {
156            list.addAll(child.getAllChildren());
157        }
158
159        return Collections.unmodifiableCollection(list);
160    }
161
162    /**
163     * Get all the constraints associated with this type of managed object. The
164     * returned collection will contain inherited constraints.
165     *
166     * @return Returns a collection containing all the constraints associated
167     *         with this type of managed object. The caller is free to modify
168     *         the collection if required.
169     */
170    public final Collection<Constraint> getAllConstraints() {
171        // This method does not used a cached set of constraints because
172        // constraints may be updated after child definitions have been defined.
173        List<Constraint> allConstraints = new LinkedList<>();
174
175        if (parent != null) {
176            allConstraints.addAll(parent.getAllConstraints());
177        }
178        allConstraints.addAll(constraints);
179
180        return allConstraints;
181    }
182
183    /**
184     * Get all the property definitions associated with this type of managed
185     * object. The returned collection will contain inherited property
186     * definitions.
187     *
188     * @return Returns an unmodifiable collection containing all the property
189     *         definitions associated with this type of managed object.
190     */
191    public final Collection<PropertyDefinition<?>> getAllPropertyDefinitions() {
192        return Collections.unmodifiableCollection(allPropertyDefinitions.values());
193    }
194
195    /**
196     * Get all the relation definitions associated with this type of managed
197     * object. The returned collection will contain inherited relation
198     * definitions.
199     *
200     * @return Returns an unmodifiable collection containing all the relation
201     *         definitions associated with this type of managed object.
202     */
203    public final Collection<RelationDefinition<?, ?>> getAllRelationDefinitions() {
204        return Collections.unmodifiableCollection(allRelationDefinitions.values());
205    }
206
207    /**
208     * Get all the relation definitions which refer to this managed object
209     * definition. The returned collection will contain relation definitions
210     * which refer to parents of this managed object definition.
211     *
212     * @return Returns a collection containing all the relation definitions
213     *         which refer to this managed object definition. The caller is free
214     *         to modify the collection if required.
215     */
216    public final Collection<RelationDefinition<? super C, ? super S>> getAllReverseRelationDefinitions() {
217        // This method does not used a cached set of relations because
218        // relations may be updated after child definitions have been defined.
219        List<RelationDefinition<? super C, ? super S>> rdlist = new LinkedList<>();
220
221        if (parent != null) {
222            rdlist.addAll(parent.getAllReverseRelationDefinitions());
223        }
224        rdlist.addAll(reverseRelationDefinitions);
225
226        return rdlist;
227    }
228
229    /**
230     * Get all the aggregation property definitions associated with this type of
231     * managed object. The returned collection will contain inherited
232     * aggregation property definitions.
233     *
234     * @return Returns an unmodifiable collection containing all the aggregation
235     *         property definitions associated with this type of managed object.
236     */
237    public final Collection<AggregationPropertyDefinition<?, ?>> getAllAggregationPropertyDefinitions() {
238        return Collections.unmodifiableCollection(allAggregationPropertyDefinitions.values());
239    }
240
241    /**
242     * Get all the aggregation property definitions which refer to this managed
243     * object definition. The returned collection will contain aggregation
244     * property definitions which refer to parents of this managed object
245     * definition.
246     *
247     * @return Returns a collection containing all the aggregation property
248     *         definitions which refer to this managed object definition. The
249     *         caller is free to modify the collection if required.
250     */
251    public final Collection<AggregationPropertyDefinition<?, ?>> getAllReverseAggregationPropertyDefinitions() {
252        // This method does not used a cached set of aggregation properties because
253        // aggregation properties may be updated after child definitions have been defined.
254        List<AggregationPropertyDefinition<?, ?>> apdlist = new LinkedList<>();
255
256        if (parent != null) {
257            apdlist.addAll(parent.getAllReverseAggregationPropertyDefinitions());
258        }
259        apdlist.addAll(reverseAggregationPropertyDefinitions);
260
261        return apdlist;
262    }
263
264    /**
265     * Get all the tags associated with this type of managed object. The
266     * returned collection will contain inherited tags.
267     *
268     * @return Returns an unmodifiable collection containing all the tags
269     *         associated with this type of managed object.
270     */
271    public final Collection<Tag> getAllTags() {
272        return Collections.unmodifiableCollection(allTags);
273    }
274
275    /**
276     * Get the named child managed object definition which inherits from this
277     * managed object definition. This method will recursively search down
278     * through the inheritance hierarchy.
279     *
280     * @param name
281     *            The name of the managed object definition sub-type.
282     * @return Returns the named child managed object definition which inherits
283     *         from this managed object definition.
284     * @throws IllegalArgumentException
285     *             If the specified managed object definition name was null or
286     *             empty or if the requested subordinate managed object
287     *             definition was not found.
288     */
289    public final AbstractManagedObjectDefinition<? extends C, ? extends S> getChild(String name) {
290        if (name == null || name.length() == 0) {
291            throw new IllegalArgumentException("null or empty managed object name");
292        }
293
294        AbstractManagedObjectDefinition<? extends C, ? extends S> d = children.get(name);
295
296        if (d == null) {
297            // Recursively search.
298            for (AbstractManagedObjectDefinition<? extends C, ? extends S> child : children.values()) {
299                try {
300                    d = child.getChild(name);
301                    break;
302                } catch (IllegalArgumentException e) {
303                    // Try the next child.
304                }
305            }
306        }
307
308        if (d == null) {
309            throw new IllegalArgumentException("child managed object definition \"" + name + "\" not found");
310        }
311
312        return d;
313    }
314
315    /**
316     * Get the child managed object definitions which inherit directly from this
317     * managed object definition.
318     *
319     * @return Returns an unmodifiable collection containing the subordinate
320     *         managed object definitions which inherit directly from this
321     *         managed object definition.
322     */
323    public final Collection<AbstractManagedObjectDefinition<? extends C, ? extends S>> getChildren() {
324        return Collections.unmodifiableCollection(children.values());
325    }
326
327    /**
328     * Get the constraints defined by this managed object definition. The
329     * returned collection will not contain inherited constraints.
330     *
331     * @return Returns an unmodifiable collection containing the constraints
332     *         defined by this managed object definition.
333     */
334    public final Collection<Constraint> getConstraints() {
335        return Collections.unmodifiableCollection(constraints);
336    }
337
338    /**
339     * Gets the optional description of this managed object definition in the
340     * default locale.
341     *
342     * @return Returns the description of this managed object definition in the
343     *         default locale, or <code>null</code> if there is no description.
344     * @throws UnsupportedOperationException
345     *             If this managed object definition is the {@link TopCfgDefn}.
346     */
347    public final LocalizableMessage getDescription() {
348        return getDescription(Locale.getDefault());
349    }
350
351    /**
352     * Gets the optional description of this managed object definition in the
353     * specified locale.
354     *
355     * @param locale
356     *            The locale.
357     * @return Returns the description of this managed object definition in the
358     *         specified locale, or <code>null</code> if there is no
359     *         description.
360     * @throws UnsupportedOperationException
361     *             If this managed object definition is the {@link TopCfgDefn}.
362     */
363    public final LocalizableMessage getDescription(Locale locale) {
364        try {
365            return ManagedObjectDefinitionI18NResource.getInstance().getMessage(this, "description", locale);
366        } catch (MissingResourceException e) {
367            return null;
368        }
369    }
370
371    /**
372     * Get the name of the definition.
373     *
374     * @return Returns the name of the definition.
375     */
376    public final String getName() {
377        return name;
378    }
379
380    /**
381     * Get the parent managed object definition, if applicable.
382     *
383     * @return Returns the parent of this managed object definition, or
384     *         <code>null</code> if this definition is the {@link TopCfgDefn}.
385     */
386    public final AbstractManagedObjectDefinition<? super C, ? super S> getParent() {
387        return parent;
388    }
389
390    /**
391     * Get the specified property definition associated with this type of
392     * managed object. The search will include any inherited property
393     * definitions.
394     *
395     * @param name
396     *            The name of the property definition to be retrieved.
397     * @return Returns the specified property definition associated with this
398     *         type of managed object.
399     * @throws IllegalArgumentException
400     *             If the specified property name was null or empty or if the
401     *             requested property definition was not found.
402     */
403    public final PropertyDefinition<?> getPropertyDefinition(String name) {
404        if (name == null || name.length() == 0) {
405            throw new IllegalArgumentException("null or empty property name");
406        }
407
408        PropertyDefinition<?> d = allPropertyDefinitions.get(name);
409        if (d == null) {
410            throw new IllegalArgumentException("property definition \"" + name + "\" not found");
411        }
412
413        return d;
414    }
415
416    /**
417     * Get the property definitions defined by this managed object definition.
418     * The returned collection will not contain inherited property definitions.
419     *
420     * @return Returns an unmodifiable collection containing the property
421     *         definitions defined by this managed object definition.
422     */
423    public final Collection<PropertyDefinition<?>> getPropertyDefinitions() {
424        return Collections.unmodifiableCollection(propertyDefinitions.values());
425    }
426
427    /**
428     * Get the specified relation definition associated with this type of
429     * managed object.The search will include any inherited relation
430     * definitions.
431     *
432     * @param name
433     *            The name of the relation definition to be retrieved.
434     * @return Returns the specified relation definition associated with this
435     *         type of managed object.
436     * @throws IllegalArgumentException
437     *             If the specified relation name was null or empty or if the
438     *             requested relation definition was not found.
439     */
440    public final RelationDefinition<?, ?> getRelationDefinition(String name) {
441        if (name == null || name.length() == 0) {
442            throw new IllegalArgumentException("null or empty relation name");
443        }
444
445        RelationDefinition<?, ?> d = allRelationDefinitions.get(name);
446        if (d == null) {
447            throw new IllegalArgumentException("relation definition \"" + name + "\" not found");
448        }
449
450        return d;
451    }
452
453    /**
454     * Get the relation definitions defined by this managed object definition.
455     * The returned collection will not contain inherited relation definitions.
456     *
457     * @return Returns an unmodifiable collection containing the relation
458     *         definitions defined by this managed object definition.
459     */
460    public final Collection<RelationDefinition<?, ?>> getRelationDefinitions() {
461        return Collections.unmodifiableCollection(relationDefinitions.values());
462    }
463
464    /**
465     * Get the relation definitions which refer directly to this managed object
466     * definition. The returned collection will not contain relation definitions
467     * which refer to parents of this managed object definition.
468     *
469     * @return Returns an unmodifiable collection containing the relation
470     *         definitions which refer directly to this managed object
471     *         definition.
472     */
473    public final Collection<RelationDefinition<C, S>> getReverseRelationDefinitions() {
474        return Collections.unmodifiableCollection(reverseRelationDefinitions);
475    }
476
477    /**
478     * Get the specified aggregation property definition associated with this
479     * type of managed object.The search will include any inherited aggregation
480     * property definitions.
481     *
482     * @param name
483     *            The name of the aggregation property definition to be
484     *            retrieved.
485     * @return Returns the specified aggregation property definition associated
486     *         with this type of managed object.
487     * @throws IllegalArgumentException
488     *             If the specified aggregation property name was null or empty
489     *             or if the requested aggregation property definition was not
490     *             found.
491     */
492    public final AggregationPropertyDefinition<?, ?> getAggregationPropertyDefinition(String name) {
493        if (name == null || name.length() == 0) {
494            throw new IllegalArgumentException("null or empty aggregation property name");
495        }
496
497        AggregationPropertyDefinition<?, ?> d = allAggregationPropertyDefinitions.get(name);
498        if (d == null) {
499            throw new IllegalArgumentException("aggregation property definition \"" + name + "\" not found");
500        }
501
502        return d;
503    }
504
505    /**
506     * Get the aggregation property definitions defined by this managed object
507     * definition. The returned collection will not contain inherited
508     * aggregation property definitions.
509     *
510     * @return Returns an unmodifiable collection containing the aggregation
511     *         property definitions defined by this managed object definition.
512     */
513    public final Collection<AggregationPropertyDefinition<?, ?>> getAggregationPropertyDefinitions() {
514        return Collections.unmodifiableCollection(aggregationPropertyDefinitions.values());
515    }
516
517    /**
518     * Get the aggregation property definitions which refer directly to this
519     * managed object definition. The returned collection will not contain
520     * aggregation property definitions which refer to parents of this managed
521     * object definition.
522     *
523     * @return Returns an unmodifiable collection containing the aggregation
524     *         property definitions which refer directly to this managed object
525     *         definition.
526     */
527    public final Collection<AggregationPropertyDefinition<?, ?>> getReverseAggregationPropertyDefinitions() {
528        return Collections.unmodifiableCollection(reverseAggregationPropertyDefinitions);
529    }
530
531    /**
532     * Gets the synopsis of this managed object definition in the default
533     * locale.
534     *
535     * @return Returns the synopsis of this managed object definition in the
536     *         default locale.
537     * @throws UnsupportedOperationException
538     *             If this managed object definition is the {@link TopCfgDefn}.
539     */
540    public final LocalizableMessage getSynopsis() {
541        return getSynopsis(Locale.getDefault());
542    }
543
544    /**
545     * Gets the synopsis of this managed object definition in the specified
546     * locale.
547     *
548     * @param locale
549     *            The locale.
550     * @return Returns the synopsis of this managed object definition in the
551     *         specified locale.
552     * @throws UnsupportedOperationException
553     *             If this managed object definition is the {@link TopCfgDefn}.
554     */
555    public final LocalizableMessage getSynopsis(Locale locale) {
556        return ManagedObjectDefinitionI18NResource.getInstance().getMessage(this, "synopsis", locale);
557    }
558
559    /**
560     * Gets the user friendly name of this managed object definition in the
561     * default locale.
562     *
563     * @return Returns the user friendly name of this managed object definition
564     *         in the default locale.
565     * @throws UnsupportedOperationException
566     *             If this managed object definition is the {@link TopCfgDefn}.
567     */
568    public final LocalizableMessage getUserFriendlyName() {
569        return getUserFriendlyName(Locale.getDefault());
570    }
571
572    /**
573     * Gets the user friendly name of this managed object definition in the
574     * specified locale.
575     *
576     * @param locale
577     *            The locale.
578     * @return Returns the user friendly name of this managed object definition
579     *         in the specified locale.
580     * @throws UnsupportedOperationException
581     *             If this managed object definition is the {@link TopCfgDefn}.
582     */
583    public final LocalizableMessage getUserFriendlyName(Locale locale) {
584        return LocalizableMessage.raw(ManagedObjectDefinitionI18NResource.getInstance().getMessage(this,
585            "user-friendly-name", locale));
586    }
587
588    /**
589     * Gets the user friendly plural name of this managed object definition in
590     * the default locale.
591     *
592     * @return Returns the user friendly plural name of this managed object
593     *         definition in the default locale.
594     * @throws UnsupportedOperationException
595     *             If this managed object definition is the {@link TopCfgDefn}.
596     */
597    public final LocalizableMessage getUserFriendlyPluralName() {
598        return getUserFriendlyPluralName(Locale.getDefault());
599    }
600
601    /**
602     * Gets the user friendly plural name of this managed object definition in
603     * the specified locale.
604     *
605     * @param locale
606     *            The locale.
607     * @return Returns the user friendly plural name of this managed object
608     *         definition in the specified locale.
609     * @throws UnsupportedOperationException
610     *             If this managed object definition is the {@link TopCfgDefn}.
611     */
612    public final LocalizableMessage getUserFriendlyPluralName(Locale locale) {
613        return ManagedObjectDefinitionI18NResource.getInstance()
614            .getMessage(this, "user-friendly-plural-name", locale);
615    }
616
617    /**
618     * Determine whether there are any child managed object definitions which
619     * inherit from this managed object definition.
620     *
621     * @return Returns <code>true</code> if this type of managed object has any
622     *         child managed object definitions, <code>false</code> otherwise.
623     */
624    public final boolean hasChildren() {
625        return !children.isEmpty();
626    }
627
628    /**
629     * Determines whether or not this managed object definition has the
630     * specified option.
631     *
632     * @param option
633     *            The option to test.
634     * @return Returns <code>true</code> if the option is set, or
635     *         <code>false</code> otherwise.
636     */
637    public final boolean hasOption(ManagedObjectOption option) {
638        return options.contains(option);
639    }
640
641    /**
642     * Determines whether or not this managed object definition has the
643     * specified tag.
644     *
645     * @param t
646     *            The tag definition.
647     * @return Returns <code>true</code> if this managed object definition has
648     *         the specified tag.
649     */
650    public final boolean hasTag(Tag t) {
651        return allTags.contains(t);
652    }
653
654    /**
655     * Determines whether or not this managed object definition is a sub-type of
656     * the provided managed object definition. This managed object definition is
657     * a sub-type of the provided managed object definition if they are both the
658     * same or if the provided managed object definition can be obtained by
659     * recursive invocations of the {@link #getParent()} method.
660     *
661     * @param d
662     *            The managed object definition to be checked.
663     * @return Returns <code>true</code> if this managed object definition is a
664     *         sub-type of the provided managed object definition.
665     */
666    public final boolean isChildOf(AbstractManagedObjectDefinition<?, ?> d) {
667        AbstractManagedObjectDefinition<?, ?> i;
668        for (i = this; i != null; i = i.parent) {
669            if (i == d) {
670                return true;
671            }
672        }
673        return false;
674    }
675
676    /**
677     * Determines whether or not this managed object definition is a super-type
678     * of the provided managed object definition. This managed object definition
679     * is a super-type of the provided managed object definition if they are
680     * both the same or if the provided managed object definition is a member of
681     * the set of children returned from {@link #getAllChildren()}.
682     *
683     * @param d
684     *            The managed object definition to be checked.
685     * @return Returns <code>true</code> if this managed object definition is a
686     *         super-type of the provided managed object definition.
687     */
688    public final boolean isParentOf(AbstractManagedObjectDefinition<?, ?> d) {
689        return d.isChildOf(this);
690    }
691
692    /**
693     * Determines whether or not this managed object definition is the
694     * {@link TopCfgDefn}.
695     *
696     * @return Returns <code>true</code> if this managed object definition is
697     *         the {@link TopCfgDefn}.
698     */
699    public final boolean isTop() {
700        return this instanceof TopCfgDefn;
701    }
702
703    /**
704     * Finds a sub-type of this managed object definition which most closely
705     * corresponds to the matching criteria of the provided definition resolver.
706     *
707     * @param r
708     *            The definition resolver.
709     * @return Returns the sub-type of this managed object definition which most
710     *         closely corresponds to the matching criteria of the provided
711     *         definition resolver.
712     * @throws DefinitionDecodingException
713     *             If no matching sub-type could be found or if the resolved
714     *             definition was abstract.
715     * @see DefinitionResolver
716     */
717    public final ManagedObjectDefinition<? extends C, ? extends S> resolveManagedObjectDefinition(DefinitionResolver r)
718            throws DefinitionDecodingException {
719        AbstractManagedObjectDefinition<? extends C, ? extends S> rd;
720        rd = resolveManagedObjectDefinitionAux(this, r);
721        if (rd == null) {
722            // Unable to resolve the definition.
723            throw new DefinitionDecodingException(this, Reason.WRONG_TYPE_INFORMATION);
724        } else if (rd instanceof ManagedObjectDefinition) {
725            return (ManagedObjectDefinition<? extends C, ? extends S>) rd;
726        } else {
727            // Resolved definition was abstract.
728            throw new DefinitionDecodingException(this, Reason.ABSTRACT_TYPE_INFORMATION);
729        }
730    }
731
732    /** {@inheritDoc} */
733    @Override
734    public final String toString() {
735        StringBuilder builder = new StringBuilder();
736        toString(builder);
737        return builder.toString();
738    }
739
740    /**
741     * Append a string representation of the managed object definition to the
742     * provided string builder.
743     *
744     * @param builder
745     *            The string builder where the string representation should be
746     *            appended.
747     */
748    public final void toString(StringBuilder builder) {
749        builder.append(getName());
750    }
751
752    /**
753     * Initializes all of the components associated with this managed object
754     * definition.
755     *
756     * @throws Exception
757     *             If this managed object definition could not be initialized.
758     */
759    protected final void initialize() throws Exception {
760        for (PropertyDefinition<?> pd : getAllPropertyDefinitions()) {
761            pd.initialize();
762            pd.getDefaultBehaviorProvider().initialize();
763        }
764
765        for (RelationDefinition<?, ?> rd : getAllRelationDefinitions()) {
766            rd.initialize();
767        }
768
769        for (AggregationPropertyDefinition<?, ?> apd : getAllAggregationPropertyDefinitions()) {
770
771            apd.initialize();
772            /*
773             * Now register the aggregation property in the referenced managed
774             * object definition for reverse lookups.
775             */
776            registerReverseAggregationPropertyDefinition(apd);
777        }
778
779        for (Constraint constraint : getAllConstraints()) {
780            constraint.initialize();
781        }
782    }
783
784    /**
785     * Register a constraint with this managed object definition.
786     * <p>
787     * This method <b>must not</b> be called by applications.
788     *
789     * @param constraint
790     *            The constraint to be registered.
791     */
792    protected final void registerConstraint(Constraint constraint) {
793        constraints.add(constraint);
794    }
795
796    /**
797     * Register a property definition with this managed object definition,
798     * overriding any existing property definition with the same name.
799     * <p>
800     * This method <b>must not</b> be called by applications.
801     *
802     * @param d
803     *            The property definition to be registered.
804     */
805    protected final void registerPropertyDefinition(PropertyDefinition<?> d) {
806        String propName = d.getName();
807
808        propertyDefinitions.put(propName, d);
809        allPropertyDefinitions.put(propName, d);
810
811        if (d instanceof AggregationPropertyDefinition<?, ?>) {
812            AggregationPropertyDefinition<?, ?> apd = (AggregationPropertyDefinition<?, ?>) d;
813            aggregationPropertyDefinitions.put(propName, apd);
814            // The key must also contain the managed object name, since several
815            // MOs
816            // in an inheritance tree may aggregate the same aggregation
817            // property name
818            allAggregationPropertyDefinitions.put(apd.getManagedObjectDefinition().getName() + ":" + propName, apd);
819        }
820    }
821
822    /**
823     * Register a relation definition with this managed object definition,
824     * overriding any existing relation definition with the same name.
825     * <p>
826     * This method <b>must not</b> be called by applications.
827     *
828     * @param d
829     *            The relation definition to be registered.
830     */
831    protected final void registerRelationDefinition(RelationDefinition<?, ?> d) {
832        // Register the relation in this managed object definition.
833        String relName = d.getName();
834
835        relationDefinitions.put(relName, d);
836        allRelationDefinitions.put(relName, d);
837
838        // Now register the relation in the referenced managed object
839        // definition for reverse lookups.
840        registerReverseRelationDefinition(d);
841    }
842
843    /**
844     * Register an option with this managed object definition.
845     * <p>
846     * This method <b>must not</b> be called by applications.
847     *
848     * @param option
849     *            The option to be registered.
850     */
851    protected final void registerOption(ManagedObjectOption option) {
852        options.add(option);
853    }
854
855    /**
856     * Register a tag with this managed object definition.
857     * <p>
858     * This method <b>must not</b> be called by applications.
859     *
860     * @param tag
861     *            The tag to be registered.
862     */
863    protected final void registerTag(Tag tag) {
864        allTags.add(tag);
865    }
866
867    /**
868     * Deregister a constraint from the managed object definition.
869     * <p>
870     * This method <b>must not</b> be called by applications and is only
871     * intended for internal testing.
872     *
873     * @param constraint
874     *            The constraint to be deregistered.
875     */
876    final void deregisterConstraint(Constraint constraint) {
877        if (!constraints.remove(constraint)) {
878            throw new RuntimeException("Failed to deregister a constraint");
879        }
880    }
881
882    /**
883     * Deregister a relation definition from the managed object definition.
884     * <p>
885     * This method <b>must not</b> be called by applications and is only
886     * intended for internal testing.
887     *
888     * @param d
889     *            The relation definition to be deregistered.
890     */
891    final void deregisterRelationDefinition(RelationDefinition<?, ?> d) {
892        // Deregister the relation from this managed object definition.
893        String relName = d.getName();
894        relationDefinitions.remove(relName);
895        allRelationDefinitions.remove(relName);
896
897        // Now deregister the relation from the referenced managed object
898        // definition for reverse lookups.
899        d.getChildDefinition().reverseRelationDefinitions.remove(d);
900    }
901
902    /**
903     * Register this managed object definition in its parent.
904     * <p>
905     * This method <b>must not</b> be called by applications and is only
906     * intended for internal testing.
907     */
908    final void registerInParent() {
909        if (parent != null) {
910            parent.children.put(name, this);
911        }
912    }
913
914    /**
915     * Register a relation definition in the referenced managed object
916     * definition's reverse lookup table.
917     */
918    private <C1 extends ConfigurationClient, S1 extends Configuration> void registerReverseRelationDefinition(
919        RelationDefinition<C1, S1> rd) {
920        rd.getChildDefinition().reverseRelationDefinitions.add(rd);
921    }
922
923    /**
924     * Register a aggregation property definition in the referenced managed
925     * object definition's reverse lookup table.
926     */
927    private void registerReverseAggregationPropertyDefinition(AggregationPropertyDefinition<?, ?> apd) {
928
929        apd.getRelationDefinition().getChildDefinition().reverseAggregationPropertyDefinitions.add(apd);
930    }
931
932    /**
933     * Recursively descend definition hierarchy to find the best match
934     * definition.
935     */
936    private AbstractManagedObjectDefinition<? extends C, ? extends S> resolveManagedObjectDefinitionAux(
937        AbstractManagedObjectDefinition<? extends C, ? extends S> d, DefinitionResolver r) {
938        if (!r.matches(d)) {
939            return null;
940        }
941
942        for (AbstractManagedObjectDefinition<? extends C, ? extends S> child : d.getChildren()) {
943            AbstractManagedObjectDefinition<? extends C, ? extends S> rd =
944                resolveManagedObjectDefinitionAux(child, r);
945            if (rd != null) {
946                return rd;
947            }
948        }
949
950        return d;
951    }
952}