Coverage Report - org.apache.maven.archetype.generator.DefaultFilesetArchetypeGenerator
 
Classes in this File Line Coverage Branch Coverage Complexity
DefaultFilesetArchetypeGenerator
85%
234/274
71%
77/108
4.154
 
 1  
 package org.apache.maven.archetype.generator;
 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.ArchetypeGenerationRequest;
 23  
 import org.apache.maven.archetype.common.ArchetypeArtifactManager;
 24  
 import org.apache.maven.archetype.common.ArchetypeFilesResolver;
 25  
 import org.apache.maven.archetype.common.Constants;
 26  
 import org.apache.maven.archetype.common.PomManager;
 27  
 import org.apache.maven.archetype.exception.ArchetypeGenerationFailure;
 28  
 import org.apache.maven.archetype.exception.ArchetypeNotConfigured;
 29  
 import org.apache.maven.archetype.exception.InvalidPackaging;
 30  
 import org.apache.maven.archetype.exception.OutputFileExists;
 31  
 import org.apache.maven.archetype.exception.PomFileExists;
 32  
 import org.apache.maven.archetype.exception.ProjectDirectoryExists;
 33  
 import org.apache.maven.archetype.exception.UnknownArchetype;
 34  
 import org.apache.maven.archetype.metadata.AbstractArchetypeDescriptor;
 35  
 import org.apache.maven.archetype.metadata.ArchetypeDescriptor;
 36  
 import org.apache.maven.archetype.metadata.FileSet;
 37  
 import org.apache.maven.archetype.metadata.ModuleDescriptor;
 38  
 import org.apache.maven.archetype.metadata.RequiredProperty;
 39  
 import org.apache.velocity.VelocityContext;
 40  
 import org.apache.velocity.app.Velocity;
 41  
 import org.apache.velocity.context.Context;
 42  
 import org.codehaus.plexus.component.annotations.Component;
 43  
 import org.codehaus.plexus.component.annotations.Requirement;
 44  
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 45  
 import org.codehaus.plexus.util.FileUtils;
 46  
 import org.codehaus.plexus.util.IOUtil;
 47  
 import org.codehaus.plexus.util.StringUtils;
 48  
 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 49  
 import org.codehaus.plexus.velocity.VelocityComponent;
 50  
 import org.dom4j.DocumentException;
 51  
 
 52  
 import java.io.File;
 53  
 import java.io.FileNotFoundException;
 54  
 import java.io.FileOutputStream;
 55  
 import java.io.IOException;
 56  
 import java.io.InputStream;
 57  
 import java.io.OutputStream;
 58  
 import java.io.OutputStreamWriter;
 59  
 import java.io.StringWriter;
 60  
 import java.io.Writer;
 61  
 import java.util.ArrayList;
 62  
 import java.util.Iterator;
 63  
 import java.util.List;
 64  
 import java.util.regex.Pattern;
 65  
 import java.util.zip.ZipEntry;
 66  
 import java.util.zip.ZipFile;
 67  
 
 68  
 @Component( role = FilesetArchetypeGenerator.class )
 69  34
 public class DefaultFilesetArchetypeGenerator
 70  
     extends AbstractLogEnabled
 71  
     implements FilesetArchetypeGenerator
 72  
 {
 73  
     @Requirement
 74  
     private ArchetypeArtifactManager archetypeArtifactManager;
 75  
 
 76  
     @Requirement
 77  
     private ArchetypeFilesResolver archetypeFilesResolver;
 78  
 
 79  
     @Requirement
 80  
     private PomManager pomManager;
 81  
 
 82  
     @Requirement
 83  
     private VelocityComponent velocity;
 84  
 
 85  
     /**
 86  
      * Token delimiter.
 87  
      */
 88  
     private static final String DELIMITER = "__";
 89  
 
 90  
     /**
 91  
      * Pattern used to detect tokens in a string. Tokens are any text surrounded
 92  
      * by the delimiter.
 93  
      */
 94  2
     private static final Pattern TOKEN_PATTERN = Pattern.compile( ".*" + DELIMITER + ".*" + DELIMITER + ".*" );
 95  
 
 96  
     public void generateArchetype( ArchetypeGenerationRequest request, File archetypeFile )
 97  
         throws UnknownArchetype, ArchetypeNotConfigured, ProjectDirectoryExists, PomFileExists, OutputFileExists,
 98  
         ArchetypeGenerationFailure
 99  
     {
 100  26
         ClassLoader old = Thread.currentThread().getContextClassLoader();
 101  
 
 102  
         try
 103  
         {
 104  26
             ArchetypeDescriptor archetypeDescriptor =
 105  
                 archetypeArtifactManager.getFileSetArchetypeDescriptor( archetypeFile );
 106  
 
 107  26
             if ( !isArchetypeConfigured( archetypeDescriptor, request ) )
 108  
             {
 109  2
                 if ( request.isInteractiveMode() )
 110  
                 {
 111  0
                     throw new ArchetypeNotConfigured( "No archetype was chosen.", null );
 112  
                 }
 113  
 
 114  2
                 StringBuffer exceptionMessage = new StringBuffer(
 115  
                     "Archetype " + request.getArchetypeGroupId() + ":" + request.getArchetypeArtifactId() + ":"
 116  
                         + request.getArchetypeVersion() + " is not configured" );
 117  
 
 118  2
                 List<String> missingProperties = new ArrayList<String>( 0 );
 119  2
                 for ( RequiredProperty requiredProperty : archetypeDescriptor.getRequiredProperties() )
 120  
                 {
 121  16
                     if ( StringUtils.isEmpty( request.getProperties().getProperty( requiredProperty.getKey() ) ) )
 122  
                     {
 123  16
                         exceptionMessage.append( "\n\tProperty " + requiredProperty.getKey() + " is missing." );
 124  
 
 125  16
                         missingProperties.add( requiredProperty.getKey() );
 126  
                     }
 127  
                 }
 128  
 
 129  2
                 throw new ArchetypeNotConfigured( exceptionMessage.toString(), missingProperties );
 130  
             }
 131  
 
 132  24
             Context context = prepareVelocityContext( request );
 133  
 
 134  24
             String packageName = request.getPackage();
 135  24
             String artifactId = request.getArtifactId();
 136  24
             File outputDirectoryFile = new File( request.getOutputDirectory(), artifactId );
 137  24
             File basedirPom = new File( request.getOutputDirectory(), Constants.ARCHETYPE_POM );
 138  24
             File pom = new File( outputDirectoryFile, Constants.ARCHETYPE_POM );
 139  
 
 140  24
             List<String> archetypeResources = archetypeArtifactManager.getFilesetArchetypeResources( archetypeFile );
 141  
 
 142  24
             ZipFile archetypeZipFile = archetypeArtifactManager.getArchetypeZipFile( archetypeFile );
 143  
 
 144  24
             ClassLoader archetypeJarLoader = archetypeArtifactManager.getArchetypeJarLoader( archetypeFile );
 145  
 
 146  24
             Thread.currentThread().setContextClassLoader( archetypeJarLoader );
 147  
 
 148  24
             if ( archetypeDescriptor.isPartial() )
 149  
             {
 150  8
                 getLogger().debug( "Processing partial archetype " + archetypeDescriptor.getName() );
 151  8
                 if ( outputDirectoryFile.exists() )
 152  
                 {
 153  4
                     if ( !pom.exists() )
 154  
                     {
 155  0
                         throw new PomFileExists( "This is a partial archetype and the pom.xml file doesn't exist." );
 156  
                     }
 157  
 
 158  4
                     processPomWithMerge( context, pom, "" );
 159  
 
 160  4
                     processArchetypeTemplatesWithWarning( archetypeDescriptor, archetypeResources, archetypeZipFile, "",
 161  
                                                           context, packageName, outputDirectoryFile );
 162  
                 }
 163  
                 else
 164  
                 {
 165  4
                     if ( basedirPom.exists() )
 166  
                     {
 167  2
                         processPomWithMerge( context, basedirPom, "" );
 168  
 
 169  2
                         processArchetypeTemplatesWithWarning( archetypeDescriptor, archetypeResources, archetypeZipFile,
 170  
                                                               "", context, packageName,
 171  
                                                               new File( request.getOutputDirectory() ) );
 172  
                     }
 173  
                     else
 174  
                     {
 175  2
                         processPom( context, pom, "" );
 176  
 
 177  2
                         processArchetypeTemplates( archetypeDescriptor, archetypeResources, archetypeZipFile, "",
 178  
                                                    context, packageName, outputDirectoryFile );
 179  
                     }
 180  
                 }
 181  
 
 182  8
                 if ( archetypeDescriptor.getModules().size() > 0 )
 183  
                 {
 184  0
                     getLogger().info( "Modules ignored in partial mode" );
 185  
                 }
 186  
             }
 187  
             else
 188  
             {
 189  16
                 getLogger().debug( "Processing complete archetype " + archetypeDescriptor.getName() );
 190  16
                 if ( outputDirectoryFile.exists() && pom.exists() )
 191  
                 {
 192  0
                     throw new ProjectDirectoryExists(
 193  
                         "A Maven 2 project already exists in the directory " + outputDirectoryFile.getPath() );
 194  
                 }
 195  
 
 196  16
                 if ( outputDirectoryFile.exists() )
 197  
                 {
 198  0
                     getLogger().warn( "The directory " + outputDirectoryFile.getPath() + " already exists." );
 199  
                 }
 200  
 
 201  16
                 context.put( "rootArtifactId", artifactId );
 202  
 
 203  16
                 processFilesetModule( artifactId, artifactId, archetypeResources, pom, archetypeZipFile, "", basedirPom,
 204  
                                       outputDirectoryFile, packageName, archetypeDescriptor, context );
 205  
             }
 206  
 
 207  
             // ----------------------------------------------------------------------
 208  
             // Log message on OldArchetype creation
 209  
             // ----------------------------------------------------------------------
 210  24
             if ( getLogger().isInfoEnabled() )
 211  
             {
 212  24
                 getLogger().info( "project created from Archetype in dir: " + outputDirectoryFile.getAbsolutePath() );
 213  
             }
 214  
         }
 215  0
         catch ( FileNotFoundException ex )
 216  
         {
 217  0
             throw new ArchetypeGenerationFailure( ex );
 218  
         }
 219  0
         catch ( IOException ex )
 220  
         {
 221  0
             throw new ArchetypeGenerationFailure( ex );
 222  
         }
 223  0
         catch ( XmlPullParserException ex )
 224  
         {
 225  0
             throw new ArchetypeGenerationFailure( ex );
 226  
         }
 227  0
         catch ( DocumentException ex )
 228  
         {
 229  0
             throw new ArchetypeGenerationFailure( ex );
 230  
         }
 231  0
         catch ( ArchetypeGenerationFailure ex )
 232  
         {
 233  0
             throw new ArchetypeGenerationFailure( ex );
 234  
         }
 235  0
         catch ( InvalidPackaging ex )
 236  
         {
 237  0
             throw new ArchetypeGenerationFailure( ex );
 238  
         }
 239  
         finally
 240  
         {
 241  26
             Thread.currentThread().setContextClassLoader( old );
 242  24
         }
 243  24
     }
 244  
 
 245  
     public String getPackageAsDirectory( String packageName )
 246  
     {
 247  152
         return StringUtils.replace( packageName, ".", "/" );
 248  
     }
 249  
 
 250  
     private boolean copyFile( final File outFile, final String template, final boolean failIfExists,
 251  
                               final ZipFile archetypeZipFile )
 252  
         throws FileNotFoundException, OutputFileExists, IOException
 253  
     {
 254  22
         getLogger().debug( "Copying file " + template );
 255  
 
 256  22
         if ( failIfExists && outFile.exists() )
 257  
         {
 258  0
             throw new OutputFileExists( "Don't rewrite file " + outFile.getName() );
 259  
         }
 260  22
         else if ( outFile.exists() )
 261  
         {
 262  0
             getLogger().warn( "CP Don't override file " + outFile );
 263  
 
 264  0
             return false;
 265  
         }
 266  
 
 267  22
         ZipEntry input = archetypeZipFile.getEntry( Constants.ARCHETYPE_RESOURCES + "/" + template );
 268  
 
 269  22
         if ( input.isDirectory() )
 270  
         {
 271  0
             outFile.mkdirs();
 272  
         }
 273  
         else
 274  
         {
 275  22
             InputStream inputStream = null;
 276  22
             OutputStream out = null;
 277  
             try
 278  
             {
 279  22
                 inputStream = archetypeZipFile.getInputStream( input );
 280  
 
 281  22
                 outFile.getParentFile().mkdirs();
 282  
 
 283  22
                 out = new FileOutputStream( outFile );
 284  
 
 285  22
                 IOUtil.copy( inputStream, out );
 286  
             }
 287  
             finally
 288  
             {
 289  22
                 IOUtil.close( inputStream );
 290  22
                 IOUtil.close( out );
 291  22
             }
 292  
         }
 293  
 
 294  22
         return true;
 295  
     }
 296  
 
 297  
     private int copyFiles( String directory, List<String> fileSetResources, boolean packaged, String packageName,
 298  
                            File outputDirectoryFile, ZipFile archetypeZipFile, String moduleOffset,
 299  
                            boolean failIfExists, Context context )
 300  
         throws OutputFileExists, FileNotFoundException, IOException
 301  
     {
 302  26
         int count = 0;
 303  
 
 304  26
         for ( String template : fileSetResources )
 305  
         {
 306  22
             File outputFile =
 307  
                 getOutputFile( template, directory, outputDirectoryFile, packaged, packageName, moduleOffset, context );
 308  
 
 309  22
             if ( copyFile( outputFile, template, failIfExists, archetypeZipFile ) )
 310  
             {
 311  22
                 count++;
 312  
             }
 313  22
         }
 314  
 
 315  26
         return count;
 316  
     }
 317  
 
 318  
     private String getEncoding( String archetypeEncoding )
 319  
     {
 320  160
         return StringUtils.isEmpty( archetypeEncoding ) ? "UTF-8" : archetypeEncoding;
 321  
     }
 322  
 
 323  
     private String getOffsetSeparator( String moduleOffset )
 324  
     {
 325  46
         return StringUtils.isEmpty( moduleOffset ) ? "/" : ( "/" + moduleOffset + "/" );
 326  
     }
 327  
 
 328  
     private File getOutputFile( String template, String directory, File outputDirectoryFile, boolean packaged,
 329  
                                 String packageName, String moduleOffset, Context context )
 330  
     {
 331  318
         String templateName = StringUtils.replaceOnce( template, directory, "" );
 332  
 
 333  318
         String outputFileName =
 334  
             directory + "/" + ( packaged ? getPackageAsDirectory( packageName ) : "" ) + "/" + templateName.substring(
 335  
                 moduleOffset.length() );
 336  
 
 337  318
         if ( TOKEN_PATTERN.matcher( outputFileName ).matches() )
 338  
         {
 339  20
             outputFileName = replaceFilenameTokens( outputFileName, context );
 340  
         }
 341  
 
 342  318
         return new File( outputDirectoryFile, outputFileName );
 343  
     }
 344  
 
 345  
     /**
 346  
      * Replaces all tokens (text surrounded by the {@link #DELIMITER}) within
 347  
      * the given string, using properties contained within the context. If a
 348  
      * property does not exist in the context, the token is left unmodified
 349  
      * and a warning is logged.
 350  
      *
 351  
      * @param filePath the file name and path to be interpolated
 352  
      * @param context  contains the available properties
 353  
      */
 354  
     private String replaceFilenameTokens( final String filePath, final Context context )
 355  
     {
 356  20
         String interpolatedResult = filePath;
 357  
 
 358  20
         int start = 0;
 359  
 
 360  
         while ( true )
 361  
         {
 362  48
             start = interpolatedResult.indexOf( DELIMITER, start );
 363  
 
 364  48
             if ( start == -1 )
 365  
             {
 366  20
                 break;
 367  
             }
 368  
 
 369  28
             int end = interpolatedResult.indexOf( DELIMITER, start + DELIMITER.length() );
 370  
 
 371  28
             if ( end == -1 )
 372  
             {
 373  0
                 break;
 374  
             }
 375  
 
 376  28
             String propertyToken = interpolatedResult.substring( start + DELIMITER.length(), end );
 377  
 
 378  28
             String contextPropertyValue = (String) context.get( propertyToken );
 379  
 
 380  28
             if ( contextPropertyValue != null && contextPropertyValue.trim().length() > 0 )
 381  
             {
 382  24
                 String search = DELIMITER + propertyToken + DELIMITER;
 383  
 
 384  24
                 if ( getLogger().isDebugEnabled() )
 385  
                 {
 386  0
                     getLogger().debug(
 387  
                         "Replacing '" + search + "' in file path '" + interpolatedResult + "' with value '"
 388  
                             + contextPropertyValue + "'." );
 389  
                 }
 390  
 
 391  24
                 interpolatedResult = StringUtils.replace( interpolatedResult, search, contextPropertyValue );
 392  
 
 393  24
                 end = end + contextPropertyValue.length() - search.length();
 394  24
             }
 395  
             else
 396  
             {
 397  
                 // Need to skip the undefined property
 398  4
                 getLogger().warn(
 399  
                     "Property '" + propertyToken + "' was not specified, so the token in '" + interpolatedResult
 400  
                         + "' is not being replaced." );
 401  
             }
 402  
 
 403  28
             start = end + DELIMITER.length() + 1;
 404  28
         }
 405  
 
 406  20
         if ( getLogger().isDebugEnabled() )
 407  
         {
 408  0
             getLogger().debug( "Final interpolated file path: '" + interpolatedResult + "'" );
 409  
         }
 410  
 
 411  20
         return interpolatedResult;
 412  
     }
 413  
 
 414  
     private String getPackageInPathFormat( String aPackage )
 415  
     {
 416  24
         return StringUtils.replace( aPackage, ".", "/" );
 417  
     }
 418  
 
 419  
     private boolean isArchetypeConfigured( ArchetypeDescriptor archetypeDescriptor, ArchetypeGenerationRequest request )
 420  
     {
 421  26
         for ( RequiredProperty requiredProperty : archetypeDescriptor.getRequiredProperties() )
 422  
         {
 423  84
             if ( StringUtils.isEmpty( request.getProperties().getProperty( requiredProperty.getKey() ) ) )
 424  
             {
 425  2
                 return false;
 426  
             }
 427  
         }
 428  
 
 429  24
         return true;
 430  
     }
 431  
 
 432  
     private void setParentArtifactId( Context context, String artifactId )
 433  
     {
 434  12
         context.put( Constants.PARENT_ARTIFACT_ID, artifactId );
 435  12
     }
 436  
 
 437  
     private Context prepareVelocityContext( ArchetypeGenerationRequest request )
 438  
     {
 439  24
         Context context = new VelocityContext();
 440  24
         context.put( Constants.GROUP_ID, request.getGroupId() );
 441  24
         context.put( Constants.ARTIFACT_ID, request.getArtifactId() );
 442  24
         context.put( Constants.VERSION, request.getVersion() );
 443  24
         context.put( Constants.PACKAGE, request.getPackage() );
 444  24
         final String packageInPathFormat = getPackageInPathFormat( request.getPackage() );
 445  24
         context.put( Constants.PACKAGE_IN_PATH_FORMAT, packageInPathFormat );
 446  
 
 447  24
         if ( getLogger().isInfoEnabled() )
 448  
         {
 449  24
             getLogger().info( "----------------------------------------------------------------------------" );
 450  
 
 451  24
             getLogger().info(
 452  
                 "Using following parameters for creating project from Archetype: " + request.getArchetypeArtifactId()
 453  
                     + ":" + request.getArchetypeVersion() );
 454  
 
 455  24
             getLogger().info( "----------------------------------------------------------------------------" );
 456  24
             getLogger().info( "Parameter: " + Constants.GROUP_ID + ", Value: " + request.getGroupId() );
 457  24
             getLogger().info( "Parameter: " + Constants.ARTIFACT_ID + ", Value: " + request.getArtifactId() );
 458  24
             getLogger().info( "Parameter: " + Constants.VERSION + ", Value: " + request.getVersion() );
 459  24
             getLogger().info( "Parameter: " + Constants.PACKAGE + ", Value: " + request.getPackage() );
 460  24
             getLogger().info( "Parameter: " + Constants.PACKAGE_IN_PATH_FORMAT + ", Value: " + packageInPathFormat );
 461  
         }
 462  
 
 463  24
         for ( Iterator<?> iterator = request.getProperties().keySet().iterator(); iterator.hasNext(); )
 464  
         {
 465  146
             String key = (String) iterator.next();
 466  
 
 467  146
             String value = request.getProperties().getProperty( key );
 468  
 
 469  146
             if ( maybeVelocityExpression( value ) )
 470  
             {
 471  0
                 value =  evaluateExpression( context, key, value );
 472  
             }
 473  
 
 474  146
             context.put( key, value );
 475  
 
 476  146
             if ( getLogger().isInfoEnabled() )
 477  
             {
 478  146
                 getLogger().info( "Parameter: " + key + ", Value: " + value );
 479  
             }
 480  146
         }
 481  24
         return context;
 482  
     }
 483  
 
 484  
     private boolean maybeVelocityExpression( String value )
 485  
     {
 486  146
         return value != null && value.contains( "${" );
 487  
     }
 488  
 
 489  
     private String evaluateExpression( Context context, String key, String value )
 490  
     {
 491  0
         StringWriter stringWriter = new StringWriter();
 492  
         try
 493  
         {
 494  0
             Velocity.evaluate( context, stringWriter, key, value );
 495  0
             return stringWriter.toString();
 496  
         }
 497  0
         catch ( Exception ex )
 498  
         {
 499  0
             return value;
 500  
         }
 501  
         finally
 502  
         {
 503  0
             IOUtil.close( stringWriter );
 504  
         }
 505  
 
 506  
     }
 507  
 
 508  
     private void processArchetypeTemplates( AbstractArchetypeDescriptor archetypeDescriptor,
 509  
                                             List<String> archetypeResources, ZipFile archetypeZipFile,
 510  
                                             String moduleOffset, Context context, String packageName,
 511  
                                             File outputDirectoryFile )
 512  
         throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException
 513  
     {
 514  40
         processTemplates( packageName, outputDirectoryFile, context, archetypeDescriptor, archetypeResources,
 515  
                           archetypeZipFile, moduleOffset, false );
 516  40
     }
 517  
 
 518  
     private void processArchetypeTemplatesWithWarning( ArchetypeDescriptor archetypeDescriptor,
 519  
                                                        List<String> archetypeResources, ZipFile archetypeZipFile,
 520  
                                                        String moduleOffset, Context context, String packageName,
 521  
                                                        File outputDirectoryFile )
 522  
         throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException
 523  
     {
 524  6
         processTemplates( packageName, outputDirectoryFile, context, archetypeDescriptor, archetypeResources,
 525  
                           archetypeZipFile, moduleOffset, true );
 526  6
     }
 527  
 
 528  
     private int processFileSet( String directory, List<String> fileSetResources, boolean packaged, String packageName,
 529  
                                 Context context, File outputDirectoryFile, String moduleOffset,
 530  
                                 String archetypeEncoding, boolean failIfExists )
 531  
         throws OutputFileExists, ArchetypeGenerationFailure
 532  
     {
 533  114
         int count = 0;
 534  
 
 535  114
         for ( String template : fileSetResources )
 536  
         {
 537  156
             File outputFile =
 538  
                 getOutputFile( template, directory, outputDirectoryFile, packaged, packageName, moduleOffset, context );
 539  
 
 540  156
             if ( processTemplate( outputFile, context, Constants.ARCHETYPE_RESOURCES + "/" + template,
 541  
                                   archetypeEncoding, failIfExists ) )
 542  
             {
 543  152
                 count++;
 544  
             }
 545  156
         }
 546  
 
 547  114
         return count;
 548  
     }
 549  
 
 550  
     private void processFilesetModule( String rootArtifactId, String artifactId, final List<String> archetypeResources,
 551  
                                        File pom, final ZipFile archetypeZipFile, String moduleOffset, File basedirPom,
 552  
                                        File outputDirectoryFile, final String packageName,
 553  
                                        final AbstractArchetypeDescriptor archetypeDescriptor, final Context context )
 554  
         throws DocumentException, XmlPullParserException, ArchetypeGenerationFailure, InvalidPackaging, IOException,
 555  
         OutputFileExists
 556  
     {
 557  38
         outputDirectoryFile.mkdirs();
 558  38
         getLogger().debug( "Processing module " + artifactId );
 559  38
         getLogger().debug( "Processing module rootArtifactId " + rootArtifactId );
 560  38
         getLogger().debug( "Processing module pom " + pom );
 561  38
         getLogger().debug( "Processing module moduleOffset " + moduleOffset );
 562  38
         getLogger().debug( "Processing module outputDirectoryFile " + outputDirectoryFile );
 563  
 
 564  38
         processFilesetProject( archetypeDescriptor,
 565  
                                StringUtils.replace( artifactId, "${rootArtifactId}", rootArtifactId ),
 566  
                                archetypeResources, pom, archetypeZipFile, moduleOffset, context, packageName,
 567  
                                outputDirectoryFile, basedirPom );
 568  
 
 569  38
         String parentArtifactId = (String) context.get( Constants.PARENT_ARTIFACT_ID );
 570  
 
 571  38
         Iterator<ModuleDescriptor> subprojects = archetypeDescriptor.getModules().iterator();
 572  
 
 573  38
         if ( subprojects.hasNext() )
 574  
         {
 575  12
             getLogger().debug( artifactId + " has modules (" + archetypeDescriptor.getModules() + ")" );
 576  
 
 577  12
             setParentArtifactId( context, StringUtils.replace( artifactId, "${rootArtifactId}", rootArtifactId ) );
 578  
         }
 579  
 
 580  60
         while ( subprojects.hasNext() )
 581  
         {
 582  22
             ModuleDescriptor project = subprojects.next();
 583  
 
 584  22
             File moduleOutputDirectoryFile = new File( outputDirectoryFile,
 585  
                                                        StringUtils.replace( project.getDir(), "__rootArtifactId__",
 586  
                                                                             rootArtifactId ) );
 587  
 
 588  22
             context.put( Constants.ARTIFACT_ID,
 589  
                          StringUtils.replace( project.getId(), "${rootArtifactId}", rootArtifactId ) );
 590  
 
 591  22
             processFilesetModule( rootArtifactId,
 592  
                                   StringUtils.replace( project.getDir(), "__rootArtifactId__", rootArtifactId ),
 593  
                                   archetypeResources, new File( moduleOutputDirectoryFile, Constants.ARCHETYPE_POM ),
 594  
                                   archetypeZipFile,
 595  
                                   ( StringUtils.isEmpty( moduleOffset ) ? "" : ( moduleOffset + "/" ) )
 596  
                                       + StringUtils.replace( project.getDir(), "${rootArtifactId}", rootArtifactId ),
 597  
                                   pom, moduleOutputDirectoryFile, packageName, project, context );
 598  22
         }
 599  
 
 600  38
         restoreParentArtifactId( context, parentArtifactId );
 601  
 
 602  38
         getLogger().debug( "Processed " + artifactId );
 603  38
     }
 604  
 
 605  
     private void processFilesetProject( final AbstractArchetypeDescriptor archetypeDescriptor, final String moduleId,
 606  
                                         final List<String> archetypeResources, final File pom,
 607  
                                         final ZipFile archetypeZipFile, String moduleOffset, final Context context,
 608  
                                         final String packageName, final File outputDirectoryFile,
 609  
                                         final File basedirPom )
 610  
         throws DocumentException, XmlPullParserException, ArchetypeGenerationFailure, InvalidPackaging, IOException,
 611  
         FileNotFoundException, OutputFileExists
 612  
     {
 613  38
         getLogger().debug( "Processing fileset project moduleId " + moduleId );
 614  38
         getLogger().debug( "Processing fileset project pom " + pom );
 615  38
         getLogger().debug( "Processing fileset project moduleOffset " + moduleOffset );
 616  38
         getLogger().debug( "Processing fileset project outputDirectoryFile " + outputDirectoryFile );
 617  38
         getLogger().debug( "Processing fileset project basedirPom " + basedirPom );
 618  
 
 619  38
         if ( basedirPom.exists() )
 620  
         {
 621  24
             processPomWithParent( context, pom, moduleOffset, basedirPom, moduleId );
 622  
         }
 623  
         else
 624  
         {
 625  14
             processPom( context, pom, moduleOffset );
 626  
         }
 627  
 
 628  38
         processArchetypeTemplates( archetypeDescriptor, archetypeResources, archetypeZipFile, moduleOffset, context,
 629  
                                    packageName, outputDirectoryFile );
 630  38
     }
 631  
 
 632  
     private void processPom( Context context, File pom, String moduleOffset )
 633  
         throws OutputFileExists, ArchetypeGenerationFailure
 634  
     {
 635  16
         getLogger().debug( "Processing pom " + pom );
 636  
 
 637  16
         processTemplate( pom, context,
 638  
                          Constants.ARCHETYPE_RESOURCES + getOffsetSeparator( moduleOffset ) + Constants.ARCHETYPE_POM,
 639  
                          getEncoding( null ), true );
 640  16
     }
 641  
 
 642  
     private void processPomWithMerge( Context context, File pom, String moduleOffset )
 643  
         throws OutputFileExists, IOException, XmlPullParserException, ArchetypeGenerationFailure
 644  
     {
 645  6
         getLogger().debug( "Processing pom " + pom + " with merge" );
 646  
 
 647  6
         File temporaryPom = getTemporaryFile( pom );
 648  
 
 649  6
         processTemplate( temporaryPom, context,
 650  
                          Constants.ARCHETYPE_RESOURCES + getOffsetSeparator( moduleOffset ) + Constants.ARCHETYPE_POM,
 651  
                          getEncoding( null ), true );
 652  
 
 653  6
         pomManager.mergePoms( pom, temporaryPom );
 654  
 
 655  
         // getTemporaryFile sets deleteOnExit. Lets try to delete and then make sure deleteOnExit is
 656  
         // still set. Windows has issues deleting files with certain JDKs.
 657  
         try
 658  
         {
 659  6
             FileUtils.forceDelete( temporaryPom );
 660  
         }
 661  0
         catch ( IOException e )
 662  
         {
 663  0
             temporaryPom.deleteOnExit();
 664  6
         }
 665  6
     }
 666  
 
 667  
     private void processPomWithParent( Context context, File pom, String moduleOffset, File basedirPom,
 668  
                                        String moduleId )
 669  
         throws OutputFileExists, XmlPullParserException, DocumentException, IOException, InvalidPackaging,
 670  
         ArchetypeGenerationFailure
 671  
     {
 672  24
         getLogger().debug( "Processing pom " + pom + " with parent " + basedirPom );
 673  
 
 674  24
         processTemplate( pom, context,
 675  
                          Constants.ARCHETYPE_RESOURCES + getOffsetSeparator( moduleOffset ) + Constants.ARCHETYPE_POM,
 676  
                          getEncoding( null ), true );
 677  
 
 678  24
         getLogger().debug( "Adding module " + moduleId );
 679  
 
 680  24
         pomManager.addModule( basedirPom, moduleId );
 681  
 
 682  24
         pomManager.addParent( pom, basedirPom );
 683  24
     }
 684  
 
 685  
     @SuppressWarnings( "deprecation" )
 686  
     private boolean processTemplate( File outFile, Context context, String templateFileName, String encoding,
 687  
                                      boolean failIfExists )
 688  
         throws OutputFileExists, ArchetypeGenerationFailure
 689  
     {
 690  202
         templateFileName = templateFileName.replace( File.separatorChar, '/' );
 691  
 
 692  202
         String localTemplateFileName = templateFileName.replace( '/', File.separatorChar );
 693  202
         if ( !templateFileName.equals( localTemplateFileName ) && !velocity.getEngine().templateExists(
 694  
             templateFileName ) && velocity.getEngine().templateExists( localTemplateFileName ) )
 695  
         {
 696  0
             templateFileName = localTemplateFileName;
 697  
         }
 698  
 
 699  202
         getLogger().debug( "Processing template " + templateFileName );
 700  
 
 701  202
         if ( outFile.exists() )
 702  
         {
 703  4
             if ( failIfExists )
 704  
             {
 705  0
                 throw new OutputFileExists( "Don't override file " + outFile.getAbsolutePath() );
 706  
             }
 707  
 
 708  4
             getLogger().warn( "Don't override file " + outFile );
 709  
 
 710  4
             return false;
 711  
         }
 712  
 
 713  198
         if ( templateFileName.endsWith( "/" ) )
 714  
         {
 715  0
             getLogger().debug( "Creating directory " + outFile );
 716  
 
 717  0
             outFile.mkdirs();
 718  
 
 719  0
             return true;
 720  
         }
 721  
 
 722  198
         if ( !outFile.getParentFile().exists() )
 723  
         {
 724  40
             outFile.getParentFile().mkdirs();
 725  
         }
 726  
 
 727  198
         getLogger().debug( "Merging into " + outFile );
 728  
 
 729  198
         Writer writer = null;
 730  
 
 731  
         try
 732  
         {
 733  198
             StringWriter stringWriter = new StringWriter();
 734  
 
 735  198
             velocity.getEngine().mergeTemplate( templateFileName, encoding, context, stringWriter );
 736  
 
 737  198
             writer = new OutputStreamWriter( new FileOutputStream( outFile ), encoding );
 738  
 
 739  198
             writer.write( StringUtils.unifyLineSeparators( stringWriter.toString() ) );
 740  
 
 741  198
             writer.flush();
 742  
         }
 743  0
         catch ( Exception e )
 744  
         {
 745  0
             throw new ArchetypeGenerationFailure( "Error merging velocity templates: " + e.getMessage(), e );
 746  
         }
 747  
         finally
 748  
         {
 749  198
             IOUtil.close( writer );
 750  198
         }
 751  
 
 752  198
         return true;
 753  
     }
 754  
 
 755  
     private void processTemplates( String packageName, File outputDirectoryFile, Context context,
 756  
                                    AbstractArchetypeDescriptor archetypeDescriptor, List<String> archetypeResources,
 757  
                                    ZipFile archetypeZipFile, String moduleOffset, boolean failIfExists )
 758  
         throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException
 759  
     {
 760  46
         Iterator<FileSet> iterator = archetypeDescriptor.getFileSets().iterator();
 761  46
         if ( iterator.hasNext() )
 762  
         {
 763  44
             getLogger().debug( "Processing filesets" + "\n  " + archetypeResources );
 764  
         }
 765  
 
 766  46
         int count = 0;
 767  186
         while ( iterator.hasNext() )
 768  
         {
 769  140
             FileSet fileSet = iterator.next();
 770  140
             count++;
 771  
 
 772  140
             List<String> fileSetResources =
 773  
                 archetypeFilesResolver.filterFiles( moduleOffset, fileSet, archetypeResources );
 774  
 
 775  
             // This creates an empty directory, even if there is no file to process
 776  
             // Fix for ARCHETYPE-57
 777  140
             getOutputFile( moduleOffset, fileSet.getDirectory(), outputDirectoryFile, fileSet.isPackaged(), packageName,
 778  
                            moduleOffset, context ).mkdirs();
 779  
 
 780  140
             if ( fileSet.isFiltered() )
 781  
             {
 782  114
                 getLogger().debug( "    Processing fileset " + fileSet + " -> " + fileSetResources.size() + ":\n      "
 783  
                                        + fileSetResources );
 784  
 
 785  114
                 int processed =
 786  
                     processFileSet( fileSet.getDirectory(), fileSetResources, fileSet.isPackaged(), packageName,
 787  
                                     context, outputDirectoryFile, moduleOffset, getEncoding( fileSet.getEncoding() ),
 788  
                                     failIfExists );
 789  
 
 790  114
                 getLogger().debug( "    Processed " + processed + " files." );
 791  114
             }
 792  
             else
 793  
             {
 794  26
                 getLogger().debug( "    Copying fileset " + fileSet + " -> " + fileSetResources.size() + ":\n      "
 795  
                                        + fileSetResources );
 796  
 
 797  26
                 int copied = copyFiles( fileSet.getDirectory(), fileSetResources, fileSet.isPackaged(), packageName,
 798  
                                         outputDirectoryFile, archetypeZipFile, moduleOffset, failIfExists, context );
 799  
 
 800  26
                 getLogger().debug( "    Copied " + copied + " files." );
 801  
             }
 802  140
         }
 803  
 
 804  46
         getLogger().debug( "Processed " + count + " filesets" );
 805  46
     }
 806  
 
 807  
     private void restoreParentArtifactId( Context context, String parentArtifactId )
 808  
     {
 809  38
         if ( StringUtils.isEmpty( parentArtifactId ) )
 810  
         {
 811  16
             context.remove( Constants.PARENT_ARTIFACT_ID );
 812  
         }
 813  
         else
 814  
         {
 815  22
             context.put( Constants.PARENT_ARTIFACT_ID, parentArtifactId );
 816  
         }
 817  38
     }
 818  
 
 819  
     private File getTemporaryFile( File file )
 820  
     {
 821  6
         File tmp = FileUtils.createTempFile( file.getName(), Constants.TMP, file.getParentFile() );
 822  
 
 823  6
         tmp.deleteOnExit();
 824  
 
 825  6
         return tmp;
 826  
     }
 827  
 }