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

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