001/* 002 * Copyright (C) Christian Schulte, 2005-206 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without 006 * modification, are permitted provided that the following conditions 007 * are met: 008 * 009 * o Redistributions of source code must retain the above copyright 010 * notice, this list of conditions and the following disclaimer. 011 * 012 * o Redistributions in binary form must reproduce the above copyright 013 * notice, this list of conditions and the following disclaimer in 014 * the documentation and/or other materials provided with the 015 * distribution. 016 * 017 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 018 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 019 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 020 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, 021 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 022 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 023 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 024 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 025 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 026 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 027 * 028 * $JOMC: AbstractJomcMojo.java 4555 2012-05-24 23:35:41Z schulte2005 $ 029 * 030 */ 031package org.jomc.mojo; 032 033import java.io.BufferedReader; 034import java.io.File; 035import java.io.IOException; 036import java.io.InputStream; 037import java.io.StringReader; 038import java.io.StringWriter; 039import java.net.MalformedURLException; 040import java.net.SocketTimeoutException; 041import java.net.URI; 042import java.net.URISyntaxException; 043import java.net.URL; 044import java.net.URLClassLoader; 045import java.net.URLConnection; 046import java.util.Collection; 047import java.util.Date; 048import java.util.HashSet; 049import java.util.Iterator; 050import java.util.List; 051import java.util.Locale; 052import java.util.Map; 053import java.util.Properties; 054import java.util.Set; 055import java.util.logging.Level; 056import javax.xml.bind.JAXBException; 057import javax.xml.bind.Marshaller; 058import javax.xml.transform.ErrorListener; 059import javax.xml.transform.Transformer; 060import javax.xml.transform.TransformerConfigurationException; 061import javax.xml.transform.TransformerException; 062import javax.xml.transform.TransformerFactory; 063import javax.xml.transform.stream.StreamSource; 064import org.apache.commons.lang.StringEscapeUtils; 065import org.apache.commons.lang.StringUtils; 066import org.apache.maven.artifact.Artifact; 067import org.apache.maven.artifact.ArtifactUtils; 068import org.apache.maven.execution.MavenSession; 069import org.apache.maven.plugin.AbstractMojo; 070import org.apache.maven.plugin.MojoExecutionException; 071import org.apache.maven.plugin.MojoFailureException; 072import org.apache.maven.plugin.descriptor.MojoDescriptor; 073import org.apache.maven.project.MavenProject; 074import org.jomc.model.Module; 075import org.jomc.model.Modules; 076import org.jomc.model.modlet.DefaultModelProcessor; 077import org.jomc.model.modlet.DefaultModelProvider; 078import org.jomc.model.modlet.ModelHelper; 079import org.jomc.modlet.DefaultModelContext; 080import org.jomc.modlet.DefaultModletProvider; 081import org.jomc.modlet.Model; 082import org.jomc.modlet.ModelContext; 083import org.jomc.modlet.ModelContextFactory; 084import org.jomc.modlet.ModelException; 085import org.jomc.modlet.ModelValidationReport; 086import org.jomc.tools.ClassFileProcessor; 087import org.jomc.tools.JomcTool; 088import org.jomc.tools.ResourceFileProcessor; 089import org.jomc.tools.SourceFileProcessor; 090import org.jomc.tools.modlet.ToolsModelProcessor; 091import org.jomc.tools.modlet.ToolsModelProvider; 092 093/** 094 * Base class for executing {@code JomcTool}s. 095 * 096 * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a> 097 * @version $JOMC: AbstractJomcMojo.java 4555 2012-05-24 23:35:41Z schulte2005 $ 098 */ 099public abstract class AbstractJomcMojo extends AbstractMojo 100{ 101 102 /** 103 * The encoding to use for reading and writing files. 104 * 105 * @parameter default-value="${project.build.sourceEncoding}" expression="${jomc.sourceEncoding}" 106 */ 107 private String sourceEncoding; 108 109 /** 110 * The encoding to use for reading templates. 111 * <p><strong>Deprecated:</strong> As of JOMC 1.3, please use the 'defaultTemplateEncoding' parameter. This 112 * parameter will be removed in version 2.0.</p> 113 * 114 * @parameter expression="${jomc.templateEncoding}" 115 */ 116 @Deprecated 117 private String templateEncoding; 118 119 /** 120 * The encoding to use for reading templates. 121 * 122 * @parameter expression="${jomc.defaultTemplateEncoding}" 123 * 124 * @since 1.3 125 */ 126 private String defaultTemplateEncoding; 127 128 /** 129 * Location to search for templates in addition to searching the class path of the plugin. 130 * <p>First an attempt is made to parse the location value to an URL. On successful parsing, that URL is used. 131 * Otherwise the location value is interpreted as a directory name relative to the base directory of the project. 132 * If that directory exists, that directory is used. If nothing is found at the given location, a warning message is 133 * logged.</p> 134 * 135 * @parameter expression="${jomc.templateLocation}" 136 * @since 1.2 137 */ 138 private String templateLocation; 139 140 /** 141 * The template profile to use when accessing templates. 142 * 143 * @parameter expression="${jomc.templateProfile}" 144 */ 145 private String templateProfile; 146 147 /** 148 * The default template profile to use when accessing templates. 149 * 150 * @parameter expression="${jomc.defaultTemplateProfile}" 151 */ 152 private String defaultTemplateProfile; 153 154 /** 155 * The location to search for providers. 156 * 157 * @parameter expression="${jomc.providerLocation}" 158 */ 159 private String providerLocation; 160 161 /** 162 * The location to search for platform providers. 163 * 164 * @parameter expression="${jomc.platformProviderLocation}" 165 */ 166 private String platformProviderLocation; 167 168 /** 169 * The identifier of the model to process. 170 * 171 * @parameter default-value="http://jomc.org/model" expression="${jomc.model}" 172 */ 173 private String model; 174 175 /** 176 * The name of the {@code ModelContextFactory} implementation class backing the task. 177 * 178 * @parameter expression="${jomc.modelContextFactoryClassName}" 179 * @since 1.2 180 */ 181 private String modelContextFactoryClassName; 182 183 /** 184 * The location to search for modlets. 185 * 186 * @parameter expression="${jomc.modletLocation}" 187 */ 188 private String modletLocation; 189 190 /** 191 * The {@code http://jomc.org/modlet} namespace schema system id. 192 * 193 * @parameter expression="${jomc.modletSchemaSystemId}" 194 * @since 1.2 195 */ 196 private String modletSchemaSystemId; 197 198 /** 199 * The location to search for modules. 200 * 201 * @parameter expression="${jomc.moduleLocation}" 202 */ 203 private String moduleLocation; 204 205 /** 206 * The location to search for transformers. 207 * 208 * @parameter expression="${jomc.transformerLocation}" 209 */ 210 private String transformerLocation; 211 212 /** 213 * The indentation string ('\t' for tab). 214 * 215 * @parameter expression="${jomc.indentation}" 216 */ 217 private String indentation; 218 219 /** 220 * The line separator ('\r\n' for DOS, '\r' for Mac, '\n' for Unix). 221 * 222 * @parameter expression="${jomc.lineSeparator}" 223 */ 224 private String lineSeparator; 225 226 /** 227 * The locale. 228 * <pre> 229 * <locale> 230 * <language>Lowercase two-letter ISO-639 code.</language> 231 * <country>Uppercase two-letter ISO-3166 code.</country> 232 * <variant>Vendor and browser specific code.</variant> 233 * </locale> 234 * </pre> 235 * 236 * @parameter 237 * @since 1.2 238 * @see Locale 239 */ 240 private LocaleType locale; 241 242 /** 243 * Controls verbosity of the plugin. 244 * 245 * @parameter expression="${jomc.verbose}" default-value="false" 246 */ 247 private boolean verbose; 248 249 /** 250 * Controls processing of source code files. 251 * 252 * @parameter expression="${jomc.sourceProcessing}" default-value="true" 253 */ 254 private boolean sourceProcessingEnabled; 255 256 /** 257 * Controls processing of resource files. 258 * 259 * @parameter expression="${jomc.resourceProcessing}" default-value="true" 260 */ 261 private boolean resourceProcessingEnabled; 262 263 /** 264 * Controls processing of class files. 265 * 266 * @parameter expression="${jomc.classProcessing}" default-value="true" 267 */ 268 private boolean classProcessingEnabled; 269 270 /** 271 * Controls processing of models. 272 * 273 * @parameter expression="${jomc.modelProcessing}" default-value="true" 274 */ 275 private boolean modelProcessingEnabled; 276 277 /** 278 * Controls model object class path resolution. 279 * 280 * @parameter expression="${jomc.modelObjectClasspathResolution}" default-value="true" 281 */ 282 private boolean modelObjectClasspathResolutionEnabled; 283 284 /** 285 * Name of the module to process. 286 * 287 * @parameter default-value="${project.name}" expression="${jomc.moduleName}" 288 */ 289 private String moduleName; 290 291 /** 292 * Name of the test module to process. 293 * 294 * @parameter default-value="${project.name} Tests" expression="${jomc.testModuleName}" 295 */ 296 private String testModuleName; 297 298 /** 299 * Directory holding the compiled class files of the project. 300 * <p><strong>Deprecated:</strong> As of JOMC 1.1, please use the 'outputDirectory' parameter. This parameter will 301 * be removed in version 2.0.</p> 302 * 303 * @parameter 304 */ 305 @Deprecated 306 private String classesDirectory; 307 308 /** 309 * Directory holding the compiled test class files of the project. 310 * <p><strong>Deprecated:</strong> As of JOMC 1.1, please use the 'testOutputDirectory' parameter. This parameter 311 * will be removed in version 2.0.</p> 312 * 313 * @parameter 314 */ 315 @Deprecated 316 private String testClassesDirectory; 317 318 /** 319 * Output directory of the project. 320 * 321 * @parameter default-value="${project.build.outputDirectory}" expression="${jomc.outputDirectory}" 322 * @since 1.1 323 */ 324 private String outputDirectory; 325 326 /** 327 * Test output directory of the project. 328 * 329 * @parameter default-value="${project.build.testOutputDirectory}" expression="${jomc.testOutputDirectory}" 330 * @since 1.1 331 */ 332 private String testOutputDirectory; 333 334 /** 335 * Directory holding the source files of the project. 336 * 337 * @parameter default-value="${project.build.sourceDirectory}" expression="${jomc.sourceDirectory}" 338 * @since 1.1 339 */ 340 private String sourceDirectory; 341 342 /** 343 * Directory holding the test source files of the project. 344 * 345 * @parameter default-value="${project.build.testSourceDirectory}" expression="${jomc.testSourceDirectory}" 346 * @since 1.1 347 */ 348 private String testSourceDirectory; 349 350 /** 351 * Directory holding the session related files of the project. 352 * 353 * @parameter default-value="${project.build.directory}/jomc-sessions" expression="${jomc.sessionDirectory}" 354 * @since 1.1 355 */ 356 private String sessionDirectory; 357 358 /** 359 * Directory holding the reports of the project. 360 * 361 * @parameter default-value="${project.reporting.outputDirectory}" expression="${jomc.reportOutputDirectory}" 362 * @since 1.1 363 */ 364 private String reportOutputDirectory; 365 366 /** 367 * Velocity runtime properties. 368 * <pre> 369 * <velocityProperties> 370 * <velocityProperty> 371 * <key>The name of the property.</key> 372 * <value>The value of the property.</value> 373 * <type>The name of the class of the properties object.</type> 374 * </velocityProperty> 375 * </velocityProperties> 376 * </pre> 377 * 378 * @parameter 379 * @since 1.2 380 */ 381 private List<VelocityProperty> velocityProperties; 382 383 /** 384 * Velocity runtime property resources. 385 * <pre> 386 * <velocityPropertyResources> 387 * <velocityPropertyResource> 388 * <location>The location of the properties resource.</location> 389 * <optional>Flag indicating the properties resource is optional.</optional> 390 * <format>The format of the properties resource.</format> 391 * <connectTimeout>Timeout value, in milliseconds.</connectTimeout> 392 * <readTimeout>Timeout value, in milliseconds.</readTimeout> 393 * </velocityPropertyResource> 394 * </velocityPropertyResources> 395 * </pre> 396 * <p>The location value is used to first search the class path of the plugin. If a class path resource is found, 397 * that resource is used. If no class path resource is found, an attempt is made to parse the location value to an 398 * URL. On successful parsing, that URL is used. Otherwise the location value is interpreted as a file name relative 399 * to the base directory of the project. If that file exists, that file is used. If nothing is found at the given 400 * location, depending on the optional flag, a warning message is logged or a build failure is produced.</p> 401 * <p>The optional flag is used to flag the resource optional. When an optional resource is not found, a warning 402 * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false</p> 403 * <p>The format value is used to specify the format of the properties resource. Supported values are {@code plain} 404 * and {@code xml}.<br/><b>Default value is:</b> plain</p> 405 * <p>The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening 406 * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/> 407 * <b>Default value is:</b> 60000</p> 408 * <p>The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource. 409 * A timeout of zero is interpreted as an infinite timeout.<br/> 410 * <b>Default value is:</b> 60000</p> 411 * 412 * @parameter 413 * @since 1.2 414 */ 415 private List<VelocityPropertyResource> velocityPropertyResources; 416 417 /** 418 * Template parameters. 419 * <pre> 420 * <templateParameters> 421 * <templateParameter> 422 * <key>The name of the parameter.</key> 423 * <value>The value of the parameter.</value> 424 * <type>The name of the class of the parameter's object.</type> 425 * </templateParameter> 426 * </templateParameters> 427 * </pre> 428 * 429 * @parameter 430 * @since 1.2 431 */ 432 private List<TemplateParameter> templateParameters; 433 434 /** 435 * Template parameter resources. 436 * <pre> 437 * <templateParameterResources> 438 * <templateParameterResource> 439 * <location>The location of the properties resource.</location> 440 * <optional>Flag indicating the properties resource is optional.</optional> 441 * <format>The format of the properties resource.</format> 442 * <connectTimeout>Timeout value, in milliseconds.</connectTimeout> 443 * <readTimeout>Timeout value, in milliseconds.</readTimeout> 444 * </templateParameterResource> 445 * </templateParameterResources> 446 * </pre> 447 * <p>The location value is used to first search the class path of the plugin. If a class path resource is found, 448 * that resource is used. If no class path resource is found, an attempt is made to parse the location value to an 449 * URL. On successful parsing, that URL is used. Otherwise the location value is interpreted as a file name relative 450 * to the base directory of the project. If that file exists, that file is used. If nothing is found at the given 451 * location, depending on the optional flag, a warning message is logged or a build failure is produced.</p> 452 * <p>The optional flag is used to flag the resource optional. When an optional resource is not found, a warning 453 * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false</p> 454 * <p>The format value is used to specify the format of the properties resource. Supported values are {@code plain} 455 * and {@code xml}.<br/><b>Default value is:</b> plain</p> 456 * <p>The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening 457 * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/> 458 * <b>Default value is:</b> 60000</p> 459 * <p>The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource. 460 * A timeout of zero is interpreted as an infinite timeout.<br/> 461 * <b>Default value is:</b> 60000</p> 462 * 463 * @parameter 464 * @since 1.2 465 */ 466 private List<TemplateParameterResource> templateParameterResources; 467 468 /** 469 * Global transformation parameters. 470 * <pre> 471 * <transformationParameters> 472 * <transformationParameter> 473 * <key>The name of the parameter.</key> 474 * <value>The value of the parameter.</value> 475 * <type>The name of the class of the parameter's object.</type> 476 * </transformationParameter> 477 * </transformationParameters> 478 * </pre> 479 * 480 * @parameter 481 * @since 1.2 482 */ 483 private List<TransformationParameter> transformationParameters; 484 485 /** 486 * Global transformation output properties. 487 * <pre> 488 * <transformationOutputProperties> 489 * <transformationOutputProperty> 490 * <key>The name of the property.</key> 491 * <value>The value of the property.</value> 492 * <type>The name of the class of the properties object.</type> 493 * </transformationOutputProperty> 494 * </transformationOutputProperties> 495 * </pre> 496 * 497 * @parameter 498 * @since 1.2 499 */ 500 private List<TransformationOutputProperty> transformationOutputProperties; 501 502 /** 503 * Global transformation parameter resources. 504 * <pre> 505 * <transformationParameterResources> 506 * <transformationParameterResource> 507 * <location>The location of the properties resource.</location> 508 * <optional>Flag indicating the properties resource is optional.</optional> 509 * <format>The format of the properties resource.</format> 510 * <connectTimeout>Timeout value, in milliseconds.</connectTimeout> 511 * <readTimeout>Timeout value, in milliseconds.</readTimeout> 512 * </transformationParameterResource> 513 * </transformationParameterResources> 514 * </pre> 515 * <p>The location value is used to first search the class path of the plugin. If a class path resource is found, 516 * that resource is used. If no class path resource is found, an attempt is made to parse the location value to an 517 * URL. On successful parsing, that URL is used. Otherwise the location value is interpreted as a file name relative 518 * to the base directory of the project. If that file exists, that file is used. If nothing is found at the given 519 * location, depending on the optional flag, a warning message is logged or a build failure is produced.</p> 520 * <p>The optional flag is used to flag the resource optional. When an optional resource is not found, a warning 521 * message is logged instead of producing a build failure.<br/><b>Default value is:</b> false</p> 522 * <p>The format value is used to specify the format of the properties resource. Supported values are {@code plain} 523 * and {@code xml}.<br/><b>Default value is:</b> plain</p> 524 * <p>The connectTimeout value is used to specify the timeout, in milliseconds, to be used when opening 525 * communications links to the resource. A timeout of zero is interpreted as an infinite timeout.<br/> 526 * <b>Default value is:</b> 60000</p> 527 * <p>The readTimeout value is used to specify the timeout, in milliseconds, to be used when reading the resource. 528 * A timeout of zero is interpreted as an infinite timeout.<br/> 529 * <b>Default value is:</b> 60000</p> 530 * 531 * @parameter 532 * @since 1.2 533 */ 534 private List<TransformationParameterResource> transformationParameterResources; 535 536 /** 537 * Class name of the {@code ClassFileProcessor} backing the goal. 538 * 539 * @parameter default-value="org.jomc.tools.ClassFileProcessor" expression="${jomc.classFileProcessorClassName}" 540 * @since 1.2 541 */ 542 private String classFileProcessorClassName; 543 544 /** 545 * Class name of the {@code ResourceFileProcessor} backing the goal. 546 * 547 * @parameter default-value="org.jomc.tools.ResourceFileProcessor" 548 * expression="${jomc.resourceFileProcessorClassName}" 549 * @since 1.2 550 */ 551 private String resourceFileProcessorClassName; 552 553 /** 554 * Class name of the {@code SourceFileProcessor} backing the goal. 555 * 556 * @parameter default-value="org.jomc.tools.SourceFileProcessor" expression="${jomc.sourceFileProcessorClassName}" 557 * @since 1.2 558 */ 559 private String sourceFileProcessorClassName; 560 561 /** 562 * {@code ModelContext} attributes. 563 * <pre> 564 * <modelContextAttributes> 565 * <modelContextAttribute> 566 * <key>The name of the attribute.</key> 567 * <value>The value of the attribute.</value> 568 * <type>The name of the class of the attributes's object.</type> 569 * </modelContextAttribute> 570 * </modelContextAttributes> 571 * </pre> 572 * 573 * @parameter 574 * @since 1.2 575 */ 576 private List<ModelContextAttribute> modelContextAttributes; 577 578 /** 579 * Flag controlling JAXP schema validation of model resources. 580 * 581 * @parameter default-value="true" expression="${jomc.modelResourceValidationEnabled}" 582 * 583 * @since 1.2 584 */ 585 private boolean modelResourceValidationEnabled; 586 587 /** 588 * Flag controlling JAXP schema validation of modlet resources. 589 * 590 * @parameter default-value="true" expression="${jomc.modletResourceValidationEnabled}" 591 * 592 * @since 1.2 593 */ 594 private boolean modletResourceValidationEnabled; 595 596 /** 597 * The Maven project of the instance. 598 * 599 * @parameter expression="${project}" 600 * @required 601 * @readonly 602 */ 603 private MavenProject mavenProject; 604 605 /** 606 * List of plugin artifacts. 607 * 608 * @parameter expression="${plugin.artifacts}" 609 * @required 610 * @readonly 611 */ 612 private List<Artifact> pluginArtifacts; 613 614 /** 615 * The Maven session of the instance. 616 * 617 * @parameter expression="${session}" 618 * @required 619 * @readonly 620 * @since 1.1 621 */ 622 private MavenSession mavenSession; 623 624 /** Creates a new {@code AbstractJomcMojo} instance. */ 625 public AbstractJomcMojo() 626 { 627 super(); 628 } 629 630 /** 631 * {@inheritDoc} 632 * @see #assertValidParameters() 633 * @see #isExecutionPermitted() 634 * @see #executeTool() 635 */ 636 public void execute() throws MojoExecutionException, MojoFailureException 637 { 638 this.assertValidParameters(); 639 640 try 641 { 642 this.logSeparator(); 643 644 if ( this.isLoggable( Level.INFO ) ) 645 { 646 this.log( Level.INFO, Messages.getMessage( "title" ), null ); 647 } 648 649 if ( this.isExecutionPermitted() ) 650 { 651 this.executeTool(); 652 } 653 else if ( this.isLoggable( Level.INFO ) ) 654 { 655 this.log( Level.INFO, Messages.getMessage( "executionSuppressed", this.getExecutionStrategy() ), null ); 656 } 657 } 658 catch ( final Exception e ) 659 { 660 throw new MojoExecutionException( Messages.getMessage( e ), e ); 661 } 662 finally 663 { 664 JomcTool.setDefaultTemplateProfile( null ); 665 this.logSeparator(); 666 } 667 } 668 669 /** 670 * Validates the parameters of the goal. 671 * 672 * @throws MojoFailureException if illegal parameter values are detected. 673 * 674 * @see #assertValidResources(java.util.Collection) 675 * @since 1.2 676 */ 677 protected void assertValidParameters() throws MojoFailureException 678 { 679 this.assertValidResources( this.templateParameterResources ); 680 this.assertValidResources( this.transformationParameterResources ); 681 this.assertValidResources( this.velocityPropertyResources ); 682 } 683 684 /** 685 * Validates a given resource collection. 686 * 687 * @param resources The resource collection to validate or {@code null}. 688 * 689 * @throws MojoFailureException if a location property of a given resource holds a {@code null} value or a given 690 * {@code PropertiesResourceType} holds an illegal format. 691 * 692 * @see #assertValidParameters() 693 * @see PropertiesResourceType#isFormatSupported(java.lang.String) 694 * @since 1.2 695 */ 696 protected final void assertValidResources( final Collection<? extends ResourceType> resources ) 697 throws MojoFailureException 698 { 699 if ( resources != null ) 700 { 701 for ( ResourceType r : resources ) 702 { 703 if ( r.getLocation() == null ) 704 { 705 throw new MojoFailureException( Messages.getMessage( "mandatoryParameter", "location" ) ); 706 } 707 708 if ( r instanceof PropertiesResourceType ) 709 { 710 final PropertiesResourceType p = (PropertiesResourceType) r; 711 712 if ( !PropertiesResourceType.isFormatSupported( p.getFormat() ) ) 713 { 714 throw new MojoFailureException( Messages.getMessage( 715 "illegalPropertiesFormat", p.getFormat(), 716 StringUtils.join( PropertiesResourceType.getSupportedFormats(), ',' ) ) ); 717 718 } 719 } 720 } 721 } 722 } 723 724 /** 725 * Executes this tool. 726 * 727 * @throws Exception if execution of this tool fails. 728 */ 729 protected abstract void executeTool() throws Exception; 730 731 /** 732 * Gets the goal of the instance. 733 * 734 * @return The goal of the instance. 735 * 736 * @throws MojoExecutionException if getting the goal of the instance fails. 737 * @since 1.1 738 */ 739 protected abstract String getGoal() throws MojoExecutionException; 740 741 /** 742 * Gets the execution strategy of the instance. 743 * 744 * @return The execution strategy of the instance. 745 * 746 * @throws MojoExecutionException if getting the execution strategy of the instance fails. 747 * @since 1.1 748 */ 749 protected abstract String getExecutionStrategy() throws MojoExecutionException; 750 751 /** 752 * Gets a flag indicating the current execution is permitted. 753 * 754 * @return {@code true}, if the current execution is permitted; {@code false}, if the current execution is 755 * suppressed. 756 * 757 * @throws MojoExecutionException if getting the flag fails. 758 * 759 * @since 1.1 760 * @see #getGoal() 761 * @see #getExecutionStrategy() 762 */ 763 protected boolean isExecutionPermitted() throws MojoExecutionException 764 { 765 try 766 { 767 boolean permitted = true; 768 769 if ( MojoDescriptor.SINGLE_PASS_EXEC_STRATEGY.equals( this.getExecutionStrategy() ) ) 770 { 771 final File flagFile = 772 new File( this.getSessionDirectory(), 773 ArtifactUtils.versionlessKey( this.getMavenProject().getArtifact() ).hashCode() 774 + "-" + this.getGoal() 775 + "-" + this.getMavenSession().getStartTime().getTime() + ".flg" ); 776 777 if ( !this.getSessionDirectory().exists() && !this.getSessionDirectory().mkdirs() ) 778 { 779 throw new MojoExecutionException( Messages.getMessage( 780 "failedCreatingDirectory", this.getSessionDirectory().getAbsolutePath() ) ); 781 782 } 783 784 permitted = flagFile.createNewFile(); 785 } 786 787 return permitted; 788 } 789 catch ( final IOException e ) 790 { 791 throw new MojoExecutionException( Messages.getMessage( e ), e ); 792 } 793 } 794 795 /** 796 * Gets the Maven project of the instance. 797 * 798 * @return The Maven project of the instance. 799 * 800 * @throws MojoExecutionException if getting the Maven project of the instance fails. 801 */ 802 protected MavenProject getMavenProject() throws MojoExecutionException 803 { 804 return this.mavenProject; 805 } 806 807 /** 808 * Gets the Maven session of the instance. 809 * 810 * @return The Maven session of the instance. 811 * 812 * @throws MojoExecutionException if getting the Maven session of the instance fails. 813 * 814 * @since 1.1 815 */ 816 protected MavenSession getMavenSession() throws MojoExecutionException 817 { 818 return this.mavenSession; 819 } 820 821 /** 822 * Gets an absolute {@code File} instance for a given name. 823 * <p>This method constructs a new {@code File} instance using the given name. If the resulting file is not 824 * absolute, the value of the {@code basedir} property of the current Maven project is prepended.</p> 825 * 826 * @param name The name to get an absolute {@code File} instance for. 827 * 828 * @return An absolute {@code File} instance constructed from {@code name}. 829 * 830 * @throws MojoExecutionException if getting an absolute {@code File} instance for {@code name} fails. 831 * @throws NullPointerException if {@code name} is {@code null}. 832 * 833 * @since 1.1 834 */ 835 protected File getAbsoluteFile( final String name ) throws MojoExecutionException 836 { 837 if ( name == null ) 838 { 839 throw new NullPointerException( "name" ); 840 } 841 842 File file = new File( name ); 843 if ( !file.isAbsolute() ) 844 { 845 file = new File( this.getMavenProject().getBasedir(), name ); 846 } 847 848 return file; 849 } 850 851 /** 852 * Gets the directory holding the compiled class files of the project. 853 * 854 * @return The directory holding the compiled class files of the project. 855 * 856 * @throws MojoExecutionException if getting the directory fails. 857 * 858 * @since 1.1 859 */ 860 protected File getOutputDirectory() throws MojoExecutionException 861 { 862 if ( this.classesDirectory != null ) 863 { 864 if ( this.isLoggable( Level.WARNING ) ) 865 { 866 this.log( Level.WARNING, Messages.getMessage( 867 "deprecationWarning", "classesDirectory", "outputDirectory" ), null ); 868 869 } 870 871 if ( !this.classesDirectory.equals( this.outputDirectory ) ) 872 { 873 if ( this.isLoggable( Level.WARNING ) ) 874 { 875 this.log( Level.WARNING, Messages.getMessage( "ignoringParameter", "outputDirectory" ), null ); 876 } 877 878 this.outputDirectory = this.classesDirectory; 879 } 880 881 this.classesDirectory = null; 882 } 883 884 final File dir = this.getAbsoluteFile( this.outputDirectory ); 885 if ( !dir.exists() && !dir.mkdirs() ) 886 { 887 throw new MojoExecutionException( Messages.getMessage( "failedCreatingDirectory", dir.getAbsolutePath() ) ); 888 } 889 890 return dir; 891 } 892 893 /** 894 * Gets the directory holding the compiled test class files of the project. 895 * 896 * @return The directory holding the compiled test class files of the project. 897 * 898 * @throws MojoExecutionException if getting the directory fails. 899 * 900 * @since 1.1 901 */ 902 protected File getTestOutputDirectory() throws MojoExecutionException 903 { 904 if ( this.testClassesDirectory != null ) 905 { 906 if ( this.isLoggable( Level.WARNING ) ) 907 { 908 this.log( Level.WARNING, Messages.getMessage( 909 "deprecationWarning", "testClassesDirectory", "testOutputDirectory" ), null ); 910 911 } 912 913 if ( !this.testClassesDirectory.equals( this.testOutputDirectory ) ) 914 { 915 if ( this.isLoggable( Level.WARNING ) ) 916 { 917 this.log( Level.WARNING, Messages.getMessage( "ignoringParameter", "testOutputDirectory" ), null ); 918 } 919 920 this.testOutputDirectory = this.testClassesDirectory; 921 } 922 923 this.testClassesDirectory = null; 924 } 925 926 final File dir = this.getAbsoluteFile( this.testOutputDirectory ); 927 if ( !dir.exists() && !dir.mkdirs() ) 928 { 929 throw new MojoExecutionException( Messages.getMessage( "failedCreatingDirectory", dir.getAbsolutePath() ) ); 930 } 931 932 return dir; 933 } 934 935 /** 936 * Gets the directory holding the source files of the project. 937 * 938 * @return The directory holding the source files of the project. 939 * 940 * @throws MojoExecutionException if getting the directory fails. 941 * 942 * @since 1.1 943 */ 944 protected File getSourceDirectory() throws MojoExecutionException 945 { 946 return this.getAbsoluteFile( this.sourceDirectory ); 947 } 948 949 /** 950 * Gets the directory holding the test source files of the project. 951 * 952 * @return The directory holding the test source files of the project. 953 * 954 * @throws MojoExecutionException if getting the directory fails. 955 * 956 * @since 1.1 957 */ 958 protected File getTestSourceDirectory() throws MojoExecutionException 959 { 960 return this.getAbsoluteFile( this.testSourceDirectory ); 961 } 962 963 /** 964 * Gets the directory holding the session related files of the project. 965 * 966 * @return The directory holding the session related files of the project. 967 * 968 * @throws MojoExecutionException if getting the directory fails. 969 * 970 * @since 1.1 971 */ 972 protected File getSessionDirectory() throws MojoExecutionException 973 { 974 return this.getAbsoluteFile( this.sessionDirectory ); 975 } 976 977 /** 978 * Gets the directory holding the reports of the project. 979 * 980 * @return The directory holding the reports of the project. 981 * 982 * @throws MojoExecutionException if getting the directory fails. 983 * 984 * @since 1.1 985 */ 986 protected File getReportOutputDirectory() throws MojoExecutionException 987 { 988 return this.getAbsoluteFile( this.reportOutputDirectory ); 989 } 990 991 /** 992 * Gets the project's runtime class loader of the instance. 993 * 994 * @return The project's runtime class loader of the instance. 995 * 996 * @throws MojoExecutionException if getting the class loader fails. 997 */ 998 protected ClassLoader getMainClassLoader() throws MojoExecutionException 999 { 1000 try 1001 { 1002 final Set<String> mainClasspathElements = this.getMainClasspathElements(); 1003 final Set<URI> uris = new HashSet<URI>( mainClasspathElements.size() ); 1004 1005 for ( String element : mainClasspathElements ) 1006 { 1007 final URI uri = new File( element ).toURI(); 1008 if ( !uris.contains( uri ) ) 1009 { 1010 uris.add( uri ); 1011 } 1012 } 1013 1014 if ( this.isLoggable( Level.FINEST ) ) 1015 { 1016 this.log( Level.FINEST, Messages.getMessage( "mainClasspathInfo" ), null ); 1017 } 1018 1019 int i = 0; 1020 final URL[] urls = new URL[ uris.size() ]; 1021 for ( URI uri : uris ) 1022 { 1023 urls[i++] = uri.toURL(); 1024 1025 if ( this.isLoggable( Level.FINEST ) ) 1026 { 1027 this.log( Level.FINEST, "\t" + urls[i - 1].toExternalForm(), null ); 1028 } 1029 } 1030 1031 return new URLClassLoader( urls, Thread.currentThread().getContextClassLoader() ); 1032 } 1033 catch ( final IOException e ) 1034 { 1035 throw new MojoExecutionException( Messages.getMessage( e ), e ); 1036 } 1037 } 1038 1039 /** 1040 * Gets the project's test class loader of the instance. 1041 * 1042 * @return The project's test class loader of the instance. 1043 * 1044 * @throws MojoExecutionException if getting the class loader fails. 1045 */ 1046 protected ClassLoader getTestClassLoader() throws MojoExecutionException 1047 { 1048 try 1049 { 1050 final Set<String> testClasspathElements = this.getTestClasspathElements(); 1051 final Set<URI> uris = new HashSet<URI>( testClasspathElements.size() ); 1052 1053 for ( String element : testClasspathElements ) 1054 { 1055 final URI uri = new File( element ).toURI(); 1056 if ( !uris.contains( uri ) ) 1057 { 1058 uris.add( uri ); 1059 } 1060 } 1061 1062 if ( this.isLoggable( Level.FINEST ) ) 1063 { 1064 this.log( Level.FINEST, Messages.getMessage( "testClasspathInfo" ), null ); 1065 } 1066 1067 int i = 0; 1068 final URL[] urls = new URL[ uris.size() ]; 1069 for ( URI uri : uris ) 1070 { 1071 urls[i++] = uri.toURL(); 1072 1073 if ( this.isLoggable( Level.FINEST ) ) 1074 { 1075 this.log( Level.FINEST, "\t" + urls[i - 1].toExternalForm(), null ); 1076 } 1077 } 1078 1079 return new URLClassLoader( urls, Thread.currentThread().getContextClassLoader() ); 1080 } 1081 catch ( final IOException e ) 1082 { 1083 throw new MojoExecutionException( Messages.getMessage( e ), e ); 1084 } 1085 } 1086 1087 /** 1088 * Gets the project's runtime class path elements. 1089 * 1090 * @return A set of class path element strings. 1091 * 1092 * @throws MojoExecutionException if getting the class path elements fails. 1093 */ 1094 protected Set<String> getMainClasspathElements() throws MojoExecutionException 1095 { 1096 final List<?> runtimeArtifacts = this.getMavenProject().getRuntimeArtifacts(); 1097 final List<?> compileArtifacts = this.getMavenProject().getCompileArtifacts(); 1098 final Set<String> elements = new HashSet<String>( runtimeArtifacts.size() + compileArtifacts.size() + 1 ); 1099 elements.add( this.getOutputDirectory().getAbsolutePath() ); 1100 1101 for ( final Iterator<?> it = runtimeArtifacts.iterator(); it.hasNext(); ) 1102 { 1103 final Artifact a = (Artifact) it.next(); 1104 final Artifact pluginArtifact = this.getPluginArtifact( a ); 1105 1106 if ( a.getFile() == null ) 1107 { 1108 if ( this.isLoggable( Level.WARNING ) ) 1109 { 1110 this.log( Level.WARNING, Messages.getMessage( "ignoringArtifact", a.toString() ), null ); 1111 } 1112 1113 continue; 1114 } 1115 1116 if ( pluginArtifact != null ) 1117 { 1118 if ( this.isLoggable( Level.FINER ) ) 1119 { 1120 this.log( Level.FINER, Messages.getMessage( 1121 "ignoringPluginArtifact", a.toString(), pluginArtifact.toString() ), null ); 1122 1123 } 1124 1125 continue; 1126 } 1127 1128 final String element = a.getFile().getAbsolutePath(); 1129 elements.add( element ); 1130 } 1131 1132 for ( final Iterator<?> it = compileArtifacts.iterator(); it.hasNext(); ) 1133 { 1134 final Artifact a = (Artifact) it.next(); 1135 final Artifact pluginArtifact = this.getPluginArtifact( a ); 1136 1137 if ( a.getFile() == null ) 1138 { 1139 if ( this.isLoggable( Level.WARNING ) ) 1140 { 1141 this.log( Level.WARNING, Messages.getMessage( "ignoringArtifact", a.toString() ), null ); 1142 } 1143 1144 continue; 1145 } 1146 1147 if ( pluginArtifact != null ) 1148 { 1149 if ( this.isLoggable( Level.FINER ) ) 1150 { 1151 this.log( Level.FINER, Messages.getMessage( 1152 "ignoringPluginArtifact", a.toString(), pluginArtifact.toString() ), null ); 1153 1154 } 1155 1156 continue; 1157 } 1158 1159 final String element = a.getFile().getAbsolutePath(); 1160 elements.add( element ); 1161 } 1162 1163 return elements; 1164 } 1165 1166 /** 1167 * Gets the project's test class path elements. 1168 * 1169 * @return A set of class path element strings. 1170 * 1171 * @throws MojoExecutionException if getting the class path elements fails. 1172 */ 1173 protected Set<String> getTestClasspathElements() throws MojoExecutionException 1174 { 1175 final List<?> testArtifacts = this.getMavenProject().getTestArtifacts(); 1176 final Set<String> elements = new HashSet<String>( testArtifacts.size() + 2 ); 1177 elements.add( this.getOutputDirectory().getAbsolutePath() ); 1178 elements.add( this.getTestOutputDirectory().getAbsolutePath() ); 1179 1180 for ( final Iterator<?> it = testArtifacts.iterator(); it.hasNext(); ) 1181 { 1182 final Artifact a = (Artifact) it.next(); 1183 final Artifact pluginArtifact = this.getPluginArtifact( a ); 1184 1185 if ( a.getFile() == null ) 1186 { 1187 if ( this.isLoggable( Level.WARNING ) ) 1188 { 1189 this.log( Level.WARNING, Messages.getMessage( "ignoringArtifact", a.toString() ), null ); 1190 } 1191 1192 continue; 1193 } 1194 1195 if ( pluginArtifact != null ) 1196 { 1197 if ( this.isLoggable( Level.FINER ) ) 1198 { 1199 this.log( Level.FINER, Messages.getMessage( 1200 "ignoringPluginArtifact", a.toString(), pluginArtifact.toString() ), null ); 1201 1202 } 1203 1204 continue; 1205 } 1206 1207 final String element = a.getFile().getAbsolutePath(); 1208 elements.add( element ); 1209 } 1210 1211 return elements; 1212 } 1213 1214 /** 1215 * Gets a flag indicating verbose output is enabled. 1216 * 1217 * @return {@code true}, if verbose output is enabled; {@code false}, if information messages are suppressed. 1218 * 1219 * @throws MojoExecutionException if getting the flag fails. 1220 * 1221 * @since 1.1 1222 */ 1223 protected final boolean isVerbose() throws MojoExecutionException 1224 { 1225 return this.verbose; 1226 } 1227 1228 /** 1229 * Sets the flag indicating verbose output is enabled. 1230 * 1231 * @param value {@code true}, to enable verbose output; {@code false}, to suppress information messages. 1232 * 1233 * @throws MojoExecutionException if setting the flag fails. 1234 * 1235 * @since 1.1 1236 */ 1237 protected final void setVerbose( final boolean value ) throws MojoExecutionException 1238 { 1239 this.verbose = value; 1240 } 1241 1242 /** 1243 * Gets a flag indicating the processing of sources is enabled. 1244 * 1245 * @return {@code true}, if processing of sources is enabled; {@code false}, else. 1246 * 1247 * @throws MojoExecutionException if getting the flag fails. 1248 */ 1249 protected final boolean isSourceProcessingEnabled() throws MojoExecutionException 1250 { 1251 return this.sourceProcessingEnabled; 1252 } 1253 1254 /** 1255 * Sets the flag indicating the processing of sources is enabled. 1256 * 1257 * @param value {@code true}, to enable processing of sources; {@code false}, to disable processing of sources. 1258 * 1259 * @throws MojoExecutionException if setting the flag fails. 1260 * 1261 * @since 1.1 1262 */ 1263 protected final void setSourceProcessingEnabled( final boolean value ) throws MojoExecutionException 1264 { 1265 this.sourceProcessingEnabled = value; 1266 } 1267 1268 /** 1269 * Gets a flag indicating the processing of resources is enabled. 1270 * 1271 * @return {@code true}, if processing of resources is enabled; {@code false}, else. 1272 * 1273 * @throws MojoExecutionException if getting the flag fails. 1274 */ 1275 protected final boolean isResourceProcessingEnabled() throws MojoExecutionException 1276 { 1277 return this.resourceProcessingEnabled; 1278 } 1279 1280 /** 1281 * Sets the flag indicating the processing of resources is enabled. 1282 * 1283 * @param value {@code true}, to enable processing of resources; {@code false}, to disable processing of resources. 1284 * 1285 * @throws MojoExecutionException if setting the flag fails. 1286 * 1287 * @since 1.1 1288 */ 1289 protected final void setResourceProcessingEnabled( final boolean value ) throws MojoExecutionException 1290 { 1291 this.resourceProcessingEnabled = value; 1292 } 1293 1294 /** 1295 * Gets a flag indicating the processing of classes is enabled. 1296 * 1297 * @return {@code true}, if processing of classes is enabled; {@code false}, else. 1298 * 1299 * @throws MojoExecutionException if getting the flag fails. 1300 */ 1301 protected final boolean isClassProcessingEnabled() throws MojoExecutionException 1302 { 1303 return this.classProcessingEnabled; 1304 } 1305 1306 /** 1307 * Sets the flag indicating the processing of classes is enabled. 1308 * 1309 * @param value {@code true}, to enable processing of classes; {@code false}, to disable processing of classes. 1310 * 1311 * @throws MojoExecutionException if setting the flag fails. 1312 * 1313 * @since 1.1 1314 */ 1315 protected final void setClassProcessingEnabled( final boolean value ) throws MojoExecutionException 1316 { 1317 this.classProcessingEnabled = value; 1318 } 1319 1320 /** 1321 * Gets a flag indicating the processing of models is enabled. 1322 * 1323 * @return {@code true}, if processing of models is enabled; {@code false}, else. 1324 * 1325 * @throws MojoExecutionException if getting the flag fails. 1326 */ 1327 protected final boolean isModelProcessingEnabled() throws MojoExecutionException 1328 { 1329 return this.modelProcessingEnabled; 1330 } 1331 1332 /** 1333 * Sets the flag indicating the processing of models is enabled. 1334 * 1335 * @param value {@code true}, to enable processing of models; {@code false}, to disable processing of models. 1336 * 1337 * @throws MojoExecutionException if setting the flag fails. 1338 * 1339 * @since 1.1 1340 */ 1341 protected final void setModelProcessingEnabled( final boolean value ) throws MojoExecutionException 1342 { 1343 this.modelProcessingEnabled = value; 1344 } 1345 1346 /** 1347 * Gets a flag indicating model object class path resolution is enabled. 1348 * 1349 * @return {@code true}, if model object class path resolution is enabled; {@code false}, else. 1350 * 1351 * @throws MojoExecutionException if getting the flag fails. 1352 */ 1353 protected final boolean isModelObjectClasspathResolutionEnabled() throws MojoExecutionException 1354 { 1355 return this.modelObjectClasspathResolutionEnabled; 1356 } 1357 1358 /** 1359 * Sets the flag indicating model object class path resolution is enabled. 1360 * 1361 * @param value {@code true}, to enable model object class path resolution; {@code false}, to disable model object 1362 * class path resolution. 1363 * 1364 * @throws MojoExecutionException if setting the flag fails. 1365 * 1366 * @since 1.1 1367 */ 1368 protected final void setModelObjectClasspathResolutionEnabled( final boolean value ) throws MojoExecutionException 1369 { 1370 this.modelObjectClasspathResolutionEnabled = value; 1371 } 1372 1373 /** 1374 * Gets the identifier of the model to process. 1375 * 1376 * @return The identifier of the model to process. 1377 * 1378 * @throws MojoExecutionException if getting the identifier fails. 1379 */ 1380 protected String getModel() throws MojoExecutionException 1381 { 1382 return this.model; 1383 } 1384 1385 /** 1386 * Gets the name of the module to process. 1387 * 1388 * @return The name of the module to process. 1389 * 1390 * @throws MojoExecutionException if getting the name of the module fails. 1391 */ 1392 protected String getModuleName() throws MojoExecutionException 1393 { 1394 return this.moduleName; 1395 } 1396 1397 /** 1398 * Gets the name of the test module to process. 1399 * 1400 * @return The name of the test module to process. 1401 * 1402 * @throws MojoExecutionException if getting the name of the test module fails. 1403 */ 1404 protected String getTestModuleName() throws MojoExecutionException 1405 { 1406 return this.testModuleName; 1407 } 1408 1409 /** 1410 * Gets the model to process. 1411 * 1412 * @param context The model context to get the model to process with. 1413 * 1414 * @return The model to process. 1415 * 1416 * @throws NullPointerException if {@code context} is {@code null}. 1417 * @throws MojoExecutionException if getting the model fails. 1418 */ 1419 protected Model getModel( final ModelContext context ) throws MojoExecutionException 1420 { 1421 if ( context == null ) 1422 { 1423 throw new NullPointerException( "context" ); 1424 } 1425 1426 try 1427 { 1428 Model m = context.findModel( this.getModel() ); 1429 final Modules modules = ModelHelper.getModules( m ); 1430 1431 if ( modules != null && this.isModelObjectClasspathResolutionEnabled() ) 1432 { 1433 final Module classpathModule = 1434 modules.getClasspathModule( Modules.getDefaultClasspathModuleName(), context.getClassLoader() ); 1435 1436 if ( classpathModule != null ) 1437 { 1438 modules.getModule().add( classpathModule ); 1439 } 1440 } 1441 1442 if ( this.isModelProcessingEnabled() ) 1443 { 1444 m = context.processModel( m ); 1445 } 1446 1447 return m; 1448 } 1449 catch ( final ModelException e ) 1450 { 1451 throw new MojoExecutionException( Messages.getMessage( e ), e ); 1452 } 1453 } 1454 1455 /** 1456 * Creates a new model context instance for a given class loader. 1457 * 1458 * @param classLoader The class loader to use for creating the context. 1459 * 1460 * @return A new model context instance for {@code classLoader}. 1461 * 1462 * @throws MojoExecutionException if creating the model context fails. 1463 * 1464 * @see #setupModelContext(org.jomc.modlet.ModelContext) 1465 */ 1466 protected ModelContext createModelContext( final ClassLoader classLoader ) throws MojoExecutionException 1467 { 1468 final ModelContextFactory modelContextFactory; 1469 if ( this.modelContextFactoryClassName != null ) 1470 { 1471 modelContextFactory = ModelContextFactory.newInstance( this.modelContextFactoryClassName ); 1472 } 1473 else 1474 { 1475 modelContextFactory = ModelContextFactory.newInstance(); 1476 } 1477 1478 final ModelContext context = modelContextFactory.newModelContext( classLoader ); 1479 this.setupModelContext( context ); 1480 1481 return context; 1482 } 1483 1484 /** 1485 * Creates a new tool instance for processing source files. 1486 * 1487 * @param context The context of the tool. 1488 * 1489 * @return A new tool instance for processing source files. 1490 * 1491 * @throws NullPointerException if {@code context} is {@code null}. 1492 * @throws MojoExecutionException if creating a new tool instance fails. 1493 * 1494 * @see #createJomcTool(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class) 1495 */ 1496 protected SourceFileProcessor createSourceFileProcessor( final ModelContext context ) throws MojoExecutionException 1497 { 1498 if ( context == null ) 1499 { 1500 throw new NullPointerException( "context" ); 1501 } 1502 1503 return this.createJomcTool( context, this.sourceFileProcessorClassName, SourceFileProcessor.class ); 1504 } 1505 1506 /** 1507 * Creates a new tool instance for processing resource files. 1508 * 1509 * @param context The context of the tool. 1510 * 1511 * @return A new tool instance for processing resource files. 1512 * 1513 * @throws NullPointerException if {@code context} is {@code null}. 1514 * @throws MojoExecutionException if creating a new tool instance fails. 1515 * 1516 * @see #createJomcTool(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class) 1517 */ 1518 protected ResourceFileProcessor createResourceFileProcessor( final ModelContext context ) 1519 throws MojoExecutionException 1520 { 1521 if ( context == null ) 1522 { 1523 throw new NullPointerException( "context" ); 1524 } 1525 1526 return this.createJomcTool( context, this.resourceFileProcessorClassName, ResourceFileProcessor.class ); 1527 } 1528 1529 /** 1530 * Creates a new tool instance for processing class files. 1531 * 1532 * @param context The context of the tool. 1533 * 1534 * @return A new tool instance for processing class files. 1535 * 1536 * @throws NullPointerException if {@code context} is {@code null}. 1537 * @throws MojoExecutionException if creating a new tool instance fails. 1538 * 1539 * @see #createJomcTool(org.jomc.modlet.ModelContext, java.lang.String, java.lang.Class) 1540 */ 1541 protected ClassFileProcessor createClassFileProcessor( final ModelContext context ) throws MojoExecutionException 1542 { 1543 if ( context == null ) 1544 { 1545 throw new NullPointerException( "context" ); 1546 } 1547 1548 return this.createJomcTool( context, this.classFileProcessorClassName, ClassFileProcessor.class ); 1549 } 1550 1551 /** 1552 * Creates a new {@code JomcTool} object for a given class name and type. 1553 * 1554 * @param context The context of the tool. 1555 * @param className The name of the class to create an object of. 1556 * @param type The class of the type of object to create. 1557 * @param <T> The type of the object to create. 1558 * 1559 * @return A new instance of the class with name {@code className}. 1560 * 1561 * @throws NullPointerException if {@code context}, {@code className} or {@code type} is {@code null}. 1562 * @throws MojoExecutionException if creating a new {@code JomcTool} object fails. 1563 * 1564 * @see #createObject(java.lang.String, java.lang.Class) 1565 * @see #setupJomcTool(org.jomc.modlet.ModelContext, org.jomc.tools.JomcTool) 1566 * 1567 * @since 1.2 1568 */ 1569 protected <T extends JomcTool> T createJomcTool( final ModelContext context, final String className, 1570 final Class<T> type ) throws MojoExecutionException 1571 { 1572 if ( context == null ) 1573 { 1574 throw new NullPointerException( "context" ); 1575 } 1576 if ( className == null ) 1577 { 1578 throw new NullPointerException( "className" ); 1579 } 1580 if ( type == null ) 1581 { 1582 throw new NullPointerException( "type" ); 1583 } 1584 1585 final T tool = this.createObject( className, type ); 1586 this.setupJomcTool( context, tool ); 1587 return tool; 1588 } 1589 1590 /** 1591 * Creates a new object for a given class name and type. 1592 * 1593 * @param className The name of the class to create an object of. 1594 * @param type The class of the type of object to create. 1595 * @param <T> The type of the object to create. 1596 * 1597 * @return A new instance of the class with name {@code className}. 1598 * 1599 * @throws NullPointerException if {@code className} or {@code type} is {@code null}. 1600 * @throws MojoExecutionException if creating a new object fails. 1601 * 1602 * @since 1.2 1603 */ 1604 protected <T> T createObject( final String className, final Class<T> type ) throws MojoExecutionException 1605 { 1606 if ( className == null ) 1607 { 1608 throw new NullPointerException( "className" ); 1609 } 1610 if ( type == null ) 1611 { 1612 throw new NullPointerException( "type" ); 1613 } 1614 1615 try 1616 { 1617 return Class.forName( className ).asSubclass( type ).newInstance(); 1618 } 1619 catch ( final InstantiationException e ) 1620 { 1621 throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e ); 1622 } 1623 catch ( final IllegalAccessException e ) 1624 { 1625 throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e ); 1626 } 1627 catch ( final ClassNotFoundException e ) 1628 { 1629 throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e ); 1630 } 1631 catch ( final ClassCastException e ) 1632 { 1633 throw new MojoExecutionException( Messages.getMessage( "failedCreatingObject", className ), e ); 1634 } 1635 } 1636 1637 /** 1638 * Creates an {@code URL} for a given resource location. 1639 * <p>This method first searches the class path of the plugin for a single resource matching {@code location}. If 1640 * such a resource is found, the URL of that resource is returned. If no such resource is found, an attempt is made 1641 * to parse the given location to an URL. On successful parsing, that URL is returned. Failing that, the given 1642 * location is interpreted as a file name relative to the project's base directory. If that file is found, the URL 1643 * of that file is returned. Otherwise {@code null} is returned.</p> 1644 * 1645 * @param location The location to create an {@code URL} from. 1646 * 1647 * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and 1648 * {@code location} points to a non-existent resource. 1649 * 1650 * @throws NullPointerException if {@code location} is {@code null}. 1651 * @throws MojoExecutionException if creating an URL fails. 1652 * 1653 * @since 1.2 1654 */ 1655 protected URL getResource( final String location ) throws MojoExecutionException 1656 { 1657 if ( location == null ) 1658 { 1659 throw new NullPointerException( "location" ); 1660 } 1661 1662 try 1663 { 1664 String absolute = location; 1665 if ( !absolute.startsWith( "/" ) ) 1666 { 1667 absolute = "/" + location; 1668 } 1669 1670 URL resource = this.getClass().getResource( absolute ); 1671 if ( resource == null ) 1672 { 1673 try 1674 { 1675 resource = new URL( location ); 1676 } 1677 catch ( final MalformedURLException e ) 1678 { 1679 if ( this.isLoggable( Level.FINEST ) ) 1680 { 1681 this.log( Level.FINEST, Messages.getMessage( e ), e ); 1682 } 1683 1684 resource = null; 1685 } 1686 } 1687 1688 if ( resource == null ) 1689 { 1690 final File f = this.getAbsoluteFile( location ); 1691 1692 if ( f.isFile() ) 1693 { 1694 resource = f.toURI().toURL(); 1695 } 1696 } 1697 1698 return resource; 1699 } 1700 catch ( final MalformedURLException e ) 1701 { 1702 String m = Messages.getMessage( e ); 1703 m = m == null ? "" : " " + m; 1704 1705 throw new MojoExecutionException( Messages.getMessage( "malformedLocation", location, m ), e ); 1706 } 1707 } 1708 1709 /** 1710 * Creates an {@code URL} for a given directory location. 1711 * <p>This method first attempts to parse the given location to an URL. On successful parsing, that URL is returned. 1712 * Failing that, the given location is interpreted as a directory name relative to the project's base directory. 1713 * If that directory is found, the URL of that directory is returned. Otherwise {@code null} is returned.</p> 1714 * 1715 * @param location The directory location to create an {@code URL} from. 1716 * 1717 * @return An {@code URL} for {@code location} or {@code null}, if parsing {@code location} to an URL fails and 1718 * {@code location} points to a non-existent directory. 1719 * 1720 * @throws NullPointerException if {@code location} is {@code null}. 1721 * @throws MojoExecutionException if creating an URL fails. 1722 * 1723 * @since 1.2 1724 */ 1725 protected URL getDirectory( final String location ) throws MojoExecutionException 1726 { 1727 if ( location == null ) 1728 { 1729 throw new NullPointerException( "location" ); 1730 } 1731 1732 try 1733 { 1734 URL resource = null; 1735 1736 try 1737 { 1738 resource = new URL( location ); 1739 } 1740 catch ( final MalformedURLException e ) 1741 { 1742 if ( this.isLoggable( Level.FINEST ) ) 1743 { 1744 this.log( Level.FINEST, Messages.getMessage( e ), e ); 1745 } 1746 1747 resource = null; 1748 } 1749 1750 if ( resource == null ) 1751 { 1752 final File f = this.getAbsoluteFile( location ); 1753 1754 if ( f.isDirectory() ) 1755 { 1756 resource = f.toURI().toURL(); 1757 } 1758 } 1759 1760 return resource; 1761 } 1762 catch ( final MalformedURLException e ) 1763 { 1764 String m = Messages.getMessage( e ); 1765 m = m == null ? "" : " " + m; 1766 1767 throw new MojoExecutionException( Messages.getMessage( "malformedLocation", location, m ), e ); 1768 } 1769 } 1770 1771 /** 1772 * Creates a new {@code Transformer} from a given {@code TransformerResourceType}. 1773 * 1774 * @param resource The resource to initialize the transformer with. 1775 * 1776 * @return A {@code Transformer} for {@code resource} or {@code null}, if {@code resource} is not found and flagged 1777 * optional. 1778 * 1779 * @throws NullPointerException if {@code resource} is {@code null}. 1780 * @throws MojoExecutionException if creating a transformer fails. 1781 * 1782 * @see #getResource(java.lang.String) 1783 * @since 1.2 1784 */ 1785 protected Transformer getTransformer( final TransformerResourceType resource ) throws MojoExecutionException 1786 { 1787 if ( resource == null ) 1788 { 1789 throw new NullPointerException( "resource" ); 1790 } 1791 1792 InputStream in = null; 1793 boolean suppressExceptionOnClose = true; 1794 final URL url = this.getResource( resource.getLocation() ); 1795 final ErrorListener errorListener = new ErrorListener() 1796 { 1797 1798 public void warning( final TransformerException exception ) throws TransformerException 1799 { 1800 try 1801 { 1802 log( Level.WARNING, Messages.getMessage( exception ), exception ); 1803 } 1804 catch ( final MojoExecutionException e ) 1805 { 1806 getLog().warn( exception ); 1807 getLog().error( e ); 1808 } 1809 } 1810 1811 public void error( final TransformerException exception ) throws TransformerException 1812 { 1813 try 1814 { 1815 log( Level.SEVERE, Messages.getMessage( exception ), exception ); 1816 } 1817 catch ( final MojoExecutionException e ) 1818 { 1819 getLog().error( exception ); 1820 getLog().error( e ); 1821 } 1822 1823 throw exception; 1824 } 1825 1826 public void fatalError( final TransformerException exception ) throws TransformerException 1827 { 1828 try 1829 { 1830 log( Level.SEVERE, Messages.getMessage( exception ), exception ); 1831 } 1832 catch ( final MojoExecutionException e ) 1833 { 1834 getLog().error( exception ); 1835 getLog().error( e ); 1836 } 1837 1838 throw exception; 1839 } 1840 1841 }; 1842 1843 try 1844 { 1845 if ( url != null ) 1846 { 1847 if ( this.isLoggable( Level.FINER ) ) 1848 { 1849 this.log( Level.FINER, Messages.getMessage( "loadingTransformer", url.toExternalForm() ), null ); 1850 } 1851 1852 final URLConnection con = url.openConnection(); 1853 con.setConnectTimeout( resource.getConnectTimeout() ); 1854 con.setReadTimeout( resource.getReadTimeout() ); 1855 con.connect(); 1856 in = con.getInputStream(); 1857 1858 final TransformerFactory transformerFactory = TransformerFactory.newInstance(); 1859 transformerFactory.setErrorListener( errorListener ); 1860 final Transformer transformer = 1861 transformerFactory.newTransformer( new StreamSource( in, url.toURI().toASCIIString() ) ); 1862 1863 transformer.setErrorListener( errorListener ); 1864 1865 for ( Map.Entry<Object, Object> e : System.getProperties().entrySet() ) 1866 { 1867 transformer.setParameter( e.getKey().toString(), e.getValue() ); 1868 } 1869 1870 if ( this.getMavenProject().getProperties() != null ) 1871 { 1872 for ( Map.Entry<Object, Object> e : this.getMavenProject().getProperties().entrySet() ) 1873 { 1874 transformer.setParameter( e.getKey().toString(), e.getValue() ); 1875 } 1876 } 1877 1878 if ( this.transformationParameterResources != null ) 1879 { 1880 for ( int i = 0, s0 = this.transformationParameterResources.size(); i < s0; i++ ) 1881 { 1882 for ( Map.Entry<Object, Object> e : 1883 this.getProperties( this.transformationParameterResources.get( i ) ).entrySet() ) 1884 { 1885 transformer.setParameter( e.getKey().toString(), e.getValue() ); 1886 } 1887 } 1888 } 1889 1890 if ( this.transformationParameters != null ) 1891 { 1892 for ( TransformationParameter e : this.transformationParameters ) 1893 { 1894 transformer.setParameter( e.getKey(), e.getObject() ); 1895 } 1896 } 1897 1898 if ( this.transformationOutputProperties != null ) 1899 { 1900 for ( TransformationOutputProperty e : this.transformationOutputProperties ) 1901 { 1902 transformer.setOutputProperty( e.getKey(), e.getValue() ); 1903 } 1904 } 1905 1906 for ( int i = 0, s0 = resource.getTransformationParameterResources().size(); i < s0; i++ ) 1907 { 1908 for ( Map.Entry<Object, Object> e : 1909 this.getProperties( resource.getTransformationParameterResources().get( i ) ).entrySet() ) 1910 { 1911 transformer.setParameter( e.getKey().toString(), e.getValue() ); 1912 } 1913 } 1914 1915 for ( TransformationParameter e : resource.getTransformationParameters() ) 1916 { 1917 transformer.setParameter( e.getKey(), e.getObject() ); 1918 } 1919 1920 for ( TransformationOutputProperty e : resource.getTransformationOutputProperties() ) 1921 { 1922 transformer.setOutputProperty( e.getKey(), e.getValue() ); 1923 } 1924 1925 suppressExceptionOnClose = false; 1926 return transformer; 1927 } 1928 else if ( resource.isOptional() ) 1929 { 1930 if ( this.isLoggable( Level.WARNING ) ) 1931 { 1932 this.log( Level.WARNING, Messages.getMessage( 1933 "transformerNotFound", resource.getLocation() ), null ); 1934 1935 } 1936 } 1937 else 1938 { 1939 throw new MojoExecutionException( Messages.getMessage( 1940 "transformerNotFound", resource.getLocation() ) ); 1941 1942 } 1943 } 1944 catch ( final InstantiationException e ) 1945 { 1946 throw new MojoExecutionException( Messages.getMessage( e ), e ); 1947 } 1948 catch ( final URISyntaxException e ) 1949 { 1950 throw new MojoExecutionException( Messages.getMessage( e ), e ); 1951 } 1952 catch ( final TransformerConfigurationException e ) 1953 { 1954 String m = Messages.getMessage( e ); 1955 if ( m == null ) 1956 { 1957 m = Messages.getMessage( e.getException() ); 1958 } 1959 1960 m = m == null ? "" : " " + m; 1961 1962 throw new MojoExecutionException( Messages.getMessage( 1963 "failedCreatingTransformer", resource.getLocation(), m ), e ); 1964 1965 } 1966 catch ( final SocketTimeoutException e ) 1967 { 1968 String m = Messages.getMessage( e ); 1969 m = m == null ? "" : " " + m; 1970 1971 if ( resource.isOptional() ) 1972 { 1973 if ( this.isLoggable( Level.WARNING ) ) 1974 { 1975 this.log( Level.WARNING, Messages.getMessage( 1976 "failedLoadingTransformer", url.toExternalForm(), m ), e ); 1977 1978 } 1979 } 1980 else 1981 { 1982 throw new MojoExecutionException( Messages.getMessage( 1983 "failedLoadingTransformer", url.toExternalForm(), m ), e ); 1984 1985 } 1986 } 1987 catch ( final IOException e ) 1988 { 1989 String m = Messages.getMessage( e ); 1990 m = m == null ? "" : " " + m; 1991 1992 if ( resource.isOptional() ) 1993 { 1994 if ( this.isLoggable( Level.WARNING ) ) 1995 { 1996 this.log( Level.WARNING, Messages.getMessage( 1997 "failedLoadingTransformer", url.toExternalForm(), m ), e ); 1998 1999 } 2000 } 2001 else 2002 { 2003 throw new MojoExecutionException( Messages.getMessage( 2004 "failedLoadingTransformer", url.toExternalForm(), m ), e ); 2005 2006 } 2007 } 2008 finally 2009 { 2010 try 2011 { 2012 if ( in != null ) 2013 { 2014 in.close(); 2015 } 2016 } 2017 catch ( final IOException e ) 2018 { 2019 if ( suppressExceptionOnClose ) 2020 { 2021 this.getLog().error( e ); 2022 } 2023 else 2024 { 2025 throw new MojoExecutionException( Messages.getMessage( e ), e ); 2026 } 2027 } 2028 } 2029 2030 return null; 2031 } 2032 2033 /** 2034 * Creates a new {@code Properties} instance from a {@code PropertiesResourceType}. 2035 * 2036 * @param propertiesResourceType The {@code PropertiesResourceType} specifying the properties to create. 2037 * 2038 * @return The properties for {@code propertiesResourceType}. 2039 * 2040 * @throws NullPointerException if {@code propertiesResourceType} is {@code null}. 2041 * @throws MojoExecutionException if loading properties fails. 2042 * 2043 * @see #getResource(java.lang.String) 2044 * @since 1.2 2045 */ 2046 protected Properties getProperties( final PropertiesResourceType propertiesResourceType ) 2047 throws MojoExecutionException 2048 { 2049 if ( propertiesResourceType == null ) 2050 { 2051 throw new NullPointerException( "propertiesResourceType" ); 2052 } 2053 2054 InputStream in = null; 2055 boolean suppressExceptionOnClose = true; 2056 final URL url = this.getResource( propertiesResourceType.getLocation() ); 2057 final Properties properties = new Properties(); 2058 2059 try 2060 { 2061 if ( url != null ) 2062 { 2063 if ( this.isLoggable( Level.FINER ) ) 2064 { 2065 this.log( Level.FINER, Messages.getMessage( "loadingProperties", url.toExternalForm() ), null ); 2066 } 2067 2068 final URLConnection con = url.openConnection(); 2069 con.setConnectTimeout( propertiesResourceType.getConnectTimeout() ); 2070 con.setReadTimeout( propertiesResourceType.getReadTimeout() ); 2071 con.connect(); 2072 2073 in = con.getInputStream(); 2074 2075 if ( PropertiesResourceType.PLAIN_FORMAT.equalsIgnoreCase( propertiesResourceType.getFormat() ) ) 2076 { 2077 properties.load( in ); 2078 } 2079 else if ( PropertiesResourceType.XML_FORMAT.equalsIgnoreCase( propertiesResourceType.getFormat() ) ) 2080 { 2081 properties.loadFromXML( in ); 2082 } 2083 } 2084 else if ( propertiesResourceType.isOptional() ) 2085 { 2086 if ( this.isLoggable( Level.WARNING ) ) 2087 { 2088 this.log( Level.WARNING, Messages.getMessage( 2089 "propertiesNotFound", propertiesResourceType.getLocation() ), null ); 2090 2091 } 2092 } 2093 else 2094 { 2095 throw new MojoExecutionException( Messages.getMessage( 2096 "propertiesNotFound", propertiesResourceType.getLocation() ) ); 2097 2098 } 2099 2100 suppressExceptionOnClose = false; 2101 } 2102 catch ( final SocketTimeoutException e ) 2103 { 2104 String m = Messages.getMessage( e ); 2105 m = m == null ? "" : " " + m; 2106 2107 if ( propertiesResourceType.isOptional() ) 2108 { 2109 if ( this.isLoggable( Level.WARNING ) ) 2110 { 2111 this.log( Level.WARNING, Messages.getMessage( 2112 "failedLoadingProperties", url.toExternalForm(), m ), e ); 2113 2114 } 2115 } 2116 else 2117 { 2118 throw new MojoExecutionException( Messages.getMessage( 2119 "failedLoadingProperties", url.toExternalForm(), m ), e ); 2120 2121 } 2122 } 2123 catch ( final IOException e ) 2124 { 2125 String m = Messages.getMessage( e ); 2126 m = m == null ? "" : " " + m; 2127 2128 if ( propertiesResourceType.isOptional() ) 2129 { 2130 if ( this.isLoggable( Level.WARNING ) ) 2131 { 2132 this.log( Level.WARNING, Messages.getMessage( 2133 "failedLoadingProperties", url.toExternalForm(), m ), e ); 2134 2135 } 2136 } 2137 else 2138 { 2139 throw new MojoExecutionException( Messages.getMessage( 2140 "failedLoadingProperties", url.toExternalForm(), m ), e ); 2141 2142 } 2143 } 2144 finally 2145 { 2146 try 2147 { 2148 if ( in != null ) 2149 { 2150 in.close(); 2151 } 2152 } 2153 catch ( final IOException e ) 2154 { 2155 if ( suppressExceptionOnClose ) 2156 { 2157 this.getLog().error( e ); 2158 } 2159 else 2160 { 2161 throw new MojoExecutionException( Messages.getMessage( e ), e ); 2162 } 2163 } 2164 } 2165 2166 return properties; 2167 } 2168 2169 /** 2170 * Tests if messages at a given level are logged. 2171 * 2172 * @param level The level to test. 2173 * 2174 * @return {@code true}, if messages at {@code level} are logged; {@code false}, if messages at {@code level} are 2175 * suppressed. 2176 * 2177 * @throws NullPointerException if {@code level} is {@code null}. 2178 * @throws MojoExecutionException if testing the level fails. 2179 * 2180 * @see #isVerbose() 2181 * @since 1.2 2182 */ 2183 protected boolean isLoggable( final Level level ) throws MojoExecutionException 2184 { 2185 if ( level == null ) 2186 { 2187 throw new NullPointerException( "level" ); 2188 } 2189 2190 boolean loggable = false; 2191 2192 if ( level.intValue() <= Level.CONFIG.intValue() ) 2193 { 2194 loggable = this.getLog().isDebugEnabled(); 2195 } 2196 else if ( level.intValue() <= Level.INFO.intValue() ) 2197 { 2198 loggable = this.getLog().isInfoEnabled() && this.isVerbose(); 2199 } 2200 else if ( level.intValue() <= Level.WARNING.intValue() ) 2201 { 2202 loggable = this.getLog().isWarnEnabled(); 2203 } 2204 else if ( level.intValue() <= Level.SEVERE.intValue() ) 2205 { 2206 loggable = this.getLog().isErrorEnabled(); 2207 } 2208 2209 return loggable; 2210 } 2211 2212 /** 2213 * Logs a separator at a given level. 2214 * 2215 * @param level The level to log a separator at. 2216 * 2217 * @throws MojoExecutionException if logging fails. 2218 * 2219 * @deprecated As of JOMC 1.1, please use method {@link #logSeparator()}. This method will be removed in version 2220 * 2.0. 2221 */ 2222 @Deprecated 2223 protected void logSeparator( final Level level ) throws MojoExecutionException 2224 { 2225 this.logSeparator(); 2226 } 2227 2228 /** 2229 * Logs a separator. 2230 * 2231 * @throws MojoExecutionException if logging fails. 2232 * 2233 * @since 1.1 2234 */ 2235 protected void logSeparator() throws MojoExecutionException 2236 { 2237 if ( this.isLoggable( Level.INFO ) ) 2238 { 2239 this.log( Level.INFO, Messages.getMessage( "separator" ), null ); 2240 } 2241 } 2242 2243 /** 2244 * Logs a message stating a tool is starting to process a module. 2245 * 2246 * @param toolName The tool starting execution. 2247 * @param module The module getting processed. 2248 * 2249 * @throws MojoExecutionException if logging fails. 2250 */ 2251 protected void logProcessingModule( final String toolName, final String module ) throws MojoExecutionException 2252 { 2253 if ( this.isLoggable( Level.INFO ) ) 2254 { 2255 this.log( Level.INFO, Messages.getMessage( "processingModule", toolName, module ), null ); 2256 } 2257 } 2258 2259 /** 2260 * Logs a message stating a tool is starting to process a model. 2261 * 2262 * @param toolName The tool starting execution. 2263 * @param model The model getting processed. 2264 * 2265 * @throws MojoExecutionException if logging fails. 2266 * 2267 * @since 1.1 2268 */ 2269 protected void logProcessingModel( final String toolName, final String model ) throws MojoExecutionException 2270 { 2271 if ( this.isLoggable( Level.INFO ) ) 2272 { 2273 this.log( Level.INFO, Messages.getMessage( "processingModel", toolName, model ), null ); 2274 } 2275 } 2276 2277 /** 2278 * Logs a message stating that a module has not been found. 2279 * 2280 * @param module The module not having been found. 2281 * 2282 * @throws MojoExecutionException if logging fails. 2283 */ 2284 protected void logMissingModule( final String module ) throws MojoExecutionException 2285 { 2286 if ( this.isLoggable( Level.WARNING ) ) 2287 { 2288 this.log( Level.WARNING, Messages.getMessage( "missingModule", module ), null ); 2289 } 2290 } 2291 2292 /** 2293 * Logs a message stating that a tool successfully completed execution. 2294 * 2295 * @param toolName The name of the tool. 2296 * 2297 * @throws MojoExecutionException if logging fails. 2298 */ 2299 protected void logToolSuccess( final String toolName ) throws MojoExecutionException 2300 { 2301 if ( this.isLoggable( Level.INFO ) ) 2302 { 2303 this.log( Level.INFO, Messages.getMessage( "toolSuccess", toolName ), null ); 2304 } 2305 } 2306 2307 /** 2308 * Logs a {@code ModelValidationReport}. 2309 * 2310 * @param context The context to use when marshalling detail elements of the report. 2311 * @param level The level to log at. 2312 * @param report The report to log. 2313 * 2314 * @throws MojoExecutionException if logging {@code report} fails. 2315 */ 2316 protected void log( final ModelContext context, final Level level, final ModelValidationReport report ) 2317 throws MojoExecutionException 2318 { 2319 try 2320 { 2321 if ( !report.getDetails().isEmpty() ) 2322 { 2323 this.logSeparator(); 2324 Marshaller marshaller = null; 2325 2326 for ( ModelValidationReport.Detail detail : report.getDetails() ) 2327 { 2328 this.log( detail.getLevel(), "o " + detail.getMessage(), null ); 2329 2330 if ( detail.getElement() != null && this.isLoggable( Level.FINEST ) ) 2331 { 2332 if ( marshaller == null ) 2333 { 2334 marshaller = context.createMarshaller( this.getModel() ); 2335 marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE ); 2336 } 2337 2338 final StringWriter stringWriter = new StringWriter(); 2339 marshaller.marshal( detail.getElement(), stringWriter ); 2340 this.log( Level.FINEST, stringWriter.toString(), null ); 2341 } 2342 } 2343 } 2344 } 2345 catch ( final ModelException e ) 2346 { 2347 throw new MojoExecutionException( Messages.getMessage( e ), e ); 2348 } 2349 catch ( final JAXBException e ) 2350 { 2351 String message = Messages.getMessage( e ); 2352 if ( message == null && e.getLinkedException() != null ) 2353 { 2354 message = Messages.getMessage( e.getLinkedException() ); 2355 } 2356 2357 throw new MojoExecutionException( message, e ); 2358 } 2359 } 2360 2361 /** 2362 * Logs a message and throwable at a given level. 2363 * 2364 * @param level The level to log at. 2365 * @param message The message to log or {@code null}. 2366 * @param throwable The throwable to log or {@code null}. 2367 * 2368 * @throws MojoExecutionException if logging fails. 2369 */ 2370 protected void log( final Level level, final String message, final Throwable throwable ) 2371 throws MojoExecutionException 2372 { 2373 BufferedReader reader = null; 2374 boolean suppressExceptionOnClose = true; 2375 2376 try 2377 { 2378 if ( this.isLoggable( level ) ) 2379 { 2380 String line; 2381 reader = new BufferedReader( new StringReader( message == null ? "" : message ) ); 2382 boolean throwableLogged = false; 2383 2384 while ( ( line = reader.readLine() ) != null ) 2385 { 2386 final String mojoMessage = 2387 Messages.getMessage( this.getLog().isDebugEnabled() ? "debugMessage" : "logMessage", line, 2388 Thread.currentThread().getName(), new Date( System.currentTimeMillis() ) ); 2389 2390 if ( level.intValue() <= Level.CONFIG.intValue() ) 2391 { 2392 this.getLog().debug( mojoMessage, throwableLogged ? null : throwable ); 2393 } 2394 else if ( level.intValue() <= Level.INFO.intValue() ) 2395 { 2396 this.getLog().info( mojoMessage, throwableLogged ? null : throwable ); 2397 } 2398 else if ( level.intValue() <= Level.WARNING.intValue() ) 2399 { 2400 this.getLog().warn( mojoMessage, throwableLogged ? null : throwable ); 2401 } 2402 else if ( level.intValue() <= Level.SEVERE.intValue() ) 2403 { 2404 this.getLog().error( mojoMessage, throwableLogged ? null : throwable ); 2405 } 2406 2407 throwableLogged = true; 2408 } 2409 } 2410 2411 suppressExceptionOnClose = false; 2412 } 2413 catch ( final IOException e ) 2414 { 2415 this.getLog().error( e ); 2416 throw new AssertionError( e ); 2417 } 2418 finally 2419 { 2420 try 2421 { 2422 if ( reader != null ) 2423 { 2424 reader.close(); 2425 } 2426 } 2427 catch ( final IOException e ) 2428 { 2429 if ( !suppressExceptionOnClose ) 2430 { 2431 throw new AssertionError( e ); 2432 } 2433 } 2434 } 2435 } 2436 2437 /** 2438 * Configures a {@code ModelContext} instance. 2439 * 2440 * @param context The model context to configure. 2441 * 2442 * @throws NullPointerException if {@code context} is {@code null}. 2443 * @throws MojoExecutionException if configuring {@code context} fails. 2444 */ 2445 protected void setupModelContext( final ModelContext context ) throws MojoExecutionException 2446 { 2447 if ( context == null ) 2448 { 2449 throw new NullPointerException( "context" ); 2450 } 2451 2452 if ( this.isVerbose() || this.getLog().isDebugEnabled() ) 2453 { 2454 context.setLogLevel( this.getLog().isDebugEnabled() ? Level.ALL : Level.INFO ); 2455 } 2456 2457 try 2458 { 2459 context.setModletSchemaSystemId( this.modletSchemaSystemId ); 2460 context.getListeners().add( new ModelContext.Listener() 2461 { 2462 2463 @Override 2464 public void onLog( final Level level, final String message, final Throwable t ) 2465 { 2466 super.onLog( level, message, t ); 2467 2468 try 2469 { 2470 log( level, message, t ); 2471 } 2472 catch ( final MojoExecutionException e ) 2473 { 2474 getLog().error( e ); 2475 } 2476 } 2477 2478 } ); 2479 2480 if ( this.providerLocation != null ) 2481 { 2482 context.setAttribute( DefaultModelContext.PROVIDER_LOCATION_ATTRIBUTE_NAME, this.providerLocation ); 2483 } 2484 2485 if ( this.platformProviderLocation != null ) 2486 { 2487 context.setAttribute( DefaultModelContext.PLATFORM_PROVIDER_LOCATION_ATTRIBUTE_NAME, 2488 this.platformProviderLocation ); 2489 2490 } 2491 2492 if ( this.modletLocation != null ) 2493 { 2494 context.setAttribute( DefaultModletProvider.MODLET_LOCATION_ATTRIBUTE_NAME, this.modletLocation ); 2495 } 2496 2497 if ( this.transformerLocation != null ) 2498 { 2499 context.setAttribute( DefaultModelProcessor.TRANSFORMER_LOCATION_ATTRIBUTE_NAME, 2500 this.transformerLocation ); 2501 } 2502 2503 if ( this.moduleLocation != null ) 2504 { 2505 context.setAttribute( DefaultModelProvider.MODULE_LOCATION_ATTRIBUTE_NAME, this.moduleLocation ); 2506 } 2507 2508 context.setAttribute( ToolsModelProvider.MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME, 2509 this.modelObjectClasspathResolutionEnabled ); 2510 2511 context.setAttribute( ToolsModelProcessor.MODEL_OBJECT_CLASSPATH_RESOLUTION_ENABLED_ATTRIBUTE_NAME, 2512 this.modelObjectClasspathResolutionEnabled ); 2513 2514 context.setAttribute( DefaultModletProvider.VALIDATING_ATTRIBUTE_NAME, this.modletResourceValidationEnabled ); 2515 context.setAttribute( DefaultModelProvider.VALIDATING_ATTRIBUTE_NAME, this.modelResourceValidationEnabled ); 2516 2517 if ( this.modelContextAttributes != null ) 2518 { 2519 for ( ModelContextAttribute e : this.modelContextAttributes ) 2520 { 2521 final Object object = e.getObject(); 2522 2523 if ( object != null ) 2524 { 2525 context.setAttribute( e.getKey(), object ); 2526 } 2527 else 2528 { 2529 context.clearAttribute( e.getKey() ); 2530 } 2531 } 2532 } 2533 } 2534 catch ( final InstantiationException e ) 2535 { 2536 throw new MojoExecutionException( Messages.getMessage( e ), e ); 2537 } 2538 } 2539 2540 /** 2541 * Configures a {@code JomcTool} instance. 2542 * 2543 * @param context The model context to use for configuring {@code tool}. 2544 * @param tool The tool to configure. 2545 * 2546 * @throws NullPointerException if {@code context} of {@code tool} is {@code null}. 2547 * @throws MojoExecutionException if configuring {@code tool} fails. 2548 */ 2549 protected void setupJomcTool( final ModelContext context, final JomcTool tool ) throws MojoExecutionException 2550 { 2551 if ( context == null ) 2552 { 2553 throw new NullPointerException( "context" ); 2554 } 2555 if ( tool == null ) 2556 { 2557 throw new NullPointerException( "tool" ); 2558 } 2559 2560 try 2561 { 2562 if ( this.isVerbose() || this.getLog().isDebugEnabled() ) 2563 { 2564 tool.setLogLevel( this.getLog().isDebugEnabled() ? Level.ALL : Level.INFO ); 2565 } 2566 2567 tool.getListeners().add( new JomcTool.Listener() 2568 { 2569 2570 @Override 2571 public void onLog( final Level level, final String message, final Throwable t ) 2572 { 2573 super.onLog( level, message, t ); 2574 2575 try 2576 { 2577 log( level, message, t ); 2578 } 2579 catch ( final MojoExecutionException e ) 2580 { 2581 getLog().error( e ); 2582 } 2583 } 2584 2585 } ); 2586 2587 if ( this.templateEncoding != null ) 2588 { 2589 if ( this.isLoggable( Level.WARNING ) ) 2590 { 2591 this.log( Level.WARNING, Messages.getMessage( 2592 "deprecationWarning", "templateEncoding", "defaultTemplateEncoding" ), null ); 2593 2594 } 2595 2596 tool.setDefaultTemplateEncoding( this.templateEncoding ); 2597 } 2598 else 2599 { 2600 tool.setDefaultTemplateEncoding( this.defaultTemplateEncoding ); 2601 } 2602 2603 tool.setInputEncoding( this.sourceEncoding ); 2604 tool.setOutputEncoding( this.sourceEncoding ); 2605 tool.setDefaultTemplateProfile( this.defaultTemplateProfile ); 2606 tool.setTemplateProfile( this.templateProfile ); 2607 tool.setModel( this.getModel( context ) ); 2608 2609 if ( this.indentation != null ) 2610 { 2611 tool.setIndentation( StringEscapeUtils.unescapeJava( this.indentation ) ); 2612 } 2613 2614 if ( this.lineSeparator != null ) 2615 { 2616 tool.setLineSeparator( StringEscapeUtils.unescapeJava( this.lineSeparator ) ); 2617 } 2618 2619 if ( this.locale != null ) 2620 { 2621 tool.setLocale( new Locale( StringUtils.defaultString( this.locale.getLanguage() ), 2622 StringUtils.defaultString( this.locale.getCountry() ), 2623 StringUtils.defaultString( this.locale.getVariant() ) ) ); 2624 2625 } 2626 2627 if ( this.velocityPropertyResources != null ) 2628 { 2629 for ( int i = 0, s0 = this.velocityPropertyResources.size(); i < s0; i++ ) 2630 { 2631 for ( Map.Entry<Object, Object> e : 2632 this.getProperties( this.velocityPropertyResources.get( i ) ).entrySet() ) 2633 { 2634 if ( e.getValue() != null ) 2635 { 2636 tool.getVelocityEngine().setProperty( e.getKey().toString(), e ); 2637 } 2638 else 2639 { 2640 tool.getVelocityEngine().clearProperty( e.getKey().toString() ); 2641 } 2642 } 2643 } 2644 } 2645 2646 if ( this.velocityProperties != null ) 2647 { 2648 for ( VelocityProperty e : this.velocityProperties ) 2649 { 2650 final Object object = e.getObject(); 2651 2652 if ( object != null ) 2653 { 2654 tool.getVelocityEngine().setProperty( e.getKey(), object ); 2655 } 2656 else 2657 { 2658 tool.getVelocityEngine().clearProperty( e.getKey() ); 2659 } 2660 } 2661 } 2662 2663 for ( Map.Entry<Object, Object> e : System.getProperties().entrySet() ) 2664 { 2665 tool.getTemplateParameters().put( e.getKey().toString(), e.getValue() ); 2666 } 2667 2668 if ( this.getMavenProject().getProperties() != null ) 2669 { 2670 for ( Map.Entry<Object, Object> e : System.getProperties().entrySet() ) 2671 { 2672 tool.getTemplateParameters().put( e.getKey().toString(), e.getValue() ); 2673 } 2674 } 2675 2676 if ( this.templateParameterResources != null ) 2677 { 2678 for ( int i = 0, s0 = this.templateParameterResources.size(); i < s0; i++ ) 2679 { 2680 for ( Map.Entry<Object, Object> e : 2681 this.getProperties( this.templateParameterResources.get( i ) ).entrySet() ) 2682 { 2683 if ( e.getValue() != null ) 2684 { 2685 tool.getTemplateParameters().put( e.getKey().toString(), e.getValue() ); 2686 } 2687 else 2688 { 2689 tool.getTemplateParameters().remove( e.getKey().toString() ); 2690 } 2691 } 2692 } 2693 } 2694 2695 if ( this.templateParameters != null ) 2696 { 2697 for ( TemplateParameter e : this.templateParameters ) 2698 { 2699 final Object object = e.getObject(); 2700 2701 if ( object != null ) 2702 { 2703 tool.getTemplateParameters().put( e.getKey(), object ); 2704 } 2705 else 2706 { 2707 tool.getTemplateParameters().remove( e.getKey() ); 2708 } 2709 } 2710 } 2711 2712 if ( this.templateLocation != null ) 2713 { 2714 final URL url = this.getDirectory( this.templateLocation ); 2715 tool.setTemplateLocation( url ); 2716 2717 if ( url == null && this.isLoggable( Level.WARNING ) ) 2718 { 2719 this.log( Level.WARNING, Messages.getMessage( "locationNotFound", this.templateLocation ), null ); 2720 } 2721 } 2722 } 2723 catch ( final InstantiationException e ) 2724 { 2725 throw new MojoExecutionException( Messages.getMessage( e ), e ); 2726 } 2727 catch ( final IOException e ) 2728 { 2729 throw new MojoExecutionException( Messages.getMessage( e ), e ); 2730 } 2731 } 2732 2733 private Artifact getPluginArtifact( final Artifact a ) 2734 { 2735 for ( int i = 0, s0 = this.pluginArtifacts.size(); i < s0; i++ ) 2736 { 2737 final Artifact pluginArtifact = this.pluginArtifacts.get( i ); 2738 2739 if ( pluginArtifact.getGroupId().equals( a.getGroupId() ) 2740 && pluginArtifact.getArtifactId().equals( a.getArtifactId() ) 2741 && ( pluginArtifact.hasClassifier() 2742 ? pluginArtifact.getClassifier().equals( a.getClassifier() ) 2743 : !a.hasClassifier() ) ) 2744 { 2745 return pluginArtifact; 2746 } 2747 } 2748 2749 return null; 2750 } 2751 2752}