EMMA Coverage Report (generated Wed Feb 03 01:24:19 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%  (1249/1716)72%  (254.1/353)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JomcTool100% (1/1)86%  (49/57)72%  (1209/1670)72%  (242.1/338)
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)
getMessage (String, Object []): String 100% (1/1)72%  (13/18)67%  (2/3)
getJavaPackageName (String): String 100% (1/1)76%  (16/21)75%  (3/4)
getJavaTypeName (Argument): String 100% (1/1)82%  (23/28)75%  (6/8)
getVelocityTemplate (String): Template 100% (1/1)82%  (157/191)83%  (25/30)
log (Level, String, Throwable): void 100% (1/1)83%  (24/29)83%  (5/6)
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% (33/33)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% (29/29)100% (4/4)
getOutputEncoding (): String 100% (1/1)100% (32/32)100% (5/5)
getProfile (): String 100% (1/1)100% (29/29)100% (6/6)
getTemplateEncoding (): String 100% (1/1)100% (32/32)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 1435 2010-01-30 01:52:40Z 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 1435 2010-01-30 01:52:40Z 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, getMessage( "defaultLogLevelInfo", this.getClass().getCanonicalName(),
264                                                this.logLevel.getLocalizedName() ), null );
265 
266        }
267 
268        return this.logLevel;
269    }
270 
271    /**
272     * Sets the log level of the instance.
273     *
274     * @param value The new log level of the instance or {@code null}.
275     *
276     * @see #getLogLevel()
277     * @see #isLoggable(java.util.logging.Level)
278     */
279    public void setLogLevel( final Level value )
280    {
281        this.logLevel = value;
282    }
283 
284    /**
285     * Checks if a message at a given level is provided to the listeners of the instance.
286     *
287     * @param level The level to test.
288     *
289     * @return {@code true} if messages at {@code level} are provided to the listeners of the instance;
290     * {@code false} if messages at {@code level} are not provided to the listeners of the instance.
291     *
292     * @throws NullPointerException if {@code level} is {@code null}.
293     *
294     * @see #getLogLevel()
295     * @see #setLogLevel(java.util.logging.Level)
296     * @see #log(java.util.logging.Level, java.lang.String, java.lang.Throwable)
297     */
298    public boolean isLoggable( final Level level )
299    {
300        if ( level == null )
301        {
302            throw new NullPointerException( "level" );
303        }
304 
305        return level.intValue() >= this.getLogLevel().intValue();
306    }
307 
308    /**
309     * Gets the Java package name of a specification.
310     *
311     * @param specification The specification to get the Java package name of.
312     *
313     * @return The Java package name of {@code specification} or {@code null}.
314     *
315     * @throws NullPointerException if {@code specification} is {@code null}.
316     */
317    public String getJavaPackageName( final Specification specification )
318    {
319        if ( specification == null )
320        {
321            throw new NullPointerException( "specification" );
322        }
323 
324        return specification.getClazz() != null ? this.getJavaPackageName( specification.getClazz() ) : null;
325    }
326 
327    /**
328     * Gets the Java type name of a specification.
329     *
330     * @param specification The specification to get the Java type name of.
331     * @param qualified {@code true} to return the fully qualified type name (with package name prepended);
332     * {@code false} to return the short type name (without package name prepended).
333     *
334     * @return The Java type name of {@code specification} or {@code null}.
335     *
336     * @throws NullPointerException if {@code specification} is {@code null}.
337     */
338    public String getJavaTypeName( final Specification specification, final boolean qualified )
339    {
340        if ( specification == null )
341        {
342            throw new NullPointerException( "specification" );
343        }
344 
345        if ( specification.getClazz() != null )
346        {
347            final StringBuilder typeName = new StringBuilder();
348            final String javaPackageName = this.getJavaPackageName( specification );
349 
350            if ( qualified && javaPackageName.length() > 0 )
351            {
352                typeName.append( javaPackageName ).append( '.' );
353            }
354 
355            typeName.append( javaPackageName.length() > 0
356                             ? specification.getClazz().substring( javaPackageName.length() + 1 )
357                             : specification.getClazz() );
358 
359            return typeName.toString();
360        }
361 
362        return null;
363    }
364 
365    /**
366     * Gets the Java class path location of a specification.
367     *
368     * @param specification The specification to return the Java class path location of.
369     *
370     * @return The Java class path location of {@code specification} or {@code null}.
371     *
372     * @throws NullPointerException if {@code specification} is {@code null}.
373     */
374    public String getJavaClasspathLocation( final Specification specification )
375    {
376        if ( specification == null )
377        {
378            throw new NullPointerException( "specification" );
379        }
380 
381        return specification.getClazz() != null
382               ? ( this.getJavaTypeName( specification, true ) ).replace( '.', '/' )
383               : null;
384 
385    }
386 
387    /**
388     * Gets the Java package name of a specification reference.
389     *
390     * @param reference The specification reference to get the Java package name of.
391     *
392     * @return The Java package name of {@code reference} or {@code null}.
393     *
394     * @throws NullPointerException if {@code reference} is {@code null}.
395     */
396    public String getJavaPackageName( final SpecificationReference reference )
397    {
398        if ( reference == null )
399        {
400            throw new NullPointerException( "reference" );
401        }
402 
403        final Specification s = this.getModules().getSpecification( reference.getIdentifier() );
404        assert s != null : "Specification '" + reference.getIdentifier() + "' not found.";
405        return s.getClazz() != null ? this.getJavaPackageName( s ) : null;
406    }
407 
408    /**
409     * Gets the name of a Java type of a given specification reference.
410     *
411     * @param reference The specification reference to get a 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 reference} or {@code null}.
416     *
417     * @throws NullPointerException if {@code reference} is {@code null}.
418     */
419    public String getJavaTypeName( final SpecificationReference reference, final boolean qualified )
420    {
421        if ( reference == null )
422        {
423            throw new NullPointerException( "reference" );
424        }
425 
426        final Specification s = this.getModules().getSpecification( reference.getIdentifier() );
427        assert s != null : "Specification '" + reference.getIdentifier() + "' not found.";
428        return s.getClazz() != null ? this.getJavaTypeName( s, qualified ) : null;
429    }
430 
431    /**
432     * Gets the Java package name of an implementation.
433     *
434     * @param implementation The implementation to get the Java package name of.
435     *
436     * @return The Java package name of {@code implementation} or {@code null}.
437     *
438     * @throws NullPointerException if {@code implementation} is {@code null}.
439     */
440    public String getJavaPackageName( final Implementation implementation )
441    {
442        if ( implementation == null )
443        {
444            throw new NullPointerException( "implementation" );
445        }
446 
447        return implementation.getClazz() != null ? this.getJavaPackageName( implementation.getClazz() ) : null;
448    }
449 
450    /**
451     * Gets the Java type name of an implementation.
452     *
453     * @param implementation The implementation to get the Java type name of.
454     * @param qualified {@code true} to return the fully qualified type name (with package name prepended);
455     * {@code false} to return the short type name (without package name prepended).
456     *
457     * @return The Java type name of {@code implementation} or {@code null}.
458     *
459     * @throws NullPointerException if {@code implementation} is {@code null}.
460     */
461    public String getJavaTypeName( final Implementation implementation, final boolean qualified )
462    {
463        if ( implementation == null )
464        {
465            throw new NullPointerException( "implementation" );
466        }
467 
468        if ( implementation.getClazz() != null )
469        {
470            final StringBuilder typeName = new StringBuilder();
471            final String javaPackageName = this.getJavaPackageName( implementation );
472 
473            if ( qualified && javaPackageName.length() > 0 )
474            {
475                typeName.append( javaPackageName ).append( '.' );
476            }
477 
478            typeName.append( javaPackageName.length() > 0
479                             ? implementation.getClazz().substring( javaPackageName.length() + 1 )
480                             : implementation.getClazz() );
481 
482            return typeName.toString();
483        }
484 
485        return null;
486    }
487 
488    /**
489     * Gets the Java class path location of an implementation.
490     *
491     * @param implementation The implementation to return the Java class path location of.
492     *
493     * @return The Java class path location of {@code implementation} or {@code null}.
494     *
495     * @throws NullPointerException if {@code implementation} is {@code null}.
496     */
497    public String getJavaClasspathLocation( final Implementation implementation )
498    {
499        if ( implementation == null )
500        {
501            throw new NullPointerException( "implementation" );
502        }
503 
504        return implementation.getClazz() != null
505               ? ( this.getJavaTypeName( implementation, true ) ).replace( '.', '/' )
506               : null;
507 
508    }
509 
510    /**
511     * Gets all Java interfaces an implementation implements.
512     *
513     * @param implementation The implementation to get all implemented Java interfaces of.
514     * @param qualified {@code true} to return the fully qualified type names (with package name prepended);
515     * {@code false} to return the short type names (without package name prepended).
516     *
517     * @return Unmodifiable list contaning all Java interfaces implemented by {@code implementation}.
518     *
519     * @throws NullPointerException if {@code implementation} is {@code null}.
520     */
521    public List<String> getJavaInterfaceNames( final Implementation implementation, final boolean qualified )
522    {
523        if ( implementation == null )
524        {
525            throw new NullPointerException( "implementation" );
526        }
527 
528        final Specifications specs = this.getModules().getSpecifications( implementation.getIdentifier() );
529        final List<String> col = new ArrayList<String>( specs == null ? 0 : specs.getSpecification().size() );
530 
531        if ( specs != null )
532        {
533            for ( Specification s : specs.getSpecification() )
534            {
535                if ( s.getClazz() != null )
536                {
537                    final String typeName = this.getJavaTypeName( s, qualified );
538                    if ( !col.contains( typeName ) )
539                    {
540                        col.add( typeName );
541                    }
542                }
543            }
544        }
545 
546        return Collections.unmodifiableList( col );
547    }
548 
549    /**
550     * Gets the Java type name of an argument.
551     *
552     * @param argument The argument to get the Java type name of.
553     *
554     * @return The Java type name of {@code argument}.
555     *
556     * @throws NullPointerException if {@code argument} is {@code null}.
557     */
558    public String getJavaTypeName( final Argument argument )
559    {
560        if ( argument == null )
561        {
562            throw new NullPointerException( "argument" );
563        }
564 
565        String javaTypeName = "java.lang.String";
566 
567        if ( argument.getType() == ArgumentType.DATE || argument.getType() == ArgumentType.TIME )
568        {
569            javaTypeName = "java.util.Date";
570        }
571        else if ( argument.getType() == ArgumentType.NUMBER )
572        {
573            javaTypeName = "java.lang.Number";
574        }
575 
576        return javaTypeName;
577    }
578 
579    /**
580     * Gets the Java type name of a property.
581     *
582     * @param property The property to get the Java type name of.
583     * @param boxify {@code true} to return the name of the Java wrapper class when the type is a Java primitive type;
584     * {@code false} to return the exact binary name (unboxed name) of the Java type.
585     *
586     * @return The Java type name of {@code property}.
587     *
588     * @throws NullPointerException if {@code property} is {@code null}.
589     */
590    public String getJavaTypeName( final Property property, final boolean boxify )
591    {
592        if ( property == null )
593        {
594            throw new NullPointerException( "property" );
595        }
596 
597        if ( property.getType() != null )
598        {
599            final String typeName = property.getType();
600 
601            if ( boxify )
602            {
603                if ( Boolean.TYPE.getName().equals( typeName ) )
604                {
605                    return Boolean.class.getName();
606                }
607                if ( Byte.TYPE.getName().equals( typeName ) )
608                {
609                    return Byte.class.getName();
610                }
611                if ( Character.TYPE.getName().equals( typeName ) )
612                {
613                    return Character.class.getName();
614                }
615                if ( Double.TYPE.getName().equals( typeName ) )
616                {
617                    return Double.class.getName();
618                }
619                if ( Float.TYPE.getName().equals( typeName ) )
620                {
621                    return Float.class.getName();
622                }
623                if ( Integer.TYPE.getName().equals( typeName ) )
624                {
625                    return Integer.class.getName();
626                }
627                if ( Long.TYPE.getName().equals( typeName ) )
628                {
629                    return Long.class.getName();
630                }
631                if ( Short.TYPE.getName().equals( typeName ) )
632                {
633                    return Short.class.getName();
634                }
635            }
636 
637            return typeName;
638        }
639 
640        return property.getAny() != null ? Object.class.getName() : String.class.getName();
641    }
642 
643    /**
644     * Gets a flag indicating if the type of a given property is a Java primitive.
645     *
646     * @param property The property to query.
647     *
648     * @return {@code true} if the type of {@code property} is a Java primitive; {@code false} if not.
649     *
650     * @throws NullPointerException if {@code property} is {@code null}.
651     */
652    public boolean isJavaPrimitiveType( final Property property )
653    {
654        if ( property == null )
655        {
656            throw new NullPointerException( "property" );
657        }
658 
659        return !this.getJavaTypeName( property, false ).equals( this.getJavaTypeName( property, true ) );
660    }
661 
662    /**
663     * Gets the name of a Java accessor method of a given property.
664     *
665     * @param property The property to get a Java accessor method name of.
666     *
667     * @return The Java accessor method name of {@code property}.
668     *
669     * @throws NullPointerException if {@code property} is {@code null}.
670     */
671    public String getJavaGetterMethodName( final Property property )
672    {
673        if ( property == null )
674        {
675            throw new NullPointerException( "property" );
676        }
677 
678        final char[] name = property.getName().toCharArray();
679        name[0] = Character.toUpperCase( name[0] );
680        String prefix = "get";
681 
682        final String javaTypeName = this.getJavaTypeName( property, true );
683        if ( Boolean.class.getName().equals( javaTypeName ) )
684        {
685            prefix = "is";
686        }
687 
688        return prefix + String.valueOf( name );
689    }
690 
691    /**
692     * Gets the name of a Java type of a given dependency.
693     *
694     * @param dependency The dependency to get a dependency Java type name of.
695     *
696     * @return The Java type name of {@code dependency} or {@code null}.
697     *
698     * @throws NullPointerException if {@code dependency} is {@code null}.
699     */
700    public String getJavaTypeName( final Dependency dependency )
701    {
702        if ( dependency == null )
703        {
704            throw new NullPointerException( "dependency" );
705        }
706 
707        final Specification s = this.getModules().getSpecification( dependency.getIdentifier() );
708 
709        if ( s != null && s.getClazz() != null )
710        {
711            final StringBuilder typeName = new StringBuilder();
712            typeName.append( this.getJavaTypeName( s, true ) );
713            if ( s.getMultiplicity() == Multiplicity.MANY && dependency.getImplementationName() == null )
714            {
715                typeName.append( "[]" );
716            }
717 
718            return typeName.toString();
719        }
720 
721        return null;
722    }
723 
724    /**
725     * Gets the name of a Java accessor method of a given dependency.
726     *
727     * @param dependency The dependency to get a Java accessor method name of.
728     *
729     * @return The Java accessor method name of {@code dependency}.
730     *
731     * @throws NullPointerException if {@code dependency} is {@code null}.
732     */
733    public String getJavaGetterMethodName( final Dependency dependency )
734    {
735        if ( dependency == null )
736        {
737            throw new NullPointerException( "dependency" );
738        }
739 
740        final char[] name = dependency.getName().toCharArray();
741        name[0] = Character.toUpperCase( name[0] );
742        return "get" + String.valueOf( name );
743    }
744 
745    /**
746     * Gets the name of a Java accessor method of a given message.
747     *
748     * @param message The message to get a Java accessor method name of.
749     *
750     * @return The Java accessor method name of {@code message}.
751     *
752     * @throws NullPointerException if {@code message} is {@code null}.
753     */
754    public String getJavaGetterMethodName( final Message message )
755    {
756        if ( message == null )
757        {
758            throw new NullPointerException( "message" );
759        }
760 
761        final char[] name = message.getName().toCharArray();
762        name[0] = Character.toUpperCase( name[0] );
763        return "get" + String.valueOf( name ) + "Message";
764    }
765 
766    /**
767     * Gets the name of a Java modifier of a dependency of a given implementation.
768     *
769     * @param implementation The implementation to get a dependency Java modifier name of.
770     * @param dependency The dependency to get a Java modifier name of.
771     *
772     * @return The Java modifier name of {@code dependency} of {@code implementation}.
773     *
774     * @throws NullPointerException if {@code implementation} or {@code dependency} is {@code null}.
775     */
776    public String getJavaModifierName( final Implementation implementation, final Dependency dependency )
777    {
778        if ( implementation == null )
779        {
780            throw new NullPointerException( "implementation" );
781        }
782        if ( dependency == null )
783        {
784            throw new NullPointerException( "dependency" );
785        }
786 
787        return "private";
788    }
789 
790    /**
791     * Gets the name of a Java modifier of a message of a given implementation.
792     *
793     * @param implementation The implementation to get a message Java modifier name of.
794     * @param message The message to get a Java modifier name of.
795     *
796     * @return The Java modifier name of {@code message} of {@code implementation}.
797     *
798     * @throws NullPointerException if {@code implementation} or {@code message} is {@code null}.
799     */
800    public String getJavaModifierName( final Implementation implementation, final Message message )
801    {
802        if ( implementation == null )
803        {
804            throw new NullPointerException( "implementation" );
805        }
806        if ( message == null )
807        {
808            throw new NullPointerException( "message" );
809        }
810 
811        return "private";
812    }
813 
814    /**
815     * Gets the name of a Java modifier for a given property of a given implementation.
816     *
817     * @param implementation The implementation declaring {@code property}.
818     * @param property The property to get a Java modifier name for.
819     *
820     * @return The Java modifier name for {@code property} of {@code implementation}.
821     *
822     * @throws NullPointerException if {@code implementation} or {@code property} is {@code null}.
823     */
824    public String getJavaModifierName( final Implementation implementation, final Property property )
825    {
826        if ( implementation == null )
827        {
828            throw new NullPointerException( "implementation" );
829        }
830        if ( property == null )
831        {
832            throw new NullPointerException( "property" );
833        }
834 
835        String modifier = "private";
836        final Properties specified = this.getModules().getSpecifiedProperties( implementation.getIdentifier() );
837 
838        if ( specified != null && specified.getProperty( property.getName() ) != null )
839        {
840            modifier = "public";
841        }
842 
843        return modifier;
844    }
845 
846    /**
847     * Formats a text to a Javadoc comment.
848     *
849     * @param text The text to format to a Javadoc comment.
850     * @param linebreak The text to replace line breaks with.
851     *
852     * @return {@code text} formatted as a Javadoc comment.
853     *
854     * @throws NullPointerException if {@code text} or {@code linebreak} is {@code null}.
855     */
856    public String getJavadocComment( final Text text, final String linebreak )
857    {
858        if ( text == null )
859        {
860            throw new NullPointerException( "text" );
861        }
862        if ( linebreak == null )
863        {
864            throw new NullPointerException( "linebreak" );
865        }
866 
867        String normalized = text.getValue();
868        normalized = normalized.replaceAll( "\\/\\*\\*", "/*" );
869        normalized = normalized.replaceAll( "\\*/", "/" );
870        normalized = normalized.replaceAll( "\n", "\n" + linebreak );
871        return StringEscapeUtils.escapeHtml( normalized );
872    }
873 
874    /**
875     * Formats a string to a Java string with unicode escapes.
876     *
877     * @param str The string to format to a Java string or {@code null}.
878     *
879     * @return {@code str} formatted as a Java string or {@code null}.
880     */
881    public String getJavaString( final String str )
882    {
883        return StringEscapeUtils.escapeJava( str );
884    }
885 
886    /**
887     * Gets a flag indicating if the class of a given specification is located in the Java default package.
888     *
889     * @param specification The specification to test.
890     *
891     * @return {@code true} if the class of {@code specification} is located in the Java default package; {@code false}
892     * if not.
893     *
894     * @throws NullPointerException if {@code specification} is {@code null}.
895     */
896    public boolean isJavaDefaultPackage( final Specification specification )
897    {
898        if ( specification == null )
899        {
900            throw new NullPointerException( "specification" );
901        }
902 
903        return specification.getClazz() != null && this.getJavaPackageName( specification ).length() == 0;
904    }
905 
906    /**
907     * Gets a flag indicating if the class of a given implementation is located in the Java default package.
908     *
909     * @param implementation The implementation to test.
910     *
911     * @return {@code true} if the class of {@code implementation} is located in the Java default package; {@code false}
912     * if not.
913     *
914     * @throws NullPointerException if {@code implementation} is {@code null}.
915     */
916    public boolean isJavaDefaultPackage( final Implementation implementation )
917    {
918        if ( implementation == null )
919        {
920            throw new NullPointerException( "implementation" );
921        }
922 
923        return implementation.getClazz() != null && this.getJavaPackageName( implementation ).length() == 0;
924    }
925 
926    /**
927     * Gets the display language of a given language code.
928     *
929     * @param language The language code to get the display language of.
930     *
931     * @return The display language of {@code language}.
932     *
933     * @throws NullPointerException if {@code language} is {@code null}.
934     */
935    public String getDisplayLanguage( final String language )
936    {
937        if ( language == null )
938        {
939            throw new NullPointerException( "language" );
940        }
941 
942        final Locale locale = new Locale( language );
943        return locale.getDisplayLanguage( locale );
944    }
945 
946    /**
947     * Formats a calendar instance to a string.
948     *
949     * @param calendar The calendar to format.
950     *
951     * @return Date of {@code calendar} formatted using a short format style pattern.
952     *
953     * @throws NullPointerException if {@code calendar} is {@code null}.
954     *
955     * @see DateFormat#SHORT
956     */
957    public String getShortDate( final Calendar calendar )
958    {
959        if ( calendar == null )
960        {
961            throw new NullPointerException( "calendar" );
962        }
963 
964        return DateFormat.getDateInstance( DateFormat.SHORT ).format( calendar.getTime() );
965    }
966 
967    /**
968     * Formats a calendar instance to a string.
969     *
970     * @param calendar The calendar to format.
971     *
972     * @return Date of {@code calendar} formatted using a long format style pattern.
973     *
974     * @throws NullPointerException if {@code calendar} is {@code null}.
975     *
976     * @see DateFormat#LONG
977     */
978    public String getLongDate( final Calendar calendar )
979    {
980        if ( calendar == null )
981        {
982            throw new NullPointerException( "calendar" );
983        }
984 
985        return DateFormat.getDateInstance( DateFormat.LONG ).format( calendar.getTime() );
986    }
987 
988    /**
989     * Formats a calendar instance to a string.
990     *
991     * @param calendar The calendar to format.
992     *
993     * @return Time of {@code calendar} formatted using a short format style pattern.
994     *
995     * @throws NullPointerException if {@code calendar} is {@code null}.
996     *
997     * @see DateFormat#SHORT
998     */
999    public String getShortTime( final Calendar calendar )
1000    {
1001        if ( calendar == null )
1002        {
1003            throw new NullPointerException( "calendar" );
1004        }
1005 
1006        return DateFormat.getTimeInstance( DateFormat.SHORT ).format( calendar.getTime() );
1007    }
1008 
1009    /**
1010     * Formats a calendar instance to a string.
1011     *
1012     * @param calendar The calendar to format.
1013     *
1014     * @return Time of {@code calendar} formatted using a long format style pattern.
1015     *
1016     * @throws NullPointerException if {@code calendar} is {@code null}.
1017     *
1018     * @see DateFormat#LONG
1019     */
1020    public String getLongTime( final Calendar calendar )
1021    {
1022        if ( calendar == null )
1023        {
1024            throw new NullPointerException( "calendar" );
1025        }
1026 
1027        return DateFormat.getTimeInstance( DateFormat.LONG ).format( calendar.getTime() );
1028    }
1029 
1030    /**
1031     * Formats a calendar instance to a string.
1032     *
1033     * @param calendar The calendar to format.
1034     *
1035     * @return Date and time of {@code calendar} formatted using a short format style pattern.
1036     *
1037     * @throws NullPointerException if {@code calendar} is {@code null}.
1038     *
1039     * @see DateFormat#SHORT
1040     */
1041    public String getShortDateTime( final Calendar calendar )
1042    {
1043        if ( calendar == null )
1044        {
1045            throw new NullPointerException( "calendar" );
1046        }
1047 
1048        return DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT ).format( calendar.getTime() );
1049    }
1050 
1051    /**
1052     * Formats a calendar instance to a string.
1053     *
1054     * @param calendar The calendar to format.
1055     *
1056     * @return Date and time of {@code calendar} formatted using a long format style pattern.
1057     *
1058     * @throws NullPointerException if {@code calendar} is {@code null}.
1059     *
1060     * @see DateFormat#LONG
1061     */
1062    public String getLongDateTime( final Calendar calendar )
1063    {
1064        if ( calendar == null )
1065        {
1066            throw new NullPointerException( "calendar" );
1067        }
1068 
1069        return DateFormat.getDateTimeInstance( DateFormat.LONG, DateFormat.LONG ).format( calendar.getTime() );
1070    }
1071 
1072    /**
1073     * Gets a string describing the range of years for given calendars.
1074     *
1075     * @param start The start of the range.
1076     * @param end The end of the range.
1077     *
1078     * @return Formatted range of the years of {@code start} and {@code end}.
1079     *
1080     * @throws NullPointerException if {@code start} or {@code end} is {@code null}.
1081     */
1082    public String getYears( final Calendar start, final Calendar end )
1083    {
1084        if ( start == null )
1085        {
1086            throw new NullPointerException( "start" );
1087        }
1088        if ( end == null )
1089        {
1090            throw new NullPointerException( "end" );
1091        }
1092 
1093        final Format yearFormat = new SimpleDateFormat( "yyyy" );
1094        final int s = start.get( Calendar.YEAR );
1095        final int e = end.get( Calendar.YEAR );
1096        final StringBuilder years = new StringBuilder();
1097 
1098        if ( s != e )
1099        {
1100            if ( s < e )
1101            {
1102                years.append( yearFormat.format( start.getTime() ) ).append( " - " ).
1103                    append( yearFormat.format( end.getTime() ) );
1104 
1105            }
1106            else
1107            {
1108                years.append( yearFormat.format( end.getTime() ) ).append( " - " ).
1109                    append( yearFormat.format( start.getTime() ) );
1110 
1111            }
1112        }
1113        else
1114        {
1115            years.append( yearFormat.format( start.getTime() ) );
1116        }
1117 
1118        return years.toString();
1119    }
1120 
1121    /**
1122     * Gets the modules of the instance.
1123     *
1124     * @return The modules of the instance.
1125     *
1126     * @see #setModules(org.jomc.model.Modules)
1127     */
1128    public Modules getModules()
1129    {
1130        if ( this.modules == null )
1131        {
1132            this.modules = new Modules();
1133        }
1134 
1135        return this.modules;
1136    }
1137 
1138    /**
1139     * Sets the modules of the instance.
1140     *
1141     * @param value The new modules of the instance.
1142     *
1143     * @see #getModules()
1144     */
1145    public void setModules( final Modules value )
1146    {
1147        this.modules = value;
1148    }
1149 
1150    /**
1151     * Gets the {@code VelocityEngine} used for generating source code.
1152     *
1153     * @return The {@code VelocityEngine} used for generating source code.
1154     *
1155     * @throws ToolException if initializing a new velocity engine fails.
1156     *
1157     * @see #setVelocityEngine(org.apache.velocity.app.VelocityEngine)
1158     */
1159    public VelocityEngine getVelocityEngine() throws ToolException
1160    {
1161        if ( this.velocityEngine == null )
1162        {
1163            try
1164            {
1165                final java.util.Properties props = new java.util.Properties();
1166                props.put( "resource.loader", "class" );
1167                props.put( "class.resource.loader.class", VELOCITY_RESOURCE_LOADER );
1168                props.put( "runtime.references.strict", Boolean.TRUE.toString() );
1169 
1170                final VelocityEngine engine = new VelocityEngine();
1171                engine.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM, new LogChute()
1172                {
1173 
1174                    public void init( final RuntimeServices runtimeServices ) throws Exception
1175                    {
1176                    }
1177 
1178                    public void log( final int level, final String message )
1179                    {
1180                        this.log( level, message, null );
1181                    }
1182 
1183                    public void log( final int level, final String message, final Throwable throwable )
1184                    {
1185                        JomcTool.this.log( this.toToolLevel( level ), message, throwable );
1186                    }
1187 
1188                    public boolean isLevelEnabled( final int level )
1189                    {
1190                        return isLoggable( this.toToolLevel( level ) );
1191                    }
1192 
1193                    private Level toToolLevel( final int logChuteLevel )
1194                    {
1195                        switch ( logChuteLevel )
1196                        {
1197                            case LogChute.DEBUG_ID:
1198                                return Level.FINE;
1199 
1200                            case LogChute.ERROR_ID:
1201                                return Level.SEVERE;
1202 
1203                            case LogChute.INFO_ID:
1204                                return Level.INFO;
1205 
1206                            case LogChute.TRACE_ID:
1207                                return Level.FINER;
1208 
1209                            case LogChute.WARN_ID:
1210                                return Level.WARNING;
1211 
1212                            default:
1213                                return Level.FINEST;
1214 
1215                        }
1216                    }
1217 
1218                } );
1219 
1220                engine.init( props );
1221                this.velocityEngine = engine;
1222                this.templateCache.clear();
1223            }
1224            catch ( final Exception e )
1225            {
1226                throw new ToolException( e );
1227            }
1228        }
1229 
1230        return this.velocityEngine;
1231    }
1232 
1233    /**
1234     * Sets the {@code VelocityEngine} of the instance.
1235     *
1236     * @param value The new {@code VelocityEngine} of the instance.
1237     *
1238     * @see #getVelocityEngine()
1239     */
1240    public void setVelocityEngine( final VelocityEngine value )
1241    {
1242        this.velocityEngine = value;
1243    }
1244 
1245    /**
1246     * Gets the velocity context used for merging templates.
1247     *
1248     * @return The velocity context used for merging templates.
1249     */
1250    public VelocityContext getVelocityContext()
1251    {
1252        final Date now = new Date();
1253        final VelocityContext ctx = new VelocityContext();
1254        ctx.put( "modules", this.getModules() );
1255        ctx.put( "tool", this );
1256        ctx.put( "calendar", Calendar.getInstance() );
1257        ctx.put( "now", new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ" ).format( now ) );
1258        ctx.put( "year", new SimpleDateFormat( "yyyy" ).format( now ) );
1259        ctx.put( "month", new SimpleDateFormat( "MM" ).format( now ) );
1260        ctx.put( "day", new SimpleDateFormat( "dd" ).format( now ) );
1261        ctx.put( "hour", new SimpleDateFormat( "HH" ).format( now ) );
1262        ctx.put( "minute", new SimpleDateFormat( "mm" ).format( now ) );
1263        ctx.put( "second", new SimpleDateFormat( "ss" ).format( now ) );
1264        ctx.put( "timezone", new SimpleDateFormat( "Z" ).format( now ) );
1265        return ctx;
1266    }
1267 
1268    /**
1269     * Gets the encoding to use for reading templates.
1270     *
1271     * @return The encoding to use for reading templates.
1272     *
1273     * @see #setTemplateEncoding(java.lang.String)
1274     */
1275    public String getTemplateEncoding()
1276    {
1277        if ( this.templateEncoding == null )
1278        {
1279            this.templateEncoding = getMessage( "buildSourceEncoding" );
1280            this.templateCache.clear();
1281            if ( this.isLoggable( Level.CONFIG ) )
1282            {
1283                this.log( Level.CONFIG, getMessage( "defaultTemplateEncoding", this.templateEncoding ), null );
1284            }
1285        }
1286 
1287        return this.templateEncoding;
1288    }
1289 
1290    /**
1291     * Sets the encoding to use for reading templates.
1292     *
1293     * @param value The encoding to use for reading templates.
1294     *
1295     * @see #getTemplateEncoding()
1296     */
1297    public void setTemplateEncoding( final String value )
1298    {
1299        this.templateEncoding = value;
1300        this.templateCache.clear();
1301    }
1302 
1303    /**
1304     * Gets the encoding to use for reading files.
1305     *
1306     * @return The encoding to use for reading files.
1307     *
1308     * @see #setInputEncoding(java.lang.String)
1309     */
1310    public String getInputEncoding()
1311    {
1312        if ( this.inputEncoding == null )
1313        {
1314            this.inputEncoding = new InputStreamReader( new ByteArrayInputStream( NO_BYTES ) ).getEncoding();
1315            if ( this.isLoggable( Level.CONFIG ) )
1316            {
1317                this.log( Level.CONFIG, getMessage( "defaultInputEncoding", this.inputEncoding ), null );
1318            }
1319        }
1320 
1321        return this.inputEncoding;
1322    }
1323 
1324    /**
1325     * Sets the encoding to use for reading files.
1326     *
1327     * @param value The encoding to use for reading files.
1328     *
1329     * @see #getInputEncoding()
1330     */
1331    public void setInputEncoding( final String value )
1332    {
1333        this.inputEncoding = value;
1334    }
1335 
1336    /**
1337     * Gets the encoding to use for writing files.
1338     *
1339     * @return The encoding to use for writing files.
1340     *
1341     * @see #setOutputEncoding(java.lang.String)
1342     */
1343    public String getOutputEncoding()
1344    {
1345        if ( this.outputEncoding == null )
1346        {
1347            this.outputEncoding = new OutputStreamWriter( new ByteArrayOutputStream() ).getEncoding();
1348            if ( this.isLoggable( Level.CONFIG ) )
1349            {
1350                this.log( Level.CONFIG, getMessage( "defaultOutputEncoding", this.outputEncoding ), null );
1351            }
1352        }
1353 
1354        return this.outputEncoding;
1355    }
1356 
1357    /**
1358     * Sets the encoding to use for writing files.
1359     *
1360     * @param value The encoding to use for writing files.
1361     *
1362     * @see #getOutputEncoding()
1363     */
1364    public void setOutputEncoding( final String value )
1365    {
1366        this.outputEncoding = value;
1367    }
1368 
1369    /**
1370     * Gets the profile of the instance.
1371     *
1372     * @return The profile of the instance.
1373     *
1374     * @see #setProfile(java.lang.String)
1375     */
1376    public String getProfile()
1377    {
1378        if ( this.profile == null )
1379        {
1380            this.profile = DEFAULT_PROFILE;
1381            this.templateCache.clear();
1382            if ( this.isLoggable( Level.CONFIG ) )
1383            {
1384                this.log( Level.CONFIG, getMessage( "defaultProfile", this.profile ), null );
1385            }
1386        }
1387 
1388        return this.profile;
1389    }
1390 
1391    /**
1392     * Sets the profile of the instance.
1393     *
1394     * @param value The profile of the instance.
1395     *
1396     * @see #getProfile()
1397     */
1398    public void setProfile( final String value )
1399    {
1400        this.profile = value;
1401        this.templateCache.clear();
1402    }
1403 
1404    /**
1405     * Gets a velocity template for a given name.
1406     * <p>This method returns the template corresponding to the profile of the instance. If that template is not found,
1407     * the template of the default profile is returned so that only templates differing from the default templates need
1408     * to be provided when exchanging templates.</p>
1409     *
1410     * @param templateName The name of the template to get.
1411     *
1412     * @return The template matching {@code templateName}.
1413     *
1414     * @throws NullPointerException if {@code templateName} is {@code null}.
1415     * @throws ToolException if getting the template fails.
1416     *
1417     * @see #getProfile()
1418     * @see #getTemplateEncoding()
1419     */
1420    public Template getVelocityTemplate( final String templateName ) throws ToolException
1421    {
1422        if ( templateName == null )
1423        {
1424            throw new NullPointerException( "templateName" );
1425        }
1426 
1427        Map<String, Template> templates = this.templateCache.get();
1428        if ( templates == null )
1429        {
1430            templates = new HashMap<String, Template>();
1431            this.templateCache = new WeakReference<Map<String, Template>>( templates );
1432        }
1433 
1434        Template template = templates.get( templateName );
1435 
1436        if ( template == null )
1437        {
1438            try
1439            {
1440                template = this.getVelocityEngine().getTemplate(
1441                    TEMPLATE_PREFIX + this.getProfile() + "/" + templateName, this.getTemplateEncoding() );
1442 
1443                templates.put( templateName, template );
1444 
1445                if ( this.templateCache.get() == null )
1446                {
1447                    this.templateCache = new WeakReference<Map<String, Template>>( templates );
1448                }
1449            }
1450            catch ( final ResourceNotFoundException e )
1451            {
1452                if ( this.isLoggable( Level.CONFIG ) )
1453                {
1454                    this.log( Level.CONFIG, getMessage( "templateNotFound", templateName, this.getProfile() ), e );
1455                }
1456 
1457                try
1458                {
1459                    template = this.getVelocityEngine().getTemplate(
1460                        TEMPLATE_PREFIX + DEFAULT_PROFILE + "/" + templateName, this.getTemplateEncoding() );
1461 
1462                    if ( this.isLoggable( Level.CONFIG ) )
1463                    {
1464                        this.log( Level.CONFIG, getMessage( "defaultTemplate", templateName, DEFAULT_PROFILE ), e );
1465                    }
1466 
1467                    templates.put( templateName, template );
1468 
1469                    if ( this.templateCache.get() == null )
1470                    {
1471                        this.templateCache = new WeakReference<Map<String, Template>>( templates );
1472                    }
1473                }
1474                catch ( final ResourceNotFoundException e2 )
1475                {
1476                    throw new ToolException( getMessage( "templateNotFound", templateName, DEFAULT_PROFILE ), e2 );
1477                }
1478                catch ( final Exception e2 )
1479                {
1480                    throw new ToolException( getMessage( "failedGettingTemplate", templateName ), e2 );
1481                }
1482            }
1483            catch ( final Exception e )
1484            {
1485                throw new ToolException( getMessage( "failedGettingTemplate", templateName ), e );
1486            }
1487        }
1488 
1489        return template;
1490    }
1491 
1492    /**
1493     * Notifies registered listeners.
1494     *
1495     * @param level The level of the event.
1496     * @param message The message of the event or {@code null}.
1497     * @param throwable The throwable of the event or {@code null}.
1498     *
1499     * @throws NullPointerException if {@code level} is {@code null}.
1500     *
1501     * @see #getListeners()
1502     */
1503    protected void log( final Level level, final String message, final Throwable throwable )
1504    {
1505        if ( level == null )
1506        {
1507            throw new NullPointerException( "level" );
1508        }
1509 
1510        if ( this.isLoggable( level ) )
1511        {
1512            for ( Listener l : this.getListeners() )
1513            {
1514                l.onLog( level, message, throwable );
1515            }
1516        }
1517    }
1518 
1519    private String getJavaPackageName( final String identifier )
1520    {
1521        if ( identifier == null )
1522        {
1523            throw new NullPointerException( "identifier" );
1524        }
1525 
1526        final int idx = identifier.lastIndexOf( '.' );
1527        return idx != -1 ? identifier.substring( 0, idx ) : "";
1528    }
1529 
1530    private static String getMessage( final String key, final Object... arguments )
1531    {
1532        if ( key == null )
1533        {
1534            throw new NullPointerException( "key" );
1535        }
1536 
1537        return MessageFormat.format( ResourceBundle.getBundle( JomcTool.class.getName().replace( '.', '/' ) ).
1538            getString( key ), arguments );
1539 
1540    }
1541 
1542}

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