EMMA Coverage Report (generated Tue Nov 18 06:49:09 CET 2014)
[all classes][org.jomc.tools]

COVERAGE SUMMARY FOR SOURCE FILE [JomcTool.java]

nameclass, %method, %block, %line, %
JomcTool.java100% (4/4)91%  (114/125)74%  (3102/4172)80%  (626/785)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JomcTool$Listener100% (1/1)100% (2/2)55%  (6/11)80%  (4/5)
onLog (Level, String, Throwable): void 100% (1/1)38%  (3/8)67%  (2/3)
JomcTool$Listener (): void 100% (1/1)100% (3/3)100% (2/2)
     
class JomcTool100% (1/1)90%  (101/112)74%  (3049/4114)79%  (612/770)
getCsvString (String): String 0%   (0/1)0%   (0/3)0%   (0/1)
getJavaClasspathLocation (String, boolean): String 0%   (0/1)0%   (0/22)0%   (0/6)
getJavaFieldName (Dependency): String 0%   (0/1)0%   (0/12)0%   (0/3)
getJavaFieldName (Message): String 0%   (0/1)0%   (0/12)0%   (0/3)
getJavaFieldName (Property): String 0%   (0/1)0%   (0/12)0%   (0/3)
getJavaScriptString (String): String 0%   (0/1)0%   (0/3)0%   (0/1)
getMessage (Throwable): String 0%   (0/1)0%   (0/19)0%   (0/1)
getSqlString (String): String 0%   (0/1)0%   (0/3)0%   (0/1)
getXmlString (String): String 0%   (0/1)0%   (0/3)0%   (0/1)
setLocale (Locale): void 0%   (0/1)0%   (0/4)0%   (0/2)
setTemplateEncoding (String): void 0%   (0/1)0%   (0/4)0%   (0/2)
getJavadocComment (Text, int, String): String 100% (1/1)14%  (22/158)18%  (6/33)
findVelocityTemplate (String, String): Template 100% (1/1)26%  (25/97)38%  (5/13)
mergeTemplateProfileContextProperties (String, String, VelocityContext): void 100% (1/1)35%  (91/261)66%  (19/29)
getJavaSetterMethodName (Dependency): String 100% (1/1)35%  (7/20)67%  (2/3)
getJavaSetterMethodName (Message): String 100% (1/1)35%  (7/20)67%  (2/3)
getJavaSetterMethodName (Property): String 100% (1/1)35%  (7/20)67%  (2/3)
isJavaDefaultPackage (Implementation): boolean 100% (1/1)37%  (7/19)50%  (2/4)
isJavaDefaultPackage (Specification): boolean 100% (1/1)37%  (7/19)50%  (2/4)
isJavaPrimitiveType (Property): boolean 100% (1/1)37%  (7/19)50%  (2/4)
getJavaTypeName (Argument): String 100% (1/1)39%  (7/18)50%  (2/4)
getJavaTypeName (Implementation, boolean): String 100% (1/1)39%  (7/18)50%  (2/4)
getJavaTypeName (Specification, boolean): String 100% (1/1)39%  (7/18)50%  (2/4)
getJavaTypeName (Dependency): String 100% (1/1)44%  (43/97)53%  (9/17)
getTemplateProfileContextProperties (String, String): Properties 100% (1/1)54%  (145/271)58%  (24.3/42)
getImplementedJavaTypeNames (Implementation, boolean): List 100% (1/1)55%  (44/80)69%  (9.7/14)
getJavaMethodParameterName (Argument): String 100% (1/1)58%  (7/12)67%  (2/3)
getJavaMethodParameterName (Dependency): String 100% (1/1)58%  (7/12)67%  (2/3)
getJavaMethodParameterName (Message): String 100% (1/1)58%  (7/12)67%  (2/3)
getJavaMethodParameterName (Property): String 100% (1/1)58%  (7/12)67%  (2/3)
getJavaKeywords (): Set 100% (1/1)64%  (57/89)56%  (8.4/15)
getTemplateEncoding (String): String 100% (1/1)68%  (23/34)67%  (6/9)
getTemplateProfileProperties (String): Properties 100% (1/1)68%  (168/247)74%  (30.3/41)
getJavadocComment (Texts, int, String): String 100% (1/1)69%  (22/32)86%  (6/7)
getVelocityEngine (): VelocityEngine 100% (1/1)69%  (55/80)72%  (13/18)
getParentTemplateProfile (String): String 100% (1/1)74%  (32/43)67%  (6/9)
getJavaTypeName (SpecificationReference, boolean): String 100% (1/1)77%  (41/53)73%  (8/11)
getJavaTypeName (Property, boolean): String 100% (1/1)81%  (21/26)75%  (6/8)
setTemplateLocation (URL): void 100% (1/1)81%  (13/16)83%  (5/6)
JomcTool (JomcTool): void 100% (1/1)84%  (82/98)96%  (17.3/18)
log (Level, String, Throwable): void 100% (1/1)84%  (26/31)83%  (5/6)
<static initializer> 100% (1/1)93%  (25/27)98%  (3.9/4)
getJavaGetterMethodName (Property): String 100% (1/1)94%  (32/34)86%  (6/7)
getJavaPackageName (Implementation): String 100% (1/1)94%  (16/17)98%  (3.9/4)
getJavaPackageName (Specification): String 100% (1/1)94%  (16/17)98%  (3.9/4)
getVelocityTemplate (String, String): Template 100% (1/1)95%  (218/230)97%  (30/31)
getVelocityContext (): VelocityContext 100% (1/1)95%  (278/293)99%  (35.7/36)
getJavaClasspathLocation (Implementation): String 100% (1/1)95%  (19/20)98%  (3.9/4)
getJavaClasspathLocation (Specification): String 100% (1/1)95%  (19/20)98%  (3.9/4)
getHtmlString (String): String 100% (1/1)95%  (20/21)95%  (1/1)
getJavaPackageName (SpecificationReference): String 100% (1/1)98%  (51/52)99%  (10.9/11)
JomcTool (): void 100% (1/1)100% (3/3)100% (2/2)
getBooleanString (Boolean): String 100% (1/1)100% (25/25)100% (2/2)
getDefaultLogLevel (): Level 100% (1/1)100% (10/10)100% (3/3)
getDefaultTemplateEncoding (): String 100% (1/1)100% (29/29)100% (5/5)
getDefaultTemplateProfile (): String 100% (1/1)100% (8/8)100% (3/3)
getDisplayLanguage (String): String 100% (1/1)100% (16/16)100% (4/4)
getIndentation (): String 100% (1/1)100% (27/27)100% (5/5)
getIndentation (int): String 100% (1/1)100% (80/80)100% (15/15)
getInputEncoding (): String 100% (1/1)100% (33/33)100% (5/5)
getIsoDate (Calendar): String 100% (1/1)100% (17/17)100% (3/3)
getIsoDateTime (Calendar): String 100% (1/1)100% (17/17)100% (3/3)
getIsoTime (Calendar): String 100% (1/1)100% (17/17)100% (3/3)
getJavaConstantName (String): String 100% (1/1)100% (99/99)100% (21/21)
getJavaFieldName (String): String 100% (1/1)100% (99/99)100% (21/21)
getJavaGetterMethodName (Dependency): String 100% (1/1)100% (20/20)100% (3/3)
getJavaGetterMethodName (Message): String 100% (1/1)100% (20/20)100% (3/3)
getJavaIdentifier (String, boolean): String 100% (1/1)100% (97/97)100% (21/21)
getJavaInterfaceNames (Implementation, boolean): List 100% (1/1)100% (12/12)100% (3/3)
getJavaMethodParameterName (String): String 100% (1/1)100% (99/99)100% (21/21)
getJavaModifierName (Implementation, Dependency): String 100% (1/1)100% (33/33)100% (10/10)
getJavaModifierName (Implementation, Message): String 100% (1/1)100% (33/33)100% (10/10)
getJavaModifierName (Implementation, Property): String 100% (1/1)100% (33/33)100% (10/10)
getJavaString (String): String 100% (1/1)100% (3/3)100% (1/1)
getLineSeparator (): String 100% (1/1)100% (29/29)100% (5/5)
getListeners (): List 100% (1/1)100% (11/11)100% (3/3)
getLocale (): Locale 100% (1/1)100% (26/26)100% (5/5)
getLogLevel (): Level 100% (1/1)100% (27/27)100% (5/5)
getLongDate (Calendar): String 100% (1/1)100% (15/15)100% (3/3)
getLongDateTime (Calendar): String 100% (1/1)100% (16/16)100% (3/3)
getLongTime (Calendar): String 100% (1/1)100% (15/15)100% (3/3)
getMediumDate (Calendar): String 100% (1/1)100% (15/15)100% (3/3)
getMediumDateTime (Calendar): String 100% (1/1)100% (16/16)100% (3/3)
getMediumTime (Calendar): String 100% (1/1)100% (15/15)100% (3/3)
getMessage (String, Object []): String 100% (1/1)100% (11/11)100% (1/1)
getModel (): Model 100% (1/1)100% (15/15)100% (4/4)
getModules (): Modules 100% (1/1)100% (4/4)100% (1/1)
getOutputEncoding (): String 100% (1/1)100% (32/32)100% (5/5)
getShortDate (Calendar): String 100% (1/1)100% (15/15)100% (3/3)
getShortDateTime (Calendar): String 100% (1/1)100% (16/16)100% (3/3)
getShortTime (Calendar): String 100% (1/1)100% (15/15)100% (3/3)
getTemplateEncoding (): String 100% (1/1)100% (3/3)100% (1/1)
getTemplateLocation (): URL 100% (1/1)100% (3/3)100% (1/1)
getTemplateParameters (): Map 100% (1/1)100% (12/12)100% (3/3)
getTemplateProfile (): String 100% (1/1)100% (26/26)100% (5/5)
getVelocityTemplate (String): Template 100% (1/1)100% (13/13)100% (3/3)
getYears (Calendar, Calendar): String 100% (1/1)100% (79/79)100% (14/14)
isLoggable (Level): boolean 100% (1/1)100% (17/17)100% (3/3)
setDefaultLogLevel (Level): void 100% (1/1)100% (3/3)100% (2/2)
setDefaultTemplateEncoding (String): void 100% (1/1)100% (7/7)100% (3/3)
setDefaultTemplateProfile (String): void 100% (1/1)100% (3/3)100% (2/2)
setIndentation (String): void 100% (1/1)100% (4/4)100% (2/2)
setInputEncoding (String): void 100% (1/1)100% (4/4)100% (2/2)
setLineSeparator (String): void 100% (1/1)100% (4/4)100% (2/2)
setLogLevel (Level): void 100% (1/1)100% (4/4)100% (2/2)
setModel (Model): void 100% (1/1)100% (4/4)100% (2/2)
setOutputEncoding (String): void 100% (1/1)100% (4/4)100% (2/2)
setTemplateProfile (String): void 100% (1/1)100% (4/4)100% (2/2)
setVelocityEngine (VelocityEngine): void 100% (1/1)100% (7/7)100% (3/3)
toJavaConstantName (String): JavaIdentifier 100% (1/1)100% (10/10)100% (4/4)
toJavaMethodName (String): JavaIdentifier 100% (1/1)100% (10/10)100% (4/4)
toJavaVariableName (String): JavaIdentifier 100% (1/1)100% (10/10)100% (4/4)
     
class JomcTool$1JomcLogChute100% (1/1)100% (5/5)100% (25/25)100% (9/9)
JomcTool$1JomcLogChute (JomcTool): void 100% (1/1)100% (6/6)100% (3/3)
init (RuntimeServices): void 100% (1/1)100% (1/1)100% (1/1)
isLevelEnabled (int): boolean 100% (1/1)100% (5/5)100% (1/1)
log (int, String): void 100% (1/1)100% (6/6)100% (2/2)
log (int, String, Throwable): void 100% (1/1)100% (7/7)100% (2/2)
     
class JomcTool$TemplateData100% (1/1)100% (6/6)100% (22/22)100% (1/1)
JomcTool$TemplateData (): void 100% (1/1)100% (3/3)100% (1/1)
JomcTool$TemplateData (JomcTool$1): void 100% (1/1)100% (3/3)100% (1/1)
access$100 (JomcTool$TemplateData): String 100% (1/1)100% (3/3)100% (1/1)
access$102 (JomcTool$TemplateData, String): String 100% (1/1)100% (5/5)100% (1/1)
access$200 (JomcTool$TemplateData): Template 100% (1/1)100% (3/3)100% (1/1)
access$202 (JomcTool$TemplateData, Template): Template 100% (1/1)100% (5/5)100% (1/1)

