ToolsModelProvider.java

  1. /*
  2.  *   Copyright (C) Christian Schulte <cs@schulte.it>, 2005-206
  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: ToolsModelProvider.java 5043 2015-05-27 07:03:39Z schulte $
  29.  *
  30.  */
  31. package org.jomc.tools.modlet;

  32. import java.lang.reflect.Field;
  33. import java.text.MessageFormat;
  34. import java.util.ArrayList;
  35. import java.util.HashMap;
  36. import java.util.HashSet;
  37. import java.util.Locale;
  38. import java.util.Map;
  39. import java.util.ResourceBundle;
  40. import java.util.Set;
  41. import java.util.logging.Level;
  42. import javax.xml.bind.JAXBElement;
  43. import javax.xml.namespace.QName;
  44. import org.jomc.model.Dependencies;
  45. import org.jomc.model.Implementation;
  46. import org.jomc.model.InheritanceModel;
  47. import org.jomc.model.JavaTypeName;
  48. import org.jomc.model.Messages;
  49. import org.jomc.model.ModelObjectException;
  50. import org.jomc.model.Module;
  51. import org.jomc.model.Modules;
  52. import org.jomc.model.Properties;
  53. import org.jomc.model.Specification;
  54. import org.jomc.model.Specifications;
  55. import org.jomc.model.modlet.ModelHelper;
  56. import org.jomc.modlet.Model;
  57. import org.jomc.modlet.ModelContext;
  58. import org.jomc.modlet.ModelException;
  59. import org.jomc.modlet.ModelProvider;
  60. import org.jomc.tools.model.ObjectFactory;
  61. import org.jomc.tools.model.SourceFileType;
  62. import org.jomc.tools.model.SourceFilesType;
  63. import org.jomc.tools.model.SourceSectionType;
  64. import org.jomc.tools.model.SourceSectionsType;
  65. import static org.jomc.tools.modlet.ToolsModletConstants.ANNOTATIONS_SECTION_NAME;
  66. import static org.jomc.tools.modlet.ToolsModletConstants.CONSTRUCTORS_HEAD_TEMPLATE;
  67. import static org.jomc.tools.modlet.ToolsModletConstants.CONSTRUCTORS_SECTION_NAME;
  68. import static org.jomc.tools.modlet.ToolsModletConstants.CONSTRUCTORS_TAIL_TEMPLATE;
  69. import static org.jomc.tools.modlet.ToolsModletConstants.DEFAULT_CONSTRUCTOR_SECTION_NAME;
  70. import static org.jomc.tools.modlet.ToolsModletConstants.DEFAULT_CONSTRUCTOR_TEMPLATE;
  71. import static org.jomc.tools.modlet.ToolsModletConstants.DEPENDENCIES_SECTION_NAME;
  72. import static org.jomc.tools.modlet.ToolsModletConstants.DEPENDENCIES_TEMPLATE;
  73. import static org.jomc.tools.modlet.ToolsModletConstants.DOCUMENTATION_SECTION_NAME;
  74. import static org.jomc.tools.modlet.ToolsModletConstants.IMPLEMENTATION_ANNOTATIONS_TEMPLATE;
  75. import static org.jomc.tools.modlet.ToolsModletConstants.IMPLEMENTATION_DOCUMENTATION_TEMPLATE;
  76. import static org.jomc.tools.modlet.ToolsModletConstants.IMPLEMENTATION_LICENSE_TEMPLATE;
  77. import static org.jomc.tools.modlet.ToolsModletConstants.IMPLEMENTATION_TEMPLATE;
  78. import static org.jomc.tools.modlet.ToolsModletConstants.LICENSE_SECTION_NAME;
  79. import static org.jomc.tools.modlet.ToolsModletConstants.MESSAGES_SECTION_NAME;
  80. import static org.jomc.tools.modlet.ToolsModletConstants.MESSAGES_TEMPLATE;
  81. import static org.jomc.tools.modlet.ToolsModletConstants.PROPERTIES_SECTION_NAME;
  82. import static org.jomc.tools.modlet.ToolsModletConstants.PROPERTIES_TEMPLATE;
  83. import static org.jomc.tools.modlet.ToolsModletConstants.SPECIFICATION_ANNOTATIONS_TEMPLATE;
  84. import static org.jomc.tools.modlet.ToolsModletConstants.SPECIFICATION_DOCUMENTATION_TEMPLATE;
  85. import static org.jomc.tools.modlet.ToolsModletConstants.SPECIFICATION_LICENSE_TEMPLATE;
  86. import static org.jomc.tools.modlet.ToolsModletConstants.SPECIFICATION_TEMPLATE;

  87. /**
  88.  * Object management and configuration tools {@code ModelProvider} implementation.
  89.  *
  90.  * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
  91.  * @version $JOMC: ToolsModelProvider.java 5043 2015-05-27 07:03:39Z schulte $
  92.  * @see ModelContext#findModel(java.lang.String)
  93.  * @since 1.2
  94.  */
  95. public class ToolsModelProvider implements ModelProvider
  96. {

  97.     /**
  98.      * Constant for the qualified name of {@code source-files} elements.
  99.      */
  100.     private static final QName SOURCE_FILES_QNAME = new ObjectFactory().createSourceFiles( null ).getName();

  101.     /**
  102.      * Constant for the name of the model context attribute backing property {@code enabled}.
  103.      *
  104.      * @see #findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
  105.      * @see ModelContext#getAttribute(java.lang.String)
  106.      */
  107.     public static final String ENABLED_ATTRIBUTE_NAME = "org.jomc.tools.modlet.ToolsModelProvider.enabledAttribute";

  108.     /**
  109.      * Constant for the name of the system property controlling property {@code defaultEnabled}.
  110.      *
  111.      * @see #isDefaultEnabled()
  112.      */
  113.     private static final String DEFAULT_ENABLED_PROPERTY_NAME =
  114.         "org.jomc.tools.modlet.ToolsModelProvider.defaultEnabled";

  115.     /**
  116.      * Default value of the flag indicating the provider is enabled by default.
  117.      *
  118.      * @see #isDefaultEnabled()
  119.      */
  120.     private static final Boolean DEFAULT_ENABLED = Boolean.TRUE;

  121.     /**
  122.      * Flag indicating the provider is enabled by default.
  123.      */
  124.     private static volatile Boolean defaultEnabled;

  125.     /**
  126.      * Flag indicating the provider is enabled.
  127.      */
  128.     private Boolean enabled;

  129.     /**
  130.      * Constant for the name of the model context attribute backing property
  131.      * {@code modelObjectClasspathResolutionEnabled}.
  132.      *
  133.      * @see #findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
  134.      * @see ModelContext#getAttribute(java.lang.String)
  135.      */
  136.     public static final String MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME =
  137.         "org.jomc.tools.modlet.ToolsModelProvider.modelObjectClasspathResolutionEnabledAttribute";

  138.     /**
  139.      * Constant for the name of the system property controlling property
  140.      * {@code defaultModelObjectClasspathResolutionEnabled}.
  141.      *
  142.      * @see #isDefaultModelObjectClasspathResolutionEnabled()
  143.      */
  144.     private static final String DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_PROPERTY_NAME =
  145.         "org.jomc.tools.modlet.ToolsModelProvider.defaultModelObjectClasspathResolutionEnabled";

  146.     /**
  147.      * Default value of the flag indicating model object class path resolution is enabled by default.
  148.      *
  149.      * @see #isDefaultModelObjectClasspathResolutionEnabled()
  150.      */
  151.     private static final Boolean DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED = Boolean.TRUE;

  152.     /**
  153.      * Flag indicating model object class path resolution is enabled by default.
  154.      */
  155.     private static volatile Boolean defaultModelObjectClasspathResolutionEnabled;

  156.     /**
  157.      * Flag indicating model object class path resolution is enabled.
  158.      */
  159.     private Boolean modelObjectClasspathResolutionEnabled;

  160.     /**
  161.      * Constant for the name of the model context attribute backing property {@code headComment}.
  162.      *
  163.      * @see #findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
  164.      * @see ModelContext#getAttribute(java.lang.String)
  165.      * @since 1.6
  166.      */
  167.     public static final String HEAD_COMMENT_ATTRIBUTE_NAME =
  168.         "org.jomc.tools.modlet.ToolsModelProvider.headCommentAttribute";

  169.     /**
  170.      * Constant for the name of the system property controlling property {@code defaultHeadComment}.
  171.      *
  172.      * @see #getDefaultHeadComment()
  173.      * @since 1.6
  174.      */
  175.     private static final String DEFAULT_HEAD_COMMENT_PROPERTY_NAME =
  176.         "org.jomc.tools.modlet.ToolsModelProvider.defaultHeadComment";

  177.     /**
  178.      * Default head comment the provider is providing by default.
  179.      *
  180.      * @see #getDefaultHeadComment()
  181.      * @since 1.6
  182.      */
  183.     private static final String DEFAULT_HEAD_COMMENT = "//";

  184.     /**
  185.      * Head comment the provider is providing by default.
  186.      *
  187.      * @since 1.6
  188.      */
  189.     private static volatile String defaultHeadComment;

  190.     /**
  191.      * Head comment the provider is providing.
  192.      *
  193.      * @since 1.6
  194.      */
  195.     private String headComment;

  196.     /**
  197.      * Constant for the name of the model context attribute backing property {@code tailComment}.
  198.      *
  199.      * @see #findModel(org.jomc.modlet.ModelContext, org.jomc.modlet.Model)
  200.      * @see ModelContext#getAttribute(java.lang.String)
  201.      * @since 1.6
  202.      */
  203.     public static final String TAIL_COMMENT_ATTRIBUTE_NAME =
  204.         "org.jomc.tools.modlet.ToolsModelProvider.tailCommentAttribute";

  205.     /**
  206.      * Constant for the name of the system property controlling property {@code defaultTailComment}.
  207.      *
  208.      * @see #getDefaultTailComment()
  209.      * @since 1.6
  210.      */
  211.     private static final String DEFAULT_TAIL_COMMENT_PROPERTY_NAME =
  212.         "org.jomc.tools.modlet.ToolsModelProvider.defaultTailComment";

  213.     /**
  214.      * Default tail comment the provider is providing by default.
  215.      *
  216.      * @see #getDefaultTailComment()
  217.      * @since 1.6
  218.      */
  219.     private static final String DEFAULT_TAIL_COMMENT = null;

  220.     /**
  221.      * Tail comment the provider is providing by default.
  222.      *
  223.      * @since 1.6
  224.      */
  225.     private static volatile String defaultTailComment;

  226.     /**
  227.      * Tail comment the provider is providing.
  228.      *
  229.      * @since 1.6
  230.      */
  231.     private String tailComment;

  232.     /**
  233.      * Creates a new {@code ToolsModelProvider} instance.
  234.      */
  235.     public ToolsModelProvider()
  236.     {
  237.         super();
  238.     }

  239.     /**
  240.      * Gets a flag indicating the provider is enabled by default.
  241.      * <p>
  242.      * The default enabled flag is controlled by system property
  243.      * {@code org.jomc.tools.modlet.ToolsModelProvider.defaultEnabled} holding a value indicating the provider is
  244.      * enabled by default. If that property is not set, the {@code true} default is returned.
  245.      * </p>
  246.      *
  247.      * @return {@code true}, if the provider is enabled by default; {@code false}, if the provider is disabled by
  248.      * default.
  249.      *
  250.      * @see #setDefaultEnabled(java.lang.Boolean)
  251.      */
  252.     public static boolean isDefaultEnabled()
  253.     {
  254.         if ( defaultEnabled == null )
  255.         {
  256.             defaultEnabled = Boolean.valueOf( System.getProperty( DEFAULT_ENABLED_PROPERTY_NAME,
  257.                                                                   Boolean.toString( DEFAULT_ENABLED ) ) );

  258.         }

  259.         return defaultEnabled;
  260.     }

  261.     /**
  262.      * Sets the flag indicating the provider is enabled by default.
  263.      *
  264.      * @param value The new value of the flag indicating the provider is enabled by default or {@code null}.
  265.      *
  266.      * @see #isDefaultEnabled()
  267.      */
  268.     public static void setDefaultEnabled( final Boolean value )
  269.     {
  270.         defaultEnabled = value;
  271.     }

  272.     /**
  273.      * Gets a flag indicating the provider is enabled.
  274.      *
  275.      * @return {@code true}, if the provider is enabled; {@code false}, if the provider is disabled.
  276.      *
  277.      * @see #isDefaultEnabled()
  278.      * @see #setEnabled(java.lang.Boolean)
  279.      */
  280.     public final boolean isEnabled()
  281.     {
  282.         if ( this.enabled == null )
  283.         {
  284.             this.enabled = isDefaultEnabled();
  285.         }

  286.         return this.enabled;
  287.     }

  288.     /**
  289.      * Sets the flag indicating the provider is enabled.
  290.      *
  291.      * @param value The new value of the flag indicating the provider is enabled or {@code null}.
  292.      *
  293.      * @see #isEnabled()
  294.      */
  295.     public final void setEnabled( final Boolean value )
  296.     {
  297.         this.enabled = value;
  298.     }

  299.     /**
  300.      * Gets a flag indicating model object class path resolution is enabled by default.
  301.      * <p>
  302.      * The model object class path resolution default enabled flag is controlled by system property
  303.      * {@code org.jomc.tools.modlet.ToolsModelProvider.defaultModelObjectClasspathResolutionEnabled} holding a value
  304.      * indicating model object class path resolution is enabled by default. If that property is not set, the
  305.      * {@code true} default is returned.
  306.      * </p>
  307.      *
  308.      * @return {@code true}, if model object class path resolution is enabled by default; {@code false}, if model object
  309.      * class path resolution is disabled by default.
  310.      *
  311.      * @see #setDefaultModelObjectClasspathResolutionEnabled(java.lang.Boolean)
  312.      */
  313.     public static boolean isDefaultModelObjectClasspathResolutionEnabled()
  314.     {
  315.         if ( defaultModelObjectClasspathResolutionEnabled == null )
  316.         {
  317.             defaultModelObjectClasspathResolutionEnabled = Boolean.valueOf( System.getProperty(
  318.                 DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_PROPERTY_NAME,
  319.                 Boolean.toString( DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED ) ) );

  320.         }

  321.         return defaultModelObjectClasspathResolutionEnabled;
  322.     }

  323.     /**
  324.      * Sets the flag indicating model object class path resolution is enabled by default.
  325.      *
  326.      * @param value The new value of the flag indicating model object class path resolution is enabled by default or
  327.      * {@code null}.
  328.      *
  329.      * @see #isDefaultModelObjectClasspathResolutionEnabled()
  330.      */
  331.     public static void setDefaultModelObjectClasspathResolutionEnabled( final Boolean value )
  332.     {
  333.         defaultModelObjectClasspathResolutionEnabled = value;
  334.     }

  335.     /**
  336.      * Gets a flag indicating model object class path resolution is enabled.
  337.      *
  338.      * @return {@code true}, if model object class path resolution is enabled; {@code false}, if model object class path
  339.      * resolution is disabled.
  340.      *
  341.      * @see #isDefaultModelObjectClasspathResolutionEnabled()
  342.      * @see #setModelObjectClasspathResolutionEnabled(java.lang.Boolean)
  343.      */
  344.     public final boolean isModelObjectClasspathResolutionEnabled()
  345.     {
  346.         if ( this.modelObjectClasspathResolutionEnabled == null )
  347.         {
  348.             this.modelObjectClasspathResolutionEnabled = isDefaultModelObjectClasspathResolutionEnabled();
  349.         }

  350.         return this.modelObjectClasspathResolutionEnabled;
  351.     }

  352.     /**
  353.      * Sets the flag indicating model object class path resolution is is enabled.
  354.      *
  355.      * @param value The new value of the flag indicating model object class path resolution is enabled or {@code null}.
  356.      *
  357.      * @see #isModelObjectClasspathResolutionEnabled()
  358.      */
  359.     public final void setModelObjectClasspathResolutionEnabled( final Boolean value )
  360.     {
  361.         this.modelObjectClasspathResolutionEnabled = value;
  362.     }

  363.     /**
  364.      * Gets the head comment the provider is providing by default.
  365.      * <p>
  366.      * The default head comment is controlled by system property
  367.      * {@code org.jomc.tools.modlet.ToolsModelProvider.defaultHeadComment} holding the head comment the provider is
  368.      * providing by default. If that property is not set, the {@code //} default is returned.
  369.      * </p>
  370.      *
  371.      * @return The head comment the provider is providing by default or {@code null}.
  372.      *
  373.      * @see #setDefaultHeadComment(java.lang.String)
  374.      * @since 1.6
  375.      */
  376.     public static String getDefaultHeadComment()
  377.     {
  378.         if ( defaultHeadComment == null )
  379.         {
  380.             defaultHeadComment = System.getProperty( DEFAULT_HEAD_COMMENT_PROPERTY_NAME, DEFAULT_HEAD_COMMENT );
  381.         }

  382.         return defaultHeadComment;
  383.     }

  384.     /**
  385.      * Sets the head comment the provider is providing by default.
  386.      *
  387.      * @param value The new head comment the provider is providing by default or {@code null}.
  388.      *
  389.      * @see #getDefaultHeadComment()
  390.      * @since 1.6
  391.      */
  392.     public static void setDefaultHeadComment( final String value )
  393.     {
  394.         defaultHeadComment = value;
  395.     }

  396.     /**
  397.      * Gets the head comment the provider is providing.
  398.      *
  399.      * @return The head comment the provider is providing or {@code null}.
  400.      *
  401.      * @see #getDefaultHeadComment()
  402.      * @see #setDefaultHeadComment(java.lang.String)
  403.      * @since 1.6
  404.      */
  405.     public final String getHeadComment()
  406.     {
  407.         if ( this.headComment == null )
  408.         {
  409.             this.headComment = getDefaultHeadComment();
  410.         }

  411.         return this.headComment;
  412.     }

  413.     /**
  414.      * Sets the head comment the provider is providing.
  415.      *
  416.      * @param value The new head comment the provider is providing or {@code null}.
  417.      *
  418.      * @see #getHeadComment()
  419.      * @since 1.6
  420.      */
  421.     public final void setHeadComment( final String value )
  422.     {
  423.         this.headComment = value;
  424.     }

  425.     /**
  426.      * Gets the tail comment the provider is providing by default.
  427.      * <p>
  428.      * The default tail comment is controlled by system property
  429.      * {@code org.jomc.tools.modlet.ToolsModelProvider.defaultTailComment} holding the tail comment the provider is
  430.      * providing by default. If that property is not set, the {@code null} default is returned.
  431.      * </p>
  432.      *
  433.      * @return The tail comment the provider is providing by default or {@code null}.
  434.      *
  435.      * @see #setDefaultTailComment(java.lang.String)
  436.      * @since 1.6
  437.      */
  438.     public static String getDefaultTailComment()
  439.     {
  440.         if ( defaultTailComment == null )
  441.         {
  442.             defaultTailComment = System.getProperty( DEFAULT_TAIL_COMMENT_PROPERTY_NAME, DEFAULT_TAIL_COMMENT );
  443.         }

  444.         return defaultTailComment;
  445.     }

  446.     /**
  447.      * Sets the tail comment the provider is providing by default.
  448.      *
  449.      * @param value The new tail comment the provider is providing by default or {@code null}.
  450.      *
  451.      * @see #getDefaultTailComment()
  452.      * @since 1.6
  453.      */
  454.     public static void setDefaultTailComment( final String value )
  455.     {
  456.         defaultTailComment = value;
  457.     }

  458.     /**
  459.      * Gets the tail comment the provider is providing.
  460.      *
  461.      * @return The tail comment the provider is providing or {@code null}.
  462.      *
  463.      * @see #getDefaultTailComment()
  464.      * @see #setDefaultTailComment(java.lang.String)
  465.      * @since 1.6
  466.      */
  467.     public final String getTailComment()
  468.     {
  469.         if ( this.tailComment == null )
  470.         {
  471.             this.tailComment = getDefaultTailComment();
  472.         }

  473.         return this.tailComment;
  474.     }

  475.     /**
  476.      * Sets the tail comment the provider is providing.
  477.      *
  478.      * @param value The new tail comment the provider is providing or {@code null}.
  479.      *
  480.      * @see #getTailComment()
  481.      * @since 1.6
  482.      */
  483.     public final void setTailComment( final String value )
  484.     {
  485.         this.tailComment = value;
  486.     }

  487.     /**
  488.      * {@inheritDoc}
  489.      *
  490.      * @see #isEnabled()
  491.      * @see #isModelObjectClasspathResolutionEnabled()
  492.      * @see #getHeadComment()
  493.      * @see #getTailComment()
  494.      * @see #ENABLED_ATTRIBUTE_NAME
  495.      * @see #MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME
  496.      * @see #HEAD_COMMENT_ATTRIBUTE_NAME
  497.      * @see #TAIL_COMMENT_ATTRIBUTE_NAME
  498.      */
  499.     public Model findModel( final ModelContext context, final Model model ) throws ModelException
  500.     {
  501.         if ( context == null )
  502.         {
  503.             throw new NullPointerException( "context" );
  504.         }
  505.         if ( model == null )
  506.         {
  507.             throw new NullPointerException( "model" );
  508.         }

  509.         Model provided = null;

  510.         boolean contextEnabled = this.isEnabled();
  511.         if ( DEFAULT_ENABLED == contextEnabled && context.getAttribute( ENABLED_ATTRIBUTE_NAME ) instanceof Boolean )
  512.         {
  513.             contextEnabled = (Boolean) context.getAttribute( ENABLED_ATTRIBUTE_NAME );
  514.         }

  515.         boolean contextModelObjectClasspathResolutionEnabled = this.isModelObjectClasspathResolutionEnabled();
  516.         if ( contextModelObjectClasspathResolutionEnabled == DEFAULT_MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED
  517.                  && context.getAttribute( MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME ) instanceof Boolean )
  518.         {
  519.             contextModelObjectClasspathResolutionEnabled =
  520.                 (Boolean) context.getAttribute( MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME );

  521.         }

  522.         if ( contextEnabled )
  523.         {
  524.             provided = model.clone();
  525.             final Modules modules = ModelHelper.getModules( provided );

  526.             if ( modules != null )
  527.             {
  528.                 Module classpathModule = null;
  529.                 if ( contextModelObjectClasspathResolutionEnabled )
  530.                 {
  531.                     classpathModule = modules.getClasspathModule( Modules.getDefaultClasspathModuleName(),
  532.                                                                   context.getClassLoader() );

  533.                     if ( classpathModule != null
  534.                              && modules.getModule( Modules.getDefaultClasspathModuleName() ) == null )
  535.                     {
  536.                         modules.getModule().add( classpathModule );
  537.                     }
  538.                     else
  539.                     {
  540.                         classpathModule = null;
  541.                     }
  542.                 }

  543.                 if ( modules.getSpecifications() != null )
  544.                 {
  545.                     for ( int i = 0, s0 = modules.getSpecifications().getSpecification().size(); i < s0; i++ )
  546.                     {
  547.                         final Specification specification = modules.getSpecifications().getSpecification().get( i );
  548.                         final SourceFileType sourceFileType = specification.getAnyObject( SourceFileType.class );
  549.                         final SourceFilesType sourceFilesType = specification.getAnyObject( SourceFilesType.class );

  550.                         if ( sourceFileType == null && specification.isClassDeclaration() )
  551.                         {
  552.                             final SourceFilesType defaultSourceFiles =
  553.                                 this.getDefaultSourceFilesType( context, modules, specification );

  554.                             if ( sourceFilesType != null )
  555.                             {
  556.                                 this.overwriteSourceFiles( sourceFilesType, defaultSourceFiles, true );
  557.                             }
  558.                             else
  559.                             {
  560.                                 specification.getAny().add(
  561.                                     new ObjectFactory().createSourceFiles( defaultSourceFiles ) );

  562.                             }
  563.                         }
  564.                     }
  565.                 }

  566.                 if ( modules.getImplementations() != null )
  567.                 {
  568.                     final Map<Implementation, SourceFilesType> userSourceFiles =
  569.                         new HashMap<Implementation, SourceFilesType>(
  570.                             modules.getImplementations().getImplementation().size() );

  571.                     InheritanceModel imodel = new InheritanceModel( modules );

  572.                     for ( int i = 0, s0 = modules.getImplementations().getImplementation().size(); i < s0; i++ )
  573.                     {
  574.                         final Implementation implementation = modules.getImplementations().getImplementation().get( i );
  575.                         final SourceFileType sourceFileType = implementation.getAnyObject( SourceFileType.class );
  576.                         final SourceFilesType sourceFilesType = implementation.getAnyObject( SourceFilesType.class );

  577.                         if ( sourceFileType == null )
  578.                         {
  579.                             if ( sourceFilesType != null )
  580.                             {
  581.                                 userSourceFiles.put( implementation, sourceFilesType );
  582.                             }
  583.                             else if ( implementation.isClassDeclaration() )
  584.                             {
  585.                                 final SourceFilesType defaultSourceFiles =
  586.                                     this.getDefaultSourceFilesType( context, modules, implementation );

  587.                                 boolean finalAncestor = false;

  588.                                 final Set<InheritanceModel.Node<JAXBElement<?>>> sourceFilesNodes =
  589.                                     imodel.getJaxbElementNodes( implementation.getIdentifier(), SOURCE_FILES_QNAME );

  590.                                 for ( final InheritanceModel.Node<JAXBElement<?>> sourceFilesNode : sourceFilesNodes )
  591.                                 {
  592.                                     if ( sourceFilesNode.getModelObject().getValue() instanceof SourceFilesType )
  593.                                     {
  594.                                         final SourceFilesType ancestorSourceFiles =
  595.                                             (SourceFilesType) sourceFilesNode.getModelObject().getValue();

  596.                                         this.overwriteSourceFiles( defaultSourceFiles, ancestorSourceFiles, false );

  597.                                         if ( ancestorSourceFiles.isFinal() )
  598.                                         {
  599.                                             finalAncestor = true;
  600.                                         }
  601.                                     }
  602.                                 }

  603.                                 if ( !finalAncestor )
  604.                                 {
  605.                                     implementation.getAny().add(
  606.                                         new ObjectFactory().createSourceFiles( defaultSourceFiles ) );

  607.                                 }
  608.                             }
  609.                         }
  610.                     }

  611.                     for ( final Map.Entry<Implementation, SourceFilesType> e : userSourceFiles.entrySet() )
  612.                     {
  613.                         this.overwriteSourceFiles( e.getValue(), this.getDefaultSourceFilesType(
  614.                                                    context, modules, e.getKey() ), true );

  615.                     }

  616.                     imodel = new InheritanceModel( modules );

  617.                     for ( int i = 0, s0 = modules.getImplementations().getImplementation().size(); i < s0; i++ )
  618.                     {
  619.                         final Implementation implementation = modules.getImplementations().getImplementation().get( i );
  620.                         final SourceFilesType sourceFilesType = implementation.getAnyObject( SourceFilesType.class );

  621.                         if ( sourceFilesType != null && !userSourceFiles.containsKey( implementation ) )
  622.                         {
  623.                             boolean override = false;

  624.                             final Set<InheritanceModel.Node<JAXBElement<?>>> sourceFilesNodes =
  625.                                 imodel.getJaxbElementNodes( implementation.getIdentifier(), SOURCE_FILES_QNAME );

  626.                             for ( final InheritanceModel.Node<JAXBElement<?>> e : sourceFilesNodes )
  627.                             {
  628.                                 if ( !e.getOverriddenNodes().isEmpty() )
  629.                                 {
  630.                                     override = true;
  631.                                     break;
  632.                                 }
  633.                             }

  634.                             if ( override )
  635.                             {
  636.                                 sourceFilesType.setOverride( override );
  637.                             }
  638.                         }
  639.                     }
  640.                 }

  641.                 if ( classpathModule != null )
  642.                 {
  643.                     modules.getModule().remove( classpathModule );
  644.                 }
  645.             }
  646.         }
  647.         else if ( context.isLoggable( Level.FINER ) )
  648.         {
  649.             context.log( Level.FINER, getMessage( "disabled", this.getClass().getSimpleName(),
  650.                                                   model.getIdentifier() ), null );

  651.         }

  652.         return provided;
  653.     }

  654.     /**
  655.      * Gets the default source code file location for a given specification.
  656.      * <p>
  657.      * If the specification provides a Java type name, this method returns a Java source code file location based on
  658.      * that Java type name.
  659.      * </p>
  660.      *
  661.      * @param context The context to get the default location with.
  662.      * @param modules The model to get the default location with.
  663.      * @param specification The specification to get the default location for.
  664.      *
  665.      * @return The default location for {@code specification} or {@code null}.
  666.      *
  667.      * @throws NullPointerException if {@code context}, {@code modules} or {@code specification} is {@code null}.
  668.      *
  669.      * @see #getDefaultSourceFilesType(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Specification)
  670.      * @see SourceFileType#getLocation()
  671.      * @see Specification#getJavaTypeName()
  672.      * @since 1.6
  673.      */
  674.     protected String getDefaultSourceFileLocation( final ModelContext context, final Modules modules,
  675.                                                    final Specification specification )
  676.     {
  677.         if ( context == null )
  678.         {
  679.             throw new NullPointerException( "context" );
  680.         }
  681.         if ( modules == null )
  682.         {
  683.             throw new NullPointerException( "modules" );
  684.         }
  685.         if ( specification == null )
  686.         {
  687.             throw new NullPointerException( "specification" );
  688.         }

  689.         String location = null;

  690.         try
  691.         {
  692.             if ( specification.getJavaTypeName() != null )
  693.             {
  694.                 location = specification.getJavaTypeName().getQualifiedName().replace( '.', '/' ) + ".java";
  695.             }
  696.         }
  697.         catch ( final ModelObjectException e )
  698.         {
  699.             context.log( Level.WARNING, getMessage( e ), null );
  700.         }

  701.         return location;
  702.     }

  703.     /**
  704.      * Gets the default source code file location for a given implementation.
  705.      * <p>
  706.      * If the implementation provides a Java type name, this method returns a Java source code file location based on
  707.      * that Java type name.
  708.      * </p>
  709.      *
  710.      * @param context The context to get the default location with.
  711.      * @param modules The model to get the default location with.
  712.      * @param implementation The implementation to get the default location for.
  713.      *
  714.      * @return The default location for {@code implementation} or {@code null}.
  715.      *
  716.      * @throws NullPointerException if {@code context}, {@code modules} or {@code implementation} is {@code null}.
  717.      *
  718.      * @see #getDefaultSourceFilesType(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Implementation)
  719.      * @see SourceFileType#getLocation()
  720.      * @see Implementation#getJavaTypeName()
  721.      * @since 1.6
  722.      */
  723.     protected String getDefaultSourceFileLocation( final ModelContext context, final Modules modules,
  724.                                                    final Implementation implementation )
  725.     {
  726.         if ( context == null )
  727.         {
  728.             throw new NullPointerException( "context" );
  729.         }
  730.         if ( modules == null )
  731.         {
  732.             throw new NullPointerException( "modules" );
  733.         }
  734.         if ( implementation == null )
  735.         {
  736.             throw new NullPointerException( "implementation" );
  737.         }

  738.         String location = null;

  739.         try
  740.         {
  741.             if ( implementation.getJavaTypeName() != null )
  742.             {
  743.                 location = implementation.getJavaTypeName().getQualifiedName().replace( '.', '/' ) + ".java";
  744.             }
  745.         }
  746.         catch ( final ModelObjectException e )
  747.         {
  748.             context.log( Level.WARNING, getMessage( e ), null );
  749.         }

  750.         return location;
  751.     }

  752.     /**
  753.      * Gets the default source section name for a given specification.
  754.      * <p>
  755.      * If the specification provides a Java type name, this method returns a section name based on that Java type
  756.      * name.
  757.      * </p>
  758.      *
  759.      * @param context The context to get the default section name with.
  760.      * @param modules The model to get the default section name with.
  761.      * @param specification The specification to get the default section name for.
  762.      *
  763.      * @return The default source section name for {@code specification} or {@code null}.
  764.      *
  765.      * @throws NullPointerException if {@code context}, {@code modules} or {@code specification} is {@code null}.
  766.      *
  767.      * @see #getDefaultSourceFilesType(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Specification)
  768.      * @see SourceSectionType#getName()
  769.      * @see Specification#getJavaTypeName()
  770.      * @since 1.6
  771.      */
  772.     protected String getDefaultSourceSectionName( final ModelContext context, final Modules modules,
  773.                                                   final Specification specification )
  774.     {
  775.         if ( context == null )
  776.         {
  777.             throw new NullPointerException( "context" );
  778.         }
  779.         if ( modules == null )
  780.         {
  781.             throw new NullPointerException( "modules" );
  782.         }
  783.         if ( specification == null )
  784.         {
  785.             throw new NullPointerException( "specification" );
  786.         }

  787.         String sectionName = null;

  788.         try
  789.         {
  790.             final JavaTypeName javaTypeName = specification.getJavaTypeName();

  791.             if ( javaTypeName != null )
  792.             {
  793.                 sectionName = javaTypeName.getName( false );
  794.             }
  795.         }
  796.         catch ( final ModelObjectException e )
  797.         {
  798.             context.log( Level.WARNING, getMessage( e ), null );
  799.         }

  800.         return sectionName;
  801.     }

  802.     /**
  803.      * Gets the default source section name for a given implementation.
  804.      * <p>
  805.      * If the implementation provides a Java type name, this method returns a section name based that Java type
  806.      * name.
  807.      * </p>
  808.      *
  809.      * @param context The context to get the default section name with.
  810.      * @param modules The model to get the default section name with.
  811.      * @param implementation The implementation to get the default section name for.
  812.      *
  813.      * @return The default source section name for {@code implementation} or {@code null}.
  814.      *
  815.      * @throws NullPointerException if {@code context}, {@code modules} or {@code implementation} is {@code null}.
  816.      *
  817.      * @see #getDefaultSourceFilesType(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Implementation)
  818.      * @see SourceSectionType#getName()
  819.      * @see Implementation#getJavaTypeName()
  820.      * @since 1.6
  821.      */
  822.     protected String getDefaultSourceSectionName( final ModelContext context, final Modules modules,
  823.                                                   final Implementation implementation )
  824.     {
  825.         if ( context == null )
  826.         {
  827.             throw new NullPointerException( "context" );
  828.         }
  829.         if ( modules == null )
  830.         {
  831.             throw new NullPointerException( "modules" );
  832.         }
  833.         if ( implementation == null )
  834.         {
  835.             throw new NullPointerException( "implementation" );
  836.         }

  837.         String sectionName = null;

  838.         try
  839.         {
  840.             final JavaTypeName javaTypeName = implementation.getJavaTypeName();

  841.             if ( javaTypeName != null )
  842.             {
  843.                 sectionName = javaTypeName.getName( false );
  844.             }
  845.         }
  846.         catch ( final ModelObjectException e )
  847.         {
  848.             context.log( Level.WARNING, getMessage( e ), null );
  849.         }

  850.         return sectionName;
  851.     }

  852.     /**
  853.      * Creates a new default source files model for a given specification.
  854.      *
  855.      * @param context The context to create a new default source files model with.
  856.      * @param modules The model to create a new default source files model with.
  857.      * @param specification The specification to create a new default source files model for.
  858.      *
  859.      * @return A new default source files model for {@code specification}.
  860.      *
  861.      * @throws NullPointerException if {@code context}, {@code modules} or {@code specification} is {@code null}.
  862.      *
  863.      * @see #getDefaultSourceFileLocation(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Specification)
  864.      * @see #getDefaultSourceSectionName(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Specification)
  865.      * @since 1.6
  866.      */
  867.     protected SourceFilesType getDefaultSourceFilesType( final ModelContext context, final Modules modules,
  868.                                                          final Specification specification )
  869.     {
  870.         if ( context == null )
  871.         {
  872.             throw new NullPointerException( "context" );
  873.         }
  874.         if ( modules == null )
  875.         {
  876.             throw new NullPointerException( "modules" );
  877.         }
  878.         if ( specification == null )
  879.         {
  880.             throw new NullPointerException( "specification" );
  881.         }

  882.         String contextHeadComment = this.getHeadComment();
  883.         if ( ( DEFAULT_HEAD_COMMENT != null
  884.                ? DEFAULT_HEAD_COMMENT.equals( contextHeadComment )
  885.                : contextHeadComment == null )
  886.                  && context.getAttribute( HEAD_COMMENT_ATTRIBUTE_NAME ) instanceof String )
  887.         {
  888.             contextHeadComment = (String) context.getAttribute( HEAD_COMMENT_ATTRIBUTE_NAME );
  889.         }

  890.         if ( contextHeadComment != null && contextHeadComment.length() == 0 )
  891.         {
  892.             contextHeadComment = null;
  893.         }

  894.         String contextTailComment = this.getTailComment();
  895.         if ( ( DEFAULT_TAIL_COMMENT != null
  896.                ? DEFAULT_TAIL_COMMENT.equals( contextTailComment )
  897.                : contextTailComment == null )
  898.                  && context.getAttribute( TAIL_COMMENT_ATTRIBUTE_NAME ) instanceof String )
  899.         {
  900.             contextTailComment = (String) context.getAttribute( TAIL_COMMENT_ATTRIBUTE_NAME );
  901.         }

  902.         if ( contextTailComment != null && contextTailComment.length() == 0 )
  903.         {
  904.             contextTailComment = null;
  905.         }

  906.         final Set<String> uniqueSectionNames = new HashSet<String>( 16 );
  907.         final Set<String> sectionNames = new HashSet<String>( 16 );
  908.         sectionNames.add( LICENSE_SECTION_NAME );
  909.         sectionNames.add( ANNOTATIONS_SECTION_NAME );
  910.         sectionNames.add( DOCUMENTATION_SECTION_NAME );

  911.         final SourceFilesType sourceFilesType = new SourceFilesType();
  912.         final SourceFileType sourceFileType = new SourceFileType();
  913.         sourceFilesType.getSourceFile().add( sourceFileType );

  914.         sourceFileType.setIdentifier( "Default" );
  915.         sourceFileType.setLocation( this.getDefaultSourceFileLocation( context, modules, specification ) );

  916.         sourceFileType.setTemplate( SPECIFICATION_TEMPLATE );
  917.         sourceFileType.setHeadComment( contextHeadComment );
  918.         sourceFileType.setTailComment( contextTailComment );
  919.         sourceFileType.setSourceSections( new SourceSectionsType() );

  920.         SourceSectionType s = new SourceSectionType();
  921.         s.setName( LICENSE_SECTION_NAME );
  922.         s.setHeadTemplate( SPECIFICATION_LICENSE_TEMPLATE );
  923.         s.setOptional( true );
  924.         sourceFileType.getSourceSections().getSourceSection().add( s );

  925.         s = new SourceSectionType();
  926.         s.setName( ANNOTATIONS_SECTION_NAME );
  927.         s.setHeadTemplate( SPECIFICATION_ANNOTATIONS_TEMPLATE );
  928.         sourceFileType.getSourceSections().getSourceSection().add( s );

  929.         s = new SourceSectionType();
  930.         s.setName( DOCUMENTATION_SECTION_NAME );
  931.         s.setHeadTemplate( SPECIFICATION_DOCUMENTATION_TEMPLATE );
  932.         s.setOptional( true );
  933.         sourceFileType.getSourceSections().getSourceSection().add( s );

  934.         final String sectionName = this.getDefaultSourceSectionName( context, modules, specification );

  935.         if ( sectionName != null )
  936.         {
  937.             if ( sectionNames.add( sectionName ) )
  938.             {
  939.                 s = new SourceSectionType();
  940.                 s.setName( sectionName );
  941.                 s.setIndentationLevel( 1 );
  942.                 s.setEditable( true );
  943.                 sourceFileType.getSourceSections().getSourceSection().add( s );
  944.             }
  945.             else if ( uniqueSectionNames.add( sectionName ) )
  946.             {
  947.                 final Module module = modules.getModuleOfSpecification( specification.getIdentifier() );
  948.                 context.log( Level.WARNING, getMessage( "specificationSectionNameUniqueness",
  949.                                                         specification.getIdentifier(),
  950.                                                         module.getName(),
  951.                                                         sourceFileType.getIdentifier(),
  952.                                                         sectionName ),
  953.                              null );

  954.             }
  955.         }

  956.         return sourceFilesType;
  957.     }

  958.     /**
  959.      * Creates a new default source files model for a given implementation.
  960.      *
  961.      * @param context The context to create a new default source files model with.
  962.      * @param modules The model to create a new default source files model with.
  963.      * @param implementation The implementation to create a new default source files model for.
  964.      *
  965.      * @return A new default source files model for {@code implementation}.
  966.      *
  967.      * @throws NullPointerException if {@code context}, {@code modules} or {@code implementation} is {@code null}.
  968.      *
  969.      * @see #getDefaultSourceFileLocation(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Implementation)
  970.      * @see #getDefaultSourceSectionName(org.jomc.modlet.ModelContext, org.jomc.model.Modules, org.jomc.model.Implementation)
  971.      * @since 1.6
  972.      */
  973.     protected SourceFilesType getDefaultSourceFilesType( final ModelContext context, final Modules modules,
  974.                                                          final Implementation implementation )
  975.     {
  976.         if ( context == null )
  977.         {
  978.             throw new NullPointerException( "context" );
  979.         }
  980.         if ( modules == null )
  981.         {
  982.             throw new NullPointerException( "modules" );
  983.         }
  984.         if ( implementation == null )
  985.         {
  986.             throw new NullPointerException( "implementation" );
  987.         }

  988.         String contextHeadComment = this.getHeadComment();
  989.         if ( ( DEFAULT_HEAD_COMMENT != null
  990.                ? DEFAULT_HEAD_COMMENT.equals( contextHeadComment )
  991.                : contextHeadComment == null )
  992.                  && context.getAttribute( HEAD_COMMENT_ATTRIBUTE_NAME ) instanceof String )
  993.         {
  994.             contextHeadComment = (String) context.getAttribute( HEAD_COMMENT_ATTRIBUTE_NAME );
  995.         }

  996.         if ( contextHeadComment != null && contextHeadComment.length() == 0 )
  997.         {
  998.             contextHeadComment = null;
  999.         }

  1000.         String contextTailComment = this.getTailComment();
  1001.         if ( ( DEFAULT_TAIL_COMMENT != null
  1002.                ? DEFAULT_TAIL_COMMENT.equals( contextTailComment )
  1003.                : contextTailComment == null )
  1004.                  && context.getAttribute( TAIL_COMMENT_ATTRIBUTE_NAME ) instanceof String )
  1005.         {
  1006.             contextTailComment = (String) context.getAttribute( TAIL_COMMENT_ATTRIBUTE_NAME );
  1007.         }

  1008.         if ( contextTailComment != null && contextTailComment.length() == 0 )
  1009.         {
  1010.             contextTailComment = null;
  1011.         }

  1012.         final Set<String> uniqueSectionNames = new HashSet<String>( 16 );
  1013.         final ArrayList<String> sectionNames = new ArrayList<String>( 16 );
  1014.         sectionNames.add( LICENSE_SECTION_NAME );
  1015.         sectionNames.add( ANNOTATIONS_SECTION_NAME );
  1016.         sectionNames.add( DOCUMENTATION_SECTION_NAME );
  1017.         sectionNames.add( CONSTRUCTORS_SECTION_NAME );
  1018.         sectionNames.add( DEFAULT_CONSTRUCTOR_SECTION_NAME );
  1019.         sectionNames.add( DEPENDENCIES_SECTION_NAME );
  1020.         sectionNames.add( PROPERTIES_SECTION_NAME );
  1021.         sectionNames.add( MESSAGES_SECTION_NAME );

  1022.         final SourceFilesType sourceFilesType = new SourceFilesType();
  1023.         final SourceFileType sourceFileType = new SourceFileType();
  1024.         sourceFilesType.getSourceFile().add( sourceFileType );

  1025.         final Specifications specifications = modules.getSpecifications( implementation.getIdentifier() );
  1026.         final Dependencies dependencies = modules.getDependencies( implementation.getIdentifier() );
  1027.         final Messages messages = modules.getMessages( implementation.getIdentifier() );
  1028.         final Properties properties = modules.getProperties( implementation.getIdentifier() );

  1029.         sourceFileType.setIdentifier( "Default" );
  1030.         sourceFileType.setLocation( this.getDefaultSourceFileLocation( context, modules, implementation ) );

  1031.         sourceFileType.setTemplate( IMPLEMENTATION_TEMPLATE );
  1032.         sourceFileType.setHeadComment( contextHeadComment );
  1033.         sourceFileType.setTailComment( contextTailComment );
  1034.         sourceFileType.setSourceSections( new SourceSectionsType() );

  1035.         SourceSectionType s = new SourceSectionType();
  1036.         s.setName( LICENSE_SECTION_NAME );
  1037.         s.setHeadTemplate( IMPLEMENTATION_LICENSE_TEMPLATE );
  1038.         s.setOptional( true );
  1039.         sourceFileType.getSourceSections().getSourceSection().add( s );

  1040.         s = new SourceSectionType();
  1041.         s.setName( ANNOTATIONS_SECTION_NAME );
  1042.         s.setHeadTemplate( IMPLEMENTATION_ANNOTATIONS_TEMPLATE );
  1043.         sourceFileType.getSourceSections().getSourceSection().add( s );

  1044.         s = new SourceSectionType();
  1045.         s.setName( DOCUMENTATION_SECTION_NAME );
  1046.         s.setHeadTemplate( IMPLEMENTATION_DOCUMENTATION_TEMPLATE );
  1047.         s.setOptional( true );
  1048.         sourceFileType.getSourceSections().getSourceSection().add( s );

  1049.         if ( specifications != null )
  1050.         {
  1051.             sectionNames.ensureCapacity( sectionNames.size() + specifications.getSpecification().size() );

  1052.             for ( final Specification specification : specifications.getSpecification() )
  1053.             {
  1054.                 final String sectionName = this.getDefaultSourceSectionName( context, modules, specification );

  1055.                 if ( sectionName != null )
  1056.                 {
  1057.                     if ( !sectionNames.contains( sectionName ) )
  1058.                     {
  1059.                         sectionNames.add( sectionName );

  1060.                         s = new SourceSectionType();
  1061.                         s.setName( sectionName );
  1062.                         s.setIndentationLevel( 1 );
  1063.                         s.setEditable( true );
  1064.                         sourceFileType.getSourceSections().getSourceSection().add( s );
  1065.                     }
  1066.                     else if ( uniqueSectionNames.add( sectionName ) )
  1067.                     {
  1068.                         final Module module = modules.getModuleOfImplementation( implementation.getIdentifier() );
  1069.                         context.log( Level.WARNING, getMessage( "implementationSectionNameUniqueness",
  1070.                                                                 implementation.getIdentifier(),
  1071.                                                                 module.getName(),
  1072.                                                                 sourceFileType.getIdentifier(),
  1073.                                                                 sectionName ),
  1074.                                      null );

  1075.                     }
  1076.                 }
  1077.             }
  1078.         }

  1079.         final String sectionName = this.getDefaultSourceSectionName( context, modules, implementation );

  1080.         if ( sectionName != null )
  1081.         {
  1082.             if ( !sectionNames.contains( sectionName ) )
  1083.             {
  1084.                 sectionNames.add( sectionName );

  1085.                 s = new SourceSectionType();
  1086.                 s.setName( sectionName );
  1087.                 s.setIndentationLevel( 1 );
  1088.                 s.setEditable( true );
  1089.                 sourceFileType.getSourceSections().getSourceSection().add( s );
  1090.             }
  1091.             else if ( uniqueSectionNames.add( sectionName ) )
  1092.             {
  1093.                 final Module module = modules.getModuleOfImplementation( implementation.getIdentifier() );
  1094.                 context.log( Level.WARNING, getMessage( "implementationSectionNameUniqueness",
  1095.                                                         implementation.getIdentifier(),
  1096.                                                         module.getName(),
  1097.                                                         sourceFileType.getIdentifier(),
  1098.                                                         sectionName ),
  1099.                              null );

  1100.             }
  1101.         }

  1102.         s = new SourceSectionType();
  1103.         s.setName( CONSTRUCTORS_SECTION_NAME );
  1104.         s.setIndentationLevel( 1 );
  1105.         s.setHeadTemplate( CONSTRUCTORS_HEAD_TEMPLATE );
  1106.         s.setTailTemplate( CONSTRUCTORS_TAIL_TEMPLATE );
  1107.         s.setOptional( specifications == null || ( specifications.getSpecification().isEmpty()
  1108.                                                    && specifications.getReference().isEmpty() ) );

  1109.         s.setSourceSections( new SourceSectionsType() );
  1110.         sourceFileType.getSourceSections().getSourceSection().add( s );

  1111.         final SourceSectionType defaultCtor = new SourceSectionType();
  1112.         defaultCtor.setName( DEFAULT_CONSTRUCTOR_SECTION_NAME );
  1113.         defaultCtor.setIndentationLevel( 2 );
  1114.         defaultCtor.setHeadTemplate( DEFAULT_CONSTRUCTOR_TEMPLATE );
  1115.         defaultCtor.setEditable( true );
  1116.         s.getSourceSections().getSourceSection().add( defaultCtor );

  1117.         s = new SourceSectionType();
  1118.         s.setName( DEPENDENCIES_SECTION_NAME );
  1119.         s.setIndentationLevel( 1 );
  1120.         s.setHeadTemplate( DEPENDENCIES_TEMPLATE );
  1121.         s.setOptional( dependencies == null || dependencies.getDependency().isEmpty() );
  1122.         sourceFileType.getSourceSections().getSourceSection().add( s );

  1123.         s = new SourceSectionType();
  1124.         s.setName( PROPERTIES_SECTION_NAME );
  1125.         s.setIndentationLevel( 1 );
  1126.         s.setHeadTemplate( PROPERTIES_TEMPLATE );
  1127.         s.setOptional( properties == null || properties.getProperty().isEmpty() );
  1128.         sourceFileType.getSourceSections().getSourceSection().add( s );

  1129.         s = new SourceSectionType();
  1130.         s.setName( MESSAGES_SECTION_NAME );
  1131.         s.setIndentationLevel( 1 );
  1132.         s.setHeadTemplate( MESSAGES_TEMPLATE );
  1133.         s.setOptional( messages == null || messages.getMessage().isEmpty() );
  1134.         sourceFileType.getSourceSections().getSourceSection().add( s );

  1135.         return sourceFilesType;
  1136.     }

  1137.     /**
  1138.      * Overwrites a list of source code files with another list of source code files.
  1139.      *
  1140.      * @param targetSourceFiles The list to overwrite.
  1141.      * @param sourceSourceFiles The list to overwrite with.
  1142.      * @param preserveExisting {@code true}, to preserve existing attributes of source code files and sections;
  1143.      * {@code false}, to overwrite existing attributes of source code files and sections.
  1144.      *
  1145.      * @throws NullPointerException if {@code targetSourceFiles} or {@code sourceSourceFiles} is {@code null}.
  1146.      */
  1147.     private void overwriteSourceFiles( final SourceFilesType targetSourceFiles, final SourceFilesType sourceSourceFiles,
  1148.                                        final boolean preserveExisting )
  1149.     {
  1150.         if ( targetSourceFiles == null )
  1151.         {
  1152.             throw new NullPointerException( "targetSourceFiles" );
  1153.         }
  1154.         if ( sourceSourceFiles == null )
  1155.         {
  1156.             throw new NullPointerException( "sourceSourceFiles" );
  1157.         }

  1158.         try
  1159.         {
  1160.             for ( final SourceFileType s : sourceSourceFiles.getSourceFile() )
  1161.             {
  1162.                 final SourceFileType targetSourceFile = targetSourceFiles.getSourceFile( s.getIdentifier() );

  1163.                 if ( targetSourceFile != null )
  1164.                 {
  1165.                     this.overwriteSourceFile( targetSourceFile, s, preserveExisting );
  1166.                 }
  1167.             }
  1168.         }
  1169.         catch ( final NoSuchFieldException e )
  1170.         {
  1171.             throw new AssertionError( e );
  1172.         }
  1173.     }

  1174.     /**
  1175.      * Overwrites a source code file with another source code file.
  1176.      *
  1177.      * @param targetSourceFile The source code file to overwrite.
  1178.      * @param sourceSourceFile The source code file to overwrite with.
  1179.      * @param preserveExisting {@code true}, to preserve existing attributes of the given source code file and sections;
  1180.      * {@code false}, to overwrite existing attributes of the given source code file and sections.
  1181.      *
  1182.      * @throws NullPointerException if {@code targetSourceFile} or {@code sourceSourceFile} is {@code null}.
  1183.      */
  1184.     private void overwriteSourceFile( final SourceFileType targetSourceFile, final SourceFileType sourceSourceFile,
  1185.                                       final boolean preserveExisting )
  1186.         throws NoSuchFieldException
  1187.     {
  1188.         if ( targetSourceFile == null )
  1189.         {
  1190.             throw new NullPointerException( "targetSourceFile" );
  1191.         }
  1192.         if ( sourceSourceFile == null )
  1193.         {
  1194.             throw new NullPointerException( "sourceSourceFile" );
  1195.         }

  1196.         if ( !preserveExisting )
  1197.         {
  1198.             targetSourceFile.setIdentifier( sourceSourceFile.getIdentifier() );
  1199.             targetSourceFile.setLocation( sourceSourceFile.getLocation() );
  1200.             targetSourceFile.setTemplate( sourceSourceFile.getTemplate() );
  1201.             targetSourceFile.setHeadComment( sourceSourceFile.getHeadComment() );
  1202.             targetSourceFile.setTailComment( sourceSourceFile.getTailComment() );

  1203.             if ( isFieldSet( sourceSourceFile, "_final" ) )
  1204.             {
  1205.                 targetSourceFile.setFinal( sourceSourceFile.isFinal() );
  1206.             }
  1207.             if ( isFieldSet( sourceSourceFile, "modelVersion" ) )
  1208.             {
  1209.                 targetSourceFile.setModelVersion( sourceSourceFile.getModelVersion() );
  1210.             }
  1211.             if ( isFieldSet( sourceSourceFile, "override" ) )
  1212.             {
  1213.                 targetSourceFile.setOverride( sourceSourceFile.isOverride() );
  1214.             }
  1215.         }

  1216.         if ( sourceSourceFile.getSourceSections() != null )
  1217.         {
  1218.             if ( targetSourceFile.getSourceSections() == null )
  1219.             {
  1220.                 targetSourceFile.setSourceSections( new SourceSectionsType() );
  1221.             }

  1222.             this.overwriteSourceSections( targetSourceFile.getSourceSections(), sourceSourceFile.getSourceSections(),
  1223.                                           preserveExisting );

  1224.         }
  1225.     }

  1226.     /**
  1227.      * Overwrites source code file sections with other source code file sections.
  1228.      *
  1229.      * @param targetSourceSections The source code file sections to overwrite.
  1230.      * @param sourceSourceSections The source code file sections to overwrite with.
  1231.      * @param preserveExisting {@code true}, to preserve existing attributes of the given source code file sections;
  1232.      * {@code false}, to overwrite existing attributes of the given source code file sections.
  1233.      *
  1234.      * @throws NullPointerException if {@code targetSourceSections} or {@code sourceSourceSections} is {@code null}.
  1235.      */
  1236.     private void overwriteSourceSections( final SourceSectionsType targetSourceSections,
  1237.                                           final SourceSectionsType sourceSourceSections,
  1238.                                           final boolean preserveExisting ) throws NoSuchFieldException
  1239.     {
  1240.         if ( targetSourceSections == null )
  1241.         {
  1242.             throw new NullPointerException( "targetSourceSections" );
  1243.         }
  1244.         if ( sourceSourceSections == null )
  1245.         {
  1246.             throw new NullPointerException( "sourceSourceSections" );
  1247.         }

  1248.         for ( final SourceSectionType sourceSection : sourceSourceSections.getSourceSection() )
  1249.         {
  1250.             SourceSectionType targetSection = null;

  1251.             for ( final SourceSectionType t : targetSourceSections.getSourceSection() )
  1252.             {
  1253.                 if ( sourceSection.getName().equals( t.getName() ) )
  1254.                 {
  1255.                     targetSection = t;
  1256.                     break;
  1257.                 }
  1258.             }

  1259.             if ( targetSection != null )
  1260.             {
  1261.                 if ( !preserveExisting )
  1262.                 {
  1263.                     targetSection.setName( sourceSection.getName() );
  1264.                     targetSection.setHeadTemplate( sourceSection.getHeadTemplate() );
  1265.                     targetSection.setTailTemplate( sourceSection.getTailTemplate() );

  1266.                     if ( isFieldSet( sourceSection, "editable" ) )
  1267.                     {
  1268.                         targetSection.setEditable( sourceSection.isEditable() );
  1269.                     }
  1270.                     if ( isFieldSet( sourceSection, "indentationLevel" ) )
  1271.                     {
  1272.                         targetSection.setIndentationLevel( sourceSection.getIndentationLevel() );
  1273.                     }
  1274.                     if ( isFieldSet( sourceSection, "modelVersion" ) )
  1275.                     {
  1276.                         targetSection.setModelVersion( sourceSection.getModelVersion() );
  1277.                     }
  1278.                     if ( isFieldSet( sourceSection, "optional" ) )
  1279.                     {
  1280.                         targetSection.setOptional( sourceSection.isOptional() );
  1281.                     }
  1282.                 }
  1283.             }
  1284.             else
  1285.             {
  1286.                 targetSection = sourceSection.clone();
  1287.                 targetSourceSections.getSourceSection().add( targetSection );
  1288.             }

  1289.             if ( sourceSection.getSourceSections() != null )
  1290.             {
  1291.                 if ( targetSection.getSourceSections() == null )
  1292.                 {
  1293.                     targetSection.setSourceSections( new SourceSectionsType() );
  1294.                 }

  1295.                 this.overwriteSourceSections( targetSection.getSourceSections(), sourceSection.getSourceSections(),
  1296.                                               preserveExisting );
  1297.             }
  1298.         }
  1299.     }

  1300.     private static boolean isFieldSet( final Object object, final String fieldName ) throws NoSuchFieldException
  1301.     {
  1302.         final Field field = getField( object.getClass(), fieldName );

  1303.         if ( field == null )
  1304.         {
  1305.             throw new NoSuchFieldException( fieldName );
  1306.         }

  1307.         final boolean accessible = field.isAccessible();

  1308.         try
  1309.         {
  1310.             field.setAccessible( true );
  1311.             return field.get( object ) != null;
  1312.         }
  1313.         catch ( final IllegalAccessException e )
  1314.         {
  1315.             throw new AssertionError( e );
  1316.         }
  1317.         finally
  1318.         {
  1319.             field.setAccessible( accessible );
  1320.         }
  1321.     }

  1322.     private static Field getField( final Class<?> clazz, final String name )
  1323.     {
  1324.         if ( clazz != null )
  1325.         {
  1326.             try
  1327.             {
  1328.                 return clazz.getDeclaredField( name );
  1329.             }
  1330.             catch ( final NoSuchFieldException e )
  1331.             {
  1332.                 return getField( clazz.getSuperclass(), name );
  1333.             }
  1334.         }

  1335.         return null;
  1336.     }

  1337.     private static String getMessage( final Throwable t )
  1338.     {
  1339.         return t != null
  1340.                    ? t.getMessage() != null && t.getMessage().trim().length() > 0
  1341.                          ? t.getMessage()
  1342.                          : getMessage( t.getCause() )
  1343.                    : null;

  1344.     }

  1345.     private static String getMessage( final String key, final Object... args )
  1346.     {
  1347.         return MessageFormat.format( ResourceBundle.getBundle(
  1348.             ToolsModelProvider.class.getName().replace( '.', '/' ), Locale.getDefault() ).getString( key ), args );

  1349.     }

  1350. }