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