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