InheritanceModel.java

  1. /*
  2.  *   Copyright (C) Christian Schulte <cs@schulte.it>, 2011-325
  3.  *   All rights reserved.
  4.  *
  5.  *   Redistribution and use in source and binary forms, with or without
  6.  *   modification, are permitted provided that the following conditions
  7.  *   are met:
  8.  *
  9.  *     o Redistributions of source code must retain the above copyright
  10.  *       notice, this list of conditions and the following disclaimer.
  11.  *
  12.  *     o Redistributions in binary form must reproduce the above copyright
  13.  *       notice, this list of conditions and the following disclaimer in
  14.  *       the documentation and/or other materials provided with the
  15.  *       distribution.
  16.  *
  17.  *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  18.  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  19.  *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  20.  *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  *
  28.  *   $JOMC: InheritanceModel.java 5043 2015-05-27 07:03:39Z schulte $
  29.  *
  30.  */
  31. package org.jomc.model;

  32. import java.util.Collection;
  33. import java.util.Collections;
  34. import java.util.HashMap;
  35. import java.util.HashSet;
  36. import java.util.Iterator;
  37. import java.util.LinkedList;
  38. import java.util.List;
  39. import java.util.Map;
  40. import java.util.Set;
  41. import javax.xml.bind.JAXBElement;
  42. import javax.xml.namespace.QName;
  43. import org.w3c.dom.Element;

  44. /**
  45.  * Inheritance model.
  46.  *
  47.  * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
  48.  * @version $JOMC: InheritanceModel.java 5043 2015-05-27 07:03:39Z schulte $
  49.  * @since 1.2
  50.  */
  51. public class InheritanceModel
  52. {

  53.     /**
  54.      * Inheritance model node.
  55.      *
  56.      * @param <T> The type of the model object of the node.
  57.      *
  58.      * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
  59.      * @version $JOMC: InheritanceModel.java 5043 2015-05-27 07:03:39Z schulte $
  60.      * @since 1.2
  61.      */
  62.     public static class Node<T>
  63.     {

  64.         /**
  65.          * The implementation the node originates from.
  66.          */
  67.         private final Implementation implementation;

  68.         /**
  69.          * The specification the node originates from.
  70.          */
  71.         private final Specification specification;

  72.         /**
  73.          * The class declaration the node originates from.
  74.          */
  75.         private final Implementation classDeclaration;

  76.         /**
  77.          * The direct descendant node.
  78.          */
  79.         private final Node<Implementation> descendant;

  80.         /**
  81.          * The model object of the node.
  82.          */
  83.         private final T modelObject;

  84.         /**
  85.          * Flag indicating the node is the final node in an inheritance hierarchy.
  86.          */
  87.         private final boolean _final;

  88.         /**
  89.          * Flag indicating the node is intended to override an ancestor node.
  90.          */
  91.         private final boolean override;

  92.         /**
  93.          * The path to the node.
  94.          */
  95.         private final LinkedList<Node<Implementation>> path = new LinkedList<Node<Implementation>>();

  96.         /**
  97.          * The nodes overridden by the node.
  98.          */
  99.         private final Set<Node<T>> overriddenNodes = new HashSet<Node<T>>();

  100.         /**
  101.          * Creates a new {@code Node} instance.
  102.          *
  103.          * @param implementation The implementation the node originates from.
  104.          * @param specification The specification the node originates from or {@code null}.
  105.          * @param classDeclaration The class declaration the node originates from or {@code null}.
  106.          * @param descendant The direct descendant node of the node or {@code null}.
  107.          * @param modelObject The model object of the node.
  108.          * @param finalNode {@code true}, if the node is the final node in an inheritance hierarchy; {@code false},
  109.          * else.
  110.          * @param overrideNode {@code true}, if the node is intended to override an ancestor node; {@code false}, else.
  111.          */
  112.         public Node( final Implementation implementation, final Specification specification,
  113.                      final Implementation classDeclaration, final Node<Implementation> descendant, final T modelObject,
  114.                      final boolean finalNode, final boolean overrideNode )
  115.         {
  116.             super();
  117.             this.implementation = implementation;
  118.             this.specification = specification;
  119.             this.classDeclaration = classDeclaration;
  120.             this.descendant = descendant;
  121.             this.modelObject = modelObject;
  122.             this._final = finalNode;
  123.             this.override = overrideNode;
  124.         }

  125.         /**
  126.          * Gets the implementation the node originates from.
  127.          *
  128.          * @return The implementation the node originates from.
  129.          */
  130.         public final Implementation getImplementation()
  131.         {
  132.             return this.implementation;
  133.         }

  134.         /**
  135.          * Gets the specification the node originates from.
  136.          *
  137.          * @return The specification the node originates from or {@code null}, if the node does not originate from a
  138.          * specification.
  139.          */
  140.         public final Specification getSpecification()
  141.         {
  142.             return this.specification;
  143.         }

  144.         /**
  145.          * Gets the class declaration the node originates from.
  146.          *
  147.          * @return The class declaration the node originates from or {@code null}, if the node does not originate from a
  148.          * class declaration.
  149.          */
  150.         public final Implementation getClassDeclaration()
  151.         {
  152.             return this.classDeclaration;
  153.         }

  154.         /**
  155.          * Gets the direct descendant node of the node.
  156.          *
  157.          * @return The direct descendant node of the node or {@code null}.
  158.          *
  159.          * @see InheritanceModel#getSourceNodes(java.lang.String)
  160.          */
  161.         public final Node<Implementation> getDescendant()
  162.         {
  163.             return this.descendant;
  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.          * Gets a flag indicating the node is the final node in an inheritance hierarchy.
  176.          *
  177.          * @return {@code true}, if the node is the final node in an inheritance hierarchy; {@code false}, else.
  178.          */
  179.         public final boolean isFinal()
  180.         {
  181.             return this._final;
  182.         }

  183.         /**
  184.          * Gets a flag indicating the node is intended to override an ancestor node.
  185.          *
  186.          * @return {@code true}, if the node is intended to override an ancestor; {@code false} else.
  187.          */
  188.         public final boolean isOverride()
  189.         {
  190.             return this.override;
  191.         }

  192.         /**
  193.          * Gets a set of nodes overridden by the node.
  194.          *
  195.          * @return An unmodifiable set holding nodes overridden by the node.
  196.          */
  197.         public final Set<Node<T>> getOverriddenNodes()
  198.         {
  199.             return Collections.unmodifiableSet( this.overriddenNodes );
  200.         }

  201.         /**
  202.          * Gets the path to the node.
  203.          *
  204.          * @return An unmodifiable list holding path elements.
  205.          */
  206.         public final List<Node<Implementation>> getPath()
  207.         {
  208.             return Collections.unmodifiableList( this.path );
  209.         }

  210.         /**
  211.          * Gets a set of nodes overridden by the node.
  212.          *
  213.          * @return A modifiable set holding nodes overridden by the node.
  214.          *
  215.          * @see #getOverriddenNodes()
  216.          */
  217.         private Set<Node<T>> getModifiableOverriddenNodes()
  218.         {
  219.             return this.overriddenNodes;
  220.         }

  221.         /**
  222.          * Gets the path to the node.
  223.          *
  224.          * @return A modifiable list holding path nodes of the node.
  225.          *
  226.          * @see #getPath()
  227.          */
  228.         private LinkedList<Node<Implementation>> getModifiablePath()
  229.         {
  230.             return this.path;
  231.         }

  232.     }

  233.     /**
  234.      * Enumeration of context states.
  235.      */
  236.     private enum ContextState
  237.     {

  238.         PREPARING,
  239.         PREPARED

  240.     }

  241.     /**
  242.      * The modules backing the model.
  243.      */
  244.     private final Modules modules;

  245.     /**
  246.      * {@code Dependency} nodes by context and dependency name.
  247.      */
  248.     private final Map<String, Map<String, Set<Node<Dependency>>>> dependencies = newMap();

  249.     /**
  250.      * {@code Dependency} nodes by context and implementation identifier.
  251.      */
  252.     private final Map<String, Map<String, Map<String, Set<Node<Dependency>>>>> effDependencies = newMap();

  253.     /**
  254.      * {@code Message} nodes by context and message name.
  255.      */
  256.     private final Map<String, Map<String, Set<Node<Message>>>> messages = newMap();

  257.     /**
  258.      * {@code Message} nodes by context and implementation identifier.
  259.      */
  260.     private final Map<String, Map<String, Map<String, Set<Node<Message>>>>> effMessages = newMap();

  261.     /**
  262.      * {@code Property} nodes by context and property name.
  263.      */
  264.     private final Map<String, Map<String, Set<Node<Property>>>> properties = newMap();

  265.     /**
  266.      * {@code Property} nodes by context and implementation identifier.
  267.      */
  268.     private final Map<String, Map<String, Map<String, Set<Node<Property>>>>> effProperties = newMap();

  269.     /**
  270.      * {@code SpecificationReference} nodes by context and specification identifier.
  271.      */
  272.     private final Map<String, Map<String, Set<Node<SpecificationReference>>>> specReferences = newMap();

  273.     /**
  274.      * {@code SpecificationReference} nodes by context and implementation identifier.
  275.      */
  276.     private final Map<String, Map<String, Map<String, Set<Node<SpecificationReference>>>>> effSpecReferences =
  277.         newMap();

  278.     /**
  279.      * {@code ImplementationReference} nodes by context and implementation reference identifier.
  280.      */
  281.     private final Map<String, Map<String, Set<Node<ImplementationReference>>>> implReferences = newMap();

  282.     /**
  283.      * {@code ImplementationReference} nodes by context and implementation reference identifier.
  284.      */
  285.     private final Map<String, Set<Node<ImplementationReference>>> cyclicImplReferences = newMap();

  286.     /**
  287.      * {@code ImplementationReference} nodes by context and implementation identifier.
  288.      */
  289.     private final Map<String, Map<String, Map<String, Set<Node<ImplementationReference>>>>> effImplReferences =
  290.         newMap();

  291.     /**
  292.      * {@code Element} nodes by context and qualified name.
  293.      */
  294.     private final Map<String, Map<QName, Set<Node<Element>>>> xmlElements = newMap();

  295.     /**
  296.      * {@code Element} nodes by context and implementation identifier.
  297.      */
  298.     private final Map<String, Map<String, Map<QName, Set<Node<Element>>>>> effXmlElements = newMap();

  299.     /**
  300.      * {@code JAXBElement} nodes by context and qualified name.
  301.      */
  302.     private final Map<String, Map<QName, Set<Node<JAXBElement<?>>>>> jaxbElements = newMap();

  303.     /**
  304.      * {@code JAXBElement} nodes by context and implementation identifier.
  305.      */
  306.     private final Map<String, Map<String, Map<QName, Set<Node<JAXBElement<?>>>>>> effJaxbElements =
  307.         newMap();

  308.     /**
  309.      * {@code Implementation} nodes by context and implementation identifier.
  310.      */
  311.     private final Map<String, Map<String, Node<Implementation>>> implementations = newMap();

  312.     /**
  313.      * Source nodes of a hierarchy by context and implementation identifier.
  314.      */
  315.     private final Map<String, Map<String, Node<Implementation>>> sourceNodes = newMap();

  316.     /**
  317.      * Context states by context identifier.
  318.      */
  319.     private final Map<String, ContextState> contextStates = newMap();

  320.     /**
  321.      * Creates a new {@code InheritanceModel} instance.
  322.      *
  323.      * @param modules The modules backing the model.
  324.      *
  325.      * @throws NullPointerException if {@code modules} is {@code null}.
  326.      *
  327.      * @see Modules#clone()
  328.      */
  329.     public InheritanceModel( final Modules modules )
  330.     {
  331.         super();

  332.         if ( modules == null )
  333.         {
  334.             throw new NullPointerException( "modules" );
  335.         }

  336.         this.modules = modules.clone();
  337.     }

  338.     /**
  339.      * Gets a set holding source nodes of an implementation.
  340.      *
  341.      * @param implementation The identifier of the implementation to get source nodes of.
  342.      *
  343.      * @return An unmodifiable set holding source nodes of the implementation identified by {@code implementation}.
  344.      *
  345.      * @throws NullPointerException if {@code implementation} is {@code null}.
  346.      *
  347.      * @see Node#getDescendant()
  348.      */
  349.     public Set<Node<Implementation>> getSourceNodes( final String implementation )
  350.     {
  351.         if ( implementation == null )
  352.         {
  353.             throw new NullPointerException( "implementation" );
  354.         }

  355.         this.prepareContext( implementation );
  356.         final Collection<Node<Implementation>> col = map( this.sourceNodes, implementation ).values();
  357.         return unmodifiableSet( newSet( col ) );
  358.     }

  359.     /**
  360.      * Gets a set holding implementation reference nodes of an implementation causing a cycle.
  361.      *
  362.      * @param implementation The identifier of the implementation to get implementation reference nodes causing a cycle
  363.      * of.
  364.      *
  365.      * @return An unmodifiable set holding implementation reference nodes of the implementation identified by
  366.      * {@code implementation} causing a cycle.
  367.      *
  368.      * @throws NullPointerException if {@code implementation} is {@code null}.
  369.      *
  370.      * @since 1.5
  371.      *
  372.      * @see Node#getPath()
  373.      */
  374.     public Set<Node<ImplementationReference>> getCycleNodes( final String implementation )
  375.     {
  376.         if ( implementation == null )
  377.         {
  378.             throw new NullPointerException( "implementation" );
  379.         }

  380.         this.prepareContext( implementation );
  381.         return unmodifiableSet( nodes( this.cyclicImplReferences, implementation ) );
  382.     }

  383.     /**
  384.      * Gets a set holding the names of all dependencies of an implementation.
  385.      *
  386.      * @param implementation The identifier of the implementation to get the names of all dependencies of.
  387.      *
  388.      * @return An unmodifiable set holding the names of all dependencies of the implementation identified by
  389.      * {@code implementation}.
  390.      *
  391.      * @throws NullPointerException if {@code implementation} is {@code null}.
  392.      */
  393.     public Set<String> getDependencyNames( final String implementation )
  394.     {
  395.         if ( implementation == null )
  396.         {
  397.             throw new NullPointerException( "implementation" );
  398.         }

  399.         this.prepareContext( implementation );
  400.         return Collections.unmodifiableSet( map( this.dependencies, implementation ).keySet() );
  401.     }

  402.     /**
  403.      * Gets a set holding effective dependency nodes of an implementation.
  404.      *
  405.      * @param implementation The identifier of the implementation to get effective dependency nodes of.
  406.      * @param name The dependency name to get effective nodes for.
  407.      *
  408.      * @return An unmodifiable set holding effective dependency nodes matching {@code name} of the implementation
  409.      * identified by {@code implementation}.
  410.      *
  411.      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
  412.      *
  413.      * @see #getDependencyNames(java.lang.String)
  414.      */
  415.     public Set<Node<Dependency>> getDependencyNodes( final String implementation, final String name )
  416.     {
  417.         if ( implementation == null )
  418.         {
  419.             throw new NullPointerException( "implementation" );
  420.         }
  421.         if ( name == null )
  422.         {
  423.             throw new NullPointerException( "name" );
  424.         }

  425.         this.prepareContext( implementation );
  426.         Set<Node<Dependency>> set = null;

  427.         final Map<String, Set<Node<Dependency>>> map =
  428.             getEffectiveNodes( this.effDependencies, implementation, implementation );

  429.         if ( map != null )
  430.         {
  431.             set = map.get( name );
  432.         }

  433.         return unmodifiableSet( set );
  434.     }

  435.     /**
  436.      * Gets a set holding the identifiers of all implementation references of an implementation.
  437.      *
  438.      * @param implementation The identifier of the implementation to get the identifiers of all implementation
  439.      * references of.
  440.      *
  441.      * @return An unmodifiable set holding the identifiers of all implementation references of the implementation
  442.      * identified by {@code implementation}.
  443.      *
  444.      * @throws NullPointerException if {@code implementation} is {@code null}.
  445.      */
  446.     public Set<String> getImplementationReferenceIdentifiers( final String implementation )
  447.     {
  448.         if ( implementation == null )
  449.         {
  450.             throw new NullPointerException( "implementation" );
  451.         }

  452.         this.prepareContext( implementation );
  453.         return Collections.unmodifiableSet( map( this.implReferences, implementation ).keySet() );
  454.     }

  455.     /**
  456.      * Gets a set holding effective implementation reference nodes of an implementation.
  457.      *
  458.      * @param implementation The identifier of the implementation to get effective implementation reference nodes of.
  459.      * @param identifier The implementation reference identifier to get effective nodes for.
  460.      *
  461.      * @return An unmodifiable set holding effective implementation reference nodes matching {@code identifier} of the
  462.      * implementation identified by {@code implementation}.
  463.      *
  464.      * @throws NullPointerException if {@code implementation} or {@code identifier} is {@code null}.
  465.      *
  466.      * @see #getImplementationReferenceIdentifiers(java.lang.String)
  467.      */
  468.     public Set<Node<ImplementationReference>> getImplementationReferenceNodes( final String implementation,
  469.                                                                                final String identifier )
  470.     {
  471.         if ( implementation == null )
  472.         {
  473.             throw new NullPointerException( "implementation" );
  474.         }
  475.         if ( identifier == null )
  476.         {
  477.             throw new NullPointerException( "identifier" );
  478.         }

  479.         this.prepareContext( implementation );
  480.         Set<Node<ImplementationReference>> set = null;
  481.         final Map<String, Set<Node<ImplementationReference>>> map =
  482.             getEffectiveNodes( this.effImplReferences, implementation, implementation );

  483.         if ( map != null )
  484.         {
  485.             set = map.get( identifier );
  486.         }

  487.         return unmodifiableSet( set );
  488.     }

  489.     /**
  490.      * Gets a set holding the qualified names of all XML elements of an implementation.
  491.      *
  492.      * @param implementation The identifier of the implementation to get the qualified names of all XML elements of.
  493.      *
  494.      * @return An unmodifiable set holding the qualified names of all XML elements of the implementation identified by
  495.      * {@code implementation}.
  496.      *
  497.      * @throws NullPointerException if {@code implementation} is {@code null}.
  498.      */
  499.     public Set<QName> getJaxbElementNames( final String implementation )
  500.     {
  501.         if ( implementation == null )
  502.         {
  503.             throw new NullPointerException( "implementation" );
  504.         }

  505.         this.prepareContext( implementation );
  506.         return Collections.unmodifiableSet( map( this.jaxbElements, implementation ).keySet() );
  507.     }

  508.     /**
  509.      * Gets a set holding effective JAXB element nodes of an implementation.
  510.      *
  511.      * @param implementation The identifier of the implementation to get effective JAXB element nodes of.
  512.      * @param name The qualified JAXB element name to get effective nodes for.
  513.      *
  514.      * @return An unmodifiable set holding effective JAXB element nodes matching {@code name} of the implementation
  515.      * identified by {@code implementation}.
  516.      *
  517.      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
  518.      *
  519.      * @see #getJaxbElementNames(java.lang.String)
  520.      */
  521.     public Set<Node<JAXBElement<?>>> getJaxbElementNodes( final String implementation, final QName name )
  522.     {
  523.         if ( implementation == null )
  524.         {
  525.             throw new NullPointerException( "implementation" );
  526.         }
  527.         if ( name == null )
  528.         {
  529.             throw new NullPointerException( "name" );
  530.         }

  531.         this.prepareContext( implementation );
  532.         Set<Node<JAXBElement<?>>> set = null;
  533.         final Map<QName, Set<Node<JAXBElement<?>>>> map =
  534.             getEffectiveNodes( this.effJaxbElements, implementation, implementation );

  535.         if ( map != null )
  536.         {
  537.             set = map.get( name );
  538.         }

  539.         return unmodifiableSet( set );
  540.     }

  541.     /**
  542.      * Gets a set holding the names of all messages of an implementation.
  543.      *
  544.      * @param implementation The identifier of the implementation to get the names of all messages of.
  545.      *
  546.      * @return An unmodifiable set holding the names of all messages of the implementation identified by
  547.      * {@code implementation}.
  548.      *
  549.      * @throws NullPointerException if {@code implementation} is {@code null}.
  550.      */
  551.     public Set<String> getMessageNames( final String implementation )
  552.     {
  553.         if ( implementation == null )
  554.         {
  555.             throw new NullPointerException( "implementation" );
  556.         }

  557.         this.prepareContext( implementation );
  558.         return Collections.unmodifiableSet( map( this.messages, implementation ).keySet() );
  559.     }

  560.     /**
  561.      * Gets a set holding effective message nodes of an implementation.
  562.      *
  563.      * @param implementation The identifier of the implementation to get effective message nodes of.
  564.      * @param name The message name to get effective nodes for.
  565.      *
  566.      * @return An unmodifiable set holding effective message nodes matching {@code name} of the implementation
  567.      * identified by {@code implementation}.
  568.      *
  569.      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
  570.      *
  571.      * @see #getMessageNames(java.lang.String)
  572.      */
  573.     public Set<Node<Message>> getMessageNodes( final String implementation, final String name )
  574.     {
  575.         if ( implementation == null )
  576.         {
  577.             throw new NullPointerException( "implementation" );
  578.         }
  579.         if ( name == null )
  580.         {
  581.             throw new NullPointerException( "name" );
  582.         }

  583.         this.prepareContext( implementation );
  584.         Set<Node<Message>> set = null;
  585.         final Map<String, Set<Node<Message>>> map =
  586.             getEffectiveNodes( this.effMessages, implementation, implementation );

  587.         if ( map != null )
  588.         {
  589.             set = map.get( name );
  590.         }

  591.         return unmodifiableSet( set );
  592.     }

  593.     /**
  594.      * Gets a set holding the names of all properties of an implementation.
  595.      *
  596.      * @param implementation The identifier of the implementation to get the names of all properties of.
  597.      *
  598.      * @return An unmodifiable set holding the names of all properties of the implementation identified by
  599.      * {@code implementation}.
  600.      *
  601.      * @throws NullPointerException if {@code implementation} is {@code null}.
  602.      */
  603.     public Set<String> getPropertyNames( final String implementation )
  604.     {
  605.         if ( implementation == null )
  606.         {
  607.             throw new NullPointerException( "implementation" );
  608.         }

  609.         this.prepareContext( implementation );
  610.         return Collections.unmodifiableSet( map( this.properties, implementation ).keySet() );
  611.     }

  612.     /**
  613.      * Gets a set holding effective property nodes of an implementation.
  614.      *
  615.      * @param implementation The identifier of the implementation to get effective property nodes of.
  616.      * @param name The property name to get effective nodes for.
  617.      *
  618.      * @return An unmodifiable set holding effective property nodes matching {@code name} of the implementation
  619.      * identified by {@code implementation}.
  620.      *
  621.      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
  622.      *
  623.      * @see #getPropertyNames(java.lang.String)
  624.      */
  625.     public Set<Node<Property>> getPropertyNodes( final String implementation, final String name )
  626.     {
  627.         if ( implementation == null )
  628.         {
  629.             throw new NullPointerException( "implementation" );
  630.         }
  631.         if ( name == null )
  632.         {
  633.             throw new NullPointerException( "name" );
  634.         }

  635.         this.prepareContext( implementation );
  636.         Set<Node<Property>> set = null;
  637.         final Map<String, Set<Node<Property>>> map =
  638.             getEffectiveNodes( this.effProperties, implementation, implementation );

  639.         if ( map != null )
  640.         {
  641.             set = map.get( name );
  642.         }

  643.         return unmodifiableSet( set );
  644.     }

  645.     /**
  646.      * Gets a set holding the identifiers of all specification references of an implementation.
  647.      *
  648.      * @param implementation The identifier of the implementation to get the identifiers of all specification references
  649.      * of.
  650.      *
  651.      * @return An unmodifiable set holding the identifiers of all specification references of the implementation
  652.      * identified by {@code implementation}.
  653.      *
  654.      * @throws NullPointerException if {@code implementation} is {@code null}.
  655.      */
  656.     public Set<String> getSpecificationReferenceIdentifiers( final String implementation )
  657.     {
  658.         if ( implementation == null )
  659.         {
  660.             throw new NullPointerException( "implementation" );
  661.         }

  662.         this.prepareContext( implementation );
  663.         return Collections.unmodifiableSet( map( this.specReferences, implementation ).keySet() );
  664.     }

  665.     /**
  666.      * Gets a set holding effective specification reference nodes of an implementation.
  667.      *
  668.      * @param implementation The identifier of the implementation to get effective specification reference nodes of.
  669.      * @param identifier The specification reference identifier to get effective nodes for.
  670.      *
  671.      * @return An unmodifiable set holding effective specification reference nodes matching {@code identifier} of the
  672.      * implementation identified by {@code implementation}.
  673.      *
  674.      * @throws NullPointerException if {@code implementation} or {@code identifier} is {@code null}.
  675.      *
  676.      * @see #getSpecificationReferenceIdentifiers(java.lang.String)
  677.      */
  678.     public Set<Node<SpecificationReference>> getSpecificationReferenceNodes( final String implementation,
  679.                                                                              final String identifier )
  680.     {
  681.         if ( implementation == null )
  682.         {
  683.             throw new NullPointerException( "implementation" );
  684.         }
  685.         if ( identifier == null )
  686.         {
  687.             throw new NullPointerException( "identifier" );
  688.         }

  689.         this.prepareContext( implementation );
  690.         Set<Node<SpecificationReference>> set = null;
  691.         final Map<String, Set<Node<SpecificationReference>>> map =
  692.             getEffectiveNodes( this.effSpecReferences, implementation, implementation );

  693.         if ( map != null )
  694.         {
  695.             set = map.get( identifier );
  696.         }

  697.         return unmodifiableSet( set );
  698.     }

  699.     /**
  700.      * Gets a set holding the qualified names of all XML elements of an implementation.
  701.      *
  702.      * @param implementation The identifier of the implementation to get the qualified names of all XML elements of.
  703.      *
  704.      * @return An unmodifiable set holding the qualified names of all XML elements of the implementation identified by
  705.      * {@code implementation}.
  706.      *
  707.      * @throws NullPointerException if {@code implementation} is {@code null}.
  708.      */
  709.     public Set<QName> getXmlElementNames( final String implementation )
  710.     {
  711.         if ( implementation == null )
  712.         {
  713.             throw new NullPointerException( "implementation" );
  714.         }

  715.         this.prepareContext( implementation );
  716.         return Collections.unmodifiableSet( map( this.xmlElements, implementation ).keySet() );
  717.     }

  718.     /**
  719.      * Gets a set holding effective XML element nodes of an implementation.
  720.      *
  721.      * @param implementation The identifier of the implementation to get effective XML element nodes of.
  722.      * @param name The qualified XML element name to get effective nodes for.
  723.      *
  724.      * @return An unmodifiable set holding effective XML element nodes matching {@code name} of the implementation
  725.      * identified by {@code implementation}.
  726.      *
  727.      * @throws NullPointerException if {@code implementation} or {@code name} is {@code null}.
  728.      *
  729.      * @see #getXmlElementNames(java.lang.String)
  730.      */
  731.     public Set<Node<Element>> getXmlElementNodes( final String implementation, final QName name )
  732.     {
  733.         if ( implementation == null )
  734.         {
  735.             throw new NullPointerException( "implementation" );
  736.         }
  737.         if ( name == null )
  738.         {
  739.             throw new NullPointerException( "name" );
  740.         }

  741.         this.prepareContext( implementation );
  742.         Set<Node<Element>> set = null;
  743.         final Map<QName, Set<Node<Element>>> map =
  744.             getEffectiveNodes( this.effXmlElements, implementation, implementation );

  745.         if ( map != null )
  746.         {
  747.             set = map.get( name );
  748.         }

  749.         return unmodifiableSet( set );
  750.     }

  751.     private void prepareContext( final String context )
  752.     {
  753.         ContextState state = this.contextStates.get( context );

  754.         if ( state == null )
  755.         {
  756.             state = ContextState.PREPARING;
  757.             this.contextStates.put( context, state );

  758.             final Implementation i = this.modules.getImplementation( context );

  759.             if ( i != null )
  760.             {
  761.                 this.collectNodes( context, i, null, null );

  762.                 for ( final Node<Implementation> source : map( this.sourceNodes, context ).values() )
  763.                 {
  764.                     this.collectEffectiveNodes( context, source );
  765.                 }
  766.             }

  767.             state = ContextState.PREPARED;
  768.             this.contextStates.put( context, state );
  769.         }

  770.         assert state == ContextState.PREPARED :
  771.             "Unexpected context state '" + state + "' for context '" + context + "'.";

  772.     }

  773.     private void collectNodes( final String context, final Implementation declaration,
  774.                                final Node<Implementation> descendant, LinkedList<Node<Implementation>> path )
  775.     {
  776.         if ( path == null )
  777.         {
  778.             path = new LinkedList<Node<Implementation>>();
  779.         }

  780.         final Map<String, Node<Implementation>> contextImplementations = map( this.implementations, context );

  781.         if ( declaration != null && !contextImplementations.containsKey( declaration.getIdentifier() ) )
  782.         {
  783.             final Node<Implementation> declarationNode = new Node<Implementation>(
  784.                 declaration, null, null, descendant, declaration, declaration.isFinal(), false );

  785.             declarationNode.getModifiablePath().addAll( path );

  786.             contextImplementations.put( declaration.getIdentifier(), declarationNode );

  787.             path.addLast( declarationNode );

  788.             if ( declaration.getDependencies() != null )
  789.             {
  790.                 for ( int i = 0, s0 = declaration.getDependencies().getDependency().size(); i < s0; i++ )
  791.                 {
  792.                     final Dependency d = declaration.getDependencies().getDependency().get( i );
  793.                     final Node<Dependency> node =
  794.                         new Node<Dependency>( declaration, null, null, descendant, d, d.isFinal(), d.isOverride() );

  795.                     node.getModifiablePath().addAll( path );

  796.                     addNode( map( this.dependencies, context ), node, node.getModelObject().getName() );
  797.                 }
  798.             }

  799.             if ( declaration.getMessages() != null )
  800.             {
  801.                 for ( int i = 0, s0 = declaration.getMessages().getMessage().size(); i < s0; i++ )
  802.                 {
  803.                     final Message m = declaration.getMessages().getMessage().get( i );
  804.                     final Node<Message> node =
  805.                         new Node<Message>( declaration, null, null, descendant, m, m.isFinal(), m.isOverride() );

  806.                     node.getModifiablePath().addAll( path );

  807.                     addNode( map( this.messages, context ), node, node.getModelObject().getName() );
  808.                 }

  809.                 if ( !declaration.getMessages().getReference().isEmpty() )
  810.                 {
  811.                     final Module m = this.modules.getModuleOfImplementation( declaration.getIdentifier() );

  812.                     if ( m != null && m.getMessages() != null )
  813.                     {
  814.                         for ( int i = 0, s0 = declaration.getMessages().getReference().size(); i < s0; i++ )
  815.                         {
  816.                             final MessageReference r = declaration.getMessages().getReference().get( i );
  817.                             Message msg = m.getMessages().getMessage( r.getName() );

  818.                             if ( msg != null )
  819.                             {
  820.                                 msg = msg.clone();
  821.                                 msg.setFinal( r.isFinal() );
  822.                                 msg.setOverride( r.isOverride() );

  823.                                 final Node<Message> node = new Node<Message>(
  824.                                     declaration, null, null, descendant, msg, msg.isFinal(), msg.isOverride() );

  825.                                 node.getModifiablePath().addAll( path );

  826.                                 addNode( map( this.messages, context ), node, node.getModelObject().getName() );
  827.                             }
  828.                         }
  829.                     }
  830.                 }
  831.             }

  832.             if ( declaration.getProperties() != null )
  833.             {
  834.                 for ( int i = 0, s0 = declaration.getProperties().getProperty().size(); i < s0; i++ )
  835.                 {
  836.                     final Property p = declaration.getProperties().getProperty().get( i );
  837.                     final Node<Property> node =
  838.                         new Node<Property>( declaration, null, null, descendant, p, p.isFinal(), p.isOverride() );

  839.                     node.getModifiablePath().addAll( path );

  840.                     addNode( map( this.properties, context ), node, node.getModelObject().getName() );
  841.                 }

  842.                 if ( !declaration.getProperties().getReference().isEmpty() )
  843.                 {
  844.                     final Module m = this.modules.getModuleOfImplementation( declaration.getIdentifier() );

  845.                     if ( m != null && m.getProperties() != null )
  846.                     {
  847.                         for ( int i = 0, s0 = declaration.getProperties().getReference().size(); i < s0; i++ )
  848.                         {
  849.                             final PropertyReference r = declaration.getProperties().getReference().get( i );
  850.                             Property p = m.getProperties().getProperty( r.getName() );

  851.                             if ( p != null )
  852.                             {
  853.                                 p = p.clone();
  854.                                 p.setFinal( r.isFinal() );
  855.                                 p.setOverride( r.isOverride() );

  856.                                 final Node<Property> node = new Node<Property>(
  857.                                     declaration, null, null, descendant, p, p.isFinal(), p.isOverride() );

  858.                                 node.getModifiablePath().addAll( path );

  859.                                 addNode( map( this.properties, context ), node, node.getModelObject().getName() );
  860.                             }
  861.                         }
  862.                     }
  863.                 }
  864.             }

  865.             if ( declaration.getSpecifications() != null )
  866.             {
  867.                 for ( int i = 0, s0 = declaration.getSpecifications().getReference().size(); i < s0; i++ )
  868.                 {
  869.                     final SpecificationReference r = declaration.getSpecifications().getReference().get( i );
  870.                     final Node<SpecificationReference> node = new Node<SpecificationReference>(
  871.                         declaration, null, null, descendant, r, r.isFinal(), r.isOverride() );

  872.                     node.getModifiablePath().addAll( path );

  873.                     addNode( map( this.specReferences, context ), node, node.getModelObject().getIdentifier() );

  874.                     final Specification s = this.modules.getSpecification( r.getIdentifier() );

  875.                     if ( s != null && s.getProperties() != null )
  876.                     {
  877.                         for ( int j = 0, s1 = s.getProperties().getProperty().size(); j < s1; j++ )
  878.                         {
  879.                             final Property p = s.getProperties().getProperty().get( j );
  880.                             final Node<Property> n =
  881.                                 new Node<Property>( declaration, s, null, descendant, p, p.isFinal(), p.isOverride() );

  882.                             n.getModifiablePath().addAll( path );

  883.                             addNode( map( this.properties, context ), n, n.getModelObject().getName() );
  884.                         }
  885.                     }
  886.                 }
  887.             }

  888.             if ( !declaration.getAny().isEmpty() )
  889.             {
  890.                 for ( int i = 0, s0 = declaration.getAny().size(); i < s0; i++ )
  891.                 {
  892.                     final Object any = declaration.getAny().get( i );

  893.                     if ( any instanceof Element )
  894.                     {
  895.                         final Element e = (Element) any;
  896.                         final Node<Element> node =
  897.                             new Node<Element>( declaration, null, null, descendant, e, false, false );

  898.                         node.getModifiablePath().addAll( path );

  899.                         addNode( map( this.xmlElements, context ), node, getXmlElementName( e ) );
  900.                         continue;
  901.                     }

  902.                     if ( any instanceof JAXBElement<?> )
  903.                     {
  904.                         final JAXBElement<?> e = (JAXBElement<?>) any;
  905.                         boolean _final = false;
  906.                         boolean override = false;

  907.                         if ( e.getValue() instanceof Inheritable )
  908.                         {
  909.                             _final = ( (Inheritable) e.getValue() ).isFinal();
  910.                             override = ( (Inheritable) e.getValue() ).isOverride();
  911.                         }

  912.                         final Node<JAXBElement<?>> node =
  913.                             new Node<JAXBElement<?>>( declaration, null, null, descendant, e, _final, override );

  914.                         node.getModifiablePath().addAll( path );

  915.                         addNode( map( this.jaxbElements, context ), node, e.getName() );
  916.                         continue;
  917.                     }
  918.                 }
  919.             }

  920.             if ( declaration.getImplementations() != null
  921.                      && !declaration.getImplementations().getReference().isEmpty() )
  922.             {
  923.                 boolean all_cyclic = true;

  924.                 for ( int i = 0, s0 = declaration.getImplementations().getReference().size(); i < s0; i++ )
  925.                 {
  926.                     final ImplementationReference r = declaration.getImplementations().getReference().get( i );
  927.                     final Node<ImplementationReference> node = new Node<ImplementationReference>(
  928.                         declaration, null, null, descendant, r, r.isFinal(), r.isOverride() );

  929.                     node.getModifiablePath().addAll( path );

  930.                     final Implementation ancestor = this.modules.getImplementation( r.getIdentifier() );

  931.                     boolean cycle = false;
  932.                     if ( ancestor != null && contextImplementations.containsKey( ancestor.getIdentifier() ) )
  933.                     {
  934.                         for ( int j = 0, s1 = path.size(); j < s1; j++ )
  935.                         {
  936.                             final Node<Implementation> n = path.get( j );

  937.                             if ( n.getModelObject().getIdentifier().equals( ancestor.getIdentifier() ) )
  938.                             {
  939.                                 cycle = true;
  940.                                 node.getModifiablePath().add( n );
  941.                                 break;
  942.                             }
  943.                         }
  944.                     }

  945.                     if ( cycle )
  946.                     {
  947.                         addNode( this.cyclicImplReferences, node, context );
  948.                     }
  949.                     else
  950.                     {
  951.                         all_cyclic = false;
  952.                         addNode( map( this.implReferences, context ), node, node.getModelObject().getIdentifier() );
  953.                         this.collectNodes( context, ancestor, declarationNode, path );
  954.                     }
  955.                 }

  956.                 if ( all_cyclic )
  957.                 {
  958.                     map( this.sourceNodes, context ).
  959.                         put( declarationNode.getModelObject().getIdentifier(), declarationNode );

  960.                 }
  961.             }
  962.             else
  963.             {
  964.                 map( this.sourceNodes, context ).
  965.                     put( declarationNode.getModelObject().getIdentifier(), declarationNode );

  966.             }

  967.             path.removeLast();
  968.         }
  969.     }

  970.     private void collectEffectiveNodes( final String context, final Node<Implementation> node )
  971.     {
  972.         final Map<String, Set<Node<SpecificationReference>>> directSpecificationReferences =
  973.             getDirectEffectiveNodes( map( this.specReferences, context ), node.getModelObject().getIdentifier() );

  974.         final Map<String, Set<Node<Dependency>>> directDependencies =
  975.             getDirectEffectiveNodes( map( this.dependencies, context ), node.getModelObject().getIdentifier() );

  976.         final Map<String, Set<Node<Message>>> directMessages =
  977.             getDirectEffectiveNodes( map( this.messages, context ), node.getModelObject().getIdentifier() );

  978.         final Map<String, Set<Node<Property>>> directProperties =
  979.             getDirectEffectiveNodes( map( this.properties, context ), node.getModelObject().getIdentifier() );

  980.         final Map<String, Set<Node<ImplementationReference>>> directImplementationReferences =
  981.             getDirectEffectiveNodes( map( this.implReferences, context ), node.getModelObject().getIdentifier() );

  982.         final Map<QName, Set<Node<Element>>> directXmlElements =
  983.             getDirectEffectiveNodes( map( this.xmlElements, context ), node.getModelObject().getIdentifier() );

  984.         final Map<QName, Set<Node<JAXBElement<?>>>> directJaxbElements =
  985.             getDirectEffectiveNodes( map( this.jaxbElements, context ), node.getModelObject().getIdentifier() );

  986.         overrideNodes( map( this.effSpecReferences, context ), node, directSpecificationReferences );
  987.         overrideNodes( map( this.effImplReferences, context ), node, directImplementationReferences );
  988.         overrideNodes( map( this.effDependencies, context ), node, directDependencies );
  989.         overrideNodes( map( this.effMessages, context ), node, directMessages );
  990.         overrideNodes( map( this.effProperties, context ), node, directProperties );
  991.         overrideNodes( map( this.effJaxbElements, context ), node, directJaxbElements );
  992.         overrideNodes( map( this.effXmlElements, context ), node, directXmlElements );

  993.         this.addClassDeclarationNodes( context, node );

  994.         final Map<String, Set<Node<SpecificationReference>>> ancestorSpecificationReferences =
  995.             getEffectiveNodes( this.effSpecReferences, context, node.getModelObject().getIdentifier() );

  996.         final Map<String, Set<Node<Dependency>>> ancestorDependencies =
  997.             getEffectiveNodes( this.effDependencies, context, node.getModelObject().getIdentifier() );

  998.         final Map<String, Set<Node<Message>>> ancestorMessages =
  999.             getEffectiveNodes( this.effMessages, context, node.getModelObject().getIdentifier() );

  1000.         final Map<String, Set<Node<Property>>> ancestorProperties =
  1001.             getEffectiveNodes( this.effProperties, context, node.getModelObject().getIdentifier() );

  1002.         final Map<String, Set<Node<ImplementationReference>>> ancestorImplementationReferences =
  1003.             getEffectiveNodes( this.effImplReferences, context, node.getModelObject().getIdentifier() );

  1004.         final Map<QName, Set<Node<Element>>> ancestorXmlElements =
  1005.             getEffectiveNodes( this.effXmlElements, context, node.getModelObject().getIdentifier() );

  1006.         final Map<QName, Set<Node<JAXBElement<?>>>> ancestorJaxbElements =
  1007.             getEffectiveNodes( this.effJaxbElements, context, node.getModelObject().getIdentifier() );

  1008.         if ( node.getDescendant() != null )
  1009.         {
  1010.             if ( ancestorSpecificationReferences != null )
  1011.             {
  1012.                 inheritNodes( map( this.effSpecReferences, context ), ancestorSpecificationReferences,
  1013.                               node.getDescendant() );

  1014.             }

  1015.             if ( ancestorDependencies != null )
  1016.             {
  1017.                 inheritNodes( map( this.effDependencies, context ), ancestorDependencies,
  1018.                               node.getDescendant() );

  1019.             }

  1020.             if ( ancestorProperties != null )
  1021.             {
  1022.                 inheritNodes( map( this.effProperties, context ), ancestorProperties, node.getDescendant() );
  1023.             }

  1024.             if ( ancestorMessages != null )
  1025.             {
  1026.                 inheritNodes( map( this.effMessages, context ), ancestorMessages, node.getDescendant() );
  1027.             }

  1028.             if ( ancestorImplementationReferences != null )
  1029.             {
  1030.                 inheritNodes( map( this.effImplReferences, context ), ancestorImplementationReferences,
  1031.                               node.getDescendant() );

  1032.             }

  1033.             if ( ancestorXmlElements != null )
  1034.             {
  1035.                 inheritNodes( map( this.effXmlElements, context ), ancestorXmlElements,
  1036.                               node.getDescendant() );

  1037.             }

  1038.             if ( ancestorJaxbElements != null )
  1039.             {
  1040.                 inheritNodes( map( this.effJaxbElements, context ), ancestorJaxbElements,
  1041.                               node.getDescendant() );

  1042.             }

  1043.             collectEffectiveNodes( context, node.getDescendant() );
  1044.         }
  1045.     }

  1046.     private void addClassDeclarationNodes( final String context, final Node<Implementation> node )
  1047.     {
  1048.         final Implementation classDeclaration = this.getClassDeclaration( node.getModelObject() );

  1049.         if ( classDeclaration != null )
  1050.         {
  1051.             this.prepareContext( classDeclaration.getIdentifier() );

  1052.             Map<String, Set<Node<Dependency>>> effectiveDependencies =
  1053.                 getEffectiveNodes( this.effDependencies, context, node.getModelObject().getIdentifier() );

  1054.             Map<String, Set<Node<Message>>> effectiveMessages =
  1055.                 getEffectiveNodes( this.effMessages, context, node.getModelObject().getIdentifier() );

  1056.             Map<String, Set<Node<Property>>> effectiveProperties =
  1057.                 getEffectiveNodes( this.effProperties, context, node.getModelObject().getIdentifier() );

  1058.             Map<String, Set<Node<SpecificationReference>>> effectiveSpecificationReferences =
  1059.                 getEffectiveNodes( this.effSpecReferences, context, node.getModelObject().getIdentifier() );

  1060.             Map<QName, Set<Node<Element>>> effectiveXmlElements =
  1061.                 getEffectiveNodes( this.effXmlElements, context, node.getModelObject().getIdentifier() );

  1062.             Map<QName, Set<Node<JAXBElement<?>>>> effectiveJaxbElements =
  1063.                 getEffectiveNodes( this.effJaxbElements, context, node.getModelObject().getIdentifier() );

  1064.             final Map<String, Set<Node<Dependency>>> declDependencies =
  1065.                 getEffectiveNodes( this.effDependencies, classDeclaration.getIdentifier(),
  1066.                                    classDeclaration.getIdentifier() );

  1067.             final Map<String, Set<Node<Message>>> declMessages =
  1068.                 getEffectiveNodes( this.effMessages, classDeclaration.getIdentifier(),
  1069.                                    classDeclaration.getIdentifier() );

  1070.             final Map<String, Set<Node<Property>>> declProperties =
  1071.                 getEffectiveNodes( this.effProperties, classDeclaration.getIdentifier(),
  1072.                                    classDeclaration.getIdentifier() );

  1073.             final Map<String, Set<Node<SpecificationReference>>> declSpecReferences =
  1074.                 getEffectiveNodes( this.effSpecReferences, classDeclaration.getIdentifier(),
  1075.                                    classDeclaration.getIdentifier() );

  1076.             final Map<QName, Set<Node<Element>>> declXmlElements =
  1077.                 getEffectiveNodes( this.effXmlElements, classDeclaration.getIdentifier(),
  1078.                                    classDeclaration.getIdentifier() );

  1079.             final Map<QName, Set<Node<JAXBElement<?>>>> declJaxbElements =
  1080.                 getEffectiveNodes( this.effJaxbElements, classDeclaration.getIdentifier(),
  1081.                                    classDeclaration.getIdentifier() );

  1082.             if ( declDependencies != null )
  1083.             {
  1084.                 if ( effectiveDependencies == null )
  1085.                 {
  1086.                     effectiveDependencies = newMap();
  1087.                     map( this.effDependencies, context ).
  1088.                         put( node.getModelObject().getIdentifier(), effectiveDependencies );

  1089.                 }

  1090.                 for ( final Map.Entry<String, Set<Node<Dependency>>> e : declDependencies.entrySet() )
  1091.                 {
  1092.                     final Set<Node<Dependency>> set = newSet( e.getValue().size() );

  1093.                     for ( final Node<Dependency> n : e.getValue() )
  1094.                     {
  1095.                         final Node<Dependency> effNode = new Node<Dependency>(
  1096.                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
  1097.                             n.isFinal(), n.isOverride() );

  1098.                         effNode.getModifiablePath().addAll( n.getPath() );
  1099.                         set.add( effNode );

  1100.                         addNode( map( this.dependencies, context ), effNode, e.getKey() );
  1101.                     }

  1102.                     if ( effectiveDependencies.containsKey( e.getKey() ) )
  1103.                     {
  1104.                         for ( final Node<Dependency> effNode : effectiveDependencies.get( e.getKey() ) )
  1105.                         {
  1106.                             effNode.getModifiableOverriddenNodes().addAll( set );
  1107.                         }
  1108.                     }
  1109.                     else
  1110.                     {
  1111.                         effectiveDependencies.put( e.getKey(), set );
  1112.                     }
  1113.                 }
  1114.             }

  1115.             if ( declSpecReferences != null )
  1116.             {
  1117.                 if ( effectiveSpecificationReferences == null )
  1118.                 {
  1119.                     effectiveSpecificationReferences = newMap();
  1120.                     map( this.effSpecReferences, context ).
  1121.                         put( node.getModelObject().getIdentifier(), effectiveSpecificationReferences );

  1122.                 }

  1123.                 for ( final Map.Entry<String, Set<Node<SpecificationReference>>> e : declSpecReferences.entrySet() )
  1124.                 {
  1125.                     final Set<Node<SpecificationReference>> set = newSet( e.getValue().size() );

  1126.                     for ( final Node<SpecificationReference> n : e.getValue() )
  1127.                     {
  1128.                         final Node<SpecificationReference> effNode = new Node<SpecificationReference>(
  1129.                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
  1130.                             n.isFinal(), n.isOverride() );

  1131.                         effNode.getModifiablePath().addAll( n.getPath() );
  1132.                         set.add( effNode );

  1133.                         addNode( map( this.specReferences, context ), effNode, e.getKey() );
  1134.                     }

  1135.                     if ( effectiveSpecificationReferences.containsKey( e.getKey() ) )
  1136.                     {
  1137.                         for ( final Node<SpecificationReference> effNode
  1138.                                   : effectiveSpecificationReferences.get( e.getKey() ) )
  1139.                         {
  1140.                             effNode.getModifiableOverriddenNodes().addAll( set );
  1141.                         }
  1142.                     }
  1143.                     else
  1144.                     {
  1145.                         effectiveSpecificationReferences.put( e.getKey(), set );
  1146.                     }
  1147.                 }
  1148.             }

  1149.             if ( declMessages != null )
  1150.             {
  1151.                 if ( effectiveMessages == null )
  1152.                 {
  1153.                     effectiveMessages = newMap();
  1154.                     map( this.effMessages, context ).
  1155.                         put( node.getModelObject().getIdentifier(), effectiveMessages );

  1156.                 }

  1157.                 for ( final Map.Entry<String, Set<Node<Message>>> e : declMessages.entrySet() )
  1158.                 {
  1159.                     final Set<Node<Message>> set = newSet( e.getValue().size() );

  1160.                     for ( final Node<Message> n : e.getValue() )
  1161.                     {
  1162.                         final Node<Message> effNode = new Node<Message>(
  1163.                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
  1164.                             n.isFinal(), n.isOverride() );

  1165.                         effNode.getModifiablePath().addAll( n.getPath() );
  1166.                         set.add( effNode );

  1167.                         addNode( map( this.messages, context ), effNode, e.getKey() );
  1168.                     }

  1169.                     if ( effectiveMessages.containsKey( e.getKey() ) )
  1170.                     {
  1171.                         for ( final Node<Message> effNode : effectiveMessages.get( e.getKey() ) )
  1172.                         {
  1173.                             effNode.getModifiableOverriddenNodes().addAll( set );
  1174.                         }
  1175.                     }
  1176.                     else
  1177.                     {
  1178.                         effectiveMessages.put( e.getKey(), set );
  1179.                     }
  1180.                 }
  1181.             }

  1182.             if ( declProperties != null )
  1183.             {
  1184.                 if ( effectiveProperties == null )
  1185.                 {
  1186.                     effectiveProperties = newMap();
  1187.                     map( this.effProperties, context ).
  1188.                         put( node.getModelObject().getIdentifier(), effectiveProperties );

  1189.                 }

  1190.                 for ( final Map.Entry<String, Set<Node<Property>>> e : declProperties.entrySet() )
  1191.                 {
  1192.                     final Set<Node<Property>> set = newSet( e.getValue().size() );

  1193.                     for ( final Node<Property> n : e.getValue() )
  1194.                     {
  1195.                         final Node<Property> effNode = new Node<Property>(
  1196.                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
  1197.                             n.isFinal(), n.isOverride() );

  1198.                         effNode.getModifiablePath().addAll( n.getPath() );
  1199.                         set.add( effNode );

  1200.                         addNode( map( this.properties, context ), effNode, e.getKey() );
  1201.                     }

  1202.                     if ( effectiveProperties.containsKey( e.getKey() ) )
  1203.                     {
  1204.                         for ( final Node<Property> effNode : effectiveProperties.get( e.getKey() ) )
  1205.                         {
  1206.                             effNode.getModifiableOverriddenNodes().addAll( set );
  1207.                         }
  1208.                     }
  1209.                     else
  1210.                     {
  1211.                         effectiveProperties.put( e.getKey(), set );
  1212.                     }
  1213.                 }
  1214.             }

  1215.             if ( declXmlElements != null )
  1216.             {
  1217.                 if ( effectiveXmlElements == null )
  1218.                 {
  1219.                     effectiveXmlElements = newMap();
  1220.                     map( this.effXmlElements, context ).
  1221.                         put( node.getModelObject().getIdentifier(), effectiveXmlElements );

  1222.                 }

  1223.                 for ( final Map.Entry<QName, Set<Node<Element>>> e : declXmlElements.entrySet() )
  1224.                 {
  1225.                     final Set<Node<Element>> set = newSet( e.getValue().size() );

  1226.                     for ( final Node<Element> n : e.getValue() )
  1227.                     {
  1228.                         final Node<Element> effNode = new Node<Element>(
  1229.                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
  1230.                             n.isFinal(), n.isOverride() );

  1231.                         effNode.getModifiablePath().addAll( n.getPath() );
  1232.                         set.add( effNode );

  1233.                         addNode( map( this.xmlElements, context ), effNode, e.getKey() );
  1234.                     }

  1235.                     if ( effectiveXmlElements.containsKey( e.getKey() ) )
  1236.                     {
  1237.                         for ( final Node<Element> effNode : effectiveXmlElements.get( e.getKey() ) )
  1238.                         {
  1239.                             effNode.getModifiableOverriddenNodes().addAll( set );
  1240.                         }
  1241.                     }
  1242.                     else
  1243.                     {
  1244.                         effectiveXmlElements.put( e.getKey(), set );
  1245.                     }
  1246.                 }
  1247.             }

  1248.             if ( declJaxbElements != null )
  1249.             {
  1250.                 if ( effectiveJaxbElements == null )
  1251.                 {
  1252.                     effectiveJaxbElements = newMap();
  1253.                     map( this.effJaxbElements, context ).
  1254.                         put( node.getModelObject().getIdentifier(), effectiveJaxbElements );

  1255.                 }

  1256.                 for ( final Map.Entry<QName, Set<Node<JAXBElement<?>>>> e : declJaxbElements.entrySet() )
  1257.                 {
  1258.                     final Set<Node<JAXBElement<?>>> set = newSet( e.getValue().size() );

  1259.                     for ( final Node<JAXBElement<?>> n : e.getValue() )
  1260.                     {
  1261.                         final Node<JAXBElement<?>> effNode = new Node<JAXBElement<?>>(
  1262.                             node.getModelObject(), n.getSpecification(), classDeclaration, null, n.getModelObject(),
  1263.                             n.isFinal(), n.isOverride() );

  1264.                         effNode.getModifiablePath().addAll( n.getPath() );
  1265.                         set.add( effNode );

  1266.                         addNode( map( this.jaxbElements, context ), effNode, e.getKey() );
  1267.                     }

  1268.                     if ( effectiveJaxbElements.containsKey( e.getKey() ) )
  1269.                     {
  1270.                         for ( final Node<JAXBElement<?>> effNode : effectiveJaxbElements.get( e.getKey() ) )
  1271.                         {
  1272.                             effNode.getModifiableOverriddenNodes().addAll( set );
  1273.                         }
  1274.                     }
  1275.                     else
  1276.                     {
  1277.                         effectiveJaxbElements.put( e.getKey(), set );
  1278.                     }
  1279.                 }
  1280.             }
  1281.         }
  1282.     }

  1283.     private Implementation getClassDeclaration( final Implementation implementation )
  1284.     {
  1285.         Implementation declaration = null;

  1286.         if ( implementation.getClazz() != null && !implementation.isClassDeclaration() )
  1287.         {
  1288.             find:
  1289.             for ( int i = 0, s0 = this.modules.getModule().size(); i < s0; i++ )
  1290.             {
  1291.                 final Module candidateModule = this.modules.getModule().get( i );

  1292.                 if ( candidateModule.getImplementations() != null )
  1293.                 {
  1294.                     for ( int j = 0, s1 = candidateModule.getImplementations().getImplementation().size(); j < s1; j++ )
  1295.                     {
  1296.                         final Implementation candidate =
  1297.                             candidateModule.getImplementations().getImplementation().get( j );

  1298.                         if ( candidate.isClassDeclaration()
  1299.                                  && candidate.getClazz().equals( implementation.getClazz() ) )
  1300.                         {
  1301.                             declaration = candidate;
  1302.                             break find;
  1303.                         }
  1304.                     }
  1305.                 }
  1306.             }
  1307.         }

  1308.         return declaration;
  1309.     }

  1310.     private static <T, K> void addNode( final Map<K, Set<Node<T>>> map, final Node<T> node, final K key )
  1311.     {
  1312.         Set<Node<T>> set = map.get( key );

  1313.         if ( set == null )
  1314.         {
  1315.             set = newSet();
  1316.             map.put( key, set );
  1317.         }

  1318.         set.add( node );
  1319.     }

  1320.     private static <T, K> void overrideNodes( final Map<String, Map<K, Set<Node<T>>>> effective,
  1321.                                               final Node<Implementation> implementation,
  1322.                                               final Map<K, Set<Node<T>>> directNodes )
  1323.     {
  1324.         for ( final Map.Entry<K, Set<Node<T>>> e : directNodes.entrySet() )
  1325.         {
  1326.             final Set<Node<T>> effectiveNodes =
  1327.                 effectiveNodes( effective, implementation.getModelObject().getIdentifier(), e.getKey() );

  1328.             final Set<Node<T>> overridingNodes = newSet();

  1329.             for ( final Node<T> directNode : e.getValue() )
  1330.             {
  1331.                 for ( final Iterator<Node<T>> it = effectiveNodes.iterator(); it.hasNext(); )
  1332.                 {
  1333.                     final Node<T> effectiveNode = it.next();

  1334.                     if ( isOverriding( effectiveNode, directNode ) )
  1335.                     {
  1336.                         it.remove();

  1337.                         if ( directNode != effectiveNode )
  1338.                         {
  1339.                             directNode.getModifiableOverriddenNodes().add( effectiveNode );
  1340.                         }
  1341.                     }
  1342.                 }

  1343.                 boolean overriddenByAncestor = false;

  1344.                 if ( directNode.getSpecification() != null )
  1345.                 {
  1346.                     for ( final Node<T> effectiveNode : effectiveNodes )
  1347.                     {
  1348.                         if ( effectiveNode.getSpecification() == null )
  1349.                         {
  1350.                             overriddenByAncestor = true;
  1351.                             effectiveNode.getModifiableOverriddenNodes().add( directNode );
  1352.                         }
  1353.                     }
  1354.                 }

  1355.                 if ( !overriddenByAncestor )
  1356.                 {
  1357.                     overridingNodes.add( directNode );
  1358.                 }
  1359.             }

  1360.             effectiveNodes.addAll( overridingNodes );
  1361.         }
  1362.     }

  1363.     private static <K, V, T> Map<K, V> map( final Map<T, Map<K, V>> map, final T context )
  1364.     {
  1365.         Map<K, V> contextMap = map.get( context );

  1366.         if ( contextMap == null )
  1367.         {
  1368.             contextMap = newMap();
  1369.             map.put( context, contextMap );
  1370.         }

  1371.         return contextMap;
  1372.     }

  1373.     private static <K, V> Set<Node<V>> nodes( final Map<K, Set<Node<V>>> map, final K key )
  1374.     {
  1375.         Set<Node<V>> nodes = map.get( key );

  1376.         if ( nodes == null )
  1377.         {
  1378.             nodes = newSet();
  1379.             map.put( key, nodes );
  1380.         }

  1381.         return nodes;
  1382.     }

  1383.     private static <K, V> Set<Node<V>> effectiveNodes( final Map<String, Map<K, Set<Node<V>>>> map,
  1384.                                                        final String context, final K key )
  1385.     {
  1386.         return nodes( map( map, context ), key );
  1387.     }

  1388.     private static <T, K> void inheritNodes(
  1389.         final Map<String, Map<K, Set<Node<T>>>> effective, final Map<K, Set<Node<T>>> ancestor,
  1390.         final Node<Implementation> descendant )
  1391.     {
  1392.         for ( Map.Entry<K, Set<Node<T>>> e : ancestor.entrySet() )
  1393.         {
  1394.             for ( final Node<T> inherit : e.getValue() )
  1395.             {
  1396.                 if ( isInheritableNode( inherit ) )
  1397.                 {
  1398.                     effectiveNodes( effective, descendant.getModelObject().getIdentifier(), e.getKey() ).add( inherit );
  1399.                 }
  1400.             }
  1401.         }
  1402.     }

  1403.     private static <T, K> Map<K, Set<Node<T>>> getDirectEffectiveNodes( final Map<K, Set<Node<T>>> map,
  1404.                                                                         final String origin )
  1405.     {
  1406.         final Map<K, Set<Node<T>>> declarationMap = newMap( map.size() );

  1407.         for ( final Map.Entry<K, Set<Node<T>>> e : map.entrySet() )
  1408.         {
  1409.             final Set<Node<T>> set = nodes( declarationMap, e.getKey() );

  1410.             for ( final Node<T> n : e.getValue() )
  1411.             {
  1412.                 if ( isDirectEffectiveNode( n, origin ) )
  1413.                 {
  1414.                     set.add( n );
  1415.                 }
  1416.             }

  1417.             for ( final Node<T> n : e.getValue() )
  1418.             {
  1419.                 if ( isDirectSpecifiedNode( n, origin ) )
  1420.                 {
  1421.                     boolean add = true;

  1422.                     for ( final Node<T> override : set )
  1423.                     {
  1424.                         if ( override.getSpecification() == null )
  1425.                         {
  1426.                             override.getModifiableOverriddenNodes().add( n );
  1427.                             add = false;
  1428.                         }
  1429.                     }

  1430.                     if ( add )
  1431.                     {
  1432.                         set.add( n );
  1433.                     }
  1434.                 }
  1435.             }
  1436.         }

  1437.         return declarationMap;
  1438.     }

  1439.     private static <T, K> Map<K, Set<Node<T>>> getEffectiveNodes(
  1440.         final Map<String, Map<String, Map<K, Set<Node<T>>>>> effective, final String context,
  1441.         final String implementation )
  1442.     {
  1443.         return map( effective, context ).get( implementation );
  1444.     }

  1445.     private static boolean isDirectNode( final Node<?> node, final String implementation )
  1446.     {
  1447.         return implementation.equals( node.getImplementation().getIdentifier() );
  1448.     }

  1449.     private static boolean isDirectEffectiveNode( final Node<?> node, final String implementation )
  1450.     {
  1451.         return isDirectNode( node, implementation ) && node.getClassDeclaration() == null
  1452.                    && node.getSpecification() == null;

  1453.     }

  1454.     private static boolean isDirectSpecifiedNode( final Node<?> node, final String implementation )
  1455.     {
  1456.         return isDirectNode( node, implementation ) && node.getClassDeclaration() == null
  1457.                    && node.getSpecification() != null;

  1458.     }

  1459.     private static boolean isOverriding( final Node<?> node, final Node<?> override )
  1460.     {
  1461.         if ( override.getSpecification() != null )
  1462.         {
  1463.             if ( node.getSpecification() == null )
  1464.             {
  1465.                 return false;
  1466.             }
  1467.             else if ( !override.getSpecification().getIdentifier().equals( node.getSpecification().getIdentifier() ) )
  1468.             {
  1469.                 return false;
  1470.             }
  1471.         }

  1472.         return true;
  1473.     }

  1474.     private static boolean isInheritableNode( final Node<?> node )
  1475.     {
  1476.         return node.getClassDeclaration() == null;
  1477.     }

  1478.     private static <K, V> Map<K, V> newMap()
  1479.     {
  1480.         return new HashMap<K, V>();
  1481.     }

  1482.     private static <K, V> Map<K, V> newMap( final int initialCapacity )
  1483.     {
  1484.         return new HashMap<K, V>( initialCapacity );
  1485.     }

  1486.     private static <T> Set<T> newSet()
  1487.     {
  1488.         return new HashSet<T>();
  1489.     }

  1490.     private static <T> Set<T> newSet( final int initialCapacity )
  1491.     {
  1492.         return new HashSet<T>( initialCapacity );
  1493.     }

  1494.     private static <T> Set<T> newSet( final Collection<? extends T> col )
  1495.     {
  1496.         return new HashSet<T>( col );
  1497.     }

  1498.     private static <T> Set<T> unmodifiableSet( final Set<T> set )
  1499.     {
  1500.         return set != null ? Collections.unmodifiableSet( set ) : Collections.<T>emptySet();
  1501.     }

  1502.     private static QName getXmlElementName( final Element element )
  1503.     {
  1504.         if ( element.getNamespaceURI() != null )
  1505.         {
  1506.             return new QName( element.getNamespaceURI(), element.getLocalName() );
  1507.         }
  1508.         else
  1509.         {
  1510.             return new QName( element.getLocalName() );
  1511.         }
  1512.     }

  1513. }