001/* 002 * Copyright (C) Christian Schulte <cs@schulte.it>, 2005-206 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without 006 * modification, are permitted provided that the following conditions 007 * are met: 008 * 009 * o Redistributions of source code must retain the above copyright 010 * notice, this list of conditions and the following disclaimer. 011 * 012 * o Redistributions in binary form must reproduce the above copyright 013 * notice, this list of conditions and the following disclaimer in 014 * the documentation and/or other materials provided with the 015 * distribution. 016 * 017 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 018 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 019 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 020 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, 021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 022 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 023 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 024 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 026 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 027 * 028 * $JOMC: JomcTool.java 5043 2015-05-27 07:03:39Z schulte $ 029 * 030 */ 031package org.jomc.tools; 032 033import java.io.BufferedReader; 034import java.io.ByteArrayInputStream; 035import java.io.ByteArrayOutputStream; 036import java.io.FileNotFoundException; 037import java.io.IOException; 038import java.io.InputStream; 039import java.io.InputStreamReader; 040import java.io.OutputStreamWriter; 041import java.io.Reader; 042import java.io.StringReader; 043import java.lang.ref.Reference; 044import java.lang.ref.SoftReference; 045import java.lang.reflect.InvocationTargetException; 046import java.net.URL; 047import java.text.DateFormat; 048import java.text.Format; 049import java.text.MessageFormat; 050import java.text.ParseException; 051import java.text.SimpleDateFormat; 052import java.util.ArrayList; 053import java.util.Calendar; 054import java.util.Collections; 055import java.util.Enumeration; 056import java.util.HashMap; 057import java.util.List; 058import java.util.Locale; 059import java.util.Map; 060import java.util.ResourceBundle; 061import java.util.Set; 062import java.util.concurrent.ConcurrentHashMap; 063import java.util.concurrent.CopyOnWriteArrayList; 064import java.util.concurrent.CopyOnWriteArraySet; 065import java.util.logging.Level; 066import javax.activation.MimeTypeParseException; 067import org.apache.commons.io.IOUtils; 068import org.apache.commons.lang.StringEscapeUtils; 069import org.apache.commons.lang.StringUtils; 070import org.apache.velocity.Template; 071import org.apache.velocity.VelocityContext; 072import org.apache.velocity.app.VelocityEngine; 073import org.apache.velocity.exception.ParseErrorException; 074import org.apache.velocity.exception.ResourceNotFoundException; 075import org.apache.velocity.exception.VelocityException; 076import org.apache.velocity.runtime.RuntimeConstants; 077import org.apache.velocity.runtime.RuntimeServices; 078import org.apache.velocity.runtime.log.LogChute; 079import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; 080import org.apache.velocity.runtime.resource.loader.URLResourceLoader; 081import org.jomc.model.Argument; 082import org.jomc.model.Dependency; 083import org.jomc.model.Implementation; 084import org.jomc.model.InheritanceModel; 085import org.jomc.model.JavaIdentifier; 086import org.jomc.model.JavaTypeName; 087import org.jomc.model.Message; 088import org.jomc.model.ModelObject; 089import org.jomc.model.ModelObjectException; 090import org.jomc.model.Modules; 091import org.jomc.model.Multiplicity; 092import org.jomc.model.Property; 093import org.jomc.model.Specification; 094import org.jomc.model.SpecificationReference; 095import org.jomc.model.Text; 096import org.jomc.model.Texts; 097import org.jomc.model.modlet.ModelHelper; 098import org.jomc.modlet.Model; 099 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 */ 106public 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}