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 4777 2013-04-13 17:55:38Z 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 4777 2013-04-13 17:55:38Z 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 4777 2013-04-13 17:55:38Z 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 reference identifier. */
282     private final Map<String, Set<Node<ImplementationReference>>> cyclicImplReferences = newMap();
283 
284     /** {@code ImplementationReference} nodes by context and implementation identifier. */
285     private final Map<String, Map<String, Map<String, Set<Node<ImplementationReference>>>>> effImplReferences =
286         newMap();
287 
288     /** {@code Element} nodes by context and qualified name. */
289     private final Map<String, Map<QName, Set<Node<Element>>>> xmlElements = newMap();
290 
291     /** {@code Element} nodes by context and implementation identifier. */
292     private final Map<String, Map<String, Map<QName, Set<Node<Element>>>>> effXmlElements = newMap();
293 
294     /** {@code JAXBElement} nodes by context and qualified name. */
295     private final Map<String, Map<QName, Set<Node<JAXBElement<?>>>>> jaxbElements = newMap();
296 
297     /** {@code JAXBElement} nodes by context and implementation identifier. */
298     private final Map<String, Map<String, Map<QName, Set<Node<JAXBElement<?>>>>>> effJaxbElements =
299         newMap();
300 
301     /** {@code Implementation} nodes by context and implementation identifier. */
302     private final Map<String, Map<String, Node<Implementation>>> implementations = newMap();
303 
304     /** Source nodes of a hierarchy by context and implementation identifier. */
305     private final Map<String, Map<String, Node<Implementation>>> sourceNodes = newMap();
306 
307     /** Context states by context identifier. */
308     private final Map<String, ContextState> contextStates = newMap();
309 
310     /**
311      * Creates a new {@code InheritanceModel} instance.
312      *
313      * @param modules The modules backing the model.
314      *
315      * @throws NullPointerException if {@code modules} is {@code null}.
316      *
317      * @see Modules#clone()
318      */
319     public InheritanceModel( final Modules modules )
320     {
321         super();
322 
323         if ( modules == null )
324         {
325             throw new NullPointerException( "modules" );
326         }
327 
328         this.modules = modules.clone();
329     }
330 
331     /**
332      * Gets a set holding source nodes of an implementation.
333      *
334      * @param implementation The identifier of the implementation to get source nodes of.
335      *
336      * @return An unmodifiable set holding source nodes of the implementation identified by {@code implementation}.
337      *
338      * @throws NullPointerException if {@code implementation} is {@code null}.
339      *
340      * @see Node#getDescendant()
341      */
342     public Set<Node<Implementation>> getSourceNodes( final String implementation )
343     {
344         if ( implementation == null )
345         {
346             throw new NullPointerException( "implementation" );
347         }
348 
349         this.prepareContext( implementation );
350         final Collection<Node<Implementation>> col = map( this.sourceNodes, implementation ).values();
351         return unmodifiableSet( newSet( col ) );
352     }
353 
354     /**
355      * Gets a set holding implementation reference nodes of an implementation causing a cycle.
356      *
357      * @param implementation The identifier of the implementation to get implementation reference nodes causing a cycle
358      * of.
359      *
360      * @return An unmodifiable set holding implementation reference nodes of the implementation identified by
361      * {@code implementation} causing a cycle.
362      *
363      * @throws NullPointerException if {@code implementation} is {@code null}.
364      *
365      * @since 1.5
366      *
367      * @see Node#getPath()
368      */
369     public Set<Node<ImplementationReference>> getCycleNodes( final String implementation )
370     {
371         if ( implementation == null )
372         {
373             throw new NullPointerException( "implementation" );
374         }
375 
376         this.prepareContext( implementation );
377         return unmodifiableSet( nodes( this.cyclicImplReferences, implementation ) );
378     }
379 
380     /**
381      * Gets a set holding the names of all dependencies of an implementation.
382      *
383      * @param implementation The identifier of the implementation to get the names of all dependencies of.
384      *
385      * @return An unmodifiable set holding the names of all dependencies of the implementation identified by
386      * {@code implementation}.
387      *
388      * @throws NullPointerException if {@code implementation} is {@code null}.
389      */
390     public Set<String> getDependencyNames( final String implementation )
391     {
392         if ( implementation == null )
393         {
394             throw new NullPointerException( "implementation" );
395         }
396 
397         this.prepareContext( implementation );
398         return Collections.unmodifiableSet( map( this.dependencies, implementation ).keySet() );
399     }
400 
401     /**
402      * Gets a set holding effective dependency nodes of an implementation.
403      *
404      * @param implementation The identifier of the implementation to get effective dependency nodes of.
405      * @param name The dependency name to get effective nodes for.
406      *
407      * @return An unmodifiable set holding effective dependency nodes matching {@code name} of the implementation
408      * identified by {@code implementation}.
409      *
410      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
411      *
412      * @see #getDependencyNames(java.lang.String)
413      */
414     public Set<Node<Dependency>> getDependencyNodes( final String implementation, final String name )
415     {
416         if ( implementation == null )
417         {
418             throw new NullPointerException( "implementation" );
419         }
420         if ( name == null )
421         {
422             throw new NullPointerException( "name" );
423         }
424 
425         this.prepareContext( implementation );
426         Set<Node<Dependency>> set = null;
427 
428         final Map<String, Set<Node<Dependency>>> map =
429             getEffectiveNodes( this.effDependencies, implementation, implementation );
430 
431         if ( map != null )
432         {
433             set = map.get( name );
434         }
435 
436         return unmodifiableSet( set );
437     }
438 
439     /**
440      * Gets a set holding the identifiers of all implementation references of an implementation.
441      *
442      * @param implementation The identifier of the implementation to get the identifiers of all implementation
443      * references of.
444      *
445      * @return An unmodifiable set holding the identifiers of all implementation references of the implementation
446      * identified by {@code implementation}.
447      *
448      * @throws NullPointerException if {@code implementation} is {@code null}.
449      */
450     public Set<String> getImplementationReferenceIdentifiers( final String implementation )
451     {
452         if ( implementation == null )
453         {
454             throw new NullPointerException( "implementation" );
455         }
456 
457         this.prepareContext( implementation );
458         return Collections.unmodifiableSet( map( this.implReferences, implementation ).keySet() );
459     }
460 
461     /**
462      * Gets a set holding effective implementation reference nodes of an implementation.
463      *
464      * @param implementation The identifier of the implementation to get effective implementation reference nodes of.
465      * @param identifier The implementation reference identifier to get effective nodes for.
466      *
467      * @return An unmodifiable set holding effective implementation reference nodes matching {@code identifier} of the
468      * implementation identified by {@code implementation}.
469      *
470      * @throws NullPointerException if {@code implementation} or {@code identifier} is {@code null}.
471      *
472      * @see #getImplementationReferenceIdentifiers(java.lang.String)
473      */
474     public Set<Node<ImplementationReference>> getImplementationReferenceNodes( final String implementation,
475                                                                                final String identifier )
476     {
477         if ( implementation == null )
478         {
479             throw new NullPointerException( "implementation" );
480         }
481         if ( identifier == null )
482         {
483             throw new NullPointerException( "identifier" );
484         }
485 
486         this.prepareContext( implementation );
487         Set<Node<ImplementationReference>> set = null;
488         final Map<String, Set<Node<ImplementationReference>>> map =
489             getEffectiveNodes( this.effImplReferences, implementation, implementation );
490 
491         if ( map != null )
492         {
493             set = map.get( identifier );
494         }
495 
496         return unmodifiableSet( set );
497     }
498 
499     /**
500      * Gets a set holding the qualified names of all XML elements of an implementation.
501      *
502      * @param implementation The identifier of the implementation to get the qualified names of all XML elements of.
503      *
504      * @return An unmodifiable set holding the qualified names of all XML elements of the implementation identified by
505      * {@code implementation}.
506      *
507      * @throws NullPointerException if {@code implementation} is {@code null}.
508      */
509     public Set<QName> getJaxbElementNames( final String implementation )
510     {
511         if ( implementation == null )
512         {
513             throw new NullPointerException( "implementation" );
514         }
515 
516         this.prepareContext( implementation );
517         return Collections.unmodifiableSet( map( this.jaxbElements, implementation ).keySet() );
518     }
519 
520     /**
521      * Gets a set holding effective JAXB element nodes of an implementation.
522      *
523      * @param implementation The identifier of the implementation to get effective JAXB element nodes of.
524      * @param name The qualified JAXB element name to get effective nodes for.
525      *
526      * @return An unmodifiable set holding effective JAXB element nodes matching {@code name} of the implementation
527      * identified by {@code implementation}.
528      *
529      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
530      *
531      * @see #getJaxbElementNames(java.lang.String)
532      */
533     public Set<Node<JAXBElement<?>>> getJaxbElementNodes( final String implementation, final QName name )
534     {
535         if ( implementation == null )
536         {
537             throw new NullPointerException( "implementation" );
538         }
539         if ( name == null )
540         {
541             throw new NullPointerException( "name" );
542         }
543 
544         this.prepareContext( implementation );
545         Set<Node<JAXBElement<?>>> set = null;
546         final Map<QName, Set<Node<JAXBElement<?>>>> map =
547             getEffectiveNodes( this.effJaxbElements, implementation, implementation );
548 
549         if ( map != null )
550         {
551             set = map.get( name );
552         }
553 
554         return unmodifiableSet( set );
555     }
556 
557     /**
558      * Gets a set holding the names of all messages of an implementation.
559      *
560      * @param implementation The identifier of the implementation to get the names of all messages of.
561      *
562      * @return An unmodifiable set holding the names of all messages of the implementation identified by
563      * {@code implementation}.
564      *
565      * @throws NullPointerException if {@code implementation} is {@code null}.
566      */
567     public Set<String> getMessageNames( 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.messages, implementation ).keySet() );
576     }
577 
578     /**
579      * Gets a set holding effective message nodes of an implementation.
580      *
581      * @param implementation The identifier of the implementation to get effective message nodes of.
582      * @param name The message name to get effective nodes for.
583      *
584      * @return An unmodifiable set holding effective message 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 #getMessageNames(java.lang.String)
590      */
591     public Set<Node<Message>> getMessageNodes( final String implementation, final String 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<Message>> set = null;
604         final Map<String, Set<Node<Message>>> map =
605             getEffectiveNodes( this.effMessages, 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 properties of an implementation.
617      *
618      * @param implementation The identifier of the implementation to get the names of all properties of.
619      *
620      * @return An unmodifiable set holding the names of all properties of the implementation identified by
621      * {@code implementation}.
622      *
623      * @throws NullPointerException if {@code implementation} is {@code null}.
624      */
625     public Set<String> getPropertyNames( 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.properties, implementation ).keySet() );
634     }
635 
636     /**
637      * Gets a set holding effective property nodes of an implementation.
638      *
639      * @param implementation The identifier of the implementation to get effective property nodes of.
640      * @param name The property name to get effective nodes for.
641      *
642      * @return An unmodifiable set holding effective property 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 #getPropertyNames(java.lang.String)
648      */
649     public Set<Node<Property>> getPropertyNodes( 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<Property>> set = null;
662         final Map<String, Set<Node<Property>>> map =
663             getEffectiveNodes( this.effProperties, 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 identifiers of all specification references of an implementation.
675      *
676      * @param implementation The identifier of the implementation to get the identifiers of all specification references
677      * of.
678      *
679      * @return An unmodifiable set holding the identifiers of all specification references of the implementation
680      * identified by {@code implementation}.
681      *
682      * @throws NullPointerException if {@code implementation} is {@code null}.
683      */
684     public Set<String> getSpecificationReferenceIdentifiers( final String implementation )
685     {
686         if ( implementation == null )
687         {
688             throw new NullPointerException( "implementation" );
689         }
690 
691         this.prepareContext( implementation );
692         return Collections.unmodifiableSet( map( this.specReferences, implementation ).keySet() );
693     }
694 
695     /**
696      * Gets a set holding effective specification reference nodes of an implementation.
697      *
698      * @param implementation The identifier of the implementation to get effective specification reference nodes of.
699      * @param identifier The specification reference identifier to get effective nodes for.
700      *
701      * @return An unmodifiable set holding effective specification reference nodes matching {@code identifier} of the
702      * implementation identified by {@code implementation}.
703      *
704      * @throws NullPointerException if {@code implementation} or {@code identifier} is {@code null}.
705      *
706      * @see #getSpecificationReferenceIdentifiers(java.lang.String)
707      */
708     public Set<Node<SpecificationReference>> getSpecificationReferenceNodes( final String implementation,
709                                                                              final String identifier )
710     {
711         if ( implementation == null )
712         {
713             throw new NullPointerException( "implementation" );
714         }
715         if ( identifier == null )
716         {
717             throw new NullPointerException( "identifier" );
718         }
719 
720         this.prepareContext( implementation );
721         Set<Node<SpecificationReference>> set = null;
722         final Map<String, Set<Node<SpecificationReference>>> map =
723             getEffectiveNodes( this.effSpecReferences, implementation, implementation );
724 
725         if ( map != null )
726         {
727             set = map.get( identifier );
728         }
729 
730         return unmodifiableSet( set );
731     }
732 
733     /**
734      * Gets a set holding the qualified names of all XML elements of an implementation.
735      *
736      * @param implementation The identifier of the implementation to get the qualified names of all XML elements of.
737      *
738      * @return An unmodifiable set holding the qualified names of all XML elements of the implementation identified by
739      * {@code implementation}.
740      *
741      * @throws NullPointerException if {@code implementation} is {@code null}.
742      */
743     public Set<QName> getXmlElementNames( final String implementation )
744     {
745         if ( implementation == null )
746         {
747             throw new NullPointerException( "implementation" );
748         }
749 
750         this.prepareContext( implementation );
751         return Collections.unmodifiableSet( map( this.xmlElements, implementation ).keySet() );
752     }
753 
754     /**
755      * Gets a set holding effective XML element nodes of an implementation.
756      *
757      * @param implementation The identifier of the implementation to get effective XML element nodes of.
758      * @param name The qualified XML element name to get effective nodes for.
759      *
760      * @return An unmodifiable set holding effective XML element nodes matching {@code name} of the implementation
761      * identified by {@code implementation}.
762      *
763      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
764      *
765      * @see #getXmlElementNames(java.lang.String)
766      */
767     public Set<Node<Element>> getXmlElementNodes( final String implementation, final QName name )
768     {
769         if ( implementation == null )
770         {
771             throw new NullPointerException( "implementation" );
772         }
773         if ( name == null )
774         {
775             throw new NullPointerException( "name" );
776         }
777 
778         this.prepareContext( implementation );
779         Set<Node<Element>> set = null;
780         final Map<QName, Set<Node<Element>>> map =
781             getEffectiveNodes( this.effXmlElements, implementation, implementation );
782 
783         if ( map != null )
784         {
785             set = map.get( name );
786         }
787 
788         return unmodifiableSet( set );
789     }
790 
791     private void prepareContext( final String context )
792     {
793         ContextState state = this.contextStates.get( context );
794 
795         if ( state == null )
796         {
797             state = ContextState.PREPARING;
798             this.contextStates.put( context, state );
799 
800             final Implementation i = this.modules.getImplementation( context );
801 
802             if ( i != null )
803             {
804                 this.collectNodes( context, i, null, null );
805 
806                 for ( Node<Implementation> source : map( this.sourceNodes, context ).values() )
807                 {
808                     this.collectEffectiveNodes( context, source );
809                 }
810             }
811 
812             state = ContextState.PREPARED;
813             this.contextStates.put( context, state );
814         }
815 
816         assert state == ContextState.PREPARED :
817             "Unexpected context state '" + state + "' for context '" + context + "'.";
818 
819     }
820 
821     private void collectNodes( final String context, final Implementation declaration,
822                                final Node<Implementation> descendant, LinkedList<Node<Implementation>> path )
823     {
824         if ( path == null )
825         {
826             path = new LinkedList<Node<Implementation>>();
827         }
828 
829         final Map<String, Node<Implementation>> contextImplementations = map( this.implementations, context );
830 
831         if ( declaration != null && !contextImplementations.containsKey( declaration.getIdentifier() ) )
832         {
833             final Node<Implementation> declarationNode = new Node<Implementation>(
834                 declaration, null, null, descendant, declaration, declaration.isFinal(), false );
835 
836             declarationNode.getModifiablePath().addAll( path );
837 
838             contextImplementations.put( declaration.getIdentifier(), declarationNode );
839 
840             path.addLast( declarationNode );
841 
842             if ( declaration.getDependencies() != null )
843             {
844                 for ( int i = 0, s0 = declaration.getDependencies().getDependency().size(); i < s0; i++ )
845                 {
846                     final Dependency d = declaration.getDependencies().getDependency().get( i );
847                     final Node<Dependency> node =
848                         new Node<Dependency>( declaration, null, null, descendant, d, d.isFinal(), d.isOverride() );
849 
850                     node.getModifiablePath().addAll( path );
851 
852                     addNode( map( this.dependencies, context ), node, node.getModelObject().getName() );
853                 }
854             }
855 
856             if ( declaration.getMessages() != null )
857             {
858                 for ( int i = 0, s0 = declaration.getMessages().getMessage().size(); i < s0; i++ )
859                 {
860                     final Message m = declaration.getMessages().getMessage().get( i );
861                     final Node<Message> node =
862                         new Node<Message>( declaration, null, null, descendant, m, m.isFinal(), m.isOverride() );
863 
864                     node.getModifiablePath().addAll( path );
865 
866                     addNode( map( this.messages, context ), node, node.getModelObject().getName() );
867                 }
868 
869                 if ( !declaration.getMessages().getReference().isEmpty() )
870                 {
871                     final Module m = this.modules.getModuleOfImplementation( declaration.getIdentifier() );
872 
873                     if ( m != null && m.getMessages() != null )
874                     {
875                         for ( int i = 0, s0 = declaration.getMessages().getReference().size(); i < s0; i++ )
876                         {
877                             final MessageReference r = declaration.getMessages().getReference().get( i );
878                             Message msg = m.getMessages().getMessage( r.getName() );
879 
880                             if ( msg != null )
881                             {
882                                 msg = msg.clone();
883                                 msg.setFinal( r.isFinal() );
884                                 msg.setOverride( r.isOverride() );
885 
886                                 final Node<Message> node = new Node<Message>(
887                                     declaration, null, null, descendant, msg, msg.isFinal(), msg.isOverride() );
888 
889                                 node.getModifiablePath().addAll( path );
890 
891                                 addNode( map( this.messages, context ), node, node.getModelObject().getName() );
892                             }
893                         }
894                     }
895                 }
896             }
897 
898             if ( declaration.getProperties() != null )
899             {
900                 for ( int i = 0, s0 = declaration.getProperties().getProperty().size(); i < s0; i++ )
901                 {
902                     final Property p = declaration.getProperties().getProperty().get( i );
903                     final Node<Property> node =
904                         new Node<Property>( declaration, null, null, descendant, p, p.isFinal(), p.isOverride() );
905 
906                     node.getModifiablePath().addAll( path );
907 
908                     addNode( map( this.properties, context ), node, node.getModelObject().getName() );
909                 }
910 
911                 if ( !declaration.getProperties().getReference().isEmpty() )
912                 {
913                     final Module m = this.modules.getModuleOfImplementation( declaration.getIdentifier() );
914 
915                     if ( m != null && m.getProperties() != null )
916                     {
917                         for ( int i = 0, s0 = declaration.getProperties().getReference().size(); i < s0; i++ )
918                         {
919                             final PropertyReference r = declaration.getProperties().getReference().get( i );
920                             Property p = m.getProperties().getProperty( r.getName() );
921 
922                             if ( p != null )
923                             {
924                                 p = p.clone();
925                                 p.setFinal( r.isFinal() );
926                                 p.setOverride( r.isOverride() );
927 
928                                 final Node<Property> node = new Node<Property>(
929                                     declaration, null, null, descendant, p, p.isFinal(), p.isOverride() );
930 
931                                 node.getModifiablePath().addAll( path );
932 
933                                 addNode( map( this.properties, context ), node, node.getModelObject().getName() );
934                             }
935                         }
936                     }
937                 }
938             }
939 
940             if ( declaration.getSpecifications() != null )
941             {
942                 for ( int i = 0, s0 = declaration.getSpecifications().getReference().size(); i < s0; i++ )
943                 {
944                     final SpecificationReference r = declaration.getSpecifications().getReference().get( i );
945                     final Node<SpecificationReference> node = new Node<SpecificationReference>(
946                         declaration, null, null, descendant, r, r.isFinal(), r.isOverride() );
947 
948                     node.getModifiablePath().addAll( path );
949 
950                     addNode( map( this.specReferences, context ), node, node.getModelObject().getIdentifier() );
951 
952                     final Specification s = this.modules.getSpecification( r.getIdentifier() );
953 
954                     if ( s != null && s.getProperties() != null )
955                     {
956                         for ( int j = 0, s1 = s.getProperties().getProperty().size(); j < s1; j++ )
957                         {
958                             final Property p = s.getProperties().getProperty().get( j );
959                             final Node<Property> n =
960                                 new Node<Property>( declaration, s, null, descendant, p, p.isFinal(), p.isOverride() );
961 
962                             n.getModifiablePath().addAll( path );
963 
964                             addNode( map( this.properties, context ), n, n.getModelObject().getName() );
965                         }
966                     }
967                 }
968             }
969 
970             if ( !declaration.getAny().isEmpty() )
971             {
972                 for ( int i = 0, s0 = declaration.getAny().size(); i < s0; i++ )
973                 {
974                     final Object any = declaration.getAny().get( i );
975 
976                     if ( any instanceof Element )
977                     {
978                         final Element e = (Element) any;
979                         final Node<Element> node =
980                             new Node<Element>( declaration, null, null, descendant, e, false, false );
981 
982                         node.getModifiablePath().addAll( path );
983 
984                         addNode( map( this.xmlElements, context ), node, getXmlElementName( e ) );
985                         continue;
986                     }
987 
988                     if ( any instanceof JAXBElement<?> )
989                     {
990                         final JAXBElement<?> e = (JAXBElement<?>) any;
991                         boolean _final = false;
992                         boolean override = false;
993 
994                         if ( e.getValue() instanceof Inheritable )
995                         {
996                             _final = ( (Inheritable) e.getValue() ).isFinal();
997                             override = ( (Inheritable) e.getValue() ).isOverride();
998                         }
999 
1000                         final Node<JAXBElement<?>> node =
1001                             new Node<JAXBElement<?>>( declaration, null, null, descendant, e, _final, override );
1002 
1003                         node.getModifiablePath().addAll( path );
1004 
1005                         addNode( map( this.jaxbElements, context ), node, e.getName() );
1006                         continue;
1007                     }
1008                 }
1009             }
1010 
1011             if ( declaration.getImplementations() != null
1012                  && !declaration.getImplementations().getReference().isEmpty() )
1013             {
1014                 boolean all_cyclic = true;
1015 
1016                 for ( int i = 0, s0 = declaration.getImplementations().getReference().size(); i < s0; i++ )
1017                 {
1018                     final ImplementationReference r = declaration.getImplementations().getReference().get( i );
1019                     final Node<ImplementationReference> node = new Node<ImplementationReference>(
1020                         declaration, null, null, descendant, r, r.isFinal(), r.isOverride() );
1021 
1022                     node.getModifiablePath().addAll( path );
1023 
1024                     final Implementation ancestor = this.modules.getImplementation( r.getIdentifier() );
1025 
1026                     boolean cycle = false;
1027                     if ( ancestor != null && contextImplementations.containsKey( ancestor.getIdentifier() ) )
1028                     {
1029                         for ( int j = 0, s1 = path.size(); j < s1; j++ )
1030                         {
1031                             final Node<Implementation> n = path.get( j );
1032 
1033                             if ( n.getModelObject().getIdentifier().equals( ancestor.getIdentifier() ) )
1034                             {
1035                                 cycle = true;
1036                                 node.getModifiablePath().add( n );
1037                                 break;
1038                             }
1039                         }
1040                     }
1041 
1042                     if ( cycle )
1043                     {
1044                         addNode( this.cyclicImplReferences, node, context );
1045                     }
1046                     else
1047                     {
1048                         all_cyclic = false;
1049                         addNode( map( this.implReferences, context ), node, node.getModelObject().getIdentifier() );
1050                         this.collectNodes( context, ancestor, declarationNode, path );
1051                     }
1052                 }
1053 
1054                 if ( all_cyclic )
1055                 {
1056                     map( this.sourceNodes, context ).
1057                         put( declarationNode.getModelObject().getIdentifier(), declarationNode );
1058 
1059                 }
1060             }
1061             else
1062             {
1063                 map( this.sourceNodes, context ).
1064                     put( declarationNode.getModelObject().getIdentifier(), declarationNode );
1065 
1066             }
1067 
1068             path.removeLast();
1069         }
1070     }
1071 
1072     private void collectEffectiveNodes( final String context, final Node<Implementation> node )
1073     {
1074         final Map<String, Set<Node<SpecificationReference>>> directSpecificationReferences =
1075             getDirectEffectiveNodes( map( this.specReferences, context ), node.getModelObject().getIdentifier() );
1076 
1077         final Map<String, Set<Node<Dependency>>> directDependencies =
1078             getDirectEffectiveNodes( map( this.dependencies, context ), node.getModelObject().getIdentifier() );
1079 
1080         final Map<String, Set<Node<Message>>> directMessages =
1081             getDirectEffectiveNodes( map( this.messages, context ), node.getModelObject().getIdentifier() );
1082 
1083         final Map<String, Set<Node<Property>>> directProperties =
1084             getDirectEffectiveNodes( map( this.properties, context ), node.getModelObject().getIdentifier() );
1085 
1086         final Map<String, Set<Node<ImplementationReference>>> directImplementationReferences =
1087             getDirectEffectiveNodes( map( this.implReferences, context ), node.getModelObject().getIdentifier() );
1088 
1089         final Map<QName, Set<Node<Element>>> directXmlElements =
1090             getDirectEffectiveNodes( map( this.xmlElements, context ), node.getModelObject().getIdentifier() );
1091 
1092         final Map<QName, Set<Node<JAXBElement<?>>>> directJaxbElements =
1093             getDirectEffectiveNodes( map( this.jaxbElements, context ), node.getModelObject().getIdentifier() );
1094 
1095         overrideNodes( map( this.effSpecReferences, context ), node, directSpecificationReferences );
1096         overrideNodes( map( this.effImplReferences, context ), node, directImplementationReferences );
1097         overrideNodes( map( this.effDependencies, context ), node, directDependencies );
1098         overrideNodes( map( this.effMessages, context ), node, directMessages );
1099         overrideNodes( map( this.effProperties, context ), node, directProperties );
1100         overrideNodes( map( this.effJaxbElements, context ), node, directJaxbElements );
1101         overrideNodes( map( this.effXmlElements, context ), node, directXmlElements );
1102 
1103         this.addClassDeclarationNodes( context, node );
1104 
1105         final Map<String, Set<Node<SpecificationReference>>> ancestorSpecificationReferences =
1106             getEffectiveNodes( this.effSpecReferences, context, node.getModelObject().getIdentifier() );
1107 
1108         final Map<String, Set<Node<Dependency>>> ancestorDependencies =
1109             getEffectiveNodes( this.effDependencies, context, node.getModelObject().getIdentifier() );
1110 
1111         final Map<String, Set<Node<Message>>> ancestorMessages =
1112             getEffectiveNodes( this.effMessages, context, node.getModelObject().getIdentifier() );
1113 
1114         final Map<String, Set<Node<Property>>> ancestorProperties =
1115             getEffectiveNodes( this.effProperties, context, node.getModelObject().getIdentifier() );
1116 
1117         final Map<String, Set<Node<ImplementationReference>>> ancestorImplementationReferences =
1118             getEffectiveNodes( this.effImplReferences, context, node.getModelObject().getIdentifier() );
1119 
1120         final Map<QName, Set<Node<Element>>> ancestorXmlElements =
1121             getEffectiveNodes( this.effXmlElements, context, node.getModelObject().getIdentifier() );
1122 
1123         final Map<QName, Set<Node<JAXBElement<?>>>> ancestorJaxbElements =
1124             getEffectiveNodes( this.effJaxbElements, context, node.getModelObject().getIdentifier() );
1125 
1126         if ( node.getDescendant() != null )
1127         {
1128             if ( ancestorSpecificationReferences != null )
1129             {
1130                 inheritNodes( map( this.effSpecReferences, context ), ancestorSpecificationReferences,
1131                               node.getDescendant() );
1132 
1133             }
1134 
1135             if ( ancestorDependencies != null )
1136             {
1137                 inheritNodes( map( this.effDependencies, context ), ancestorDependencies,
1138                               node.getDescendant() );
1139 
1140             }
1141 
1142             if ( ancestorProperties != null )
1143             {
1144                 inheritNodes( map( this.effProperties, context ), ancestorProperties, node.getDescendant() );
1145             }
1146 
1147             if ( ancestorMessages != null )
1148             {
1149                 inheritNodes( map( this.effMessages, context ), ancestorMessages, node.getDescendant() );
1150             }
1151 
1152             if ( ancestorImplementationReferences != null )
1153             {
1154                 inheritNodes( map( this.effImplReferences, context ), ancestorImplementationReferences,
1155                               node.getDescendant() );
1156 
1157             }
1158 
1159             if ( ancestorXmlElements != null )
1160             {
1161                 inheritNodes( map( this.effXmlElements, context ), ancestorXmlElements,
1162                               node.getDescendant() );
1163 
1164             }
1165 
1166             if ( ancestorJaxbElements != null )
1167             {
1168                 inheritNodes( map( this.effJaxbElements, context ), ancestorJaxbElements,
1169                               node.getDescendant() );
1170 
1171             }
1172 
1173             collectEffectiveNodes( context, node.getDescendant() );
1174         }
1175     }
1176 
1177     private void addClassDeclarationNodes( final String context, final Node<Implementation> node )
1178     {
1179         final Implementation classDeclaration = this.getClassDeclaration( node.getModelObject() );
1180 
1181         if ( classDeclaration != null )
1182         {
1183             this.prepareContext( classDeclaration.getIdentifier() );
1184 
1185             Map<String, Set<Node<Dependency>>> effectiveDependencies =
1186                 getEffectiveNodes( this.effDependencies, context, node.getModelObject().getIdentifier() );
1187 
1188             Map<String, Set<Node<Message>>> effectiveMessages =
1189                 getEffectiveNodes( this.effMessages, context, node.getModelObject().getIdentifier() );
1190 
1191             Map<String, Set<Node<Property>>> effectiveProperties =
1192                 getEffectiveNodes( this.effProperties, context, node.getModelObject().getIdentifier() );
1193 
1194             Map<String, Set<Node<SpecificationReference>>> effectiveSpecificationReferences =
1195                 getEffectiveNodes( this.effSpecReferences, context, node.getModelObject().getIdentifier() );
1196 
1197             Map<QName, Set<Node<Element>>> effectiveXmlElements =
1198                 getEffectiveNodes( this.effXmlElements, context, node.getModelObject().getIdentifier() );
1199 
1200             Map<QName, Set<Node<JAXBElement<?>>>> effectiveJaxbElements =
1201                 getEffectiveNodes( this.effJaxbElements, context, node.getModelObject().getIdentifier() );
1202 
1203             final Map<String, Set<Node<Dependency>>> declDependencies =
1204                 getEffectiveNodes( this.effDependencies, classDeclaration.getIdentifier(),
1205                                    classDeclaration.getIdentifier() );
1206 
1207             final Map<String, Set<Node<Message>>> declMessages =
1208                 getEffectiveNodes( this.effMessages, classDeclaration.getIdentifier(),
1209                                    classDeclaration.getIdentifier() );
1210 
1211             final Map<String, Set<Node<Property>>> declProperties =
1212                 getEffectiveNodes( this.effProperties, classDeclaration.getIdentifier(),
1213                                    classDeclaration.getIdentifier() );
1214 
1215             final Map<String, Set<Node<SpecificationReference>>> declSpecReferences =
1216                 getEffectiveNodes( this.effSpecReferences, classDeclaration.getIdentifier(),
1217                                    classDeclaration.getIdentifier() );
1218 
1219             final Map<QName, Set<Node<Element>>> declXmlElements =
1220                 getEffectiveNodes( this.effXmlElements, classDeclaration.getIdentifier(),
1221                                    classDeclaration.getIdentifier() );
1222 
1223             final Map<QName, Set<Node<JAXBElement<?>>>> declJaxbElements =
1224                 getEffectiveNodes( this.effJaxbElements, classDeclaration.getIdentifier(),
1225                                    classDeclaration.getIdentifier() );
1226 
1227             if ( declDependencies != null )
1228             {
1229                 if ( effectiveDependencies == null )
1230                 {
1231                     effectiveDependencies = newMap();
1232                     map( this.effDependencies, context ).
1233                         put( node.getModelObject().getIdentifier(), effectiveDependencies );
1234 
1235                 }
1236 
1237                 for ( Map.Entry<String, Set<Node<Dependency>>> e : declDependencies.entrySet() )
1238                 {
1239                     final Set<Node<Dependency>> set = newSet( e.getValue().size() );
1240 
1241                     for ( final Node<Dependency> n : e.getValue() )
1242                     {
1243                         final Node<Dependency> effNode = new Node<Dependency>(
1244                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1245                             n.isFinal(), n.isOverride() );
1246 
1247                         effNode.getModifiablePath().addAll( n.getPath() );
1248                         set.add( effNode );
1249 
1250                         addNode( map( this.dependencies, context ), effNode, e.getKey() );
1251                     }
1252 
1253                     if ( effectiveDependencies.containsKey( e.getKey() ) )
1254                     {
1255                         for ( final Node<Dependency> effNode : effectiveDependencies.get( e.getKey() ) )
1256                         {
1257                             effNode.getModifiableOverriddenNodes().addAll( set );
1258                         }
1259                     }
1260                     else
1261                     {
1262                         effectiveDependencies.put( e.getKey(), set );
1263                     }
1264                 }
1265             }
1266 
1267             if ( declSpecReferences != null )
1268             {
1269                 if ( effectiveSpecificationReferences == null )
1270                 {
1271                     effectiveSpecificationReferences = newMap();
1272                     map( this.effSpecReferences, context ).
1273                         put( node.getModelObject().getIdentifier(), effectiveSpecificationReferences );
1274 
1275                 }
1276 
1277                 for ( Map.Entry<String, Set<Node<SpecificationReference>>> e : declSpecReferences.entrySet() )
1278                 {
1279                     final Set<Node<SpecificationReference>> set = newSet( e.getValue().size() );
1280 
1281                     for ( final Node<SpecificationReference> n : e.getValue() )
1282                     {
1283                         final Node<SpecificationReference> effNode = new Node<SpecificationReference>(
1284                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1285                             n.isFinal(), n.isOverride() );
1286 
1287                         effNode.getModifiablePath().addAll( n.getPath() );
1288                         set.add( effNode );
1289 
1290                         addNode( map( this.specReferences, context ), effNode, e.getKey() );
1291                     }
1292 
1293                     if ( effectiveSpecificationReferences.containsKey( e.getKey() ) )
1294                     {
1295                         for ( final Node<SpecificationReference> effNode
1296                               : effectiveSpecificationReferences.get( e.getKey() ) )
1297                         {
1298                             effNode.getModifiableOverriddenNodes().addAll( set );
1299                         }
1300                     }
1301                     else
1302                     {
1303                         effectiveSpecificationReferences.put( e.getKey(), set );
1304                     }
1305                 }
1306             }
1307 
1308             if ( declMessages != null )
1309             {
1310                 if ( effectiveMessages == null )
1311                 {
1312                     effectiveMessages = newMap();
1313                     map( this.effMessages, context ).
1314                         put( node.getModelObject().getIdentifier(), effectiveMessages );
1315 
1316                 }
1317 
1318                 for ( Map.Entry<String, Set<Node<Message>>> e : declMessages.entrySet() )
1319                 {
1320                     final Set<Node<Message>> set = newSet( e.getValue().size() );
1321 
1322                     for ( final Node<Message> n : e.getValue() )
1323                     {
1324                         final Node<Message> effNode = new Node<Message>(
1325                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1326                             n.isFinal(), n.isOverride() );
1327 
1328                         effNode.getModifiablePath().addAll( n.getPath() );
1329                         set.add( effNode );
1330 
1331                         addNode( map( this.messages, context ), effNode, e.getKey() );
1332                     }
1333 
1334                     if ( effectiveMessages.containsKey( e.getKey() ) )
1335                     {
1336                         for ( final Node<Message> effNode : effectiveMessages.get( e.getKey() ) )
1337                         {
1338                             effNode.getModifiableOverriddenNodes().addAll( set );
1339                         }
1340                     }
1341                     else
1342                     {
1343                         effectiveMessages.put( e.getKey(), set );
1344                     }
1345                 }
1346             }
1347 
1348             if ( declProperties != null )
1349             {
1350                 if ( effectiveProperties == null )
1351                 {
1352                     effectiveProperties = newMap();
1353                     map( this.effProperties, context ).
1354                         put( node.getModelObject().getIdentifier(), effectiveProperties );
1355 
1356                 }
1357 
1358                 for ( Map.Entry<String, Set<Node<Property>>> e : declProperties.entrySet() )
1359                 {
1360                     final Set<Node<Property>> set = newSet( e.getValue().size() );
1361 
1362                     for ( final Node<Property> n : e.getValue() )
1363                     {
1364                         final Node<Property> effNode = new Node<Property>(
1365                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1366                             n.isFinal(), n.isOverride() );
1367 
1368                         effNode.getModifiablePath().addAll( n.getPath() );
1369                         set.add( effNode );
1370 
1371                         addNode( map( this.properties, context ), effNode, e.getKey() );
1372                     }
1373 
1374                     if ( effectiveProperties.containsKey( e.getKey() ) )
1375                     {
1376                         for ( final Node<Property> effNode : effectiveProperties.get( e.getKey() ) )
1377                         {
1378                             effNode.getModifiableOverriddenNodes().addAll( set );
1379                         }
1380                     }
1381                     else
1382                     {
1383                         effectiveProperties.put( e.getKey(), set );
1384                     }
1385                 }
1386             }
1387 
1388             if ( declXmlElements != null )
1389             {
1390                 if ( effectiveXmlElements == null )
1391                 {
1392                     effectiveXmlElements = newMap();
1393                     map( this.effXmlElements, context ).
1394                         put( node.getModelObject().getIdentifier(), effectiveXmlElements );
1395 
1396                 }
1397 
1398                 for ( Map.Entry<QName, Set<Node<Element>>> e : declXmlElements.entrySet() )
1399                 {
1400                     final Set<Node<Element>> set = newSet( e.getValue().size() );
1401 
1402                     for ( final Node<Element> n : e.getValue() )
1403                     {
1404                         final Node<Element> effNode = new Node<Element>(
1405                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1406                             n.isFinal(), n.isOverride() );
1407 
1408                         effNode.getModifiablePath().addAll( n.getPath() );
1409                         set.add( effNode );
1410 
1411                         addNode( map( this.xmlElements, context ), effNode, e.getKey() );
1412                     }
1413 
1414                     if ( effectiveXmlElements.containsKey( e.getKey() ) )
1415                     {
1416                         for ( final Node<Element> effNode : effectiveXmlElements.get( e.getKey() ) )
1417                         {
1418                             effNode.getModifiableOverriddenNodes().addAll( set );
1419                         }
1420                     }
1421                     else
1422                     {
1423                         effectiveXmlElements.put( e.getKey(), set );
1424                     }
1425                 }
1426             }
1427 
1428             if ( declJaxbElements != null )
1429             {
1430                 if ( effectiveJaxbElements == null )
1431                 {
1432                     effectiveJaxbElements = newMap();
1433                     map( this.effJaxbElements, context ).
1434                         put( node.getModelObject().getIdentifier(), effectiveJaxbElements );
1435 
1436                 }
1437 
1438                 for ( Map.Entry<QName, Set<Node<JAXBElement<?>>>> e : declJaxbElements.entrySet() )
1439                 {
1440                     final Set<Node<JAXBElement<?>>> set = newSet( e.getValue().size() );
1441 
1442                     for ( final Node<JAXBElement<?>> n : e.getValue() )
1443                     {
1444                         final Node<JAXBElement<?>> effNode = new Node<JAXBElement<?>>(
1445                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
1446                             n.isFinal(), n.isOverride() );
1447 
1448                         effNode.getModifiablePath().addAll( n.getPath() );
1449                         set.add( effNode );
1450 
1451                         addNode( map( this.jaxbElements, context ), effNode, e.getKey() );
1452                     }
1453 
1454                     if ( effectiveJaxbElements.containsKey( e.getKey() ) )
1455                     {
1456                         for ( final Node<JAXBElement<?>> effNode : effectiveJaxbElements.get( e.getKey() ) )
1457                         {
1458                             effNode.getModifiableOverriddenNodes().addAll( set );
1459                         }
1460                     }
1461                     else
1462                     {
1463                         effectiveJaxbElements.put( e.getKey(), set );
1464                     }
1465                 }
1466             }
1467         }
1468     }
1469 
1470     private Implementation getClassDeclaration( final Implementation implementation )
1471     {
1472         Implementation declaration = null;
1473 
1474         if ( implementation.getClazz() != null && !implementation.isClassDeclaration() )
1475         {
1476             find:
1477             for ( int i = 0, s0 = this.modules.getModule().size(); i < s0; i++ )
1478             {
1479                 final Module candidateModule = this.modules.getModule().get( i );
1480 
1481                 if ( candidateModule.getImplementations() != null )
1482                 {
1483                     for ( int j = 0, s1 = candidateModule.getImplementations().getImplementation().size(); j < s1; j++ )
1484                     {
1485                         final Implementation candidate =
1486                             candidateModule.getImplementations().getImplementation().get( j );
1487 
1488                         if ( candidate.isClassDeclaration()
1489                              && candidate.getClazz().equals( implementation.getClazz() ) )
1490                         {
1491                             declaration = candidate;
1492                             break find;
1493                         }
1494                     }
1495                 }
1496             }
1497         }
1498 
1499         return declaration;
1500     }
1501 
1502     private static <T, K> void addNode( final Map<K, Set<Node<T>>> map, final Node<T> node, final K key )
1503     {
1504         Set<Node<T>> set = map.get( key );
1505 
1506         if ( set == null )
1507         {
1508             set = newSet();
1509             map.put( key, set );
1510         }
1511 
1512         set.add( node );
1513     }
1514 
1515     private static <T, K> void overrideNodes( final Map<String, Map<K, Set<Node<T>>>> effective,
1516                                               final Node<Implementation> implementation,
1517                                               final Map<K, Set<Node<T>>> directNodes )
1518     {
1519         for ( final Map.Entry<K, Set<Node<T>>> e : directNodes.entrySet() )
1520         {
1521             final Set<Node<T>> effectiveNodes =
1522                 effectiveNodes( effective, implementation.getModelObject().getIdentifier(), e.getKey() );
1523 
1524             final Set<Node<T>> overridingNodes = newSet();
1525 
1526             for ( final Node<T> directNode : e.getValue() )
1527             {
1528                 for ( final Iterator<Node<T>> it = effectiveNodes.iterator(); it.hasNext(); )
1529                 {
1530                     final Node<T> effectiveNode = it.next();
1531 
1532                     if ( isOverriding( effectiveNode, directNode ) )
1533                     {
1534                         it.remove();
1535 
1536                         if ( directNode != effectiveNode )
1537                         {
1538                             directNode.getModifiableOverriddenNodes().add( effectiveNode );
1539                         }
1540                     }
1541                 }
1542 
1543                 boolean overriddenByAncestor = false;
1544 
1545                 if ( directNode.getSpecification() != null )
1546                 {
1547                     for ( final Node<T> effectiveNode : effectiveNodes )
1548                     {
1549                         if ( effectiveNode.getSpecification() == null )
1550                         {
1551                             overriddenByAncestor = true;
1552                             effectiveNode.getModifiableOverriddenNodes().add( directNode );
1553                         }
1554                     }
1555                 }
1556 
1557                 if ( !overriddenByAncestor )
1558                 {
1559                     overridingNodes.add( directNode );
1560                 }
1561             }
1562 
1563             effectiveNodes.addAll( overridingNodes );
1564         }
1565     }
1566 
1567     private static <K, V, T> Map<K, V> map( final Map<T, Map<K, V>> map, final T context )
1568     {
1569         Map<K, V> contextMap = map.get( context );
1570 
1571         if ( contextMap == null )
1572         {
1573             contextMap = newMap();
1574             map.put( context, contextMap );
1575         }
1576 
1577         return contextMap;
1578     }
1579 
1580     private static <K, V> Set<Node<V>> nodes( final Map<K, Set<Node<V>>> map, final K key )
1581     {
1582         Set<Node<V>> nodes = map.get( key );
1583 
1584         if ( nodes == null )
1585         {
1586             nodes = newSet();
1587             map.put( key, nodes );
1588         }
1589 
1590         return nodes;
1591     }
1592 
1593     private static <K, V> Set<Node<V>> effectiveNodes( final Map<String, Map<K, Set<Node<V>>>> map,
1594                                                        final String context, final K key )
1595     {
1596         return nodes( map( map, context ), key );
1597     }
1598 
1599     private static <T, K> void inheritNodes(
1600         final Map<String, Map<K, Set<Node<T>>>> effective, final Map<K, Set<Node<T>>> ancestor,
1601         final Node<Implementation> descendant )
1602     {
1603         for ( Map.Entry<K, Set<Node<T>>> e : ancestor.entrySet() )
1604         {
1605             for ( final Node<T> inherit : e.getValue() )
1606             {
1607                 if ( isInheritableNode( inherit ) )
1608                 {
1609                     effectiveNodes( effective, descendant.getModelObject().getIdentifier(), e.getKey() ).add( inherit );
1610                 }
1611             }
1612         }
1613     }
1614 
1615     private static <T, K> Map<K, Set<Node<T>>> getDirectEffectiveNodes( final Map<K, Set<Node<T>>> map,
1616                                                                         final String origin )
1617     {
1618         final Map<K, Set<Node<T>>> declarationMap = newMap( map.size() );
1619 
1620         for ( Map.Entry<K, Set<Node<T>>> e : map.entrySet() )
1621         {
1622             final Set<Node<T>> set = nodes( declarationMap, e.getKey() );
1623 
1624             for ( final Node<T> n : e.getValue() )
1625             {
1626                 if ( isDirectEffectiveNode( n, origin ) )
1627                 {
1628                     set.add( n );
1629                 }
1630             }
1631 
1632             for ( final Node<T> n : e.getValue() )
1633             {
1634                 if ( isDirectSpecifiedNode( n, origin ) )
1635                 {
1636                     boolean add = true;
1637 
1638                     for ( final Node<T> override : set )
1639                     {
1640                         if ( override.getSpecification() == null )
1641                         {
1642                             override.getModifiableOverriddenNodes().add( n );
1643                             add = false;
1644                         }
1645                     }
1646 
1647                     if ( add )
1648                     {
1649                         set.add( n );
1650                     }
1651                 }
1652             }
1653         }
1654 
1655         return declarationMap;
1656     }
1657 
1658     private static <T, K> Map<K, Set<Node<T>>> getEffectiveNodes(
1659         final Map<String, Map<String, Map<K, Set<Node<T>>>>> effective, final String context,
1660         final String implementation )
1661     {
1662         return map( effective, context ).get( implementation );
1663     }
1664 
1665     private static boolean isDirectNode( final Node<?> node, final String implementation )
1666     {
1667         return implementation.equals( node.getImplementation().getIdentifier() );
1668     }
1669 
1670     private static boolean isDirectEffectiveNode( final Node<?> node, final String implementation )
1671     {
1672         return isDirectNode( node, implementation ) && node.getClassDeclaration() == null
1673                && node.getSpecification() == null;
1674 
1675     }
1676 
1677     private static boolean isDirectSpecifiedNode( final Node<?> node, final String implementation )
1678     {
1679         return isDirectNode( node, implementation ) && node.getClassDeclaration() == null
1680                && node.getSpecification() != null;
1681 
1682     }
1683 
1684     private static boolean isOverriding( final Node<?> node, final Node<?> override )
1685     {
1686         if ( override.getSpecification() != null )
1687         {
1688             if ( node.getSpecification() == null )
1689             {
1690                 return false;
1691             }
1692             else if ( !override.getSpecification().getIdentifier().equals( node.getSpecification().getIdentifier() ) )
1693             {
1694                 return false;
1695             }
1696         }
1697 
1698         return true;
1699     }
1700 
1701     private static boolean isInheritableNode( final Node<?> node )
1702     {
1703         return node.getClassDeclaration() == null;
1704     }
1705 
1706     private static <K, V> Map<K, V> newMap()
1707     {
1708         return new HashMap<K, V>();
1709     }
1710 
1711     private static <K, V> Map<K, V> newMap( final int initialCapacity )
1712     {
1713         return new HashMap<K, V>( initialCapacity );
1714     }
1715 
1716     private static <T> Set<T> newSet()
1717     {
1718         return new HashSet<T>();
1719     }
1720 
1721     private static <T> Set<T> newSet( final int initialCapacity )
1722     {
1723         return new HashSet<T>( initialCapacity );
1724     }
1725 
1726     private static <T> Set<T> newSet( final Collection<? extends T> col )
1727     {
1728         return new HashSet<T>( col );
1729     }
1730 
1731     private static <T> Set<T> unmodifiableSet( final Set<T> set )
1732     {
1733         return set != null ? Collections.unmodifiableSet( set ) : Collections.<T>emptySet();
1734     }
1735 
1736     private static QName getXmlElementName( final Element element )
1737     {
1738         if ( element.getNamespaceURI() != null )
1739         {
1740             return new QName( element.getNamespaceURI(), element.getLocalName() );
1741         }
1742         else
1743         {
1744             return new QName( element.getLocalName() );
1745         }
1746     }
1747 
1748 }