PageRenderTime 45ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/maven-archetype-2.1/archetype-common/src/main/java/org/apache/maven/archetype/generator/DefaultFilesetArchetypeGenerator.java

#
Java | 789 lines | 598 code | 144 blank | 47 comment | 52 complexity | dc42cc6b82e23913a03bb7c5b8fe65ff MD5 | raw file
Possible License(s): Apache-2.0
  1. package org.apache.maven.archetype.generator;
  2. /*
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. */
  20. import org.apache.maven.archetype.common.ArchetypeArtifactManager;
  21. import org.apache.maven.archetype.common.ArchetypeFilesResolver;
  22. import org.apache.maven.archetype.common.Constants;
  23. import org.apache.maven.archetype.common.PomManager;
  24. import org.apache.maven.archetype.exception.ArchetypeGenerationFailure;
  25. import org.apache.maven.archetype.exception.ArchetypeNotConfigured;
  26. import org.apache.maven.archetype.exception.InvalidPackaging;
  27. import org.apache.maven.archetype.exception.OutputFileExists;
  28. import org.apache.maven.archetype.exception.PomFileExists;
  29. import org.apache.maven.archetype.exception.ProjectDirectoryExists;
  30. import org.apache.maven.archetype.exception.UnknownArchetype;
  31. import org.apache.maven.archetype.metadata.AbstractArchetypeDescriptor;
  32. import org.apache.maven.archetype.metadata.ArchetypeDescriptor;
  33. import org.apache.maven.archetype.metadata.FileSet;
  34. import org.apache.maven.archetype.metadata.ModuleDescriptor;
  35. import org.apache.velocity.VelocityContext;
  36. import org.apache.velocity.context.Context;
  37. import org.codehaus.plexus.logging.AbstractLogEnabled;
  38. import org.codehaus.plexus.util.FileUtils;
  39. import org.codehaus.plexus.util.IOUtil;
  40. import org.codehaus.plexus.util.StringUtils;
  41. import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
  42. import org.codehaus.plexus.velocity.VelocityComponent;
  43. import org.dom4j.DocumentException;
  44. import java.io.File;
  45. import java.io.FileNotFoundException;
  46. import java.io.FileOutputStream;
  47. import java.io.IOException;
  48. import java.io.InputStream;
  49. import java.io.OutputStream;
  50. import java.io.OutputStreamWriter;
  51. import java.io.StringWriter;
  52. import java.io.Writer;
  53. import java.util.ArrayList;
  54. import java.util.Iterator;
  55. import java.util.List;
  56. import java.util.regex.Pattern;
  57. import java.util.zip.ZipEntry;
  58. import java.util.zip.ZipFile;
  59. import org.apache.maven.archetype.ArchetypeGenerationRequest;
  60. import org.apache.maven.archetype.metadata.RequiredProperty;
  61. /** @plexus.component */
  62. public class DefaultFilesetArchetypeGenerator
  63. extends AbstractLogEnabled
  64. implements FilesetArchetypeGenerator
  65. {
  66. /** @plexus.requirement */
  67. private ArchetypeArtifactManager archetypeArtifactManager;
  68. /** @plexus.requirement */
  69. private ArchetypeFilesResolver archetypeFilesResolver;
  70. /** @plexus.requirement */
  71. private PomManager pomManager;
  72. /** @plexus.requirement */
  73. private VelocityComponent velocity;
  74. /**
  75. * Token delimiter.
  76. */
  77. private static final String DELIMITER = "__";
  78. /**
  79. * Pattern used to detect tokens in a string. Tokens are any text surrounded
  80. * by the delimiter.
  81. */
  82. private static final Pattern TOKEN_PATTERN = Pattern.compile( ".*" + DELIMITER + ".*" + DELIMITER + ".*" );
  83. public void generateArchetype( ArchetypeGenerationRequest request, File archetypeFile )
  84. throws UnknownArchetype, ArchetypeNotConfigured, ProjectDirectoryExists, PomFileExists, OutputFileExists,
  85. ArchetypeGenerationFailure
  86. {
  87. ClassLoader old = Thread.currentThread().getContextClassLoader();
  88. try
  89. {
  90. ArchetypeDescriptor archetypeDescriptor =
  91. archetypeArtifactManager.getFileSetArchetypeDescriptor( archetypeFile );
  92. if ( !isArchetypeConfigured( archetypeDescriptor, request ) )
  93. {
  94. if ( request.isInteractiveMode() )
  95. {
  96. throw new ArchetypeNotConfigured( "No archetype was chosen.", null );
  97. }
  98. StringBuffer exceptionMessage =
  99. new StringBuffer( "Archetype " + request.getArchetypeGroupId() + ":"
  100. + request.getArchetypeArtifactId() + ":" + request.getArchetypeVersion() + " is not configured" );
  101. List<String> missingProperties = new ArrayList<String>( 0 );
  102. for ( RequiredProperty requiredProperty : archetypeDescriptor.getRequiredProperties() )
  103. {
  104. if ( StringUtils.isEmpty( request.getProperties().getProperty( requiredProperty.getKey() ) ) )
  105. {
  106. exceptionMessage.append( "\n\tProperty " + requiredProperty.getKey() + " is missing." );
  107. missingProperties.add( requiredProperty.getKey() );
  108. }
  109. }
  110. throw new ArchetypeNotConfigured( exceptionMessage.toString(), missingProperties );
  111. }
  112. Context context = prepareVelocityContext( request );
  113. String packageName = request.getPackage();
  114. String artifactId = request.getArtifactId();
  115. File outputDirectoryFile = new File( request.getOutputDirectory(), artifactId );
  116. File basedirPom = new File( request.getOutputDirectory(), Constants.ARCHETYPE_POM );
  117. File pom = new File( outputDirectoryFile, Constants.ARCHETYPE_POM );
  118. List<String> archetypeResources = archetypeArtifactManager.getFilesetArchetypeResources( archetypeFile );
  119. ZipFile archetypeZipFile = archetypeArtifactManager.getArchetypeZipFile( archetypeFile );
  120. ClassLoader archetypeJarLoader = archetypeArtifactManager.getArchetypeJarLoader( archetypeFile );
  121. Thread.currentThread().setContextClassLoader( archetypeJarLoader );
  122. if ( archetypeDescriptor.isPartial() )
  123. {
  124. getLogger().debug( "Processing partial archetype " + archetypeDescriptor.getName() );
  125. if ( outputDirectoryFile.exists() )
  126. {
  127. if ( !pom.exists() )
  128. {
  129. throw new PomFileExists( "This is a partial archetype and the pom.xml file doesn't exist." );
  130. }
  131. processPomWithMerge( context, pom, "" );
  132. processArchetypeTemplatesWithWarning( archetypeDescriptor, archetypeResources, archetypeZipFile,
  133. "", context, packageName, outputDirectoryFile );
  134. }
  135. else
  136. {
  137. if ( basedirPom.exists() )
  138. {
  139. processPomWithMerge( context, basedirPom, "" );
  140. processArchetypeTemplatesWithWarning( archetypeDescriptor, archetypeResources,
  141. archetypeZipFile, "", context, packageName,
  142. new File( request.getOutputDirectory() ) );
  143. }
  144. else
  145. {
  146. processPom( context, pom, "" );
  147. processArchetypeTemplates( archetypeDescriptor, archetypeResources, archetypeZipFile, "",
  148. context, packageName, outputDirectoryFile );
  149. }
  150. }
  151. if ( archetypeDescriptor.getModules().size() > 0 )
  152. {
  153. getLogger().info( "Modules ignored in partial mode" );
  154. }
  155. }
  156. else
  157. {
  158. getLogger().debug( "Processing complete archetype " + archetypeDescriptor.getName() );
  159. if ( outputDirectoryFile.exists() && pom.exists() )
  160. {
  161. throw new ProjectDirectoryExists( "A Maven 2 project already exists in the directory "
  162. + outputDirectoryFile.getPath() );
  163. }
  164. if ( outputDirectoryFile.exists() )
  165. {
  166. getLogger().warn( "The directory " + outputDirectoryFile.getPath() + " already exists." );
  167. }
  168. context.put( "rootArtifactId", artifactId );
  169. processFilesetModule( artifactId, artifactId, archetypeResources, pom, archetypeZipFile, "",
  170. basedirPom, outputDirectoryFile, packageName, archetypeDescriptor, context );
  171. }
  172. // ----------------------------------------------------------------------
  173. // Log message on OldArchetype creation
  174. // ----------------------------------------------------------------------
  175. if ( getLogger().isInfoEnabled() )
  176. {
  177. getLogger().info( "project created from Archetype in dir: " + outputDirectoryFile.getAbsolutePath() );
  178. }
  179. }
  180. catch ( FileNotFoundException ex )
  181. {
  182. throw new ArchetypeGenerationFailure( ex );
  183. }
  184. catch ( IOException ex )
  185. {
  186. throw new ArchetypeGenerationFailure( ex );
  187. }
  188. catch ( XmlPullParserException ex )
  189. {
  190. throw new ArchetypeGenerationFailure( ex );
  191. }
  192. catch ( DocumentException ex )
  193. {
  194. throw new ArchetypeGenerationFailure( ex );
  195. }
  196. catch ( ArchetypeGenerationFailure ex )
  197. {
  198. throw new ArchetypeGenerationFailure( ex );
  199. }
  200. catch ( InvalidPackaging ex )
  201. {
  202. throw new ArchetypeGenerationFailure( ex );
  203. }
  204. finally
  205. {
  206. Thread.currentThread().setContextClassLoader( old );
  207. }
  208. }
  209. public String getPackageAsDirectory( String packageName )
  210. {
  211. return StringUtils.replace( packageName, ".", "/" );
  212. }
  213. private boolean copyFile( final File outFile, final String template, final boolean failIfExists,
  214. final ZipFile archetypeZipFile )
  215. throws FileNotFoundException, OutputFileExists, IOException
  216. {
  217. getLogger().debug( "Copying file " + template );
  218. if ( failIfExists && outFile.exists() )
  219. {
  220. throw new OutputFileExists( "Don't rewrite file " + outFile.getName() );
  221. }
  222. else if ( outFile.exists() )
  223. {
  224. getLogger().warn( "CP Don't override file " + outFile );
  225. return false;
  226. }
  227. ZipEntry input = archetypeZipFile.getEntry( Constants.ARCHETYPE_RESOURCES + "/" + template );
  228. if ( input.isDirectory() )
  229. {
  230. outFile.mkdirs();
  231. }
  232. else
  233. {
  234. InputStream inputStream = null;
  235. OutputStream out = null;
  236. try
  237. {
  238. inputStream = archetypeZipFile.getInputStream( input );
  239. outFile.getParentFile().mkdirs();
  240. out = new FileOutputStream( outFile );
  241. IOUtil.copy( inputStream, out );
  242. }
  243. finally
  244. {
  245. IOUtil.close( inputStream );
  246. IOUtil.close( out );
  247. }
  248. }
  249. return true;
  250. }
  251. private int copyFiles( String directory, List<String> fileSetResources, boolean packaged, String packageName,
  252. File outputDirectoryFile, ZipFile archetypeZipFile, String moduleOffset,
  253. boolean failIfExists, Context context )
  254. throws OutputFileExists, FileNotFoundException, IOException
  255. {
  256. int count = 0;
  257. for ( String template : fileSetResources )
  258. {
  259. File outputFile =
  260. getOutputFile( template, directory, outputDirectoryFile, packaged, packageName, moduleOffset, context );
  261. if ( copyFile( outputFile, template, failIfExists, archetypeZipFile ) )
  262. {
  263. count++;
  264. }
  265. }
  266. return count;
  267. }
  268. private String getEncoding( String archetypeEncoding )
  269. {
  270. return StringUtils.isEmpty( archetypeEncoding ) ? "UTF-8" : archetypeEncoding;
  271. }
  272. private String getOffsetSeparator( String moduleOffset )
  273. {
  274. return StringUtils.isEmpty( moduleOffset ) ? "/" : ( "/" + moduleOffset + "/" );
  275. }
  276. private File getOutputFile( String template, String directory, File outputDirectoryFile, boolean packaged,
  277. String packageName, String moduleOffset, Context context )
  278. {
  279. String templateName = StringUtils.replaceOnce( template, directory, "" );
  280. String outputFileName =
  281. directory + "/" + ( packaged ? getPackageAsDirectory( packageName ) : "" ) + "/"
  282. + templateName.substring( moduleOffset.length() );
  283. if ( TOKEN_PATTERN.matcher( outputFileName ).matches() )
  284. {
  285. outputFileName = replaceFilenameTokens( outputFileName, context );
  286. }
  287. return new File( outputDirectoryFile, outputFileName );
  288. }
  289. /**
  290. * Replaces all tokens (text surrounded by the {@link #DELIMITER}) within
  291. * the given string, using properties contained within the context. If a
  292. * property does not exist in the context, the token is left unmodified
  293. * and a warning is logged.
  294. *
  295. * @param filePath the file name and path to be interpolated
  296. * @param context contains the available properties
  297. */
  298. private String replaceFilenameTokens( final String filePath, final Context context )
  299. {
  300. String interpolatedResult = filePath;
  301. int start = 0;
  302. while ( true )
  303. {
  304. start = interpolatedResult.indexOf( DELIMITER, start );
  305. if ( start == -1 )
  306. {
  307. break;
  308. }
  309. int end = interpolatedResult.indexOf( DELIMITER, start + DELIMITER.length() );
  310. if ( end == -1 )
  311. {
  312. break;
  313. }
  314. String propertyToken = interpolatedResult.substring( start + DELIMITER.length(), end );
  315. String contextPropertyValue = (String) context.get( propertyToken );
  316. if ( contextPropertyValue != null && contextPropertyValue.trim().length() > 0 )
  317. {
  318. String search = DELIMITER + propertyToken + DELIMITER;
  319. if ( getLogger().isDebugEnabled() )
  320. {
  321. getLogger().debug( "Replacing '" + search + "' in file path '" + interpolatedResult
  322. + "' with value '" + contextPropertyValue + "'." );
  323. }
  324. interpolatedResult = StringUtils.replace( interpolatedResult, search, contextPropertyValue );
  325. end = end + contextPropertyValue.length() - search.length();
  326. }
  327. else
  328. {
  329. // Need to skip the undefined property
  330. getLogger().warn( "Property '" + propertyToken + "' was not specified, so the token in '"
  331. + interpolatedResult + "' is not being replaced." );
  332. }
  333. start = end + DELIMITER.length() + 1;
  334. }
  335. if ( getLogger().isDebugEnabled() )
  336. {
  337. getLogger().debug( "Final interpolated file path: '" + interpolatedResult + "'" );
  338. }
  339. return interpolatedResult;
  340. }
  341. private String getPackageInPathFormat( String aPackage )
  342. {
  343. return StringUtils.replace( aPackage, ".", "/" );
  344. }
  345. private boolean isArchetypeConfigured( ArchetypeDescriptor archetypeDescriptor, ArchetypeGenerationRequest request )
  346. {
  347. for ( RequiredProperty requiredProperty : archetypeDescriptor.getRequiredProperties() )
  348. {
  349. if ( StringUtils.isEmpty( request.getProperties().getProperty( requiredProperty.getKey() ) ) )
  350. {
  351. return false;
  352. }
  353. }
  354. return true;
  355. }
  356. private void setParentArtifactId( Context context, String artifactId )
  357. {
  358. context.put( Constants.PARENT_ARTIFACT_ID, artifactId );
  359. }
  360. private Context prepareVelocityContext( ArchetypeGenerationRequest request )
  361. {
  362. Context context = new VelocityContext();
  363. context.put( Constants.GROUP_ID, request.getGroupId() );
  364. context.put( Constants.ARTIFACT_ID, request.getArtifactId() );
  365. context.put( Constants.VERSION, request.getVersion() );
  366. context.put( Constants.PACKAGE, request.getPackage() );
  367. final String packageInPathFormat = getPackageInPathFormat( request.getPackage() );
  368. context.put( Constants.PACKAGE_IN_PATH_FORMAT, packageInPathFormat );
  369. if ( getLogger().isInfoEnabled() )
  370. {
  371. getLogger().info( "----------------------------------------------------------------------------" );
  372. getLogger().info( "Using following parameters for creating project from Archetype: "
  373. + request.getArchetypeArtifactId() + ":" + request.getArchetypeVersion() );
  374. getLogger().info( "----------------------------------------------------------------------------" );
  375. getLogger().info( "Parameter: " + Constants.GROUP_ID + ", Value: " + request.getGroupId() );
  376. getLogger().info( "Parameter: " + Constants.ARTIFACT_ID + ", Value: " + request.getArtifactId() );
  377. getLogger().info( "Parameter: " + Constants.VERSION + ", Value: " + request.getVersion() );
  378. getLogger().info( "Parameter: " + Constants.PACKAGE + ", Value: " + request.getPackage() );
  379. getLogger().info( "Parameter: " + Constants.PACKAGE_IN_PATH_FORMAT + ", Value: " + packageInPathFormat );
  380. }
  381. for ( Iterator<?> iterator = request.getProperties().keySet().iterator(); iterator.hasNext(); )
  382. {
  383. String key = (String) iterator.next();
  384. Object value = request.getProperties().getProperty( key );
  385. context.put( key, value );
  386. if ( getLogger().isInfoEnabled() )
  387. {
  388. getLogger().info( "Parameter: " + key + ", Value: " + value );
  389. }
  390. }
  391. return context;
  392. }
  393. private void processArchetypeTemplates( AbstractArchetypeDescriptor archetypeDescriptor,
  394. List<String> archetypeResources, ZipFile archetypeZipFile,
  395. String moduleOffset, Context context, String packageName,
  396. File outputDirectoryFile )
  397. throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException
  398. {
  399. processTemplates( packageName, outputDirectoryFile, context, archetypeDescriptor, archetypeResources,
  400. archetypeZipFile, moduleOffset, false );
  401. }
  402. private void processArchetypeTemplatesWithWarning( ArchetypeDescriptor archetypeDescriptor,
  403. List<String> archetypeResources, ZipFile archetypeZipFile,
  404. String moduleOffset, Context context, String packageName,
  405. File outputDirectoryFile )
  406. throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException
  407. {
  408. processTemplates( packageName, outputDirectoryFile, context, archetypeDescriptor, archetypeResources,
  409. archetypeZipFile, moduleOffset, true );
  410. }
  411. private int processFileSet( String directory, List<String> fileSetResources, boolean packaged, String packageName,
  412. Context context, File outputDirectoryFile, String moduleOffset,
  413. String archetypeEncoding, boolean failIfExists )
  414. throws OutputFileExists, ArchetypeGenerationFailure
  415. {
  416. int count = 0;
  417. for ( String template : fileSetResources )
  418. {
  419. File outputFile =
  420. getOutputFile( template, directory, outputDirectoryFile, packaged, packageName, moduleOffset, context );
  421. if ( processTemplate( outputFile, context, Constants.ARCHETYPE_RESOURCES + "/" + template,
  422. archetypeEncoding, failIfExists ) )
  423. {
  424. count++;
  425. }
  426. }
  427. return count;
  428. }
  429. private void processFilesetModule( String rootArtifactId, String artifactId, final List<String> archetypeResources,
  430. File pom, final ZipFile archetypeZipFile, String moduleOffset, File basedirPom,
  431. File outputDirectoryFile, final String packageName,
  432. final AbstractArchetypeDescriptor archetypeDescriptor, final Context context )
  433. throws DocumentException, XmlPullParserException, ArchetypeGenerationFailure, InvalidPackaging, IOException,
  434. OutputFileExists
  435. {
  436. outputDirectoryFile.mkdirs();
  437. getLogger().debug( "Processing module " + artifactId );
  438. getLogger().debug( "Processing module rootArtifactId " + rootArtifactId );
  439. getLogger().debug( "Processing module pom " + pom );
  440. getLogger().debug( "Processing module moduleOffset " + moduleOffset );
  441. getLogger().debug( "Processing module outputDirectoryFile " + outputDirectoryFile );
  442. processFilesetProject( archetypeDescriptor,
  443. StringUtils.replace( artifactId, "${rootArtifactId}", rootArtifactId ),
  444. archetypeResources, pom, archetypeZipFile, moduleOffset, context, packageName,
  445. outputDirectoryFile, basedirPom );
  446. String parentArtifactId = (String) context.get( Constants.PARENT_ARTIFACT_ID );
  447. Iterator<ModuleDescriptor> subprojects = archetypeDescriptor.getModules().iterator();
  448. if ( subprojects.hasNext() )
  449. {
  450. getLogger().debug( artifactId + " has modules (" + archetypeDescriptor.getModules() + ")" );
  451. setParentArtifactId( context, StringUtils.replace( artifactId, "${rootArtifactId}", rootArtifactId ) );
  452. }
  453. while ( subprojects.hasNext() )
  454. {
  455. ModuleDescriptor project = subprojects.next();
  456. File moduleOutputDirectoryFile =
  457. new File( outputDirectoryFile,
  458. StringUtils.replace( project.getDir(), "__rootArtifactId__", rootArtifactId ) );
  459. context.put( Constants.ARTIFACT_ID,
  460. StringUtils.replace( project.getId(), "${rootArtifactId}", rootArtifactId ) );
  461. processFilesetModule( rootArtifactId,
  462. StringUtils.replace( project.getDir(), "__rootArtifactId__", rootArtifactId ),
  463. archetypeResources,
  464. new File( moduleOutputDirectoryFile, Constants.ARCHETYPE_POM ), archetypeZipFile,
  465. ( StringUtils.isEmpty( moduleOffset ) ? "" : ( moduleOffset + "/" ) )
  466. + StringUtils.replace( project.getDir(), "${rootArtifactId}", rootArtifactId ),
  467. pom, moduleOutputDirectoryFile, packageName, project, context );
  468. }
  469. restoreParentArtifactId( context, parentArtifactId );
  470. getLogger().debug( "Processed " + artifactId );
  471. }
  472. private void processFilesetProject( final AbstractArchetypeDescriptor archetypeDescriptor, final String moduleId,
  473. final List<String> archetypeResources, final File pom,
  474. final ZipFile archetypeZipFile, String moduleOffset, final Context context,
  475. final String packageName, final File outputDirectoryFile, final File basedirPom )
  476. throws DocumentException, XmlPullParserException, ArchetypeGenerationFailure, InvalidPackaging, IOException,
  477. FileNotFoundException, OutputFileExists
  478. {
  479. getLogger().debug( "Processing fileset project moduleId " + moduleId );
  480. getLogger().debug( "Processing fileset project pom " + pom );
  481. getLogger().debug( "Processing fileset project moduleOffset " + moduleOffset );
  482. getLogger().debug( "Processing fileset project outputDirectoryFile " + outputDirectoryFile );
  483. getLogger().debug( "Processing fileset project basedirPom " + basedirPom );
  484. if ( basedirPom.exists() )
  485. {
  486. processPomWithParent( context, pom, moduleOffset, basedirPom, moduleId );
  487. }
  488. else
  489. {
  490. processPom( context, pom, moduleOffset );
  491. }
  492. processArchetypeTemplates( archetypeDescriptor, archetypeResources, archetypeZipFile, moduleOffset, context,
  493. packageName, outputDirectoryFile );
  494. }
  495. private void processPom( Context context, File pom, String moduleOffset )
  496. throws OutputFileExists, ArchetypeGenerationFailure
  497. {
  498. getLogger().debug( "Processing pom " + pom );
  499. processTemplate( pom, context, Constants.ARCHETYPE_RESOURCES + getOffsetSeparator( moduleOffset )
  500. + Constants.ARCHETYPE_POM, getEncoding( null ), true );
  501. }
  502. private void processPomWithMerge( Context context, File pom, String moduleOffset )
  503. throws OutputFileExists, IOException, XmlPullParserException, ArchetypeGenerationFailure
  504. {
  505. getLogger().debug( "Processing pom " + pom + " with merge" );
  506. File temporaryPom = getTemporaryFile( pom );
  507. processTemplate( temporaryPom, context, Constants.ARCHETYPE_RESOURCES + getOffsetSeparator( moduleOffset )
  508. + Constants.ARCHETYPE_POM, getEncoding( null ), true );
  509. pomManager.mergePoms( pom, temporaryPom );
  510. // getTemporaryFile sets deleteOnExit. Lets try to delete and then make sure deleteOnExit is
  511. // still set. Windows has issues deleting files with certain JDKs.
  512. try
  513. {
  514. FileUtils.forceDelete( temporaryPom );
  515. }
  516. catch ( IOException e )
  517. {
  518. temporaryPom.deleteOnExit();
  519. }
  520. }
  521. private void processPomWithParent( Context context, File pom, String moduleOffset, File basedirPom, String moduleId )
  522. throws OutputFileExists, XmlPullParserException, DocumentException, IOException, InvalidPackaging,
  523. ArchetypeGenerationFailure
  524. {
  525. getLogger().debug( "Processing pom " + pom + " with parent " + basedirPom );
  526. processTemplate( pom, context, Constants.ARCHETYPE_RESOURCES + getOffsetSeparator( moduleOffset )
  527. + Constants.ARCHETYPE_POM, getEncoding( null ), true );
  528. getLogger().debug( "Adding module " + moduleId );
  529. pomManager.addModule( basedirPom, moduleId );
  530. pomManager.addParent( pom, basedirPom );
  531. }
  532. @SuppressWarnings( "deprecation" )
  533. private boolean processTemplate( File outFile, Context context, String templateFileName, String encoding,
  534. boolean failIfExists )
  535. throws OutputFileExists, ArchetypeGenerationFailure
  536. {
  537. templateFileName = templateFileName.replace( File.separatorChar, '/' );
  538. String localTemplateFileName = templateFileName.replace( '/', File.separatorChar );
  539. if ( !templateFileName.equals( localTemplateFileName )
  540. && !velocity.getEngine().templateExists( templateFileName )
  541. && velocity.getEngine().templateExists( localTemplateFileName ) )
  542. {
  543. templateFileName = localTemplateFileName;
  544. }
  545. getLogger().debug( "Processing template " + templateFileName );
  546. if ( outFile.exists() )
  547. {
  548. if ( failIfExists )
  549. {
  550. throw new OutputFileExists( "Don't override file " + outFile.getAbsolutePath() );
  551. }
  552. getLogger().warn( "Don't override file " + outFile );
  553. return false;
  554. }
  555. if ( templateFileName.endsWith( "/" ) )
  556. {
  557. getLogger().debug( "Creating directory " + outFile );
  558. outFile.mkdirs();
  559. return true;
  560. }
  561. if ( !outFile.getParentFile().exists() )
  562. {
  563. outFile.getParentFile().mkdirs();
  564. }
  565. getLogger().debug( "Merging into " + outFile );
  566. Writer writer = null;
  567. try
  568. {
  569. StringWriter stringWriter = new StringWriter();
  570. velocity.getEngine().mergeTemplate( templateFileName, encoding, context, stringWriter );
  571. writer = new OutputStreamWriter( new FileOutputStream( outFile ), encoding );
  572. writer.write( StringUtils.unifyLineSeparators( stringWriter.toString() ) );
  573. writer.flush();
  574. }
  575. catch ( Exception e )
  576. {
  577. throw new ArchetypeGenerationFailure( "Error merging velocity templates: " + e.getMessage(), e );
  578. }
  579. finally
  580. {
  581. IOUtil.close( writer );
  582. }
  583. return true;
  584. }
  585. private void processTemplates( String packageName, File outputDirectoryFile, Context context,
  586. AbstractArchetypeDescriptor archetypeDescriptor, List<String> archetypeResources,
  587. ZipFile archetypeZipFile, String moduleOffset, boolean failIfExists )
  588. throws OutputFileExists, ArchetypeGenerationFailure, FileNotFoundException, IOException
  589. {
  590. Iterator<FileSet> iterator = archetypeDescriptor.getFileSets().iterator();
  591. if ( iterator.hasNext() )
  592. {
  593. getLogger().debug( "Processing filesets" + "\n " + archetypeResources );
  594. }
  595. int count = 0;
  596. while ( iterator.hasNext() )
  597. {
  598. FileSet fileSet = iterator.next();
  599. count++;
  600. List<String> fileSetResources =
  601. archetypeFilesResolver.filterFiles( moduleOffset, fileSet, archetypeResources );
  602. // This creates an empty directory, even if there is no file to process
  603. // Fix for ARCHETYPE-57
  604. getOutputFile( moduleOffset, fileSet.getDirectory(), outputDirectoryFile, fileSet.isPackaged(),
  605. packageName, moduleOffset, context ).mkdirs();
  606. if ( fileSet.isFiltered() )
  607. {
  608. getLogger().debug( " Processing fileset " + fileSet + " -> " + fileSetResources.size() + ":\n "
  609. + fileSetResources );
  610. int processed =
  611. processFileSet( fileSet.getDirectory(), fileSetResources, fileSet.isPackaged(), packageName,
  612. context, outputDirectoryFile, moduleOffset, getEncoding( fileSet.getEncoding() ),
  613. failIfExists );
  614. getLogger().debug( " Processed " + processed + " files." );
  615. }
  616. else
  617. {
  618. getLogger().debug( " Copying fileset " + fileSet + " -> " + fileSetResources.size() + ":\n "
  619. + fileSetResources );
  620. int copied =
  621. copyFiles( fileSet.getDirectory(), fileSetResources, fileSet.isPackaged(), packageName,
  622. outputDirectoryFile, archetypeZipFile, moduleOffset, failIfExists, context );
  623. getLogger().debug( " Copied " + copied + " files." );
  624. }
  625. }
  626. getLogger().debug( "Processed " + count + " filesets" );
  627. }
  628. private void restoreParentArtifactId( Context context, String parentArtifactId )
  629. {
  630. if ( StringUtils.isEmpty( parentArtifactId ) )
  631. {
  632. context.remove( Constants.PARENT_ARTIFACT_ID );
  633. }
  634. else
  635. {
  636. context.put( Constants.PARENT_ARTIFACT_ID, parentArtifactId );
  637. }
  638. }
  639. private File getTemporaryFile( File file )
  640. {
  641. File tmp = FileUtils.createTempFile( file.getName(), Constants.TMP, file.getParentFile() );
  642. tmp.deleteOnExit();
  643. return tmp;
  644. }
  645. }