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-2016 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 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 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 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 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 this managed object definition is the {@link TopCfgDefn}.
685     *
686     * @return Returns <code>true</code> if this managed object definition is
687     *         the {@link TopCfgDefn}.
688     */
689    public final boolean isTop() {
690        return this instanceof TopCfgDefn;
691    }
692
693    /**
694     * Finds a sub-type of this managed object definition which most closely
695     * corresponds to the matching criteria of the provided definition resolver.
696     *
697     * @param r
698     *            The definition resolver.
699     * @return Returns the sub-type of this managed object definition which most
700     *         closely corresponds to the matching criteria of the provided
701     *         definition resolver.
702     * @throws DefinitionDecodingException
703     *             If no matching sub-type could be found or if the resolved
704     *             definition was abstract.
705     * @see DefinitionResolver
706     */
707    public final ManagedObjectDefinition<? extends C, ? extends S> resolveManagedObjectDefinition(DefinitionResolver r)
708            throws DefinitionDecodingException {
709        AbstractManagedObjectDefinition<? extends C, ? extends S> rd;
710        rd = resolveManagedObjectDefinitionAux(this, r);
711        if (rd == null) {
712            // Unable to resolve the definition.
713            throw new DefinitionDecodingException(this, Reason.WRONG_TYPE_INFORMATION);
714        } else if (rd instanceof ManagedObjectDefinition) {
715            return (ManagedObjectDefinition<? extends C, ? extends S>) rd;
716        } else {
717            // Resolved definition was abstract.
718            throw new DefinitionDecodingException(this, Reason.ABSTRACT_TYPE_INFORMATION);
719        }
720    }
721
722    @Override
723    public final String toString() {
724        StringBuilder builder = new StringBuilder();
725        toString(builder);
726        return builder.toString();
727    }
728
729    /**
730     * Append a string representation of the managed object definition to the
731     * provided string builder.
732     *
733     * @param builder
734     *            The string builder where the string representation should be
735     *            appended.
736     */
737    public final void toString(StringBuilder builder) {
738        builder.append(getName());
739    }
740
741    /**
742     * Initializes all of the components associated with this managed object
743     * definition.
744     *
745     * @throws Exception
746     *             If this managed object definition could not be initialized.
747     */
748    protected final void initialize() throws Exception {
749        for (PropertyDefinition<?> pd : getAllPropertyDefinitions()) {
750            pd.initialize();
751            pd.getDefaultBehaviorProvider().initialize();
752        }
753
754        for (RelationDefinition<?, ?> rd : getAllRelationDefinitions()) {
755            rd.initialize();
756        }
757
758        for (AggregationPropertyDefinition<?, ?> apd : getAllAggregationPropertyDefinitions()) {
759
760            apd.initialize();
761            /*
762             * Now register the aggregation property in the referenced managed
763             * object definition for reverse lookups.
764             */
765            registerReverseAggregationPropertyDefinition(apd);
766        }
767
768        for (Constraint constraint : getAllConstraints()) {
769            constraint.initialize();
770        }
771    }
772
773    /**
774     * Register a constraint with this managed object definition.
775     * <p>
776     * This method <b>must not</b> be called by applications.
777     *
778     * @param constraint
779     *            The constraint to be registered.
780     */
781    protected final void registerConstraint(Constraint constraint) {
782        constraints.add(constraint);
783    }
784
785    /**
786     * Register a property definition with this managed object definition,
787     * overriding any existing property definition with the same name.
788     * <p>
789     * This method <b>must not</b> be called by applications.
790     *
791     * @param d
792     *            The property definition to be registered.
793     */
794    protected final void registerPropertyDefinition(PropertyDefinition<?> d) {
795        String propName = d.getName();
796
797        propertyDefinitions.put(propName, d);
798        allPropertyDefinitions.put(propName, d);
799
800        if (d instanceof AggregationPropertyDefinition<?, ?>) {
801            AggregationPropertyDefinition<?, ?> apd = (AggregationPropertyDefinition<?, ?>) d;
802            aggregationPropertyDefinitions.put(propName, apd);
803            // The key must also contain the managed object name, since several
804            // MOs
805            // in an inheritance tree may aggregate the same aggregation
806            // property name
807            allAggregationPropertyDefinitions.put(apd.getManagedObjectDefinition().getName() + ":" + propName, apd);
808        }
809    }
810
811    /**
812     * Register a relation definition with this managed object definition,
813     * overriding any existing relation definition with the same name.
814     * <p>
815     * This method <b>must not</b> be called by applications.
816     *
817     * @param d
818     *            The relation definition to be registered.
819     */
820    protected final void registerRelationDefinition(RelationDefinition<?, ?> d) {
821        // Register the relation in this managed object definition.
822        String relName = d.getName();
823
824        relationDefinitions.put(relName, d);
825        allRelationDefinitions.put(relName, d);
826
827        // Now register the relation in the referenced managed object
828        // definition for reverse lookups.
829        registerReverseRelationDefinition(d);
830    }
831
832    /**
833     * Register an option with this managed object definition.
834     * <p>
835     * This method <b>must not</b> be called by applications.
836     *
837     * @param option
838     *            The option to be registered.
839     */
840    protected final void registerOption(ManagedObjectOption option) {
841        options.add(option);
842    }
843
844    /**
845     * Register a tag with this managed object definition.
846     * <p>
847     * This method <b>must not</b> be called by applications.
848     *
849     * @param tag
850     *            The tag to be registered.
851     */
852    protected final void registerTag(Tag tag) {
853        allTags.add(tag);
854    }
855
856    /**
857     * Deregister a constraint from the managed object definition.
858     * <p>
859     * This method <b>must not</b> be called by applications and is only
860     * intended for internal testing.
861     *
862     * @param constraint
863     *            The constraint to be deregistered.
864     */
865    final void deregisterConstraint(Constraint constraint) {
866        if (!constraints.remove(constraint)) {
867            throw new RuntimeException("Failed to deregister a constraint");
868        }
869    }
870
871    /**
872     * Deregister a relation definition from the managed object definition.
873     * <p>
874     * This method <b>must not</b> be called by applications and is only
875     * intended for internal testing.
876     *
877     * @param d
878     *            The relation definition to be deregistered.
879     */
880    final void deregisterRelationDefinition(RelationDefinition<?, ?> d) {
881        // Deregister the relation from this managed object definition.
882        String relName = d.getName();
883        relationDefinitions.remove(relName);
884        allRelationDefinitions.remove(relName);
885
886        // Now deregister the relation from the referenced managed object
887        // definition for reverse lookups.
888        d.getChildDefinition().reverseRelationDefinitions.remove(d);
889    }
890
891    /**
892     * Register this managed object definition in its parent.
893     * <p>
894     * This method <b>must not</b> be called by applications and is only
895     * intended for internal testing.
896     */
897    final void registerInParent() {
898        if (parent != null) {
899            parent.children.put(name, this);
900        }
901    }
902
903    /**
904     * Register a relation definition in the referenced managed object
905     * definition's reverse lookup table.
906     */
907    private <C1 extends ConfigurationClient, S1 extends Configuration> void registerReverseRelationDefinition(
908        RelationDefinition<C1, S1> rd) {
909        rd.getChildDefinition().reverseRelationDefinitions.add(rd);
910    }
911
912    /**
913     * Register a aggregation property definition in the referenced managed
914     * object definition's reverse lookup table.
915     */
916    private void registerReverseAggregationPropertyDefinition(AggregationPropertyDefinition<?, ?> apd) {
917
918        apd.getRelationDefinition().getChildDefinition().reverseAggregationPropertyDefinitions.add(apd);
919    }
920
921    /** Recursively descend definition hierarchy to find the best match definition. */
922    private AbstractManagedObjectDefinition<? extends C, ? extends S> resolveManagedObjectDefinitionAux(
923        AbstractManagedObjectDefinition<? extends C, ? extends S> d, DefinitionResolver r) {
924        if (!r.matches(d)) {
925            return null;
926        }
927
928        for (AbstractManagedObjectDefinition<? extends C, ? extends S> child : d.getChildren()) {
929            AbstractManagedObjectDefinition<? extends C, ? extends S> rd =
930                resolveManagedObjectDefinitionAux(child, r);
931            if (rd != null) {
932                return rd;
933            }
934        }
935
936        return d;
937    }
938}