EMMA Coverage Report (generated Sun Jan 17 14:36:44 UTC 2010)
[all classes][org.jomc.tools]

COVERAGE SUMMARY FOR SOURCE FILE [JomcTool.java]

nameclass, %method, %block, %line, %
JomcTool.java100% (3/3)88%  (56/64)73%  (1251/1714)72%  (251.1/349)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JomcTool100% (1/1)86%  (49/57)73%  (1211/1668)72%  (239.1/334)
JomcTool (JomcTool): void 0%   (0/1)0%   (0/51)0%   (0/15)
getJavaString (String): String 0%   (0/1)0%   (0/3)0%   (0/1)
setDefaultLogLevel (Level): void 0%   (0/1)0%   (0/3)0%   (0/2)
setInputEncoding (String): void 0%   (0/1)0%   (0/4)0%   (0/2)
setLogLevel (Level): void 0%   (0/1)0%   (0/4)0%   (0/2)
setOutputEncoding (String): void 0%   (0/1)0%   (0/4)0%   (0/2)
setTemplateEncoding (String): void 0%   (0/1)0%   (0/7)0%   (0/3)
setVelocityEngine (VelocityEngine): void 0%   (0/1)0%   (0/4)0%   (0/2)
getJavaTypeName (SpecificationReference, boolean): String 100% (1/1)17%  (7/42)40%  (2/5)
getJavaPackageName (SpecificationReference): String 100% (1/1)17%  (7/41)40%  (2/5)
getJavaTypeName (Property, boolean): String 100% (1/1)18%  (16/90)16%  (3.7/23)
getYears (Calendar, Calendar): String 100% (1/1)18%  (14/77)29%  (4/14)
getJavaClasspathLocation (Specification): String 100% (1/1)35%  (7/20)67%  (2/3)
getLongDateTime (Calendar): String 100% (1/1)50%  (7/14)67%  (2/3)
getShortDateTime (Calendar): String 100% (1/1)50%  (7/14)67%  (2/3)
getLongDate (Calendar): String 100% (1/1)54%  (7/13)67%  (2/3)
getLongTime (Calendar): String 100% (1/1)54%  (7/13)67%  (2/3)
getShortDate (Calendar): String 100% (1/1)54%  (7/13)67%  (2/3)
getShortTime (Calendar): String 100% (1/1)54%  (7/13)67%  (2/3)
getModules (): Modules 100% (1/1)55%  (6/11)67%  (2/3)
getJavaModifierName (Implementation, Property): String 100% (1/1)64%  (21/33)74%  (6.7/9)
isLoggable (Level): boolean 100% (1/1)65%  (11/17)63%  (1.9/3)
getJavaTypeName (Implementation, boolean): String 100% (1/1)68%  (34/50)76%  (7.6/10)
getJavaModifierName (Implementation, Dependency): String 100% (1/1)69%  (11/16)80%  (4/5)
getJavaModifierName (Implementation, Message): String 100% (1/1)69%  (11/16)80%  (4/5)
getJavaPackageName (String): String 100% (1/1)76%  (16/21)75%  (3/4)
getJavaTypeName (Argument): String 100% (1/1)82%  (23/28)75%  (6/8)
getMessage (String, Object): String 100% (1/1)83%  (24/29)75%  (3/4)
log (Level, String, Throwable): void 100% (1/1)83%  (24/29)83%  (5/6)
getVelocityTemplate (String): Template 100% (1/1)83%  (146/176)85%  (22/26)
getVelocityEngine (): VelocityEngine 100% (1/1)89%  (47/53)86%  (12/14)
isJavaPrimitiveType (Property): boolean 100% (1/1)90%  (19/21)95%  (2.8/3)
<static initializer> 100% (1/1)93%  (28/30)99%  (4.9/5)
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)
getJavaGetterMethodName (Property): String 100% (1/1)95%  (40/42)89%  (8/9)
getJavaTypeName (Dependency): String 100% (1/1)96%  (43/45)90%  (9/10)
getJavaTypeName (Specification, boolean): String 100% (1/1)96%  (48/50)90%  (9/10)
JomcTool (): void 100% (1/1)100% (11/11)100% (3/3)
getDefaultLogLevel (): Level 100% (1/1)100% (10/10)100% (3/3)
getDisplayLanguage (String): String 100% (1/1)100% (16/16)100% (4/4)
getInputEncoding (): String 100% (1/1)100% (34/34)100% (5/5)
getJavaGetterMethodName (Dependency): String 100% (1/1)100% (28/28)100% (5/5)
getJavaGetterMethodName (Message): String 100% (1/1)100% (30/30)100% (5/5)
getJavaInterfaceNames (Implementation, boolean): List 100% (1/1)100% (57/57)100% (12/12)
getJavadocComment (Text, String): String 100% (1/1)100% (42/42)100% (9/9)
getListeners (): List 100% (1/1)100% (11/11)100% (3/3)
getLogLevel (): Level 100% (1/1)100% (30/30)100% (4/4)
getOutputEncoding (): String 100% (1/1)100% (33/33)100% (5/5)
getProfile (): String 100% (1/1)100% (27/27)100% (5/5)
getTemplateEncoding (): String 100% (1/1)100% (33/33)100% (6/6)
getVelocityContext (): VelocityContext 100% (1/1)100% (106/106)100% (14/14)
setModules (Modules): void 100% (1/1)100% (4/4)100% (2/2)
setProfile (String): void 100% (1/1)100% (7/7)100% (3/3)
     
class JomcTool$1100% (1/1)100% (6/6)86%  (37/43)79%  (11/14)
toToolLevel (int): Level 100% (1/1)57%  (8/14)57%  (4/7)
JomcTool$1 (JomcTool): void 100% (1/1)100% (6/6)100% (1/1)
init (RuntimeServices): void 100% (1/1)100% (1/1)100% (1/1)
isLevelEnabled (int): boolean 100% (1/1)100% (7/7)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% (9/9)100% (2/2)
     
class JomcTool$Listener100% (1/1)100% (1/1)100% (3/3)100% (1/1)
JomcTool$Listener (): void 100% (1/1)100% (3/3)100% (1/1)

