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