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