EMMA Coverage Report (generated Wed May 23 05:49:57 CEST 2012)
[all classes][org.jomc.tools]

COVERAGE SUMMARY FOR SOURCE FILE [JomcTool.java]

nameclass, %method, %block, %line, %
JomcTool.java100% (3/3)93%  (98/105)79%  (2690/3405)81%  (525.1/648)

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)93%  (91/98)79%  (2659/3369)81%  (512.1/634)
getCsvString (String): String 0%   (0/1)0%   (0/3)0%   (0/1)
getJavaScriptString (String): String 0%   (0/1)0%   (0/3)0%   (0/1)
getMessage (Throwable): String 0%   (0/1)0%   (0/14)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)
setTemplateLocation (URL): void 0%   (0/1)0%   (0/13)0%   (0/5)
getJavaTypeName (SpecificationReference, boolean): String 100% (1/1)17%  (7/42)40%  (2/5)
getJavaTypeName (Property, boolean): String 100% (1/1)18%  (16/90)16%  (3.7/23)
findVelocityTemplate (String): Template 100% (1/1)27%  (26/98)38%  (5/13)
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)
getModules (): Modules 100% (1/1)50%  (8/16)60%  (3/5)
getTemplateProfileProperties (String, String): Properties 100% (1/1)53%  (141/266)54%  (22.5/42)
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)
mergeTemplateProfileProperties (String, String, VelocityContext): void 100% (1/1)59%  (70/119)54%  (14/26)
getJavaPackageName (SpecificationReference): String 100% (1/1)61%  (25/41)86%  (4.3/5)
getJavaKeywords (): Set 100% (1/1)64%  (57/89)56%  (8.4/15)
getJavaMethodParameterName (String): String 100% (1/1)67%  (66/99)82%  (17.2/21)
getVelocityEngine (): VelocityEngine 100% (1/1)69%  (55/80)72%  (13/18)
getJavadocComment (Text, int, String): String 100% (1/1)69%  (111/161)69%  (22.7/33)
getJavaIdentifier (String, boolean): String 100% (1/1)69%  (67/97)81%  (17/21)
getJavaPackageName (String): String 100% (1/1)76%  (16/21)75%  (3/4)
getJavaTypeName (Argument): String 100% (1/1)82%  (23/28)75%  (6/8)
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)
isJavaPrimitiveType (Property): boolean 100% (1/1)90%  (19/21)95%  (2.8/3)
<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)97%  (2.9/3)
getJavaPackageName (Specification): String 100% (1/1)94%  (16/17)97%  (2.9/3)
isJavaDefaultPackage (Implementation): boolean 100% (1/1)95%  (18/19)97%  (2.9/3)
isJavaDefaultPackage (Specification): boolean 100% (1/1)95%  (18/19)97%  (2.9/3)
getJavaClasspathLocation (Implementation): String 100% (1/1)95%  (19/20)97%  (2.9/3)
getJavaClasspathLocation (Specification): String 100% (1/1)95%  (19/20)97%  (2.9/3)
getVelocityContext (): VelocityContext 100% (1/1)95%  (294/309)99%  (38.8/39)
getJavaTypeName (Dependency): String 100% (1/1)96%  (46/48)90%  (9/10)
getJavaTypeName (Implementation, boolean): String 100% (1/1)96%  (51/53)90%  (9/10)
getJavaTypeName (Specification, boolean): String 100% (1/1)96%  (51/53)90%  (9/10)
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)
getDefaultTemplateProfile (): String 100% (1/1)100% (8/8)100% (3/3)
getDisplayLanguage (String): String 100% (1/1)100% (16/16)100% (4/4)
getHtmlString (String): String 100% (1/1)100% (3/3)100% (1/1)
getImplementedJavaTypeNames (Implementation, boolean): List 100% (1/1)100% (62/62)100% (12/12)
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)
getJavaGetterMethodName (Dependency): String 100% (1/1)100% (20/20)100% (3/3)
getJavaGetterMethodName (Message): String 100% (1/1)100% (20/20)100% (3/3)
getJavaInterfaceNames (Implementation, boolean): List 100% (1/1)100% (12/12)100% (3/3)
getJavaMethodParameterName (Argument): String 100% (1/1)100% (12/12)100% (3/3)
getJavaModifierName (Implementation, Dependency): String 100% (1/1)100% (16/16)100% (5/5)
getJavaModifierName (Implementation, Message): String 100% (1/1)100% (16/16)100% (5/5)
getJavaModifierName (Implementation, Property): String 100% (1/1)100% (33/33)100% (9/9)
getJavaString (String): String 100% (1/1)100% (3/3)100% (1/1)
getJavadocComment (Texts, int, String): String 100% (1/1)100% (32/32)100% (7/7)
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)
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% (29/29)100% (5/5)
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% (215/215)100% (31/31)
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)
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)
setTemplateEncoding (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)
     
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)

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 4539 2012-05-23 03:04:49Z schulte2005 $
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.SimpleDateFormat;
51import java.util.ArrayList;
52import java.util.Calendar;
53import java.util.Collections;
54import java.util.Enumeration;
55import java.util.HashMap;
56import java.util.List;
57import java.util.Locale;
58import java.util.Map;
59import java.util.ResourceBundle;
60import java.util.Set;
61import java.util.concurrent.ConcurrentHashMap;
62import java.util.concurrent.CopyOnWriteArrayList;
63import java.util.concurrent.CopyOnWriteArraySet;
64import java.util.logging.Level;
65import javax.activation.MimeType;
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.ArgumentType;
83import org.jomc.model.Dependency;
84import org.jomc.model.Implementation;
85import org.jomc.model.InheritanceModel;
86import org.jomc.model.Message;
87import org.jomc.model.ModelObject;
88import org.jomc.model.Modules;
89import org.jomc.model.Multiplicity;
90import org.jomc.model.Properties;
91import org.jomc.model.Property;
92import org.jomc.model.Specification;
93import org.jomc.model.SpecificationReference;
94import org.jomc.model.Specifications;
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:schulte2005@users.sourceforge.net">Christian Schulte</a>
104 * @version $JOMC: JomcTool.java 4539 2012-05-23 03:04:49Z schulte2005 $
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    /** The default template profile. */
151    private static volatile String defaultTemplateProfile;
152 
153    /**
154     * The log level events are logged at by default.
155     * @see #getDefaultLogLevel()
156     */
157    private static final Level DEFAULT_LOG_LEVEL = Level.WARNING;
158 
159    /** The default log level. */
160    private static volatile Level defaultLogLevel;
161 
162    /** The model of the instance. */
163    private Model model;
164 
165    /** The {@code VelocityEngine} of the instance. */
166    private VelocityEngine velocityEngine;
167 
168    /**
169     * Flag indicating the default {@code VelocityEngine}.
170     * @since 1.2.4
171     */
172    private boolean defaultVelocityEngine;
173 
174    /** The encoding to use for reading templates. */
175    private String templateEncoding;
176 
177    /**
178     * The location to search for templates in addition to searching the class path.
179     * @since 1.2
180     */
181    private URL templateLocation;
182 
183    /** The encoding to use for reading files. */
184    private String inputEncoding;
185 
186    /** The encoding to use for writing files. */
187    private String outputEncoding;
188 
189    /**
190     * The template parameters.
191     * @since 1.2
192     */
193    private Map<String, Object> templateParameters;
194 
195    /** The template profile of the instance. */
196    private String templateProfile;
197 
198    /** The indentation string of the instance. */
199    private String indentation;
200 
201    /** The line separator of the instance. */
202    private String lineSeparator;
203 
204    /** The listeners of the instance. */
205    private List<Listener> listeners;
206 
207    /** The log level of the instance. */
208    private Level logLevel;
209 
210    /**
211     * The locale of the instance.
212     * @since 1.2
213     */
214    private Locale locale;
215 
216    /** Cached indentation strings. */
217    private volatile Reference<Map<String, String>> indentationCache;
218 
219    /** Cached template locations. */
220    private volatile Reference<Map<String, String>> templateLocationsCache;
221 
222    /** Cached template profile properties. */
223    private volatile Reference<Map<String, java.util.Properties>> templateProfilePropertiesCache;
224 
225    /** Cached Java keywords. */
226    private volatile Reference<Set<String>> javaKeywordsCache;
227 
228    /** Creates a new {@code JomcTool} instance. */
229    public JomcTool()
230    {
231        super();
232    }
233 
234    /**
235     * Creates a new {@code JomcTool} instance taking a {@code JomcTool} instance to initialize the new instance with.
236     *
237     * @param tool The instance to initialize the new instance with.
238     *
239     * @throws NullPointerException if {@code tool} is {@code null}.
240     * @throws IOException if copying {@code tool} fails.
241     */
242    public JomcTool( final JomcTool tool ) throws IOException
243    {
244        this();
245 
246        if ( tool == null )
247        {
248            throw new NullPointerException( "tool" );
249        }
250 
251        this.indentation = tool.indentation;
252        this.inputEncoding = tool.inputEncoding;
253        this.lineSeparator = tool.lineSeparator;
254        this.listeners = tool.listeners != null ? new CopyOnWriteArrayList<Listener>( tool.listeners ) : null;
255        this.logLevel = tool.logLevel;
256        this.model = tool.model != null ? tool.model.clone() : null;
257        this.outputEncoding = tool.outputEncoding;
258        this.templateEncoding = tool.templateEncoding;
259        this.templateProfile = tool.templateProfile;
260        this.velocityEngine = tool.velocityEngine;
261        this.defaultVelocityEngine = tool.defaultVelocityEngine;
262        this.locale = tool.locale;
263        this.templateParameters =
264            tool.templateParameters != null
265            ? Collections.synchronizedMap( new HashMap<String, Object>( tool.templateParameters ) )
266            : null;
267 
268        this.templateLocation =
269            tool.templateLocation != null ? new URL( tool.templateLocation.toExternalForm() ) : null;
270 
271    }
272 
273    /**
274     * Gets the list of registered listeners.
275     * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
276     * to the returned list will be present inside the object. This is why there is no {@code set} method for the
277     * listeners property.</p>
278     *
279     * @return The list of registered listeners.
280     *
281     * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
282     */
283    public List<Listener> getListeners()
284    {
285        if ( this.listeners == null )
286        {
287            this.listeners = new CopyOnWriteArrayList<Listener>();
288        }
289 
290        return this.listeners;
291    }
292 
293    /**
294     * Gets the default log level events are logged at.
295     * <p>The default log level is controlled by system property {@code org.jomc.tools.JomcTool.defaultLogLevel} holding
296     * the log level to log events at by default. If that property is not set, the {@code WARNING} default is
297     * returned.</p>
298     *
299     * @return The log level events are logged at by default.
300     *
301     * @see #getLogLevel()
302     * @see Level#parse(java.lang.String)
303     */
304    public static Level getDefaultLogLevel()
305    {
306        if ( defaultLogLevel == null )
307        {
308            defaultLogLevel = Level.parse( System.getProperty( "org.jomc.tools.JomcTool.defaultLogLevel",
309                                                               DEFAULT_LOG_LEVEL.getName() ) );
310 
311        }
312 
313        return defaultLogLevel;
314    }
315 
316    /**
317     * Sets the default log level events are logged at.
318     *
319     * @param value The new default level events are logged at or {@code null}.
320     *
321     * @see #getDefaultLogLevel()
322     */
323    public static void setDefaultLogLevel( final Level value )
324    {
325        defaultLogLevel = value;
326    }
327 
328    /**
329     * Gets the log level of the instance.
330     *
331     * @return The log level of the instance.
332     *
333     * @see #getDefaultLogLevel()
334     * @see #setLogLevel(java.util.logging.Level)
335     * @see #isLoggable(java.util.logging.Level)
336     */
337    public final Level getLogLevel()
338    {
339        if ( this.logLevel == null )
340        {
341            this.logLevel = getDefaultLogLevel();
342 
343            if ( this.isLoggable( Level.CONFIG ) )
344            {
345                this.log( Level.CONFIG, getMessage( "defaultLogLevelInfo", this.logLevel.getLocalizedName() ), null );
346            }
347        }
348 
349        return this.logLevel;
350    }
351 
352    /**
353     * Sets the log level of the instance.
354     *
355     * @param value The new log level of the instance or {@code null}.
356     *
357     * @see #getLogLevel()
358     * @see #isLoggable(java.util.logging.Level)
359     */
360    public final void setLogLevel( final Level value )
361    {
362        this.logLevel = value;
363    }
364 
365    /**
366     * Checks if a message at a given level is provided to the listeners of the instance.
367     *
368     * @param level The level to test.
369     *
370     * @return {@code true}, if messages at {@code level} are provided to the listeners of the instance;
371     * {@code false}, if messages at {@code level} are not provided to the listeners of the instance.
372     *
373     * @throws NullPointerException if {@code level} is {@code null}.
374     *
375     * @see #getLogLevel()
376     * @see #setLogLevel(java.util.logging.Level)
377     * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
378     */
379    public boolean isLoggable( final Level level )
380    {
381        if ( level == null )
382        {
383            throw new NullPointerException( "level" );
384        }
385 
386        return level.intValue() >= this.getLogLevel().intValue();
387    }
388 
389    /**
390     * Gets the Java package name of a specification.
391     *
392     * @param specification The specification to get the Java package name of.
393     *
394     * @return The Java package name of {@code specification} or {@code null}.
395     *
396     * @throws NullPointerException if {@code specification} is {@code null}.
397     */
398    public String getJavaPackageName( final Specification specification )
399    {
400        if ( specification == null )
401        {
402            throw new NullPointerException( "specification" );
403        }
404 
405        return specification.getClazz() != null ? this.getJavaPackageName( specification.getClazz() ) : null;
406    }
407 
408    /**
409     * Gets the Java type name of a specification.
410     *
411     * @param specification The specification to get the Java type name of.
412     * @param qualified {@code true}, to return the fully qualified type name (with package name prepended);
413     * {@code false}, to return the short type name (without package name prepended).
414     *
415     * @return The Java type name of {@code specification} or {@code null}.
416     *
417     * @throws NullPointerException if {@code specification} is {@code null}.
418     *
419     * @see #getJavaPackageName(org.jomc.model.Specification)
420     */
421    public String getJavaTypeName( final Specification specification, final boolean qualified )
422    {
423        if ( specification == null )
424        {
425            throw new NullPointerException( "specification" );
426        }
427 
428        if ( specification.getClazz() != null )
429        {
430            final StringBuilder typeName = new StringBuilder( specification.getClazz().length() );
431            final String javaPackageName = this.getJavaPackageName( specification );
432 
433            if ( qualified && javaPackageName.length() > 0 )
434            {
435                typeName.append( javaPackageName ).append( '.' );
436            }
437 
438            typeName.append( javaPackageName.length() > 0
439                             ? specification.getClazz().substring( javaPackageName.length() + 1 )
440                             : specification.getClazz() );
441 
442            return typeName.toString();
443        }
444 
445        return null;
446    }
447 
448    /**
449     * Gets the Java class path location of a specification.
450     *
451     * @param specification The specification to return the Java class path location of.
452     *
453     * @return The Java class path location of {@code specification} or {@code null}.
454     *
455     * @throws NullPointerException if {@code specification} is {@code null}.
456     *
457     * @see #getJavaTypeName(org.jomc.model.Specification, boolean)
458     */
459    public String getJavaClasspathLocation( final Specification specification )
460    {
461        if ( specification == null )
462        {
463            throw new NullPointerException( "specification" );
464        }
465 
466        return specification.getClazz() != null
467               ? ( this.getJavaTypeName( specification, true ) ).replace( '.', '/' )
468               : null;
469 
470    }
471 
472    /**
473     * Gets the Java package name of a specification reference.
474     *
475     * @param reference The specification reference to get the Java package name of.
476     *
477     * @return The Java package name of {@code reference} or {@code null}.
478     *
479     * @throws NullPointerException if {@code reference} is {@code null}.
480     *
481     * @see #getJavaPackageName(org.jomc.model.Specification)
482     */
483    public String getJavaPackageName( final SpecificationReference reference )
484    {
485        if ( reference == null )
486        {
487            throw new NullPointerException( "reference" );
488        }
489 
490        final Specification s = this.getModules().getSpecification( reference.getIdentifier() );
491        assert s != null : "Specification '" + reference.getIdentifier() + "' not found.";
492        return s.getClazz() != null ? this.getJavaPackageName( s ) : null;
493    }
494 
495    /**
496     * Gets the name of a Java type of a given specification reference.
497     *
498     * @param reference The specification reference to get a Java type name of.
499     * @param qualified {@code true}, to return the fully qualified type name (with package name prepended);
500     * {@code false}, to return the short type name (without package name prepended).
501     *
502     * @return The Java type name of {@code reference} or {@code null}.
503     *
504     * @throws NullPointerException if {@code reference} is {@code null}.
505     *
506     * @see #getJavaTypeName(org.jomc.model.Specification, boolean)
507     */
508    public String getJavaTypeName( final SpecificationReference reference, final boolean qualified )
509    {
510        if ( reference == null )
511        {
512            throw new NullPointerException( "reference" );
513        }
514 
515        final Specification s = this.getModules().getSpecification( reference.getIdentifier() );
516        assert s != null : "Specification '" + reference.getIdentifier() + "' not found.";
517        return s.getClazz() != null ? this.getJavaTypeName( s, qualified ) : null;
518    }
519 
520    /**
521     * Gets the Java package name of an implementation.
522     *
523     * @param implementation The implementation to get the Java package name of.
524     *
525     * @return The Java package name of {@code implementation} or {@code null}.
526     *
527     * @throws NullPointerException if {@code implementation} is {@code null}.
528     */
529    public String getJavaPackageName( final Implementation implementation )
530    {
531        if ( implementation == null )
532        {
533            throw new NullPointerException( "implementation" );
534        }
535 
536        return implementation.getClazz() != null ? this.getJavaPackageName( implementation.getClazz() ) : null;
537    }
538 
539    /**
540     * Gets the Java type name of an implementation.
541     *
542     * @param implementation The implementation to get the Java type name of.
543     * @param qualified {@code true}, to return the fully qualified type name (with package name prepended);
544     * {@code false}, to return the short type name (without package name prepended).
545     *
546     * @return The Java type name of {@code implementation} or {@code null}.
547     *
548     * @throws NullPointerException if {@code implementation} is {@code null}.
549     *
550     * @see #getJavaPackageName(org.jomc.model.Implementation)
551     */
552    public String getJavaTypeName( final Implementation implementation, final boolean qualified )
553    {
554        if ( implementation == null )
555        {
556            throw new NullPointerException( "implementation" );
557        }
558 
559        if ( implementation.getClazz() != null )
560        {
561            final StringBuilder typeName = new StringBuilder( implementation.getClazz().length() );
562            final String javaPackageName = this.getJavaPackageName( implementation );
563 
564            if ( qualified && javaPackageName.length() > 0 )
565            {
566                typeName.append( javaPackageName ).append( '.' );
567            }
568 
569            typeName.append( javaPackageName.length() > 0
570                             ? implementation.getClazz().substring( javaPackageName.length() + 1 )
571                             : implementation.getClazz() );
572 
573            return typeName.toString();
574        }
575 
576        return null;
577    }
578 
579    /**
580     * Gets the Java class path location of an implementation.
581     *
582     * @param implementation The implementation to return the Java class path location of.
583     *
584     * @return The Java class path location of {@code implementation} or {@code null}.
585     *
586     * @throws NullPointerException if {@code implementation} is {@code null}.
587     */
588    public String getJavaClasspathLocation( final Implementation implementation )
589    {
590        if ( implementation == null )
591        {
592            throw new NullPointerException( "implementation" );
593        }
594 
595        return implementation.getClazz() != null
596               ? ( this.getJavaTypeName( implementation, true ) ).replace( '.', '/' )
597               : null;
598 
599    }
600 
601    /**
602     * Gets a list of names of all Java types an implementation implements.
603     *
604     * @param implementation The implementation to get names of all implemented Java types of.
605     * @param qualified {@code true}, to return the fully qualified type names (with package name prepended);
606     * {@code false}, to return the short type names (without package name prepended).
607     *
608     * @return An unmodifiable list of names of all Java types implemented by {@code implementation}.
609     *
610     * @throws NullPointerException if {@code implementation} is {@code null}.
611     *
612     * @deprecated As of JOMC 1.2, replaced by method {@link #getImplementedJavaTypeNames(org.jomc.model.Implementation, boolean)}.
613     * This method will be removed in version 2.0.
614     */
615    @Deprecated
616    public List<String> getJavaInterfaceNames( final Implementation implementation, final boolean qualified )
617    {
618        if ( implementation == null )
619        {
620            throw new NullPointerException( "implementation" );
621        }
622 
623        return this.getImplementedJavaTypeNames( implementation, qualified );
624    }
625 
626    /**
627     * Gets a list of names of all Java types an implementation implements.
628     *
629     * @param implementation The implementation to get names of all implemented Java types of.
630     * @param qualified {@code true}, to return the fully qualified type names (with package name prepended);
631     * {@code false}, to return the short type names (without package name prepended).
632     *
633     * @return An unmodifiable list of names of all Java types implemented by {@code implementation}.
634     *
635     * @throws NullPointerException if {@code implementation} is {@code null}.
636     *
637     * @since 1.2
638     *
639     * @see #getJavaTypeName(org.jomc.model.Specification, boolean)
640     */
641    public List<String> getImplementedJavaTypeNames( final Implementation implementation, final boolean qualified )
642    {
643        if ( implementation == null )
644        {
645            throw new NullPointerException( "implementation" );
646        }
647 
648        final Specifications specs = this.getModules().getSpecifications( implementation.getIdentifier() );
649        final List<String> col = new ArrayList<String>( specs == null ? 0 : specs.getSpecification().size() );
650 
651        if ( specs != null )
652        {
653            for ( int i = 0, s0 = specs.getSpecification().size(); i < s0; i++ )
654            {
655                final Specification s = specs.getSpecification().get( i );
656 
657                if ( s.getClazz() != null )
658                {
659                    final String typeName = this.getJavaTypeName( s, qualified );
660                    if ( !col.contains( typeName ) )
661                    {
662                        col.add( typeName );
663                    }
664                }
665            }
666        }
667 
668        return Collections.unmodifiableList( col );
669    }
670 
671    /**
672     * Gets the Java type name of an argument.
673     *
674     * @param argument The argument to get the Java type name of.
675     *
676     * @return The Java type name of {@code argument}.
677     *
678     * @throws NullPointerException if {@code argument} is {@code null}.
679     */
680    public String getJavaTypeName( final Argument argument )
681    {
682        if ( argument == null )
683        {
684            throw new NullPointerException( "argument" );
685        }
686 
687        String javaTypeName = "java.lang.String";
688 
689        if ( argument.getType() == ArgumentType.DATE || argument.getType() == ArgumentType.TIME )
690        {
691            javaTypeName = "java.util.Date";
692        }
693        else if ( argument.getType() == ArgumentType.NUMBER )
694        {
695            javaTypeName = "java.lang.Number";
696        }
697 
698        return javaTypeName;
699    }
700 
701    /**
702     * Gets a Java method parameter name of an argument.
703     *
704     * @param argument The argument to get the Java method parameter name of.
705     *
706     * @return The Java method parameter name of {@code argument}.
707     *
708     * @throws NullPointerException if {@code argument} is {@code null}.
709     *
710     * @since 1.2
711     */
712    public String getJavaMethodParameterName( final Argument argument )
713    {
714        if ( argument == null )
715        {
716            throw new NullPointerException( "argument" );
717        }
718 
719        return this.getJavaMethodParameterName( argument.getName() );
720    }
721 
722    /**
723     * Gets the Java type name of a property.
724     *
725     * @param property The property to get the Java type name of.
726     * @param boxify {@code true}, to return the name of the Java wrapper class when the type is a Java primitive type;
727     * {@code false}, to return the exact binary name (unboxed name) of the Java type.
728     *
729     * @return The Java type name of {@code property}.
730     *
731     * @throws NullPointerException if {@code property} is {@code null}.
732     */
733    public String getJavaTypeName( final Property property, final boolean boxify )
734    {
735        if ( property == null )
736        {
737            throw new NullPointerException( "property" );
738        }
739 
740        if ( property.getType() != null )
741        {
742            final String typeName = property.getType();
743 
744            if ( boxify )
745            {
746                if ( Boolean.TYPE.getName().equals( typeName ) )
747                {
748                    return Boolean.class.getName();
749                }
750                if ( Byte.TYPE.getName().equals( typeName ) )
751                {
752                    return Byte.class.getName();
753                }
754                if ( Character.TYPE.getName().equals( typeName ) )
755                {
756                    return Character.class.getName();
757                }
758                if ( Double.TYPE.getName().equals( typeName ) )
759                {
760                    return Double.class.getName();
761                }
762                if ( Float.TYPE.getName().equals( typeName ) )
763                {
764                    return Float.class.getName();
765                }
766                if ( Integer.TYPE.getName().equals( typeName ) )
767                {
768                    return Integer.class.getName();
769                }
770                if ( Long.TYPE.getName().equals( typeName ) )
771                {
772                    return Long.class.getName();
773                }
774                if ( Short.TYPE.getName().equals( typeName ) )
775                {
776                    return Short.class.getName();
777                }
778            }
779 
780            return typeName;
781        }
782 
783        return property.getAny() != null ? Object.class.getName() : String.class.getName();
784    }
785 
786    /**
787     * Gets a flag indicating the type of a given property is a Java primitive.
788     *
789     * @param property The property to query.
790     *
791     * @return {@code true}, if the Java type of {@code property} is primitive; {@code false}, if not.
792     *
793     * @throws NullPointerException if {@code property} is {@code null}.
794     *
795     * @see #getJavaTypeName(org.jomc.model.Property, boolean)
796     */
797    public boolean isJavaPrimitiveType( final Property property )
798    {
799        if ( property == null )
800        {
801            throw new NullPointerException( "property" );
802        }
803 
804        return !this.getJavaTypeName( property, false ).equals( this.getJavaTypeName( property, true ) );
805    }
806 
807    /**
808     * Gets the name of a Java getter method of a given property.
809     *
810     * @param property The property to get a Java getter method name of.
811     *
812     * @return The Java getter method name of {@code property}.
813     *
814     * @throws NullPointerException if {@code property} is {@code null}.
815     *
816     * @see #getJavaIdentifier(java.lang.String, boolean)
817     */
818    public String getJavaGetterMethodName( final Property property )
819    {
820        if ( property == null )
821        {
822            throw new NullPointerException( "property" );
823        }
824 
825        String prefix = "get";
826 
827        final String javaTypeName = this.getJavaTypeName( property, true );
828        if ( Boolean.class.getName().equals( javaTypeName ) )
829        {
830            prefix = "is";
831        }
832 
833        return prefix + this.getJavaIdentifier( property.getName(), true );
834    }
835 
836    /**
837     * Gets the name of a Java setter method of a given property.
838     *
839     * @param property The property to get a Java setter method name of.
840     *
841     * @return The Java setter method name of {@code property}.
842     *
843     * @throws NullPointerException if {@code property} is {@code null}.
844     *
845     * @see #getJavaIdentifier(java.lang.String, boolean)
846     *
847     * @since 1.2
848     */
849    public String getJavaSetterMethodName( final Property property )
850    {
851        if ( property == null )
852        {
853            throw new NullPointerException( "property" );
854        }
855 
856        return "set" + this.getJavaIdentifier( property.getName(), true );
857    }
858 
859    /**
860     * Gets a Java method parameter name of a property.
861     *
862     * @param property The property to get the Java method parameter name of.
863     *
864     * @return The Java method parameter name of {@code property}.
865     *
866     * @throws NullPointerException if {@code property} is {@code null}.
867     *
868     * @since 1.2
869     */
870    public String getJavaMethodParameterName( final Property property )
871    {
872        if ( property == null )
873        {
874            throw new NullPointerException( "property" );
875        }
876 
877        return this.getJavaMethodParameterName( property.getName() );
878    }
879 
880    /**
881     * Gets the name of a Java type of a given dependency.
882     *
883     * @param dependency The dependency to get a dependency Java type name of.
884     *
885     * @return The Java type name of {@code dependency} or {@code null}.
886     *
887     * @throws NullPointerException if {@code dependency} is {@code null}.
888     *
889     * @see #getJavaTypeName(org.jomc.model.Specification, boolean)
890     */
891    public String getJavaTypeName( final Dependency dependency )
892    {
893        if ( dependency == null )
894        {
895            throw new NullPointerException( "dependency" );
896        }
897 
898        final Specification s = this.getModules().getSpecification( dependency.getIdentifier() );
899 
900        if ( s != null && s.getClazz() != null )
901        {
902            final StringBuilder typeName = new StringBuilder( s.getClazz().length() );
903            typeName.append( this.getJavaTypeName( s, true ) );
904            if ( s.getMultiplicity() == Multiplicity.MANY && dependency.getImplementationName() == null )
905            {
906                typeName.append( "[]" );
907            }
908 
909            return typeName.toString();
910        }
911 
912        return null;
913    }
914 
915    /**
916     * Gets the name of a Java getter method of a given dependency.
917     *
918     * @param dependency The dependency to get a Java getter method name of.
919     *
920     * @return The Java getter method name of {@code dependency}.
921     *
922     * @throws NullPointerException if {@code dependency} is {@code null}.
923     *
924     * @see #getJavaIdentifier(java.lang.String, boolean)
925     */
926    public String getJavaGetterMethodName( final Dependency dependency )
927    {
928        if ( dependency == null )
929        {
930            throw new NullPointerException( "dependency" );
931        }
932 
933        return "get" + this.getJavaIdentifier( dependency.getName(), true );
934    }
935 
936    /**
937     * Gets the name of a Java setter method of a given dependency.
938     *
939     * @param dependency The dependency to get a Java setter method name of.
940     *
941     * @return The Java setter method name of {@code dependency}.
942     *
943     * @throws NullPointerException if {@code dependency} is {@code null}.
944     *
945     * @see #getJavaIdentifier(java.lang.String, boolean)
946     *
947     * @since 1.2
948     */
949    public String getJavaSetterMethodName( final Dependency dependency )
950    {
951        if ( dependency == null )
952        {
953            throw new NullPointerException( "dependency" );
954        }
955 
956        return "set" + this.getJavaIdentifier( dependency.getName(), true );
957    }
958 
959    /**
960     * Gets a Java method parameter name of a dependency.
961     *
962     * @param dependency The dependency to get the Java method parameter name of.
963     *
964     * @return The Java method parameter name of {@code dependency}.
965     *
966     * @throws NullPointerException if {@code dependency} is {@code null}.
967     *
968     * @since 1.2
969     */
970    public String getJavaMethodParameterName( final Dependency dependency )
971    {
972        if ( dependency == null )
973        {
974            throw new NullPointerException( "dependency" );
975        }
976 
977        return this.getJavaMethodParameterName( dependency.getName() );
978    }
979 
980    /**
981     * Gets the name of a Java getter method of a given message.
982     *
983     * @param message The message to get a Java getter method name of.
984     *
985     * @return The Java getter method name of {@code message}.
986     *
987     * @throws NullPointerException if {@code message} is {@code null}.
988     *
989     * @see #getJavaIdentifier(java.lang.String, boolean)
990     */
991    public String getJavaGetterMethodName( final Message message )
992    {
993        if ( message == null )
994        {
995            throw new NullPointerException( "message" );
996        }
997 
998        return "get" + this.getJavaIdentifier( message.getName(), true );
999    }
1000 
1001    /**
1002     * Gets the name of a Java setter method of a given message.
1003     *
1004     * @param message The message to get a Java setter method name of.
1005     *
1006     * @return The Java setter method name of {@code message}.
1007     *
1008     * @throws NullPointerException if {@code message} is {@code null}.
1009     *
1010     * @see #getJavaIdentifier(java.lang.String, boolean)
1011     *
1012     * @since 1.2
1013     */
1014    public String getJavaSetterMethodName( final Message message )
1015    {
1016        if ( message == null )
1017        {
1018            throw new NullPointerException( "message" );
1019        }
1020 
1021        return "set" + this.getJavaIdentifier( message.getName(), true );
1022    }
1023 
1024    /**
1025     * Gets a Java method parameter name of a message.
1026     *
1027     * @param message The message to get the Java method parameter name of.
1028     *
1029     * @return The Java method parameter name of {@code message}.
1030     *
1031     * @throws NullPointerException if {@code message} is {@code null}.
1032     *
1033     * @since 1.2
1034     */
1035    public String getJavaMethodParameterName( final Message message )
1036    {
1037        if ( message == null )
1038        {
1039            throw new NullPointerException( "message" );
1040        }
1041 
1042        return this.getJavaMethodParameterName( message.getName() );
1043    }
1044 
1045    /**
1046     * Gets the Java modifier name of a dependency of a given implementation.
1047     *
1048     * @param implementation The implementation declaring the dependency to get a Java modifier name of.
1049     * @param dependency The dependency to get a Java modifier name of.
1050     *
1051     * @return The Java modifier name of {@code dependency} of {@code implementation}.
1052     *
1053     * @throws NullPointerException if {@code implementation} or {@code dependency} is {@code null}.
1054     */
1055    public String getJavaModifierName( final Implementation implementation, final Dependency dependency )
1056    {
1057        if ( implementation == null )
1058        {
1059            throw new NullPointerException( "implementation" );
1060        }
1061        if ( dependency == null )
1062        {
1063            throw new NullPointerException( "dependency" );
1064        }
1065 
1066        return "private";
1067    }
1068 
1069    /**
1070     * Gets the Java modifier name of a message of a given implementation.
1071     *
1072     * @param implementation The implementation declaring the message to get a Java modifier name of.
1073     * @param message The message to get a Java modifier name of.
1074     *
1075     * @return The Java modifier name of {@code message} of {@code implementation}.
1076     *
1077     * @throws NullPointerException if {@code implementation} or {@code message} is {@code null}.
1078     */
1079    public String getJavaModifierName( final Implementation implementation, final Message message )
1080    {
1081        if ( implementation == null )
1082        {
1083            throw new NullPointerException( "implementation" );
1084        }
1085        if ( message == null )
1086        {
1087            throw new NullPointerException( "message" );
1088        }
1089 
1090        return "private";
1091    }
1092 
1093    /**
1094     * Gets the Java modifier name of a property of a given implementation.
1095     *
1096     * @param implementation The implementation declaring the property to get a Java modifier name of.
1097     * @param property The property to get a Java modifier name of.
1098     *
1099     * @return The Java modifier name of {@code property} of {@code implementation}.
1100     *
1101     * @throws NullPointerException if {@code implementation} or {@code property} is {@code null}.
1102     */
1103    public String getJavaModifierName( final Implementation implementation, final Property property )
1104    {
1105        if ( implementation == null )
1106        {
1107            throw new NullPointerException( "implementation" );
1108        }
1109        if ( property == null )
1110        {
1111            throw new NullPointerException( "property" );
1112        }
1113 
1114        String modifier = "private";
1115        final Properties specified = this.getModules().getSpecifiedProperties( implementation.getIdentifier() );
1116 
1117        if ( specified != null && specified.getProperty( property.getName() ) != null )
1118        {
1119            modifier = "public";
1120        }
1121 
1122        return modifier;
1123    }
1124 
1125    /**
1126     * Formats a text to a Javadoc comment.
1127     *
1128     * @param text The text to format to a Javadoc comment.
1129     * @param indentationLevel The indentation level of the comment.
1130     * @param linePrefix The text to prepend lines with.
1131     *
1132     * @return {@code text} formatted to a Javadoc comment.
1133     *
1134     * @throws NullPointerException if {@code text} or {@code linePrefix} is {@code null}.
1135     * @throws IllegalArgumentException if {@code indentationLevel} is negative.
1136     */
1137    public String getJavadocComment( final Text text, final int indentationLevel, final String linePrefix )
1138    {
1139        if ( text == null )
1140        {
1141            throw new NullPointerException( "text" );
1142        }
1143        if ( linePrefix == null )
1144        {
1145            throw new NullPointerException( "linePrefix" );
1146        }
1147        if ( indentationLevel < 0 )
1148        {
1149            throw new IllegalArgumentException( Integer.toString( indentationLevel ) );
1150        }
1151 
1152        BufferedReader reader = null;
1153        boolean suppressExceptionOnClose = true;
1154 
1155        try
1156        {
1157            String javadoc = "";
1158 
1159            if ( text.getValue() != null )
1160            {
1161                final String indent = this.getIndentation( indentationLevel );
1162                reader = new BufferedReader( new StringReader( text.getValue() ) );
1163                final StringBuilder builder = new StringBuilder( text.getValue().length() );
1164 
1165                String line;
1166                while ( ( line = reader.readLine() ) != null )
1167                {
1168                    builder.append( this.getLineSeparator() ).append( indent ).append( linePrefix ).
1169                        append( line.replaceAll( "\\/\\*\\*", "/*" ).replaceAll( "\\*/", "/" ) );
1170 
1171                }
1172 
1173                if ( builder.length() > 0 )
1174                {
1175                    javadoc =
1176                        builder.substring( this.getLineSeparator().length() + indent.length() + linePrefix.length() );
1177 
1178                    if ( !new MimeType( text.getType() ).match( "text/html" ) )
1179                    {
1180                        javadoc = StringEscapeUtils.escapeHtml( javadoc );
1181                    }
1182                }
1183            }
1184 
1185            suppressExceptionOnClose = false;
1186            return javadoc;
1187        }
1188        catch ( final MimeTypeParseException e )
1189        {
1190            throw new AssertionError( e );
1191        }
1192        catch ( final IOException e )
1193        {
1194            throw new AssertionError( e );
1195        }
1196        finally
1197        {
1198            try
1199            {
1200                if ( reader != null )
1201                {
1202                    reader.close();
1203                }
1204            }
1205            catch ( final IOException e )
1206            {
1207                if ( suppressExceptionOnClose )
1208                {
1209                    this.log( Level.SEVERE, getMessage( e ), e );
1210                }
1211                else
1212                {
1213                    throw new AssertionError( e );
1214                }
1215            }
1216        }
1217    }
1218 
1219    /**
1220     * Formats a text from a list of texts to a Javadoc comment.
1221     *
1222     * @param texts The list of texts to format to a Javadoc comment.
1223     * @param indentationLevel The indentation level of the comment.
1224     * @param linePrefix The text to prepend lines with.
1225     *
1226     * @return The text corresponding to the locale of the instance from the list of texts formatted to a Javadoc
1227     * comment.
1228     *
1229     * @throws NullPointerException if {@code texts} or {@code linePrefix} is {@code null}.
1230     * @throws IllegalArgumentException if {@code indentationLevel} is negative.
1231     *
1232     * @see #getLocale()
1233     *
1234     * @since 1.2
1235     */
1236    public String getJavadocComment( final Texts texts, final int indentationLevel, final String linePrefix )
1237    {
1238        if ( texts == null )
1239        {
1240            throw new NullPointerException( "texts" );
1241        }
1242        if ( linePrefix == null )
1243        {
1244            throw new NullPointerException( "linePrefix" );
1245        }
1246        if ( indentationLevel < 0 )
1247        {
1248            throw new IllegalArgumentException( Integer.toString( indentationLevel ) );
1249        }
1250 
1251        return this.getJavadocComment( texts.getText( this.getLocale().getLanguage() ), indentationLevel, linePrefix );
1252    }
1253 
1254    /**
1255     * Formats a string to a Java string with unicode escapes.
1256     *
1257     * @param str The string to format to a Java string or {@code null}.
1258     *
1259     * @return {@code str} formatted to a Java string or {@code null}.
1260     *
1261     * @see StringEscapeUtils#escapeJava(java.lang.String)
1262     */
1263    public String getJavaString( final String str )
1264    {
1265        return StringEscapeUtils.escapeJava( str );
1266    }
1267 
1268    /**
1269     * Formats a string to a Java identifier.
1270     *
1271     * @param str The string to format or {@code null}.
1272     * @param capitalize {@code true}, to return an identifier with the first character upper cased; {@code false}, to
1273     * return an identifier with the first character lower cased.
1274     *
1275     * @return {@code str} formatted to a Java identifier or {@code null}.
1276     *
1277     * @since 1.2
1278     */
1279    public String getJavaIdentifier( final String str, final boolean capitalize )
1280    {
1281        String identifier = null;
1282 
1283        if ( str != null )
1284        {
1285            final int len = str.length();
1286            final StringBuilder builder = new StringBuilder( len );
1287            boolean uc = capitalize;
1288 
1289            for ( int i = 0; i < len; i++ )
1290            {
1291                final char c = str.charAt( i );
1292                final String charString = Character.toString( c );
1293 
1294                if ( builder.length() > 0 )
1295                {
1296                    if ( Character.isJavaIdentifierPart( c ) )
1297                    {
1298                        builder.append( uc ? charString.toUpperCase( this.getLocale() ) : charString );
1299                        uc = false;
1300                    }
1301                    else
1302                    {
1303                        uc = true;
1304                    }
1305                }
1306                else
1307                {
1308                    if ( Character.isJavaIdentifierStart( c ) )
1309                    {
1310                        builder.append( uc ? charString.toUpperCase( this.getLocale() )
1311                                        : charString.toLowerCase( this.getLocale() ) );
1312 
1313                        uc = false;
1314                    }
1315                    else
1316                    {
1317                        uc = capitalize;
1318                    }
1319                }
1320            }
1321 
1322            identifier = builder.toString();
1323 
1324            if ( identifier.length() <= 0 && this.isLoggable( Level.WARNING ) )
1325            {
1326                this.log( Level.WARNING, getMessage( "invalidJavaIdentifier", str ), null );
1327            }
1328        }
1329 
1330        return identifier;
1331    }
1332 
1333    /**
1334     * Formats a string to a Java method parameter name.
1335     *
1336     * @param str The string to format or {@code null}.
1337     *
1338     * @return {@code str} formatted to a Java method parameter name or {@code null}.
1339     *
1340     * @since 1.3
1341     */
1342    private String getJavaMethodParameterName( final String str )
1343    {
1344        String methodParameterName = null;
1345 
1346        if ( str != null )
1347        {
1348            final int len = str.length();
1349            final StringBuilder builder = new StringBuilder( len );
1350            boolean uc = false;
1351 
1352            for ( int i = 0; i < len; i++ )
1353            {
1354                final char c = str.charAt( i );
1355                final String charString = Character.toString( c );
1356 
1357                if ( builder.length() > 0 )
1358                {
1359                    if ( Character.isJavaIdentifierPart( c ) )
1360                    {
1361                        builder.append( uc ? charString.toUpperCase( this.getLocale() ) : charString );
1362                        uc = false;
1363                    }
1364                    else
1365                    {
1366                        uc = true;
1367                    }
1368                }
1369                else if ( Character.isJavaIdentifierStart( c ) )
1370                {
1371                    builder.append( charString.toLowerCase( this.getLocale() ) );
1372                }
1373            }
1374 
1375            methodParameterName = builder.toString();
1376 
1377            if ( methodParameterName.length() <= 0 && this.isLoggable( Level.WARNING ) )
1378            {
1379                this.log( Level.WARNING, getMessage( "invalidJavaMethodParameterName", str ), null );
1380            }
1381 
1382            if ( this.getJavaKeywords().contains( methodParameterName ) )
1383            {
1384                methodParameterName = "_" + methodParameterName;
1385            }
1386        }
1387 
1388        return methodParameterName;
1389    }
1390 
1391    /**
1392     * Gets a flag indicating the class of a given specification is located in the Java default package.
1393     *
1394     * @param specification The specification to query.
1395     *
1396     * @return {@code true}, if the class of {@code specification} is located in the Java default package;
1397     * {@code false}, else.
1398     *
1399     * @throws NullPointerException if {@code specification} is {@code null}.
1400     */
1401    public boolean isJavaDefaultPackage( final Specification specification )
1402    {
1403        if ( specification == null )
1404        {
1405            throw new NullPointerException( "specification" );
1406        }
1407 
1408        return specification.getClazz() != null && this.getJavaPackageName( specification ).length() == 0;
1409    }
1410 
1411    /**
1412     * Gets a flag indicating the class of a given implementation is located in the Java default package.
1413     *
1414     * @param implementation The implementation to query.
1415     *
1416     * @return {@code true}, if the class of {@code implementation} is located in the Java default package;
1417     * {@code false}, else.
1418     *
1419     * @throws NullPointerException if {@code implementation} is {@code null}.
1420     */
1421    public boolean isJavaDefaultPackage( final Implementation implementation )
1422    {
1423        if ( implementation == null )
1424        {
1425            throw new NullPointerException( "implementation" );
1426        }
1427 
1428        return implementation.getClazz() != null && this.getJavaPackageName( implementation ).length() == 0;
1429    }
1430 
1431    /**
1432     * Formats a string to a HTML string with HTML entities.
1433     *
1434     * @param str The string to format to a HTML string with HTML entities or {@code null}.
1435     *
1436     * @return {@code str} formatted to a HTML string with HTML entities or {@code null}.
1437     *
1438     * @see StringEscapeUtils#escapeHtml(java.lang.String)
1439     *
1440     * @since 1.2
1441     */
1442    public String getHtmlString( final String str )
1443    {
1444        return StringEscapeUtils.escapeHtml( str );
1445    }
1446 
1447    /**
1448     * Formats a string to a XML string with XML entities.
1449     *
1450     * @param str The string to format to a XML string with XML entities or {@code null}.
1451     *
1452     * @return {@code str} formatted to a XML string with XML entities or {@code null}.
1453     *
1454     * @see StringEscapeUtils#escapeXml(java.lang.String)
1455     *
1456     * @since 1.2
1457     */
1458    public String getXmlString( final String str )
1459    {
1460        return StringEscapeUtils.escapeXml( str );
1461    }
1462 
1463    /**
1464     * Formats a string to a JavaScript string applying JavaScript string rules.
1465     *
1466     * @param str The string to format to a JavaScript string by applying JavaScript string rules or {@code null}.
1467     *
1468     * @return {@code str} formatted to a JavaScript string with JavaScript string rules applied or {@code null}.
1469     *
1470     * @see StringEscapeUtils#escapeJavaScript(java.lang.String)
1471     *
1472     * @since 1.2
1473     */
1474    public String getJavaScriptString( final String str )
1475    {
1476        return StringEscapeUtils.escapeJavaScript( str );
1477    }
1478 
1479    /**
1480     * Formats a string to a SQL string.
1481     *
1482     * @param str The string to format to a SQL string or {@code null}.
1483     *
1484     * @return {@code str} formatted to a SQL string or {@code null}.
1485     *
1486     * @see StringEscapeUtils#escapeSql(java.lang.String)
1487     *
1488     * @since 1.2
1489     */
1490    public String getSqlString( final String str )
1491    {
1492        return StringEscapeUtils.escapeSql( str );
1493    }
1494 
1495    /**
1496     * Formats a string to a CSV string.
1497     *
1498     * @param str The string to format to a CSV string or {@code null}.
1499     *
1500     * @return {@code str} formatted to a CSV string or {@code null}.
1501     *
1502     * @see StringEscapeUtils#escapeCsv(java.lang.String)
1503     *
1504     * @since 1.2
1505     */
1506    public String getCsvString( final String str )
1507    {
1508        return StringEscapeUtils.escapeCsv( str );
1509    }
1510 
1511    /**
1512     * Formats a {@code Boolean} to a string.
1513     *
1514     * @param b The {@code Boolean} to format to a string or {@code null}.
1515     *
1516     * @return {@code b} formatted to a string.
1517     *
1518     * @see #getLocale()
1519     *
1520     * @since 1.2
1521     */
1522    public String getBooleanString( final Boolean b )
1523    {
1524        final MessageFormat messageFormat = new MessageFormat( ResourceBundle.getBundle(
1525            JomcTool.class.getName().replace( '.', '/' ), this.getLocale() ).
1526            getString( b ? "booleanStringTrue" : "booleanStringFalse" ), this.getLocale() );
1527 
1528        return messageFormat.format( null );
1529    }
1530 
1531    /**
1532     * Gets the display language of a given language code.
1533     *
1534     * @param language The language code to get the display language of.
1535     *
1536     * @return The display language of {@code language}.
1537     *
1538     * @throws NullPointerException if {@code language} is {@code null}.
1539     */
1540    public String getDisplayLanguage( final String language )
1541    {
1542        if ( language == null )
1543        {
1544            throw new NullPointerException( "language" );
1545        }
1546 
1547        final Locale l = new Locale( language );
1548        return l.getDisplayLanguage( l );
1549    }
1550 
1551    /**
1552     * Formats a calendar instance to a string.
1553     *
1554     * @param calendar The calendar to format to a string.
1555     *
1556     * @return The date of {@code calendar} formatted using a short format style pattern.
1557     *
1558     * @throws NullPointerException if {@code calendar} is {@code null}.
1559     *
1560     * @see DateFormat#SHORT
1561     */
1562    public String getShortDate( final Calendar calendar )
1563    {
1564        if ( calendar == null )
1565        {
1566            throw new NullPointerException( "calendar" );
1567        }
1568 
1569        return DateFormat.getDateInstance( DateFormat.SHORT, this.getLocale() ).format( calendar.getTime() );
1570    }
1571 
1572    /**
1573     * Formats a calendar instance to a string.
1574     *
1575     * @param calendar The calendar to format to a string.
1576     *
1577     * @return The date of {@code calendar} formatted using a medium format style pattern.
1578     *
1579     * @throws NullPointerException if {@code calendar} is {@code null}.
1580     *
1581     * @see DateFormat#MEDIUM
1582     *
1583     * @since 1.2
1584     */
1585    public String getMediumDate( final Calendar calendar )
1586    {
1587        if ( calendar == null )
1588        {
1589            throw new NullPointerException( "calendar" );
1590        }
1591 
1592        return DateFormat.getDateInstance( DateFormat.MEDIUM, this.getLocale() ).format( calendar.getTime() );
1593    }
1594 
1595    /**
1596     * Formats a calendar instance to a string.
1597     *
1598     * @param calendar The calendar to format to a string.
1599     *
1600     * @return The date of {@code calendar} formatted using a long format style pattern.
1601     *
1602     * @throws NullPointerException if {@code calendar} is {@code null}.
1603     *
1604     * @see DateFormat#LONG
1605     */
1606    public String getLongDate( final Calendar calendar )
1607    {
1608        if ( calendar == null )
1609        {
1610            throw new NullPointerException( "calendar" );
1611        }
1612 
1613        return DateFormat.getDateInstance( DateFormat.LONG, this.getLocale() ).format( calendar.getTime() );
1614    }
1615 
1616    /**
1617     * Formats a calendar instance to a string.
1618     *
1619     * @param calendar The calendar to format to a string.
1620     *
1621     * @return The date of {@code calendar} formatted using an ISO-8601 format style.
1622     *
1623     * @throws NullPointerException if {@code calendar} is {@code null}.
1624     *
1625     * @see SimpleDateFormat yyyy-DDD
1626     *
1627     * @since 1.2
1628     */
1629    public String getIsoDate( final Calendar calendar )
1630    {
1631        if ( calendar == null )
1632        {
1633            throw new NullPointerException( "calendar" );
1634        }
1635 
1636        return new SimpleDateFormat( "yyyy-DDD", this.getLocale() ).format( calendar.getTime() );
1637    }
1638 
1639    /**
1640     * Formats a calendar instance to a string.
1641     *
1642     * @param calendar The calendar to format to a string.
1643     *
1644     * @return The time of {@code calendar} formatted using a short format style pattern.
1645     *
1646     * @throws NullPointerException if {@code calendar} is {@code null}.
1647     *
1648     * @see DateFormat#SHORT
1649     */
1650    public String getShortTime( final Calendar calendar )
1651    {
1652        if ( calendar == null )
1653        {
1654            throw new NullPointerException( "calendar" );
1655        }
1656 
1657        return DateFormat.getTimeInstance( DateFormat.SHORT, this.getLocale() ).format( calendar.getTime() );
1658    }
1659 
1660    /**
1661     * Formats a calendar instance to a string.
1662     *
1663     * @param calendar The calendar to format to a string.
1664     *
1665     * @return The time of {@code calendar} formatted using a medium format style pattern.
1666     *
1667     * @throws NullPointerException if {@code calendar} is {@code null}.
1668     *
1669     * @see DateFormat#MEDIUM
1670     *
1671     * @since 1.2
1672     */
1673    public String getMediumTime( final Calendar calendar )
1674    {
1675        if ( calendar == null )
1676        {
1677            throw new NullPointerException( "calendar" );
1678        }
1679 
1680        return DateFormat.getTimeInstance( DateFormat.MEDIUM, this.getLocale() ).format( calendar.getTime() );
1681    }
1682 
1683    /**
1684     * Formats a calendar instance to a string.
1685     *
1686     * @param calendar The calendar to format to a string.
1687     *
1688     * @return The time of {@code calendar} formatted using a long format style pattern.
1689     *
1690     * @throws NullPointerException if {@code calendar} is {@code null}.
1691     *
1692     * @see DateFormat#LONG
1693     */
1694    public String getLongTime( final Calendar calendar )
1695    {
1696        if ( calendar == null )
1697        {
1698            throw new NullPointerException( "calendar" );
1699        }
1700 
1701        return DateFormat.getTimeInstance( DateFormat.LONG, this.getLocale() ).format( calendar.getTime() );
1702    }
1703 
1704    /**
1705     * Formats a calendar instance to a string.
1706     *
1707     * @param calendar The calendar to format to a string.
1708     *
1709     * @return The time of {@code calendar} formatted using an ISO-8601 format style.
1710     *
1711     * @throws NullPointerException if {@code calendar} is {@code null}.
1712     *
1713     * @see SimpleDateFormat HH:mm
1714     *
1715     * @since 1.2
1716     */
1717    public String getIsoTime( final Calendar calendar )
1718    {
1719        if ( calendar == null )
1720        {
1721            throw new NullPointerException( "calendar" );
1722        }
1723 
1724        return new SimpleDateFormat( "HH:mm", this.getLocale() ).format( calendar.getTime() );
1725    }
1726 
1727    /**
1728     * Formats a calendar instance to a string.
1729     *
1730     * @param calendar The calendar to format to a string.
1731     *
1732     * @return The date and time of {@code calendar} formatted using a short format style pattern.
1733     *
1734     * @throws NullPointerException if {@code calendar} is {@code null}.
1735     *
1736     * @see DateFormat#SHORT
1737     */
1738    public String getShortDateTime( final Calendar calendar )
1739    {
1740        if ( calendar == null )
1741        {
1742            throw new NullPointerException( "calendar" );
1743        }
1744 
1745        return DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT, this.getLocale() ).
1746            format( calendar.getTime() );
1747 
1748    }
1749 
1750    /**
1751     * Formats a calendar instance to a string.
1752     *
1753     * @param calendar The calendar to format to a string.
1754     *
1755     * @return The date and time of {@code calendar} formatted using a medium format style pattern.
1756     *
1757     * @throws NullPointerException if {@code calendar} is {@code null}.
1758     *
1759     * @see DateFormat#MEDIUM
1760     *
1761     * @since 1.2
1762     */
1763    public String getMediumDateTime( final Calendar calendar )
1764    {
1765        if ( calendar == null )
1766        {
1767            throw new NullPointerException( "calendar" );
1768        }
1769 
1770        return DateFormat.getDateTimeInstance( DateFormat.MEDIUM, DateFormat.MEDIUM, this.getLocale() ).
1771            format( calendar.getTime() );
1772 
1773    }
1774 
1775    /**
1776     * Formats a calendar instance to a string.
1777     *
1778     * @param calendar The calendar to format to a string.
1779     *
1780     * @return The date and time of {@code calendar} formatted using a long format style pattern.
1781     *
1782     * @throws NullPointerException if {@code calendar} is {@code null}.
1783     *
1784     * @see DateFormat#LONG
1785     */
1786    public String getLongDateTime( final Calendar calendar )
1787    {
1788        if ( calendar == null )
1789        {
1790            throw new NullPointerException( "calendar" );
1791        }
1792 
1793        return DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG, this.getLocale() ).
1794            format( calendar.getTime() );
1795 
1796    }
1797 
1798    /**
1799     * Formats a calendar instance to a string.
1800     *
1801     * @param calendar The calendar to format to a string.
1802     *
1803     * @return The date and time of {@code calendar} formatted using a ISO-8601 format style.
1804     *
1805     * @throws NullPointerException if {@code calendar} is {@code null}.
1806     *
1807     * @see SimpleDateFormat yyyy-MM-dd'T'HH:mm:ssZ
1808     *
1809     * @since 1.2
1810     */
1811    public String getIsoDateTime( final Calendar calendar )
1812    {
1813        if ( calendar == null )
1814        {
1815            throw new NullPointerException( "calendar" );
1816        }
1817 
1818        // JDK: As of JDK 7, "yyyy-MM-dd'T'HH:mm:ssXXX".
1819        return new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ", this.getLocale() ).format( calendar.getTime() );
1820    }
1821 
1822    /**
1823     * Gets a string describing the range of years for given calendars.
1824     *
1825     * @param start The start of the range.
1826     * @param end The end of the range.
1827     *
1828     * @return Formatted range of the years of {@code start} and {@code end} (e.g. {@code "start - end"}).
1829     *
1830     * @throws NullPointerException if {@code start} or {@code end} is {@code null}.
1831     */
1832    public String getYears( final Calendar start, final Calendar end )
1833    {
1834        if ( start == null )
1835        {
1836            throw new NullPointerException( "start" );
1837        }
1838        if ( end == null )
1839        {
1840            throw new NullPointerException( "end" );
1841        }
1842 
1843        final Format yearFormat = new SimpleDateFormat( "yyyy", this.getLocale() );
1844        final int s = start.get( Calendar.YEAR );
1845        final int e = end.get( Calendar.YEAR );
1846        final StringBuilder years = new StringBuilder();
1847 
1848        if ( s != e )
1849        {
1850            if ( s < e )
1851            {
1852                years.append( yearFormat.format( start.getTime() ) ).append( " - " ).
1853                    append( yearFormat.format( end.getTime() ) );
1854 
1855            }
1856            else
1857            {
1858                years.append( yearFormat.format( end.getTime() ) ).append( " - " ).
1859                    append( yearFormat.format( start.getTime() ) );
1860 
1861            }
1862        }
1863        else
1864        {
1865            years.append( yearFormat.format( start.getTime() ) );
1866        }
1867 
1868        return years.toString();
1869    }
1870 
1871    /**
1872     * Gets the model of the instance.
1873     *
1874     * @return The model of the instance.
1875     *
1876     * @see #getModules()
1877     * @see #setModel(org.jomc.modlet.Model)
1878     */
1879    public final Model getModel()
1880    {
1881        if ( this.model == null )
1882        {
1883            this.model = new Model();
1884            this.model.setIdentifier( ModelObject.MODEL_PUBLIC_ID );
1885        }
1886 
1887        return this.model;
1888    }
1889 
1890    /**
1891     * Sets the model of the instance.
1892     *
1893     * @param value The new model of the instance or {@code null}.
1894     *
1895     * @see #getModel()
1896     */
1897    public final void setModel( final Model value )
1898    {
1899        this.model = value;
1900    }
1901 
1902    /**
1903     * Gets the modules of the instance.
1904     *
1905     * @return The modules of the instance.
1906     *
1907     * @see #getModel()
1908     * @see #setModel(org.jomc.modlet.Model)
1909     *
1910     * @deprecated As of JOMC 1.2, please use method {@link #getModel()} and {@link ModelHelper#getModules(org.jomc.modlet.Model)}.
1911     * This method will be removed in version 2.0.
1912     */
1913    @Deprecated
1914    public Modules getModules()
1915    {
1916        Modules modules = ModelHelper.getModules( this.getModel() );
1917 
1918        if ( modules == null )
1919        {
1920            modules = new Modules();
1921            ModelHelper.setModules( this.getModel(), modules );
1922        }
1923 
1924        return modules;
1925    }
1926 
1927    /**
1928     * Gets the {@code VelocityEngine} of the instance.
1929     *
1930     * @return The {@code VelocityEngine} of the instance.
1931     *
1932     * @throws IOException if initializing a new velocity engine fails.
1933     *
1934     * @see #setVelocityEngine(org.apache.velocity.app.VelocityEngine)
1935     */
1936    public final VelocityEngine getVelocityEngine() throws IOException
1937    {
1938        if ( this.velocityEngine == null )
1939        {
1940            /** {@code LogChute} logging to the listeners of the tool. */
1941            class JomcLogChute implements LogChute
1942            {
1943 
1944                JomcLogChute()
1945                {
1946                    super();
1947                }
1948 
1949                public void init( final RuntimeServices runtimeServices ) throws Exception
1950                {
1951                }
1952 
1953                public void log( final int level, final String message )
1954                {
1955                    this.log( level, message, null );
1956                }
1957 
1958                public void log( final int level, final String message, final Throwable throwable )
1959                {
1960                    JomcTool.this.log( Level.FINEST, message, throwable );
1961                }
1962 
1963                public boolean isLevelEnabled( final int level )
1964                {
1965                    return isLoggable( Level.FINEST );
1966                }
1967 
1968            }
1969 
1970            final VelocityEngine engine = new VelocityEngine();
1971            engine.setProperty( RuntimeConstants.RUNTIME_REFERENCES_STRICT, Boolean.TRUE.toString() );
1972            engine.setProperty( RuntimeConstants.VM_ARGUMENTS_STRICT, Boolean.TRUE.toString() );
1973            engine.setProperty( RuntimeConstants.STRICT_MATH, Boolean.TRUE.toString() );
1974            engine.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new JomcLogChute() );
1975 
1976            engine.setProperty( RuntimeConstants.RESOURCE_LOADER, "class" );
1977            engine.setProperty( "class.resource.loader.class", ClasspathResourceLoader.class.getName() );
1978            engine.setProperty( "class.resource.loader.cache", Boolean.TRUE.toString() );
1979 
1980            if ( this.getTemplateLocation() != null )
1981            {
1982                engine.setProperty( RuntimeConstants.RESOURCE_LOADER, "class,url" );
1983                engine.setProperty( "url.resource.loader.class", URLResourceLoader.class.getName() );
1984                engine.setProperty( "url.resource.loader.cache", Boolean.TRUE.toString() );
1985                engine.setProperty( "url.resource.loader.root", this.getTemplateLocation().toExternalForm() );
1986                engine.setProperty( "url.resource.loader.timeout", Integer.toString( 60000 ) );
1987            }
1988 
1989            this.velocityEngine = engine;
1990            this.defaultVelocityEngine = true;
1991        }
1992 
1993        return this.velocityEngine;
1994    }
1995 
1996    /**
1997     * Sets the {@code VelocityEngine} of the instance.
1998     *
1999     * @param value The new {@code VelocityEngine} of the instance or {@code null}.
2000     *
2001     * @see #getVelocityEngine()
2002     */
2003    public final void setVelocityEngine( final VelocityEngine value )
2004    {
2005        this.velocityEngine = value;
2006        this.defaultVelocityEngine = false;
2007    }
2008 
2009    /**
2010     * Gets a new velocity context used for merging templates.
2011     *
2012     * @return A new velocity context used for merging templates.
2013     *
2014     * @see #getTemplateParameters()
2015     */
2016    public VelocityContext getVelocityContext()
2017    {
2018        final Calendar now = Calendar.getInstance();
2019        final VelocityContext ctx =
2020            new VelocityContext( new HashMap<String, Object>( this.getTemplateParameters() ) );
2021 
2022        this.mergeTemplateProfileProperties( this.getTemplateProfile(), this.getLocale().getLanguage(), ctx );
2023        this.mergeTemplateProfileProperties( this.getTemplateProfile(), null, ctx );
2024        this.mergeTemplateProfileProperties( getDefaultTemplateProfile(), this.getLocale().getLanguage(), ctx );
2025        this.mergeTemplateProfileProperties( getDefaultTemplateProfile(), null, ctx );
2026 
2027        this.getModules(); // Initialization prior to cloning.
2028        final Model clonedModel = this.getModel().clone();
2029        final Modules clonedModules = ModelHelper.getModules( clonedModel );
2030        assert clonedModules != null : "Unexpected missing modules for model '" + clonedModel.getIdentifier() + "'.";
2031 
2032        ctx.put( "model", clonedModel );
2033        ctx.put( "modules", clonedModules );
2034        ctx.put( "imodel", new InheritanceModel( this.getModules() ) );
2035        ctx.put( "tool", this );
2036        ctx.put( "toolName", this.getClass().getName() );
2037        ctx.put( "toolVersion", getMessage( "projectVersion" ) );
2038        ctx.put( "toolUrl", getMessage( "projectUrl" ) );
2039        ctx.put( "calendar", now.getTime() );
2040 
2041        // JDK: As of JDK 7, "yyyy-MM-dd'T'HH:mm:ss.SSSXXX".
2042        ctx.put( "now",
2043                 new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ", this.getLocale() ).format( now.getTime() ) );
2044 
2045        ctx.put( "year", new SimpleDateFormat( "yyyy", this.getLocale() ).format( now.getTime() ) );
2046        ctx.put( "month", new SimpleDateFormat( "MM", this.getLocale() ).format( now.getTime() ) );
2047        ctx.put( "day", new SimpleDateFormat( "dd", this.getLocale() ).format( now.getTime() ) );
2048        ctx.put( "hour", new SimpleDateFormat( "HH", this.getLocale() ).format( now.getTime() ) );
2049        ctx.put( "minute", new SimpleDateFormat( "mm", this.getLocale() ).format( now.getTime() ) );
2050        ctx.put( "second", new SimpleDateFormat( "ss", this.getLocale() ).format( now.getTime() ) );
2051        ctx.put( "timezone", new SimpleDateFormat( "Z", this.getLocale() ).format( now.getTime() ) );
2052        ctx.put( "shortDate", this.getShortDate( now ) );
2053        ctx.put( "mediumDate", this.getMediumDate( now ) );
2054        ctx.put( "longDate", this.getLongDate( now ) );
2055        ctx.put( "isoDate", this.getIsoDate( now ) );
2056        ctx.put( "shortTime", this.getShortTime( now ) );
2057        ctx.put( "mediumTime", this.getMediumTime( now ) );
2058        ctx.put( "longTime", this.getLongTime( now ) );
2059        ctx.put( "isoTime", this.getIsoTime( now ) );
2060        ctx.put( "shortDateTime", this.getShortDateTime( now ) );
2061        ctx.put( "mediumDateTime", this.getMediumDateTime( now ) );
2062        ctx.put( "longDateTime", this.getLongDateTime( now ) );
2063        ctx.put( "isoDateTime", this.getIsoDateTime( now ) );
2064 
2065        return ctx;
2066    }
2067 
2068    /**
2069     * Gets the template parameters of the instance.
2070     * <p>This accessor method returns a reference to the live map, not a snapshot. Therefore any modification you make
2071     * to the returned map will be present inside the object. This is why there is no {@code set} method for the
2072     * template parameters property.</p>
2073     *
2074     * @return The template parameters of the instance.
2075     *
2076     * @see #getVelocityContext()
2077     *
2078     * @since 1.2
2079     */
2080    public final Map<String, Object> getTemplateParameters()
2081    {
2082        if ( this.templateParameters == null )
2083        {
2084            this.templateParameters = Collections.synchronizedMap( new HashMap<String, Object>() );
2085        }
2086 
2087        return this.templateParameters;
2088    }
2089 
2090    /**
2091     * Gets the location to search for templates in addition to searching the class path.
2092     *
2093     * @return The location to search for templates in addition to searching the class path or {@code null}.
2094     *
2095     * @see #setTemplateLocation(java.net.URL)
2096     *
2097     * @since 1.2
2098     */
2099    public final URL getTemplateLocation()
2100    {
2101        return this.templateLocation;
2102    }
2103 
2104    /**
2105     * Sets the location to search for templates in addition to searching the class path.
2106     *
2107     * @param value The new location to search for templates in addition to searching the class path or {@code null}.
2108     *
2109     * @see #getTemplateLocation()
2110     *
2111     * @since 1.2
2112     */
2113    public final void setTemplateLocation( final URL value )
2114    {
2115        this.templateLocation = value;
2116        this.templateProfilePropertiesCache = null;
2117 
2118        if ( this.defaultVelocityEngine )
2119        {
2120            this.setVelocityEngine( null );
2121        }
2122    }
2123 
2124    /**
2125     * Gets the encoding to use for reading templates.
2126     *
2127     * @return The encoding to use for reading templates.
2128     *
2129     * @see #setTemplateEncoding(java.lang.String)
2130     */
2131    public final String getTemplateEncoding()
2132    {
2133        if ( this.templateEncoding == null )
2134        {
2135            this.templateEncoding = getMessage( "buildSourceEncoding" );
2136 
2137            if ( this.isLoggable( Level.CONFIG ) )
2138            {
2139                this.log( Level.CONFIG, getMessage( "defaultTemplateEncoding", this.templateEncoding ), null );
2140            }
2141        }
2142 
2143        return this.templateEncoding;
2144    }
2145 
2146    /**
2147     * Sets the encoding to use for reading templates.
2148     *
2149     * @param value The new encoding to use for reading templates or {@code null}.
2150     *
2151     * @see #getTemplateEncoding()
2152     */
2153    public final void setTemplateEncoding( final String value )
2154    {
2155        this.templateEncoding = value;
2156    }
2157 
2158    /**
2159     * Gets the encoding to use for reading files.
2160     *
2161     * @return The encoding to use for reading files.
2162     *
2163     * @see #setInputEncoding(java.lang.String)
2164     */
2165    public final String getInputEncoding()
2166    {
2167        if ( this.inputEncoding == null )
2168        {
2169            this.inputEncoding = new InputStreamReader( new ByteArrayInputStream( NO_BYTES ) ).getEncoding();
2170 
2171            if ( this.isLoggable( Level.CONFIG ) )
2172            {
2173                this.log( Level.CONFIG, getMessage( "defaultInputEncoding", this.inputEncoding ), null );
2174            }
2175        }
2176 
2177        return this.inputEncoding;
2178    }
2179 
2180    /**
2181     * Sets the encoding to use for reading files.
2182     *
2183     * @param value The new encoding to use for reading files or {@code null}.
2184     *
2185     * @see #getInputEncoding()
2186     */
2187    public final void setInputEncoding( final String value )
2188    {
2189        this.inputEncoding = value;
2190    }
2191 
2192    /**
2193     * Gets the encoding to use for writing files.
2194     *
2195     * @return The encoding to use for writing files.
2196     *
2197     * @see #setOutputEncoding(java.lang.String)
2198     */
2199    public final String getOutputEncoding()
2200    {
2201        if ( this.outputEncoding == null )
2202        {
2203            this.outputEncoding = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
2204 
2205            if ( this.isLoggable( Level.CONFIG ) )
2206            {
2207                this.log( Level.CONFIG, getMessage( "defaultOutputEncoding", this.outputEncoding ), null );
2208            }
2209        }
2210 
2211        return this.outputEncoding;
2212    }
2213 
2214    /**
2215     * Sets the encoding to use for writing files.
2216     *
2217     * @param value The encoding to use for writing files or {@code null}.
2218     *
2219     * @see #getOutputEncoding()
2220     */
2221    public final void setOutputEncoding( final String value )
2222    {
2223        this.outputEncoding = value;
2224    }
2225 
2226    /**
2227     * Gets the default template profile.
2228     * <p>The default template profile is controlled by system property
2229     * {@code org.jomc.tools.JomcTool.defaultTemplateProfile} holding the name of the template profile to use by
2230     * default. If that property is not set, the {@code jomc-java} default is returned.</p>
2231     *
2232     * @return The default template profile.
2233     *
2234     * @see #setDefaultTemplateProfile(java.lang.String)
2235     *
2236     * @deprecated The {@code static} modifier of this method and support to setup the default template profile using
2237     * a system property will be removed in version 2.0.
2238     */
2239    @Deprecated
2240    public static String getDefaultTemplateProfile()
2241    {
2242        if ( defaultTemplateProfile == null )
2243        {
2244            defaultTemplateProfile = System.getProperty( "org.jomc.tools.JomcTool.defaultTemplateProfile",
2245                                                         DEFAULT_TEMPLATE_PROFILE );
2246 
2247        }
2248 
2249        return defaultTemplateProfile;
2250    }
2251 
2252    /**
2253     * Sets the default template profile.
2254     *
2255     * @param value The new default template profile or {@code null}.
2256     *
2257     * @see #getDefaultTemplateProfile()
2258     *
2259     * @deprecated The {@code static} modifier of this method will be removed in version 2.0.
2260     */
2261    @Deprecated
2262    public static void setDefaultTemplateProfile( final String value )
2263    {
2264        defaultTemplateProfile = value;
2265    }
2266 
2267    /**
2268     * Gets the template profile of the instance.
2269     *
2270     * @return The template profile of the instance.
2271     *
2272     * @see #getDefaultTemplateProfile()
2273     * @see #setTemplateProfile(java.lang.String)
2274     */
2275    public final String getTemplateProfile()
2276    {
2277        if ( this.templateProfile == null )
2278        {
2279            this.templateProfile = getDefaultTemplateProfile();
2280 
2281            if ( this.isLoggable( Level.CONFIG ) )
2282            {
2283                this.log( Level.CONFIG, getMessage( "defaultTemplateProfile", this.templateProfile ), null );
2284            }
2285        }
2286 
2287        return this.templateProfile;
2288    }
2289 
2290    /**
2291     * Sets the template profile of the instance.
2292     *
2293     * @param value The new template profile of the instance or {@code null}.
2294     *
2295     * @see #getTemplateProfile()
2296     */
2297    public final void setTemplateProfile( final String value )
2298    {
2299        this.templateProfile = value;
2300    }
2301 
2302    /**
2303     * Gets the indentation string of the instance.
2304     *
2305     * @return The indentation string of the instance.
2306     *
2307     * @see #setIndentation(java.lang.String)
2308     */
2309    public final String getIndentation()
2310    {
2311        if ( this.indentation == null )
2312        {
2313            this.indentation = "    ";
2314 
2315            if ( this.isLoggable( Level.CONFIG ) )
2316            {
2317                this.log( Level.CONFIG, getMessage( "defaultIndentation",
2318                                                    StringEscapeUtils.escapeJava( this.indentation ) ), null );
2319 
2320            }
2321        }
2322 
2323        return this.indentation;
2324    }
2325 
2326    /**
2327     * Gets an indentation string for a given indentation level.
2328     *
2329     * @param level The indentation level to get an indentation string for.
2330     *
2331     * @return The indentation string for {@code level}.
2332     *
2333     * @throws IllegalArgumentException if {@code level} is negative.
2334     *
2335     * @see #getIndentation()
2336     */
2337    public final String getIndentation( final int level )
2338    {
2339        if ( level < 0 )
2340        {
2341            throw new IllegalArgumentException( Integer.toString( level ) );
2342        }
2343 
2344        Map<String, String> map = this.indentationCache == null ? null : this.indentationCache.get();
2345 
2346        if ( map == null )
2347        {
2348            map = new ConcurrentHashMap<String, String>( 8 );
2349            this.indentationCache = new SoftReference<Map<String, String>>( map );
2350        }
2351 
2352        final String key = this.getIndentation() + "|" + level;
2353        String idt = map.get( key );
2354 
2355        if ( idt == null )
2356        {
2357            final StringBuilder b = new StringBuilder( this.getIndentation().length() * level );
2358 
2359            for ( int i = level; i > 0; i-- )
2360            {
2361                b.append( this.getIndentation() );
2362            }
2363 
2364            idt = b.toString();
2365            map.put( key, idt );
2366        }
2367 
2368        return idt;
2369    }
2370 
2371    /**
2372     * Sets the indentation string of the instance.
2373     *
2374     * @param value The new indentation string of the instance or {@code null}.
2375     *
2376     * @see #getIndentation()
2377     */
2378    public final void setIndentation( final String value )
2379    {
2380        this.indentation = value;
2381    }
2382 
2383    /**
2384     * Gets the line separator of the instance.
2385     *
2386     * @return The line separator of the instance.
2387     *
2388     * @see #setLineSeparator(java.lang.String)
2389     */
2390    public final String getLineSeparator()
2391    {
2392        if ( this.lineSeparator == null )
2393        {
2394            this.lineSeparator = System.getProperty( "line.separator", "\n" );
2395 
2396            if ( this.isLoggable( Level.CONFIG ) )
2397            {
2398                this.log( Level.CONFIG, getMessage( "defaultLineSeparator",
2399                                                    StringEscapeUtils.escapeJava( this.lineSeparator ) ), null );
2400 
2401            }
2402        }
2403 
2404        return this.lineSeparator;
2405    }
2406 
2407    /**
2408     * Sets the line separator of the instance.
2409     *
2410     * @param value The new line separator of the instance or {@code null}.
2411     *
2412     * @see #getLineSeparator()
2413     */
2414    public final void setLineSeparator( final String value )
2415    {
2416        this.lineSeparator = value;
2417    }
2418 
2419    /**
2420     * Gets the locale of the instance.
2421     *
2422     * @return The locale of the instance.
2423     *
2424     * @see #setLocale(java.util.Locale)
2425     *
2426     * @since 1.2
2427     */
2428    public final Locale getLocale()
2429    {
2430        if ( this.locale == null )
2431        {
2432            this.locale = Locale.ENGLISH;
2433 
2434            if ( this.isLoggable( Level.CONFIG ) )
2435            {
2436                this.log( Level.CONFIG, getMessage( "defaultLocale", this.locale ), null );
2437            }
2438        }
2439 
2440        return this.locale;
2441    }
2442 
2443    /**
2444     * Sets the locale of the instance.
2445     *
2446     * @param value The new locale of the instance or {@code null}.
2447     *
2448     * @see #getLocale()
2449     *
2450     * @since 1.2
2451     */
2452    public final void setLocale( final Locale value )
2453    {
2454        this.locale = value;
2455    }
2456 
2457    /**
2458     * Gets a velocity template for a given name.
2459     * <p>This method searches templates at the following locations in the shown order.
2460     * <ol>
2461     *  <li><code>org/jomc/tools/templates/{@link #getTemplateProfile() profile}/{@link #getLocale() language}/<i>templateName</i></code></li>
2462     *  <li><code>org/jomc/tools/templates/{@link #getTemplateProfile() profile}/<i>templateName</i></code></li>
2463     *  <li><code>org/jomc/tools/templates/{@link #getDefaultTemplateProfile() default profile}/{@link #getLocale() language}/<i>templateName</i></code></li>
2464     *  <li><code>org/jomc/tools/templates/{@link #getDefaultTemplateProfile() default profile}/<i>templateName</i></code></li>
2465     * </ol></p>
2466     *
2467     * @param templateName The name of the template to get.
2468     *
2469     * @return The template matching {@code templateName}.
2470     *
2471     * @throws NullPointerException if {@code templateName} is {@code null}.
2472     * @throws IOException if getting the template fails.
2473     *
2474     * @see #getLocale()
2475     * @see #getTemplateProfile()
2476     * @see #getTemplateEncoding()
2477     * @see #getVelocityEngine()
2478     */
2479    public Template getVelocityTemplate( final String templateName ) throws IOException
2480    {
2481        if ( templateName == null )
2482        {
2483            throw new NullPointerException( "templateName" );
2484        }
2485 
2486        String location = null;
2487        Template template = null;
2488        final String key = this.getLocale() + "|" + this.getTemplateProfile() + "|" + getDefaultTemplateProfile()
2489                           + "|" + templateName;
2490 
2491        Map<String, String> map = this.templateLocationsCache == null ? null : this.templateLocationsCache.get();
2492 
2493        if ( map == null )
2494        {
2495            map = Collections.synchronizedMap( new HashMap<String, String>( 32 ) );
2496            this.templateLocationsCache = new SoftReference<Map<String, String>>( map );
2497        }
2498 
2499        location = map.get( key );
2500 
2501        if ( location == null && !map.containsKey( key ) )
2502        {
2503            if ( !StringUtils.EMPTY.equals( this.getLocale().getLanguage() ) )
2504            {
2505                location = TEMPLATE_PREFIX + this.getTemplateProfile() + "/" + this.getLocale().getLanguage() + "/"
2506                           + templateName;
2507 
2508                template = this.findVelocityTemplate( location );
2509            }
2510 
2511            if ( template == null )
2512            {
2513                location = TEMPLATE_PREFIX + this.getTemplateProfile() + "/" + templateName;
2514                template = this.findVelocityTemplate( location );
2515            }
2516 
2517            if ( template == null && !StringUtils.EMPTY.equals( this.getLocale().getLanguage() ) )
2518            {
2519                location = TEMPLATE_PREFIX + getDefaultTemplateProfile() + "/" + this.getLocale().getLanguage() + "/"
2520                           + templateName;
2521 
2522                template = this.findVelocityTemplate( location );
2523            }
2524 
2525            if ( template == null )
2526            {
2527                location = TEMPLATE_PREFIX + getDefaultTemplateProfile() + "/" + templateName;
2528                template = this.findVelocityTemplate( location );
2529            }
2530 
2531            map.put( key, location );
2532        }
2533        else if ( location != null )
2534        {
2535            template = this.findVelocityTemplate( location );
2536        }
2537 
2538        if ( template == null )
2539        {
2540            throw new IOException( getMessage( "noSuchTemplate", templateName ) );
2541        }
2542 
2543        if ( this.isLoggable( Level.FINER ) )
2544        {
2545            this.log( Level.FINER, getMessage( "templateInfo", templateName, location ), null );
2546        }
2547 
2548        return template;
2549    }
2550 
2551    /**
2552     * Notifies registered listeners.
2553     *
2554     * @param level The level of the event.
2555     * @param message The message of the event or {@code null}.
2556     * @param throwable The throwable of the event or {@code null}.
2557     *
2558     * @throws NullPointerException if {@code level} is {@code null}.
2559     *
2560     * @see #getListeners()
2561     * @see #isLoggable(java.util.logging.Level)
2562     */
2563    public void log( final Level level, final String message, final Throwable throwable )
2564    {
2565        if ( level == null )
2566        {
2567            throw new NullPointerException( "level" );
2568        }
2569 
2570        if ( this.isLoggable( level ) )
2571        {
2572            for ( int i = this.getListeners().size() - 1; i >= 0; i-- )
2573            {
2574                this.getListeners().get( i ).onLog( level, message, throwable );
2575            }
2576        }
2577    }
2578 
2579    private String getJavaPackageName( final String identifier )
2580    {
2581        if ( identifier == null )
2582        {
2583            throw new NullPointerException( "identifier" );
2584        }
2585 
2586        final int idx = identifier.lastIndexOf( '.' );
2587        return idx != -1 ? identifier.substring( 0, idx ) : "";
2588    }
2589 
2590    private Template findVelocityTemplate( final String location ) throws IOException
2591    {
2592        try
2593        {
2594            return this.getVelocityEngine().getTemplate( location, this.getTemplateEncoding() );
2595        }
2596        catch ( final ResourceNotFoundException e )
2597        {
2598            if ( this.isLoggable( Level.FINER ) )
2599            {
2600                this.log( Level.FINER, getMessage( "templateNotFound", location ), null );
2601            }
2602 
2603            return null;
2604        }
2605        catch ( final ParseErrorException e )
2606        {
2607            String m = getMessage( e );
2608            m = m == null ? "" : " " + m;
2609 
2610            // JDK: As of JDK 6, "new IOException( message, cause )".
2611            throw (IOException) new IOException( getMessage( "invalidTemplate", location, m ) ).initCause( e );
2612        }
2613        catch ( final VelocityException e )
2614        {
2615            String m = getMessage( e );
2616            m = m == null ? "" : " " + m;
2617 
2618            // JDK: As of JDK 6, "new IOException( message, cause )".
2619            throw (IOException) new IOException( getMessage( "velocityException", location, m ) ).initCause( e );
2620        }
2621    }
2622 
2623    private java.util.Properties getTemplateProfileProperties( final String profileName, final String language )
2624    {
2625        Map<String, java.util.Properties> map = this.templateProfilePropertiesCache == null
2626                                                ? null : this.templateProfilePropertiesCache.get();
2627 
2628        if ( map == null )
2629        {
2630            map = new ConcurrentHashMap<String, java.util.Properties>();
2631            this.templateProfilePropertiesCache = new SoftReference<Map<String, java.util.Properties>>( map );
2632        }
2633 
2634        final String key = profileName + "|" + language;
2635        java.util.Properties profileProperties = map.get( key );
2636 
2637        if ( profileProperties == null )
2638        {
2639            InputStream in = null;
2640            URL url = null;
2641            profileProperties = new java.util.Properties();
2642            map.put( key, profileProperties );
2643 
2644            final String resourceName = TEMPLATE_PREFIX + profileName + ( language == null ? "" : "/" + language )
2645                                        + "/context.properties";
2646 
2647            try
2648            {
2649                url = this.getClass().getResource( "/" + resourceName );
2650 
2651                if ( url != null )
2652                {
2653                    in = url.openStream();
2654 
2655                    if ( this.isLoggable( Level.CONFIG ) )
2656                    {
2657                        this.log( Level.CONFIG, getMessage( "contextPropertiesFound", url.toExternalForm() ), null );
2658                    }
2659 
2660                    profileProperties.load( in );
2661                }
2662                else if ( this.getTemplateLocation() != null )
2663                {
2664                    if ( this.isLoggable( Level.CONFIG ) )
2665                    {
2666                        this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", resourceName ), null );
2667                    }
2668 
2669                    url = new URL( this.getTemplateLocation(), resourceName );
2670                    in = url.openStream();
2671 
2672                    if ( this.isLoggable( Level.CONFIG ) )
2673                    {
2674                        this.log( Level.CONFIG, getMessage( "contextPropertiesFound", url.toExternalForm() ), null );
2675                    }
2676 
2677                    profileProperties.load( in );
2678                }
2679                else if ( this.isLoggable( Level.CONFIG ) )
2680                {
2681                    this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", resourceName ), null );
2682                }
2683            }
2684            catch ( final FileNotFoundException e )
2685            {
2686                if ( this.isLoggable( Level.CONFIG ) )
2687                {
2688                    this.log( Level.CONFIG, getMessage( "contextPropertiesNotFound", url.toExternalForm() ), null );
2689                }
2690            }
2691            catch ( final IOException e )
2692            {
2693                map.remove( key );
2694                this.log( Level.SEVERE, getMessage( e ), e );
2695            }
2696            finally
2697            {
2698                try
2699                {
2700                    if ( in != null )
2701                    {
2702                        in.close();
2703                    }
2704                }
2705                catch ( final IOException e )
2706                {
2707                    this.log( Level.SEVERE, getMessage( e ), e );
2708                }
2709            }
2710        }
2711 
2712        return profileProperties;
2713    }
2714 
2715    private void mergeTemplateProfileProperties( final String profileName, final String language,
2716                                                 final VelocityContext velocityContext )
2717    {
2718        final java.util.Properties templateProfileProperties =
2719            this.getTemplateProfileProperties( profileName, language );
2720 
2721        for ( final Enumeration<?> e = templateProfileProperties.propertyNames(); e.hasMoreElements(); )
2722        {
2723            final String name = e.nextElement().toString();
2724            final String value = templateProfileProperties.getProperty( name );
2725            final String[] values = value.split( "\\|" );
2726 
2727            if ( !velocityContext.containsKey( name ) )
2728            {
2729                try
2730                {
2731                    if ( values.length > 1 )
2732                    {
2733                        final Class<?> valueClass = Class.forName( values[0] );
2734                        velocityContext.put( name, valueClass.getConstructor( String.class ).newInstance( values[1] ) );
2735                    }
2736                    else if ( value.contains( "|" ) )
2737                    {
2738                        velocityContext.put( name, Class.forName( values[0] ).newInstance() );
2739                    }
2740                    else
2741                    {
2742                        velocityContext.put( name, value );
2743                    }
2744                }
2745                catch ( final InstantiationException ex )
2746                {
2747                    this.log( Level.SEVERE, getMessage( ex ), ex );
2748                }
2749                catch ( final IllegalAccessException ex )
2750                {
2751                    this.log( Level.SEVERE, getMessage( ex ), ex );
2752                }
2753                catch ( final InvocationTargetException ex )
2754                {
2755                    this.log( Level.SEVERE, getMessage( ex ), ex );
2756                }
2757                catch ( final NoSuchMethodException ex )
2758                {
2759                    this.log( Level.SEVERE, getMessage( ex ), ex );
2760                }
2761                catch ( final ClassNotFoundException ex )
2762                {
2763                    this.log( Level.SEVERE, getMessage( ex ), ex );
2764                }
2765            }
2766        }
2767    }
2768 
2769    private Set<String> getJavaKeywords()
2770    {
2771        Reader in = null;
2772        Set<String> set = this.javaKeywordsCache == null ? null : this.javaKeywordsCache.get();
2773 
2774        try
2775        {
2776            if ( set == null )
2777            {
2778                in = new InputStreamReader( this.getClass().getResourceAsStream(
2779                    "/" + this.getClass().getPackage().getName().replace( ".", "/" ) + "/JavaKeywords.txt" ), "UTF-8" );
2780 
2781                set = new CopyOnWriteArraySet<String>( IOUtils.readLines( in ) );
2782 
2783                this.javaKeywordsCache = new SoftReference<Set<String>>( set );
2784            }
2785        }
2786        catch ( final IOException e )
2787        {
2788            throw new IllegalStateException( getMessage( e ), e );
2789        }
2790        finally
2791        {
2792            try
2793            {
2794                if ( in != null )
2795                {
2796                    in.close();
2797                }
2798            }
2799            catch ( final IOException e )
2800            {
2801                throw new IllegalStateException( getMessage( e ), e );
2802            }
2803        }
2804 
2805        return set;
2806    }
2807 
2808    private static String getMessage( final String key, final Object... arguments )
2809    {
2810        return MessageFormat.format( ResourceBundle.getBundle(
2811            JomcTool.class.getName().replace( '.', '/' ) ).getString( key ), arguments );
2812 
2813    }
2814 
2815    private static String getMessage( final Throwable t )
2816    {
2817        return t != null ? t.getMessage() != null ? t.getMessage() : getMessage( t.getCause() ) : null;
2818    }
2819 
2820}

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