1/*
2 *   Copyright (c) 2009 The JOMC Project
3 *   Copyright (c) 2005 Christian Schulte <cs@jomc.org>
4 *   All rights reserved.
5 *
6 *   Redistribution and use in source and binary forms, with or without
7 *   modification, are permitted provided that the following conditions
8 *   are met:
9 *
10 *     o Redistributions of source code must retain the above copyright
11 *       notice, this list of conditions and the following disclaimer.
12 *
13 *     o Redistributions in binary form must reproduce the above copyright
14 *       notice, this list of conditions and the following disclaimer in
15 *       the documentation and/or other materials provided with the
16 *       distribution.
17 *
18 *   THIS SOFTWARE IS PROVIDED BY THE JOMC PROJECT AND CONTRIBUTORS "AS IS"
19 *   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 *   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 *   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JOMC PROJECT OR
22 *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 *   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 *   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 *   OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 *   OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 *   ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 *   $Id: JomcTool.java 1237 2010-01-09 20:22:54Z schulte2005 $
31 *
32 */
33package org.jomc.tools;
34 
35import java.io.ByteArrayInputStream;
36import java.io.ByteArrayOutputStream;
37import java.io.InputStreamReader;
38import java.io.OutputStreamWriter;
39import java.lang.ref.Reference;
40import java.lang.ref.WeakReference;
41import java.text.DateFormat;
42import java.text.Format;
43import java.text.MessageFormat;
44import java.text.SimpleDateFormat;
45import java.util.ArrayList;
46import java.util.Calendar;
47import java.util.Collections;
48import java.util.Date;
49import java.util.HashMap;
50import java.util.LinkedList;
51import java.util.List;
52import java.util.Locale;
53import java.util.Map;
54import java.util.ResourceBundle;
55import java.util.logging.Level;
56import org.apache.commons.lang.StringEscapeUtils;
57import org.apache.velocity.Template;
58import org.apache.velocity.VelocityContext;
59import org.apache.velocity.app.VelocityEngine;
60import org.apache.velocity.exception.ResourceNotFoundException;
61import org.apache.velocity.runtime.RuntimeConstants;
62import org.apache.velocity.runtime.RuntimeServices;
63import org.apache.velocity.runtime.log.LogChute;
64import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
65import org.jomc.model.Argument;
66import org.jomc.model.ArgumentType;
67import org.jomc.model.Dependency;
68import org.jomc.model.Implementation;
69import org.jomc.model.Message;
70import org.jomc.model.Modules;
71import org.jomc.model.Multiplicity;
72import org.jomc.model.Properties;
73import org.jomc.model.Property;
74import org.jomc.model.Specification;
75import org.jomc.model.SpecificationReference;
76import org.jomc.model.Specifications;
77import org.jomc.model.Text;
78 
79/**
80 * Base tool class.
81 *
82 * @author <a href="mailto:cs@jomc.org">Christian Schulte</a>
83 * @version $Id: JomcTool.java 1237 2010-01-09 20:22:54Z schulte2005 $
84 */
85public abstract class JomcTool
86{
87 
88    /** Listener interface. */
89    public abstract static class Listener
90    {
91 
92        /**
93         * Get called on logging.
94         *
95         * @param level The level of the event.
96         * @param message The message of the event or {@code null}.
97         * @param throwable The throwable of the event or {@code null}.
98         *
99         * @throws NullPointerException if {@code level} is {@code null}.
100         */
101        public abstract void onLog( Level level, String message, Throwable throwable );
102 
103    }
104 
105    /** Empty byte array. */
106    private static final byte[] NO_BYTES =
107    {
108    };
109 
110    /** The prefix of the template location. */
111    private static final String TEMPLATE_PREFIX =
112        JomcTool.class.getPackage().getName().replace( '.', '/' ) + "/templates/";
113 
114    /** Name of the velocity classpath resource loader implementation. */
115    private static final String VELOCITY_RESOURCE_LOADER = ClasspathResourceLoader.class.getName();
116 
117    /** Constant for the default profile. */
118    private static final String DEFAULT_PROFILE = "default";
119 
120    /**
121     * Log level events are logged at by default.
122     * @see #getDefaultLogLevel()
123     */
124    private static final Level DEFAULT_LOG_LEVEL = Level.WARNING;
125 
126    /** Default log level. */
127    private static volatile Level defaultLogLevel;
128 
129    /** The modules of the instance. */
130    private Modules modules;
131 
132    /** {@code VelocityEngine} of the generator. */
133    private VelocityEngine velocityEngine;
134 
135    /** The encoding to use for reading templates. */
136    private String templateEncoding;
137 
138    /** The encoding to use for reading files. */
139    private String inputEncoding;
140 
141    /** The encoding to use for writing files. */
142    private String outputEncoding;
143 
144    /** The profile of the instance. */
145    private String profile;
146 
147    /** The listeners of the instance. */
148    private List<Listener> listeners;
149 
150    /** Log level of the instance. */
151    private Level logLevel;
152 
153    /** Cached templates. */
154    private Reference<Map<String, Template>> templateCache =
155        new WeakReference<Map<String, Template>>( new HashMap<String, Template>() );
156 
157    /** Creates a new {@code JomcTool} instance. */
158    public JomcTool()
159    {
160        super();
161    }
162 
163    /**
164     * Creates a new {@code JomcTool} instance taking a {@code JomcTool} instance to initialize the new instance with.
165     *
166     * @param tool The instance to initialize the new instance with.
167     */
168    public JomcTool( final JomcTool tool )
169    {
170        this();
171        if ( tool != null )
172        {
173            try
174            {
175                this.setTemplateEncoding( tool.getTemplateEncoding() );
176                this.setInputEncoding( tool.getInputEncoding() );
177                this.setOutputEncoding( tool.getOutputEncoding() );
178                this.setModules( tool.getModules() );
179                this.setProfile( tool.getProfile() );
180                this.setVelocityEngine( tool.getVelocityEngine() );
181                this.setLogLevel( tool.getLogLevel() );
182                this.getListeners().addAll( tool.getListeners() );
183            }
184            catch ( final Exception e )
185            {
186                if ( this.isLoggable( Level.SEVERE ) )
187                {
188                    this.log( Level.SEVERE, e.getMessage(), e );
189                }
190            }
191        }
192    }
193 
194    /**
195     * Gets the list of registered listeners.
196     * <p>This accessor method returns a reference to the live list, not a snapshot. Therefore any modification you make
197     * to the returned list will be present inside the object. This is why there is no {@code set} method for the
198     * listeners property.</p>
199     *
200     * @return The list of registered listeners.
201     *
202     * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
203     */
204    public List<Listener> getListeners()
205    {
206        if ( this.listeners == null )
207        {
208            this.listeners = new LinkedList<Listener>();
209        }
210 
211        return this.listeners;
212    }
213 
214    /**
215     * Gets the default log level events are logged at.
216     * <p>The default log level is controlled by system property {@code org.jomc.tools.JomcTool.defaultLogLevel} holding
217     * the log level to log events at by default. If that property is not set, the {@code WARNING} default is
218     * returned.</p>
219     *
220     * @return The log level events are logged at by default.
221     *
222     * @see #getLogLevel()
223     * @see Level#parse(java.lang.String)
224     */
225    public static Level getDefaultLogLevel()
226    {
227        if ( defaultLogLevel == null )
228        {
229            defaultLogLevel = Level.parse( System.getProperty( "org.jomc.tools.JomcTool.defaultLogLevel",
230                                                               DEFAULT_LOG_LEVEL.getName() ) );
231 
232        }
233 
234        return defaultLogLevel;
235    }
236 
237    /**
238     * Sets the default log level events are logged at.
239     *
240     * @param value The new default level events are logged at or {@code null}.
241     *
242     * @see #getDefaultLogLevel()
243     */
244    public static void setDefaultLogLevel( final Level value )
245    {
246        defaultLogLevel = value;
247    }
248 
249    /**
250     * Gets the log level of the instance.
251     *
252     * @return The log level of the instance.
253     *
254     * @see #getDefaultLogLevel()
255     * @see #setLogLevel(java.util.logging.Level)
256     * @see #isLoggable(java.util.logging.Level)
257     */
258    public Level getLogLevel()
259    {
260        if ( this.logLevel == null )
261        {
262            this.logLevel = getDefaultLogLevel();
263            this.log( Level.CONFIG, this.getMessage( "defaultLogLevelInfo", new Object[]
264                {
265                    this.getClass().getCanonicalName(), this.logLevel.getLocalizedName()
266                } ), null );
267 
268        }
269 
270        return this.logLevel;
271    }
272 
273    /**
274     * Sets the log level of the instance.
275     *
276     * @param value The new log level of the instance or {@code null}.
277     *
278     * @see #getLogLevel()
279     * @see #isLoggable(java.util.logging.Level)
280     */
281    public void setLogLevel( final Level value )
282    {
283        this.logLevel = value;
284    }
285 
286    /**
287     * Checks if a message at a given level is provided to the listeners of the instance.
288     *
289     * @param level The level to test.
290     *
291     * @return {@code true} if messages at {@code level} are provided to the listeners of the instance;
292     * {@code false} if messages at {@code level} are not provided to the listeners of the instance.
293     *
294     * @throws NullPointerException if {@code level} is {@code null}.
295     *
296     * @see #getLogLevel()
297     * @see #setLogLevel(java.util.logging.Level)
298     * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
299     */
300    public boolean isLoggable( final Level level )
301    {
302        if ( level == null )
303        {
304            throw new NullPointerException( "level" );
305        }
306 
307        return level.intValue() >= this.getLogLevel().intValue();
308    }
309 
310    /**
311     * Gets the Java package name of a specification.
312     *
313     * @param specification The specification to get the Java package name of.
314     *
315     * @return The Java package name of {@code specification} or {@code null}.
316     *
317     * @throws NullPointerException if {@code specification} is {@code null}.
318     */
319    public String getJavaPackageName( final Specification specification )
320    {
321        if ( specification == null )
322        {
323            throw new NullPointerException( "specification" );
324        }
325 
326        return specification.getClazz() != null ? this.getJavaPackageName( specification.getClazz() ) : null;
327    }
328 
329    /**
330     * Gets the Java type name of a specification.
331     *
332     * @param specification The specification to get the Java type name of.
333     * @param qualified {@code true} to return the fully qualified type name (with package name prepended);
334     * {@code false} to return the short type name (without package name prepended).
335     *
336     * @return The Java type name of {@code specification} or {@code null}.
337     *
338     * @throws NullPointerException if {@code specification} is {@code null}.
339     */
340    public String getJavaTypeName( final Specification specification, final boolean qualified )
341    {
342        if ( specification == null )
343        {
344            throw new NullPointerException( "specification" );
345        }
346 
347        if ( specification.getClazz() != null )
348        {
349            final StringBuilder typeName = new StringBuilder();
350            final String javaPackageName = this.getJavaPackageName( specification );
351 
352            if ( qualified && javaPackageName.length() > 0 )
353            {
354                typeName.append( javaPackageName ).append( '.' );
355            }
356 
357            typeName.append( javaPackageName.length() > 0
358                             ? specification.getClazz().substring( javaPackageName.length() + 1 )
359                             : specification.getClazz() );
360 
361            return typeName.toString();
362        }
363 
364        return null;
365    }
366 
367    /**
368     * Gets the Java class path location of a specification.
369     *
370     * @param specification The specification to return the Java class path location of.
371     *
372     * @return The Java class path location of {@code specification} or {@code null}.
373     *
374     * @throws NullPointerException if {@code specification} is {@code null}.
375     */
376    public String getJavaClasspathLocation( final Specification specification )
377    {
378        if ( specification == null )
379        {
380            throw new NullPointerException( "specification" );
381        }
382 
383        return specification.getClazz() != null
384               ? ( this.getJavaTypeName( specification, true ) ).replace( '.', '/' )
385               : null;
386 
387    }
388 
389    /**
390     * Gets the Java package name of a specification reference.
391     *
392     * @param reference The specification reference to get the Java package name of.
393     *
394     * @return The Java package name of {@code reference} or {@code null}.
395     *
396     * @throws NullPointerException if {@code reference} is {@code null}.
397     */
398    public String getJavaPackageName( final SpecificationReference reference )
399    {
400        if ( reference == null )
401        {
402            throw new NullPointerException( "reference" );
403        }
404 
405        final Specification s = this.getModules().getSpecification( reference.getIdentifier() );
406        assert s != null : "Specification '" + reference.getIdentifier() + "' not found.";
407        return s.getClazz() != null ? this.getJavaPackageName( s ) : null;
408    }
409 
410    /**
411     * Gets the name of a Java type of a given specification reference.
412     *
413     * @param reference The specification reference to get a Java type name of.
414     * @param qualified {@code true} to return the fully qualified type name (with package name prepended);
415     * {@code false} to return the short type name (without package name prepended).
416     *
417     * @return The Java type name of {@code reference} or {@code null}.
418     *
419     * @throws NullPointerException if {@code reference} is {@code null}.
420     */
421    public String getJavaTypeName( final SpecificationReference reference, final boolean qualified )
422    {
423        if ( reference == null )
424        {
425            throw new NullPointerException( "reference" );
426        }
427 
428        final Specification s = this.getModules().getSpecification( reference.getIdentifier() );
429        assert s != null : "Specification '" + reference.getIdentifier() + "' not found.";
430        return s.getClazz() != null ? this.getJavaTypeName( s, qualified ) : null;
431    }
432 
433    /**
434     * Gets the Java package name of an implementation.
435     *
436     * @param implementation The implementation to get the Java package name of.
437     *
438     * @return The Java package name of {@code implementation} or {@code null}.
439     *
440     * @throws NullPointerException if {@code implementation} is {@code null}.
441     */
442    public String getJavaPackageName( final Implementation implementation )
443    {
444        if ( implementation == null )
445        {
446            throw new NullPointerException( "implementation" );
447        }
448 
449        return implementation.getClazz() != null ? this.getJavaPackageName( implementation.getClazz() ) : null;
450    }
451 
452    /**
453     * Gets the Java type name of an implementation.
454     *
455     * @param implementation The implementation to get the Java type name of.
456     * @param qualified {@code true} to return the fully qualified type name (with package name prepended);
457     * {@code false} to return the short type name (without package name prepended).
458     *
459     * @return The Java type name of {@code implementation} or {@code null}.
460     *
461     * @throws NullPointerException if {@code implementation} is {@code null}.
462     */
463    public String getJavaTypeName( final Implementation implementation, final boolean qualified )
464    {
465        if ( implementation == null )
466        {
467            throw new NullPointerException( "implementation" );
468        }
469 
470        if ( implementation.getClazz() != null )
471        {
472            final StringBuilder typeName = new StringBuilder();
473            final String javaPackageName = this.getJavaPackageName( implementation );
474 
475            if ( qualified && javaPackageName.length() > 0 )
476            {
477                typeName.append( javaPackageName ).append( '.' );
478            }
479 
480            typeName.append( javaPackageName.length() > 0
481                             ? implementation.getClazz().substring( javaPackageName.length() + 1 )
482                             : implementation.getClazz() );
483 
484            return typeName.toString();
485        }
486 
487        return null;
488    }
489 
490    /**
491     * Gets the Java class path location of an implementation.
492     *
493     * @param implementation The implementation to return the Java class path location of.
494     *
495     * @return The Java class path location of {@code implementation} or {@code null}.
496     *
497     * @throws NullPointerException if {@code implementation} is {@code null}.
498     */
499    public String getJavaClasspathLocation( final Implementation implementation )
500    {
501        if ( implementation == null )
502        {
503            throw new NullPointerException( "implementation" );
504        }
505 
506        return implementation.getClazz() != null
507               ? ( this.getJavaTypeName( implementation, true ) ).replace( '.', '/' )
508               : null;
509 
510    }
511 
512    /**
513     * Gets all Java interfaces an implementation implements.
514     *
515     * @param implementation The implementation to get all implemented Java interfaces of.
516     * @param qualified {@code true} to return the fully qualified type names (with package name prepended);
517     * {@code false} to return the short type names (without package name prepended).
518     *
519     * @return Unmodifiable list contaning all Java interfaces implemented by {@code implementation}.
520     *
521     * @throws NullPointerException if {@code implementation} is {@code null}.
522     */
523    public List<String> getJavaInterfaceNames( final Implementation implementation, final boolean qualified )
524    {
525        if ( implementation == null )
526        {
527            throw new NullPointerException( "implementation" );
528        }
529 
530        final Specifications specs = this.getModules().getSpecifications( implementation.getIdentifier() );
531        final List<String> col = new ArrayList<String>( specs == null ? 0 : specs.getSpecification().size() );
532 
533        if ( specs != null )
534        {
535            for ( Specification s : specs.getSpecification() )
536            {
537                if ( s.getClazz() != null )
538                {
539                    final String typeName = this.getJavaTypeName( s, qualified );
540                    if ( !col.contains( typeName ) )
541                    {
542                        col.add( typeName );
543                    }
544                }
545            }
546        }
547 
548        return Collections.unmodifiableList( col );
549    }
550 
551    /**
552     * Gets the Java type name of an argument.
553     *
554     * @param argument The argument to get the Java type name of.
555     *
556     * @return The Java type name of {@code argument}.
557     *
558     * @throws NullPointerException if {@code argument} is {@code null}.
559     */
560    public String getJavaTypeName( final Argument argument )
561    {
562        if ( argument == null )
563        {
564            throw new NullPointerException( "argument" );
565        }
566 
567        String javaTypeName = "java.lang.String";
568 
569        if ( argument.getType() == ArgumentType.DATE || argument.getType() == ArgumentType.TIME )
570        {
571            javaTypeName = "java.util.Date";
572        }
573        else if ( argument.getType() == ArgumentType.NUMBER )
574        {
575            javaTypeName = "java.lang.Number";
576        }
577 
578        return javaTypeName;
579    }
580 
581    /**
582     * Gets the Java type name of a property.
583     *
584     * @param property The property to get the Java type name of.
585     * @param boxify {@code true} to return the name of the Java wrapper class when the type is a Java primitive type;
586     * {@code false} to return the exact binary name (unboxed name) of the Java type.
587     *
588     * @return The Java type name of {@code property}.
589     *
590     * @throws NullPointerException if {@code property} is {@code null}.
591     */
592    public String getJavaTypeName( final Property property, final boolean boxify )
593    {
594        if ( property == null )
595        {
596            throw new NullPointerException( "property" );
597        }
598 
599        if ( property.getType() != null )
600        {
601            final String typeName = property.getType();
602 
603            if ( boxify )
604            {
605                if ( Boolean.TYPE.getName().equals( typeName ) )
606                {
607                    return Boolean.class.getName();
608                }
609                if ( Byte.TYPE.getName().equals( typeName ) )
610                {
611                    return Byte.class.getName();
612                }
613                if ( Character.TYPE.getName().equals( typeName ) )
614                {
615                    return Character.class.getName();
616                }
617                if ( Double.TYPE.getName().equals( typeName ) )
618                {
619                    return Double.class.getName();
620                }
621                if ( Float.TYPE.getName().equals( typeName ) )
622                {
623                    return Float.class.getName();
624                }
625                if ( Integer.TYPE.getName().equals( typeName ) )
626                {
627                    return Integer.class.getName();
628                }
629                if ( Long.TYPE.getName().equals( typeName ) )
630                {
631                    return Long.class.getName();
632                }
633                if ( Short.TYPE.getName().equals( typeName ) )
634                {
635                    return Short.class.getName();
636                }
637            }
638 
639            return typeName;
640        }
641 
642        return property.getAny() != null ? Object.class.getName() : String.class.getName();
643    }
644 
645    /**
646     * Gets a flag indicating if the type of a given property is a Java primitive.
647     *
648     * @param property The property to query.
649     *
650     * @return {@code true} if the type of {@code property} is a Java primitive; {@code false} if not.
651     *
652     * @throws NullPointerException if {@code property} is {@code null}.
653     */
654    public boolean isJavaPrimitiveType( final Property property )
655    {
656        if ( property == null )
657        {
658            throw new NullPointerException( "property" );
659        }
660 
661        return !this.getJavaTypeName( property, false ).equals( this.getJavaTypeName( property, true ) );
662    }
663 
664    /**
665     * Gets the name of a Java accessor method of a given property.
666     *
667     * @param property The property to get a Java accessor method name of.
668     *
669     * @return The Java accessor method name of {@code property}.
670     *
671     * @throws NullPointerException if {@code property} is {@code null}.
672     */
673    public String getJavaGetterMethodName( final Property property )
674    {
675        if ( property == null )
676        {
677            throw new NullPointerException( "property" );
678        }
679 
680        final char[] name = property.getName().toCharArray();
681        name[0] = Character.toUpperCase( name[0] );
682        String prefix = "get";
683 
684        final String javaTypeName = this.getJavaTypeName( property, true );
685        if ( Boolean.class.getName().equals( javaTypeName ) )
686        {
687            prefix = "is";
688        }
689 
690        return prefix + String.valueOf( name );
691    }
692 
693    /**
694     * Gets the name of a Java type of a given dependency.
695     *
696     * @param dependency The dependency to get a dependency Java type name of.
697     *
698     * @return The Java type name of {@code dependency} or {@code null}.
699     *
700     * @throws NullPointerException if {@code dependency} is {@code null}.
701     */
702    public String getJavaTypeName( final Dependency dependency )
703    {
704        if ( dependency == null )
705        {
706            throw new NullPointerException( "dependency" );
707        }
708 
709        final Specification s = this.getModules().getSpecification( dependency.getIdentifier() );
710 
711        if ( s != null && s.getClazz() != null )
712        {
713            final StringBuilder typeName = new StringBuilder();
714            typeName.append( this.getJavaTypeName( s, true ) );
715            if ( s.getMultiplicity() == Multiplicity.MANY && dependency.getImplementationName() == null )
716            {
717                typeName.append( "[]" );
718            }
719 
720            return typeName.toString();
721        }
722 
723        return null;
724    }
725 
726    /**
727     * Gets the name of a Java accessor method of a given dependency.
728     *
729     * @param dependency The dependency to get a Java accessor method name of.
730     *
731     * @return The Java accessor method name of {@code dependency}.
732     *
733     * @throws NullPointerException if {@code dependency} is {@code null}.
734     */
735    public String getJavaGetterMethodName( final Dependency dependency )
736    {
737        if ( dependency == null )
738        {
739            throw new NullPointerException( "dependency" );
740        }
741 
742        final char[] name = dependency.getName().toCharArray();
743        name[0] = Character.toUpperCase( name[0] );
744        return "get" + String.valueOf( name );
745    }
746 
747    /**
748     * Gets the name of a Java accessor method of a given message.
749     *
750     * @param message The message to get a Java accessor method name of.
751     *
752     * @return The Java accessor method name of {@code message}.
753     *
754     * @throws NullPointerException if {@code message} is {@code null}.
755     */
756    public String getJavaGetterMethodName( final Message message )
757    {
758        if ( message == null )
759        {
760            throw new NullPointerException( "message" );
761        }
762 
763        final char[] name = message.getName().toCharArray();
764        name[0] = Character.toUpperCase( name[0] );
765        return "get" + String.valueOf( name ) + "Message";
766    }
767 
768    /**
769     * Gets the name of a Java modifier of a dependency of a given implementation.
770     *
771     * @param implementation The implementation to get a dependency Java modifier name of.
772     * @param dependency The dependency to get a Java modifier name of.
773     *
774     * @return The Java modifier name of {@code dependency} of {@code implementation}.
775     *
776     * @throws NullPointerException if {@code implementation} or {@code dependency} is {@code null}.
777     */
778    public String getJavaModifierName( final Implementation implementation, final Dependency dependency )
779    {
780        if ( implementation == null )
781        {
782            throw new NullPointerException( "implementation" );
783        }
784        if ( dependency == null )
785        {
786            throw new NullPointerException( "dependency" );
787        }
788 
789        return "private";
790    }
791 
792    /**
793     * Gets the name of a Java modifier of a message of a given implementation.
794     *
795     * @param implementation The implementation to get a message Java modifier name of.
796     * @param message The message to get a Java modifier name of.
797     *
798     * @return The Java modifier name of {@code message} of {@code implementation}.
799     *
800     * @throws NullPointerException if {@code implementation} or {@code message} is {@code null}.
801     */
802    public String getJavaModifierName( final Implementation implementation, final Message message )
803    {
804        if ( implementation == null )
805        {
806            throw new NullPointerException( "implementation" );
807        }
808        if ( message == null )
809        {
810            throw new NullPointerException( "message" );
811        }
812 
813        return "private";
814    }
815 
816    /**
817     * Gets the name of a Java modifier for a given property of a given implementation.
818     *
819     * @param implementation The implementation declaring {@code property}.
820     * @param property The property to get a Java modifier name for.
821     *
822     * @return The Java modifier name for {@code property} of {@code implementation}.
823     *
824     * @throws NullPointerException if {@code implementation} or {@code property} is {@code null}.
825     */
826    public String getJavaModifierName( final Implementation implementation, final Property property )
827    {
828        if ( implementation == null )
829        {
830            throw new NullPointerException( "implementation" );
831        }
832        if ( property == null )
833        {
834            throw new NullPointerException( "property" );
835        }
836 
837        String modifier = "private";
838        final Properties specified = this.getModules().getSpecifiedProperties( implementation.getIdentifier() );
839 
840        if ( specified != null && specified.getProperty( property.getName() ) != null )
841        {
842            modifier = "public";
843        }
844 
845        return modifier;
846    }
847 
848    /**
849     * Formats a text to a Javadoc comment.
850     *
851     * @param text The text to format to a Javadoc comment.
852     * @param linebreak The text to replace line breaks with.
853     *
854     * @return {@code text} formatted as a Javadoc comment.
855     *
856     * @throws NullPointerException if {@code text} or {@code linebreak} is {@code null}.
857     */
858    public String getJavadocComment( final Text text, final String linebreak )
859    {
860        if ( text == null )
861        {
862            throw new NullPointerException( "text" );
863        }
864        if ( linebreak == null )
865        {
866            throw new NullPointerException( "linebreak" );
867        }
868 
869        String normalized = text.getValue();
870        normalized = normalized.replaceAll( "\\/\\*\\*", "/*" );
871        normalized = normalized.replaceAll( "\\*/", "/" );
872        normalized = normalized.replaceAll( "\n", "\n" + linebreak );
873        return StringEscapeUtils.escapeHtml( normalized );
874    }
875 
876    /**
877     * Formats a string to a Java string with unicode escapes.
878     *
879     * @param str The string to format to a Java string or {@code null}.
880     *
881     * @return {@code str} formatted as a Java string or {@code null}.
882     */
883    public String getJavaString( final String str )
884    {
885        return StringEscapeUtils.escapeJava( str );
886    }
887 
888    /**
889     * Gets a flag indicating if the class of a given specification is located in the Java default package.
890     *
891     * @param specification The specification to test.
892     *
893     * @return {@code true} if the class of {@code specification} is located in the Java default package; {@code false}
894     * if not.
895     *
896     * @throws NullPointerException if {@code specification} is {@code null}.
897     */
898    public boolean isJavaDefaultPackage( final Specification specification )
899    {
900        if ( specification == null )
901        {
902            throw new NullPointerException( "specification" );
903        }
904 
905        return specification.getClazz() != null && this.getJavaPackageName( specification ).length() == 0;
906    }
907 
908    /**
909     * Gets a flag indicating if the class of a given implementation is located in the Java default package.
910     *
911     * @param implementation The implementation to test.
912     *
913     * @return {@code true} if the class of {@code implementation} is located in the Java default package; {@code false}
914     * if not.
915     *
916     * @throws NullPointerException if {@code implementation} is {@code null}.
917     */
918    public boolean isJavaDefaultPackage( final Implementation implementation )
919    {
920        if ( implementation == null )
921        {
922            throw new NullPointerException( "implementation" );
923        }
924 
925        return implementation.getClazz() != null && this.getJavaPackageName( implementation ).length() == 0;
926    }
927 
928    /**
929     * Gets the display language of a given language code.
930     *
931     * @param language The language code to get the display language of.
932     *
933     * @return The display language of {@code language}.
934     *
935     * @throws NullPointerException if {@code language} is {@code null}.
936     */
937    public String getDisplayLanguage( final String language )
938    {
939        if ( language == null )
940        {
941            throw new NullPointerException( "language" );
942        }
943 
944        final Locale locale = new Locale( language );
945        return locale.getDisplayLanguage( locale );
946    }
947 
948    /**
949     * Formats a calendar instance to a string.
950     *
951     * @param calendar The calendar to format.
952     *
953     * @return Date of {@code calendar} formatted using a short format style pattern.
954     *
955     * @throws NullPointerException if {@code calendar} is {@code null}.
956     *
957     * @see DateFormat#SHORT
958     */
959    public String getShortDate( final Calendar calendar )
960    {
961        if ( calendar == null )
962        {
963            throw new NullPointerException( "calendar" );
964        }
965 
966        return DateFormat.getDateInstance( DateFormat.SHORT ).format( calendar.getTime() );
967    }
968 
969    /**
970     * Formats a calendar instance to a string.
971     *
972     * @param calendar The calendar to format.
973     *
974     * @return Date of {@code calendar} formatted using a long format style pattern.
975     *
976     * @throws NullPointerException if {@code calendar} is {@code null}.
977     *
978     * @see DateFormat#LONG
979     */
980    public String getLongDate( final Calendar calendar )
981    {
982        if ( calendar == null )
983        {
984            throw new NullPointerException( "calendar" );
985        }
986 
987        return DateFormat.getDateInstance( DateFormat.LONG ).format( calendar.getTime() );
988    }
989 
990    /**
991     * Formats a calendar instance to a string.
992     *
993     * @param calendar The calendar to format.
994     *
995     * @return Time of {@code calendar} formatted using a short format style pattern.
996     *
997     * @throws NullPointerException if {@code calendar} is {@code null}.
998     *
999     * @see DateFormat#SHORT
1000     */
1001    public String getShortTime( final Calendar calendar )
1002    {
1003        if ( calendar == null )
1004        {
1005            throw new NullPointerException( "calendar" );
1006        }
1007 
1008        return DateFormat.getTimeInstance( DateFormat.SHORT ).format( calendar.getTime() );
1009    }
1010 
1011    /**
1012     * Formats a calendar instance to a string.
1013     *
1014     * @param calendar The calendar to format.
1015     *
1016     * @return Time of {@code calendar} formatted using a long format style pattern.
1017     *
1018     * @throws NullPointerException if {@code calendar} is {@code null}.
1019     *
1020     * @see DateFormat#LONG
1021     */
1022    public String getLongTime( final Calendar calendar )
1023    {
1024        if ( calendar == null )
1025        {
1026            throw new NullPointerException( "calendar" );
1027        }
1028 
1029        return DateFormat.getTimeInstance( DateFormat.LONG ).format( calendar.getTime() );
1030    }
1031 
1032    /**
1033     * Formats a calendar instance to a string.
1034     *
1035     * @param calendar The calendar to format.
1036     *
1037     * @return Date and time of {@code calendar} formatted using a short format style pattern.
1038     *
1039     * @throws NullPointerException if {@code calendar} is {@code null}.
1040     *
1041     * @see DateFormat#SHORT
1042     */
1043    public String getShortDateTime( final Calendar calendar )
1044    {
1045        if ( calendar == null )
1046        {
1047            throw new NullPointerException( "calendar" );
1048        }
1049 
1050        return DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT ).format( calendar.getTime() );
1051    }
1052 
1053    /**
1054     * Formats a calendar instance to a string.
1055     *
1056     * @param calendar The calendar to format.
1057     *
1058     * @return Date and time of {@code calendar} formatted using a long format style pattern.
1059     *
1060     * @throws NullPointerException if {@code calendar} is {@code null}.
1061     *
1062     * @see DateFormat#LONG
1063     */
1064    public String getLongDateTime( final Calendar calendar )
1065    {
1066        if ( calendar == null )
1067        {
1068            throw new NullPointerException( "calendar" );
1069        }
1070 
1071        return DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG ).format( calendar.getTime() );
1072    }
1073 
1074    /**
1075     * Gets a string describing the range of years for given calendars.
1076     *
1077     * @param start The start of the range.
1078     * @param end The end of the range.
1079     *
1080     * @return Formatted range of the years of {@code start} and {@code end}.
1081     *
1082     * @throws NullPointerException if {@code start} or {@code end} is {@code null}.
1083     */
1084    public String getYears( final Calendar start, final Calendar end )
1085    {
1086        if ( start == null )
1087        {
1088            throw new NullPointerException( "start" );
1089        }
1090        if ( end == null )
1091        {
1092            throw new NullPointerException( "end" );
1093        }
1094 
1095        final Format yearFormat = new SimpleDateFormat( "yyyy" );
1096        final int s = start.get( Calendar.YEAR );
1097        final int e = end.get( Calendar.YEAR );
1098        final StringBuilder years = new StringBuilder();
1099 
1100        if ( s != e )
1101        {
1102            if ( s < e )
1103            {
1104                years.append( yearFormat.format( start.getTime() ) ).append( " - " ).
1105                    append( yearFormat.format( end.getTime() ) );
1106 
1107            }
1108            else
1109            {
1110                years.append( yearFormat.format( end.getTime() ) ).append( " - " ).
1111                    append( yearFormat.format( start.getTime() ) );
1112 
1113            }
1114        }
1115        else
1116        {
1117            years.append( yearFormat.format( start.getTime() ) );
1118        }
1119 
1120        return years.toString();
1121    }
1122 
1123    /**
1124     * Gets the modules of the instance.
1125     *
1126     * @return The modules of the instance.
1127     *
1128     * @see #setModules(org.jomc.model.Modules)
1129     */
1130    public Modules getModules()
1131    {
1132        if ( this.modules == null )
1133        {
1134            this.modules = new Modules();
1135        }
1136 
1137        return this.modules;
1138    }
1139 
1140    /**
1141     * Sets the modules of the instance.
1142     *
1143     * @param value The new modules of the instance.
1144     *
1145     * @see #getModules()
1146     */
1147    public void setModules( final Modules value )
1148    {
1149        this.modules = value;
1150    }
1151 
1152    /**
1153     * Gets the {@code VelocityEngine} used for generating source code.
1154     *
1155     * @return The {@code VelocityEngine} used for generating source code.
1156     *
1157     * @throws ToolException if initializing a new velocity engine fails.
1158     *
1159     * @see #setVelocityEngine(org.apache.velocity.app.VelocityEngine)
1160     */
1161    public VelocityEngine getVelocityEngine() throws ToolException
1162    {
1163        if ( this.velocityEngine == null )
1164        {
1165            try
1166            {
1167                final java.util.Properties props = new java.util.Properties();
1168                props.put( "resource.loader", "class" );
1169                props.put( "class.resource.loader.class", VELOCITY_RESOURCE_LOADER );
1170                props.put( "runtime.references.strict", Boolean.TRUE.toString() );
1171 
1172                final VelocityEngine engine = new VelocityEngine();
1173                engine.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new LogChute()
1174                {
1175 
1176                    public void init( final RuntimeServices runtimeServices ) throws Exception
1177                    {
1178                    }
1179 
1180                    public void log( final int level, final String message )
1181                    {
1182                        this.log( level, message, null );
1183                    }
1184 
1185                    public void log( final int level, final String message, final Throwable throwable )
1186                    {
1187                        JomcTool.this.log( this.toToolLevel( level ), message, throwable );
1188                    }
1189 
1190                    public boolean isLevelEnabled( final int level )
1191                    {
1192                        return isLoggable( this.toToolLevel( level ) );
1193                    }
1194 
1195                    private Level toToolLevel( final int logChuteLevel )
1196                    {
1197                        switch ( logChuteLevel )
1198                        {
1199                            case LogChute.DEBUG_ID:
1200                                return Level.FINE;
1201 
1202                            case LogChute.ERROR_ID:
1203                                return Level.SEVERE;
1204 
1205                            case LogChute.INFO_ID:
1206                                return Level.INFO;
1207 
1208                            case LogChute.TRACE_ID:
1209                                return Level.FINER;
1210 
1211                            case LogChute.WARN_ID:
1212                                return Level.WARNING;
1213 
1214                            default:
1215                                return Level.FINEST;
1216 
1217                        }
1218                    }
1219 
1220                } );
1221 
1222                engine.init( props );
1223                this.velocityEngine = engine;
1224                this.templateCache.clear();
1225            }
1226            catch ( final Exception e )
1227            {
1228                throw new ToolException( e );
1229            }
1230        }
1231 
1232        return this.velocityEngine;
1233    }
1234 
1235    /**
1236     * Sets the {@code VelocityEngine} of the instance.
1237     *
1238     * @param value The new {@code VelocityEngine} of the instance.
1239     *
1240     * @see #getVelocityEngine()
1241     */
1242    public void setVelocityEngine( final VelocityEngine value )
1243    {
1244        this.velocityEngine = value;
1245    }
1246 
1247    /**
1248     * Gets the velocity context used for merging templates.
1249     *
1250     * @return The velocity context used for merging templates.
1251     */
1252    public VelocityContext getVelocityContext()
1253    {
1254        final Date now = new Date();
1255        final VelocityContext ctx = new VelocityContext();
1256        ctx.put( "modules", this.getModules() );
1257        ctx.put( "tool", this );
1258        ctx.put( "calendar", Calendar.getInstance() );
1259        ctx.put( "now", new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ" ).format( now ) );
1260        ctx.put( "year", new SimpleDateFormat( "yyyy" ).format( now ) );
1261        ctx.put( "month", new SimpleDateFormat( "MM" ).format( now ) );
1262        ctx.put( "day", new SimpleDateFormat( "dd" ).format( now ) );
1263        ctx.put( "hour", new SimpleDateFormat( "HH" ).format( now ) );
1264        ctx.put( "minute", new SimpleDateFormat( "mm" ).format( now ) );
1265        ctx.put( "second", new SimpleDateFormat( "ss" ).format( now ) );
1266        ctx.put( "timezone", new SimpleDateFormat( "Z" ).format( now ) );
1267        return ctx;
1268    }
1269 
1270    /**
1271     * Gets the encoding to use for reading templates.
1272     *
1273     * @return The encoding to use for reading templates.
1274     *
1275     * @see #setTemplateEncoding(java.lang.String)
1276     */
1277    public String getTemplateEncoding()
1278    {
1279        if ( this.templateEncoding == null )
1280        {
1281            this.templateEncoding = this.getMessage( "buildSourceEncoding", null );
1282            this.templateCache.clear();
1283            if ( this.isLoggable( Level.FINE ) )
1284            {
1285                this.log( Level.FINE, this.getMessage( "defaultTemplateEncoding", new Object[]
1286                    {
1287                        this.templateEncoding
1288                    } ), null );
1289 
1290            }
1291        }
1292 
1293        return this.templateEncoding;
1294    }
1295 
1296    /**
1297     * Sets the encoding to use for reading templates.
1298     *
1299     * @param value The encoding to use for reading templates.
1300     *
1301     * @see #getTemplateEncoding()
1302     */
1303    public void setTemplateEncoding( final String value )
1304    {
1305        this.templateEncoding = value;
1306        this.templateCache.clear();
1307    }
1308 
1309    /**
1310     * Gets the encoding to use for reading files.
1311     *
1312     * @return The encoding to use for reading files.
1313     *
1314     * @see #setInputEncoding(java.lang.String)
1315     */
1316    public String getInputEncoding()
1317    {
1318        if ( this.inputEncoding == null )
1319        {
1320            this.inputEncoding = new InputStreamReader( new ByteArrayInputStream( NO_BYTES ) ).getEncoding();
1321            if ( this.isLoggable( Level.FINE ) )
1322            {
1323                this.log( Level.FINE, this.getMessage( "defaultInputEncoding", new Object[]
1324                    {
1325                        this.inputEncoding
1326                    } ), null );
1327 
1328            }
1329        }
1330 
1331        return this.inputEncoding;
1332    }
1333 
1334    /**
1335     * Sets the encoding to use for reading files.
1336     *
1337     * @param value The encoding to use for reading files.
1338     *
1339     * @see #getInputEncoding()
1340     */
1341    public void setInputEncoding( final String value )
1342    {
1343        this.inputEncoding = value;
1344    }
1345 
1346    /**
1347     * Gets the encoding to use for writing files.
1348     *
1349     * @return The encoding to use for writing files.
1350     *
1351     * @see #setOutputEncoding(java.lang.String)
1352     */
1353    public String getOutputEncoding()
1354    {
1355        if ( this.outputEncoding == null )
1356        {
1357            this.outputEncoding = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
1358            if ( this.isLoggable( Level.FINE ) )
1359            {
1360                this.log( Level.FINE, this.getMessage( "defaultOutputEncoding", new Object[]
1361                    {
1362                        this.outputEncoding
1363                    } ), null );
1364 
1365            }
1366        }
1367 
1368        return this.outputEncoding;
1369    }
1370 
1371    /**
1372     * Sets the encoding to use for writing files.
1373     *
1374     * @param value The encoding to use for writing files.
1375     *
1376     * @see #getOutputEncoding()
1377     */
1378    public void setOutputEncoding( final String value )
1379    {
1380        this.outputEncoding = value;
1381    }
1382 
1383    /**
1384     * Gets the profile of the instance.
1385     *
1386     * @return The profile of the instance.
1387     *
1388     * @see #setProfile(java.lang.String)
1389     */
1390    public String getProfile()
1391    {
1392        if ( this.profile == null )
1393        {
1394            this.profile = DEFAULT_PROFILE;
1395            if ( this.isLoggable( Level.FINE ) )
1396            {
1397                this.log( Level.FINE, this.getMessage( "defaultProfile", new Object[]
1398                    {
1399                        this.profile
1400                    } ), null );
1401 
1402            }
1403        }
1404 
1405        return this.profile;
1406    }
1407 
1408    /**
1409     * Sets the profile of the instance.
1410     *
1411     * @param value The profile of the instance.
1412     *
1413     * @see #getProfile()
1414     */
1415    public void setProfile( final String value )
1416    {
1417        this.profile = value;
1418        this.templateCache.clear();
1419    }
1420 
1421    /**
1422     * Gets a velocity template for a given name.
1423     * <p>This method returns the template corresponding to the profile of the instance. If that template is not found,
1424     * the template of the default profile is returned so that only templates differing from the default templates need
1425     * to be provided when exchanging templates.</p>
1426     *
1427     * @param templateName The name of the template to get.
1428     *
1429     * @return The template matching {@code templateName}.
1430     *
1431     * @throws NullPointerException if {@code templateName} is {@code null}.
1432     * @throws ToolException if getting the template fails.
1433     *
1434     * @see #getProfile()
1435     * @see #getTemplateEncoding()
1436     */
1437    public Template getVelocityTemplate( final String templateName ) throws ToolException
1438    {
1439        if ( templateName == null )
1440        {
1441            throw new NullPointerException( "templateName" );
1442        }
1443 
1444        Map<String, Template> templates = this.templateCache.get();
1445        if ( templates == null )
1446        {
1447            templates = new HashMap<String, Template>();
1448            this.templateCache = new WeakReference<Map<String, Template>>( templates );
1449        }
1450 
1451        Template template = templates.get( templateName );
1452 
1453        if ( template == null )
1454        {
1455            try
1456            {
1457                template = this.getVelocityEngine().getTemplate(
1458                    TEMPLATE_PREFIX + this.getProfile() + "/" + templateName, this.getTemplateEncoding() );
1459 
1460                templates.put( templateName, template );
1461            }
1462            catch ( final ResourceNotFoundException e )
1463            {
1464                if ( this.isLoggable( Level.CONFIG ) )
1465                {
1466                    this.log( Level.CONFIG, this.getMessage( "templateNotFound", new Object[]
1467                        {
1468                            templateName, this.getProfile()
1469                        } ), e );
1470 
1471                }
1472 
1473                try
1474                {
1475                    template = this.getVelocityEngine().getTemplate(
1476                        TEMPLATE_PREFIX + DEFAULT_PROFILE + "/" + templateName, this.getTemplateEncoding() );
1477 
1478                    if ( this.isLoggable( Level.CONFIG ) )
1479                    {
1480                        this.log( Level.CONFIG, this.getMessage( "defaultTemplate", new Object[]
1481                            {
1482                                templateName, DEFAULT_PROFILE
1483                            } ), e );
1484 
1485                    }
1486 
1487                    templates.put( templateName, template );
1488                }
1489                catch ( final ResourceNotFoundException e2 )
1490                {
1491                    throw new ToolException( this.getMessage( "templateNotFound", new Object[]
1492                        {
1493                            templateName, DEFAULT_PROFILE
1494                        } ), e2 );
1495 
1496                }
1497                catch ( final Exception e2 )
1498                {
1499                    throw new ToolException( this.getMessage( "failedGettingTemplate", new Object[]
1500                        {
1501                            templateName
1502                        } ), e2 );
1503 
1504                }
1505            }
1506            catch ( final Exception e )
1507            {
1508                throw new ToolException( this.getMessage( "failedGettingTemplate", new Object[]
1509                    {
1510                        templateName
1511                    } ), e );
1512 
1513            }
1514        }
1515 
1516        return template;
1517    }
1518 
1519    /**
1520     * Notifies registered listeners.
1521     *
1522     * @param level The level of the event.
1523     * @param message The message of the event or {@code null}.
1524     * @param throwable The throwable of the event or {@code null}.
1525     *
1526     * @throws NullPointerException if {@code level} is {@code null}.
1527     *
1528     * @see #getListeners()
1529     */
1530    protected void log( final Level level, final String message, final Throwable throwable )
1531    {
1532        if ( level == null )
1533        {
1534            throw new NullPointerException( "level" );
1535        }
1536 
1537        if ( this.isLoggable( level ) )
1538        {
1539            for ( Listener l : this.getListeners() )
1540            {
1541                l.onLog( level, message, throwable );
1542            }
1543        }
1544    }
1545 
1546    private String getJavaPackageName( final String identifier )
1547    {
1548        if ( identifier == null )
1549        {
1550            throw new NullPointerException( "identifier" );
1551        }
1552 
1553        final int idx = identifier.lastIndexOf( '.' );
1554        return idx != -1 ? identifier.substring( 0, idx ) : "";
1555    }
1556 
1557    private String getMessage( final String key, final Object args )
1558    {
1559        if ( key == null )
1560        {
1561            throw new NullPointerException( "key" );
1562        }
1563 
1564        final ResourceBundle b = ResourceBundle.getBundle( JomcTool.class.getName().replace( '.', '/' ) );
1565        return args == null ? b.getString( key ) : new MessageFormat( b.getString( key ) ).format( args );
1566    }
1567 
1568}

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