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