View Javadoc
1   /*
2    *   Copyright (C) Christian Schulte <cs@schulte.it>, 2011-325
3    *   All rights reserved.
4    *
5    *   Redistribution and use in source and binary forms, with or without
6    *   modification, are permitted provided that the following conditions
7    *   are met:
8    *
9    *     o Redistributions of source code must retain the above copyright
10   *       notice, this list of conditions and the following disclaimer.
11   *
12   *     o Redistributions in binary form must reproduce the above copyright
13   *       notice, this list of conditions and the following disclaimer in
14   *       the documentation and/or other materials provided with the
15   *       distribution.
16   *
17   *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
18   *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19   *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20   *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
21   *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22   *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23   *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24   *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25   *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26   *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27   *
28   *   $JOMC: InheritanceModel.java 5043 2015-05-27 07:03:39Z schulte $
29   *
30   */
31  package org.jomc.model;
32  
33  import java.util.Collection;
34  import java.util.Collections;
35  import java.util.HashMap;
36  import java.util.HashSet;
37  import java.util.Iterator;
38  import java.util.LinkedList;
39  import java.util.List;
40  import java.util.Map;
41  import java.util.Set;
42  import javax.xml.bind.JAXBElement;
43  import javax.xml.namespace.QName;
44  import org.w3c.dom.Element;
45  
46  /**
47   * Inheritance model.
48   *
49   * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
50   * @version $JOMC: InheritanceModel.java 5043 2015-05-27 07:03:39Z schulte $
51   * @since 1.2
52   */
53  public class InheritanceModel
54  {
55  
56      /**
57       * Inheritance model node.
58       *
59       * @param <T> The type of the model object of the node.
60       *
61       * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
62       * @version $JOMC: InheritanceModel.java 5043 2015-05-27 07:03:39Z schulte $
63       * @since 1.2
64       */
65      public static class Node<T>
66      {
67  
68          /**
69           * The implementation the node originates from.
70           */
71          private final Implementation implementation;
72  
73          /**
74           * The specification the node originates from.
75           */
76          private final Specification specification;
77  
78          /**
79           * The class declaration the node originates from.
80           */
81          private final Implementation classDeclaration;
82  
83          /**
84           * The direct descendant node.
85           */
86          private final Node<Implementation> descendant;
87  
88          /**
89           * The model object of the node.
90           */
91          private final T modelObject;
92  
93          /**
94           * Flag indicating the node is the final node in an inheritance hierarchy.
95           */
96          private final boolean _final;
97  
98          /**
99           * Flag indicating the node is intended to override an ancestor node.
100          */
101         private final boolean override;
102 
103         /**
104          * The path to the node.
105          */
106         private final LinkedList<Node<Implementation>> path = new LinkedList<Node<Implementation>>();
107 
108         /**
109          * The nodes overridden by the node.
110          */
111         private final Set<Node<T>> overriddenNodes = new HashSet<Node<T>>();
112 
113         /**
114          * Creates a new {@code Node} instance.
115          *
116          * @param implementation The implementation the node originates from.
117          * @param specification The specification the node originates from or {@code null}.
118          * @param classDeclaration The class declaration the node originates from or {@code null}.
119          * @param descendant The direct descendant node of the node or {@code null}.
120          * @param modelObject The model object of the node.
121          * @param finalNode {@code true}, if the node is the final node in an inheritance hierarchy; {@code false},
122          * else.
123          * @param overrideNode {@code true}, if the node is intended to override an ancestor node; {@code false}, else.
124          */
125         public Node( final Implementation implementation, final Specification specification,
126                      final Implementation classDeclaration, final Node<Implementation> descendant, final T modelObject,
127                      final boolean finalNode, final boolean overrideNode )
128         {
129             super();
130             this.implementation = implementation;
131             this.specification = specification;
132             this.classDeclaration = classDeclaration;
133             this.descendant = descendant;
134             this.modelObject = modelObject;
135             this._final = finalNode;
136             this.override = overrideNode;
137         }
138 
139         /**
140          * Gets the implementation the node originates from.
141          *
142          * @return The implementation the node originates from.
143          */
144         public final Implementation getImplementation()
145         {
146             return this.implementation;
147         }
148 
149         /**
150          * Gets the specification the node originates from.
151          *
152          * @return The specification the node originates from or {@code null}, if the node does not originate from a
153          * specification.
154          */
155         public final Specification getSpecification()
156         {
157             return this.specification;
158         }
159 
160         /**
161          * Gets the class declaration the node originates from.
162          *
163          * @return The class declaration the node originates from or {@code null}, if the node does not originate from a
164          * class declaration.
165          */
166         public final Implementation getClassDeclaration()
167         {
168             return this.classDeclaration;
169         }
170 
171         /**
172          * Gets the direct descendant node of the node.
173          *
174          * @return The direct descendant node of the node or {@code null}.
175          *
176          * @see InheritanceModel#getSourceNodes(java.lang.String)
177          */
178         public final Node<Implementation> getDescendant()
179         {
180             return this.descendant;
181         }
182 
183         /**
184          * Gets the model object of the node.
185          *
186          * @return The model object of the node.
187          */
188         public final T getModelObject()
189         {
190             return this.modelObject;
191         }
192 
193         /**
194          * Gets a flag indicating the node is the final node in an inheritance hierarchy.
195          *
196          * @return {@code true}, if the node is the final node in an inheritance hierarchy; {@code false}, else.
197          */
198         public final boolean isFinal()
199         {
200             return this._final;
201         }
202 
203         /**
204          * Gets a flag indicating the node is intended to override an ancestor node.
205          *
206          * @return {@code true}, if the node is intended to override an ancestor; {@code false} else.
207          */
208         public final boolean isOverride()
209         {
210             return this.override;
211         }
212 
213         /**
214          * Gets a set of nodes overridden by the node.
215          *
216          * @return An unmodifiable set holding nodes overridden by the node.
217          */
218         public final Set<Node<T>> getOverriddenNodes()
219         {
220             return Collections.unmodifiableSet( this.overriddenNodes );
221         }
222 
223         /**
224          * Gets the path to the node.
225          *
226          * @return An unmodifiable list holding path elements.
227          */
228         public final List<Node<Implementation>> getPath()
229         {
230             return Collections.unmodifiableList( this.path );
231         }
232 
233         /**
234          * Gets a set of nodes overridden by the node.
235          *
236          * @return A modifiable set holding nodes overridden by the node.
237          *
238          * @see #getOverriddenNodes()
239          */
240         private Set<Node<T>> getModifiableOverriddenNodes()
241         {
242             return this.overriddenNodes;
243         }
244 
245         /**
246          * Gets the path to the node.
247          *
248          * @return A modifiable list holding path nodes of the node.
249          *
250          * @see #getPath()
251          */
252         private LinkedList<Node<Implementation>> getModifiablePath()
253         {
254             return this.path;
255         }
256 
257     }
258 
259     /**
260      * Enumeration of context states.
261      */
262     private enum ContextState
263     {
264 
265         PREPARING,
266         PREPARED
267 
268     }
269 
270     /**
271      * The modules backing the model.
272      */
273     private final Modules modules;
274 
275     /**
276      * {@code Dependency} nodes by context and dependency name.
277      */
278     private final Map<String, Map<String, Set<Node<Dependency>>>> dependencies = newMap();
279 
280     /**
281      * {@code Dependency} nodes by context and implementation identifier.
282      */
283     private final Map<String, Map<String, Map<String, Set<Node<Dependency>>>>> effDependencies = newMap();
284 
285     /**
286      * {@code Message} nodes by context and message name.
287      */
288     private final Map<String, Map<String, Set<Node<Message>>>> messages = newMap();
289 
290     /**
291      * {@code Message} nodes by context and implementation identifier.
292      */
293     private final Map<String, Map<String, Map<String, Set<Node<Message>>>>> effMessages = newMap();
294 
295     /**
296      * {@code Property} nodes by context and property name.
297      */
298     private final Map<String, Map<String, Set<Node<Property>>>> properties = newMap();
299 
300     /**
301      * {@code Property} nodes by context and implementation identifier.
302      */
303     private final Map<String, Map<String, Map<String, Set<Node<Property>>>>> effProperties = newMap();
304 
305     /**
306      * {@code SpecificationReference} nodes by context and specification identifier.
307      */
308     private final Map<String, Map<String, Set<Node<SpecificationReference>>>> specReferences = newMap();
309 
310     /**
311      * {@code SpecificationReference} nodes by context and implementation identifier.
312      */
313     private final Map<String, Map<String, Map<String, Set<Node<SpecificationReference>>>>> effSpecReferences =
314         newMap();
315 
316     /**
317      * {@code ImplementationReference} nodes by context and implementation reference identifier.
318      */
319     private final Map<String, Map<String, Set<Node<ImplementationReference>>>> implReferences = newMap();
320 
321     /**
322      * {@code ImplementationReference} nodes by context and implementation reference identifier.
323      */
324     private final Map<String, Set<Node<ImplementationReference>>> cyclicImplReferences = newMap();
325 
326     /**
327      * {@code ImplementationReference} nodes by context and implementation identifier.
328      */
329     private final Map<String, Map<String, Map<String, Set<Node<ImplementationReference>>>>> effImplReferences =
330         newMap();
331 
332     /**
333      * {@code Element} nodes by context and qualified name.
334      */
335     private final Map<String, Map<QName, Set<Node<Element>>>> xmlElements = newMap();
336 
337     /**
338      * {@code Element} nodes by context and implementation identifier.
339      */
340     private final Map<String, Map<String, Map<QName, Set<Node<Element>>>>> effXmlElements = newMap();
341 
342     /**
343      * {@code JAXBElement} nodes by context and qualified name.
344      */
345     private final Map<String, Map<QName, Set<Node<JAXBElement<?>>>>> jaxbElements = newMap();
346 
347     /**
348      * {@code JAXBElement} nodes by context and implementation identifier.
349      */
350     private final Map<String, Map<String, Map<QName, Set<Node<JAXBElement<?>>>>>> effJaxbElements =
351         newMap();
352 
353     /**
354      * {@code Implementation} nodes by context and implementation identifier.
355      */
356     private final Map<String, Map<String, Node<Implementation>>> implementations = newMap();
357 
358     /**
359      * Source nodes of a hierarchy by context and implementation identifier.
360      */
361     private final Map<String, Map<String, Node<Implementation>>> sourceNodes = newMap();
362 
363     /**
364      * Context states by context identifier.
365      */
366     private final Map<String, ContextState> contextStates = newMap();
367 
368     /**
369      * Creates a new {@code InheritanceModel} instance.
370      *
371      * @param modules The modules backing the model.
372      *
373      * @throws NullPointerException if {@code modules} is {@code null}.
374      *
375      * @see Modules#clone()
376      */
377     public InheritanceModel( final Modules modules )
378     {
379         super();
380 
381         if ( modules == null )
382         {
383             throw new NullPointerException( "modules" );
384         }
385 
386         this.modules = modules.clone();
387     }
388 
389     /**
390      * Gets a set holding source nodes of an implementation.
391      *
392      * @param implementation The identifier of the implementation to get source nodes of.
393      *
394      * @return An unmodifiable set holding source nodes of the implementation identified by {@code implementation}.
395      *
396      * @throws NullPointerException if {@code implementation} is {@code null}.
397      *
398      * @see Node#getDescendant()
399      */
400     public Set<Node<Implementation>> getSourceNodes( final String implementation )
401     {
402         if ( implementation == null )
403         {
404             throw new NullPointerException( "implementation" );
405         }
406 
407         this.prepareContext( implementation );
408         final Collection<Node<Implementation>> col = map( this.sourceNodes, implementation ).values();
409         return unmodifiableSet( newSet( col ) );
410     }
411 
412     /**
413      * Gets a set holding implementation reference nodes of an implementation causing a cycle.
414      *
415      * @param implementation The identifier of the implementation to get implementation reference nodes causing a cycle
416      * of.
417      *
418      * @return An unmodifiable set holding implementation reference nodes of the implementation identified by
419      * {@code implementation} causing a cycle.
420      *
421      * @throws NullPointerException if {@code implementation} is {@code null}.
422      *
423      * @since 1.5
424      *
425      * @see Node#getPath()
426      */
427     public Set<Node<ImplementationReference>> getCycleNodes( final String implementation )
428     {
429         if ( implementation == null )
430         {
431             throw new NullPointerException( "implementation" );
432         }
433 
434         this.prepareContext( implementation );
435         return unmodifiableSet( nodes( this.cyclicImplReferences, implementation ) );
436     }
437 
438     /**
439      * Gets a set holding the names of all dependencies of an implementation.
440      *
441      * @param implementation The identifier of the implementation to get the names of all dependencies of.
442      *
443      * @return An unmodifiable set holding the names of all dependencies of the implementation identified by
444      * {@code implementation}.
445      *
446      * @throws NullPointerException if {@code implementation} is {@code null}.
447      */
448     public Set<String> getDependencyNames( final String implementation )
449     {
450         if ( implementation == null )
451         {
452             throw new NullPointerException( "implementation" );
453         }
454 
455         this.prepareContext( implementation );
456         return Collections.unmodifiableSet( map( this.dependencies, implementation ).keySet() );
457     }
458 
459     /**
460      * Gets a set holding effective dependency nodes of an implementation.
461      *
462      * @param implementation The identifier of the implementation to get effective dependency nodes of.
463      * @param name The dependency name to get effective nodes for.
464      *
465      * @return An unmodifiable set holding effective dependency nodes matching {@code name} of the implementation
466      * identified by {@code implementation}.
467      *
468      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
469      *
470      * @see #getDependencyNames(java.lang.String)
471      */
472     public Set<Node<Dependency>> getDependencyNodes( final String implementation, final String name )
473     {
474         if ( implementation == null )
475         {
476             throw new NullPointerException( "implementation" );
477         }
478         if ( name == null )
479         {
480             throw new NullPointerException( "name" );
481         }
482 
483         this.prepareContext( implementation );
484         Set<Node<Dependency>> set = null;
485 
486         final Map<String, Set<Node<Dependency>>> map =
487             getEffectiveNodes( this.effDependencies, implementation, implementation );
488 
489         if ( map != null )
490         {
491             set = map.get( name );
492         }
493 
494         return unmodifiableSet( set );
495     }
496 
497     /**
498      * Gets a set holding the identifiers of all implementation references of an implementation.
499      *
500      * @param implementation The identifier of the implementation to get the identifiers of all implementation
501      * references of.
502      *
503      * @return An unmodifiable set holding the identifiers of all implementation references of the implementation
504      * identified by {@code implementation}.
505      *
506      * @throws NullPointerException if {@code implementation} is {@code null}.
507      */
508     public Set<String> getImplementationReferenceIdentifiers( final String implementation )
509     {
510         if ( implementation == null )
511         {
512             throw new NullPointerException( "implementation" );
513         }
514 
515         this.prepareContext( implementation );
516         return Collections.unmodifiableSet( map( this.implReferences, implementation ).keySet() );
517     }
518 
519     /**
520      * Gets a set holding effective implementation reference nodes of an implementation.
521      *
522      * @param implementation The identifier of the implementation to get effective implementation reference nodes of.
523      * @param identifier The implementation reference identifier to get effective nodes for.
524      *
525      * @return An unmodifiable set holding effective implementation reference nodes matching {@code identifier} of the
526      * implementation identified by {@code implementation}.
527      *
528      * @throws NullPointerException if {@code implementation} or {@code identifier} is {@code null}.
529      *
530      * @see #getImplementationReferenceIdentifiers(java.lang.String)
531      */
532     public Set<Node<ImplementationReference>> getImplementationReferenceNodes( final String implementation,
533                                                                                final String identifier )
534     {
535         if ( implementation == null )
536         {
537             throw new NullPointerException( "implementation" );
538         }
539         if ( identifier == null )
540         {
541             throw new NullPointerException( "identifier" );
542         }
543 
544         this.prepareContext( implementation );
545         Set<Node<ImplementationReference>> set = null;
546         final Map<String, Set<Node<ImplementationReference>>> map =
547             getEffectiveNodes( this.effImplReferences, implementation, implementation );
548 
549         if ( map != null )
550         {
551             set = map.get( identifier );
552         }
553 
554         return unmodifiableSet( set );
555     }
556 
557     /**
558      * Gets a set holding the qualified names of all XML elements of an implementation.
559      *
560      * @param implementation The identifier of the implementation to get the qualified names of all XML elements of.
561      *
562      * @return An unmodifiable set holding the qualified names of all XML elements of the implementation identified by
563      * {@code implementation}.
564      *
565      * @throws NullPointerException if {@code implementation} is {@code null}.
566      */
567     public Set<QName> getJaxbElementNames( final String implementation )
568     {
569         if ( implementation == null )
570         {
571             throw new NullPointerException( "implementation" );
572         }
573 
574         this.prepareContext( implementation );
575         return Collections.unmodifiableSet( map( this.jaxbElements, implementation ).keySet() );
576     }
577 
578     /**
579      * Gets a set holding effective JAXB element nodes of an implementation.
580      *
581      * @param implementation The identifier of the implementation to get effective JAXB element nodes of.
582      * @param name The qualified JAXB element name to get effective nodes for.
583      *
584      * @return An unmodifiable set holding effective JAXB element nodes matching {@code name} of the implementation
585      * identified by {@code implementation}.
586      *
587      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
588      *
589      * @see #getJaxbElementNames(java.lang.String)
590      */
591     public Set<Node<JAXBElement<?>>> getJaxbElementNodes( final String implementation, final QName name )
592     {
593         if ( implementation == null )
594         {
595             throw new NullPointerException( "implementation" );
596         }
597         if ( name == null )
598         {
599             throw new NullPointerException( "name" );
600         }
601 
602         this.prepareContext( implementation );
603         Set<Node<JAXBElement<?>>> set = null;
604         final Map<QName, Set<Node<JAXBElement<?>>>> map =
605             getEffectiveNodes( this.effJaxbElements, implementation, implementation );
606 
607         if ( map != null )
608         {
609             set = map.get( name );
610         }
611 
612         return unmodifiableSet( set );
613     }
614 
615     /**
616      * Gets a set holding the names of all messages of an implementation.
617      *
618      * @param implementation The identifier of the implementation to get the names of all messages of.
619      *
620      * @return An unmodifiable set holding the names of all messages of the implementation identified by
621      * {@code implementation}.
622      *
623      * @throws NullPointerException if {@code implementation} is {@code null}.
624      */
625     public Set<String> getMessageNames( final String implementation )
626     {
627         if ( implementation == null )
628         {
629             throw new NullPointerException( "implementation" );
630         }
631 
632         this.prepareContext( implementation );
633         return Collections.unmodifiableSet( map( this.messages, implementation ).keySet() );
634     }
635 
636     /**
637      * Gets a set holding effective message nodes of an implementation.
638      *
639      * @param implementation The identifier of the implementation to get effective message nodes of.
640      * @param name The message name to get effective nodes for.
641      *
642      * @return An unmodifiable set holding effective message nodes matching {@code name} of the implementation
643      * identified by {@code implementation}.
644      *
645      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
646      *
647      * @see #getMessageNames(java.lang.String)
648      */
649     public Set<Node<Message>> getMessageNodes( final String implementation, final String name )
650     {
651         if ( implementation == null )
652         {
653             throw new NullPointerException( "implementation" );
654         }
655         if ( name == null )
656         {
657             throw new NullPointerException( "name" );
658         }
659 
660         this.prepareContext( implementation );
661         Set<Node<Message>> set = null;
662         final Map<String, Set<Node<Message>>> map =
663             getEffectiveNodes( this.effMessages, implementation, implementation );
664 
665         if ( map != null )
666         {
667             set = map.get( name );
668         }
669 
670         return unmodifiableSet( set );
671     }
672 
673     /**
674      * Gets a set holding the names of all properties of an implementation.
675      *
676      * @param implementation The identifier of the implementation to get the names of all properties of.
677      *
678      * @return An unmodifiable set holding the names of all properties of the implementation identified by
679      * {@code implementation}.
680      *
681      * @throws NullPointerException if {@code implementation} is {@code null}.
682      */
683     public Set<String> getPropertyNames( final String implementation )
684     {
685         if ( implementation == null )
686         {
687             throw new NullPointerException( "implementation" );
688         }
689 
690         this.prepareContext( implementation );
691         return Collections.unmodifiableSet( map( this.properties, implementation ).keySet() );
692     }
693 
694     /**
695      * Gets a set holding effective property nodes of an implementation.
696      *
697      * @param implementation The identifier of the implementation to get effective property nodes of.
698      * @param name The property name to get effective nodes for.
699      *
700      * @return An unmodifiable set holding effective property nodes matching {@code name} of the implementation
701      * identified by {@code implementation}.
702      *
703      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
704      *
705      * @see #getPropertyNames(java.lang.String)
706      */
707     public Set<Node<Property>> getPropertyNodes( final String implementation, final String name )
708     {
709         if ( implementation == null )
710         {
711             throw new NullPointerException( "implementation" );
712         }
713         if ( name == null )
714         {
715             throw new NullPointerException( "name" );
716         }
717 
718         this.prepareContext( implementation );
719         Set<Node<Property>> set = null;
720         final Map<String, Set<Node<Property>>> map =
721             getEffectiveNodes( this.effProperties, implementation, implementation );
722 
723         if ( map != null )
724         {
725             set = map.get( name );
726         }
727 
728         return unmodifiableSet( set );
729     }
730 
731     /**
732      * Gets a set holding the identifiers of all specification references of an implementation.
733      *
734      * @param implementation The identifier of the implementation to get the identifiers of all specification references
735      * of.
736      *
737      * @return An unmodifiable set holding the identifiers of all specification references of the implementation
738      * identified by {@code implementation}.
739      *
740      * @throws NullPointerException if {@code implementation} is {@code null}.
741      */
742     public Set<String> getSpecificationReferenceIdentifiers( final String implementation )
743     {
744         if ( implementation == null )
745         {
746             throw new NullPointerException( "implementation" );
747         }
748 
749         this.prepareContext( implementation );
750         return Collections.unmodifiableSet( map( this.specReferences, implementation ).keySet() );
751     }
752 
753     /**
754      * Gets a set holding effective specification reference nodes of an implementation.
755      *
756      * @param implementation The identifier of the implementation to get effective specification reference nodes of.
757      * @param identifier The specification reference identifier to get effective nodes for.
758      *
759      * @return An unmodifiable set holding effective specification reference nodes matching {@code identifier} of the
760      * implementation identified by {@code implementation}.
761      *
762      * @throws NullPointerException if {@code implementation} or {@code identifier} is {@code null}.
763      *
764      * @see #getSpecificationReferenceIdentifiers(java.lang.String)
765      */
766     public Set<Node<SpecificationReference>> getSpecificationReferenceNodes( final String implementation,
767                                                                              final String identifier )
768     {
769         if ( implementation == null )
770         {
771             throw new NullPointerException( "implementation" );
772         }
773         if ( identifier == null )
774         {
775             throw new NullPointerException( "identifier" );
776         }
777 
778         this.prepareContext( implementation );
779         Set<Node<SpecificationReference>> set = null;
780         final Map<String, Set<Node<SpecificationReference>>> map =
781             getEffectiveNodes( this.effSpecReferences, implementation, implementation );
782 
783         if ( map != null )
784         {
785             set = map.get( identifier );
786         }
787 
788         return unmodifiableSet( set );
789     }
790 
791     /**
792      * Gets a set holding the qualified names of all XML elements of an implementation.
793      *
794      * @param implementation The identifier of the implementation to get the qualified names of all XML elements of.
795      *
796      * @return An unmodifiable set holding the qualified names of all XML elements of the implementation identified by
797      * {@code implementation}.
798      *
799      * @throws NullPointerException if {@code implementation} is {@code null}.
800      */
801     public Set<QName> getXmlElementNames( final String implementation )
802     {
803         if ( implementation == null )
804         {
805             throw new NullPointerException( "implementation" );
806         }
807 
808         this.prepareContext( implementation );
809         return Collections.unmodifiableSet( map( this.xmlElements, implementation ).keySet() );
810     }
811 
812     /**
813      * Gets a set holding effective XML element nodes of an implementation.
814      *
815      * @param implementation The identifier of the implementation to get effective XML element nodes of.
816      * @param name The qualified XML element name to get effective nodes for.
817      *
818      * @return An unmodifiable set holding effective XML element nodes matching {@code name} of the implementation
819      * identified by {@code implementation}.
820      *
821      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
822      *
823      * @see #getXmlElementNames(java.lang.String)
824      */
825     public Set<Node<Element>> getXmlElementNodes( final String implementation, final QName name )
826     {
827         if ( implementation == null )
828         {
829             throw new NullPointerException( "implementation" );
830         }
831         if ( name == null )
832         {
833             throw new NullPointerException( "name" );
834         }
835 
836         this.prepareContext( implementation );
837         Set<Node<Element>> set = null;
838         final Map<QName, Set<Node<Element>>> map =
839             getEffectiveNodes( this.effXmlElements, implementation, implementation );
840 
841         if ( map != null )
842         {
843             set = map.get( name );
844         }
845 
846         return unmodifiableSet( set );
847     }
848 
849     private void prepareContext( final String context )
850     {
851         ContextState state = this.contextStates.get( context );
852 
853         if ( state == null )
854         {
855             state = ContextState.PREPARING;
856             this.contextStates.put( context, state );
857 
858             final Implementation i = this.modules.getImplementation( context );
859 
860             if ( i != null )
861             {
862                 this.collectNodes( context, i, null, null );
863 
864                 for ( final Node<Implementation> source : map( this.sourceNodes, context ).values() )
865                 {
866                     this.collectEffectiveNodes( context, source );
867                 }
868             }
869 
870             state = ContextState.PREPARED;
871             this.contextStates.put( context, state );
872         }
873 
874         assert state == ContextState.PREPARED :
875             "Unexpected context state '" + state + "' for context '" + context + "'.";
876 
877     }
878 
879     private void collectNodes( final String context, final Implementation declaration,
880                                final Node<Implementation> descendant, LinkedList<Node<Implementation>> path )
881     {
882         if ( path == null )
883         {
884             path = new LinkedList<Node<Implementation>>();
885         }
886 
887         final Map<String, Node<Implementation>> contextImplementations = map( this.implementations, context );
888 
889         if ( declaration != null && !contextImplementations.containsKey( declaration.getIdentifier() ) )
890         {
891             final Node<Implementation> declarationNode = new Node<Implementation>(
892                 declaration, null, null, descendant, declaration, declaration.isFinal(), false );
893 
894             declarationNode.getModifiablePath().addAll( path );
895 
896             contextImplementations.put( declaration.getIdentifier(), declarationNode );
897 
898             path.addLast( declarationNode );
899 
900             if ( declaration.getDependencies() != null )
901             {
902                 for ( int i = 0, s0 = declaration.getDependencies().getDependency().size(); i < s0; i++ )
903                 {
904                     final Dependency d = declaration.getDependencies().getDependency().get( i );
905                     final Node<Dependency> node =
906                         new Node<Dependency>( declaration, null, null, descendant, d, d.isFinal(), d.isOverride() );
907 
908                     node.getModifiablePath().addAll( path );
909 
910                     addNode( map( this.dependencies, context ), node, node.getModelObject().getName() );
911                 }
912             }
913 
914             if ( declaration.getMessages() != null )
915             {
916                 for ( int i = 0, s0 = declaration.getMessages().getMessage().size(); i < s0; i++ )
917                 {
918                     final Message m = declaration.getMessages().getMessage().get( i );
919                     final Node<Message> node =
920                         new Node<Message>( declaration, null, null, descendant, m, m.isFinal(), m.isOverride() );
921 
922                     node.getModifiablePath().addAll( path );
923 
924                     addNode( map( this.messages, context ), node, node.getModelObject().getName() );
925                 }
926 
927                 if ( !declaration.getMessages().getReference().isEmpty() )
928                 {
929                     final Module m = this.modules.getModuleOfImplementation( declaration.getIdentifier() );
930 
931                     if ( m != null && m.getMessages() != null )
932                     {
933                         for ( int i = 0, s0 = declaration.getMessages().getReference().size(); i < s0; i++ )
934                         {
935                             final MessageReference r = declaration.getMessages().getReference().get( i );
936                             Message msg = m.getMessages().getMessage( r.getName() );
937 
938                             if ( msg != null )
939                             {
940                                 msg = msg.clone();
941                                 msg.setFinal( r.isFinal() );
942                                 msg.setOverride( r.isOverride() );
943 
944                                 final Node<Message> node = new Node<Message>(
945                                     declaration, null, null, descendant, msg, msg.isFinal(), msg.isOverride() );
946 
947                                 node.getModifiablePath().addAll( path );
948 
949                                 addNode( map( this.messages, context ), node, node.getModelObject().getName() );
950                             }
951                         }
952                     }
953                 }
954             }
955 
956             if ( declaration.getProperties() != null )
957             {
958                 for ( int i = 0, s0 = declaration.getProperties().getProperty().size(); i < s0; i++ )
959                 {
960                     final Property p = declaration.getProperties().getProperty().get( i );
961                     final Node<Property> node =
962                         new Node<Property>( declaration, null, null, descendant, p, p.isFinal(), p.isOverride() );
963 
964                     node.getModifiablePath().addAll( path );
965 
966                     addNode( map( this.properties, context ), node, node.getModelObject().getName() );
967                 }
968 
969                 if ( !declaration.getProperties().getReference().isEmpty() )
970                 {
971                     final Module m = this.modules.getModuleOfImplementation( declaration.getIdentifier() );
972 
973                     if ( m != null && m.getProperties() != null )
974                     {
975                         for ( int i = 0, s0 = declaration.getProperties().getReference().size(); i < s0; i++ )
976                         {
977                             final PropertyReference r = declaration.getProperties().getReference().get( i );
978                             Property p = m.getProperties().getProperty( r.getName() );
979 
980                             if ( p != null )
981                             {
982                                 p = p.clone();
983                                 p.setFinal( r.isFinal() );
984                                 p.setOverride( r.isOverride() );
985 
986                                 final Node<Property> node = new Node<Property>(
987                                     declaration, null, null, descendant, p, p.isFinal(), p.isOverride() );
988 
989                                 node.getModifiablePath().addAll( path );
990 
991                                 addNode( map( this.properties, context ), node, node.getModelObject().getName() );
992                             }
993                         }
994                     }
995                 }
996             }
997 
998             if ( declaration.getSpecifications() != null )
999             {
1000                 for ( int i = 0, s0 = declaration.getSpecifications().getReference().size(); i < s0; i++ )
1001                 {
1002                     final SpecificationReference r = declaration.getSpecifications().getReference().get( i );
1003                     final Node<SpecificationReference> node = new Node<SpecificationReference>(
1004                         declaration, null, null, descendant, r, r.isFinal(), r.isOverride() );
1005 
1006                     node.getModifiablePath().addAll( path );
1007 
1008                     addNode( map( this.specReferences, context ), node, node.getModelObject().getIdentifier() );
1009 
1010                     final Specification s = this.modules.getSpecification( r.getIdentifier() );
1011 
1012                     if ( s != null && s.getProperties() != null )
1013                     {
1014                         for ( int j = 0, s1 = s.getProperties().getProperty().size(); j < s1; j++ )
1015                         {
1016                             final Property p = s.getProperties().getProperty().get( j );
1017                             final Node<Property> n =
1018                                 new Node<Property>( declaration, s, null, descendant, p, p.isFinal(), p.isOverride() );
1019 
1020                             n.getModifiablePath().addAll( path );
1021 
1022                             addNode( map( this.properties, context ), n, n.getModelObject().getName() );
1023                         }
1024                     }
1025                 }
1026             }
1027 
1028             if ( !declaration.getAny().isEmpty() )
1029             {
1030                 for ( int i = 0, s0 = declaration.getAny().size(); i < s0; i++ )
1031                 {
1032                     final Object any = declaration.getAny().get( i );
1033 
1034                     if ( any instanceof Element )
1035                     {
1036                         final Element e = (Element) any;
1037                         final Node<Element> node =
1038                             new Node<Element>( declaration, null, null, descendant, e, false, false );
1039 
1040                         node.getModifiablePath().addAll( path );
1041 
1042                         addNode( map( this.xmlElements, context ), node, getXmlElementName( e ) );
1043                         continue;
1044                     }
1045 
1046                     if ( any instanceof JAXBElement<?> )
1047                     {
1048                         final JAXBElement<?> e = (JAXBElement<?>) any;
1049                         boolean _final = false;
1050                         boolean override = false;
1051 
1052                         if ( e.getValue() instanceof Inheritable )
1053                         {
1054                             _final = ( (Inheritable) e.getValue() ).isFinal();
1055                             override = ( (Inheritable) e.getValue() ).isOverride();
1056                         }
1057 
1058                         final Node<JAXBElement<?>> node =
1059                             new Node<JAXBElement<?>>( declaration, null, null, descendant, e, _final, override );
1060 
1061                         node.getModifiablePath().addAll( path );
1062 
1063                         addNode( map( this.jaxbElements, context ), node, e.getName() );
1064                         continue;
1065                     }
1066                 }
1067             }
1068 
1069             if ( declaration.getImplementations() != null
1070                      && !declaration.getImplementations().getReference().isEmpty() )
1071             {
1072                 boolean all_cyclic = true;
1073 
1074                 for ( int i = 0, s0 = declaration.getImplementations().getReference().size(); i < s0; i++ )
1075                 {
1076                     final ImplementationReference r = declaration.getImplementations().getReference().get( i );
1077                     final Node<ImplementationReference> node = new Node<ImplementationReference>(
1078                         declaration, null, null, descendant, r, r.isFinal(), r.isOverride() );
1079 
1080                     node.getModifiablePath().addAll( path );
1081 
1082                     final Implementation ancestor = this.modules.getImplementation( r.getIdentifier() );
1083 
1084                     boolean cycle = false;
1085                     if ( ancestor != null && contextImplementations.containsKey( ancestor.getIdentifier() ) )
1086                     {
1087                         for ( int j = 0, s1 = path.size(); j < s1; j++ )
1088                         {
1089                             final Node<Implementation> n = path.get( j );
1090 
1091                             if ( n.getModelObject().getIdentifier().equals( ancestor.getIdentifier() ) )
1092                             {
1093                                 cycle = true;
1094                                 node.getModifiablePath().add( n );
1095                                 break;
1096                             }
1097                         }
1098                     }
1099 
1100                     if ( cycle )
1101                     {
1102                         addNode( this.cyclicImplReferences, node, context );
1103                     }
1104                     else
1105                     {
1106                         all_cyclic = false;
1107                         addNode( map( this.implReferences, context ), node, node.getModelObject().getIdentifier() );
1108                         this.collectNodes( context, ancestor, declarationNode, path );
1109                     }
1110                 }
1111 
1112                 if ( all_cyclic )
1113                 {
1114                     map( this.sourceNodes, context ).
1115                         put( declarationNode.getModelObject().getIdentifier(), declarationNode );
1116 
1117                 }
1118             }
1119             else
1120             {
1121                 map( this.sourceNodes, context ).
1122                     put( declarationNode.getModelObject().getIdentifier(), declarationNode );
1123 
1124             }
1125 
1126             path.removeLast();
1127         }
1128     }
1129 
1130     private void collectEffectiveNodes( final String context, final Node<Implementation> node )
1131     {
1132         final Map<String, Set<Node<SpecificationReference>>> directSpecificationReferences =
1133             getDirectEffectiveNodes( map( this.specReferences, context ), node.getModelObject().getIdentifier() );
1134 
1135         final Map<String, Set<Node<Dependency>>> directDependencies =
1136             getDirectEffectiveNodes( map( this.dependencies, context ), node.getModelObject().getIdentifier() );
1137 
1138         final Map<String, Set<Node<Message>>> directMessages =
1139             getDirectEffectiveNodes( map( this.messages, context ), node.getModelObject().getIdentifier() );
1140 
1141         final Map<String, Set<Node<Property>>> directProperties =
1142             getDirectEffectiveNodes( map( this.properties, context ), node.getModelObject().getIdentifier() );
1143 
1144         final Map<String, Set<Node<ImplementationReference>>> directImplementationReferences =
1145             getDirectEffectiveNodes( map( this.implReferences, context ), node.getModelObject().getIdentifier() );
1146 
1147         final Map<QName, Set<Node<Element>>> directXmlElements =
1148             getDirectEffectiveNodes( map( this.xmlElements, context ), node.getModelObject().getIdentifier() );
1149 
1150         final Map<QName, Set<Node<JAXBElement<?>>>> directJaxbElements =
1151             getDirectEffectiveNodes( map( this.jaxbElements, context ), node.getModelObject().getIdentifier() );
1152 
1153         overrideNodes( map( this.effSpecReferences, context ), node, directSpecificationReferences );
1154         overrideNodes( map( this.effImplReferences, context ), node, directImplementationReferences );
1155         overrideNodes( map( this.effDependencies, context ), node, directDependencies );
1156         overrideNodes( map( this.effMessages, context ), node, directMessages );
1157         overrideNodes( map( this.effProperties, context ), node, directProperties );
1158         overrideNodes( map( this.effJaxbElements, context ), node, directJaxbElements );
1159         overrideNodes( map( this.effXmlElements, context ), node, directXmlElements );
1160 
1161         this.addClassDeclarationNodes( context, node );
1162 
1163         final Map<String, Set<Node<SpecificationReference>>> ancestorSpecificationReferences =
1164             getEffectiveNodes( this.effSpecReferences, context, node.getModelObject().getIdentifier() );
1165 
1166         final Map<String, Set<Node<Dependency>>> ancestorDependencies =
1167             getEffectiveNodes( this.effDependencies, context, node.getModelObject().getIdentifier() );
1168 
1169         final Map<String, Set<Node<Message>>> ancestorMessages =
1170             getEffectiveNodes( this.effMessages, context, node.getModelObject().getIdentifier() );
1171 
1172         final Map<String, Set<Node<Property>>> ancestorProperties =
1173             getEffectiveNodes( this.effProperties, context, node.getModelObject().getIdentifier() );
1174 
1175         final Map<String, Set<Node<ImplementationReference>>> ancestorImplementationReferences =
1176             getEffectiveNodes( this.effImplReferences, context, node.getModelObject().getIdentifier() );
1177 
1178         final Map<QName, Set<Node<Element>>> ancestorXmlElements =
1179             getEffectiveNodes( this.effXmlElements, context, node.getModelObject().getIdentifier() );
1180 
1181         final Map<QName, Set<Node<JAXBElement<?>>>> ancestorJaxbElements =
1182             getEffectiveNodes( this.effJaxbElements, context, node.getModelObject().getIdentifier() );
1183 
1184         if ( node.getDescendant() != null )
1185         {
1186             if ( ancestorSpecificationReferences != null )
1187             {
1188                 inheritNodes( map( this.effSpecReferences, context ), ancestorSpecificationReferences,
1189                               node.getDescendant() );
1190 
1191             }
1192 
1193             if ( ancestorDependencies != null )
1194             {
1195                 inheritNodes( map( this.effDependencies, context ), ancestorDependencies,
1196                               node.getDescendant() );
1197 
1198             }
1199 
1200             if ( ancestorProperties != null )
1201             {
1202                 inheritNodes( map( this.effProperties, context ), ancestorProperties, node.getDescendant() );
1203             }
1204 
1205             if ( ancestorMessages != null )
1206             {
1207                 inheritNodes( map( this.effMessages, context ), ancestorMessages, node.getDescendant() );
1208             }
1209 
1210             if ( ancestorImplementationReferences != null )
1211             {
1212                 inheritNodes( map( this.effImplReferences, context ), ancestorImplementationReferences,
1213                               node.getDescendant() );
1214 
1215             }
1216 
1217             if ( ancestorXmlElements != null )
1218             {
1219                 inheritNodes( map( this.effXmlElements, context ), ancestorXmlElements,
1220                               node.getDescendant() );
1221 
1222             }
1223 
1224             if ( ancestorJaxbElements != null )
1225             {
1226                 inheritNodes( map( this.effJaxbElements, context ), ancestorJaxbElements,
1227                               node.getDescendant() );
1228 
1229             }
1230 
1231             collectEffectiveNodes( context, node.getDescendant() );
1232         }
1233     }
1234 
1235     private void addClassDeclarationNodes( final String context, final Node<Implementation> node )
1236     {
1237         final Implementation classDeclaration = this.getClassDeclaration( node.getModelObject() );
1238 
1239         if ( classDeclaration != null )
1240         {
1241             this.prepareContext( classDeclaration.getIdentifier() );
1242 
1243             Map<String, Set<Node<Dependency>>> effectiveDependencies =
1244                 getEffectiveNodes( this.effDependencies, context, node.getModelObject().getIdentifier() );
1245 
1246             Map<String, Set<Node<Message>>> effectiveMessages =
1247                 getEffectiveNodes( this.effMessages, context, node.getModelObject().getIdentifier() );
1248 
1249             Map<String, Set<Node<Property>>> effectiveProperties =
1250                 getEffectiveNodes( this.effProperties, context, node.getModelObject().getIdentifier() );
1251 
1252             Map<String, Set<Node<SpecificationReference>>> effectiveSpecificationReferences =
1253                 getEffectiveNodes( this.effSpecReferences, context, node.getModelObject().getIdentifier() );
1254 
1255             Map<QName, Set<Node<Element>>> effectiveXmlElements =
1256                 getEffectiveNodes( this.effXmlElements, context, node.getModelObject().getIdentifier() );
1257 
1258             Map<QName, Set<Node<JAXBElement<?>>>> effectiveJaxbElements =
1259                 getEffectiveNodes( this.effJaxbElements, context, node.getModelObject().getIdentifier() );
1260 
1261             final Map<String, Set<Node<Dependency>>> declDependencies =
1262                 getEffectiveNodes( this.effDependencies, classDeclaration.getIdentifier(),
1263                                    classDeclaration.getIdentifier() );
1264 
1265             final Map<String, Set<Node<Message>>> declMessages =
1266                 getEffectiveNodes( this.effMessages, classDeclaration.getIdentifier(),
1267                                    classDeclaration.getIdentifier() );
1268 
1269             final Map<String, Set<Node<Property>>> declProperties =
1270                 getEffectiveNodes( this.effProperties, classDeclaration.getIdentifier(),
1271                                    classDeclaration.getIdentifier() );
1272 
1273             final Map<String, Set<Node<SpecificationReference>>> declSpecReferences =
1274                 getEffectiveNodes( this.effSpecReferences, classDeclaration.getIdentifier(),
1275                                    classDeclaration.getIdentifier() );
1276 
1277             final Map<QName, Set<Node<Element>>> declXmlElements =
1278                 getEffectiveNodes( this.effXmlElements, classDeclaration.getIdentifier(),
1279                                    classDeclaration.getIdentifier() );
1280 
1281             final Map<QName, Set<Node<JAXBElement<?>>>> declJaxbElements =
1282                 getEffectiveNodes( this.effJaxbElements, classDeclaration.getIdentifier(),
1283                                    classDeclaration.getIdentifier() );
1284 
1285             if ( declDependencies != null )
1286             {
1287                 if ( effectiveDependencies == null )
1288                 {
1289                     effectiveDependencies = newMap();
1290                     map( this.effDependencies, context ).
1291                         put( node.getModelObject().getIdentifier(), effectiveDependencies );
1292 
1293                 }
1294 
1295                 for ( final Map.Entry<String, Set<Node<Dependency>>> e : declDependencies.entrySet() )
1296                 {
1297                     final Set<Node<Dependency>> set = newSet( e.getValue().size() );
1298 
1299                     for ( final Node<Dependency> n : e.getValue() )
1300                     {
1301                         final Node<Dependency> effNode = new Node<Dependency>(
1302                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1303                             n.isFinal(), n.isOverride() );
1304 
1305                         effNode.getModifiablePath().addAll( n.getPath() );
1306                         set.add( effNode );
1307 
1308                         addNode( map( this.dependencies, context ), effNode, e.getKey() );
1309                     }
1310 
1311                     if ( effectiveDependencies.containsKey( e.getKey() ) )
1312                     {
1313                         for ( final Node<Dependency> effNode : effectiveDependencies.get( e.getKey() ) )
1314                         {
1315                             effNode.getModifiableOverriddenNodes().addAll( set );
1316                         }
1317                     }
1318                     else
1319                     {
1320                         effectiveDependencies.put( e.getKey(), set );
1321                     }
1322                 }
1323             }
1324 
1325             if ( declSpecReferences != null )
1326             {
1327                 if ( effectiveSpecificationReferences == null )
1328                 {
1329                     effectiveSpecificationReferences = newMap();
1330                     map( this.effSpecReferences, context ).
1331                         put( node.getModelObject().getIdentifier(), effectiveSpecificationReferences );
1332 
1333                 }
1334 
1335                 for ( final Map.Entry<String, Set<Node<SpecificationReference>>> e : declSpecReferences.entrySet() )
1336                 {
1337                     final Set<Node<SpecificationReference>> set = newSet( e.getValue().size() );
1338 
1339                     for ( final Node<SpecificationReference> n : e.getValue() )
1340                     {
1341                         final Node<SpecificationReference> effNode = new Node<SpecificationReference>(
1342                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1343                             n.isFinal(), n.isOverride() );
1344 
1345                         effNode.getModifiablePath().addAll( n.getPath() );
1346                         set.add( effNode );
1347 
1348                         addNode( map( this.specReferences, context ), effNode, e.getKey() );
1349                     }
1350 
1351                     if ( effectiveSpecificationReferences.containsKey( e.getKey() ) )
1352                     {
1353                         for ( final Node<SpecificationReference> effNode
1354                                   : effectiveSpecificationReferences.get( e.getKey() ) )
1355                         {
1356                             effNode.getModifiableOverriddenNodes().addAll( set );
1357                         }
1358                     }
1359                     else
1360                     {
1361                         effectiveSpecificationReferences.put( e.getKey(), set );
1362                     }
1363                 }
1364             }
1365 
1366             if ( declMessages != null )
1367             {
1368                 if ( effectiveMessages == null )
1369                 {
1370                     effectiveMessages = newMap();
1371                     map( this.effMessages, context ).
1372                         put( node.getModelObject().getIdentifier(), effectiveMessages );
1373 
1374                 }
1375 
1376                 for ( final Map.Entry<String, Set<Node<Message>>> e : declMessages.entrySet() )
1377                 {
1378                     final Set<Node<Message>> set = newSet( e.getValue().size() );
1379 
1380                     for ( final Node<Message> n : e.getValue() )
1381                     {
1382                         final Node<Message> effNode = new Node<Message>(
1383                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1384                             n.isFinal(), n.isOverride() );
1385 
1386                         effNode.getModifiablePath().addAll( n.getPath() );
1387                         set.add( effNode );
1388 
1389                         addNode( map( this.messages, context ), effNode, e.getKey() );
1390                     }
1391 
1392                     if ( effectiveMessages.containsKey( e.getKey() ) )
1393                     {
1394                         for ( final Node<Message> effNode : effectiveMessages.get( e.getKey() ) )
1395                         {
1396                             effNode.getModifiableOverriddenNodes().addAll( set );
1397                         }
1398                     }
1399                     else
1400                     {
1401                         effectiveMessages.put( e.getKey(), set );
1402                     }
1403                 }
1404             }
1405 
1406             if ( declProperties != null )
1407             {
1408                 if ( effectiveProperties == null )
1409                 {
1410                     effectiveProperties = newMap();
1411                     map( this.effProperties, context ).
1412                         put( node.getModelObject().getIdentifier(), effectiveProperties );
1413 
1414                 }
1415 
1416                 for ( final Map.Entry<String, Set<Node<Property>>> e : declProperties.entrySet() )
1417                 {
1418                     final Set<Node<Property>> set = newSet( e.getValue().size() );
1419 
1420                     for ( final Node<Property> n : e.getValue() )
1421                     {
1422                         final Node<Property> effNode = new Node<Property>(
1423                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1424                             n.isFinal(), n.isOverride() );
1425 
1426                         effNode.getModifiablePath().addAll( n.getPath() );
1427                         set.add( effNode );
1428 
1429                         addNode( map( this.properties, context ), effNode, e.getKey() );
1430                     }
1431 
1432                     if ( effectiveProperties.containsKey( e.getKey() ) )
1433                     {
1434                         for ( final Node<Property> effNode : effectiveProperties.get( e.getKey() ) )
1435                         {
1436                             effNode.getModifiableOverriddenNodes().addAll( set );
1437                         }
1438                     }
1439                     else
1440                     {
1441                         effectiveProperties.put( e.getKey(), set );
1442                     }
1443                 }
1444             }
1445 
1446             if ( declXmlElements != null )
1447             {
1448                 if ( effectiveXmlElements == null )
1449                 {
1450                     effectiveXmlElements = newMap();
1451                     map( this.effXmlElements, context ).
1452                         put( node.getModelObject().getIdentifier(), effectiveXmlElements );
1453 
1454                 }
1455 
1456                 for ( final Map.Entry<QName, Set<Node<Element>>> e : declXmlElements.entrySet() )
1457                 {
1458                     final Set<Node<Element>> set = newSet( e.getValue().size() );
1459 
1460                     for ( final Node<Element> n : e.getValue() )
1461                     {
1462                         final Node<Element> effNode = new Node<Element>(
1463                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1464                             n.isFinal(), n.isOverride() );
1465 
1466                         effNode.getModifiablePath().addAll( n.getPath() );
1467                         set.add( effNode );
1468 
1469                         addNode( map( this.xmlElements, context ), effNode, e.getKey() );
1470                     }
1471 
1472                     if ( effectiveXmlElements.containsKey( e.getKey() ) )
1473                     {
1474                         for ( final Node<Element> effNode : effectiveXmlElements.get( e.getKey() ) )
1475                         {
1476                             effNode.getModifiableOverriddenNodes().addAll( set );
1477                         }
1478                     }
1479                     else
1480                     {
1481                         effectiveXmlElements.put( e.getKey(), set );
1482                     }
1483                 }
1484             }
1485 
1486             if ( declJaxbElements != null )
1487             {
1488                 if ( effectiveJaxbElements == null )
1489                 {
1490                     effectiveJaxbElements = newMap();
1491                     map( this.effJaxbElements, context ).
1492                         put( node.getModelObject().getIdentifier(), effectiveJaxbElements );
1493 
1494                 }
1495 
1496                 for ( final Map.Entry<QName, Set<Node<JAXBElement<?>>>> e : declJaxbElements.entrySet() )
1497                 {
1498                     final Set<Node<JAXBElement<?>>> set = newSet( e.getValue().size() );
1499 
1500                     for ( final Node<JAXBElement<?>> n : e.getValue() )
1501                     {
1502                         final Node<JAXBElement<?>> effNode = new Node<JAXBElement<?>>(
1503                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1504                             n.isFinal(), n.isOverride() );
1505 
1506                         effNode.getModifiablePath().addAll( n.getPath() );
1507                         set.add( effNode );
1508 
1509                         addNode( map( this.jaxbElements, context ), effNode, e.getKey() );
1510                     }
1511 
1512                     if ( effectiveJaxbElements.containsKey( e.getKey() ) )
1513                     {
1514                         for ( final Node<JAXBElement<?>> effNode : effectiveJaxbElements.get( e.getKey() ) )
1515                         {
1516                             effNode.getModifiableOverriddenNodes().addAll( set );
1517                         }
1518                     }
1519                     else
1520                     {
1521                         effectiveJaxbElements.put( e.getKey(), set );
1522                     }
1523                 }
1524             }
1525         }
1526     }
1527 
1528     private Implementation getClassDeclaration( final Implementation implementation )
1529     {
1530         Implementation declaration = null;
1531 
1532         if ( implementation.getClazz() != null && !implementation.isClassDeclaration() )
1533         {
1534             find:
1535             for ( int i = 0, s0 = this.modules.getModule().size(); i < s0; i++ )
1536             {
1537                 final Module candidateModule = this.modules.getModule().get( i );
1538 
1539                 if ( candidateModule.getImplementations() != null )
1540                 {
1541                     for ( int j = 0, s1 = candidateModule.getImplementations().getImplementation().size(); j < s1; j++ )
1542                     {
1543                         final Implementation candidate =
1544                             candidateModule.getImplementations().getImplementation().get( j );
1545 
1546                         if ( candidate.isClassDeclaration()
1547                                  && candidate.getClazz().equals( implementation.getClazz() ) )
1548                         {
1549                             declaration = candidate;
1550                             break find;
1551                         }
1552                     }
1553                 }
1554             }
1555         }
1556 
1557         return declaration;
1558     }
1559 
1560     private static <T, K> void addNode( final Map<K, Set<Node<T>>> map, final Node<T> node, final K key )
1561     {
1562         Set<Node<T>> set = map.get( key );
1563 
1564         if ( set == null )
1565         {
1566             set = newSet();
1567             map.put( key, set );
1568         }
1569 
1570         set.add( node );
1571     }
1572 
1573     private static <T, K> void overrideNodes( final Map<String, Map<K, Set<Node<T>>>> effective,
1574                                               final Node<Implementation> implementation,
1575                                               final Map<K, Set<Node<T>>> directNodes )
1576     {
1577         for ( final Map.Entry<K, Set<Node<T>>> e : directNodes.entrySet() )
1578         {
1579             final Set<Node<T>> effectiveNodes =
1580                 effectiveNodes( effective, implementation.getModelObject().getIdentifier(), e.getKey() );
1581 
1582             final Set<Node<T>> overridingNodes = newSet();
1583 
1584             for ( final Node<T> directNode : e.getValue() )
1585             {
1586                 for ( final Iterator<Node<T>> it = effectiveNodes.iterator(); it.hasNext(); )
1587                 {
1588                     final Node<T> effectiveNode = it.next();
1589 
1590                     if ( isOverriding( effectiveNode, directNode ) )
1591                     {
1592                         it.remove();
1593 
1594                         if ( directNode != effectiveNode )
1595                         {
1596                             directNode.getModifiableOverriddenNodes().add( effectiveNode );
1597                         }
1598                     }
1599                 }
1600 
1601                 boolean overriddenByAncestor = false;
1602 
1603                 if ( directNode.getSpecification() != null )
1604                 {
1605                     for ( final Node<T> effectiveNode : effectiveNodes )
1606                     {
1607                         if ( effectiveNode.getSpecification() == null )
1608                         {
1609                             overriddenByAncestor = true;
1610                             effectiveNode.getModifiableOverriddenNodes().add( directNode );
1611                         }
1612                     }
1613                 }
1614 
1615                 if ( !overriddenByAncestor )
1616                 {
1617                     overridingNodes.add( directNode );
1618                 }
1619             }
1620 
1621             effectiveNodes.addAll( overridingNodes );
1622         }
1623     }
1624 
1625     private static <K, V, T> Map<K, V> map( final Map<T, Map<K, V>> map, final T context )
1626     {
1627         Map<K, V> contextMap = map.get( context );
1628 
1629         if ( contextMap == null )
1630         {
1631             contextMap = newMap();
1632             map.put( context, contextMap );
1633         }
1634 
1635         return contextMap;
1636     }
1637 
1638     private static <K, V> Set<Node<V>> nodes( final Map<K, Set<Node<V>>> map, final K key )
1639     {
1640         Set<Node<V>> nodes = map.get( key );
1641 
1642         if ( nodes == null )
1643         {
1644             nodes = newSet();
1645             map.put( key, nodes );
1646         }
1647 
1648         return nodes;
1649     }
1650 
1651     private static <K, V> Set<Node<V>> effectiveNodes( final Map<String, Map<K, Set<Node<V>>>> map,
1652                                                        final String context, final K key )
1653     {
1654         return nodes( map( map, context ), key );
1655     }
1656 
1657     private static <T, K> void inheritNodes(
1658         final Map<String, Map<K, Set<Node<T>>>> effective, final Map<K, Set<Node<T>>> ancestor,
1659         final Node<Implementation> descendant )
1660     {
1661         for ( Map.Entry<K, Set<Node<T>>> e : ancestor.entrySet() )
1662         {
1663             for ( final Node<T> inherit : e.getValue() )
1664             {
1665                 if ( isInheritableNode( inherit ) )
1666                 {
1667                     effectiveNodes( effective, descendant.getModelObject().getIdentifier(), e.getKey() ).add( inherit );
1668                 }
1669             }
1670         }
1671     }
1672 
1673     private static <T, K> Map<K, Set<Node<T>>> getDirectEffectiveNodes( final Map<K, Set<Node<T>>> map,
1674                                                                         final String origin )
1675     {
1676         final Map<K, Set<Node<T>>> declarationMap = newMap( map.size() );
1677 
1678         for ( final Map.Entry<K, Set<Node<T>>> e : map.entrySet() )
1679         {
1680             final Set<Node<T>> set = nodes( declarationMap, e.getKey() );
1681 
1682             for ( final Node<T> n : e.getValue() )
1683             {
1684                 if ( isDirectEffectiveNode( n, origin ) )
1685                 {
1686                     set.add( n );
1687                 }
1688             }
1689 
1690             for ( final Node<T> n : e.getValue() )
1691             {
1692                 if ( isDirectSpecifiedNode( n, origin ) )
1693                 {
1694                     boolean add = true;
1695 
1696                     for ( final Node<T> override : set )
1697                     {
1698                         if ( override.getSpecification() == null )
1699                         {
1700                             override.getModifiableOverriddenNodes().add( n );
1701                             add = false;
1702                         }
1703                     }
1704 
1705                     if ( add )
1706                     {
1707                         set.add( n );
1708                     }
1709                 }
1710             }
1711         }
1712 
1713         return declarationMap;
1714     }
1715 
1716     private static <T, K> Map<K, Set<Node<T>>> getEffectiveNodes(
1717         final Map<String, Map<String, Map<K, Set<Node<T>>>>> effective, final String context,
1718         final String implementation )
1719     {
1720         return map( effective, context ).get( implementation );
1721     }
1722 
1723     private static boolean isDirectNode( final Node<?> node, final String implementation )
1724     {
1725         return implementation.equals( node.getImplementation().getIdentifier() );
1726     }
1727 
1728     private static boolean isDirectEffectiveNode( final Node<?> node, final String implementation )
1729     {
1730         return isDirectNode( node, implementation ) && node.getClassDeclaration() == null
1731                    && node.getSpecification() == null;
1732 
1733     }
1734 
1735     private static boolean isDirectSpecifiedNode( final Node<?> node, final String implementation )
1736     {
1737         return isDirectNode( node, implementation ) && node.getClassDeclaration() == null
1738                    && node.getSpecification() != null;
1739 
1740     }
1741 
1742     private static boolean isOverriding( final Node<?> node, final Node<?> override )
1743     {
1744         if ( override.getSpecification() != null )
1745         {
1746             if ( node.getSpecification() == null )
1747             {
1748                 return false;
1749             }
1750             else if ( !override.getSpecification().getIdentifier().equals( node.getSpecification().getIdentifier() ) )
1751             {
1752                 return false;
1753             }
1754         }
1755 
1756         return true;
1757     }
1758 
1759     private static boolean isInheritableNode( final Node<?> node )
1760     {
1761         return node.getClassDeclaration() == null;
1762     }
1763 
1764     private static <K, V> Map<K, V> newMap()
1765     {
1766         return new HashMap<K, V>();
1767     }
1768 
1769     private static <K, V> Map<K, V> newMap( final int initialCapacity )
1770     {
1771         return new HashMap<K, V>( initialCapacity );
1772     }
1773 
1774     private static <T> Set<T> newSet()
1775     {
1776         return new HashSet<T>();
1777     }
1778 
1779     private static <T> Set<T> newSet( final int initialCapacity )
1780     {
1781         return new HashSet<T>( initialCapacity );
1782     }
1783 
1784     private static <T> Set<T> newSet( final Collection<? extends T> col )
1785     {
1786         return new HashSet<T>( col );
1787     }
1788 
1789     private static <T> Set<T> unmodifiableSet( final Set<T> set )
1790     {
1791         return set != null ? Collections.unmodifiableSet( set ) : Collections.<T>emptySet();
1792     }
1793 
1794     private static QName getXmlElementName( final Element element )
1795     {
1796         if ( element.getNamespaceURI() != null )
1797         {
1798             return new QName( element.getNamespaceURI(), element.getLocalName() );
1799         }
1800         else
1801         {
1802             return new QName( element.getLocalName() );
1803         }
1804     }
1805 
1806 }