Coverage Report - org.apache.maven.archetype.mojos.CreateArchetypeFromProjectMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
CreateArchetypeFromProjectMojo
0%
0/50
0%
0/30
7.667
 
 1  
 package org.apache.maven.archetype.mojos;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.maven.archetype.ArchetypeCreationRequest;
 23  
 import org.apache.maven.archetype.ArchetypeCreationResult;
 24  
 import org.apache.maven.archetype.ArchetypeManager;
 25  
 import org.apache.maven.archetype.common.Constants;
 26  
 import org.apache.maven.archetype.ui.creation.ArchetypeCreationConfigurator;
 27  
 import org.apache.maven.artifact.repository.ArtifactRepository;
 28  
 import org.apache.maven.execution.MavenSession;
 29  
 import org.apache.maven.plugin.AbstractMojo;
 30  
 import org.apache.maven.plugin.MojoExecutionException;
 31  
 import org.apache.maven.plugin.MojoFailureException;
 32  
 import org.apache.maven.project.MavenProject;
 33  
 import org.codehaus.plexus.util.PropertyUtils;
 34  
 import org.codehaus.plexus.util.StringUtils;
 35  
 
 36  
 import java.io.File;
 37  
 import java.util.ArrayList;
 38  
 import java.util.Arrays;
 39  
 import java.util.List;
 40  
 import java.util.Properties;
 41  
 
 42  
 /**
 43  
  * <p>
 44  
  * Creates an archetype project from the current project.
 45  
  * </p>
 46  
  * <p>
 47  
  * This goal reads your source and resource files, the values of its parameters,
 48  
  * and properties you specify in a <code>.property</code> file, and uses them to
 49  
  * create a Maven archetype project using the maven-archetype packaging. 
 50  
  * If you build the resulting project, it will create the archetype. You can then
 51  
  * use this archetype to create new projects that resemble the original.  
 52  
  * </p>
 53  
  * <p>
 54  
  * The maven-archetype-plugin uses Velocity to expand template files, and this documentation
 55  
  * talks about 'Velocity Properties', which are values substituted into Velocity templates.
 56  
  * See <a href="http://velocity.apache.org/engine/devel/user-guide.html">The Velocity User's Guide</a>
 57  
  * for more information.
 58  
  * </p>
 59  
  * <p>
 60  
  * This goal modifies the text of the files of the current project to form the Velocity template files
 61  
  * that make up the archetype.
 62  
  * </p>
 63  
  * <dl>
 64  
  * <dt>GAV</dt><dd>The GAV values for the current project are replaced by properties: groupId, artifactId, and version.
 65  
  * The user chooses new values for these when generating a project from the archetype.</dd>
 66  
  * <dt>package</dt><dd>All the files under one specified Java (or cognate) package are relocated to a project 
 67  
  * that the user chooses when generating a project. References to the class name are replaced by a property reference. For
 68  
  * example, if the current project's sources are in the package <code>org.apache.saltedpeanuts</code>, then 
 69  
  * any example of the string <code>org.apache.saltedpeanuts</code> is replaced with the Velocity property
 70  
  * reference <code>${packageName}</code>. When the user generates a project, this is in turn replaced by
 71  
  * his or her choice of a package.  
 72  
  * </dd>
 73  
  * <dt>custom properties</dt><dd>You may identify additional strings that should be replaced by parameters. 
 74  
  * To add custom properties, you must use the <code>propertyFile</code> parameter to specify a property file.
 75  
  * See the documentation for <code>propertyFile</code> for the details.
 76  
  * </dl>
 77  
  * <p>
 78  
  * Note that you may need to edit the results of this goal. This goal has no way to exclude unwanted files,
 79  
  * or add copyright notices to the Velocity templates, or add more complex elements to the archetype metadata file.
 80  
  * </p>
 81  
  * <p>
 82  
  * This goal also generates a simple integration-test that exercises the generated archetype.
 83  
  * </p>
 84  
  *
 85  
  * @author rafale
 86  
  * @requiresProject true
 87  
  * @goal create-from-project
 88  
  * @execute phase="generate-sources"
 89  
  * @aggregator
 90  
  */
 91  0
 public class CreateArchetypeFromProjectMojo
 92  
     extends AbstractMojo
 93  
 {
 94  
     /** @component */
 95  
     private ArchetypeCreationConfigurator configurator;
 96  
 
 97  
     /**
 98  
      * Enable the interactive mode to define the archetype from the project.
 99  
      *
 100  
      * @parameter expression="${interactive}" default-value="false"
 101  
      */
 102  
     private boolean interactive;
 103  
 
 104  
     /** @component */
 105  
     private ArchetypeManager manager;
 106  
 
 107  
     /**
 108  
      * File extensions which are checked for project's text files (vs binary files).
 109  
      *
 110  
      * @parameter expression="${archetype.filteredExtentions}"
 111  
      */
 112  
     private String archetypeFilteredExtentions;
 113  
 
 114  
     /**
 115  
      * Directory names which are checked for project's sources main package.
 116  
      *
 117  
      * @parameter expression="${archetype.languages}"
 118  
      */
 119  
     private String archetypeLanguages;
 120  
 
 121  
     /**
 122  
      * The location of the registry file.
 123  
      *
 124  
      * @parameter expression="${user.home}/.m2/archetype.xml"
 125  
      */
 126  
     private File archetypeRegistryFile;
 127  
 
 128  
     /**
 129  
      * Velocity templates encoding.
 130  
      *
 131  
      * @parameter default-value="UTF-8" expression="${archetype.encoding}"
 132  
      */
 133  
     private String defaultEncoding;
 134  
 
 135  
     /**
 136  
      * Create a partial archetype.
 137  
      *
 138  
      * @parameter expression="${archetype.partialArchetype}"
 139  
      */
 140  0
     private boolean partialArchetype = false;
 141  
 
 142  
     /**
 143  
      * Create pom's velocity templates with CDATA preservation. This uses the <code>String.replaceAll()</code>
 144  
      * method and risks to have some overly replacement capabilities (beware of '1.0' value).
 145  
      *
 146  
      * @parameter expression="${archetype.preserveCData}"
 147  
      */
 148  0
     private boolean preserveCData = false;
 149  
 
 150  
     /** @parameter expression="${localRepository}"
 151  
      * @readonly
 152  
      **/
 153  
     private ArtifactRepository localRepository;
 154  
 
 155  
     /**
 156  
      * POMs in archetype are created with their initial parent.
 157  
      * This property is ignored when preserveCData is true.
 158  
      *
 159  
      * @parameter expression="${archetype.keepParent}"
 160  
      */
 161  0
     private boolean keepParent = true;
 162  
 
 163  
     /**
 164  
      * The Maven project to create an archetype from.
 165  
      *
 166  
      * @parameter expression="${project}"
 167  
      * @required
 168  
      * @readonly
 169  
      */
 170  
     private MavenProject project;
 171  
 
 172  
     /**
 173  
      * The property file that holds the plugin configuration. If this is provided, then
 174  
      * the plugin reads properties from here. The properties in here can be standard
 175  
      * properties listed below or custom properties for this archetype. The standard properties
 176  
      * are below. Several of them overlap parameters of this goal; it's better to just
 177  
      * set the parameter.
 178  
      * 
 179  
      *  <dl><dt>package</dt><dd>See the packageName parameter.</dd>
 180  
      *  <dt>archetype.languages</dt><dd>See the archetypeLanguages parameter.</dd>
 181  
      *  <dt>groupId</dt><dd>The default groupId of the generated project.</dd>
 182  
      *  <dt>artifactId</dt><dd>The default artifactId of the generated project.</dd> 
 183  
      *  <dt>version</dt><dd>The default version of the generated project.</dd>
 184  
      *  <dt>archetype.filteredExtensions</dt><dd>See the filteredExensions parameter.</dd>
 185  
      *  </dl>
 186  
      *  <strong>Custom Properties</strong>
 187  
      *  <p>
 188  
      *  Custom properties allow you to replace some constant values in the project's files
 189  
      *  with Velocity macro references. When a user generates a project from your archetype
 190  
      *  he or she gets the opportunity to replace the value from the source project. 
 191  
      *  </p>
 192  
      *  <p>
 193  
      *  Custom property names <strong>may not contain the '.' character</strong>.
 194  
      *  </p>
 195  
      *  <p>
 196  
      *  For example, if you include a line like the following in your property file:
 197  
      *  <pre>
 198  
      *          cxf-version=2.5.1-SNAPSHOT
 199  
      *  </pre>
 200  
      *  the plugin will search your files for the string <pre>2.5.1-SNAPSHOT</pre> and
 201  
      *  replace them with references to a velocity macro <pre>cxf-version</pre>. It will 
 202  
      *  then list <pre>cxf-version</pre> as a <pre>requiredProperty</pre> in the 
 203  
      *  archetype-metadata.xml, with <pre>2.5.1-SNAPSHOT</pre> as the default value.
 204  
      *  </p>
 205  
      *  
 206  
      *
 207  
      * @parameter expression="${archetype.properties}"
 208  
      */
 209  
     private File propertyFile;
 210  
 
 211  
     /**
 212  
      * The property telling which phase to call on the generated archetype.
 213  
      * Interesting values are: <code>package</code>, <code>integration-test</code>, <code>install</code> and <code>deploy</code>.
 214  
      *
 215  
      * @parameter expression="${archetype.postPhase}" default-value="package"
 216  
      */
 217  
     private String archetypePostPhase;
 218  
 
 219  
     /**
 220  
      * The directory where the archetype should be created.
 221  
      * 
 222  
      * @parameter expression="${project.build.directory}/generated-sources/archetype"
 223  
      */
 224  
     private File outputDirectory;
 225  
 
 226  
     /** @parameter expression="${testMode}" */
 227  
     private boolean testMode;
 228  
 
 229  
     /** 
 230  
      * The package name for Java source files to be incorporated in the archetype and 
 231  
      * and relocated to the package that the user selects.
 232  
      * 
 233  
      * @parameter expression="${packageName}" */
 234  
     private String packageName; //Find a better way to resolve the package!!! enforce usage of the configurator
 235  
 
 236  
     /**
 237  
      *  @parameter expression="${session}"
 238  
      *  @readonly
 239  
      */
 240  
     private MavenSession session;
 241  
 
 242  
     public void execute()
 243  
         throws MojoExecutionException, MojoFailureException
 244  
     {
 245  0
         Properties executionProperties = session.getExecutionProperties();
 246  
         try
 247  
         {
 248  0
             if ( propertyFile != null )
 249  
             {
 250  0
                 propertyFile.getParentFile().mkdirs();
 251  
             }
 252  
 
 253  0
             List<String> languages = getLanguages( archetypeLanguages, propertyFile );
 254  
 
 255  0
             Properties properties =
 256  
                 configurator.configureArchetypeCreation( project, Boolean.valueOf( interactive ), executionProperties,
 257  
                                                          propertyFile, languages );
 258  
 
 259  0
             List<String> filtereds = getFilteredExtensions( archetypeFilteredExtentions, propertyFile );
 260  
 
 261  0
             ArchetypeCreationRequest request = new ArchetypeCreationRequest()
 262  
                 .setDefaultEncoding( defaultEncoding )
 263  
                 .setProject( project )
 264  
                 /* Used when in interactive mode */
 265  
                 .setProperties( properties )
 266  
                 .setLanguages( languages )
 267  
                 /* Should be refactored to use some ant patterns */
 268  
                 .setFiltereds( filtereds )
 269  
                 /* This should be correctly handled */
 270  
                 .setPreserveCData( preserveCData )
 271  
                 .setKeepParent( keepParent )
 272  
                 .setPartialArchetype( partialArchetype )
 273  
                 /* This should be used before there and use only languages and filtereds */
 274  
                 .setArchetypeRegistryFile( archetypeRegistryFile )
 275  
                 .setLocalRepository( localRepository )
 276  
                 /* this should be resolved and asked for user to verify */
 277  
                 .setPackageName( packageName )
 278  
                 .setPostPhase( archetypePostPhase )
 279  
                 .setOutputDirectory( outputDirectory );
 280  
 
 281  0
             ArchetypeCreationResult result = manager.createArchetypeFromProject( request );
 282  
 
 283  0
             if ( result.getCause() != null )
 284  
             {
 285  0
                 throw new MojoFailureException( result.getCause(), result.getCause().getMessage(),
 286  
                                                 result.getCause().getMessage() );
 287  
             }
 288  
 
 289  0
             getLog().info( "Archetype created in " + outputDirectory );
 290  
 
 291  0
             if ( testMode )
 292  
             {
 293  
                 // Now here a properties file would be useful to write so that we could automate
 294  
                 // some functional tests where we string together an:
 295  
                 //
 296  
                 // archetype create from project -> deploy it into a test repo
 297  
                 // project create from archetype -> use the repository we deployed to archetype to
 298  
                 // generate
 299  
                 // test the output
 300  
                 //
 301  
                 // This of course would be strung together from the outside.
 302  
             }
 303  
 
 304  
         }
 305  0
         catch ( MojoFailureException ex )
 306  
         {
 307  0
             throw ex;
 308  
         }
 309  0
         catch ( Exception ex )
 310  
         {
 311  0
             throw new MojoFailureException( ex, ex.getMessage(), ex.getMessage() );
 312  0
         }
 313  0
     }
 314  
 
 315  
     private List<String> getFilteredExtensions( String archetypeFilteredExtentions, File propertyFile )
 316  
     {
 317  0
         List<String> filteredExtensions = new ArrayList<String>();
 318  
 
 319  0
         if ( StringUtils.isNotEmpty( archetypeFilteredExtentions ) )
 320  
         {
 321  0
             filteredExtensions.addAll( Arrays.asList( StringUtils.split( archetypeFilteredExtentions, "," ) ) );
 322  
 
 323  0
             getLog().debug( "Found in command line extensions = " + filteredExtensions );
 324  
         }
 325  
 
 326  0
         if ( filteredExtensions.isEmpty() && propertyFile != null && propertyFile.exists() )
 327  
         {
 328  0
             Properties properties = PropertyUtils.loadProperties( propertyFile );
 329  
 
 330  0
             String extensions = properties.getProperty( Constants.ARCHETYPE_FILTERED_EXTENSIONS );
 331  0
             if ( StringUtils.isNotEmpty( extensions ) )
 332  
             {
 333  0
                 filteredExtensions.addAll( Arrays.asList( StringUtils.split( extensions, "," ) ) );
 334  
             }
 335  
 
 336  0
             getLog().debug( "Found in propertyFile " + propertyFile.getName() + " extensions = " + filteredExtensions );
 337  
         }
 338  
 
 339  0
         if ( filteredExtensions.isEmpty() )
 340  
         {
 341  0
             filteredExtensions.addAll( Constants.DEFAULT_FILTERED_EXTENSIONS );
 342  
 
 343  0
             getLog().debug( "Using default extensions = " + filteredExtensions );
 344  
         }
 345  
 
 346  0
         return filteredExtensions;
 347  
     }
 348  
 
 349  
     private List<String> getLanguages( String archetypeLanguages, File propertyFile )
 350  
     {
 351  0
         List<String> resultingLanguages = new ArrayList<String>();
 352  
 
 353  0
         if ( StringUtils.isNotEmpty( archetypeLanguages ) )
 354  
         {
 355  0
             resultingLanguages.addAll( Arrays.asList( StringUtils.split( archetypeLanguages, "," ) ) );
 356  
 
 357  0
             getLog().debug( "Found in command line languages = " + resultingLanguages );
 358  
         }
 359  
 
 360  0
         if ( resultingLanguages.isEmpty() && propertyFile != null && propertyFile.exists() )
 361  
         {
 362  0
             Properties properties = PropertyUtils.loadProperties( propertyFile );
 363  
 
 364  0
             String languages = properties.getProperty( Constants.ARCHETYPE_LANGUAGES );
 365  0
             if ( StringUtils.isNotEmpty( languages ) )
 366  
             {
 367  0
                 resultingLanguages.addAll( Arrays.asList( StringUtils.split( languages, "," ) ) );
 368  
             }
 369  
 
 370  0
             getLog().debug( "Found in propertyFile " + propertyFile.getName() + " languages = " + resultingLanguages );
 371  
         }
 372  
 
 373  0
         if ( resultingLanguages.isEmpty() )
 374  
         {
 375  0
             resultingLanguages.addAll( Constants.DEFAULT_LANGUAGES );
 376  
 
 377  0
             getLog().debug( "Using default languages = " + resultingLanguages );
 378  
         }
 379  
 
 380  0
         return resultingLanguages;
 381  
     }
 382  
 }