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