View Javadoc

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