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