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