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