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