JomcTool.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: JomcTool.java 5043 2015-05-27 07:03:39Z schulte $
  29.  *
  30.  */
  31. package org.jomc.tools;

  32. import java.io.BufferedReader;
  33. import java.io.ByteArrayInputStream;
  34. import java.io.ByteArrayOutputStream;
  35. import java.io.FileNotFoundException;
  36. import java.io.IOException;
  37. import java.io.InputStream;
  38. import java.io.InputStreamReader;
  39. import java.io.OutputStreamWriter;
  40. import java.io.Reader;
  41. import java.io.StringReader;
  42. import java.lang.ref.Reference;
  43. import java.lang.ref.SoftReference;
  44. import java.lang.reflect.InvocationTargetException;
  45. import java.net.URL;
  46. import java.text.DateFormat;
  47. import java.text.Format;
  48. import java.text.MessageFormat;
  49. import java.text.ParseException;
  50. import java.text.SimpleDateFormat;
  51. import java.util.ArrayList;
  52. import java.util.Calendar;
  53. import java.util.Collections;
  54. import java.util.Enumeration;
  55. import java.util.HashMap;
  56. import java.util.List;
  57. import java.util.Locale;
  58. import java.util.Map;
  59. import java.util.ResourceBundle;
  60. import java.util.Set;
  61. import java.util.concurrent.ConcurrentHashMap;
  62. import java.util.concurrent.CopyOnWriteArrayList;
  63. import java.util.concurrent.CopyOnWriteArraySet;
  64. import java.util.logging.Level;
  65. import javax.activation.MimeTypeParseException;
  66. import org.apache.commons.io.IOUtils;
  67. import org.apache.commons.lang.StringEscapeUtils;
  68. import org.apache.commons.lang.StringUtils;
  69. import org.apache.velocity.Template;
  70. import org.apache.velocity.VelocityContext;
  71. import org.apache.velocity.app.VelocityEngine;
  72. import org.apache.velocity.exception.ParseErrorException;
  73. import org.apache.velocity.exception.ResourceNotFoundException;
  74. import org.apache.velocity.exception.VelocityException;
  75. import org.apache.velocity.runtime.RuntimeConstants;
  76. import org.apache.velocity.runtime.RuntimeServices;
  77. import org.apache.velocity.runtime.log.LogChute;
  78. import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
  79. import org.apache.velocity.runtime.resource.loader.URLResourceLoader;
  80. import org.jomc.model.Argument;
  81. import org.jomc.model.Dependency;
  82. import org.jomc.model.Implementation;
  83. import org.jomc.model.InheritanceModel;
  84. import org.jomc.model.JavaIdentifier;
  85. import org.jomc.model.JavaTypeName;
  86. import org.jomc.model.Message;
  87. import org.jomc.model.ModelObject;
  88. import org.jomc.model.ModelObjectException;
  89. import org.jomc.model.Modules;
  90. import org.jomc.model.Multiplicity;
  91. import org.jomc.model.Property;
  92. import org.jomc.model.Specification;
  93. import org.jomc.model.SpecificationReference;
  94. import org.jomc.model.Text;
  95. import org.jomc.model.Texts;
  96. import org.jomc.model.modlet.ModelHelper;
  97. import org.jomc.modlet.Model;

  98. /**
  99.  * Base tool class.
  100.  *
  101.  * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
  102.  * @version $JOMC: JomcTool.java 5043 2015-05-27 07:03:39Z schulte $
  103.  */
  104. public class JomcTool
  105. {

  106.     /**
  107.      * Listener interface.
  108.      */
  109.     public abstract static class Listener
  110.     {

  111.         /**
  112.          * Creates a new {@code Listener} instance.
  113.          */
  114.         public Listener()
  115.         {
  116.             super();
  117.         }

  118.         /**
  119.          * Gets called on logging.
  120.          *
  121.          * @param level The level of the event.
  122.          * @param message The message of the event or {@code null}.
  123.          * @param throwable The throwable of the event or {@code null}.
  124.          *
  125.          * @throws NullPointerException if {@code level} is {@code null}.
  126.          */
  127.         public void onLog( final Level level, final String message, final Throwable throwable )
  128.         {
  129.             if ( level == null )
  130.             {
  131.                 throw new NullPointerException( "level" );
  132.             }
  133.         }

  134.     }

  135.     /**
  136.      * Empty byte array.
  137.      */
  138.     private static final byte[] NO_BYTES =
  139.     {
  140.     };

  141.     /**
  142.      * The prefix of the template location.
  143.      */
  144.     private static final String TEMPLATE_PREFIX =
  145.         JomcTool.class.getPackage().getName().replace( '.', '/' ) + "/templates/";

  146.     /**
  147.      * Constant for the default template profile.
  148.      */
  149.     private static final String DEFAULT_TEMPLATE_PROFILE = "jomc-java";

  150.     /**
  151.      * Constant for the name of the template profile property specifying a parent template profile name.
  152.      *
  153.      * @since 1.3
  154.      */
  155.     private static final String PARENT_TEMPLATE_PROFILE_PROPERTY_NAME = "parent-template-profile";

  156.     /**
  157.      * Constant for the name of the template profile property specifying the template encoding.
  158.      *
  159.      * @since 1.3
  160.      */
  161.     private static final String TEMPLATE_ENCODING_PROFILE_PROPERTY_NAME = "template-encoding";

  162.     /**
  163.      * The default encoding to use for reading templates.
  164.      *
  165.      * @since 1.3
  166.      */
  167.     private String defaultTemplateEncoding;

  168.     /**
  169.      * The default template profile.
  170.      */
  171.     private static volatile String defaultTemplateProfile;

  172.     /**
  173.      * The log level events are logged at by default.
  174.      *
  175.      * @see #getDefaultLogLevel()
  176.      */
  177.     private static final Level DEFAULT_LOG_LEVEL = Level.WARNING;

  178.     /**
  179.      * The default log level.
  180.      */
  181.     private static volatile Level defaultLogLevel;

  182.     /**
  183.      * The model of the instance.
  184.      */
  185.     private Model model;

  186.     /**
  187.      * The {@code VelocityEngine} of the instance.
  188.      */
  189.     private VelocityEngine velocityEngine;

  190.     /**
  191.      * Flag indicating the default {@code VelocityEngine}.
  192.      *
  193.      * @since 1.2.4
  194.      */
  195.     private boolean defaultVelocityEngine;

  196.     /**
  197.      * The location to search for templates in addition to searching the class path.
  198.      *
  199.      * @since 1.2
  200.      */
  201.     private URL templateLocation;

  202.     /**
  203.      * The encoding to use for reading files.
  204.      */
  205.     private String inputEncoding;

  206.     /**
  207.      * The encoding to use for writing files.
  208.      */
  209.     private String outputEncoding;

  210.     /**
  211.      * The template parameters.
  212.      *
  213.      * @since 1.2
  214.      */
  215.     private Map<String, Object> templateParameters;

  216.     /**
  217.      * The template profile of the instance.
  218.      */
  219.     private String templateProfile;

  220.     /**
  221.      * The indentation string of the instance.
  222.      */
  223.     private String indentation;

  224.     /**
  225.      * The line separator of the instance.
  226.      */
  227.     private String lineSeparator;

  228.     /**
  229.      * The listeners of the instance.
  230.      */
  231.     private List<Listener> listeners;

  232.     /**
  233.      * The log level of the instance.
  234.      */
  235.     private Level logLevel;

  236.     /**
  237.      * The locale of the instance.
  238.      *
  239.      * @since 1.2
  240.      */
  241.     private Locale locale;

  242.     /**
  243.      * Cached indentation strings.
  244.      */
  245.     private volatile Reference<Map<String, String>> indentationCache;

  246.     /**
  247.      * Cached templates.
  248.      *
  249.      * @since 1.3
  250.      */
  251.     private volatile Reference<Map<String, TemplateData>> templateCache;

  252.     /**
  253.      * Cached template profile context properties.
  254.      *
  255.      * @since 1.3
  256.      */
  257.     private volatile Reference<Map<String, java.util.Properties>> templateProfileContextPropertiesCache;

  258.     /**
  259.      * Cached template profile properties.
  260.      *
  261.      * @since 1.3
  262.      */
  263.     private volatile Reference<Map<String, java.util.Properties>> templateProfilePropertiesCache;

  264.     /**
  265.      * Cached Java keywords.
  266.      */
  267.     private volatile Reference<Set<String>> javaKeywordsCache;

  268.     /**
  269.      * Creates a new {@code JomcTool} instance.
  270.      */
  271.     public JomcTool()
  272.     {
  273.         super();
  274.     }

  275.     /**
  276.      * Creates a new {@code JomcTool} instance taking a {@code JomcTool} instance to initialize the new instance with.
  277.      *
  278.      * @param tool The instance to initialize the new instance with.
  279.      *
  280.      * @throws NullPointerException if {@code tool} is {@code null}.
  281.      * @throws IOException if copying {@code tool} fails.
  282.      */
  283.     public JomcTool( final JomcTool tool ) throws IOException
  284.     {
  285.         this();

  286.         if ( tool == null )
  287.         {
  288.             throw new NullPointerException( "tool" );
  289.         }

  290.         this.indentation = tool.indentation;
  291.         this.inputEncoding = tool.inputEncoding;
  292.         this.lineSeparator = tool.lineSeparator;
  293.         this.listeners = tool.listeners != null ? new CopyOnWriteArrayList<Listener>( tool.listeners ) : null;
  294.         this.logLevel = tool.logLevel;
  295.         this.model = tool.model != null ? tool.model.clone() : null;
  296.         this.outputEncoding = tool.outputEncoding;
  297.         this.defaultTemplateEncoding = tool.defaultTemplateEncoding;
  298.         this.templateProfile = tool.templateProfile;
  299.         this.velocityEngine = tool.velocityEngine;
  300.         this.defaultVelocityEngine = tool.defaultVelocityEngine;
  301.         this.locale = tool.locale;
  302.         this.templateParameters =
  303.             tool.templateParameters != null
  304.                 ? Collections.synchronizedMap( new HashMap<String, Object>( tool.templateParameters ) )
  305.                 : null;

  306.         this.templateLocation =
  307.             tool.templateLocation != null ? new URL( tool.templateLocation.toExternalForm() ) : null;

  308.     }

  309.     /**
  310.      * Gets the list of registered listeners.
  311.      * <p>
  312.      * This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
  313.      * to the returned list will be present inside the object. This is why there is no {@code set} method for the
  314.      * listeners property.
  315.      * </p>
  316.      *
  317.      * @return The list of registered listeners.
  318.      *
  319.      * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
  320.      */
  321.     public List<Listener> getListeners()
  322.     {
  323.         if ( this.listeners == null )
  324.         {
  325.             this.listeners = new CopyOnWriteArrayList<Listener>();
  326.         }

  327.         return this.listeners;
  328.     }

  329.     /**
  330.      * Gets the default log level events are logged at.
  331.      * <p>
  332.      * The default log level is controlled by system property {@code org.jomc.tools.JomcTool.defaultLogLevel} holding
  333.      * the log level to log events at by default. If that property is not set, the {@code WARNING} default is
  334.      * returned.
  335.      * </p>
  336.      *
  337.      * @return The log level events are logged at by default.
  338.      *
  339.      * @see #getLogLevel()
  340.      * @see Level#parse(java.lang.String)
  341.      */
  342.     public static Level getDefaultLogLevel()
  343.     {
  344.         if ( defaultLogLevel == null )
  345.         {
  346.             defaultLogLevel = Level.parse( System.getProperty( "org.jomc.tools.JomcTool.defaultLogLevel",
  347.                                                                DEFAULT_LOG_LEVEL.getName() ) );

  348.         }

  349.         return defaultLogLevel;
  350.     }

  351.     /**
  352.      * Sets the default log level events are logged at.
  353.      *
  354.      * @param value The new default level events are logged at or {@code null}.
  355.      *
  356.      * @see #getDefaultLogLevel()
  357.      */
  358.     public static void setDefaultLogLevel( final Level value )
  359.     {
  360.         defaultLogLevel = value;
  361.     }

  362.     /**
  363.      * Gets the log level of the instance.
  364.      *
  365.      * @return The log level of the instance.
  366.      *
  367.      * @see #getDefaultLogLevel()
  368.      * @see #setLogLevel(java.util.logging.Level)
  369.      * @see #isLoggable(java.util.logging.Level)
  370.      */
  371.     public final Level getLogLevel()
  372.     {
  373.         if ( this.logLevel == null )
  374.         {
  375.             this.logLevel = getDefaultLogLevel();

  376.             if ( this.isLoggable( Level.CONFIG ) )
  377.             {
  378.                 this.log( Level.CONFIG, getMessage( "defaultLogLevelInfo", this.logLevel.getLocalizedName() ), null );
  379.             }
  380.         }

  381.         return this.logLevel;
  382.     }

  383.     /**
  384.      * Sets the log level of the instance.
  385.      *
  386.      * @param value The new log level of the instance or {@code null}.
  387.      *
  388.      * @see #getLogLevel()
  389.      * @see #isLoggable(java.util.logging.Level)
  390.      */
  391.     public final void setLogLevel( final Level value )
  392.     {
  393.         this.logLevel = value;
  394.     }

  395.     /**
  396.      * Checks if a message at a given level is provided to the listeners of the instance.
  397.      *
  398.      * @param level The level to test.
  399.      *
  400.      * @return {@code true}, if messages at {@code level} are provided to the listeners of the instance;
  401.      * {@code false}, if messages at {@code level} are not provided to the listeners of the instance.
  402.      *
  403.      * @throws NullPointerException if {@code level} is {@code null}.
  404.      *
  405.      * @see #getLogLevel()
  406.      * @see #setLogLevel(java.util.logging.Level)
  407.      * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
  408.      */
  409.     public boolean isLoggable( final Level level )
  410.     {
  411.         if ( level == null )
  412.         {
  413.             throw new NullPointerException( "level" );
  414.         }

  415.         return level.intValue() >= this.getLogLevel().intValue();
  416.     }

  417.     /**
  418.      * Gets the Java package name of a specification.
  419.      *
  420.      * @param specification The specification to get the Java package name of.
  421.      *
  422.      * @return The Java package name of {@code specification} or {@code null}, if the specification does not reference a
  423.      * type.
  424.      *
  425.      * @throws NullPointerException if {@code specification} is {@code null}.
  426.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  427.      *
  428.      * @see Specification#getJavaTypeName()
  429.      * @see JavaTypeName#getPackageName()
  430.      *
  431.      * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
  432.      * removed in JOMC 2.0.
  433.      */
  434.     @Deprecated
  435.     public String getJavaPackageName( final Specification specification ) throws ModelObjectException
  436.     {
  437.         if ( specification == null )
  438.         {
  439.             throw new NullPointerException( "specification" );
  440.         }

  441.         final JavaTypeName javaTypeName = specification.getJavaTypeName();
  442.         return javaTypeName != null ? javaTypeName.getPackageName() : null;
  443.     }

  444.     /**
  445.      * Gets the Java type name of a specification.
  446.      *
  447.      * @param specification The specification to get the Java type name of.
  448.      * @param qualified {@code true}, to return the fully qualified type name (with package name prepended);
  449.      * {@code false}, to return the short type name (without package name prepended).
  450.      *
  451.      * @return The Java type name of the type referenced by the specification or {@code null}, if the specification does
  452.      * not reference a type.
  453.      *
  454.      * @throws NullPointerException if {@code specification} is {@code null}.
  455.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  456.      *
  457.      * @see Specification#getJavaTypeName()
  458.      * @see JavaTypeName#getName(boolean)
  459.      *
  460.      * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
  461.      * removed in JOMC 2.0.
  462.      */
  463.     @Deprecated
  464.     public String getJavaTypeName( final Specification specification, final boolean qualified )
  465.         throws ModelObjectException
  466.     {
  467.         if ( specification == null )
  468.         {
  469.             throw new NullPointerException( "specification" );
  470.         }

  471.         final JavaTypeName javaTypeName = specification.getJavaTypeName();
  472.         return javaTypeName != null ? javaTypeName.getName( qualified ) : null;
  473.     }

  474.     /**
  475.      * Gets the Java class path location of a specification.
  476.      *
  477.      * @param specification The specification to return the Java class path location of.
  478.      *
  479.      * @return The Java class path location of {@code specification} or {@code null}, if the specification does not
  480.      * reference a type.
  481.      *
  482.      * @throws NullPointerException if {@code specification} is {@code null}.
  483.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  484.      *
  485.      * @see Specification#getJavaTypeName()
  486.      * @see JavaTypeName#getQualifiedName()
  487.      *
  488.      * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
  489.      * removed in JOMC 2.0.
  490.      */
  491.     @Deprecated
  492.     public String getJavaClasspathLocation( final Specification specification ) throws ModelObjectException
  493.     {
  494.         if ( specification == null )
  495.         {
  496.             throw new NullPointerException( "specification" );
  497.         }

  498.         final JavaTypeName javaTypeName = specification.getJavaTypeName();
  499.         return javaTypeName != null ? javaTypeName.getQualifiedName().replace( '.', '/' ) : null;
  500.     }

  501.     /**
  502.      * Gets the Java package name of a specification reference.
  503.      *
  504.      * @param reference The specification reference to get the Java package name of.
  505.      *
  506.      * @return The Java package name of {@code reference} or {@code null}, if the referenced specification is not found
  507.      * or does not reference a type.
  508.      *
  509.      * @throws NullPointerException if {@code reference} is {@code null}.
  510.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  511.      *
  512.      * @see Modules#getSpecification(java.lang.String)
  513.      * @see Specification#getJavaTypeName()
  514.      * @see JavaTypeName#getPackageName()
  515.      *
  516.      * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
  517.      * removed in JOMC 2.0.
  518.      */
  519.     @Deprecated
  520.     public String getJavaPackageName( final SpecificationReference reference ) throws ModelObjectException
  521.     {
  522.         if ( reference == null )
  523.         {
  524.             throw new NullPointerException( "reference" );
  525.         }

  526.         Specification s = null;
  527.         String javaPackageName = null;

  528.         if ( this.getModules() != null
  529.                  && ( s = this.getModules().getSpecification( reference.getIdentifier() ) ) != null )
  530.         {
  531.             final JavaTypeName javaTypeName = s.getJavaTypeName();
  532.             javaPackageName = javaTypeName != null ? javaTypeName.getPackageName() : null;
  533.         }
  534.         else if ( this.isLoggable( Level.WARNING ) )
  535.         {
  536.             this.log( Level.WARNING, getMessage( "specificationNotFound", reference.getIdentifier() ), null );
  537.         }

  538.         return javaPackageName;
  539.     }

  540.     /**
  541.      * Gets the name of a Java type of a given specification reference.
  542.      *
  543.      * @param reference The specification reference to get a Java type name of.
  544.      * @param qualified {@code true}, to return the fully qualified type name (with package name prepended);
  545.      * {@code false}, to return the short type name (without package name prepended).
  546.      *
  547.      * @return The Java type name of {@code reference} or {@code null}, if the referenced specification is not found
  548.      * or does not reference a type.
  549.      *
  550.      * @throws NullPointerException if {@code reference} is {@code null}.
  551.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  552.      *
  553.      * @see Modules#getSpecification(java.lang.String)
  554.      * @see Specification#getJavaTypeName()
  555.      * @see JavaTypeName#getName(boolean)
  556.      *
  557.      * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
  558.      * removed in JOMC 2.0.
  559.      */
  560.     @Deprecated
  561.     public String getJavaTypeName( final SpecificationReference reference, final boolean qualified )
  562.         throws ModelObjectException
  563.     {
  564.         if ( reference == null )
  565.         {
  566.             throw new NullPointerException( "reference" );
  567.         }

  568.         Specification s = null;
  569.         String typeName = null;

  570.         if ( this.getModules() != null
  571.                  && ( s = this.getModules().getSpecification( reference.getIdentifier() ) ) != null )
  572.         {
  573.             final JavaTypeName javaTypeName = s.getJavaTypeName();
  574.             typeName = javaTypeName != null ? javaTypeName.getName( qualified ) : null;
  575.         }
  576.         else if ( this.isLoggable( Level.WARNING ) )
  577.         {
  578.             this.log( Level.WARNING, getMessage( "specificationNotFound", reference.getIdentifier() ), null );
  579.         }

  580.         return typeName;
  581.     }

  582.     /**
  583.      * Gets the Java package name of an implementation.
  584.      *
  585.      * @param implementation The implementation to get the Java package name of.
  586.      *
  587.      * @return The Java package name of {@code implementation} or {@code null}, if the implementation does not reference
  588.      * a type.
  589.      *
  590.      * @throws NullPointerException if {@code implementation} is {@code null}.
  591.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  592.      *
  593.      * @see Implementation#getJavaTypeName()
  594.      * @see JavaTypeName#getPackageName()
  595.      *
  596.      * @deprecated As of JOMC 1.4, please use method {@link Implementation#getJavaTypeName()}. This method will be
  597.      * removed in JOMC 2.0.
  598.      */
  599.     @Deprecated
  600.     public String getJavaPackageName( final Implementation implementation ) throws ModelObjectException
  601.     {
  602.         if ( implementation == null )
  603.         {
  604.             throw new NullPointerException( "implementation" );
  605.         }

  606.         final JavaTypeName javaTypeName = implementation.getJavaTypeName();
  607.         return javaTypeName != null ? javaTypeName.getPackageName() : null;
  608.     }

  609.     /**
  610.      * Gets the Java type name of an implementation.
  611.      *
  612.      * @param implementation The implementation to get the Java type name of.
  613.      * @param qualified {@code true}, to return the fully qualified type name (with package name prepended);
  614.      * {@code false}, to return the short type name (without package name prepended).
  615.      *
  616.      * @return The Java type name of the type referenced by the implementation or {@code null}, if the implementation
  617.      * does not reference a type.
  618.      *
  619.      * @throws NullPointerException if {@code implementation} is {@code null}.
  620.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  621.      *
  622.      * @see Implementation#getJavaTypeName()
  623.      * @see JavaTypeName#getName(boolean)
  624.      *
  625.      * @deprecated As of JOMC 1.4, please use method {@link Implementation#getJavaTypeName()}. This method will be
  626.      * removed in JOMC 2.0.
  627.      */
  628.     @Deprecated
  629.     public String getJavaTypeName( final Implementation implementation, final boolean qualified )
  630.         throws ModelObjectException
  631.     {
  632.         if ( implementation == null )
  633.         {
  634.             throw new NullPointerException( "implementation" );
  635.         }

  636.         final JavaTypeName javaTypeName = implementation.getJavaTypeName();
  637.         return javaTypeName != null ? javaTypeName.getName( qualified ) : null;
  638.     }

  639.     /**
  640.      * Gets the Java class path location of an implementation.
  641.      *
  642.      * @param implementation The implementation to return the Java class path location of.
  643.      *
  644.      * @return The Java class path location of {@code implementation} or {@code null}, if the implementation does not
  645.      * reference a type.
  646.      *
  647.      * @throws NullPointerException if {@code implementation} is {@code null}.
  648.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  649.      *
  650.      * @see Implementation#getJavaTypeName()
  651.      * @see JavaTypeName#getQualifiedName()
  652.      *
  653.      * @deprecated As of JOMC 1.4, please use method {@link Implementation#getJavaTypeName()}. This method will be
  654.      * removed in JOMC 2.0.
  655.      */
  656.     @Deprecated
  657.     public String getJavaClasspathLocation( final Implementation implementation ) throws ModelObjectException
  658.     {
  659.         if ( implementation == null )
  660.         {
  661.             throw new NullPointerException( "implementation" );
  662.         }

  663.         final JavaTypeName javaTypeName = implementation.getJavaTypeName();
  664.         return javaTypeName != null ? javaTypeName.getQualifiedName().replace( '.', '/' ) : null;
  665.     }

  666.     /**
  667.      * Gets a list of names of all Java types an implementation implements.
  668.      *
  669.      * @param implementation The implementation to get names of all implemented Java types of.
  670.      * @param qualified {@code true}, to return the fully qualified type names (with package name prepended);
  671.      * {@code false}, to return the short type names (without package name prepended).
  672.      *
  673.      * @return An unmodifiable list of names of all Java types implemented by {@code implementation}.
  674.      *
  675.      * @throws NullPointerException if {@code implementation} is {@code null}.
  676.      * @throws ModelObjectException if compiling the name of a referenced type to a {@code JavaTypeName} fails.
  677.      *
  678.      * @deprecated As of JOMC 1.2, replaced by method {@link #getImplementedJavaTypeNames(org.jomc.model.Implementation, boolean)}.
  679.      * This method will be removed in version 2.0.
  680.      */
  681.     @Deprecated
  682.     public List<String> getJavaInterfaceNames( final Implementation implementation, final boolean qualified )
  683.         throws ModelObjectException
  684.     {
  685.         if ( implementation == null )
  686.         {
  687.             throw new NullPointerException( "implementation" );
  688.         }

  689.         return this.getImplementedJavaTypeNames( implementation, qualified );
  690.     }

  691.     /**
  692.      * Gets a list of names of all Java types an implementation implements.
  693.      *
  694.      * @param implementation The implementation to get names of all implemented Java types of.
  695.      * @param qualified {@code true}, to return the fully qualified type names (with package name prepended);
  696.      * {@code false}, to return the short type names (without package name prepended).
  697.      *
  698.      * @return An unmodifiable list of names of all Java types implemented by {@code implementation}.
  699.      *
  700.      * @throws NullPointerException if {@code implementation} is {@code null}.
  701.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  702.      *
  703.      * @since 1.2
  704.      *
  705.      * @deprecated As of JOMC 1.4, please use method {@link Modules#getImplementedJavaTypeNames(java.lang.String)}.
  706.      * This method will be removed in JOMC 2.0.
  707.      */
  708.     @Deprecated
  709.     public List<String> getImplementedJavaTypeNames( final Implementation implementation, final boolean qualified )
  710.         throws ModelObjectException
  711.     {
  712.         if ( implementation == null )
  713.         {
  714.             throw new NullPointerException( "implementation" );
  715.         }

  716.         List<String> col = null;

  717.         if ( this.getModules() != null )
  718.         {
  719.             final List<JavaTypeName> javaTypeNames =
  720.                 this.getModules().getImplementedJavaTypeNames( implementation.getIdentifier() );

  721.             if ( javaTypeNames != null )
  722.             {
  723.                 col = new ArrayList<String>( javaTypeNames.size() );

  724.                 for ( int i = 0, s0 = javaTypeNames.size(); i < s0; i++ )
  725.                 {
  726.                     if ( !col.contains( javaTypeNames.get( i ).getName( qualified ) ) )
  727.                     {
  728.                         col.add( javaTypeNames.get( i ).getName( qualified ) );
  729.                     }
  730.                 }
  731.             }
  732.         }
  733.         else if ( this.isLoggable( Level.WARNING ) )
  734.         {
  735.             this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
  736.         }

  737.         return Collections.unmodifiableList( col != null ? col : Collections.<String>emptyList() );
  738.     }

  739.     /**
  740.      * Gets the Java type name of an argument.
  741.      *
  742.      * @param argument The argument to get the Java type name of.
  743.      *
  744.      * @return The Java type name of the type referenced by the argument or {@code null}, if the argument does not
  745.      * reference a type.
  746.      *
  747.      * @throws NullPointerException if {@code argument} is {@code null}.
  748.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  749.      *
  750.      * @see Argument#getJavaTypeName()
  751.      * @see JavaTypeName#getName(boolean)
  752.      *
  753.      * @deprecated As of JOMC 1.4, please use method {@link Argument#getJavaTypeName()}. This method will be removed in
  754.      * JOMC 2.0.
  755.      */
  756.     @Deprecated
  757.     public String getJavaTypeName( final Argument argument ) throws ModelObjectException
  758.     {
  759.         if ( argument == null )
  760.         {
  761.             throw new NullPointerException( "argument" );
  762.         }

  763.         final JavaTypeName javaTypeName = argument.getJavaTypeName();
  764.         return javaTypeName != null ? javaTypeName.getName( true ) : null;
  765.     }

  766.     /**
  767.      * Gets a Java method parameter name of an argument.
  768.      *
  769.      * @param argument The argument to get the Java method parameter name of.
  770.      *
  771.      * @return The Java method parameter name of {@code argument}.
  772.      *
  773.      * @throws NullPointerException if {@code argument} is {@code null}.
  774.      * @throws ModelObjectException if compiling the name of the argument to a {@code JavaIdentifier} fails.
  775.      *
  776.      * @see Argument#getJavaVariableName()
  777.      *
  778.      * @since 1.2
  779.      *
  780.      * @deprecated As of JOMC 1.4, please use method {@link Argument#getJavaVariableName()}. This method will be
  781.      * removed in JOMC 2.0.
  782.      */
  783.     @Deprecated
  784.     public String getJavaMethodParameterName( final Argument argument ) throws ModelObjectException
  785.     {
  786.         if ( argument == null )
  787.         {
  788.             throw new NullPointerException( "argument" );
  789.         }

  790.         return this.getJavaMethodParameterName( argument.getName() );
  791.     }

  792.     /**
  793.      * Gets the Java type name of a property.
  794.      *
  795.      * @param property The property to get the Java type name of.
  796.      * @param boxify {@code true}, to return the name of the Java wrapper class when the type is a Java primitive type;
  797.      * {@code false}, to return the exact binary name (unboxed name) of the Java type.
  798.      *
  799.      * @return The Java type name of the type referenced by the property or {@code null}, if the property does not
  800.      * reference a type.
  801.      *
  802.      * @throws NullPointerException if {@code property} is {@code null}.
  803.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  804.      *
  805.      * @see Property#getJavaTypeName()
  806.      * @see JavaTypeName#getBoxedName()
  807.      * @see JavaTypeName#getName(boolean)
  808.      *
  809.      * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaTypeName()}. This method will be removed in
  810.      * JOMC 2.0.
  811.      */
  812.     @Deprecated
  813.     public String getJavaTypeName( final Property property, final boolean boxify ) throws ModelObjectException
  814.     {
  815.         if ( property == null )
  816.         {
  817.             throw new NullPointerException( "property" );
  818.         }

  819.         JavaTypeName javaTypeName = property.getJavaTypeName();

  820.         if ( javaTypeName != null )
  821.         {
  822.             if ( boxify && javaTypeName.isPrimitive() )
  823.             {
  824.                 javaTypeName = javaTypeName.getBoxedName();
  825.             }

  826.             return javaTypeName.getName( true );
  827.         }

  828.         return null;
  829.     }

  830.     /**
  831.      * Gets a flag indicating the type of a given property is a Java primitive.
  832.      *
  833.      * @param property The property to query.
  834.      *
  835.      * @return {@code true}, if the Java type referenced by the property is primitive or {@code false}, if the property
  836.      * does not reference a type or if the Java type referenced by the property is not primitive.
  837.      *
  838.      * @throws NullPointerException if {@code property} is {@code null}.
  839.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  840.      *
  841.      * @see Property#getJavaTypeName()
  842.      * @see JavaTypeName#isPrimitive()
  843.      *
  844.      * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaTypeName()}. This method will be removed in
  845.      * JOMC 2.0.
  846.      */
  847.     @Deprecated
  848.     public boolean isJavaPrimitiveType( final Property property ) throws ModelObjectException
  849.     {
  850.         if ( property == null )
  851.         {
  852.             throw new NullPointerException( "property" );
  853.         }

  854.         final JavaTypeName javaTypeName = property.getJavaTypeName();
  855.         return javaTypeName != null && javaTypeName.isPrimitive();
  856.     }

  857.     /**
  858.      * Gets the name of a Java getter method of a given property.
  859.      *
  860.      * @param property The property to get a Java getter method name of.
  861.      *
  862.      * @return The Java getter method name of {@code property}.
  863.      *
  864.      * @throws NullPointerException if {@code property} is {@code null}.
  865.      * @throws ModelObjectException if compiling the name of the property to a {@code JavaIdentifier} fails.
  866.      *
  867.      * @see Property#getJavaGetterMethodName()
  868.      *
  869.      * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaGetterMethodName()}. This method will be
  870.      * removed in JOMC 2.0.
  871.      */
  872.     @Deprecated
  873.     public String getJavaGetterMethodName( final Property property ) throws ModelObjectException
  874.     {
  875.         if ( property == null )
  876.         {
  877.             throw new NullPointerException( "property" );
  878.         }

  879.         String prefix = "get";

  880.         final String javaTypeName = this.getJavaTypeName( property, true );
  881.         if ( Boolean.class.getName().equals( javaTypeName ) )
  882.         {
  883.             prefix = "is";
  884.         }

  885.         return prefix + this.getJavaIdentifier( property.getName(), true );
  886.     }

  887.     /**
  888.      * Gets the name of a Java setter method of a given property.
  889.      *
  890.      * @param property The property to get a Java setter method name of.
  891.      *
  892.      * @return The Java setter method name of {@code property}.
  893.      *
  894.      * @throws NullPointerException if {@code property} is {@code null}.
  895.      * @throws ModelObjectException if compiling the name of the property to a {@code JavaIdentifier} fails.
  896.      *
  897.      * @see Property#getJavaSetterMethodName()
  898.      *
  899.      * @since 1.2
  900.      *
  901.      * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaSetterMethodName()}. This method will be
  902.      * removed in JOMC 2.0.
  903.      */
  904.     @Deprecated
  905.     public String getJavaSetterMethodName( final Property property ) throws ModelObjectException
  906.     {
  907.         if ( property == null )
  908.         {
  909.             throw new NullPointerException( "property" );
  910.         }

  911.         return "set" + this.getJavaIdentifier( property.getName(), true );
  912.     }

  913.     /**
  914.      * Gets a Java method parameter name of a property.
  915.      *
  916.      * @param property The property to get the Java method parameter name of.
  917.      *
  918.      * @return The Java method parameter name of {@code property}.
  919.      *
  920.      * @throws NullPointerException if {@code property} is {@code null}.
  921.      * @throws ModelObjectException if copmiling the name of the property to a {@code JavaIdentifier} fails.
  922.      *
  923.      * @see Property#getJavaVariableName()
  924.      *
  925.      * @since 1.2
  926.      *
  927.      * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaVariableName()}. This method will be
  928.      * removed in JOMC 2.0.
  929.      */
  930.     @Deprecated
  931.     public String getJavaMethodParameterName( final Property property ) throws ModelObjectException
  932.     {
  933.         if ( property == null )
  934.         {
  935.             throw new NullPointerException( "property" );
  936.         }

  937.         return this.getJavaMethodParameterName( property.getName() );
  938.     }

  939.     /**
  940.      * Gets a Java field name of a property.
  941.      *
  942.      * @param property The property to get the Java field name of.
  943.      *
  944.      * @return The Java field name of {@code property}.
  945.      *
  946.      * @throws NullPointerException if {@code property} is {@code null}.
  947.      * @throws ModelObjectException if compiling the name of the property to a {@code JavaIdentifier} fails.
  948.      *
  949.      * @see Property#getJavaVariableName()
  950.      *
  951.      * @since 1.3
  952.      *
  953.      * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaVariableName()}. This method will be removed
  954.      * in JOMC 2.0.
  955.      */
  956.     @Deprecated
  957.     public String getJavaFieldName( final Property property ) throws ModelObjectException
  958.     {
  959.         if ( property == null )
  960.         {
  961.             throw new NullPointerException( "property" );
  962.         }

  963.         return this.getJavaFieldName( property.getName() );
  964.     }

  965.     /**
  966.      * Gets the name of a Java type of a given dependency.
  967.      *
  968.      * @param dependency The dependency to get a dependency Java type name of.
  969.      *
  970.      * @return The Java type name of the dependency or {@code null}, if the referenced specification is not found or
  971.      * does not reference a type.
  972.      *
  973.      * @throws NullPointerException if {@code dependency} is {@code null}.
  974.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  975.      *
  976.      * @deprecated As of JOMC 1.4, please use method {@link Modules#getDependencyJavaTypeName(java.lang.String, java.lang.String)}.
  977.      * This method will be removed in JOMC 2.0.
  978.      */
  979.     @Deprecated
  980.     public String getJavaTypeName( final Dependency dependency ) throws ModelObjectException
  981.     {
  982.         if ( dependency == null )
  983.         {
  984.             throw new NullPointerException( "dependency" );
  985.         }

  986.         Specification s = null;
  987.         StringBuilder typeName = null;
  988.         String javaTypeName = null;

  989.         try
  990.         {
  991.             if ( this.getModules() != null
  992.                      && ( s = this.getModules().getSpecification( dependency.getIdentifier() ) ) != null )
  993.             {
  994.                 if ( s.getClazz() != null )
  995.                 {
  996.                     typeName = new StringBuilder( s.getClazz().length() );
  997.                     typeName.append( this.getJavaTypeName( s, true ) );

  998.                     if ( s.getMultiplicity() == Multiplicity.MANY && dependency.getImplementationName() == null )
  999.                     {
  1000.                         typeName.append( "[]" );
  1001.                     }

  1002.                     javaTypeName = JavaTypeName.parse( typeName.toString() ).getName( true );
  1003.                 }
  1004.             }
  1005.             else if ( this.isLoggable( Level.WARNING ) )
  1006.             {
  1007.                 this.log( Level.WARNING, getMessage( "specificationNotFound", dependency.getIdentifier() ), null );
  1008.             }

  1009.             return javaTypeName;
  1010.         }
  1011.         catch ( final ParseException e )
  1012.         {
  1013.             throw new ModelObjectException( getMessage( "dependencyJavaTypeNameParseException", typeName,
  1014.                                                         getMessage( e ) ), e );

  1015.         }
  1016.     }

  1017.     /**
  1018.      * Gets the name of a Java getter method of a given dependency.
  1019.      *
  1020.      * @param dependency The dependency to get a Java getter method name of.
  1021.      *
  1022.      * @return The Java getter method name of {@code dependency}.
  1023.      *
  1024.      * @throws NullPointerException if {@code dependency} is {@code null}.
  1025.      * @throws ModelObjectException if compiling the name of the dependency to a {@code JavaIdentifier} fails.
  1026.      *
  1027.      * @see Dependency#getJavaGetterMethodName()
  1028.      *
  1029.      * @deprecated As of JOMC 1.4, please use method {@link Dependency#getJavaGetterMethodName()}. This method will be
  1030.      * removed in JOMC 2.0.
  1031.      */
  1032.     @Deprecated
  1033.     public String getJavaGetterMethodName( final Dependency dependency ) throws ModelObjectException
  1034.     {
  1035.         if ( dependency == null )
  1036.         {
  1037.             throw new NullPointerException( "dependency" );
  1038.         }

  1039.         return "get" + this.getJavaIdentifier( dependency.getName(), true );
  1040.     }

  1041.     /**
  1042.      * Gets the name of a Java setter method of a given dependency.
  1043.      *
  1044.      * @param dependency The dependency to get a Java setter method name of.
  1045.      *
  1046.      * @return The Java setter method name of {@code dependency}.
  1047.      *
  1048.      * @throws NullPointerException if {@code dependency} is {@code null}.
  1049.      * @throws ModelObjectException if compiling the name of the dependency to a {@code JavaIdentifier} fails.
  1050.      *
  1051.      * @see Dependency#getJavaSetterMethodName()
  1052.      *
  1053.      * @since 1.2
  1054.      *
  1055.      * @deprecated As of JOMC 1.4, please use method {@link Dependency#getJavaSetterMethodName()}. This method will be
  1056.      * removed in JOMC 2.0.
  1057.      */
  1058.     @Deprecated
  1059.     public String getJavaSetterMethodName( final Dependency dependency ) throws ModelObjectException
  1060.     {
  1061.         if ( dependency == null )
  1062.         {
  1063.             throw new NullPointerException( "dependency" );
  1064.         }

  1065.         return "set" + this.getJavaIdentifier( dependency.getName(), true );
  1066.     }

  1067.     /**
  1068.      * Gets a Java method parameter name of a dependency.
  1069.      *
  1070.      * @param dependency The dependency to get the Java method parameter name of.
  1071.      *
  1072.      * @return The Java method parameter name of {@code dependency}.
  1073.      *
  1074.      * @throws NullPointerException if {@code dependency} is {@code null}.
  1075.      * @throws ModelObjectException if compiling the name of the dependency to a {@code JavaIdentifier} fails.
  1076.      *
  1077.      * @see Dependency#getJavaVariableName()
  1078.      *
  1079.      * @since 1.2
  1080.      *
  1081.      * @deprecated As of JOMC 1.4, please use method {@link Dependency#getJavaVariableName()}. This method will be
  1082.      * removed in JOMC 2.0.
  1083.      */
  1084.     @Deprecated
  1085.     public String getJavaMethodParameterName( final Dependency dependency ) throws ModelObjectException
  1086.     {
  1087.         if ( dependency == null )
  1088.         {
  1089.             throw new NullPointerException( "dependency" );
  1090.         }

  1091.         return this.getJavaMethodParameterName( dependency.getName() );
  1092.     }

  1093.     /**
  1094.      * Gets a Java field name of a dependency.
  1095.      *
  1096.      * @param dependency The dependency to get the Java field name of.
  1097.      *
  1098.      * @return The Java field name of {@code dependency}.
  1099.      *
  1100.      * @throws NullPointerException if {@code dependency} is {@code null}.
  1101.      * @throws ModelObjectException if compiling the name of the dependency to a {@code JavaIdentifier} fails.
  1102.      *
  1103.      * @see Dependency#getJavaVariableName()
  1104.      *
  1105.      * @since 1.3
  1106.      *
  1107.      * @deprecated As of JOMC 1.4, please use method {@link Dependency#getJavaVariableName()}. This method will be
  1108.      * removed in JOMC 2.0.
  1109.      */
  1110.     @Deprecated
  1111.     public String getJavaFieldName( final Dependency dependency ) throws ModelObjectException
  1112.     {
  1113.         if ( dependency == null )
  1114.         {
  1115.             throw new NullPointerException( "dependency" );
  1116.         }

  1117.         return this.getJavaFieldName( dependency.getName() );
  1118.     }

  1119.     /**
  1120.      * Gets the name of a Java getter method of a given message.
  1121.      *
  1122.      * @param message The message to get a Java getter method name of.
  1123.      *
  1124.      * @return The Java getter method name of {@code message}.
  1125.      *
  1126.      * @throws NullPointerException if {@code message} is {@code null}.
  1127.      * @throws ModelObjectException if compiling the name of the message to a {@code JavaIdentifier} fails.
  1128.      *
  1129.      * @see Message#getJavaGetterMethodName()
  1130.      *
  1131.      * @deprecated As of JOMC 1.4, please use method {@link Message#getJavaGetterMethodName()}. This method will be
  1132.      * removed in JOMC 2.0.
  1133.      */
  1134.     @Deprecated
  1135.     public String getJavaGetterMethodName( final Message message ) throws ModelObjectException
  1136.     {
  1137.         if ( message == null )
  1138.         {
  1139.             throw new NullPointerException( "message" );
  1140.         }

  1141.         return "get" + this.getJavaIdentifier( message.getName(), true );
  1142.     }

  1143.     /**
  1144.      * Gets the name of a Java setter method of a given message.
  1145.      *
  1146.      * @param message The message to get a Java setter method name of.
  1147.      *
  1148.      * @return The Java setter method name of {@code message}.
  1149.      *
  1150.      * @throws NullPointerException if {@code message} is {@code null}.
  1151.      * @throws ModelObjectException if compiling the name of the message to a {@code JavaIdentifier} fails.
  1152.      *
  1153.      * @see Message#getJavaSetterMethodName()
  1154.      *
  1155.      * @since 1.2
  1156.      *
  1157.      * @deprecated As of JOMC 1.4, please use method {@link Message#getJavaSetterMethodName()}. This method will be
  1158.      * removed in JOMC 2.0.
  1159.      */
  1160.     @Deprecated
  1161.     public String getJavaSetterMethodName( final Message message ) throws ModelObjectException
  1162.     {
  1163.         if ( message == null )
  1164.         {
  1165.             throw new NullPointerException( "message" );
  1166.         }

  1167.         return "set" + this.getJavaIdentifier( message.getName(), true );
  1168.     }

  1169.     /**
  1170.      * Gets a Java method parameter name of a message.
  1171.      *
  1172.      * @param message The message to get the Java method parameter name of.
  1173.      *
  1174.      * @return The Java method parameter name of {@code message}.
  1175.      *
  1176.      * @throws NullPointerException if {@code message} is {@code null}.
  1177.      * @throws ModelObjectException if compiling the name of the message to a {@code JavaIdentifier} fails.
  1178.      *
  1179.      * @see Message#getJavaVariableName()
  1180.      *
  1181.      * @since 1.2
  1182.      *
  1183.      * @deprecated As of JOMC 1.4, please use method {@link Message#getJavaVariableName()}. This method will be removed
  1184.      * in JOMC 2.0.
  1185.      */
  1186.     @Deprecated
  1187.     public String getJavaMethodParameterName( final Message message ) throws ModelObjectException
  1188.     {
  1189.         if ( message == null )
  1190.         {
  1191.             throw new NullPointerException( "message" );
  1192.         }

  1193.         return this.getJavaMethodParameterName( message.getName() );
  1194.     }

  1195.     /**
  1196.      * Gets a Java field name of a message.
  1197.      *
  1198.      * @param message The message to get the Java field name of.
  1199.      *
  1200.      * @return The Java field name of {@code message}.
  1201.      *
  1202.      * @throws NullPointerException if {@code message} is {@code null}.
  1203.      * @throws ModelObjectException if compiling the name of the message to a {@code JavaIdentifier} fails.
  1204.      *
  1205.      * @see Message#getJavaVariableName()
  1206.      *
  1207.      * @since 1.3
  1208.      *
  1209.      * @deprecated As of JOMC 1.4, please use method {@link Message#getJavaVariableName()}. This method will be removed
  1210.      * in JOMC 2.0.
  1211.      */
  1212.     @Deprecated
  1213.     public String getJavaFieldName( final Message message ) throws ModelObjectException
  1214.     {
  1215.         if ( message == null )
  1216.         {
  1217.             throw new NullPointerException( "message" );
  1218.         }

  1219.         return this.getJavaFieldName( message.getName() );
  1220.     }

  1221.     /**
  1222.      * Gets the Java modifier name of a dependency of a given implementation.
  1223.      *
  1224.      * @param implementation The implementation declaring the dependency to get a Java modifier name of.
  1225.      * @param dependency The dependency to get a Java modifier name of.
  1226.      *
  1227.      * @return The Java modifier name of {@code dependency} of {@code implementation}.
  1228.      *
  1229.      * @throws NullPointerException if {@code implementation} or {@code dependency} is {@code null}.
  1230.      *
  1231.      * @deprecated As of JOMC 1.4, please use method {@link Modules#getDependencyJavaModifierName(java.lang.String, java.lang.String)}.
  1232.      * This method will be removed in JOMC 2.0.
  1233.      */
  1234.     @Deprecated
  1235.     public String getJavaModifierName( final Implementation implementation, final Dependency dependency )
  1236.     {
  1237.         if ( implementation == null )
  1238.         {
  1239.             throw new NullPointerException( "implementation" );
  1240.         }
  1241.         if ( dependency == null )
  1242.         {
  1243.             throw new NullPointerException( "dependency" );
  1244.         }

  1245.         String modifierName = "private";

  1246.         if ( this.getModules() != null )
  1247.         {
  1248.             modifierName =
  1249.                 this.getModules().getDependencyJavaModifierName( implementation.getIdentifier(), dependency.getName() );

  1250.             if ( modifierName == null )
  1251.             {
  1252.                 modifierName = "private";
  1253.             }
  1254.         }

  1255.         return modifierName;
  1256.     }

  1257.     /**
  1258.      * Gets the Java modifier name of a message of a given implementation.
  1259.      *
  1260.      * @param implementation The implementation declaring the message to get a Java modifier name of.
  1261.      * @param message The message to get a Java modifier name of.
  1262.      *
  1263.      * @return The Java modifier name of {@code message} of {@code implementation}.
  1264.      *
  1265.      * @throws NullPointerException if {@code implementation} or {@code message} is {@code null}.
  1266.      *
  1267.      * @deprecated As of JOMC 1.4, please use method {@link Modules#getMessageJavaModifierName(java.lang.String, java.lang.String)}.
  1268.      * This method will be removed in JOMC 2.0.
  1269.      */
  1270.     @Deprecated
  1271.     public String getJavaModifierName( final Implementation implementation, final Message message )
  1272.     {
  1273.         if ( implementation == null )
  1274.         {
  1275.             throw new NullPointerException( "implementation" );
  1276.         }
  1277.         if ( message == null )
  1278.         {
  1279.             throw new NullPointerException( "message" );
  1280.         }

  1281.         String modifierName = "private";

  1282.         if ( this.getModules() != null )
  1283.         {
  1284.             modifierName =
  1285.                 this.getModules().getMessageJavaModifierName( implementation.getIdentifier(), message.getName() );

  1286.             if ( modifierName == null )
  1287.             {
  1288.                 modifierName = "private";
  1289.             }
  1290.         }

  1291.         return modifierName;
  1292.     }

  1293.     /**
  1294.      * Gets the Java modifier name of a property of a given implementation.
  1295.      *
  1296.      * @param implementation The implementation declaring the property to get a Java modifier name of.
  1297.      * @param property The property to get a Java modifier name of.
  1298.      *
  1299.      * @return The Java modifier name of {@code property} of {@code implementation}.
  1300.      *
  1301.      * @throws NullPointerException if {@code implementation} or {@code property} is {@code null}.
  1302.      *
  1303.      * @deprecated As of JOMC 1.4, please use method {@link Modules#getPropertyJavaModifierName(java.lang.String, java.lang.String)}.
  1304.      * This method will be removed in JOMC 2.0.
  1305.      */
  1306.     @Deprecated
  1307.     public String getJavaModifierName( final Implementation implementation, final Property property )
  1308.     {
  1309.         if ( implementation == null )
  1310.         {
  1311.             throw new NullPointerException( "implementation" );
  1312.         }
  1313.         if ( property == null )
  1314.         {
  1315.             throw new NullPointerException( "property" );
  1316.         }

  1317.         String modifierName = "private";

  1318.         if ( this.getModules() != null )
  1319.         {
  1320.             modifierName =
  1321.                 this.getModules().getPropertyJavaModifierName( implementation.getIdentifier(), property.getName() );

  1322.             if ( modifierName == null )
  1323.             {
  1324.                 modifierName = "private";
  1325.             }
  1326.         }

  1327.         return modifierName;
  1328.     }

  1329.     /**
  1330.      * Formats a text to a Javadoc comment.
  1331.      *
  1332.      * @param text The text to format to a Javadoc comment.
  1333.      * @param indentationLevel The indentation level of the comment.
  1334.      * @param linePrefix The text to prepend lines with.
  1335.      *
  1336.      * @return {@code text} formatted to a Javadoc comment.
  1337.      *
  1338.      * @throws NullPointerException if {@code text} or {@code linePrefix} is {@code null}.
  1339.      * @throws IllegalArgumentException if {@code indentationLevel} is negative.
  1340.      * @throws ModelObjectException if compiling the type of the text to a {@code MimeType} fails.
  1341.      *
  1342.      * @deprecated As of JOMC 1.4, please use method {@link Text#getJavadocComment(java.lang.String, java.lang.String)}.
  1343.      * This method will be removed in JOMC 2.0.
  1344.      */
  1345.     @Deprecated
  1346.     public String getJavadocComment( final Text text, final int indentationLevel, final String linePrefix )
  1347.         throws ModelObjectException
  1348.     {
  1349.         if ( text == null )
  1350.         {
  1351.             throw new NullPointerException( "text" );
  1352.         }
  1353.         if ( linePrefix == null )
  1354.         {
  1355.             throw new NullPointerException( "linePrefix" );
  1356.         }
  1357.         if ( indentationLevel < 0 )
  1358.         {
  1359.             throw new IllegalArgumentException( Integer.toString( indentationLevel ) );
  1360.         }

  1361.         BufferedReader reader = null;
  1362.         boolean suppressExceptionOnClose = true;

  1363.         try
  1364.         {
  1365.             String javadoc = "";

  1366.             if ( text.getValue() != null )
  1367.             {
  1368.                 final String indent = this.getIndentation( indentationLevel );
  1369.                 reader = new BufferedReader( new StringReader( text.getValue() ) );
  1370.                 final StringBuilder builder = new StringBuilder( text.getValue().length() );

  1371.                 String line;
  1372.                 while ( ( line = reader.readLine() ) != null )
  1373.                 {
  1374.                     builder.append( this.getLineSeparator() ).append( indent ).append( linePrefix ).
  1375.                         append( line.replaceAll( "\\/\\*\\*", "/*" ).replaceAll( "\\*/", "/" ) );

  1376.                 }

  1377.                 if ( builder.length() > 0 )
  1378.                 {
  1379.                     javadoc =
  1380.                         builder.substring( this.getLineSeparator().length() + indent.length() + linePrefix.length() );

  1381.                     if ( !text.getMimeType().match( "text/html" ) )
  1382.                     {
  1383.                         javadoc = StringEscapeUtils.escapeHtml( javadoc );
  1384.                     }
  1385.                 }
  1386.             }

  1387.             suppressExceptionOnClose = false;
  1388.             return javadoc;
  1389.         }
  1390.         catch ( final MimeTypeParseException e )
  1391.         {
  1392.             throw new AssertionError( e );
  1393.         }
  1394.         catch ( final IOException e )
  1395.         {
  1396.             throw new AssertionError( e );
  1397.         }
  1398.         finally
  1399.         {
  1400.             try
  1401.             {
  1402.                 if ( reader != null )
  1403.                 {
  1404.                     reader.close();
  1405.                 }
  1406.             }
  1407.             catch ( final IOException e )
  1408.             {
  1409.                 if ( suppressExceptionOnClose )
  1410.                 {
  1411.                     this.log( Level.SEVERE, getMessage( e ), e );
  1412.                 }
  1413.                 else
  1414.                 {
  1415.                     throw new AssertionError( e );
  1416.                 }
  1417.             }
  1418.         }
  1419.     }

  1420.     /**
  1421.      * Formats a text from a list of texts to a Javadoc comment.
  1422.      *
  1423.      * @param texts The list of texts to format to a Javadoc comment.
  1424.      * @param indentationLevel The indentation level of the comment.
  1425.      * @param linePrefix The text to prepend lines with.
  1426.      *
  1427.      * @return The text corresponding to the locale of the instance from the list of texts formatted to a Javadoc
  1428.      * comment.
  1429.      *
  1430.      * @throws NullPointerException if {@code texts} or {@code linePrefix} is {@code null}.
  1431.      * @throws IllegalArgumentException if {@code indentationLevel} is negative.
  1432.      * @throws ModelObjectException if compiling a referenced type to a {@code MimeType} fails.
  1433.      *
  1434.      * @see #getLocale()
  1435.      *
  1436.      * @since 1.2
  1437.      *
  1438.      * @deprecated As of JOMC 1.4, please use method {@link Text#getJavadocComment(java.lang.String, java.lang.String)}.
  1439.      * This method will be removed in JOMC 2.0.
  1440.      */
  1441.     @Deprecated
  1442.     public String getJavadocComment( final Texts texts, final int indentationLevel, final String linePrefix )
  1443.         throws ModelObjectException
  1444.     {
  1445.         if ( texts == null )
  1446.         {
  1447.             throw new NullPointerException( "texts" );
  1448.         }
  1449.         if ( linePrefix == null )
  1450.         {
  1451.             throw new NullPointerException( "linePrefix" );
  1452.         }
  1453.         if ( indentationLevel < 0 )
  1454.         {
  1455.             throw new IllegalArgumentException( Integer.toString( indentationLevel ) );
  1456.         }

  1457.         return this.getJavadocComment( texts.getText( this.getLocale().getLanguage() ), indentationLevel, linePrefix );
  1458.     }

  1459.     /**
  1460.      * Formats a string to a Java string with unicode escapes.
  1461.      *
  1462.      * @param str The string to format to a Java string or {@code null}.
  1463.      *
  1464.      * @return {@code str} formatted to a Java string or {@code null}.
  1465.      *
  1466.      * @see StringEscapeUtils#escapeJava(java.lang.String)
  1467.      */
  1468.     public String getJavaString( final String str )
  1469.     {
  1470.         return StringEscapeUtils.escapeJava( str );
  1471.     }

  1472.     /**
  1473.      * Formats a string to a Java class path location.
  1474.      *
  1475.      * @param str The string to format or {@code null}.
  1476.      * @param absolute {@code true} to return an absolute class path location; {@code false} to return a relative
  1477.      * class path location.
  1478.      *
  1479.      * @return {@code str} formatted to a Java class path location.
  1480.      *
  1481.      * @since 1.3
  1482.      *
  1483.      * @deprecated As of JOMC 1.4, please use {@link JavaTypeName#getQualifiedName()}. This method will be removed in
  1484.      * JOMC 2.0.
  1485.      */
  1486.     @Deprecated
  1487.     public String getJavaClasspathLocation( final String str, final boolean absolute )
  1488.     {
  1489.         String classpathLocation = null;

  1490.         if ( str != null )
  1491.         {
  1492.             classpathLocation = str.replace( '.', '/' );

  1493.             if ( absolute )
  1494.             {
  1495.                 classpathLocation = "/" + classpathLocation;
  1496.             }
  1497.         }

  1498.         return classpathLocation;
  1499.     }

  1500.     /**
  1501.      * Formats a string to a Java identifier.
  1502.      *
  1503.      * @param str The string to format or {@code null}.
  1504.      * @param capitalize {@code true}, to return an identifier with the first character upper cased; {@code false}, to
  1505.      * return an identifier with the first character lower cased.
  1506.      *
  1507.      * @return {@code str} formatted to a Java identifier or {@code null}.
  1508.      *
  1509.      * @since 1.2
  1510.      *
  1511.      * @deprecated As of JOMC 1.4, please use method {@link #toJavaVariableName(java.lang.String)}. This method will be
  1512.      * removed in JOMC 2.0.
  1513.      */
  1514.     @Deprecated
  1515.     public String getJavaIdentifier( final String str, final boolean capitalize )
  1516.     {
  1517.         String identifier = null;

  1518.         if ( str != null )
  1519.         {
  1520.             final int len = str.length();
  1521.             final StringBuilder builder = new StringBuilder( len );
  1522.             boolean uc = capitalize;

  1523.             for ( int i = 0; i < len; i++ )
  1524.             {
  1525.                 final char c = str.charAt( i );
  1526.                 final String charString = Character.toString( c );

  1527.                 if ( builder.length() > 0 )
  1528.                 {
  1529.                     if ( Character.isJavaIdentifierPart( c ) )
  1530.                     {
  1531.                         builder.append( uc ? charString.toUpperCase( this.getLocale() ) : charString );
  1532.                         uc = false;
  1533.                     }
  1534.                     else
  1535.                     {
  1536.                         uc = true;
  1537.                     }
  1538.                 }
  1539.                 else
  1540.                 {
  1541.                     if ( Character.isJavaIdentifierStart( c ) )
  1542.                     {
  1543.                         builder.append( uc ? charString.toUpperCase( this.getLocale() )
  1544.                                             : charString.toLowerCase( this.getLocale() ) );

  1545.                         uc = false;
  1546.                     }
  1547.                     else
  1548.                     {
  1549.                         uc = capitalize;
  1550.                     }
  1551.                 }
  1552.             }

  1553.             identifier = builder.toString();

  1554.             if ( identifier.length() <= 0 && this.isLoggable( Level.WARNING ) )
  1555.             {
  1556.                 this.log( Level.WARNING, getMessage( "invalidJavaIdentifier", str ), null );
  1557.             }
  1558.         }

  1559.         return identifier;
  1560.     }

  1561.     /**
  1562.      * Formats a string to a Java method parameter name.
  1563.      *
  1564.      * @param str The string to format or {@code null}.
  1565.      *
  1566.      * @return {@code str} formatted to a Java method parameter name or {@code null}.
  1567.      *
  1568.      * @since 1.3
  1569.      *
  1570.      * @deprecated As of JOMC 1.4, please use method {@link #toJavaVariableName(java.lang.String)}. This method will be
  1571.      * removed in JOMC 2.0.
  1572.      */
  1573.     @Deprecated
  1574.     public String getJavaMethodParameterName( final String str )
  1575.     {
  1576.         String methodParameterName = null;

  1577.         if ( str != null )
  1578.         {
  1579.             final int len = str.length();
  1580.             final StringBuilder builder = new StringBuilder( len );
  1581.             boolean uc = false;

  1582.             for ( int i = 0; i < len; i++ )
  1583.             {
  1584.                 final char c = str.charAt( i );
  1585.                 final String charString = Character.toString( c );

  1586.                 if ( builder.length() > 0 )
  1587.                 {
  1588.                     if ( Character.isJavaIdentifierPart( c ) )
  1589.                     {
  1590.                         builder.append( uc ? charString.toUpperCase( this.getLocale() ) : charString );
  1591.                         uc = false;
  1592.                     }
  1593.                     else
  1594.                     {
  1595.                         uc = true;
  1596.                     }
  1597.                 }
  1598.                 else if ( Character.isJavaIdentifierStart( c ) )
  1599.                 {
  1600.                     builder.append( charString.toLowerCase( this.getLocale() ) );
  1601.                 }
  1602.             }

  1603.             methodParameterName = builder.toString();

  1604.             if ( methodParameterName.length() <= 0 && this.isLoggable( Level.WARNING ) )
  1605.             {
  1606.                 this.log( Level.WARNING, getMessage( "invalidJavaMethodParameterName", str ), null );
  1607.             }

  1608.             if ( this.getJavaKeywords().contains( methodParameterName ) )
  1609.             {
  1610.                 methodParameterName = "_" + methodParameterName;
  1611.             }
  1612.         }

  1613.         return methodParameterName;
  1614.     }

  1615.     /**
  1616.      * Formats a string to a Java field name.
  1617.      *
  1618.      * @param str The string to format or {@code null}.
  1619.      *
  1620.      * @return {@code str} formatted to a Java field name or {@code null}.
  1621.      *
  1622.      * @since 1.3
  1623.      *
  1624.      * @deprecated As of JOMC 1.4, please use method {@link #toJavaVariableName(java.lang.String)}. This method will be
  1625.      * removed in JOMC 2.0.
  1626.      */
  1627.     @Deprecated
  1628.     public String getJavaFieldName( final String str )
  1629.     {
  1630.         String fieldName = null;

  1631.         if ( str != null )
  1632.         {
  1633.             final int len = str.length();
  1634.             final StringBuilder builder = new StringBuilder( len );
  1635.             boolean uc = false;

  1636.             for ( int i = 0; i < len; i++ )
  1637.             {
  1638.                 final char c = str.charAt( i );
  1639.                 final String charString = Character.toString( c );

  1640.                 if ( builder.length() > 0 )
  1641.                 {
  1642.                     if ( Character.isJavaIdentifierPart( c ) )
  1643.                     {
  1644.                         builder.append( uc ? charString.toUpperCase( this.getLocale() ) : charString );
  1645.                         uc = false;
  1646.                     }
  1647.                     else
  1648.                     {
  1649.                         uc = true;
  1650.                     }
  1651.                 }
  1652.                 else if ( Character.isJavaIdentifierStart( c ) )
  1653.                 {
  1654.                     builder.append( charString.toLowerCase( this.getLocale() ) );
  1655.                 }
  1656.             }

  1657.             fieldName = builder.toString();

  1658.             if ( fieldName.length() <= 0 && this.isLoggable( Level.WARNING ) )
  1659.             {
  1660.                 this.log( Level.WARNING, getMessage( "invalidJavaFieldName", str ), null );
  1661.             }

  1662.             if ( this.getJavaKeywords().contains( fieldName ) )
  1663.             {
  1664.                 fieldName = "_" + fieldName;
  1665.             }
  1666.         }

  1667.         return fieldName;
  1668.     }

  1669.     /**
  1670.      * Formats a string to a Java constant name.
  1671.      *
  1672.      * @param str The string to format or {@code null}.
  1673.      *
  1674.      * @return {@code str} formatted to a Java constant name or {@code null}.
  1675.      *
  1676.      * @since 1.3
  1677.      *
  1678.      * @deprecated As of JOMC 1.4, please use method {@link #toJavaConstantName(java.lang.String)}. This method will be
  1679.      * removed in JOMC 2.0.
  1680.      */
  1681.     @Deprecated
  1682.     public String getJavaConstantName( final String str )
  1683.     {
  1684.         String name = null;

  1685.         if ( str != null )
  1686.         {
  1687.             final int len = str.length();
  1688.             final StringBuilder builder = new StringBuilder( len );
  1689.             boolean separator = false;

  1690.             for ( int i = 0; i < len; i++ )
  1691.             {
  1692.                 final char c = str.charAt( i );

  1693.                 if ( builder.length() > 0 ? Character.isJavaIdentifierPart( c ) : Character.isJavaIdentifierStart( c ) )
  1694.                 {
  1695.                     if ( builder.length() > 0 )
  1696.                     {
  1697.                         if ( !separator )
  1698.                         {
  1699.                             final char previous = builder.charAt( builder.length() - 1 );
  1700.                             separator = Character.isLowerCase( previous ) && Character.isUpperCase( c );
  1701.                         }

  1702.                         if ( separator )
  1703.                         {
  1704.                             builder.append( '_' );
  1705.                         }
  1706.                     }

  1707.                     builder.append( c );
  1708.                     separator = false;
  1709.                 }
  1710.                 else
  1711.                 {
  1712.                     separator = true;
  1713.                 }
  1714.             }

  1715.             name = builder.toString().toUpperCase( this.getLocale() );

  1716.             if ( name.length() <= 0 && this.isLoggable( Level.WARNING ) )
  1717.             {
  1718.                 this.log( Level.WARNING, getMessage( "invalidJavaConstantName", str ), null );
  1719.             }
  1720.         }

  1721.         return name;
  1722.     }

  1723.     /**
  1724.      * Compiles a string to a Java constant name.
  1725.      *
  1726.      * @param str The string to compile or {@code null}.
  1727.      *
  1728.      * @return {@code str} compiled to a {@code JavaIdentifier} or {@code null}, if {@code str} is {@code null}.
  1729.      *
  1730.      * @throws ParseException if compiling {@code str} to a {@code JavaIdentifier} fails.
  1731.      *
  1732.      * @since 1.3
  1733.      *
  1734.      * @see JavaIdentifier#normalize(java.lang.String, org.jomc.model.JavaIdentifier.NormalizationMode)
  1735.      * @see org.jomc.model.JavaIdentifier.NormalizationMode#CONSTANT_NAME_CONVENTION
  1736.      */
  1737.     public JavaIdentifier toJavaConstantName( final String str ) throws ParseException
  1738.     {
  1739.         JavaIdentifier constantName = null;

  1740.         if ( str != null )
  1741.         {
  1742.             constantName = JavaIdentifier.normalize( str, JavaIdentifier.NormalizationMode.CONSTANT_NAME_CONVENTION );
  1743.         }

  1744.         return constantName;
  1745.     }

  1746.     /**
  1747.      * Compiles a string to a Java method name.
  1748.      *
  1749.      * @param str The string to compile or {@code null}.
  1750.      *
  1751.      * @return {@code str} compiled to a {@code JavaIdentifier} or {@code null}, if {@code str} is {@code null}.
  1752.      *
  1753.      * @throws ParseException if compiling {@code str} to a {@code JavaIdentifier} fails.
  1754.      *
  1755.      * @since 1.4
  1756.      *
  1757.      * @see JavaIdentifier#normalize(java.lang.String, org.jomc.model.JavaIdentifier.NormalizationMode)
  1758.      * @see org.jomc.model.JavaIdentifier.NormalizationMode#METHOD_NAME_CONVENTION
  1759.      */
  1760.     public JavaIdentifier toJavaMethodName( final String str ) throws ParseException
  1761.     {
  1762.         JavaIdentifier variableName = null;

  1763.         if ( str != null )
  1764.         {
  1765.             variableName =
  1766.                 JavaIdentifier.normalize( str, JavaIdentifier.NormalizationMode.METHOD_NAME_CONVENTION );

  1767.         }

  1768.         return variableName;
  1769.     }

  1770.     /**
  1771.      * Compiles a string to a Java variable name.
  1772.      *
  1773.      * @param str The string to compile or {@code null}.
  1774.      *
  1775.      * @return {@code str} compiled to a {@code JavaIdentifier} or {@code null}, if {@code str} is {@code null}.
  1776.      *
  1777.      * @throws ParseException if compiling {@code str} to a {@code JavaIdentifier} fails.
  1778.      *
  1779.      * @since 1.4
  1780.      *
  1781.      * @see JavaIdentifier#normalize(java.lang.String, org.jomc.model.JavaIdentifier.NormalizationMode)
  1782.      * @see org.jomc.model.JavaIdentifier.NormalizationMode#VARIABLE_NAME_CONVENTION
  1783.      */
  1784.     public JavaIdentifier toJavaVariableName( final String str ) throws ParseException
  1785.     {
  1786.         JavaIdentifier variableName = null;

  1787.         if ( str != null )
  1788.         {
  1789.             variableName =
  1790.                 JavaIdentifier.normalize( str, JavaIdentifier.NormalizationMode.VARIABLE_NAME_CONVENTION );

  1791.         }

  1792.         return variableName;
  1793.     }

  1794.     /**
  1795.      * Gets a flag indicating the type referenced by a given specification is located in an unnamed Java package.
  1796.      *
  1797.      * @param specification The specification to query.
  1798.      *
  1799.      * @return {@code true}, if the type referenced by {@code specification} is located in an unnamed Java package;
  1800.      * {@code false}, if the specification does not reference a type or if the referenced type is not located in an
  1801.      * unnamed Java package.
  1802.      *
  1803.      * @throws NullPointerException if {@code specification} is {@code null}.
  1804.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  1805.      *
  1806.      * @see Specification#getJavaTypeName()
  1807.      * @see JavaTypeName#isUnnamedPackage()
  1808.      *
  1809.      * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
  1810.      * removed in JOMC 2.0.
  1811.      */
  1812.     @Deprecated
  1813.     public boolean isJavaDefaultPackage( final Specification specification ) throws ModelObjectException
  1814.     {
  1815.         if ( specification == null )
  1816.         {
  1817.             throw new NullPointerException( "specification" );
  1818.         }

  1819.         final JavaTypeName javaTypeName = specification.getJavaTypeName();
  1820.         return javaTypeName != null && javaTypeName.isUnnamedPackage();
  1821.     }

  1822.     /**
  1823.      * Gets a flag indicating the type referenced by a given implementation is located in an unnamed Java package.
  1824.      *
  1825.      * @param implementation The implementation to query.
  1826.      *
  1827.      * @return {@code true}, if the type referenced by {@code implementation} is located in an unnamed Java package;
  1828.      * {@code false}, if the implementation does not reference a type or if the referenced type is not located in an
  1829.      * unnamed Java package.
  1830.      *
  1831.      * @throws NullPointerException if {@code implementation} is {@code null}.
  1832.      * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
  1833.      *
  1834.      * @see Implementation#getJavaTypeName()
  1835.      * @see JavaTypeName#isUnnamedPackage()
  1836.      *
  1837.      * @deprecated As of JOMC 1.4, please use method {@link Implementation#getJavaTypeName()}. This method will be
  1838.      * removed in JOMC 2.0.
  1839.      */
  1840.     @Deprecated
  1841.     public boolean isJavaDefaultPackage( final Implementation implementation ) throws ModelObjectException
  1842.     {
  1843.         if ( implementation == null )
  1844.         {
  1845.             throw new NullPointerException( "implementation" );
  1846.         }

  1847.         final JavaTypeName javaTypeName = implementation.getJavaTypeName();
  1848.         return javaTypeName != null && javaTypeName.isUnnamedPackage();
  1849.     }

  1850.     /**
  1851.      * Formats a string to a HTML string with HTML entities.
  1852.      *
  1853.      * @param str The string to format to a HTML string with HTML entities or {@code null}.
  1854.      *
  1855.      * @return {@code str} formatted to a HTML string with HTML entities or {@code null}.
  1856.      *
  1857.      * @since 1.2
  1858.      */
  1859.     public String getHtmlString( final String str )
  1860.     {
  1861.         return str != null ? str.replace( "&", "&amp;" ).replace( "<", "&lt;" ).replace( ">", "&gt;" ).
  1862.             replace( "\"", "&quot;" ).replace( "*", "&lowast;" ) : null;

  1863.     }

  1864.     /**
  1865.      * Formats a string to a XML string with XML entities.
  1866.      *
  1867.      * @param str The string to format to a XML string with XML entities or {@code null}.
  1868.      *
  1869.      * @return {@code str} formatted to a XML string with XML entities or {@code null}.
  1870.      *
  1871.      * @see StringEscapeUtils#escapeXml(java.lang.String)
  1872.      *
  1873.      * @since 1.2
  1874.      */
  1875.     public String getXmlString( final String str )
  1876.     {
  1877.         return StringEscapeUtils.escapeXml( str );
  1878.     }

  1879.     /**
  1880.      * Formats a string to a JavaScript string applying JavaScript string rules.
  1881.      *
  1882.      * @param str The string to format to a JavaScript string by applying JavaScript string rules or {@code null}.
  1883.      *
  1884.      * @return {@code str} formatted to a JavaScript string with JavaScript string rules applied or {@code null}.
  1885.      *
  1886.      * @see StringEscapeUtils#escapeJavaScript(java.lang.String)
  1887.      *
  1888.      * @since 1.2
  1889.      */
  1890.     public String getJavaScriptString( final String str )
  1891.     {
  1892.         return StringEscapeUtils.escapeJavaScript( str );
  1893.     }

  1894.     /**
  1895.      * Formats a string to a SQL string.
  1896.      *
  1897.      * @param str The string to format to a SQL string or {@code null}.
  1898.      *
  1899.      * @return {@code str} formatted to a SQL string or {@code null}.
  1900.      *
  1901.      * @see StringEscapeUtils#escapeSql(java.lang.String)
  1902.      *
  1903.      * @since 1.2
  1904.      */
  1905.     public String getSqlString( final String str )
  1906.     {
  1907.         return StringEscapeUtils.escapeSql( str );
  1908.     }

  1909.     /**
  1910.      * Formats a string to a CSV string.
  1911.      *
  1912.      * @param str The string to format to a CSV string or {@code null}.
  1913.      *
  1914.      * @return {@code str} formatted to a CSV string or {@code null}.
  1915.      *
  1916.      * @see StringEscapeUtils#escapeCsv(java.lang.String)
  1917.      *
  1918.      * @since 1.2
  1919.      */
  1920.     public String getCsvString( final String str )
  1921.     {
  1922.         return StringEscapeUtils.escapeCsv( str );
  1923.     }

  1924.     /**
  1925.      * Formats a {@code Boolean} to a string.
  1926.      *
  1927.      * @param b The {@code Boolean} to format to a string or {@code null}.
  1928.      *
  1929.      * @return {@code b} formatted to a string.
  1930.      *
  1931.      * @see #getLocale()
  1932.      *
  1933.      * @since 1.2
  1934.      */
  1935.     public String getBooleanString( final Boolean b )
  1936.     {
  1937.         final MessageFormat messageFormat = new MessageFormat( ResourceBundle.getBundle(
  1938.             JomcTool.class.getName().replace( '.', '/' ), this.getLocale() ).
  1939.             getString( b ? "booleanStringTrue" : "booleanStringFalse" ), this.getLocale() );

  1940.         return messageFormat.format( null );
  1941.     }

  1942.     /**
  1943.      * Gets the display language of a given language code.
  1944.      *
  1945.      * @param language The language code to get the display language of.
  1946.      *
  1947.      * @return The display language of {@code language}.
  1948.      *
  1949.      * @throws NullPointerException if {@code language} is {@code null}.
  1950.      */
  1951.     public String getDisplayLanguage( final String language )
  1952.     {
  1953.         if ( language == null )
  1954.         {
  1955.             throw new NullPointerException( "language" );
  1956.         }

  1957.         final Locale l = new Locale( language );
  1958.         return l.getDisplayLanguage( l );
  1959.     }

  1960.     /**
  1961.      * Formats a calendar instance to a string.
  1962.      *
  1963.      * @param calendar The calendar to format to a string.
  1964.      *
  1965.      * @return The date of {@code calendar} formatted using a short format style pattern.
  1966.      *
  1967.      * @throws NullPointerException if {@code calendar} is {@code null}.
  1968.      *
  1969.      * @see DateFormat#SHORT
  1970.      */
  1971.     public String getShortDate( final Calendar calendar )
  1972.     {
  1973.         if ( calendar == null )
  1974.         {
  1975.             throw new NullPointerException( "calendar" );
  1976.         }

  1977.         return DateFormat.getDateInstance( DateFormat.SHORT, this.getLocale() ).format( calendar.getTime() );
  1978.     }

  1979.     /**
  1980.      * Formats a calendar instance to a string.
  1981.      *
  1982.      * @param calendar The calendar to format to a string.
  1983.      *
  1984.      * @return The date of {@code calendar} formatted using a medium format style pattern.
  1985.      *
  1986.      * @throws NullPointerException if {@code calendar} is {@code null}.
  1987.      *
  1988.      * @see DateFormat#MEDIUM
  1989.      *
  1990.      * @since 1.2
  1991.      */
  1992.     public String getMediumDate( final Calendar calendar )
  1993.     {
  1994.         if ( calendar == null )
  1995.         {
  1996.             throw new NullPointerException( "calendar" );
  1997.         }

  1998.         return DateFormat.getDateInstance( DateFormat.MEDIUM, this.getLocale() ).format( calendar.getTime() );
  1999.     }

  2000.     /**
  2001.      * Formats a calendar instance to a string.
  2002.      *
  2003.      * @param calendar The calendar to format to a string.
  2004.      *
  2005.      * @return The date of {@code calendar} formatted using a long format style pattern.
  2006.      *
  2007.      * @throws NullPointerException if {@code calendar} is {@code null}.
  2008.      *
  2009.      * @see DateFormat#LONG
  2010.      */
  2011.     public String getLongDate( final Calendar calendar )
  2012.     {
  2013.         if ( calendar == null )
  2014.         {
  2015.             throw new NullPointerException( "calendar" );
  2016.         }

  2017.         return DateFormat.getDateInstance( DateFormat.LONG, this.getLocale() ).format( calendar.getTime() );
  2018.     }

  2019.     /**
  2020.      * Formats a calendar instance to a string.
  2021.      *
  2022.      * @param calendar The calendar to format to a string.
  2023.      *
  2024.      * @return The date of {@code calendar} formatted using an ISO-8601 format style.
  2025.      *
  2026.      * @throws NullPointerException if {@code calendar} is {@code null}.
  2027.      *
  2028.      * @see SimpleDateFormat yyyy-DDD
  2029.      *
  2030.      * @since 1.2
  2031.      */
  2032.     public String getIsoDate( final Calendar calendar )
  2033.     {
  2034.         if ( calendar == null )
  2035.         {
  2036.             throw new NullPointerException( "calendar" );
  2037.         }

  2038.         return new SimpleDateFormat( "yyyy-DDD", this.getLocale() ).format( calendar.getTime() );
  2039.     }

  2040.     /**
  2041.      * Formats a calendar instance to a string.
  2042.      *
  2043.      * @param calendar The calendar to format to a string.
  2044.      *
  2045.      * @return The time of {@code calendar} formatted using a short format style pattern.
  2046.      *
  2047.      * @throws NullPointerException if {@code calendar} is {@code null}.
  2048.      *
  2049.      * @see DateFormat#SHORT
  2050.      */
  2051.     public String getShortTime( final Calendar calendar )
  2052.     {
  2053.         if ( calendar == null )
  2054.         {
  2055.             throw new NullPointerException( "calendar" );
  2056.         }

  2057.         return DateFormat.getTimeInstance( DateFormat.SHORT, this.getLocale() ).format( calendar.getTime() );
  2058.     }

  2059.     /**
  2060.      * Formats a calendar instance to a string.
  2061.      *
  2062.      * @param calendar The calendar to format to a string.
  2063.      *
  2064.      * @return The time of {@code calendar} formatted using a medium format style pattern.
  2065.      *
  2066.      * @throws NullPointerException if {@code calendar} is {@code null}.
  2067.      *
  2068.      * @see DateFormat#MEDIUM
  2069.      *
  2070.      * @since 1.2
  2071.      */
  2072.     public String getMediumTime( final Calendar calendar )
  2073.     {
  2074.         if ( calendar == null )
  2075.         {
  2076.             throw new NullPointerException( "calendar" );
  2077.         }

  2078.         return DateFormat.getTimeInstance( DateFormat.MEDIUM, this.getLocale() ).format( calendar.getTime() );
  2079.     }

  2080.     /**
  2081.      * Formats a calendar instance to a string.
  2082.      *
  2083.      * @param calendar The calendar to format to a string.
  2084.      *
  2085.      * @return The time of {@code calendar} formatted using a long format style pattern.
  2086.      *
  2087.      * @throws NullPointerException if {@code calendar} is {@code null}.
  2088.      *
  2089.      * @see DateFormat#LONG
  2090.      */
  2091.     public String getLongTime( final Calendar calendar )
  2092.     {
  2093.         if ( calendar == null )
  2094.         {
  2095.             throw new NullPointerException( "calendar" );
  2096.         }

  2097.         return DateFormat.getTimeInstance( DateFormat.LONG, this.getLocale() ).format( calendar.getTime() );
  2098.     }

  2099.     /**
  2100.      * Formats a calendar instance to a string.
  2101.      *
  2102.      * @param calendar The calendar to format to a string.
  2103.      *
  2104.      * @return The time of {@code calendar} formatted using an ISO-8601 format style.
  2105.      *
  2106.      * @throws NullPointerException if {@code calendar} is {@code null}.
  2107.      *
  2108.      * @see SimpleDateFormat HH:mm
  2109.      *
  2110.      * @since 1.2
  2111.      */
  2112.     public String getIsoTime( final Calendar calendar )
  2113.     {
  2114.         if ( calendar == null )
  2115.         {
  2116.             throw new NullPointerException( "calendar" );
  2117.         }

  2118.         return new SimpleDateFormat( "HH:mm", this.getLocale() ).format( calendar.getTime() );
  2119.     }

  2120.     /**
  2121.      * Formats a calendar instance to a string.
  2122.      *
  2123.      * @param calendar The calendar to format to a string.
  2124.      *
  2125.      * @return The date and time of {@code calendar} formatted using a short format style pattern.
  2126.      *
  2127.      * @throws NullPointerException if {@code calendar} is {@code null}.
  2128.      *
  2129.      * @see DateFormat#SHORT
  2130.      */
  2131.     public String getShortDateTime( final Calendar calendar )
  2132.     {
  2133.         if ( calendar == null )
  2134.         {
  2135.             throw new NullPointerException( "calendar" );
  2136.         }

  2137.         return DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT, this.getLocale() ).
  2138.             format( calendar.getTime() );

  2139.     }

  2140.     /**
  2141.      * Formats a calendar instance to a string.
  2142.      *
  2143.      * @param calendar The calendar to format to a string.
  2144.      *
  2145.      * @return The date and time of {@code calendar} formatted using a medium format style pattern.
  2146.      *
  2147.      * @throws NullPointerException if {@code calendar} is {@code null}.
  2148.      *
  2149.      * @see DateFormat#MEDIUM
  2150.      *
  2151.      * @since 1.2
  2152.      */
  2153.     public String getMediumDateTime( final Calendar calendar )
  2154.     {
  2155.         if ( calendar == null )
  2156.         {
  2157.             throw new NullPointerException( "calendar" );
  2158.         }

  2159.         return DateFormat.getDateTimeInstance( DateFormat.MEDIUM, DateFormat.MEDIUM, this.getLocale() ).
  2160.             format( calendar.getTime() );

  2161.     }

  2162.     /**
  2163.      * Formats a calendar instance to a string.
  2164.      *
  2165.      * @param calendar The calendar to format to a string.
  2166.      *
  2167.      * @return The date and time of {@code calendar} formatted using a long format style pattern.
  2168.      *
  2169.      * @throws NullPointerException if {@code calendar} is {@code null}.
  2170.      *
  2171.      * @see DateFormat#LONG
  2172.      */
  2173.     public String getLongDateTime( final Calendar calendar )
  2174.     {
  2175.         if ( calendar == null )
  2176.         {
  2177.             throw new NullPointerException( "calendar" );
  2178.         }

  2179.         return DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG, this.getLocale() ).
  2180.             format( calendar.getTime() );

  2181.     }

  2182.     /**
  2183.      * Formats a calendar instance to a string.
  2184.      *
  2185.      * @param calendar The calendar to format to a string.
  2186.      *
  2187.      * @return The date and time of {@code calendar} formatted using a ISO-8601 format style.
  2188.      *
  2189.      * @throws NullPointerException if {@code calendar} is {@code null}.
  2190.      *
  2191.      * @see SimpleDateFormat yyyy-MM-dd'T'HH:mm:ssZ
  2192.      *
  2193.      * @since 1.2
  2194.      */
  2195.     public String getIsoDateTime( final Calendar calendar )
  2196.     {
  2197.         if ( calendar == null )
  2198.         {
  2199.             throw new NullPointerException( "calendar" );
  2200.         }

  2201.         // JDK: As of JDK 7, "yyyy-MM-dd'T'HH:mm:ssXXX".
  2202.         return new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ", this.getLocale() ).format( calendar.getTime() );
  2203.     }

  2204.     /**
  2205.      * Gets a string describing the range of years for given calendars.
  2206.      *
  2207.      * @param start The start of the range.
  2208.      * @param end The end of the range.
  2209.      *
  2210.      * @return Formatted range of the years of {@code start} and {@code end} (e.g. {@code "start - end"}).
  2211.      *
  2212.      * @throws NullPointerException if {@code start} or {@code end} is {@code null}.
  2213.      */
  2214.     public String getYears( final Calendar start, final Calendar end )
  2215.     {
  2216.         if ( start == null )
  2217.         {
  2218.             throw new NullPointerException( "start" );
  2219.         }
  2220.         if ( end == null )
  2221.         {
  2222.             throw new NullPointerException( "end" );
  2223.         }

  2224.         final Format yearFormat = new SimpleDateFormat( "yyyy", this.getLocale() );
  2225.         final int s = start.get( Calendar.YEAR );
  2226.         final int e = end.get( Calendar.YEAR );
  2227.         final StringBuilder years = new StringBuilder();

  2228.         if ( s != e )
  2229.         {
  2230.             if ( s < e )
  2231.             {
  2232.                 years.append( yearFormat.format( start.getTime() ) ).append( " - " ).
  2233.                     append( yearFormat.format( end.getTime() ) );

  2234.             }
  2235.             else
  2236.             {
  2237.                 years.append( yearFormat.format( end.getTime() ) ).append( " - " ).
  2238.                     append( yearFormat.format( start.getTime() ) );

  2239.             }
  2240.         }
  2241.         else
  2242.         {
  2243.             years.append( yearFormat.format( start.getTime() ) );
  2244.         }

  2245.         return years.toString();
  2246.     }

  2247.     /**
  2248.      * Gets the model of the instance.
  2249.      *
  2250.      * @return The model of the instance.
  2251.      *
  2252.      * @see #getModules()
  2253.      * @see #setModel(org.jomc.modlet.Model)
  2254.      */
  2255.     public final Model getModel()
  2256.     {
  2257.         if ( this.model == null )
  2258.         {
  2259.             this.model = new Model();
  2260.             this.model.setIdentifier( ModelObject.MODEL_PUBLIC_ID );
  2261.         }

  2262.         return this.model;
  2263.     }

  2264.     /**
  2265.      * Sets the model of the instance.
  2266.      *
  2267.      * @param value The new model of the instance or {@code null}.
  2268.      *
  2269.      * @see #getModel()
  2270.      */
  2271.     public final void setModel( final Model value )
  2272.     {
  2273.         this.model = value;
  2274.     }

  2275.     /**
  2276.      * Gets the modules of the model of the instance.
  2277.      *
  2278.      * @return The modules of the model of the instance or {@code null}, if no modules are found.
  2279.      *
  2280.      * @see #getModel()
  2281.      * @see #setModel(org.jomc.modlet.Model)
  2282.      */
  2283.     public final Modules getModules()
  2284.     {
  2285.         return ModelHelper.getModules( this.getModel() );
  2286.     }

  2287.     /**
  2288.      * Gets the {@code VelocityEngine} of the instance.
  2289.      *
  2290.      * @return The {@code VelocityEngine} of the instance.
  2291.      *
  2292.      * @throws IOException if initializing a new velocity engine fails.
  2293.      *
  2294.      * @see #setVelocityEngine(org.apache.velocity.app.VelocityEngine)
  2295.      */
  2296.     public final VelocityEngine getVelocityEngine() throws IOException
  2297.     {
  2298.         if ( this.velocityEngine == null )
  2299.         {
  2300.             /**
  2301.              * {@code LogChute} logging to the listeners of the tool.
  2302.              */
  2303.             class JomcLogChute implements LogChute
  2304.             {

  2305.                 JomcLogChute()
  2306.                 {
  2307.                     super();
  2308.                 }

  2309.                 public void init( final RuntimeServices runtimeServices ) throws Exception
  2310.                 {
  2311.                 }

  2312.                 public void log( final int level, final String message )
  2313.                 {
  2314.                     this.log( level, message, null );
  2315.                 }

  2316.                 public void log( final int level, final String message, final Throwable throwable )
  2317.                 {
  2318.                     JomcTool.this.log( Level.FINEST, message, throwable );
  2319.                 }

  2320.                 public boolean isLevelEnabled( final int level )
  2321.                 {
  2322.                     return isLoggable( Level.FINEST );
  2323.                 }

  2324.             }

  2325.             final VelocityEngine engine = new VelocityEngine();
  2326.             engine.setProperty( RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE.toString() );
  2327.             engine.setProperty( RuntimeConstants.VM_ARGUMENTS_STRICT, Boolean.TRUE.toString() );
  2328.             engine.setProperty( RuntimeConstants.STRICT_MATH, Boolean.TRUE.toString() );
  2329.             engine.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new JomcLogChute() );

  2330.             engine.setProperty( RuntimeConstants.RESOURCE_LOADER, "class" );
  2331.             engine.setProperty( "class.resource.loader.class", ClasspathResourceLoader.class.getName() );
  2332.             engine.setProperty( "class.resource.loader.cache", Boolean.TRUE.toString() );

  2333.             if ( this.getTemplateLocation() != null )
  2334.             {
  2335.                 engine.setProperty( RuntimeConstants.RESOURCE_LOADER, "class,url" );
  2336.                 engine.setProperty( "url.resource.loader.class", URLResourceLoader.class.getName() );
  2337.                 engine.setProperty( "url.resource.loader.cache", Boolean.TRUE.toString() );
  2338.                 engine.setProperty( "url.resource.loader.root", this.getTemplateLocation().toExternalForm() );
  2339.                 engine.setProperty( "url.resource.loader.timeout", Integer.toString( 60000 ) );
  2340.             }

  2341.             this.velocityEngine = engine;
  2342.             this.defaultVelocityEngine = true;
  2343.         }

  2344.         return this.velocityEngine;
  2345.     }

  2346.     /**
  2347.      * Sets the {@code VelocityEngine} of the instance.
  2348.      *
  2349.      * @param value The new {@code VelocityEngine} of the instance or {@code null}.
  2350.      *
  2351.      * @see #getVelocityEngine()
  2352.      */
  2353.     public final void setVelocityEngine( final VelocityEngine value )
  2354.     {
  2355.         this.velocityEngine = value;
  2356.         this.defaultVelocityEngine = false;
  2357.     }

  2358.     /**
  2359.      * Gets a new velocity context used for merging templates.
  2360.      *
  2361.      * @return A new velocity context used for merging templates.
  2362.      *
  2363.      * @throws IOException if creating a new context instance fails.
  2364.      *
  2365.      * @see #getTemplateParameters()
  2366.      */
  2367.     public VelocityContext getVelocityContext() throws IOException
  2368.     {
  2369.         final Calendar now = Calendar.getInstance();
  2370.         final VelocityContext ctx =
  2371.             new VelocityContext( new HashMap<String, Object>( this.getTemplateParameters() ) );

  2372.         this.mergeTemplateProfileContextProperties( this.getTemplateProfile(), this.getLocale().getLanguage(), ctx );
  2373.         this.mergeTemplateProfileContextProperties( this.getTemplateProfile(), null, ctx );

  2374.         final Model clonedModel = this.getModel().clone();
  2375.         final Modules clonedModules = ModelHelper.getModules( clonedModel );
  2376.         assert clonedModules != null : "Unexpected missing modules for model '" + clonedModel.getIdentifier() + "'.";

  2377.         ctx.put( "model", clonedModel );
  2378.         ctx.put( "modules", clonedModules );
  2379.         ctx.put( "imodel", new InheritanceModel( clonedModules ) );
  2380.         ctx.put( "tool", this );
  2381.         ctx.put( "toolName", this.getClass().getName() );
  2382.         ctx.put( "toolVersion", getMessage( "projectVersion" ) );
  2383.         ctx.put( "toolUrl", getMessage( "projectUrl" ) );
  2384.         ctx.put( "calendar", now.getTime() );

  2385.         // JDK: As of JDK 7, "yyyy-MM-dd'T'HH:mm:ss.SSSXXX".
  2386.         ctx.put( "now",
  2387.                  new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ", this.getLocale() ).format( now.getTime() ) );

  2388.         ctx.put( "year", new SimpleDateFormat( "yyyy", this.getLocale() ).format( now.getTime() ) );
  2389.         ctx.put( "month", new SimpleDateFormat( "MM", this.getLocale() ).format( now.getTime() ) );
  2390.         ctx.put( "day", new SimpleDateFormat( "dd", this.getLocale() ).format( now.getTime() ) );
  2391.         ctx.put( "hour", new SimpleDateFormat( "HH", this.getLocale() ).format( now.getTime() ) );
  2392.         ctx.put( "minute", new SimpleDateFormat( "mm", this.getLocale() ).format( now.getTime() ) );
  2393.         ctx.put( "second", new SimpleDateFormat( "ss", this.getLocale() ).format( now.getTime() ) );
  2394.         ctx.put( "timezone", new SimpleDateFormat( "Z", this.getLocale() ).format( now.getTime() ) );
  2395.         ctx.put( "shortDate", this.getShortDate( now ) );
  2396.         ctx.put( "mediumDate", this.getMediumDate( now ) );
  2397.         ctx.put( "longDate", this.getLongDate( now ) );
  2398.         ctx.put( "isoDate", this.getIsoDate( now ) );
  2399.         ctx.put( "shortTime", this.getShortTime( now ) );
  2400.         ctx.put( "mediumTime", this.getMediumTime( now ) );
  2401.         ctx.put( "longTime", this.getLongTime( now ) );
  2402.         ctx.put( "isoTime", this.getIsoTime( now ) );
  2403.         ctx.put( "shortDateTime", this.getShortDateTime( now ) );
  2404.         ctx.put( "mediumDateTime", this.getMediumDateTime( now ) );
  2405.         ctx.put( "longDateTime", this.getLongDateTime( now ) );
  2406.         ctx.put( "isoDateTime", this.getIsoDateTime( now ) );

  2407.         return ctx;
  2408.     }

  2409.     /**
  2410.      * Gets the template parameters of the instance.
  2411.      * <p>
  2412.      * This accessor method returns a reference to the live map, not a snapshot. Therefore any modification you make
  2413.      * to the returned map will be present inside the object. This is why there is no {@code set} method for the
  2414.      * template parameters property.
  2415.      * </p>
  2416.      *
  2417.      * @return The template parameters of the instance.
  2418.      *
  2419.      * @see #getVelocityContext()
  2420.      *
  2421.      * @since 1.2
  2422.      */
  2423.     public final Map<String, Object> getTemplateParameters()
  2424.     {
  2425.         if ( this.templateParameters == null )
  2426.         {
  2427.             this.templateParameters = Collections.synchronizedMap( new HashMap<String, Object>() );
  2428.         }

  2429.         return this.templateParameters;
  2430.     }

  2431.     /**
  2432.      * Gets the location to search for templates in addition to searching the class path.
  2433.      *
  2434.      * @return The location to search for templates in addition to searching the class path or {@code null}.
  2435.      *
  2436.      * @see #setTemplateLocation(java.net.URL)
  2437.      *
  2438.      * @since 1.2
  2439.      */
  2440.     public final URL getTemplateLocation()
  2441.     {
  2442.         return this.templateLocation;
  2443.     }

  2444.     /**
  2445.      * Sets the location to search for templates in addition to searching the class path.
  2446.      *
  2447.      * @param value The new location to search for templates in addition to searching the class path or {@code null}.
  2448.      *
  2449.      * @see #getTemplateLocation()
  2450.      *
  2451.      * @since 1.2
  2452.      */
  2453.     public final void setTemplateLocation( final URL value )
  2454.     {
  2455.         this.templateLocation = value;
  2456.         this.templateProfileContextPropertiesCache = null;
  2457.         this.templateProfilePropertiesCache = null;

  2458.         if ( this.defaultVelocityEngine )
  2459.         {
  2460.             this.setVelocityEngine( null );
  2461.         }
  2462.     }

  2463.     /**
  2464.      * Gets the encoding to use for reading templates.
  2465.      *
  2466.      * @return The encoding to use for reading templates.
  2467.      *
  2468.      * @see #setTemplateEncoding(java.lang.String)
  2469.      *
  2470.      * @deprecated As of JOMC 1.3, replaced by method {@link #getDefaultTemplateEncoding()}. This method will be removed
  2471.      * in JOMC 2.0.
  2472.      */
  2473.     @Deprecated
  2474.     public final String getTemplateEncoding()
  2475.     {
  2476.         return this.getDefaultTemplateEncoding();
  2477.     }

  2478.     /**
  2479.      * Sets the encoding to use for reading templates.
  2480.      *
  2481.      * @param value The new encoding to use for reading templates or {@code null}.
  2482.      *
  2483.      * @see #getTemplateEncoding()
  2484.      *
  2485.      * @deprecated As of JOMC 1.3, replaced by method {@link #setDefaultTemplateEncoding(java.lang.String)}. This method
  2486.      * will be removed in JOMC 2.0.
  2487.      */
  2488.     @Deprecated
  2489.     public final void setTemplateEncoding( final String value )
  2490.     {
  2491.         this.setDefaultTemplateEncoding( value );
  2492.     }

  2493.     /**
  2494.      * Gets the default encoding used for reading templates.
  2495.      *
  2496.      * @return The default encoding used for reading templates.
  2497.      *
  2498.      * @see #setDefaultTemplateEncoding(java.lang.String)
  2499.      *
  2500.      * @since 1.3
  2501.      */
  2502.     public final String getDefaultTemplateEncoding()
  2503.     {
  2504.         if ( this.defaultTemplateEncoding == null )
  2505.         {
  2506.             this.defaultTemplateEncoding = getMessage( "buildSourceEncoding" );

  2507.             if ( this.isLoggable( Level.CONFIG ) )
  2508.             {
  2509.                 this.log( Level.CONFIG, getMessage( "defaultTemplateEncoding", this.defaultTemplateEncoding ), null );
  2510.             }
  2511.         }

  2512.         return this.defaultTemplateEncoding;
  2513.     }

  2514.     /**
  2515.      * Sets the default encoding to use for reading templates.
  2516.      *
  2517.      * @param value The new default encoding to use for reading templates or {@code null}.
  2518.      *
  2519.      * @see #getDefaultTemplateEncoding()
  2520.      *
  2521.      * @since 1.3
  2522.      */
  2523.     public final void setDefaultTemplateEncoding( final String value )
  2524.     {
  2525.         this.defaultTemplateEncoding = value;
  2526.         this.templateCache = null;
  2527.     }

  2528.     /**
  2529.      * Gets the template encoding of a given template profile.
  2530.      *
  2531.      * @param tp The template profile to get the template encoding of.
  2532.      *
  2533.      * @return The template encoding of the template profile identified by {@code tp} or the default template encoding
  2534.      * if no such encoding is defined.
  2535.      *
  2536.      * @throws NullPointerException if {@code tp} is {@code null}.
  2537.      *
  2538.      * @see #getDefaultTemplateEncoding()
  2539.      *
  2540.      * @since 1.3
  2541.      */
  2542.     public final String getTemplateEncoding( final String tp )
  2543.     {
  2544.         if ( tp == null )
  2545.         {
  2546.             throw new NullPointerException( "tp" );
  2547.         }

  2548.         String te = null;

  2549.         try
  2550.         {
  2551.             te = this.getTemplateProfileProperties( tp ).getProperty( TEMPLATE_ENCODING_PROFILE_PROPERTY_NAME );
  2552.         }
  2553.         catch ( final IOException e )
  2554.         {
  2555.             if ( this.isLoggable( Level.SEVERE ) )
  2556.             {
  2557.                 this.log( Level.SEVERE, getMessage( e ), e );
  2558.             }
  2559.         }

  2560.         return te != null ? te : this.getDefaultTemplateEncoding();
  2561.     }

  2562.     /**
  2563.      * Gets the encoding to use for reading files.
  2564.      *
  2565.      * @return The encoding to use for reading files.
  2566.      *
  2567.      * @see #setInputEncoding(java.lang.String)
  2568.      */
  2569.     public final String getInputEncoding()
  2570.     {
  2571.         if ( this.inputEncoding == null )
  2572.         {
  2573.             this.inputEncoding = new InputStreamReader( new ByteArrayInputStream( NO_BYTES ) ).getEncoding();

  2574.             if ( this.isLoggable( Level.CONFIG ) )
  2575.             {
  2576.                 this.log( Level.CONFIG, getMessage( "defaultInputEncoding", this.inputEncoding ), null );
  2577.             }
  2578.         }

  2579.         return this.inputEncoding;
  2580.     }

  2581.     /**
  2582.      * Sets the encoding to use for reading files.
  2583.      *
  2584.      * @param value The new encoding to use for reading files or {@code null}.
  2585.      *
  2586.      * @see #getInputEncoding()
  2587.      */
  2588.     public final void setInputEncoding( final String value )
  2589.     {
  2590.         this.inputEncoding = value;
  2591.     }

  2592.     /**
  2593.      * Gets the encoding to use for writing files.
  2594.      *
  2595.      * @return The encoding to use for writing files.
  2596.      *
  2597.      * @see #setOutputEncoding(java.lang.String)
  2598.      */
  2599.     public final String getOutputEncoding()
  2600.     {
  2601.         if ( this.outputEncoding == null )
  2602.         {
  2603.             this.outputEncoding = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();

  2604.             if ( this.isLoggable( Level.CONFIG ) )
  2605.             {
  2606.                 this.log( Level.CONFIG, getMessage( "defaultOutputEncoding", this.outputEncoding ), null );
  2607.             }
  2608.         }

  2609.         return this.outputEncoding;
  2610.     }

  2611.     /**
  2612.      * Sets the encoding to use for writing files.
  2613.      *
  2614.      * @param value The encoding to use for writing files or {@code null}.
  2615.      *
  2616.      * @see #getOutputEncoding()
  2617.      */
  2618.     public final void setOutputEncoding( final String value )
  2619.     {
  2620.         this.outputEncoding = value;
  2621.     }

  2622.     /**
  2623.      * Gets the default template profile.
  2624.      * <p>
  2625.      * The default template profile is the implicit parent profile of any template profile not specifying a parent
  2626.      * template profile.
  2627.      * </p>
  2628.      *
  2629.      * @return The default template profile.
  2630.      *
  2631.      * @see #setDefaultTemplateProfile(java.lang.String)
  2632.      *
  2633.      * @deprecated The {@code static} modifier of this method and support to setup the default template profile using
  2634.      * a system property will be removed in version 2.0.
  2635.      */
  2636.     @Deprecated
  2637.     public static String getDefaultTemplateProfile()
  2638.     {
  2639.         if ( defaultTemplateProfile == null )
  2640.         {
  2641.             defaultTemplateProfile = System.getProperty( "org.jomc.tools.JomcTool.defaultTemplateProfile",
  2642.                                                          DEFAULT_TEMPLATE_PROFILE );

  2643.         }

  2644.         return defaultTemplateProfile;
  2645.     }

  2646.     /**
  2647.      * Sets the default template profile.
  2648.      *
  2649.      * @param value The new default template profile or {@code null}.
  2650.      *
  2651.      * @see #getDefaultTemplateProfile()
  2652.      *
  2653.      * @deprecated The {@code static} modifier of this method will be removed in version 2.0.
  2654.      */
  2655.     @Deprecated
  2656.     public static void setDefaultTemplateProfile( final String value )
  2657.     {
  2658.         defaultTemplateProfile = value;
  2659.     }

  2660.     /**
  2661.      * Gets the template profile of the instance.
  2662.      *
  2663.      * @return The template profile of the instance.
  2664.      *
  2665.      * @see #getDefaultTemplateProfile()
  2666.      * @see #setTemplateProfile(java.lang.String)
  2667.      */
  2668.     public final String getTemplateProfile()
  2669.     {
  2670.         if ( this.templateProfile == null )
  2671.         {
  2672.             this.templateProfile = getDefaultTemplateProfile();

  2673.             if ( this.isLoggable( Level.CONFIG ) )
  2674.             {
  2675.                 this.log( Level.CONFIG, getMessage( "defaultTemplateProfile", this.templateProfile ), null );
  2676.             }
  2677.         }

  2678.         return this.templateProfile;
  2679.     }

  2680.     /**
  2681.      * Sets the template profile of the instance.
  2682.      *
  2683.      * @param value The new template profile of the instance or {@code null}.
  2684.      *
  2685.      * @see #getTemplateProfile()
  2686.      */
  2687.     public final void setTemplateProfile( final String value )
  2688.     {
  2689.         this.templateProfile = value;
  2690.     }

  2691.     /**
  2692.      * Gets the parent template profile of a given template profile.
  2693.      *
  2694.      * @param tp The template profile to get the parent template profile of.
  2695.      *
  2696.      * @return The parent template profile of the template profile identified by {@code tp}; the default template
  2697.      * profile, if no such parent template profile is defined; {@code null}, if {@code tp} denotes the default template
  2698.      * profile.
  2699.      *
  2700.      * @throws NullPointerException if {@code tp} is {@code null}.
  2701.      *
  2702.      * @see #getDefaultTemplateProfile()
  2703.      *
  2704.      * @since 1.3
  2705.      */
  2706.     public final String getParentTemplateProfile( final String tp )
  2707.     {
  2708.         if ( tp == null )
  2709.         {
  2710.             throw new NullPointerException( "tp" );
  2711.         }

  2712.         String parentTemplateProfile = null;

  2713.         try
  2714.         {
  2715.             parentTemplateProfile =
  2716.                 this.getTemplateProfileProperties( tp ).getProperty( PARENT_TEMPLATE_PROFILE_PROPERTY_NAME );

  2717.         }
  2718.         catch ( final IOException e )
  2719.         {
  2720.             if ( this.isLoggable( Level.SEVERE ) )
  2721.             {
  2722.                 this.log( Level.SEVERE, getMessage( e ), e );
  2723.             }
  2724.         }

  2725.         return parentTemplateProfile != null ? parentTemplateProfile
  2726.                    : tp.equals( this.getDefaultTemplateProfile() ) ? null : this.getDefaultTemplateProfile();

  2727.     }

  2728.     /**
  2729.      * Gets the indentation string of the instance.
  2730.      *
  2731.      * @return The indentation string of the instance.
  2732.      *
  2733.      * @see #setIndentation(java.lang.String)
  2734.      */
  2735.     public final String getIndentation()
  2736.     {
  2737.         if ( this.indentation == null )
  2738.         {
  2739.             this.indentation = "    ";

  2740.             if ( this.isLoggable( Level.CONFIG ) )
  2741.             {
  2742.                 this.log( Level.CONFIG, getMessage( "defaultIndentation",
  2743.                                                     StringEscapeUtils.escapeJava( this.indentation ) ), null );

  2744.             }
  2745.         }

  2746.         return this.indentation;
  2747.     }

  2748.     /**
  2749.      * Gets an indentation string for a given indentation level.
  2750.      *
  2751.      * @param level The indentation level to get an indentation string for.
  2752.      *
  2753.      * @return The indentation string for {@code level}.
  2754.      *
  2755.      * @throws IllegalArgumentException if {@code level} is negative.
  2756.      *
  2757.      * @see #getIndentation()
  2758.      */
  2759.     public final String getIndentation( final int level )
  2760.     {
  2761.         if ( level < 0 )
  2762.         {
  2763.             throw new IllegalArgumentException( Integer.toString( level ) );
  2764.         }

  2765.         Map<String, String> map = this.indentationCache == null ? null : this.indentationCache.get();

  2766.         if ( map == null )
  2767.         {
  2768.             map = new ConcurrentHashMap<String, String>( 8 );
  2769.             this.indentationCache = new SoftReference<Map<String, String>>( map );
  2770.         }

  2771.         final String key = this.getIndentation() + "|" + level;
  2772.         String idt = map.get( key );

  2773.         if ( idt == null )
  2774.         {
  2775.             final StringBuilder b = new StringBuilder( this.getIndentation().length() * level );

  2776.             for ( int i = level; i > 0; i-- )
  2777.             {
  2778.                 b.append( this.getIndentation() );
  2779.             }

  2780.             idt = b.toString();
  2781.             map.put( key, idt );
  2782.         }

  2783.         return idt;
  2784.     }

  2785.     /**
  2786.      * Sets the indentation string of the instance.
  2787.      *
  2788.      * @param value The new indentation string of the instance or {@code null}.
  2789.      *
  2790.      * @see #getIndentation()
  2791.      */
  2792.     public final void setIndentation( final String value )
  2793.     {
  2794.         this.indentation = value;
  2795.     }

  2796.     /**
  2797.      * Gets the line separator of the instance.
  2798.      *
  2799.      * @return The line separator of the instance.
  2800.      *
  2801.      * @see #setLineSeparator(java.lang.String)
  2802.      */
  2803.     public final String getLineSeparator()
  2804.     {
  2805.         if ( this.lineSeparator == null )
  2806.         {
  2807.             this.lineSeparator = System.getProperty( "line.separator", "\n" );

  2808.             if ( this.isLoggable( Level.CONFIG ) )
  2809.             {
  2810.                 this.log( Level.CONFIG, getMessage( "defaultLineSeparator",
  2811.                                                     StringEscapeUtils.escapeJava( this.lineSeparator ) ), null );

  2812.             }
  2813.         }

  2814.         return this.lineSeparator;
  2815.     }

  2816.     /**
  2817.      * Sets the line separator of the instance.
  2818.      *
  2819.      * @param value The new line separator of the instance or {@code null}.
  2820.      *
  2821.      * @see #getLineSeparator()
  2822.      */
  2823.     public final void setLineSeparator( final String value )
  2824.     {
  2825.         this.lineSeparator = value;
  2826.     }

  2827.     /**
  2828.      * Gets the locale of the instance.
  2829.      *
  2830.      * @return The locale of the instance.
  2831.      *
  2832.      * @see #setLocale(java.util.Locale)
  2833.      *
  2834.      * @since 1.2
  2835.      */
  2836.     public final Locale getLocale()
  2837.     {
  2838.         if ( this.locale == null )
  2839.         {
  2840.             this.locale = Locale.ENGLISH;

  2841.             if ( this.isLoggable( Level.CONFIG ) )
  2842.             {
  2843.                 this.log( Level.CONFIG, getMessage( "defaultLocale", this.locale ), null );
  2844.             }
  2845.         }

  2846.         return this.locale;
  2847.     }

  2848.     /**
  2849.      * Sets the locale of the instance.
  2850.      *
  2851.      * @param value The new locale of the instance or {@code null}.
  2852.      *
  2853.      * @see #getLocale()
  2854.      *
  2855.      * @since 1.2
  2856.      */
  2857.     public final void setLocale( final Locale value )
  2858.     {
  2859.         this.locale = value;
  2860.     }

  2861.     /**
  2862.      * Gets a velocity template for a given name.
  2863.      * <p>
  2864.      * This method searches templates at the following locations recursively in the shown order stopping whenever
  2865.      * a matching template is found.
  2866.      * <ol>
  2867.      * <li><code>org/jomc/tools/templates/{@link #getTemplateProfile() profile}/{@link #getLocale() language}/<i>templateName</i></code></li>
  2868.      * <li><code>org/jomc/tools/templates/{@link #getParentTemplateProfile(java.lang.String) parent profile}/{@link #getLocale() language}/<i>templateName</i></code></li>
  2869.      * <li><code>org/jomc/tools/templates/{@link #getTemplateProfile() profile}/<i>templateName</i></code></li>
  2870.      * <li><code>org/jomc/tools/templates/{@link #getParentTemplateProfile(java.lang.String) parent profile}/{@link #getLocale() language}/<i>templateName</i></code></li>
  2871.      * </ol></p>
  2872.      *
  2873.      * @param templateName The name of the template to get.
  2874.      *
  2875.      * @return The template matching {@code templateName}.
  2876.      *
  2877.      * @throws NullPointerException if {@code templateName} is {@code null}.
  2878.      * @throws FileNotFoundException if no such template is found.
  2879.      * @throws IOException if getting the template fails.
  2880.      *
  2881.      * @see #getTemplateProfile()
  2882.      * @see #getParentTemplateProfile(java.lang.String)
  2883.      * @see #getLocale()
  2884.      * @see #getTemplateEncoding(java.lang.String)
  2885.      * @see #getVelocityEngine()
  2886.      */
  2887.     public Template getVelocityTemplate( final String templateName ) throws FileNotFoundException, IOException
  2888.     {
  2889.         if ( templateName == null )
  2890.         {
  2891.             throw new NullPointerException( "templateName" );
  2892.         }

  2893.         return this.getVelocityTemplate( this.getTemplateProfile(), templateName );
  2894.     }

  2895.     /**
  2896.      * Notifies registered listeners.
  2897.      *
  2898.      * @param level The level of the event.
  2899.      * @param message The message of the event or {@code null}.
  2900.      * @param throwable The throwable of the event or {@code null}.
  2901.      *
  2902.      * @throws NullPointerException if {@code level} is {@code null}.
  2903.      *
  2904.      * @see #getListeners()
  2905.      * @see #isLoggable(java.util.logging.Level)
  2906.      */
  2907.     public void log( final Level level, final String message, final Throwable throwable )
  2908.     {
  2909.         if ( level == null )
  2910.         {
  2911.             throw new NullPointerException( "level" );
  2912.         }

  2913.         if ( this.isLoggable( level ) )
  2914.         {
  2915.             for ( int i = this.getListeners().size() - 1; i >= 0; i-- )
  2916.             {
  2917.                 this.getListeners().get( i ).onLog( level, message, throwable );
  2918.             }
  2919.         }
  2920.     }

  2921.     private Template findVelocityTemplate( final String location, final String encoding ) throws IOException
  2922.     {
  2923.         try
  2924.         {
  2925.             return this.getVelocityEngine().getTemplate( location, encoding );
  2926.         }
  2927.         catch ( final ResourceNotFoundException e )
  2928.         {
  2929.             if ( this.isLoggable( Level.FINER ) )
  2930.             {
  2931.                 this.log( Level.FINER, getMessage( "templateNotFound", location ), null );
  2932.             }

  2933.             return null;
  2934.         }
  2935.         catch ( final ParseErrorException e )
  2936.         {
  2937.             String m = getMessage( e );
  2938.             m = m == null ? "" : " " + m;

  2939.             // JDK: As of JDK 6, "new IOException( message, cause )".
  2940.             throw (IOException) new IOException( getMessage( "invalidTemplate", location, m ) ).initCause( e );
  2941.         }
  2942.         catch ( final VelocityException e )
  2943.         {
  2944.             String m = getMessage( e );
  2945.             m = m == null ? "" : " " + m;

  2946.             // JDK: As of JDK 6, "new IOException( message, cause )".
  2947.             throw (IOException) new IOException( getMessage( "velocityException", location, m ) ).initCause( e );
  2948.         }
  2949.     }

  2950.     private java.util.Properties getTemplateProfileContextProperties( final String profileName, final String language )
  2951.         throws IOException
  2952.     {
  2953.         Map<String, java.util.Properties> map = this.templateProfileContextPropertiesCache == null
  2954.                                                     ? null : this.templateProfileContextPropertiesCache.get();

  2955.         if ( map == null )
  2956.         {
  2957.             map = new ConcurrentHashMap<String, java.util.Properties>();
  2958.             this.templateProfileContextPropertiesCache = new SoftReference<Map<String, java.util.Properties>>( map );
  2959.         }

  2960.         final String key = profileName + "|" + language;
  2961.         java.util.Properties profileProperties = map.get( key );
  2962.         boolean suppressExceptionOnClose = true;

  2963.         if ( profileProperties == null )
  2964.         {
  2965.             InputStream in = null;
  2966.             URL url = null;
  2967.             profileProperties = new java.util.Properties();

  2968.             final String resourceName = TEMPLATE_PREFIX + profileName + ( language == null ? "" : "/" + language )
  2969.                                             + "/context.properties";

  2970.             try
  2971.             {
  2972.                 url = this.getClass().getResource( "/" + resourceName );

  2973.                 if ( url != null )
  2974.                 {
  2975.                     in = url.openStream();

  2976.                     if ( this.isLoggable( Level.CONFIG ) )
  2977.                     {
  2978.                         this.log( Level.CONFIG, getMessage( "contextPropertiesFound", url.toExternalForm() ), null );
  2979.                     }

  2980.                     profileProperties.load( in );
  2981.                 }
  2982.                 else if ( this.getTemplateLocation() != null )
  2983.                 {
  2984.                     if ( this.isLoggable( Level.CONFIG ) )
  2985.                     {
  2986.                         this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", resourceName ), null );
  2987.                     }

  2988.                     url = new URL( this.getTemplateLocation(), resourceName );
  2989.                     in = url.openStream();

  2990.                     if ( this.isLoggable( Level.CONFIG ) )
  2991.                     {
  2992.                         this.log( Level.CONFIG, getMessage( "contextPropertiesFound", url.toExternalForm() ), null );
  2993.                     }

  2994.                     profileProperties.load( in );
  2995.                 }
  2996.                 else if ( this.isLoggable( Level.CONFIG ) )
  2997.                 {
  2998.                     this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", resourceName ), null );
  2999.                 }

  3000.                 suppressExceptionOnClose = false;
  3001.             }
  3002.             catch ( final FileNotFoundException e )
  3003.             {
  3004.                 if ( this.isLoggable( Level.CONFIG ) )
  3005.                 {
  3006.                     this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", url.toExternalForm() ), null );
  3007.                 }
  3008.             }
  3009.             finally
  3010.             {
  3011.                 map.put( key, profileProperties );

  3012.                 try
  3013.                 {
  3014.                     if ( in != null )
  3015.                     {
  3016.                         in.close();
  3017.                     }
  3018.                 }
  3019.                 catch ( final IOException e )
  3020.                 {
  3021.                     if ( suppressExceptionOnClose )
  3022.                     {
  3023.                         this.log( Level.SEVERE, getMessage( e ), e );
  3024.                     }
  3025.                     else
  3026.                     {
  3027.                         throw e;
  3028.                     }
  3029.                 }
  3030.             }
  3031.         }

  3032.         return profileProperties;
  3033.     }

  3034.     private void mergeTemplateProfileContextProperties( final String profileName, final String language,
  3035.                                                         final VelocityContext velocityContext ) throws IOException
  3036.     {
  3037.         if ( profileName != null )
  3038.         {
  3039.             final java.util.Properties templateProfileProperties =
  3040.                 this.getTemplateProfileContextProperties( profileName, language );

  3041.             for ( final Enumeration<?> e = templateProfileProperties.propertyNames(); e.hasMoreElements(); )
  3042.             {
  3043.                 final String name = e.nextElement().toString();
  3044.                 final String value = templateProfileProperties.getProperty( name );
  3045.                 final String[] values = value.split( "\\|" );

  3046.                 if ( !velocityContext.containsKey( name ) )
  3047.                 {
  3048.                     final String className = values[0];

  3049.                     try
  3050.                     {
  3051.                         if ( values.length > 1 )
  3052.                         {
  3053.                             final Class<?> valueClass = Class.forName( className );
  3054.                             velocityContext.put( name,
  3055.                                                  valueClass.getConstructor( String.class ).newInstance( values[1] ) );
  3056.                         }
  3057.                         else if ( value.contains( "|" ) )
  3058.                         {
  3059.                             velocityContext.put( name, Class.forName( values[0] ).newInstance() );
  3060.                         }
  3061.                         else
  3062.                         {
  3063.                             velocityContext.put( name, value );
  3064.                         }
  3065.                     }
  3066.                     catch ( final InstantiationException ex )
  3067.                     {
  3068.                         // JDK: As of JDK 6, "new IOException( message, cause )".
  3069.                         throw (IOException) new IOException( getMessage(
  3070.                             "contextPropertiesException", profileName + ( language != null ? ", " + language : "" ) ) ).
  3071.                             initCause( ex );

  3072.                     }
  3073.                     catch ( final IllegalAccessException ex )
  3074.                     {
  3075.                         // JDK: As of JDK 6, "new IOException( message, cause )".
  3076.                         throw (IOException) new IOException( getMessage(
  3077.                             "contextPropertiesException", profileName + ( language != null ? ", " + language : "" ) ) ).
  3078.                             initCause( ex );

  3079.                     }
  3080.                     catch ( final InvocationTargetException ex )
  3081.                     {
  3082.                         // JDK: As of JDK 6, "new IOException( message, cause )".
  3083.                         throw (IOException) new IOException( getMessage(
  3084.                             "contextPropertiesException", profileName + ( language != null ? ", " + language : "" ) ) ).
  3085.                             initCause( ex );

  3086.                     }
  3087.                     catch ( final NoSuchMethodException ex )
  3088.                     {
  3089.                         // JDK: As of JDK 6, "new IOException( message, cause )".
  3090.                         throw (IOException) new IOException( getMessage(
  3091.                             "contextPropertiesException", profileName + ( language != null ? ", " + language : "" ) ) ).
  3092.                             initCause( ex );

  3093.                     }
  3094.                     catch ( final ClassNotFoundException ex )
  3095.                     {
  3096.                         // JDK: As of JDK 6, "new IOException( message, cause )".
  3097.                         throw (IOException) new IOException( getMessage(
  3098.                             "contextPropertiesException", profileName + ( language != null ? ", " + language : "" ) ) ).
  3099.                             initCause( ex );

  3100.                     }
  3101.                 }
  3102.             }

  3103.             this.mergeTemplateProfileContextProperties( this.getParentTemplateProfile( profileName ), language,
  3104.                                                         velocityContext );

  3105.         }
  3106.     }

  3107.     private java.util.Properties getTemplateProfileProperties( final String profileName ) throws IOException
  3108.     {
  3109.         Map<String, java.util.Properties> map = this.templateProfilePropertiesCache == null
  3110.                                                     ? null : this.templateProfilePropertiesCache.get();

  3111.         if ( map == null )
  3112.         {
  3113.             map = new ConcurrentHashMap<String, java.util.Properties>();
  3114.             this.templateProfilePropertiesCache = new SoftReference<Map<String, java.util.Properties>>( map );
  3115.         }

  3116.         java.util.Properties profileProperties = map.get( profileName );
  3117.         boolean suppressExceptionOnClose = true;

  3118.         if ( profileProperties == null )
  3119.         {
  3120.             InputStream in = null;
  3121.             profileProperties = new java.util.Properties();

  3122.             final String resourceName = TEMPLATE_PREFIX + profileName + "/profile.properties";
  3123.             URL url = null;

  3124.             try
  3125.             {
  3126.                 url = this.getClass().getResource( "/" + resourceName );

  3127.                 if ( url != null )
  3128.                 {
  3129.                     in = url.openStream();

  3130.                     if ( this.isLoggable( Level.CONFIG ) )
  3131.                     {
  3132.                         this.log( Level.CONFIG, getMessage( "templateProfilePropertiesFound", url.toExternalForm() ),
  3133.                                   null );

  3134.                     }

  3135.                     profileProperties.load( in );
  3136.                 }
  3137.                 else if ( this.getTemplateLocation() != null )
  3138.                 {
  3139.                     if ( this.isLoggable( Level.CONFIG ) )
  3140.                     {
  3141.                         this.log( Level.CONFIG, getMessage( "templateProfilePropertiesNotFound", resourceName ), null );
  3142.                     }

  3143.                     url = new URL( this.getTemplateLocation(), resourceName );
  3144.                     in = url.openStream();

  3145.                     if ( this.isLoggable( Level.CONFIG ) )
  3146.                     {
  3147.                         this.log( Level.CONFIG, getMessage( "templateProfilePropertiesFound", url.toExternalForm() ),
  3148.                                   null );

  3149.                     }

  3150.                     profileProperties.load( in );
  3151.                 }
  3152.                 else if ( this.isLoggable( Level.CONFIG ) )
  3153.                 {
  3154.                     this.log( Level.CONFIG, getMessage( "templateProfilePropertiesNotFound", resourceName ), null );
  3155.                 }

  3156.                 suppressExceptionOnClose = false;
  3157.             }
  3158.             catch ( final FileNotFoundException e )
  3159.             {
  3160.                 if ( this.isLoggable( Level.CONFIG ) )
  3161.                 {
  3162.                     this.log( Level.CONFIG, getMessage( "templateProfilePropertiesNotFound", url.toExternalForm() ),
  3163.                               null );

  3164.                 }
  3165.             }
  3166.             finally
  3167.             {
  3168.                 map.put( profileName, profileProperties );

  3169.                 try
  3170.                 {
  3171.                     if ( in != null )
  3172.                     {
  3173.                         in.close();
  3174.                     }
  3175.                 }
  3176.                 catch ( final IOException e )
  3177.                 {
  3178.                     if ( suppressExceptionOnClose )
  3179.                     {
  3180.                         this.log( Level.SEVERE, getMessage( e ), e );
  3181.                     }
  3182.                     else
  3183.                     {
  3184.                         throw e;
  3185.                     }
  3186.                 }
  3187.             }
  3188.         }

  3189.         return profileProperties;
  3190.     }

  3191.     private Set<String> getJavaKeywords()
  3192.     {
  3193.         Reader in = null;
  3194.         Set<String> set = this.javaKeywordsCache == null ? null : this.javaKeywordsCache.get();

  3195.         try
  3196.         {
  3197.             if ( set == null )
  3198.             {
  3199.                 in = new InputStreamReader( this.getClass().getResourceAsStream(
  3200.                     "/" + this.getClass().getPackage().getName().replace( ".", "/" ) + "/JavaKeywords.txt" ), "UTF-8" );

  3201.                 set = new CopyOnWriteArraySet<String>( IOUtils.readLines( in ) );

  3202.                 this.javaKeywordsCache = new SoftReference<Set<String>>( set );
  3203.             }
  3204.         }
  3205.         catch ( final IOException e )
  3206.         {
  3207.             throw new IllegalStateException( getMessage( e ), e );
  3208.         }
  3209.         finally
  3210.         {
  3211.             try
  3212.             {
  3213.                 if ( in != null )
  3214.                 {
  3215.                     in.close();
  3216.                 }
  3217.             }
  3218.             catch ( final IOException e )
  3219.             {
  3220.                 throw new IllegalStateException( getMessage( e ), e );
  3221.             }
  3222.         }

  3223.         return set;
  3224.     }

  3225.     private Template getVelocityTemplate( final String tp, final String tn ) throws IOException
  3226.     {
  3227.         Template template = null;

  3228.         if ( tp != null )
  3229.         {
  3230.             final String key = this.getLocale() + "|" + this.getTemplateProfile() + "|"
  3231.                                    + this.getDefaultTemplateProfile() + "|" + tn;

  3232.             Map<String, TemplateData> map = this.templateCache == null
  3233.                                                 ? null : this.templateCache.get();

  3234.             if ( map == null )
  3235.             {
  3236.                 map = new ConcurrentHashMap<String, TemplateData>( 32 );
  3237.                 this.templateCache = new SoftReference<Map<String, TemplateData>>( map );
  3238.             }

  3239.             TemplateData templateData = map.get( key );

  3240.             if ( templateData == null )
  3241.             {
  3242.                 templateData = new TemplateData();

  3243.                 if ( !StringUtils.EMPTY.equals( this.getLocale().getLanguage() ) )
  3244.                 {
  3245.                     templateData.location = TEMPLATE_PREFIX + tp + "/" + this.getLocale().getLanguage() + "/" + tn;
  3246.                     templateData.template =
  3247.                         this.findVelocityTemplate( templateData.location, this.getTemplateEncoding( tp ) );

  3248.                 }

  3249.                 if ( templateData.template == null )
  3250.                 {
  3251.                     templateData.location = TEMPLATE_PREFIX + tp + "/" + tn;
  3252.                     templateData.template =
  3253.                         this.findVelocityTemplate( templateData.location, this.getTemplateEncoding( tp ) );

  3254.                 }

  3255.                 if ( templateData.template == null )
  3256.                 {
  3257.                     template = this.getVelocityTemplate( this.getParentTemplateProfile( tp ), tn );

  3258.                     if ( template == null )
  3259.                     {
  3260.                         map.put( key, new TemplateData() );
  3261.                         throw new FileNotFoundException( getMessage( "noSuchTemplate", tn ) );
  3262.                     }
  3263.                 }
  3264.                 else
  3265.                 {
  3266.                     if ( this.isLoggable( Level.FINER ) )
  3267.                     {
  3268.                         this.log( Level.FINER, getMessage( "templateInfo", tn, templateData.location ), null );
  3269.                     }

  3270.                     template = templateData.template;
  3271.                     map.put( key, templateData );
  3272.                 }
  3273.             }
  3274.             else if ( templateData.template == null )
  3275.             {
  3276.                 throw new FileNotFoundException( getMessage( "noSuchTemplate", tn ) );
  3277.             }
  3278.             else
  3279.             {
  3280.                 if ( this.isLoggable( Level.FINER ) )
  3281.                 {
  3282.                     this.log( Level.FINER, getMessage( "templateInfo", tn, templateData.location ), null );
  3283.                 }

  3284.                 template = templateData.template;
  3285.             }
  3286.         }

  3287.         return template;
  3288.     }

  3289.     private static String getMessage( final String key, final Object... arguments )
  3290.     {
  3291.         return MessageFormat.format( ResourceBundle.getBundle(
  3292.             JomcTool.class.getName().replace( '.', '/' ) ).getString( key ), arguments );

  3293.     }

  3294.     private static String getMessage( final Throwable t )
  3295.     {
  3296.         return t != null
  3297.                    ? t.getMessage() != null && t.getMessage().trim().length() > 0
  3298.                          ? t.getMessage()
  3299.                          : getMessage( t.getCause() )
  3300.                    : null;

  3301.     }

  3302.     /**
  3303.      * @since 1.3
  3304.      */
  3305.     private static class TemplateData
  3306.     {

  3307.         private String location;

  3308.         private Template template;

  3309.     }

  3310. }