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