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