1/*
2 *   Copyright (C) Christian Schulte, 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 4996 2014-11-16 03:19:12Z schulte $
29 *
30 */
31package org.jomc.tools;
32 
33import java.io.BufferedReader;
34import java.io.ByteArrayInputStream;
35import java.io.ByteArrayOutputStream;
36import java.io.FileNotFoundException;
37import java.io.IOException;
38import java.io.InputStream;
39import java.io.InputStreamReader;
40import java.io.OutputStreamWriter;
41import java.io.Reader;
42import java.io.StringReader;
43import java.lang.ref.Reference;
44import java.lang.ref.SoftReference;
45import java.lang.reflect.InvocationTargetException;
46import java.net.URL;
47import java.text.DateFormat;
48import java.text.Format;
49import java.text.MessageFormat;
50import java.text.ParseException;
51import java.text.SimpleDateFormat;
52import java.util.ArrayList;
53import java.util.Calendar;
54import java.util.Collections;
55import java.util.Enumeration;
56import java.util.HashMap;
57import java.util.List;
58import java.util.Locale;
59import java.util.Map;
60import java.util.ResourceBundle;
61import java.util.Set;
62import java.util.concurrent.ConcurrentHashMap;
63import java.util.concurrent.CopyOnWriteArrayList;
64import java.util.concurrent.CopyOnWriteArraySet;
65import java.util.logging.Level;
66import javax.activation.MimeTypeParseException;
67import org.apache.commons.io.IOUtils;
68import org.apache.commons.lang.StringEscapeUtils;
69import org.apache.commons.lang.StringUtils;
70import org.apache.velocity.Template;
71import org.apache.velocity.VelocityContext;
72import org.apache.velocity.app.VelocityEngine;
73import org.apache.velocity.exception.ParseErrorException;
74import org.apache.velocity.exception.ResourceNotFoundException;
75import org.apache.velocity.exception.VelocityException;
76import org.apache.velocity.runtime.RuntimeConstants;
77import org.apache.velocity.runtime.RuntimeServices;
78import org.apache.velocity.runtime.log.LogChute;
79import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
80import org.apache.velocity.runtime.resource.loader.URLResourceLoader;
81import org.jomc.model.Argument;
82import org.jomc.model.Dependency;
83import org.jomc.model.Implementation;
84import org.jomc.model.InheritanceModel;
85import org.jomc.model.JavaIdentifier;
86import org.jomc.model.JavaTypeName;
87import org.jomc.model.Message;
88import org.jomc.model.ModelObject;
89import org.jomc.model.ModelObjectException;
90import org.jomc.model.Modules;
91import org.jomc.model.Multiplicity;
92import org.jomc.model.Property;
93import org.jomc.model.Specification;
94import org.jomc.model.SpecificationReference;
95import org.jomc.model.Text;
96import org.jomc.model.Texts;
97import org.jomc.model.modlet.ModelHelper;
98import org.jomc.modlet.Model;
99 
100/**
101 * Base tool class.
102 *
103 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
104 * @version $JOMC: JomcTool.java 4996 2014-11-16 03:19:12Z schulte $
105 */
106public class JomcTool
107{
108 
109    /** Listener interface. */
110    public abstract static class Listener
111    {
112 
113        /** Creates a new {@code Listener} instance. */
114        public Listener()
115        {
116            super();
117        }
118 
119        /**
120         * Gets called on logging.
121         *
122         * @param level The level of the event.
123         * @param message The message of the event or {@code null}.
124         * @param throwable The throwable of the event or {@code null}.
125         *
126         * @throws NullPointerException if {@code level} is {@code null}.
127         */
128        public void onLog( final Level level, final String message, final Throwable throwable )
129        {
130            if ( level == null )
131            {
132                throw new NullPointerException( "level" );
133            }
134        }
135 
136    }
137 
138    /** Empty byte array. */
139    private static final byte[] NO_BYTES =
140    {
141    };
142 
143    /** The prefix of the template location. */
144    private static final String TEMPLATE_PREFIX =
145        JomcTool.class.getPackage().getName().replace( '.', '/' ) + "/templates/";
146 
147    /** Constant for the default template profile. */
148    private static final String DEFAULT_TEMPLATE_PROFILE = "jomc-java";
149 
150    /**
151     * Constant for the name of the template profile property specifying a parent template profile name.
152     * @since 1.3
153     */
154    private static final String PARENT_TEMPLATE_PROFILE_PROPERTY_NAME = "parent-template-profile";
155 
156    /**
157     * Constant for the name of the template profile property specifying the template encoding.
158     * @since 1.3
159     */
160    private static final String TEMPLATE_ENCODING_PROFILE_PROPERTY_NAME = "template-encoding";
161 
162    /**
163     * The default encoding to use for reading templates.
164     * @since 1.3
165     */
166    private String defaultTemplateEncoding;
167 
168    /** The default template profile. */
169    private static volatile String defaultTemplateProfile;
170 
171    /**
172     * The log level events are logged at by default.
173     * @see #getDefaultLogLevel()
174     */
175    private static final Level DEFAULT_LOG_LEVEL = Level.WARNING;
176 
177    /** The default log level. */
178    private static volatile Level defaultLogLevel;
179 
180    /** The model of the instance. */
181    private Model model;
182 
183    /** The {@code VelocityEngine} of the instance. */
184    private VelocityEngine velocityEngine;
185 
186    /**
187     * Flag indicating the default {@code VelocityEngine}.
188     * @since 1.2.4
189     */
190    private boolean defaultVelocityEngine;
191 
192    /**
193     * The location to search for templates in addition to searching the class path.
194     * @since 1.2
195     */
196    private URL templateLocation;
197 
198    /** The encoding to use for reading files. */
199    private String inputEncoding;
200 
201    /** The encoding to use for writing files. */
202    private String outputEncoding;
203 
204    /**
205     * The template parameters.
206     * @since 1.2
207     */
208    private Map<String, Object> templateParameters;
209 
210    /** The template profile of the instance. */
211    private String templateProfile;
212 
213    /** The indentation string of the instance. */
214    private String indentation;
215 
216    /** The line separator of the instance. */
217    private String lineSeparator;
218 
219    /** The listeners of the instance. */
220    private List<Listener> listeners;
221 
222    /** The log level of the instance. */
223    private Level logLevel;
224 
225    /**
226     * The locale of the instance.
227     * @since 1.2
228     */
229    private Locale locale;
230 
231    /** Cached indentation strings. */
232    private volatile Reference<Map<String, String>> indentationCache;
233 
234    /**
235     * Cached templates.
236     * @since 1.3
237     */
238    private volatile Reference<Map<String, TemplateData>> templateCache;
239 
240    /**
241     * Cached template profile context properties.
242     * @since 1.3
243     */
244    private volatile Reference<Map<String, java.util.Properties>> templateProfileContextPropertiesCache;
245 
246    /**
247     * Cached template profile properties.
248     * @since 1.3
249     */
250    private volatile Reference<Map<String, java.util.Properties>> templateProfilePropertiesCache;
251 
252    /** Cached Java keywords. */
253    private volatile Reference<Set<String>> javaKeywordsCache;
254 
255    /** Creates a new {@code JomcTool} instance. */
256    public JomcTool()
257    {
258        super();
259    }
260 
261    /**
262     * Creates a new {@code JomcTool} instance taking a {@code JomcTool} instance to initialize the new instance with.
263     *
264     * @param tool The instance to initialize the new instance with.
265     *
266     * @throws NullPointerException if {@code tool} is {@code null}.
267     * @throws IOException if copying {@code tool} fails.
268     */
269    public JomcTool( final JomcTool tool ) throws IOException
270    {
271        this();
272 
273        if ( tool == null )
274        {
275            throw new NullPointerException( "tool" );
276        }
277 
278        this.indentation = tool.indentation;
279        this.inputEncoding = tool.inputEncoding;
280        this.lineSeparator = tool.lineSeparator;
281        this.listeners = tool.listeners != null ? new CopyOnWriteArrayList<Listener>( tool.listeners ) : null;
282        this.logLevel = tool.logLevel;
283        this.model = tool.model != null ? tool.model.clone() : null;
284        this.outputEncoding = tool.outputEncoding;
285        this.defaultTemplateEncoding = tool.defaultTemplateEncoding;
286        this.templateProfile = tool.templateProfile;
287        this.velocityEngine = tool.velocityEngine;
288        this.defaultVelocityEngine = tool.defaultVelocityEngine;
289        this.locale = tool.locale;
290        this.templateParameters =
291            tool.templateParameters != null
292            ? Collections.synchronizedMap( new HashMap<String, Object>( tool.templateParameters ) )
293            : null;
294 
295        this.templateLocation =
296            tool.templateLocation != null ? new URL( tool.templateLocation.toExternalForm() ) : null;
297 
298    }
299 
300    /**
301     * Gets the list of registered listeners.
302     * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
303     * to the returned list will be present inside the object. This is why there is no {@code set} method for the
304     * listeners property.</p>
305     *
306     * @return The list of registered listeners.
307     *
308     * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
309     */
310    public List<Listener> getListeners()
311    {
312        if ( this.listeners == null )
313        {
314            this.listeners = new CopyOnWriteArrayList<Listener>();
315        }
316 
317        return this.listeners;
318    }
319 
320    /**
321     * Gets the default log level events are logged at.
322     * <p>The default log level is controlled by system property {@code org.jomc.tools.JomcTool.defaultLogLevel} holding
323     * the log level to log events at by default. If that property is not set, the {@code WARNING} default is
324     * returned.</p>
325     *
326     * @return The log level events are logged at by default.
327     *
328     * @see #getLogLevel()
329     * @see Level#parse(java.lang.String)
330     */
331    public static Level getDefaultLogLevel()
332    {
333        if ( defaultLogLevel == null )
334        {
335            defaultLogLevel = Level.parse( System.getProperty( "org.jomc.tools.JomcTool.defaultLogLevel",
336                                                               DEFAULT_LOG_LEVEL.getName() ) );
337 
338        }
339 
340        return defaultLogLevel;
341    }
342 
343    /**
344     * Sets the default log level events are logged at.
345     *
346     * @param value The new default level events are logged at or {@code null}.
347     *
348     * @see #getDefaultLogLevel()
349     */
350    public static void setDefaultLogLevel( final Level value )
351    {
352        defaultLogLevel = value;
353    }
354 
355    /**
356     * Gets the log level of the instance.
357     *
358     * @return The log level of the instance.
359     *
360     * @see #getDefaultLogLevel()
361     * @see #setLogLevel(java.util.logging.Level)
362     * @see #isLoggable(java.util.logging.Level)
363     */
364    public final Level getLogLevel()
365    {
366        if ( this.logLevel == null )
367        {
368            this.logLevel = getDefaultLogLevel();
369 
370            if ( this.isLoggable( Level.CONFIG ) )
371            {
372                this.log( Level.CONFIG, getMessage( "defaultLogLevelInfo", this.logLevel.getLocalizedName() ), null );
373            }
374        }
375 
376        return this.logLevel;
377    }
378 
379    /**
380     * Sets the log level of the instance.
381     *
382     * @param value The new log level of the instance or {@code null}.
383     *
384     * @see #getLogLevel()
385     * @see #isLoggable(java.util.logging.Level)
386     */
387    public final void setLogLevel( final Level value )
388    {
389        this.logLevel = value;
390    }
391 
392    /**
393     * Checks if a message at a given level is provided to the listeners of the instance.
394     *
395     * @param level The level to test.
396     *
397     * @return {@code true}, if messages at {@code level} are provided to the listeners of the instance;
398     * {@code false}, if messages at {@code level} are not provided to the listeners of the instance.
399     *
400     * @throws NullPointerException if {@code level} is {@code null}.
401     *
402     * @see #getLogLevel()
403     * @see #setLogLevel(java.util.logging.Level)
404     * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
405     */
406    public boolean isLoggable( final Level level )
407    {
408        if ( level == null )
409        {
410            throw new NullPointerException( "level" );
411        }
412 
413        return level.intValue() >= this.getLogLevel().intValue();
414    }
415 
416    /**
417     * Gets the Java package name of a specification.
418     *
419     * @param specification The specification to get the Java package name of.
420     *
421     * @return The Java package name of {@code specification} or {@code null}, if the specification does not reference a
422     * type.
423     *
424     * @throws NullPointerException if {@code specification} is {@code null}.
425     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
426     *
427     * @see Specification#getJavaTypeName()
428     * @see JavaTypeName#getPackageName()
429     *
430     * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
431     * removed in JOMC 2.0.
432     */
433    @Deprecated
434    public String getJavaPackageName( final Specification specification ) throws ModelObjectException
435    {
436        if ( specification == null )
437        {
438            throw new NullPointerException( "specification" );
439        }
440 
441        final JavaTypeName javaTypeName = specification.getJavaTypeName();
442        return javaTypeName != null ? javaTypeName.getPackageName() : null;
443    }
444 
445    /**
446     * Gets the Java type name of a specification.
447     *
448     * @param specification The specification to get the Java type name of.
449     * @param qualified {@code true}, to return the fully qualified type name (with package name prepended);
450     * {@code false}, to return the short type name (without package name prepended).
451     *
452     * @return The Java type name of the type referenced by the specification or {@code null}, if the specification does
453     * not reference a type.
454     *
455     * @throws NullPointerException if {@code specification} is {@code null}.
456     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
457     *
458     * @see Specification#getJavaTypeName()
459     * @see JavaTypeName#getName(boolean)
460     *
461     * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
462     * removed in JOMC 2.0.
463     */
464    @Deprecated
465    public String getJavaTypeName( final Specification specification, final boolean qualified )
466        throws ModelObjectException
467    {
468        if ( specification == null )
469        {
470            throw new NullPointerException( "specification" );
471        }
472 
473        final JavaTypeName javaTypeName = specification.getJavaTypeName();
474        return javaTypeName != null ? javaTypeName.getName( qualified ) : null;
475    }
476 
477    /**
478     * Gets the Java class path location of a specification.
479     *
480     * @param specification The specification to return the Java class path location of.
481     *
482     * @return The Java class path location of {@code specification} or {@code null}, if the specification does not
483     * reference a type.
484     *
485     * @throws NullPointerException if {@code specification} is {@code null}.
486     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
487     *
488     * @see Specification#getJavaTypeName()
489     * @see JavaTypeName#getQualifiedName()
490     *
491     * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
492     * removed in JOMC 2.0.
493     */
494    @Deprecated
495    public String getJavaClasspathLocation( final Specification specification ) throws ModelObjectException
496    {
497        if ( specification == null )
498        {
499            throw new NullPointerException( "specification" );
500        }
501 
502        final JavaTypeName javaTypeName = specification.getJavaTypeName();
503        return javaTypeName != null ? javaTypeName.getQualifiedName().replace( '.', '/' ) : null;
504    }
505 
506    /**
507     * Gets the Java package name of a specification reference.
508     *
509     * @param reference The specification reference to get the Java package name of.
510     *
511     * @return The Java package name of {@code reference} or {@code null}, if the referenced specification is not found
512     * or does not reference a type.
513     *
514     * @throws NullPointerException if {@code reference} is {@code null}.
515     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
516     *
517     * @see Modules#getSpecification(java.lang.String)
518     * @see Specification#getJavaTypeName()
519     * @see JavaTypeName#getPackageName()
520     *
521     * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
522     * removed in JOMC 2.0.
523     */
524    @Deprecated
525    public String getJavaPackageName( final SpecificationReference reference ) throws ModelObjectException
526    {
527        if ( reference == null )
528        {
529            throw new NullPointerException( "reference" );
530        }
531 
532        Specification s = null;
533        String javaPackageName = null;
534 
535        if ( this.getModules() != null
536             && ( s = this.getModules().getSpecification( reference.getIdentifier() ) ) != null )
537        {
538            final JavaTypeName javaTypeName = s.getJavaTypeName();
539            javaPackageName = javaTypeName != null ? javaTypeName.getPackageName() : null;
540        }
541        else if ( this.isLoggable( Level.WARNING ) )
542        {
543            this.log( Level.WARNING, getMessage( "specificationNotFound", reference.getIdentifier() ), null );
544        }
545 
546        return javaPackageName;
547    }
548 
549    /**
550     * Gets the name of a Java type of a given specification reference.
551     *
552     * @param reference The specification reference to get a Java type name of.
553     * @param qualified {@code true}, to return the fully qualified type name (with package name prepended);
554     * {@code false}, to return the short type name (without package name prepended).
555     *
556     * @return The Java type name of {@code reference} or {@code null}, if the referenced specification is not found
557     * or does not reference a type.
558     *
559     * @throws NullPointerException if {@code reference} is {@code null}.
560     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
561     *
562     * @see Modules#getSpecification(java.lang.String)
563     * @see Specification#getJavaTypeName()
564     * @see JavaTypeName#getName(boolean)
565     *
566     * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
567     * removed in JOMC 2.0.
568     */
569    @Deprecated
570    public String getJavaTypeName( final SpecificationReference reference, final boolean qualified )
571        throws ModelObjectException
572    {
573        if ( reference == null )
574        {
575            throw new NullPointerException( "reference" );
576        }
577 
578        Specification s = null;
579        String typeName = null;
580 
581        if ( this.getModules() != null
582             && ( s = this.getModules().getSpecification( reference.getIdentifier() ) ) != null )
583        {
584            final JavaTypeName javaTypeName = s.getJavaTypeName();
585            typeName = javaTypeName != null ? javaTypeName.getName( qualified ) : null;
586        }
587        else if ( this.isLoggable( Level.WARNING ) )
588        {
589            this.log( Level.WARNING, getMessage( "specificationNotFound", reference.getIdentifier() ), null );
590        }
591 
592        return typeName;
593    }
594 
595    /**
596     * Gets the Java package name of an implementation.
597     *
598     * @param implementation The implementation to get the Java package name of.
599     *
600     * @return The Java package name of {@code implementation} or {@code null}, if the implementation does not reference
601     * a type.
602     *
603     * @throws NullPointerException if {@code implementation} is {@code null}.
604     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
605     *
606     * @see Implementation#getJavaTypeName()
607     * @see JavaTypeName#getPackageName()
608     *
609     * @deprecated As of JOMC 1.4, please use method {@link Implementation#getJavaTypeName()}. This method will be
610     * removed in JOMC 2.0.
611     */
612    @Deprecated
613    public String getJavaPackageName( final Implementation implementation ) throws ModelObjectException
614    {
615        if ( implementation == null )
616        {
617            throw new NullPointerException( "implementation" );
618        }
619 
620        final JavaTypeName javaTypeName = implementation.getJavaTypeName();
621        return javaTypeName != null ? javaTypeName.getPackageName() : null;
622    }
623 
624    /**
625     * Gets the Java type name of an implementation.
626     *
627     * @param implementation The implementation to get the Java type name of.
628     * @param qualified {@code true}, to return the fully qualified type name (with package name prepended);
629     * {@code false}, to return the short type name (without package name prepended).
630     *
631     * @return The Java type name of the type referenced by the implementation or {@code null}, if the implementation
632     * does not reference a type.
633     *
634     * @throws NullPointerException if {@code implementation} is {@code null}.
635     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
636     *
637     * @see Implementation#getJavaTypeName()
638     * @see JavaTypeName#getName(boolean)
639     *
640     * @deprecated As of JOMC 1.4, please use method {@link Implementation#getJavaTypeName()}. This method will be
641     * removed in JOMC 2.0.
642     */
643    @Deprecated
644    public String getJavaTypeName( final Implementation implementation, final boolean qualified )
645        throws ModelObjectException
646    {
647        if ( implementation == null )
648        {
649            throw new NullPointerException( "implementation" );
650        }
651 
652        final JavaTypeName javaTypeName = implementation.getJavaTypeName();
653        return javaTypeName != null ? javaTypeName.getName( qualified ) : null;
654    }
655 
656    /**
657     * Gets the Java class path location of an implementation.
658     *
659     * @param implementation The implementation to return the Java class path location of.
660     *
661     * @return The Java class path location of {@code implementation} or {@code null}, if the implementation does not
662     * reference a type.
663     *
664     * @throws NullPointerException if {@code implementation} is {@code null}.
665     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
666     *
667     * @see Implementation#getJavaTypeName()
668     * @see JavaTypeName#getQualifiedName()
669     *
670     * @deprecated As of JOMC 1.4, please use method {@link Implementation#getJavaTypeName()}. This method will be
671     * removed in JOMC 2.0.
672     */
673    @Deprecated
674    public String getJavaClasspathLocation( final Implementation implementation ) throws ModelObjectException
675    {
676        if ( implementation == null )
677        {
678            throw new NullPointerException( "implementation" );
679        }
680 
681        final JavaTypeName javaTypeName = implementation.getJavaTypeName();
682        return javaTypeName != null ? javaTypeName.getQualifiedName().replace( '.', '/' ) : null;
683    }
684 
685    /**
686     * Gets a list of names of all Java types an implementation implements.
687     *
688     * @param implementation The implementation to get names of all implemented Java types of.
689     * @param qualified {@code true}, to return the fully qualified type names (with package name prepended);
690     * {@code false}, to return the short type names (without package name prepended).
691     *
692     * @return An unmodifiable list of names of all Java types implemented by {@code implementation}.
693     *
694     * @throws NullPointerException if {@code implementation} is {@code null}.
695     * @throws ModelObjectException if compiling the name of a referenced type to a {@code JavaTypeName} fails.
696     *
697     * @deprecated As of JOMC 1.2, replaced by method {@link #getImplementedJavaTypeNames(org.jomc.model.Implementation, boolean)}.
698     * This method will be removed in version 2.0.
699     */
700    @Deprecated
701    public List<String> getJavaInterfaceNames( final Implementation implementation, final boolean qualified )
702        throws ModelObjectException
703    {
704        if ( implementation == null )
705        {
706            throw new NullPointerException( "implementation" );
707        }
708 
709        return this.getImplementedJavaTypeNames( implementation, qualified );
710    }
711 
712    /**
713     * Gets a list of names of all Java types an implementation implements.
714     *
715     * @param implementation The implementation to get names of all implemented Java types of.
716     * @param qualified {@code true}, to return the fully qualified type names (with package name prepended);
717     * {@code false}, to return the short type names (without package name prepended).
718     *
719     * @return An unmodifiable list of names of all Java types implemented by {@code implementation}.
720     *
721     * @throws NullPointerException if {@code implementation} is {@code null}.
722     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
723     *
724     * @since 1.2
725     *
726     * @deprecated As of JOMC 1.4, please use method {@link Modules#getImplementedJavaTypeNames(java.lang.String)}.
727     * This method will be removed in JOMC 2.0.
728     */
729    @Deprecated
730    public List<String> getImplementedJavaTypeNames( final Implementation implementation, final boolean qualified )
731        throws ModelObjectException
732    {
733        if ( implementation == null )
734        {
735            throw new NullPointerException( "implementation" );
736        }
737 
738        List<String> col = null;
739 
740        if ( this.getModules() != null )
741        {
742            final List<JavaTypeName> javaTypeNames =
743                this.getModules().getImplementedJavaTypeNames( implementation.getIdentifier() );
744 
745            if ( javaTypeNames != null )
746            {
747                col = new ArrayList<String>( javaTypeNames.size() );
748 
749                for ( int i = 0, s0 = javaTypeNames.size(); i < s0; i++ )
750                {
751                    if ( !col.contains( javaTypeNames.get( i ).getName( qualified ) ) )
752                    {
753                        col.add( javaTypeNames.get( i ).getName( qualified ) );
754                    }
755                }
756            }
757        }
758        else if ( this.isLoggable( Level.WARNING ) )
759        {
760            this.log( Level.WARNING, getMessage( "modulesNotFound", this.getModel().getIdentifier() ), null );
761        }
762 
763        return Collections.unmodifiableList( col != null ? col : Collections.<String>emptyList() );
764    }
765 
766    /**
767     * Gets the Java type name of an argument.
768     *
769     * @param argument The argument to get the Java type name of.
770     *
771     * @return The Java type name of the type referenced by the argument or {@code null}, if the argument does not
772     * reference a type.
773     *
774     * @throws NullPointerException if {@code argument} is {@code null}.
775     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
776     *
777     * @see Argument#getJavaTypeName()
778     * @see JavaTypeName#getName(boolean)
779     *
780     * @deprecated As of JOMC 1.4, please use method {@link Argument#getJavaTypeName()}. This method will be removed in
781     * JOMC 2.0.
782     */
783    @Deprecated
784    public String getJavaTypeName( final Argument argument ) throws ModelObjectException
785    {
786        if ( argument == null )
787        {
788            throw new NullPointerException( "argument" );
789        }
790 
791        final JavaTypeName javaTypeName = argument.getJavaTypeName();
792        return javaTypeName != null ? javaTypeName.getName( true ) : null;
793    }
794 
795    /**
796     * Gets a Java method parameter name of an argument.
797     *
798     * @param argument The argument to get the Java method parameter name of.
799     *
800     * @return The Java method parameter name of {@code argument}.
801     *
802     * @throws NullPointerException if {@code argument} is {@code null}.
803     * @throws ModelObjectException if compiling the name of the argument to a {@code JavaIdentifier} fails.
804     *
805     * @see Argument#getJavaVariableName()
806     *
807     * @since 1.2
808     *
809     * @deprecated As of JOMC 1.4, please use method {@link Argument#getJavaVariableName()}. This method will be
810     * removed in JOMC 2.0.
811     */
812    @Deprecated
813    public String getJavaMethodParameterName( final Argument argument ) throws ModelObjectException
814    {
815        if ( argument == null )
816        {
817            throw new NullPointerException( "argument" );
818        }
819 
820        return this.getJavaMethodParameterName( argument.getName() );
821    }
822 
823    /**
824     * Gets the Java type name of a property.
825     *
826     * @param property The property to get the Java type name of.
827     * @param boxify {@code true}, to return the name of the Java wrapper class when the type is a Java primitive type;
828     * {@code false}, to return the exact binary name (unboxed name) of the Java type.
829     *
830     * @return The Java type name of the type referenced by the property or {@code null}, if the property does not
831     * reference a type.
832     *
833     * @throws NullPointerException if {@code property} is {@code null}.
834     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
835     *
836     * @see Property#getJavaTypeName()
837     * @see JavaTypeName#getBoxedName()
838     * @see JavaTypeName#getName(boolean)
839     *
840     * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaTypeName()}. This method will be removed in
841     * JOMC 2.0.
842     */
843    @Deprecated
844    public String getJavaTypeName( final Property property, final boolean boxify ) throws ModelObjectException
845    {
846        if ( property == null )
847        {
848            throw new NullPointerException( "property" );
849        }
850 
851        JavaTypeName javaTypeName = property.getJavaTypeName();
852 
853        if ( javaTypeName != null )
854        {
855            if ( boxify && javaTypeName.isPrimitive() )
856            {
857                javaTypeName = javaTypeName.getBoxedName();
858            }
859 
860            return javaTypeName.getName( true );
861        }
862 
863        return null;
864    }
865 
866    /**
867     * Gets a flag indicating the type of a given property is a Java primitive.
868     *
869     * @param property The property to query.
870     *
871     * @return {@code true}, if the Java type referenced by the property is primitive or {@code false}, if the property
872     * does not reference a type or if the Java type referenced by the property is not primitive.
873     *
874     * @throws NullPointerException if {@code property} is {@code null}.
875     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
876     *
877     * @see Property#getJavaTypeName()
878     * @see JavaTypeName#isPrimitive()
879     *
880     * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaTypeName()}. This method will be removed in
881     * JOMC 2.0.
882     */
883    @Deprecated
884    public boolean isJavaPrimitiveType( final Property property ) throws ModelObjectException
885    {
886        if ( property == null )
887        {
888            throw new NullPointerException( "property" );
889        }
890 
891        final JavaTypeName javaTypeName = property.getJavaTypeName();
892        return javaTypeName != null && javaTypeName.isPrimitive();
893    }
894 
895    /**
896     * Gets the name of a Java getter method of a given property.
897     *
898     * @param property The property to get a Java getter method name of.
899     *
900     * @return The Java getter method name of {@code property}.
901     *
902     * @throws NullPointerException if {@code property} is {@code null}.
903     * @throws ModelObjectException if compiling the name of the property to a {@code JavaIdentifier} fails.
904     *
905     * @see Property#getJavaGetterMethodName()
906     *
907     * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaGetterMethodName()}. This method will be
908     * removed in JOMC 2.0.
909     */
910    @Deprecated
911    public String getJavaGetterMethodName( final Property property ) throws ModelObjectException
912    {
913        if ( property == null )
914        {
915            throw new NullPointerException( "property" );
916        }
917 
918        String prefix = "get";
919 
920        final String javaTypeName = this.getJavaTypeName( property, true );
921        if ( Boolean.class.getName().equals( javaTypeName ) )
922        {
923            prefix = "is";
924        }
925 
926        return prefix + this.getJavaIdentifier( property.getName(), true );
927    }
928 
929    /**
930     * Gets the name of a Java setter method of a given property.
931     *
932     * @param property The property to get a Java setter method name of.
933     *
934     * @return The Java setter method name of {@code property}.
935     *
936     * @throws NullPointerException if {@code property} is {@code null}.
937     * @throws ModelObjectException if compiling the name of the property to a {@code JavaIdentifier} fails.
938     *
939     * @see Property#getJavaSetterMethodName()
940     *
941     * @since 1.2
942     *
943     * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaSetterMethodName()}. This method will be
944     * removed in JOMC 2.0.
945     */
946    @Deprecated
947    public String getJavaSetterMethodName( final Property property ) throws ModelObjectException
948    {
949        if ( property == null )
950        {
951            throw new NullPointerException( "property" );
952        }
953 
954        return "set" + this.getJavaIdentifier( property.getName(), true );
955    }
956 
957    /**
958     * Gets a Java method parameter name of a property.
959     *
960     * @param property The property to get the Java method parameter name of.
961     *
962     * @return The Java method parameter name of {@code property}.
963     *
964     * @throws NullPointerException if {@code property} is {@code null}.
965     * @throws ModelObjectException if copmiling the name of the property to a {@code JavaIdentifier} fails.
966     *
967     * @see Property#getJavaVariableName()
968     *
969     * @since 1.2
970     *
971     * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaVariableName()}. This method will be
972     * removed in JOMC 2.0.
973     */
974    @Deprecated
975    public String getJavaMethodParameterName( final Property property ) throws ModelObjectException
976    {
977        if ( property == null )
978        {
979            throw new NullPointerException( "property" );
980        }
981 
982        return this.getJavaMethodParameterName( property.getName() );
983    }
984 
985    /**
986     * Gets a Java field name of a property.
987     *
988     * @param property The property to get the Java field name of.
989     *
990     * @return The Java field name of {@code property}.
991     *
992     * @throws NullPointerException if {@code property} is {@code null}.
993     * @throws ModelObjectException if compiling the name of the property to a {@code JavaIdentifier} fails.
994     *
995     * @see Property#getJavaVariableName()
996     *
997     * @since 1.3
998     *
999     * @deprecated As of JOMC 1.4, please use method {@link Property#getJavaVariableName()}. This method will be removed
1000     * in JOMC 2.0.
1001     */
1002    @Deprecated
1003    public String getJavaFieldName( final Property property ) throws ModelObjectException
1004    {
1005        if ( property == null )
1006        {
1007            throw new NullPointerException( "property" );
1008        }
1009 
1010        return this.getJavaFieldName( property.getName() );
1011    }
1012 
1013    /**
1014     * Gets the name of a Java type of a given dependency.
1015     *
1016     * @param dependency The dependency to get a dependency Java type name of.
1017     *
1018     * @return The Java type name of the dependency or {@code null}, if the referenced specification is not found or
1019     * does not reference a type.
1020     *
1021     * @throws NullPointerException if {@code dependency} is {@code null}.
1022     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
1023     *
1024     * @deprecated As of JOMC 1.4, please use method {@link Modules#getDependencyJavaTypeName(java.lang.String, java.lang.String)}.
1025     * This method will be removed in JOMC 2.0.
1026     */
1027    @Deprecated
1028    public String getJavaTypeName( final Dependency dependency ) throws ModelObjectException
1029    {
1030        if ( dependency == null )
1031        {
1032            throw new NullPointerException( "dependency" );
1033        }
1034 
1035        Specification s = null;
1036        StringBuilder typeName = null;
1037        String javaTypeName = null;
1038 
1039        try
1040        {
1041            if ( this.getModules() != null
1042                 && ( s = this.getModules().getSpecification( dependency.getIdentifier() ) ) != null )
1043            {
1044                if ( s.getClazz() != null )
1045                {
1046                    typeName = new StringBuilder( s.getClazz().length() );
1047                    typeName.append( this.getJavaTypeName( s, true ) );
1048 
1049                    if ( s.getMultiplicity() == Multiplicity.MANY && dependency.getImplementationName() == null )
1050                    {
1051                        typeName.append( "[]" );
1052                    }
1053 
1054                    javaTypeName = JavaTypeName.parse( typeName.toString() ).getName( true );
1055                }
1056            }
1057            else if ( this.isLoggable( Level.WARNING ) )
1058            {
1059                this.log( Level.WARNING, getMessage( "specificationNotFound", dependency.getIdentifier() ), null );
1060            }
1061 
1062            return javaTypeName;
1063        }
1064        catch ( final ParseException e )
1065        {
1066            throw new ModelObjectException( getMessage( "dependencyJavaTypeNameParseException", typeName,
1067                                                        getMessage( e ) ), e );
1068 
1069        }
1070    }
1071 
1072    /**
1073     * Gets the name of a Java getter method of a given dependency.
1074     *
1075     * @param dependency The dependency to get a Java getter method name of.
1076     *
1077     * @return The Java getter method name of {@code dependency}.
1078     *
1079     * @throws NullPointerException if {@code dependency} is {@code null}.
1080     * @throws ModelObjectException if compiling the name of the dependency to a {@code JavaIdentifier} fails.
1081     *
1082     * @see Dependency#getJavaGetterMethodName()
1083     *
1084     * @deprecated As of JOMC 1.4, please use method {@link Dependency#getJavaGetterMethodName()}. This method will be
1085     * removed in JOMC 2.0.
1086     */
1087    @Deprecated
1088    public String getJavaGetterMethodName( final Dependency dependency ) throws ModelObjectException
1089    {
1090        if ( dependency == null )
1091        {
1092            throw new NullPointerException( "dependency" );
1093        }
1094 
1095        return "get" + this.getJavaIdentifier( dependency.getName(), true );
1096    }
1097 
1098    /**
1099     * Gets the name of a Java setter method of a given dependency.
1100     *
1101     * @param dependency The dependency to get a Java setter method name of.
1102     *
1103     * @return The Java setter method name of {@code dependency}.
1104     *
1105     * @throws NullPointerException if {@code dependency} is {@code null}.
1106     * @throws ModelObjectException if compiling the name of the dependency to a {@code JavaIdentifier} fails.
1107     *
1108     * @see Dependency#getJavaSetterMethodName()
1109     *
1110     * @since 1.2
1111     *
1112     * @deprecated As of JOMC 1.4, please use method {@link Dependency#getJavaSetterMethodName()}. This method will be
1113     * removed in JOMC 2.0.
1114     */
1115    @Deprecated
1116    public String getJavaSetterMethodName( final Dependency dependency ) throws ModelObjectException
1117    {
1118        if ( dependency == null )
1119        {
1120            throw new NullPointerException( "dependency" );
1121        }
1122 
1123        return "set" + this.getJavaIdentifier( dependency.getName(), true );
1124    }
1125 
1126    /**
1127     * Gets a Java method parameter name of a dependency.
1128     *
1129     * @param dependency The dependency to get the Java method parameter name of.
1130     *
1131     * @return The Java method parameter name of {@code dependency}.
1132     *
1133     * @throws NullPointerException if {@code dependency} is {@code null}.
1134     * @throws ModelObjectException if compiling the name of the dependency to a {@code JavaIdentifier} fails.
1135     *
1136     * @see Dependency#getJavaVariableName()
1137     *
1138     * @since 1.2
1139     *
1140     * @deprecated As of JOMC 1.4, please use method {@link Dependency#getJavaVariableName()}. This method will be
1141     * removed in JOMC 2.0.
1142     */
1143    @Deprecated
1144    public String getJavaMethodParameterName( final Dependency dependency ) throws ModelObjectException
1145    {
1146        if ( dependency == null )
1147        {
1148            throw new NullPointerException( "dependency" );
1149        }
1150 
1151        return this.getJavaMethodParameterName( dependency.getName() );
1152    }
1153 
1154    /**
1155     * Gets a Java field name of a dependency.
1156     *
1157     * @param dependency The dependency to get the Java field name of.
1158     *
1159     * @return The Java field name of {@code dependency}.
1160     *
1161     * @throws NullPointerException if {@code dependency} is {@code null}.
1162     * @throws ModelObjectException if compiling the name of the dependency to a {@code JavaIdentifier} fails.
1163     *
1164     * @see Dependency#getJavaVariableName()
1165     *
1166     * @since 1.3
1167     *
1168     * @deprecated As of JOMC 1.4, please use method {@link Dependency#getJavaVariableName()}. This method will be
1169     * removed in JOMC 2.0.
1170     */
1171    @Deprecated
1172    public String getJavaFieldName( final Dependency dependency ) throws ModelObjectException
1173    {
1174        if ( dependency == null )
1175        {
1176            throw new NullPointerException( "dependency" );
1177        }
1178 
1179        return this.getJavaFieldName( dependency.getName() );
1180    }
1181 
1182    /**
1183     * Gets the name of a Java getter method of a given message.
1184     *
1185     * @param message The message to get a Java getter method name of.
1186     *
1187     * @return The Java getter method name of {@code message}.
1188     *
1189     * @throws NullPointerException if {@code message} is {@code null}.
1190     * @throws ModelObjectException if compiling the name of the message to a {@code JavaIdentifier} fails.
1191     *
1192     * @see Message#getJavaGetterMethodName()
1193     *
1194     * @deprecated As of JOMC 1.4, please use method {@link Message#getJavaGetterMethodName()}. This method will be
1195     * removed in JOMC 2.0.
1196     */
1197    @Deprecated
1198    public String getJavaGetterMethodName( final Message message ) throws ModelObjectException
1199    {
1200        if ( message == null )
1201        {
1202            throw new NullPointerException( "message" );
1203        }
1204 
1205        return "get" + this.getJavaIdentifier( message.getName(), true );
1206    }
1207 
1208    /**
1209     * Gets the name of a Java setter method of a given message.
1210     *
1211     * @param message The message to get a Java setter method name of.
1212     *
1213     * @return The Java setter method name of {@code message}.
1214     *
1215     * @throws NullPointerException if {@code message} is {@code null}.
1216     * @throws ModelObjectException if compiling the name of the message to a {@code JavaIdentifier} fails.
1217     *
1218     * @see Message#getJavaSetterMethodName()
1219     *
1220     * @since 1.2
1221     *
1222     * @deprecated As of JOMC 1.4, please use method {@link Message#getJavaSetterMethodName()}. This method will be
1223     * removed in JOMC 2.0.
1224     */
1225    @Deprecated
1226    public String getJavaSetterMethodName( final Message message ) throws ModelObjectException
1227    {
1228        if ( message == null )
1229        {
1230            throw new NullPointerException( "message" );
1231        }
1232 
1233        return "set" + this.getJavaIdentifier( message.getName(), true );
1234    }
1235 
1236    /**
1237     * Gets a Java method parameter name of a message.
1238     *
1239     * @param message The message to get the Java method parameter name of.
1240     *
1241     * @return The Java method parameter name of {@code message}.
1242     *
1243     * @throws NullPointerException if {@code message} is {@code null}.
1244     * @throws ModelObjectException if compiling the name of the message to a {@code JavaIdentifier} fails.
1245     *
1246     * @see Message#getJavaVariableName()
1247     *
1248     * @since 1.2
1249     *
1250     * @deprecated As of JOMC 1.4, please use method {@link Message#getJavaVariableName()}. This method will be removed
1251     * in JOMC 2.0.
1252     */
1253    @Deprecated
1254    public String getJavaMethodParameterName( final Message message ) throws ModelObjectException
1255    {
1256        if ( message == null )
1257        {
1258            throw new NullPointerException( "message" );
1259        }
1260 
1261        return this.getJavaMethodParameterName( message.getName() );
1262    }
1263 
1264    /**
1265     * Gets a Java field name of a message.
1266     *
1267     * @param message The message to get the Java field name of.
1268     *
1269     * @return The Java field name of {@code message}.
1270     *
1271     * @throws NullPointerException if {@code message} is {@code null}.
1272     * @throws ModelObjectException if compiling the name of the message to a {@code JavaIdentifier} fails.
1273     *
1274     * @see Message#getJavaVariableName()
1275     *
1276     * @since 1.3
1277     *
1278     * @deprecated As of JOMC 1.4, please use method {@link Message#getJavaVariableName()}. This method will be removed
1279     * in JOMC 2.0.
1280     */
1281    @Deprecated
1282    public String getJavaFieldName( final Message message ) throws ModelObjectException
1283    {
1284        if ( message == null )
1285        {
1286            throw new NullPointerException( "message" );
1287        }
1288 
1289        return this.getJavaFieldName( message.getName() );
1290    }
1291 
1292    /**
1293     * Gets the Java modifier name of a dependency of a given implementation.
1294     *
1295     * @param implementation The implementation declaring the dependency to get a Java modifier name of.
1296     * @param dependency The dependency to get a Java modifier name of.
1297     *
1298     * @return The Java modifier name of {@code dependency} of {@code implementation}.
1299     *
1300     * @throws NullPointerException if {@code implementation} or {@code dependency} is {@code null}.
1301     *
1302     * @deprecated As of JOMC 1.4, please use method {@link Modules#getDependencyJavaModifierName(java.lang.String, java.lang.String)}.
1303     * This method will be removed in JOMC 2.0.
1304     */
1305    @Deprecated
1306    public String getJavaModifierName( final Implementation implementation, final Dependency dependency )
1307    {
1308        if ( implementation == null )
1309        {
1310            throw new NullPointerException( "implementation" );
1311        }
1312        if ( dependency == null )
1313        {
1314            throw new NullPointerException( "dependency" );
1315        }
1316 
1317        String modifierName = "private";
1318 
1319        if ( this.getModules() != null )
1320        {
1321            modifierName =
1322                this.getModules().getDependencyJavaModifierName( implementation.getIdentifier(), dependency.getName() );
1323 
1324            if ( modifierName == null )
1325            {
1326                modifierName = "private";
1327            }
1328        }
1329 
1330        return modifierName;
1331    }
1332 
1333    /**
1334     * Gets the Java modifier name of a message of a given implementation.
1335     *
1336     * @param implementation The implementation declaring the message to get a Java modifier name of.
1337     * @param message The message to get a Java modifier name of.
1338     *
1339     * @return The Java modifier name of {@code message} of {@code implementation}.
1340     *
1341     * @throws NullPointerException if {@code implementation} or {@code message} is {@code null}.
1342     *
1343     * @deprecated As of JOMC 1.4, please use method {@link Modules#getMessageJavaModifierName(java.lang.String, java.lang.String)}.
1344     * This method will be removed in JOMC 2.0.
1345     */
1346    @Deprecated
1347    public String getJavaModifierName( final Implementation implementation, final Message message )
1348    {
1349        if ( implementation == null )
1350        {
1351            throw new NullPointerException( "implementation" );
1352        }
1353        if ( message == null )
1354        {
1355            throw new NullPointerException( "message" );
1356        }
1357 
1358        String modifierName = "private";
1359 
1360        if ( this.getModules() != null )
1361        {
1362            modifierName =
1363                this.getModules().getMessageJavaModifierName( implementation.getIdentifier(), message.getName() );
1364 
1365            if ( modifierName == null )
1366            {
1367                modifierName = "private";
1368            }
1369        }
1370 
1371        return modifierName;
1372    }
1373 
1374    /**
1375     * Gets the Java modifier name of a property of a given implementation.
1376     *
1377     * @param implementation The implementation declaring the property to get a Java modifier name of.
1378     * @param property The property to get a Java modifier name of.
1379     *
1380     * @return The Java modifier name of {@code property} of {@code implementation}.
1381     *
1382     * @throws NullPointerException if {@code implementation} or {@code property} is {@code null}.
1383     *
1384     * @deprecated As of JOMC 1.4, please use method {@link Modules#getPropertyJavaModifierName(java.lang.String, java.lang.String)}.
1385     * This method will be removed in JOMC 2.0.
1386     */
1387    @Deprecated
1388    public String getJavaModifierName( final Implementation implementation, final Property property )
1389    {
1390        if ( implementation == null )
1391        {
1392            throw new NullPointerException( "implementation" );
1393        }
1394        if ( property == null )
1395        {
1396            throw new NullPointerException( "property" );
1397        }
1398 
1399        String modifierName = "private";
1400 
1401        if ( this.getModules() != null )
1402        {
1403            modifierName =
1404                this.getModules().getPropertyJavaModifierName( implementation.getIdentifier(), property.getName() );
1405 
1406            if ( modifierName == null )
1407            {
1408                modifierName = "private";
1409            }
1410        }
1411 
1412        return modifierName;
1413    }
1414 
1415    /**
1416     * Formats a text to a Javadoc comment.
1417     *
1418     * @param text The text to format to a Javadoc comment.
1419     * @param indentationLevel The indentation level of the comment.
1420     * @param linePrefix The text to prepend lines with.
1421     *
1422     * @return {@code text} formatted to a Javadoc comment.
1423     *
1424     * @throws NullPointerException if {@code text} or {@code linePrefix} is {@code null}.
1425     * @throws IllegalArgumentException if {@code indentationLevel} is negative.
1426     * @throws ModelObjectException if compiling the type of the text to a {@code MimeType} fails.
1427     *
1428     * @deprecated As of JOMC 1.4, please use method {@link Text#getJavadocComment(java.lang.String, java.lang.String)}.
1429     * This method will be removed in JOMC 2.0.
1430     */
1431    @Deprecated
1432    public String getJavadocComment( final Text text, final int indentationLevel, final String linePrefix )
1433        throws ModelObjectException
1434    {
1435        if ( text == null )
1436        {
1437            throw new NullPointerException( "text" );
1438        }
1439        if ( linePrefix == null )
1440        {
1441            throw new NullPointerException( "linePrefix" );
1442        }
1443        if ( indentationLevel < 0 )
1444        {
1445            throw new IllegalArgumentException( Integer.toString( indentationLevel ) );
1446        }
1447 
1448        BufferedReader reader = null;
1449        boolean suppressExceptionOnClose = true;
1450 
1451        try
1452        {
1453            String javadoc = "";
1454 
1455            if ( text.getValue() != null )
1456            {
1457                final String indent = this.getIndentation( indentationLevel );
1458                reader = new BufferedReader( new StringReader( text.getValue() ) );
1459                final StringBuilder builder = new StringBuilder( text.getValue().length() );
1460 
1461                String line;
1462                while ( ( line = reader.readLine() ) != null )
1463                {
1464                    builder.append( this.getLineSeparator() ).append( indent ).append( linePrefix ).
1465                        append( line.replaceAll( "\\/\\*\\*", "/*" ).replaceAll( "\\*/", "/" ) );
1466 
1467                }
1468 
1469                if ( builder.length() > 0 )
1470                {
1471                    javadoc =
1472                        builder.substring( this.getLineSeparator().length() + indent.length() + linePrefix.length() );
1473 
1474                    if ( !text.getMimeType().match( "text/html" ) )
1475                    {
1476                        javadoc = StringEscapeUtils.escapeHtml( javadoc );
1477                    }
1478                }
1479            }
1480 
1481            suppressExceptionOnClose = false;
1482            return javadoc;
1483        }
1484        catch ( final MimeTypeParseException e )
1485        {
1486            throw new AssertionError( e );
1487        }
1488        catch ( final IOException e )
1489        {
1490            throw new AssertionError( e );
1491        }
1492        finally
1493        {
1494            try
1495            {
1496                if ( reader != null )
1497                {
1498                    reader.close();
1499                }
1500            }
1501            catch ( final IOException e )
1502            {
1503                if ( suppressExceptionOnClose )
1504                {
1505                    this.log( Level.SEVERE, getMessage( e ), e );
1506                }
1507                else
1508                {
1509                    throw new AssertionError( e );
1510                }
1511            }
1512        }
1513    }
1514 
1515    /**
1516     * Formats a text from a list of texts to a Javadoc comment.
1517     *
1518     * @param texts The list of texts to format to a Javadoc comment.
1519     * @param indentationLevel The indentation level of the comment.
1520     * @param linePrefix The text to prepend lines with.
1521     *
1522     * @return The text corresponding to the locale of the instance from the list of texts formatted to a Javadoc
1523     * comment.
1524     *
1525     * @throws NullPointerException if {@code texts} or {@code linePrefix} is {@code null}.
1526     * @throws IllegalArgumentException if {@code indentationLevel} is negative.
1527     * @throws ModelObjectException if compiling a referenced type to a {@code MimeType} fails.
1528     *
1529     * @see #getLocale()
1530     *
1531     * @since 1.2
1532     *
1533     * @deprecated As of JOMC 1.4, please use method {@link Text#getJavadocComment(java.lang.String, java.lang.String)}.
1534     * This method will be removed in JOMC 2.0.
1535     */
1536    @Deprecated
1537    public String getJavadocComment( final Texts texts, final int indentationLevel, final String linePrefix )
1538        throws ModelObjectException
1539    {
1540        if ( texts == null )
1541        {
1542            throw new NullPointerException( "texts" );
1543        }
1544        if ( linePrefix == null )
1545        {
1546            throw new NullPointerException( "linePrefix" );
1547        }
1548        if ( indentationLevel < 0 )
1549        {
1550            throw new IllegalArgumentException( Integer.toString( indentationLevel ) );
1551        }
1552 
1553        return this.getJavadocComment( texts.getText( this.getLocale().getLanguage() ), indentationLevel, linePrefix );
1554    }
1555 
1556    /**
1557     * Formats a string to a Java string with unicode escapes.
1558     *
1559     * @param str The string to format to a Java string or {@code null}.
1560     *
1561     * @return {@code str} formatted to a Java string or {@code null}.
1562     *
1563     * @see StringEscapeUtils#escapeJava(java.lang.String)
1564     */
1565    public String getJavaString( final String str )
1566    {
1567        return StringEscapeUtils.escapeJava( str );
1568    }
1569 
1570    /**
1571     * Formats a string to a Java class path location.
1572     *
1573     * @param str The string to format or {@code null}.
1574     * @param absolute {@code true} to return an absolute class path location; {@code false} to return a relative
1575     * class path location.
1576     *
1577     * @return {@code str} formatted to a Java class path location.
1578     *
1579     * @since 1.3
1580     *
1581     * @deprecated As of JOMC 1.4, please use {@link JavaTypeName#getQualifiedName()}. This method will be removed in
1582     * JOMC 2.0.
1583     */
1584    @Deprecated
1585    public String getJavaClasspathLocation( final String str, final boolean absolute )
1586    {
1587        String classpathLocation = null;
1588 
1589        if ( str != null )
1590        {
1591            classpathLocation = str.replace( '.', '/' );
1592 
1593            if ( absolute )
1594            {
1595                classpathLocation = "/" + classpathLocation;
1596            }
1597        }
1598 
1599        return classpathLocation;
1600    }
1601 
1602    /**
1603     * Formats a string to a Java identifier.
1604     *
1605     * @param str The string to format or {@code null}.
1606     * @param capitalize {@code true}, to return an identifier with the first character upper cased; {@code false}, to
1607     * return an identifier with the first character lower cased.
1608     *
1609     * @return {@code str} formatted to a Java identifier or {@code null}.
1610     *
1611     * @since 1.2
1612     *
1613     * @deprecated As of JOMC 1.4, please use method {@link #toJavaVariableName(java.lang.String)}. This method will be
1614     * removed in JOMC 2.0.
1615     */
1616    @Deprecated
1617    public String getJavaIdentifier( final String str, final boolean capitalize )
1618    {
1619        String identifier = null;
1620 
1621        if ( str != null )
1622        {
1623            final int len = str.length();
1624            final StringBuilder builder = new StringBuilder( len );
1625            boolean uc = capitalize;
1626 
1627            for ( int i = 0; i < len; i++ )
1628            {
1629                final char c = str.charAt( i );
1630                final String charString = Character.toString( c );
1631 
1632                if ( builder.length() > 0 )
1633                {
1634                    if ( Character.isJavaIdentifierPart( c ) )
1635                    {
1636                        builder.append( uc ? charString.toUpperCase( this.getLocale() ) : charString );
1637                        uc = false;
1638                    }
1639                    else
1640                    {
1641                        uc = true;
1642                    }
1643                }
1644                else
1645                {
1646                    if ( Character.isJavaIdentifierStart( c ) )
1647                    {
1648                        builder.append( uc ? charString.toUpperCase( this.getLocale() )
1649                                        : charString.toLowerCase( this.getLocale() ) );
1650 
1651                        uc = false;
1652                    }
1653                    else
1654                    {
1655                        uc = capitalize;
1656                    }
1657                }
1658            }
1659 
1660            identifier = builder.toString();
1661 
1662            if ( identifier.length() <= 0 && this.isLoggable( Level.WARNING ) )
1663            {
1664                this.log( Level.WARNING, getMessage( "invalidJavaIdentifier", str ), null );
1665            }
1666        }
1667 
1668        return identifier;
1669    }
1670 
1671    /**
1672     * Formats a string to a Java method parameter name.
1673     *
1674     * @param str The string to format or {@code null}.
1675     *
1676     * @return {@code str} formatted to a Java method parameter name or {@code null}.
1677     *
1678     * @since 1.3
1679     *
1680     * @deprecated As of JOMC 1.4, please use method {@link #toJavaVariableName(java.lang.String)}. This method will be
1681     * removed in JOMC 2.0.
1682     */
1683    @Deprecated
1684    public String getJavaMethodParameterName( final String str )
1685    {
1686        String methodParameterName = null;
1687 
1688        if ( str != null )
1689        {
1690            final int len = str.length();
1691            final StringBuilder builder = new StringBuilder( len );
1692            boolean uc = false;
1693 
1694            for ( int i = 0; i < len; i++ )
1695            {
1696                final char c = str.charAt( i );
1697                final String charString = Character.toString( c );
1698 
1699                if ( builder.length() > 0 )
1700                {
1701                    if ( Character.isJavaIdentifierPart( c ) )
1702                    {
1703                        builder.append( uc ? charString.toUpperCase( this.getLocale() ) : charString );
1704                        uc = false;
1705                    }
1706                    else
1707                    {
1708                        uc = true;
1709                    }
1710                }
1711                else if ( Character.isJavaIdentifierStart( c ) )
1712                {
1713                    builder.append( charString.toLowerCase( this.getLocale() ) );
1714                }
1715            }
1716 
1717            methodParameterName = builder.toString();
1718 
1719            if ( methodParameterName.length() <= 0 && this.isLoggable( Level.WARNING ) )
1720            {
1721                this.log( Level.WARNING, getMessage( "invalidJavaMethodParameterName", str ), null );
1722            }
1723 
1724            if ( this.getJavaKeywords().contains( methodParameterName ) )
1725            {
1726                methodParameterName = "_" + methodParameterName;
1727            }
1728        }
1729 
1730        return methodParameterName;
1731    }
1732 
1733    /**
1734     * Formats a string to a Java field name.
1735     *
1736     * @param str The string to format or {@code null}.
1737     *
1738     * @return {@code str} formatted to a Java field name or {@code null}.
1739     *
1740     * @since 1.3
1741     *
1742     * @deprecated As of JOMC 1.4, please use method {@link #toJavaVariableName(java.lang.String)}. This method will be
1743     * removed in JOMC 2.0.
1744     */
1745    @Deprecated
1746    public String getJavaFieldName( final String str )
1747    {
1748        String fieldName = null;
1749 
1750        if ( str != null )
1751        {
1752            final int len = str.length();
1753            final StringBuilder builder = new StringBuilder( len );
1754            boolean uc = false;
1755 
1756            for ( int i = 0; i < len; i++ )
1757            {
1758                final char c = str.charAt( i );
1759                final String charString = Character.toString( c );
1760 
1761                if ( builder.length() > 0 )
1762                {
1763                    if ( Character.isJavaIdentifierPart( c ) )
1764                    {
1765                        builder.append( uc ? charString.toUpperCase( this.getLocale() ) : charString );
1766                        uc = false;
1767                    }
1768                    else
1769                    {
1770                        uc = true;
1771                    }
1772                }
1773                else if ( Character.isJavaIdentifierStart( c ) )
1774                {
1775                    builder.append( charString.toLowerCase( this.getLocale() ) );
1776                }
1777            }
1778 
1779            fieldName = builder.toString();
1780 
1781            if ( fieldName.length() <= 0 && this.isLoggable( Level.WARNING ) )
1782            {
1783                this.log( Level.WARNING, getMessage( "invalidJavaFieldName", str ), null );
1784            }
1785 
1786            if ( this.getJavaKeywords().contains( fieldName ) )
1787            {
1788                fieldName = "_" + fieldName;
1789            }
1790        }
1791 
1792        return fieldName;
1793    }
1794 
1795    /**
1796     * Formats a string to a Java constant name.
1797     *
1798     * @param str The string to format or {@code null}.
1799     *
1800     * @return {@code str} formatted to a Java constant name or {@code null}.
1801     *
1802     * @since 1.3
1803     *
1804     * @deprecated As of JOMC 1.4, please use method {@link #toJavaConstantName(java.lang.String)}. This method will be
1805     * removed in JOMC 2.0.
1806     */
1807    @Deprecated
1808    public String getJavaConstantName( final String str )
1809    {
1810        String name = null;
1811 
1812        if ( str != null )
1813        {
1814            final int len = str.length();
1815            final StringBuilder builder = new StringBuilder( len );
1816            boolean separator = false;
1817 
1818            for ( int i = 0; i < len; i++ )
1819            {
1820                final char c = str.charAt( i );
1821 
1822                if ( builder.length() > 0 ? Character.isJavaIdentifierPart( c ) : Character.isJavaIdentifierStart( c ) )
1823                {
1824                    if ( builder.length() > 0 )
1825                    {
1826                        if ( !separator )
1827                        {
1828                            final char previous = builder.charAt( builder.length() - 1 );
1829                            separator = Character.isLowerCase( previous ) && Character.isUpperCase( c );
1830                        }
1831 
1832                        if ( separator )
1833                        {
1834                            builder.append( '_' );
1835                        }
1836                    }
1837 
1838                    builder.append( c );
1839                    separator = false;
1840                }
1841                else
1842                {
1843                    separator = true;
1844                }
1845            }
1846 
1847            name = builder.toString().toUpperCase( this.getLocale() );
1848 
1849            if ( name.length() <= 0 && this.isLoggable( Level.WARNING ) )
1850            {
1851                this.log( Level.WARNING, getMessage( "invalidJavaConstantName", str ), null );
1852            }
1853        }
1854 
1855        return name;
1856    }
1857 
1858    /**
1859     * Compiles a string to a Java constant name.
1860     *
1861     * @param str The string to compile or {@code null}.
1862     *
1863     * @return {@code str} compiled to a {@code JavaIdentifier} or {@code null}, if {@code str} is {@code null}.
1864     *
1865     * @throws ParseException if compiling {@code str} to a {@code JavaIdentifier} fails.
1866     *
1867     * @since 1.3
1868     *
1869     * @see JavaIdentifier#normalize(java.lang.String, org.jomc.model.JavaIdentifier.NormalizationMode)
1870     * @see org.jomc.model.JavaIdentifier.NormalizationMode#CONSTANT_NAME_CONVENTION
1871     */
1872    public JavaIdentifier toJavaConstantName( final String str ) throws ParseException
1873    {
1874        JavaIdentifier constantName = null;
1875 
1876        if ( str != null )
1877        {
1878            constantName = JavaIdentifier.normalize( str, JavaIdentifier.NormalizationMode.CONSTANT_NAME_CONVENTION );
1879        }
1880 
1881        return constantName;
1882    }
1883 
1884    /**
1885     * Compiles a string to a Java method name.
1886     *
1887     * @param str The string to compile or {@code null}.
1888     *
1889     * @return {@code str} compiled to a {@code JavaIdentifier} or {@code null}, if {@code str} is {@code null}.
1890     *
1891     * @throws ParseException if compiling {@code str} to a {@code JavaIdentifier} fails.
1892     *
1893     * @since 1.4
1894     *
1895     * @see JavaIdentifier#normalize(java.lang.String, org.jomc.model.JavaIdentifier.NormalizationMode)
1896     * @see org.jomc.model.JavaIdentifier.NormalizationMode#METHOD_NAME_CONVENTION
1897     */
1898    public JavaIdentifier toJavaMethodName( final String str ) throws ParseException
1899    {
1900        JavaIdentifier variableName = null;
1901 
1902        if ( str != null )
1903        {
1904            variableName =
1905                JavaIdentifier.normalize( str, JavaIdentifier.NormalizationMode.METHOD_NAME_CONVENTION );
1906 
1907        }
1908 
1909        return variableName;
1910    }
1911 
1912    /**
1913     * Compiles a string to a Java variable name.
1914     *
1915     * @param str The string to compile or {@code null}.
1916     *
1917     * @return {@code str} compiled to a {@code JavaIdentifier} or {@code null}, if {@code str} is {@code null}.
1918     *
1919     * @throws ParseException if compiling {@code str} to a {@code JavaIdentifier} fails.
1920     *
1921     * @since 1.4
1922     *
1923     * @see JavaIdentifier#normalize(java.lang.String, org.jomc.model.JavaIdentifier.NormalizationMode)
1924     * @see org.jomc.model.JavaIdentifier.NormalizationMode#VARIABLE_NAME_CONVENTION
1925     */
1926    public JavaIdentifier toJavaVariableName( final String str ) throws ParseException
1927    {
1928        JavaIdentifier variableName = null;
1929 
1930        if ( str != null )
1931        {
1932            variableName =
1933                JavaIdentifier.normalize( str, JavaIdentifier.NormalizationMode.VARIABLE_NAME_CONVENTION );
1934 
1935        }
1936 
1937        return variableName;
1938    }
1939 
1940    /**
1941     * Gets a flag indicating the type referenced by a given specification is located in an unnamed Java package.
1942     *
1943     * @param specification The specification to query.
1944     *
1945     * @return {@code true}, if the type referenced by {@code specification} is located in an unnamed Java package;
1946     * {@code false}, if the specification does not reference a type or if the referenced type is not located in an
1947     * unnamed Java package.
1948     *
1949     * @throws NullPointerException if {@code specification} is {@code null}.
1950     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
1951     *
1952     * @see Specification#getJavaTypeName()
1953     * @see JavaTypeName#isUnnamedPackage()
1954     *
1955     * @deprecated As of JOMC 1.4, please use method {@link Specification#getJavaTypeName()}. This method will be
1956     * removed in JOMC 2.0.
1957     */
1958    @Deprecated
1959    public boolean isJavaDefaultPackage( final Specification specification ) throws ModelObjectException
1960    {
1961        if ( specification == null )
1962        {
1963            throw new NullPointerException( "specification" );
1964        }
1965 
1966        final JavaTypeName javaTypeName = specification.getJavaTypeName();
1967        return javaTypeName != null && javaTypeName.isUnnamedPackage();
1968    }
1969 
1970    /**
1971     * Gets a flag indicating the type referenced by a given implementation is located in an unnamed Java package.
1972     *
1973     * @param implementation The implementation to query.
1974     *
1975     * @return {@code true}, if the type referenced by {@code implementation} is located in an unnamed Java package;
1976     * {@code false}, if the implementation does not reference a type or if the referenced type is not located in an
1977     * unnamed Java package.
1978     *
1979     * @throws NullPointerException if {@code implementation} is {@code null}.
1980     * @throws ModelObjectException if compiling the name of the referenced type to a {@code JavaTypeName} fails.
1981     *
1982     * @see Implementation#getJavaTypeName()
1983     * @see JavaTypeName#isUnnamedPackage()
1984     *
1985     * @deprecated As of JOMC 1.4, please use method {@link Implementation#getJavaTypeName()}. This method will be
1986     * removed in JOMC 2.0.
1987     */
1988    @Deprecated
1989    public boolean isJavaDefaultPackage( final Implementation implementation ) throws ModelObjectException
1990    {
1991        if ( implementation == null )
1992        {
1993            throw new NullPointerException( "implementation" );
1994        }
1995 
1996        final JavaTypeName javaTypeName = implementation.getJavaTypeName();
1997        return javaTypeName != null && javaTypeName.isUnnamedPackage();
1998    }
1999 
2000    /**
2001     * Formats a string to a HTML string with HTML entities.
2002     *
2003     * @param str The string to format to a HTML string with HTML entities or {@code null}.
2004     *
2005     * @return {@code str} formatted to a HTML string with HTML entities or {@code null}.
2006     *
2007     * @since 1.2
2008     */
2009    public String getHtmlString( final String str )
2010    {
2011        return str != null ? str.replace( "&", "&amp;" ).replace( "<", "&lt;" ).replace( ">", "&gt;" ).
2012            replace( "\"", "&quot;" ).replace( "*", "&lowast;" ) : null;
2013 
2014    }
2015 
2016    /**
2017     * Formats a string to a XML string with XML entities.
2018     *
2019     * @param str The string to format to a XML string with XML entities or {@code null}.
2020     *
2021     * @return {@code str} formatted to a XML string with XML entities or {@code null}.
2022     *
2023     * @see StringEscapeUtils#escapeXml(java.lang.String)
2024     *
2025     * @since 1.2
2026     */
2027    public String getXmlString( final String str )
2028    {
2029        return StringEscapeUtils.escapeXml( str );
2030    }
2031 
2032    /**
2033     * Formats a string to a JavaScript string applying JavaScript string rules.
2034     *
2035     * @param str The string to format to a JavaScript string by applying JavaScript string rules or {@code null}.
2036     *
2037     * @return {@code str} formatted to a JavaScript string with JavaScript string rules applied or {@code null}.
2038     *
2039     * @see StringEscapeUtils#escapeJavaScript(java.lang.String)
2040     *
2041     * @since 1.2
2042     */
2043    public String getJavaScriptString( final String str )
2044    {
2045        return StringEscapeUtils.escapeJavaScript( str );
2046    }
2047 
2048    /**
2049     * Formats a string to a SQL string.
2050     *
2051     * @param str The string to format to a SQL string or {@code null}.
2052     *
2053     * @return {@code str} formatted to a SQL string or {@code null}.
2054     *
2055     * @see StringEscapeUtils#escapeSql(java.lang.String)
2056     *
2057     * @since 1.2
2058     */
2059    public String getSqlString( final String str )
2060    {
2061        return StringEscapeUtils.escapeSql( str );
2062    }
2063 
2064    /**
2065     * Formats a string to a CSV string.
2066     *
2067     * @param str The string to format to a CSV string or {@code null}.
2068     *
2069     * @return {@code str} formatted to a CSV string or {@code null}.
2070     *
2071     * @see StringEscapeUtils#escapeCsv(java.lang.String)
2072     *
2073     * @since 1.2
2074     */
2075    public String getCsvString( final String str )
2076    {
2077        return StringEscapeUtils.escapeCsv( str );
2078    }
2079 
2080    /**
2081     * Formats a {@code Boolean} to a string.
2082     *
2083     * @param b The {@code Boolean} to format to a string or {@code null}.
2084     *
2085     * @return {@code b} formatted to a string.
2086     *
2087     * @see #getLocale()
2088     *
2089     * @since 1.2
2090     */
2091    public String getBooleanString( final Boolean b )
2092    {
2093        final MessageFormat messageFormat = new MessageFormat( ResourceBundle.getBundle(
2094            JomcTool.class.getName().replace( '.', '/' ), this.getLocale() ).
2095            getString( b ? "booleanStringTrue" : "booleanStringFalse" ), this.getLocale() );
2096 
2097        return messageFormat.format( null );
2098    }
2099 
2100    /**
2101     * Gets the display language of a given language code.
2102     *
2103     * @param language The language code to get the display language of.
2104     *
2105     * @return The display language of {@code language}.
2106     *
2107     * @throws NullPointerException if {@code language} is {@code null}.
2108     */
2109    public String getDisplayLanguage( final String language )
2110    {
2111        if ( language == null )
2112        {
2113            throw new NullPointerException( "language" );
2114        }
2115 
2116        final Locale l = new Locale( language );
2117        return l.getDisplayLanguage( l );
2118    }
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 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 getShortDate( final Calendar calendar )
2132    {
2133        if ( calendar == null )
2134        {
2135            throw new NullPointerException( "calendar" );
2136        }
2137 
2138        return DateFormat.getDateInstance( DateFormat.SHORT, this.getLocale() ).format( calendar.getTime() );
2139    }
2140 
2141    /**
2142     * Formats a calendar instance to a string.
2143     *
2144     * @param calendar The calendar to format to a string.
2145     *
2146     * @return The date of {@code calendar} formatted using a medium format style pattern.
2147     *
2148     * @throws NullPointerException if {@code calendar} is {@code null}.
2149     *
2150     * @see DateFormat#MEDIUM
2151     *
2152     * @since 1.2
2153     */
2154    public String getMediumDate( final Calendar calendar )
2155    {
2156        if ( calendar == null )
2157        {
2158            throw new NullPointerException( "calendar" );
2159        }
2160 
2161        return DateFormat.getDateInstance( DateFormat.MEDIUM, this.getLocale() ).format( calendar.getTime() );
2162    }
2163 
2164    /**
2165     * Formats a calendar instance to a string.
2166     *
2167     * @param calendar The calendar to format to a string.
2168     *
2169     * @return The date of {@code calendar} formatted using a long format style pattern.
2170     *
2171     * @throws NullPointerException if {@code calendar} is {@code null}.
2172     *
2173     * @see DateFormat#LONG
2174     */
2175    public String getLongDate( final Calendar calendar )
2176    {
2177        if ( calendar == null )
2178        {
2179            throw new NullPointerException( "calendar" );
2180        }
2181 
2182        return DateFormat.getDateInstance( DateFormat.LONG, this.getLocale() ).format( calendar.getTime() );
2183    }
2184 
2185    /**
2186     * Formats a calendar instance to a string.
2187     *
2188     * @param calendar The calendar to format to a string.
2189     *
2190     * @return The date of {@code calendar} formatted using an ISO-8601 format style.
2191     *
2192     * @throws NullPointerException if {@code calendar} is {@code null}.
2193     *
2194     * @see SimpleDateFormat yyyy-DDD
2195     *
2196     * @since 1.2
2197     */
2198    public String getIsoDate( final Calendar calendar )
2199    {
2200        if ( calendar == null )
2201        {
2202            throw new NullPointerException( "calendar" );
2203        }
2204 
2205        return new SimpleDateFormat( "yyyy-DDD", this.getLocale() ).format( calendar.getTime() );
2206    }
2207 
2208    /**
2209     * Formats a calendar instance to a string.
2210     *
2211     * @param calendar The calendar to format to a string.
2212     *
2213     * @return The time of {@code calendar} formatted using a short format style pattern.
2214     *
2215     * @throws NullPointerException if {@code calendar} is {@code null}.
2216     *
2217     * @see DateFormat#SHORT
2218     */
2219    public String getShortTime( final Calendar calendar )
2220    {
2221        if ( calendar == null )
2222        {
2223            throw new NullPointerException( "calendar" );
2224        }
2225 
2226        return DateFormat.getTimeInstance( DateFormat.SHORT, this.getLocale() ).format( calendar.getTime() );
2227    }
2228 
2229    /**
2230     * Formats a calendar instance to a string.
2231     *
2232     * @param calendar The calendar to format to a string.
2233     *
2234     * @return The time of {@code calendar} formatted using a medium format style pattern.
2235     *
2236     * @throws NullPointerException if {@code calendar} is {@code null}.
2237     *
2238     * @see DateFormat#MEDIUM
2239     *
2240     * @since 1.2
2241     */
2242    public String getMediumTime( final Calendar calendar )
2243    {
2244        if ( calendar == null )
2245        {
2246            throw new NullPointerException( "calendar" );
2247        }
2248 
2249        return DateFormat.getTimeInstance( DateFormat.MEDIUM, this.getLocale() ).format( calendar.getTime() );
2250    }
2251 
2252    /**
2253     * Formats a calendar instance to a string.
2254     *
2255     * @param calendar The calendar to format to a string.
2256     *
2257     * @return The time of {@code calendar} formatted using a long format style pattern.
2258     *
2259     * @throws NullPointerException if {@code calendar} is {@code null}.
2260     *
2261     * @see DateFormat#LONG
2262     */
2263    public String getLongTime( final Calendar calendar )
2264    {
2265        if ( calendar == null )
2266        {
2267            throw new NullPointerException( "calendar" );
2268        }
2269 
2270        return DateFormat.getTimeInstance( DateFormat.LONG, this.getLocale() ).format( calendar.getTime() );
2271    }
2272 
2273    /**
2274     * Formats a calendar instance to a string.
2275     *
2276     * @param calendar The calendar to format to a string.
2277     *
2278     * @return The time of {@code calendar} formatted using an ISO-8601 format style.
2279     *
2280     * @throws NullPointerException if {@code calendar} is {@code null}.
2281     *
2282     * @see SimpleDateFormat HH:mm
2283     *
2284     * @since 1.2
2285     */
2286    public String getIsoTime( final Calendar calendar )
2287    {
2288        if ( calendar == null )
2289        {
2290            throw new NullPointerException( "calendar" );
2291        }
2292 
2293        return new SimpleDateFormat( "HH:mm", this.getLocale() ).format( calendar.getTime() );
2294    }
2295 
2296    /**
2297     * Formats a calendar instance to a string.
2298     *
2299     * @param calendar The calendar to format to a string.
2300     *
2301     * @return The date and time of {@code calendar} formatted using a short format style pattern.
2302     *
2303     * @throws NullPointerException if {@code calendar} is {@code null}.
2304     *
2305     * @see DateFormat#SHORT
2306     */
2307    public String getShortDateTime( final Calendar calendar )
2308    {
2309        if ( calendar == null )
2310        {
2311            throw new NullPointerException( "calendar" );
2312        }
2313 
2314        return DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT, this.getLocale() ).
2315            format( calendar.getTime() );
2316 
2317    }
2318 
2319    /**
2320     * Formats a calendar instance to a string.
2321     *
2322     * @param calendar The calendar to format to a string.
2323     *
2324     * @return The date and time of {@code calendar} formatted using a medium format style pattern.
2325     *
2326     * @throws NullPointerException if {@code calendar} is {@code null}.
2327     *
2328     * @see DateFormat#MEDIUM
2329     *
2330     * @since 1.2
2331     */
2332    public String getMediumDateTime( final Calendar calendar )
2333    {
2334        if ( calendar == null )
2335        {
2336            throw new NullPointerException( "calendar" );
2337        }
2338 
2339        return DateFormat.getDateTimeInstance( DateFormat.MEDIUM, DateFormat.MEDIUM, this.getLocale() ).
2340            format( calendar.getTime() );
2341 
2342    }
2343 
2344    /**
2345     * Formats a calendar instance to a string.
2346     *
2347     * @param calendar The calendar to format to a string.
2348     *
2349     * @return The date and time of {@code calendar} formatted using a long format style pattern.
2350     *
2351     * @throws NullPointerException if {@code calendar} is {@code null}.
2352     *
2353     * @see DateFormat#LONG
2354     */
2355    public String getLongDateTime( final Calendar calendar )
2356    {
2357        if ( calendar == null )
2358        {
2359            throw new NullPointerException( "calendar" );
2360        }
2361 
2362        return DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG, this.getLocale() ).
2363            format( calendar.getTime() );
2364 
2365    }
2366 
2367    /**
2368     * Formats a calendar instance to a string.
2369     *
2370     * @param calendar The calendar to format to a string.
2371     *
2372     * @return The date and time of {@code calendar} formatted using a ISO-8601 format style.
2373     *
2374     * @throws NullPointerException if {@code calendar} is {@code null}.
2375     *
2376     * @see SimpleDateFormat yyyy-MM-dd'T'HH:mm:ssZ
2377     *
2378     * @since 1.2
2379     */
2380    public String getIsoDateTime( final Calendar calendar )
2381    {
2382        if ( calendar == null )
2383        {
2384            throw new NullPointerException( "calendar" );
2385        }
2386 
2387        // JDK: As of JDK 7, "yyyy-MM-dd'T'HH:mm:ssXXX".
2388        return new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ", this.getLocale() ).format( calendar.getTime() );
2389    }
2390 
2391    /**
2392     * Gets a string describing the range of years for given calendars.
2393     *
2394     * @param start The start of the range.
2395     * @param end The end of the range.
2396     *
2397     * @return Formatted range of the years of {@code start} and {@code end} (e.g. {@code "start - end"}).
2398     *
2399     * @throws NullPointerException if {@code start} or {@code end} is {@code null}.
2400     */
2401    public String getYears( final Calendar start, final Calendar end )
2402    {
2403        if ( start == null )
2404        {
2405            throw new NullPointerException( "start" );
2406        }
2407        if ( end == null )
2408        {
2409            throw new NullPointerException( "end" );
2410        }
2411 
2412        final Format yearFormat = new SimpleDateFormat( "yyyy", this.getLocale() );
2413        final int s = start.get( Calendar.YEAR );
2414        final int e = end.get( Calendar.YEAR );
2415        final StringBuilder years = new StringBuilder();
2416 
2417        if ( s != e )
2418        {
2419            if ( s < e )
2420            {
2421                years.append( yearFormat.format( start.getTime() ) ).append( " - " ).
2422                    append( yearFormat.format( end.getTime() ) );
2423 
2424            }
2425            else
2426            {
2427                years.append( yearFormat.format( end.getTime() ) ).append( " - " ).
2428                    append( yearFormat.format( start.getTime() ) );
2429 
2430            }
2431        }
2432        else
2433        {
2434            years.append( yearFormat.format( start.getTime() ) );
2435        }
2436 
2437        return years.toString();
2438    }
2439 
2440    /**
2441     * Gets the model of the instance.
2442     *
2443     * @return The model of the instance.
2444     *
2445     * @see #getModules()
2446     * @see #setModel(org.jomc.modlet.Model)
2447     */
2448    public final Model getModel()
2449    {
2450        if ( this.model == null )
2451        {
2452            this.model = new Model();
2453            this.model.setIdentifier( ModelObject.MODEL_PUBLIC_ID );
2454        }
2455 
2456        return this.model;
2457    }
2458 
2459    /**
2460     * Sets the model of the instance.
2461     *
2462     * @param value The new model of the instance or {@code null}.
2463     *
2464     * @see #getModel()
2465     */
2466    public final void setModel( final Model value )
2467    {
2468        this.model = value;
2469    }
2470 
2471    /**
2472     * Gets the modules of the model of the instance.
2473     *
2474     * @return The modules of the model of the instance or {@code null}, if no modules are found.
2475     *
2476     * @see #getModel()
2477     * @see #setModel(org.jomc.modlet.Model)
2478     */
2479    public final Modules getModules()
2480    {
2481        return ModelHelper.getModules( this.getModel() );
2482    }
2483 
2484    /**
2485     * Gets the {@code VelocityEngine} of the instance.
2486     *
2487     * @return The {@code VelocityEngine} of the instance.
2488     *
2489     * @throws IOException if initializing a new velocity engine fails.
2490     *
2491     * @see #setVelocityEngine(org.apache.velocity.app.VelocityEngine)
2492     */
2493    public final VelocityEngine getVelocityEngine() throws IOException
2494    {
2495        if ( this.velocityEngine == null )
2496        {
2497            /** {@code LogChute} logging to the listeners of the tool. */
2498            class JomcLogChute implements LogChute
2499            {
2500 
2501                JomcLogChute()
2502                {
2503                    super();
2504                }
2505 
2506                public void init( final RuntimeServices runtimeServices ) throws Exception
2507                {
2508                }
2509 
2510                public void log( final int level, final String message )
2511                {
2512                    this.log( level, message, null );
2513                }
2514 
2515                public void log( final int level, final String message, final Throwable throwable )
2516                {
2517                    JomcTool.this.log( Level.FINEST, message, throwable );
2518                }
2519 
2520                public boolean isLevelEnabled( final int level )
2521                {
2522                    return isLoggable( Level.FINEST );
2523                }
2524 
2525            }
2526 
2527            final VelocityEngine engine = new VelocityEngine();
2528            engine.setProperty( RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE.toString() );
2529            engine.setProperty( RuntimeConstants.VM_ARGUMENTS_STRICT, Boolean.TRUE.toString() );
2530            engine.setProperty( RuntimeConstants.STRICT_MATH, Boolean.TRUE.toString() );
2531            engine.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new JomcLogChute() );
2532 
2533            engine.setProperty( RuntimeConstants.RESOURCE_LOADER, "class" );
2534            engine.setProperty( "class.resource.loader.class", ClasspathResourceLoader.class.getName() );
2535            engine.setProperty( "class.resource.loader.cache", Boolean.TRUE.toString() );
2536 
2537            if ( this.getTemplateLocation() != null )
2538            {
2539                engine.setProperty( RuntimeConstants.RESOURCE_LOADER, "class,url" );
2540                engine.setProperty( "url.resource.loader.class", URLResourceLoader.class.getName() );
2541                engine.setProperty( "url.resource.loader.cache", Boolean.TRUE.toString() );
2542                engine.setProperty( "url.resource.loader.root", this.getTemplateLocation().toExternalForm() );
2543                engine.setProperty( "url.resource.loader.timeout", Integer.toString( 60000 ) );
2544            }
2545 
2546            this.velocityEngine = engine;
2547            this.defaultVelocityEngine = true;
2548        }
2549 
2550        return this.velocityEngine;
2551    }
2552 
2553    /**
2554     * Sets the {@code VelocityEngine} of the instance.
2555     *
2556     * @param value The new {@code VelocityEngine} of the instance or {@code null}.
2557     *
2558     * @see #getVelocityEngine()
2559     */
2560    public final void setVelocityEngine( final VelocityEngine value )
2561    {
2562        this.velocityEngine = value;
2563        this.defaultVelocityEngine = false;
2564    }
2565 
2566    /**
2567     * Gets a new velocity context used for merging templates.
2568     *
2569     * @return A new velocity context used for merging templates.
2570     *
2571     * @throws IOException if creating a new context instance fails.
2572     *
2573     * @see #getTemplateParameters()
2574     */
2575    public VelocityContext getVelocityContext() throws IOException
2576    {
2577        final Calendar now = Calendar.getInstance();
2578        final VelocityContext ctx =
2579            new VelocityContext( new HashMap<String, Object>( this.getTemplateParameters() ) );
2580 
2581        this.mergeTemplateProfileContextProperties( this.getTemplateProfile(), this.getLocale().getLanguage(), ctx );
2582        this.mergeTemplateProfileContextProperties( this.getTemplateProfile(), null, ctx );
2583 
2584        final Model clonedModel = this.getModel().clone();
2585        final Modules clonedModules = ModelHelper.getModules( clonedModel );
2586        assert clonedModules != null : "Unexpected missing modules for model '" + clonedModel.getIdentifier() + "'.";
2587 
2588        ctx.put( "model", clonedModel );
2589        ctx.put( "modules", clonedModules );
2590        ctx.put( "imodel", new InheritanceModel( clonedModules ) );
2591        ctx.put( "tool", this );
2592        ctx.put( "toolName", this.getClass().getName() );
2593        ctx.put( "toolVersion", getMessage( "projectVersion" ) );
2594        ctx.put( "toolUrl", getMessage( "projectUrl" ) );
2595        ctx.put( "calendar", now.getTime() );
2596 
2597        // JDK: As of JDK 7, "yyyy-MM-dd'T'HH:mm:ss.SSSXXX".
2598        ctx.put( "now",
2599                 new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ", this.getLocale() ).format( now.getTime() ) );
2600 
2601        ctx.put( "year", new SimpleDateFormat( "yyyy", this.getLocale() ).format( now.getTime() ) );
2602        ctx.put( "month", new SimpleDateFormat( "MM", this.getLocale() ).format( now.getTime() ) );
2603        ctx.put( "day", new SimpleDateFormat( "dd", this.getLocale() ).format( now.getTime() ) );
2604        ctx.put( "hour", new SimpleDateFormat( "HH", this.getLocale() ).format( now.getTime() ) );
2605        ctx.put( "minute", new SimpleDateFormat( "mm", this.getLocale() ).format( now.getTime() ) );
2606        ctx.put( "second", new SimpleDateFormat( "ss", this.getLocale() ).format( now.getTime() ) );
2607        ctx.put( "timezone", new SimpleDateFormat( "Z", this.getLocale() ).format( now.getTime() ) );
2608        ctx.put( "shortDate", this.getShortDate( now ) );
2609        ctx.put( "mediumDate", this.getMediumDate( now ) );
2610        ctx.put( "longDate", this.getLongDate( now ) );
2611        ctx.put( "isoDate", this.getIsoDate( now ) );
2612        ctx.put( "shortTime", this.getShortTime( now ) );
2613        ctx.put( "mediumTime", this.getMediumTime( now ) );
2614        ctx.put( "longTime", this.getLongTime( now ) );
2615        ctx.put( "isoTime", this.getIsoTime( now ) );
2616        ctx.put( "shortDateTime", this.getShortDateTime( now ) );
2617        ctx.put( "mediumDateTime", this.getMediumDateTime( now ) );
2618        ctx.put( "longDateTime", this.getLongDateTime( now ) );
2619        ctx.put( "isoDateTime", this.getIsoDateTime( now ) );
2620 
2621        return ctx;
2622    }
2623 
2624    /**
2625     * Gets the template parameters of the instance.
2626     * <p>This accessor method returns a reference to the live map, not a snapshot. Therefore any modification you make
2627     * to the returned map will be present inside the object. This is why there is no {@code set} method for the
2628     * template parameters property.</p>
2629     *
2630     * @return The template parameters of the instance.
2631     *
2632     * @see #getVelocityContext()
2633     *
2634     * @since 1.2
2635     */
2636    public final Map<String, Object> getTemplateParameters()
2637    {
2638        if ( this.templateParameters == null )
2639        {
2640            this.templateParameters = Collections.synchronizedMap( new HashMap<String, Object>() );
2641        }
2642 
2643        return this.templateParameters;
2644    }
2645 
2646    /**
2647     * Gets the location to search for templates in addition to searching the class path.
2648     *
2649     * @return The location to search for templates in addition to searching the class path or {@code null}.
2650     *
2651     * @see #setTemplateLocation(java.net.URL)
2652     *
2653     * @since 1.2
2654     */
2655    public final URL getTemplateLocation()
2656    {
2657        return this.templateLocation;
2658    }
2659 
2660    /**
2661     * Sets the location to search for templates in addition to searching the class path.
2662     *
2663     * @param value The new location to search for templates in addition to searching the class path or {@code null}.
2664     *
2665     * @see #getTemplateLocation()
2666     *
2667     * @since 1.2
2668     */
2669    public final void setTemplateLocation( final URL value )
2670    {
2671        this.templateLocation = value;
2672        this.templateProfileContextPropertiesCache = null;
2673        this.templateProfilePropertiesCache = null;
2674 
2675        if ( this.defaultVelocityEngine )
2676        {
2677            this.setVelocityEngine( null );
2678        }
2679    }
2680 
2681    /**
2682     * Gets the encoding to use for reading templates.
2683     *
2684     * @return The encoding to use for reading templates.
2685     *
2686     * @see #setTemplateEncoding(java.lang.String)
2687     *
2688     * @deprecated As of JOMC 1.3, replaced by method {@link #getDefaultTemplateEncoding()}. This method will be removed
2689     * in JOMC 2.0.
2690     */
2691    @Deprecated
2692    public final String getTemplateEncoding()
2693    {
2694        return this.getDefaultTemplateEncoding();
2695    }
2696 
2697    /**
2698     * Sets the encoding to use for reading templates.
2699     *
2700     * @param value The new encoding to use for reading templates or {@code null}.
2701     *
2702     * @see #getTemplateEncoding()
2703     *
2704     * @deprecated As of JOMC 1.3, replaced by method {@link #setDefaultTemplateEncoding(java.lang.String)}. This method
2705     * will be removed in JOMC 2.0.
2706     */
2707    @Deprecated
2708    public final void setTemplateEncoding( final String value )
2709    {
2710        this.setDefaultTemplateEncoding( value );
2711    }
2712 
2713    /**
2714     * Gets the default encoding used for reading templates.
2715     *
2716     * @return The default encoding used for reading templates.
2717     *
2718     * @see #setDefaultTemplateEncoding(java.lang.String)
2719     *
2720     * @since 1.3
2721     */
2722    public final String getDefaultTemplateEncoding()
2723    {
2724        if ( this.defaultTemplateEncoding == null )
2725        {
2726            this.defaultTemplateEncoding = getMessage( "buildSourceEncoding" );
2727 
2728            if ( this.isLoggable( Level.CONFIG ) )
2729            {
2730                this.log( Level.CONFIG, getMessage( "defaultTemplateEncoding", this.defaultTemplateEncoding ), null );
2731            }
2732        }
2733 
2734        return this.defaultTemplateEncoding;
2735    }
2736 
2737    /**
2738     * Sets the default encoding to use for reading templates.
2739     *
2740     * @param value The new default encoding to use for reading templates or {@code null}.
2741     *
2742     * @see #getDefaultTemplateEncoding()
2743     *
2744     * @since 1.3
2745     */
2746    public final void setDefaultTemplateEncoding( final String value )
2747    {
2748        this.defaultTemplateEncoding = value;
2749        this.templateCache = null;
2750    }
2751 
2752    /**
2753     * Gets the template encoding of a given template profile.
2754     *
2755     * @param tp The template profile to get the template encoding of.
2756     *
2757     * @return The template encoding of the template profile identified by {@code tp} or the default template encoding
2758     * if no such encoding is defined.
2759     *
2760     * @throws NullPointerException if {@code tp} is {@code null}.
2761     *
2762     * @see #getDefaultTemplateEncoding()
2763     *
2764     * @since 1.3
2765     */
2766    public final String getTemplateEncoding( final String tp )
2767    {
2768        if ( tp == null )
2769        {
2770            throw new NullPointerException( "tp" );
2771        }
2772 
2773        String te = null;
2774 
2775        try
2776        {
2777            te = this.getTemplateProfileProperties( tp ).getProperty( TEMPLATE_ENCODING_PROFILE_PROPERTY_NAME );
2778        }
2779        catch ( final IOException e )
2780        {
2781            if ( this.isLoggable( Level.SEVERE ) )
2782            {
2783                this.log( Level.SEVERE, getMessage( e ), e );
2784            }
2785        }
2786 
2787        return te != null ? te : this.getDefaultTemplateEncoding();
2788    }
2789 
2790    /**
2791     * Gets the encoding to use for reading files.
2792     *
2793     * @return The encoding to use for reading files.
2794     *
2795     * @see #setInputEncoding(java.lang.String)
2796     */
2797    public final String getInputEncoding()
2798    {
2799        if ( this.inputEncoding == null )
2800        {
2801            this.inputEncoding = new InputStreamReader( new ByteArrayInputStream( NO_BYTES ) ).getEncoding();
2802 
2803            if ( this.isLoggable( Level.CONFIG ) )
2804            {
2805                this.log( Level.CONFIG, getMessage( "defaultInputEncoding", this.inputEncoding ), null );
2806            }
2807        }
2808 
2809        return this.inputEncoding;
2810    }
2811 
2812    /**
2813     * Sets the encoding to use for reading files.
2814     *
2815     * @param value The new encoding to use for reading files or {@code null}.
2816     *
2817     * @see #getInputEncoding()
2818     */
2819    public final void setInputEncoding( final String value )
2820    {
2821        this.inputEncoding = value;
2822    }
2823 
2824    /**
2825     * Gets the encoding to use for writing files.
2826     *
2827     * @return The encoding to use for writing files.
2828     *
2829     * @see #setOutputEncoding(java.lang.String)
2830     */
2831    public final String getOutputEncoding()
2832    {
2833        if ( this.outputEncoding == null )
2834        {
2835            this.outputEncoding = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
2836 
2837            if ( this.isLoggable( Level.CONFIG ) )
2838            {
2839                this.log( Level.CONFIG, getMessage( "defaultOutputEncoding", this.outputEncoding ), null );
2840            }
2841        }
2842 
2843        return this.outputEncoding;
2844    }
2845 
2846    /**
2847     * Sets the encoding to use for writing files.
2848     *
2849     * @param value The encoding to use for writing files or {@code null}.
2850     *
2851     * @see #getOutputEncoding()
2852     */
2853    public final void setOutputEncoding( final String value )
2854    {
2855        this.outputEncoding = value;
2856    }
2857 
2858    /**
2859     * Gets the default template profile.
2860     * <p>The default template profile is the implicit parent profile of any template profile not specifying a parent
2861     * template profile.</p>
2862     *
2863     * @return The default template profile.
2864     *
2865     * @see #setDefaultTemplateProfile(java.lang.String)
2866     *
2867     * @deprecated The {@code static} modifier of this method and support to setup the default template profile using
2868     * a system property will be removed in version 2.0.
2869     */
2870    @Deprecated
2871    public static String getDefaultTemplateProfile()
2872    {
2873        if ( defaultTemplateProfile == null )
2874        {
2875            defaultTemplateProfile = System.getProperty( "org.jomc.tools.JomcTool.defaultTemplateProfile",
2876                                                         DEFAULT_TEMPLATE_PROFILE );
2877 
2878        }
2879 
2880        return defaultTemplateProfile;
2881    }
2882 
2883    /**
2884     * Sets the default template profile.
2885     *
2886     * @param value The new default template profile or {@code null}.
2887     *
2888     * @see #getDefaultTemplateProfile()
2889     *
2890     * @deprecated The {@code static} modifier of this method will be removed in version 2.0.
2891     */
2892    @Deprecated
2893    public static void setDefaultTemplateProfile( final String value )
2894    {
2895        defaultTemplateProfile = value;
2896    }
2897 
2898    /**
2899     * Gets the template profile of the instance.
2900     *
2901     * @return The template profile of the instance.
2902     *
2903     * @see #getDefaultTemplateProfile()
2904     * @see #setTemplateProfile(java.lang.String)
2905     */
2906    public final String getTemplateProfile()
2907    {
2908        if ( this.templateProfile == null )
2909        {
2910            this.templateProfile = getDefaultTemplateProfile();
2911 
2912            if ( this.isLoggable( Level.CONFIG ) )
2913            {
2914                this.log( Level.CONFIG, getMessage( "defaultTemplateProfile", this.templateProfile ), null );
2915            }
2916        }
2917 
2918        return this.templateProfile;
2919    }
2920 
2921    /**
2922     * Sets the template profile of the instance.
2923     *
2924     * @param value The new template profile of the instance or {@code null}.
2925     *
2926     * @see #getTemplateProfile()
2927     */
2928    public final void setTemplateProfile( final String value )
2929    {
2930        this.templateProfile = value;
2931    }
2932 
2933    /**
2934     * Gets the parent template profile of a given template profile.
2935     *
2936     * @param tp The template profile to get the parent template profile of.
2937     *
2938     * @return The parent template profile of the template profile identified by {@code tp}; the default template
2939     * profile, if no such parent template profile is defined; {@code null}, if {@code tp} denotes the default template
2940     * profile.
2941     *
2942     * @throws NullPointerException if {@code tp} is {@code null}.
2943     *
2944     * @see #getDefaultTemplateProfile()
2945     *
2946     * @since 1.3
2947     */
2948    public final String getParentTemplateProfile( final String tp )
2949    {
2950        if ( tp == null )
2951        {
2952            throw new NullPointerException( "tp" );
2953        }
2954 
2955        String parentTemplateProfile = null;
2956 
2957        try
2958        {
2959            parentTemplateProfile =
2960                this.getTemplateProfileProperties( tp ).getProperty( PARENT_TEMPLATE_PROFILE_PROPERTY_NAME );
2961 
2962        }
2963        catch ( final IOException e )
2964        {
2965            if ( this.isLoggable( Level.SEVERE ) )
2966            {
2967                this.log( Level.SEVERE, getMessage( e ), e );
2968            }
2969        }
2970 
2971        return parentTemplateProfile != null ? parentTemplateProfile
2972               : tp.equals( this.getDefaultTemplateProfile() ) ? null : this.getDefaultTemplateProfile();
2973 
2974    }
2975 
2976    /**
2977     * Gets the indentation string of the instance.
2978     *
2979     * @return The indentation string of the instance.
2980     *
2981     * @see #setIndentation(java.lang.String)
2982     */
2983    public final String getIndentation()
2984    {
2985        if ( this.indentation == null )
2986        {
2987            this.indentation = "    ";
2988 
2989            if ( this.isLoggable( Level.CONFIG ) )
2990            {
2991                this.log( Level.CONFIG, getMessage( "defaultIndentation",
2992                                                    StringEscapeUtils.escapeJava( this.indentation ) ), null );
2993 
2994            }
2995        }
2996 
2997        return this.indentation;
2998    }
2999 
3000    /**
3001     * Gets an indentation string for a given indentation level.
3002     *
3003     * @param level The indentation level to get an indentation string for.
3004     *
3005     * @return The indentation string for {@code level}.
3006     *
3007     * @throws IllegalArgumentException if {@code level} is negative.
3008     *
3009     * @see #getIndentation()
3010     */
3011    public final String getIndentation( final int level )
3012    {
3013        if ( level < 0 )
3014        {
3015            throw new IllegalArgumentException( Integer.toString( level ) );
3016        }
3017 
3018        Map<String, String> map = this.indentationCache == null ? null : this.indentationCache.get();
3019 
3020        if ( map == null )
3021        {
3022            map = new ConcurrentHashMap<String, String>( 8 );
3023            this.indentationCache = new SoftReference<Map<String, String>>( map );
3024        }
3025 
3026        final String key = this.getIndentation() + "|" + level;
3027        String idt = map.get( key );
3028 
3029        if ( idt == null )
3030        {
3031            final StringBuilder b = new StringBuilder( this.getIndentation().length() * level );
3032 
3033            for ( int i = level; i > 0; i-- )
3034            {
3035                b.append( this.getIndentation() );
3036            }
3037 
3038            idt = b.toString();
3039            map.put( key, idt );
3040        }
3041 
3042        return idt;
3043    }
3044 
3045    /**
3046     * Sets the indentation string of the instance.
3047     *
3048     * @param value The new indentation string of the instance or {@code null}.
3049     *
3050     * @see #getIndentation()
3051     */
3052    public final void setIndentation( final String value )
3053    {
3054        this.indentation = value;
3055    }
3056 
3057    /**
3058     * Gets the line separator of the instance.
3059     *
3060     * @return The line separator of the instance.
3061     *
3062     * @see #setLineSeparator(java.lang.String)
3063     */
3064    public final String getLineSeparator()
3065    {
3066        if ( this.lineSeparator == null )
3067        {
3068            this.lineSeparator = System.getProperty( "line.separator", "\n" );
3069 
3070            if ( this.isLoggable( Level.CONFIG ) )
3071            {
3072                this.log( Level.CONFIG, getMessage( "defaultLineSeparator",
3073                                                    StringEscapeUtils.escapeJava( this.lineSeparator ) ), null );
3074 
3075            }
3076        }
3077 
3078        return this.lineSeparator;
3079    }
3080 
3081    /**
3082     * Sets the line separator of the instance.
3083     *
3084     * @param value The new line separator of the instance or {@code null}.
3085     *
3086     * @see #getLineSeparator()
3087     */
3088    public final void setLineSeparator( final String value )
3089    {
3090        this.lineSeparator = value;
3091    }
3092 
3093    /**
3094     * Gets the locale of the instance.
3095     *
3096     * @return The locale of the instance.
3097     *
3098     * @see #setLocale(java.util.Locale)
3099     *
3100     * @since 1.2
3101     */
3102    public final Locale getLocale()
3103    {
3104        if ( this.locale == null )
3105        {
3106            this.locale = Locale.ENGLISH;
3107 
3108            if ( this.isLoggable( Level.CONFIG ) )
3109            {
3110                this.log( Level.CONFIG, getMessage( "defaultLocale", this.locale ), null );
3111            }
3112        }
3113 
3114        return this.locale;
3115    }
3116 
3117    /**
3118     * Sets the locale of the instance.
3119     *
3120     * @param value The new locale of the instance or {@code null}.
3121     *
3122     * @see #getLocale()
3123     *
3124     * @since 1.2
3125     */
3126    public final void setLocale( final Locale value )
3127    {
3128        this.locale = value;
3129    }
3130 
3131    /**
3132     * Gets a velocity template for a given name.
3133     * <p>This method searches templates at the following locations recursively in the shown order stopping whenever
3134     * a matching template is found.
3135     * <ol>
3136     *  <li><code>org/jomc/tools/templates/{@link #getTemplateProfile() profile}/{@link #getLocale() language}/<i>templateName</i></code></li>
3137     *  <li><code>org/jomc/tools/templates/{@link #getParentTemplateProfile(java.lang.String) parent profile}/{@link #getLocale() language}/<i>templateName</i></code></li>
3138     *  <li><code>org/jomc/tools/templates/{@link #getTemplateProfile() profile}/<i>templateName</i></code></li>
3139     *  <li><code>org/jomc/tools/templates/{@link #getParentTemplateProfile(java.lang.String) parent profile}/{@link #getLocale() language}/<i>templateName</i></code></li>
3140     * </ol></p>
3141     *
3142     * @param templateName The name of the template to get.
3143     *
3144     * @return The template matching {@code templateName}.
3145     *
3146     * @throws NullPointerException if {@code templateName} is {@code null}.
3147     * @throws FileNotFoundException if no such template is found.
3148     * @throws IOException if getting the template fails.
3149     *
3150     * @see #getTemplateProfile()
3151     * @see #getParentTemplateProfile(java.lang.String)
3152     * @see #getLocale()
3153     * @see #getTemplateEncoding(java.lang.String)
3154     * @see #getVelocityEngine()
3155     */
3156    public Template getVelocityTemplate( final String templateName ) throws FileNotFoundException, IOException
3157    {
3158        if ( templateName == null )
3159        {
3160            throw new NullPointerException( "templateName" );
3161        }
3162 
3163        return this.getVelocityTemplate( this.getTemplateProfile(), templateName );
3164    }
3165 
3166    /**
3167     * Notifies registered listeners.
3168     *
3169     * @param level The level of the event.
3170     * @param message The message of the event or {@code null}.
3171     * @param throwable The throwable of the event or {@code null}.
3172     *
3173     * @throws NullPointerException if {@code level} is {@code null}.
3174     *
3175     * @see #getListeners()
3176     * @see #isLoggable(java.util.logging.Level)
3177     */
3178    public void log( final Level level, final String message, final Throwable throwable )
3179    {
3180        if ( level == null )
3181        {
3182            throw new NullPointerException( "level" );
3183        }
3184 
3185        if ( this.isLoggable( level ) )
3186        {
3187            for ( int i = this.getListeners().size() - 1; i >= 0; i-- )
3188            {
3189                this.getListeners().get( i ).onLog( level, message, throwable );
3190            }
3191        }
3192    }
3193 
3194    private Template findVelocityTemplate( final String location, final String encoding ) throws IOException
3195    {
3196        try
3197        {
3198            return this.getVelocityEngine().getTemplate( location, encoding );
3199        }
3200        catch ( final ResourceNotFoundException e )
3201        {
3202            if ( this.isLoggable( Level.FINER ) )
3203            {
3204                this.log( Level.FINER, getMessage( "templateNotFound", location ), null );
3205            }
3206 
3207            return null;
3208        }
3209        catch ( final ParseErrorException e )
3210        {
3211            String m = getMessage( e );
3212            m = m == null ? "" : " " + m;
3213 
3214            // JDK: As of JDK 6, "new IOException( message, cause )".
3215            throw (IOException) new IOException( getMessage( "invalidTemplate", location, m ) ).initCause( e );
3216        }
3217        catch ( final VelocityException e )
3218        {
3219            String m = getMessage( e );
3220            m = m == null ? "" : " " + m;
3221 
3222            // JDK: As of JDK 6, "new IOException( message, cause )".
3223            throw (IOException) new IOException( getMessage( "velocityException", location, m ) ).initCause( e );
3224        }
3225    }
3226 
3227    private java.util.Properties getTemplateProfileContextProperties( final String profileName, final String language )
3228        throws IOException
3229    {
3230        Map<String, java.util.Properties> map = this.templateProfileContextPropertiesCache == null
3231                                                ? null : this.templateProfileContextPropertiesCache.get();
3232 
3233        if ( map == null )
3234        {
3235            map = new ConcurrentHashMap<String, java.util.Properties>();
3236            this.templateProfileContextPropertiesCache = new SoftReference<Map<String, java.util.Properties>>( map );
3237        }
3238 
3239        final String key = profileName + "|" + language;
3240        java.util.Properties profileProperties = map.get( key );
3241        boolean suppressExceptionOnClose = true;
3242 
3243        if ( profileProperties == null )
3244        {
3245            InputStream in = null;
3246            URL url = null;
3247            profileProperties = new java.util.Properties();
3248 
3249            final String resourceName = TEMPLATE_PREFIX + profileName + ( language == null ? "" : "/" + language )
3250                                        + "/context.properties";
3251 
3252            try
3253            {
3254                url = this.getClass().getResource( "/" + resourceName );
3255 
3256                if ( url != null )
3257                {
3258                    in = url.openStream();
3259 
3260                    if ( this.isLoggable( Level.CONFIG ) )
3261                    {
3262                        this.log( Level.CONFIG, getMessage( "contextPropertiesFound", url.toExternalForm() ), null );
3263                    }
3264 
3265                    profileProperties.load( in );
3266                }
3267                else if ( this.getTemplateLocation() != null )
3268                {
3269                    if ( this.isLoggable( Level.CONFIG ) )
3270                    {
3271                        this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", resourceName ), null );
3272                    }
3273 
3274                    url = new URL( this.getTemplateLocation(), resourceName );
3275                    in = url.openStream();
3276 
3277                    if ( this.isLoggable( Level.CONFIG ) )
3278                    {
3279                        this.log( Level.CONFIG, getMessage( "contextPropertiesFound", url.toExternalForm() ), null );
3280                    }
3281 
3282                    profileProperties.load( in );
3283                }
3284                else if ( this.isLoggable( Level.CONFIG ) )
3285                {
3286                    this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", resourceName ), null );
3287                }
3288 
3289                suppressExceptionOnClose = false;
3290            }
3291            catch ( final FileNotFoundException e )
3292            {
3293                if ( this.isLoggable( Level.CONFIG ) )
3294                {
3295                    this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", url.toExternalForm() ), null );
3296                }
3297            }
3298            finally
3299            {
3300                map.put( key, profileProperties );
3301 
3302                try
3303                {
3304                    if ( in != null )
3305                    {
3306                        in.close();
3307                    }
3308                }
3309                catch ( final IOException e )
3310                {
3311                    if ( suppressExceptionOnClose )
3312                    {
3313                        this.log( Level.SEVERE, getMessage( e ), e );
3314                    }
3315                    else
3316                    {
3317                        throw e;
3318                    }
3319                }
3320            }
3321        }
3322 
3323        return profileProperties;
3324    }
3325 
3326    private void mergeTemplateProfileContextProperties( final String profileName, final String language,
3327                                                        final VelocityContext velocityContext ) throws IOException
3328    {
3329        if ( profileName != null )
3330        {
3331            final java.util.Properties templateProfileProperties =
3332                this.getTemplateProfileContextProperties( profileName, language );
3333 
3334            for ( final Enumeration<?> e = templateProfileProperties.propertyNames(); e.hasMoreElements(); )
3335            {
3336                final String name = e.nextElement().toString();
3337                final String value = templateProfileProperties.getProperty( name );
3338                final String[] values = value.split( "\\|" );
3339 
3340                if ( !velocityContext.containsKey( name ) )
3341                {
3342                    final String className = values[0];
3343 
3344                    try
3345                    {
3346                        if ( values.length > 1 )
3347                        {
3348                            final Class<?> valueClass = Class.forName( className );
3349                            velocityContext.put( name,
3350                                                 valueClass.getConstructor( String.class ).newInstance( values[1] ) );
3351                        }
3352                        else if ( value.contains( "|" ) )
3353                        {
3354                            velocityContext.put( name, Class.forName( values[0] ).newInstance() );
3355                        }
3356                        else
3357                        {
3358                            velocityContext.put( name, value );
3359                        }
3360                    }
3361                    catch ( final InstantiationException ex )
3362                    {
3363                        // JDK: As of JDK 6, "new IOException( message, cause )".
3364                        throw (IOException) new IOException( getMessage(
3365                            "contextPropertiesException", profileName + ( language != null ? ", " + language : "" ) ) ).
3366                            initCause( ex );
3367 
3368                    }
3369                    catch ( final IllegalAccessException ex )
3370                    {
3371                        // JDK: As of JDK 6, "new IOException( message, cause )".
3372                        throw (IOException) new IOException( getMessage(
3373                            "contextPropertiesException", profileName + ( language != null ? ", " + language : "" ) ) ).
3374                            initCause( ex );
3375 
3376                    }
3377                    catch ( final InvocationTargetException ex )
3378                    {
3379                        // JDK: As of JDK 6, "new IOException( message, cause )".
3380                        throw (IOException) new IOException( getMessage(
3381                            "contextPropertiesException", profileName + ( language != null ? ", " + language : "" ) ) ).
3382                            initCause( ex );
3383 
3384                    }
3385                    catch ( final NoSuchMethodException ex )
3386                    {
3387                        // JDK: As of JDK 6, "new IOException( message, cause )".
3388                        throw (IOException) new IOException( getMessage(
3389                            "contextPropertiesException", profileName + ( language != null ? ", " + language : "" ) ) ).
3390                            initCause( ex );
3391 
3392                    }
3393                    catch ( final ClassNotFoundException ex )
3394                    {
3395                        // JDK: As of JDK 6, "new IOException( message, cause )".
3396                        throw (IOException) new IOException( getMessage(
3397                            "contextPropertiesException", profileName + ( language != null ? ", " + language : "" ) ) ).
3398                            initCause( ex );
3399 
3400                    }
3401                }
3402            }
3403 
3404            this.mergeTemplateProfileContextProperties( this.getParentTemplateProfile( profileName ), language,
3405                                                        velocityContext );
3406 
3407        }
3408    }
3409 
3410    private java.util.Properties getTemplateProfileProperties( final String profileName ) throws IOException
3411    {
3412        Map<String, java.util.Properties> map = this.templateProfilePropertiesCache == null
3413                                                ? null : this.templateProfilePropertiesCache.get();
3414 
3415        if ( map == null )
3416        {
3417            map = new ConcurrentHashMap<String, java.util.Properties>();
3418            this.templateProfilePropertiesCache = new SoftReference<Map<String, java.util.Properties>>( map );
3419        }
3420 
3421        java.util.Properties profileProperties = map.get( profileName );
3422        boolean suppressExceptionOnClose = true;
3423 
3424        if ( profileProperties == null )
3425        {
3426            InputStream in = null;
3427            profileProperties = new java.util.Properties();
3428 
3429            final String resourceName = TEMPLATE_PREFIX + profileName + "/profile.properties";
3430            URL url = null;
3431 
3432            try
3433            {
3434                url = this.getClass().getResource( "/" + resourceName );
3435 
3436                if ( url != null )
3437                {
3438                    in = url.openStream();
3439 
3440                    if ( this.isLoggable( Level.CONFIG ) )
3441                    {
3442                        this.log( Level.CONFIG, getMessage( "templateProfilePropertiesFound", url.toExternalForm() ),
3443                                  null );
3444 
3445                    }
3446 
3447                    profileProperties.load( in );
3448                }
3449                else if ( this.getTemplateLocation() != null )
3450                {
3451                    if ( this.isLoggable( Level.CONFIG ) )
3452                    {
3453                        this.log( Level.CONFIG, getMessage( "templateProfilePropertiesNotFound", resourceName ), null );
3454                    }
3455 
3456                    url = new URL( this.getTemplateLocation(), resourceName );
3457                    in = url.openStream();
3458 
3459                    if ( this.isLoggable( Level.CONFIG ) )
3460                    {
3461                        this.log( Level.CONFIG, getMessage( "templateProfilePropertiesFound", url.toExternalForm() ),
3462                                  null );
3463 
3464                    }
3465 
3466                    profileProperties.load( in );
3467                }
3468                else if ( this.isLoggable( Level.CONFIG ) )
3469                {
3470                    this.log( Level.CONFIG, getMessage( "templateProfilePropertiesNotFound", resourceName ), null );
3471                }
3472 
3473                suppressExceptionOnClose = false;
3474            }
3475            catch ( final FileNotFoundException e )
3476            {
3477                if ( this.isLoggable( Level.CONFIG ) )
3478                {
3479                    this.log( Level.CONFIG, getMessage( "templateProfilePropertiesNotFound", url.toExternalForm() ),
3480                              null );
3481 
3482                }
3483            }
3484            finally
3485            {
3486                map.put( profileName, profileProperties );
3487 
3488                try
3489                {
3490                    if ( in != null )
3491                    {
3492                        in.close();
3493                    }
3494                }
3495                catch ( final IOException e )
3496                {
3497                    if ( suppressExceptionOnClose )
3498                    {
3499                        this.log( Level.SEVERE, getMessage( e ), e );
3500                    }
3501                    else
3502                    {
3503                        throw e;
3504                    }
3505                }
3506            }
3507        }
3508 
3509        return profileProperties;
3510    }
3511 
3512    private Set<String> getJavaKeywords()
3513    {
3514        Reader in = null;
3515        Set<String> set = this.javaKeywordsCache == null ? null : this.javaKeywordsCache.get();
3516 
3517        try
3518        {
3519            if ( set == null )
3520            {
3521                in = new InputStreamReader( this.getClass().getResourceAsStream(
3522                    "/" + this.getClass().getPackage().getName().replace( ".", "/" ) + "/JavaKeywords.txt" ), "UTF-8" );
3523 
3524                set = new CopyOnWriteArraySet<String>( IOUtils.readLines( in ) );
3525 
3526                this.javaKeywordsCache = new SoftReference<Set<String>>( set );
3527            }
3528        }
3529        catch ( final IOException e )
3530        {
3531            throw new IllegalStateException( getMessage( e ), e );
3532        }
3533        finally
3534        {
3535            try
3536            {
3537                if ( in != null )
3538                {
3539                    in.close();
3540                }
3541            }
3542            catch ( final IOException e )
3543            {
3544                throw new IllegalStateException( getMessage( e ), e );
3545            }
3546        }
3547 
3548        return set;
3549    }
3550 
3551    private Template getVelocityTemplate( final String tp, final String tn ) throws IOException
3552    {
3553        Template template = null;
3554 
3555        if ( tp != null )
3556        {
3557            final String key = this.getLocale() + "|" + this.getTemplateProfile() + "|"
3558                               + this.getDefaultTemplateProfile() + "|" + tn;
3559 
3560            Map<String, TemplateData> map = this.templateCache == null
3561                                            ? null : this.templateCache.get();
3562 
3563            if ( map == null )
3564            {
3565                map = new ConcurrentHashMap<String, TemplateData>( 32 );
3566                this.templateCache = new SoftReference<Map<String, TemplateData>>( map );
3567            }
3568 
3569            TemplateData templateData = map.get( key );
3570 
3571            if ( templateData == null )
3572            {
3573                templateData = new TemplateData();
3574 
3575                if ( !StringUtils.EMPTY.equals( this.getLocale().getLanguage() ) )
3576                {
3577                    templateData.location = TEMPLATE_PREFIX + tp + "/" + this.getLocale().getLanguage() + "/" + tn;
3578                    templateData.template =
3579                        this.findVelocityTemplate( templateData.location, this.getTemplateEncoding( tp ) );
3580 
3581                }
3582 
3583                if ( templateData.template == null )
3584                {
3585                    templateData.location = TEMPLATE_PREFIX + tp + "/" + tn;
3586                    templateData.template =
3587                        this.findVelocityTemplate( templateData.location, this.getTemplateEncoding( tp ) );
3588 
3589                }
3590 
3591                if ( templateData.template == null )
3592                {
3593                    template = this.getVelocityTemplate( this.getParentTemplateProfile( tp ), tn );
3594 
3595                    if ( template == null )
3596                    {
3597                        map.put( key, new TemplateData() );
3598                        throw new FileNotFoundException( getMessage( "noSuchTemplate", tn ) );
3599                    }
3600                }
3601                else
3602                {
3603                    if ( this.isLoggable( Level.FINER ) )
3604                    {
3605                        this.log( Level.FINER, getMessage( "templateInfo", tn, templateData.location ), null );
3606                    }
3607 
3608                    template = templateData.template;
3609                    map.put( key, templateData );
3610                }
3611            }
3612            else if ( templateData.template == null )
3613            {
3614                throw new FileNotFoundException( getMessage( "noSuchTemplate", tn ) );
3615            }
3616            else
3617            {
3618                if ( this.isLoggable( Level.FINER ) )
3619                {
3620                    this.log( Level.FINER, getMessage( "templateInfo", tn, templateData.location ), null );
3621                }
3622 
3623                template = templateData.template;
3624            }
3625        }
3626 
3627        return template;
3628    }
3629 
3630    private static String getMessage( final String key, final Object... arguments )
3631    {
3632        return MessageFormat.format( ResourceBundle.getBundle(
3633            JomcTool.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
3634 
3635    }
3636 
3637    private static String getMessage( final Throwable t )
3638    {
3639        return t != null
3640               ? t.getMessage() != null && t.getMessage().trim().length() > 0
3641                 ? t.getMessage()
3642                 : getMessage( t.getCause() )
3643               : null;
3644 
3645    }
3646 
3647    /** @since 1.3 */
3648    private static class TemplateData
3649    {
3650 
3651        private String location;
3652 
3653        private Template template;
3654 
3655    }
3656 
3657}

[all classes][org.jomc.tools]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov