View Javadoc
1   package org.apache.maven.archetype.creator;
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.common.ArchetypeFilesResolver;
25  import org.apache.maven.archetype.common.Constants;
26  import org.apache.maven.archetype.common.PomManager;
27  import org.apache.maven.archetype.common.util.FileCharsetDetector;
28  import org.apache.maven.archetype.common.util.ListScanner;
29  import org.apache.maven.archetype.common.util.PathUtils;
30  import org.apache.maven.archetype.exception.TemplateCreationException;
31  import org.apache.maven.archetype.metadata.ArchetypeDescriptor;
32  import org.apache.maven.archetype.metadata.FileSet;
33  import org.apache.maven.archetype.metadata.ModuleDescriptor;
34  import org.apache.maven.archetype.metadata.RequiredProperty;
35  import org.apache.maven.archetype.metadata.io.xpp3.ArchetypeDescriptorXpp3Writer;
36  import org.apache.maven.artifact.Artifact;
37  import org.apache.maven.artifact.repository.ArtifactRepository;
38  import org.apache.maven.model.Build;
39  import org.apache.maven.model.Dependency;
40  import org.apache.maven.model.Extension;
41  import org.apache.maven.model.Model;
42  import org.apache.maven.model.Plugin;
43  import org.apache.maven.model.PluginManagement;
44  import org.apache.maven.model.Profile;
45  import org.apache.maven.project.MavenProject;
46  import org.apache.maven.project.MavenProjectBuilder;
47  import org.apache.maven.project.ProjectBuildingException;
48  import org.apache.maven.shared.invoker.DefaultInvocationRequest;
49  import org.apache.maven.shared.invoker.DefaultInvoker;
50  import org.apache.maven.shared.invoker.InvocationRequest;
51  import org.apache.maven.shared.invoker.Invoker;
52  import org.codehaus.plexus.component.annotations.Component;
53  import org.codehaus.plexus.component.annotations.Requirement;
54  import org.codehaus.plexus.logging.AbstractLogEnabled;
55  import org.codehaus.plexus.util.DirectoryScanner;
56  import org.codehaus.plexus.util.FileUtils;
57  import org.codehaus.plexus.util.IOUtil;
58  import org.codehaus.plexus.util.ReaderFactory;
59  import org.codehaus.plexus.util.StringUtils;
60  import org.codehaus.plexus.util.WriterFactory;
61  import org.codehaus.plexus.util.xml.Xpp3Dom;
62  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
63  
64  import java.io.File;
65  import java.io.FileInputStream;
66  import java.io.FileNotFoundException;
67  import java.io.FileOutputStream;
68  import java.io.IOException;
69  import java.io.InputStream;
70  import java.io.OutputStream;
71  import java.io.Reader;
72  import java.io.Writer;
73  import java.util.ArrayList;
74  import java.util.Arrays;
75  import java.util.Collections;
76  import java.util.HashMap;
77  import java.util.HashSet;
78  import java.util.Iterator;
79  import java.util.List;
80  import java.util.Map;
81  import java.util.Properties;
82  import java.util.Set;
83  
84  /**
85   * Create a 2.x Archetype project from a project. Since 2.0-alpha-5, an integration-test named "basic" is created along
86   * the archetype itself to provide immediate test when building the archetype.
87   */
88  @Component( role = ArchetypeCreator.class, hint = "fileset" )
89  public class FilesetArchetypeCreator
90      extends AbstractLogEnabled
91      implements ArchetypeCreator
92  {
93      private static final String DEFAULT_OUTPUT_DIRECTORY =
94          "target" + File.separator + "generated-sources" + File.separator + "archetype";
95  
96      @Requirement
97      private ArchetypeFilesResolver archetypeFilesResolver;
98  
99      @Requirement
100     private PomManager pomManager;
101 
102     @Requirement
103     private MavenProjectBuilder projectBuilder;
104 
105     public void createArchetype( ArchetypeCreationRequest request, ArchetypeCreationResult result )
106     {
107         MavenProject project = request.getProject();
108         List<String> languages = request.getLanguages();
109         List<String> filtereds = request.getFiltereds();
110         String defaultEncoding = request.getDefaultEncoding();
111         boolean preserveCData = request.isPreserveCData();
112         boolean keepParent = request.isKeepParent();
113         boolean partialArchetype = request.isPartialArchetype();
114         ArtifactRepository localRepository = request.getLocalRepository();
115         File outputDirectory = request.getOutputDirectory();
116         File basedir = project.getBasedir();
117 
118         Properties properties = new Properties();
119         Properties configurationProperties = new Properties();
120         if ( request.getProperties() != null )
121         {
122             properties.putAll( request.getProperties() );
123             configurationProperties.putAll( request.getProperties() );
124         }
125 
126         extractPropertiesFromProject( project, properties, configurationProperties, request.getPackageName() );
127 
128         if ( outputDirectory == null )
129         {
130             getLogger().debug( "No output directory defined, using default: " + DEFAULT_OUTPUT_DIRECTORY );
131             outputDirectory = FileUtils.resolveFile( basedir, DEFAULT_OUTPUT_DIRECTORY );
132         }
133         outputDirectory.mkdirs();
134 
135         getLogger().debug( "Creating archetype in " + outputDirectory );
136 
137         try
138         {
139             File archetypePomFile =
140                 createArchetypeProjectPom( project, localRepository, configurationProperties, outputDirectory );
141 
142             File archetypeResourcesDirectory = new File( outputDirectory, getTemplateOutputDirectory() );
143 
144             File archetypeFilesDirectory = new File( archetypeResourcesDirectory, Constants.ARCHETYPE_RESOURCES );
145             getLogger().debug( "Archetype's files output directory " + archetypeFilesDirectory );
146 
147             File archetypeDescriptorFile = new File( archetypeResourcesDirectory, Constants.ARCHETYPE_DESCRIPTOR );
148             archetypeDescriptorFile.getParentFile().mkdirs();
149 
150             getLogger().debug( "Starting archetype's descriptor " + project.getArtifactId() );
151             ArchetypeDescriptor archetypeDescriptor = new ArchetypeDescriptor();
152 
153             archetypeDescriptor.setName( project.getArtifactId() );
154             archetypeDescriptor.setPartial( partialArchetype );
155 
156             addRequiredProperties( archetypeDescriptor, properties );
157 
158             // TODO ensure reverseProperties contains NO dotted properties
159             Properties reverseProperties = getReversedProperties( archetypeDescriptor, properties );
160             // reverseProperties.remove( Constants.GROUP_ID );
161 
162             // TODO ensure pomReversedProperties contains NO dotted properties
163             Properties pomReversedProperties = getReversedProperties( archetypeDescriptor, properties );
164             // pomReversedProperties.remove( Constants.PACKAGE );
165 
166             String packageName = configurationProperties.getProperty( Constants.PACKAGE );
167 
168             Model pom = pomManager.readPom( FileUtils.resolveFile( basedir, Constants.ARCHETYPE_POM ) );
169 
170             List<String> excludePatterns =
171                 configurationProperties.getProperty( Constants.EXCLUDE_PATTERNS ) != null
172                     ? Arrays.asList(
173                     StringUtils.split( configurationProperties.getProperty( Constants.EXCLUDE_PATTERNS ), "," ) )
174                     : Collections.<String>emptyList();
175 
176             List<String> fileNames = resolveFileNames( pom, basedir, excludePatterns );
177             if ( getLogger().isDebugEnabled() )
178             {
179                 getLogger().debug( "Scanned for files " + fileNames.size() );
180 
181                 for ( String name : fileNames )
182                 {
183                     getLogger().debug( "- " + name );
184                 }
185             }
186 
187             List<FileSet> filesets = resolveFileSets( packageName, fileNames, languages, filtereds, defaultEncoding );
188             getLogger().debug( "Resolved filesets for " + archetypeDescriptor.getName() );
189 
190             archetypeDescriptor.setFileSets( filesets );
191 
192             createArchetypeFiles( reverseProperties, filesets, packageName, basedir, archetypeFilesDirectory,
193                                   defaultEncoding );
194             getLogger().debug( "Created files for " + archetypeDescriptor.getName() );
195 
196             setParentArtifactId( reverseProperties, configurationProperties.getProperty( Constants.ARTIFACT_ID ) );
197 
198             for ( Iterator<String> modules = pom.getModules().iterator(); modules.hasNext(); )
199             {
200                 String moduleId = (String) modules.next();
201                 String rootArtifactId = configurationProperties.getProperty( Constants.ARTIFACT_ID );
202                 String moduleIdDirectory = moduleId;
203 
204                 if ( moduleId.indexOf( rootArtifactId ) >= 0 )
205                 {
206                     moduleIdDirectory = StringUtils.replace( moduleId, rootArtifactId, "__rootArtifactId__" );
207                 }
208 
209                 getLogger().debug( "Creating module " + moduleId );
210 
211                 ModuleDescriptor moduleDescriptor =
212                     createModule( reverseProperties, rootArtifactId, moduleId, packageName,
213                                   FileUtils.resolveFile( basedir, moduleId ),
214                                   new File( archetypeFilesDirectory, moduleIdDirectory ), languages, filtereds,
215                                   defaultEncoding, preserveCData, keepParent );
216 
217                 archetypeDescriptor.addModule( moduleDescriptor );
218 
219                 getLogger().debug(
220                     "Added module " + moduleDescriptor.getName() + " in " + archetypeDescriptor.getName() );
221             }
222 
223             restoreParentArtifactId( reverseProperties, null );
224             restoreArtifactId( reverseProperties, configurationProperties.getProperty( Constants.ARTIFACT_ID ) );
225 
226             createPoms( pom, configurationProperties.getProperty( Constants.ARTIFACT_ID ),
227                         configurationProperties.getProperty( Constants.ARTIFACT_ID ), archetypeFilesDirectory, basedir,
228                         pomReversedProperties, preserveCData, keepParent );
229             getLogger().debug( "Created Archetype " + archetypeDescriptor.getName() + " template pom(s)" );
230 
231             Writer out = null;
232             try
233             {
234                 out = WriterFactory.newXmlWriter( archetypeDescriptorFile );
235 
236                 ArchetypeDescriptorXpp3Writer writer = new ArchetypeDescriptorXpp3Writer();
237 
238                 writer.write( out, archetypeDescriptor );
239 
240                 getLogger().debug( "Archetype " + archetypeDescriptor.getName() + " descriptor written" );
241             }
242             finally
243             {
244                 IOUtil.close( out );
245             }
246 
247             createArchetypeBasicIt( archetypeDescriptor, outputDirectory );
248 
249             InvocationRequest internalRequest = new DefaultInvocationRequest();
250             internalRequest.setPomFile( archetypePomFile );
251             internalRequest.setGoals( Collections.singletonList( request.getPostPhase() ) );
252 
253             Invoker invoker = new DefaultInvoker();
254             invoker.execute( internalRequest );
255         }
256         catch ( Exception e )
257         {
258             result.setCause( e );
259         }
260     }
261 
262     /**
263      * Create an archetype IT, ie goals.txt and archetype.properties in src/test/resources/projects/basic.
264      *
265      * @param archetypeDescriptor
266      * @param generatedSourcesDirectory
267      * @throws IOException
268      * @since 2.0-alpha-5
269      */
270     private void createArchetypeBasicIt( ArchetypeDescriptor archetypeDescriptor, File generatedSourcesDirectory )
271         throws IOException
272     {
273         String basic =
274             Constants.SRC + File.separator + Constants.TEST + File.separator + Constants.RESOURCES + File.separator
275                 + "projects" + File.separator + "basic";
276         File basicItDirectory = new File( generatedSourcesDirectory, basic );
277         basicItDirectory.mkdirs();
278 
279         InputStream in = null;
280         OutputStream out = null;
281 
282         try
283         {
284             in = FilesetArchetypeCreator.class.getResourceAsStream( "archetype.properties" );
285 
286             Properties archetypeProperties = new Properties();
287             archetypeProperties.load( in );
288 
289             for ( RequiredProperty req : archetypeDescriptor.getRequiredProperties() )
290             {
291                 archetypeProperties.put( req.getKey(), req.getDefaultValue() );
292             }
293 
294             out = new FileOutputStream( new File( basicItDirectory, "archetype.properties" ) );
295             archetypeProperties.store( out, null );
296         }
297         finally
298         {
299             IOUtil.close( in );
300             IOUtil.close( out );
301         }
302         copyResource( "goal.txt", new File( basicItDirectory, "goal.txt" ) );
303 
304         getLogger().debug( "Added basic integration test" );
305     }
306 
307     private void extractPropertiesFromProject( MavenProject project, Properties properties,
308                                                Properties configurationProperties, String packageName )
309     {
310         if ( !properties.containsKey( Constants.GROUP_ID ) )
311         {
312             properties.setProperty( Constants.GROUP_ID, project.getGroupId() );
313         }
314         configurationProperties.setProperty( Constants.GROUP_ID, properties.getProperty( Constants.GROUP_ID ) );
315 
316         if ( !properties.containsKey( Constants.ARTIFACT_ID ) )
317         {
318             properties.setProperty( Constants.ARTIFACT_ID, project.getArtifactId() );
319         }
320         configurationProperties.setProperty( Constants.ARTIFACT_ID, properties.getProperty( Constants.ARTIFACT_ID ) );
321 
322         if ( !properties.containsKey( Constants.VERSION ) )
323         {
324             properties.setProperty( Constants.VERSION, project.getVersion() );
325         }
326         configurationProperties.setProperty( Constants.VERSION, properties.getProperty( Constants.VERSION ) );
327 
328         if ( packageName != null )
329         {
330             properties.setProperty( Constants.PACKAGE, packageName );
331         }
332         else if ( !properties.containsKey( Constants.PACKAGE ) )
333         {
334             properties.setProperty( Constants.PACKAGE, project.getGroupId() );
335         }
336         configurationProperties.setProperty( Constants.PACKAGE, properties.getProperty( Constants.PACKAGE ) );
337     }
338 
339     /**
340      * Create the archetype project pom.xml file, that will be used to build the archetype.
341      */
342     private File createArchetypeProjectPom( MavenProject project, ArtifactRepository localRepository,
343                                             Properties configurationProperties, File projectDir )
344         throws TemplateCreationException, IOException
345     {
346         Model model = new Model();
347         model.setModelVersion( "4.0.0" );
348         // these values should be retrieved from the request with sensible defaults
349         model.setGroupId( configurationProperties.getProperty( Constants.ARCHETYPE_GROUP_ID, project.getGroupId() ) );
350         model.setArtifactId(
351             configurationProperties.getProperty( Constants.ARCHETYPE_ARTIFACT_ID, project.getArtifactId() ) );
352         model.setVersion( configurationProperties.getProperty( Constants.ARCHETYPE_VERSION, project.getVersion() ) );
353         model.setPackaging( "maven-archetype" );
354         model.setName(
355             configurationProperties.getProperty( Constants.ARCHETYPE_ARTIFACT_ID, project.getArtifactId() ) );
356         model.setUrl( configurationProperties.getProperty( Constants.ARCHETYPE_URL, project.getUrl() ) );
357         model.setDescription(
358             configurationProperties.getProperty( Constants.ARCHETYPE_DESCRIPTION, project.getDescription() ) );
359         model.setLicenses( project.getLicenses() );
360         model.setDevelopers( project.getDevelopers() );
361         model.setScm( project.getScm() );
362         Build build = new Build();
363         model.setBuild( build );
364 
365         // In many cases where we are behind a firewall making Archetypes for work mates we want
366         // to simply be able to deploy the archetypes once we have created them. In order to do
367         // this we want to utilize information from the project we are creating the archetype from.
368         // This will be a fully working project that has been testing and inherits from a POM
369         // that contains deployment information, along with any extensions required for deployment.
370         // We don't want to create archetypes that cannot be deployed after we create them. People
371         // might want to edit the archetype POM but they should not have too.
372 
373         if ( project.getParent() != null )
374         {
375             Artifact pa = project.getParentArtifact();
376 
377             try
378             {
379                 MavenProject p =
380                     projectBuilder.buildFromRepository( pa, project.getRemoteArtifactRepositories(), localRepository );
381 
382                 if ( p.getDistributionManagement() != null )
383                 {
384                     model.setDistributionManagement( p.getDistributionManagement() );
385                 }
386 
387                 if ( p.getBuildExtensions() != null )
388                 {
389                     for ( Iterator<Extension> i = p.getBuildExtensions().iterator(); i.hasNext(); )
390                     {
391                         Extension be = i.next();
392 
393                         model.getBuild().addExtension( be );
394                     }
395                 }
396             }
397             catch ( ProjectBuildingException e )
398             {
399                 throw new TemplateCreationException(
400                     "Error reading parent POM of project: " + pa.getGroupId() + ":" + pa.getArtifactId() + ":"
401                         + pa.getVersion() );
402             }
403         }
404 
405         Extension extension = new Extension();
406         extension.setGroupId( "org.apache.maven.archetype" );
407         extension.setArtifactId( "archetype-packaging" );
408         extension.setVersion( getArchetypeVersion() );
409         model.getBuild().addExtension( extension );
410 
411         Plugin plugin = new Plugin();
412         plugin.setGroupId( "org.apache.maven.plugins" );
413         plugin.setArtifactId( "maven-archetype-plugin" );
414         plugin.setVersion( getArchetypeVersion() );
415 
416         PluginManagement pluginManagement = new PluginManagement();
417         pluginManagement.addPlugin( plugin );
418         model.getBuild().setPluginManagement( pluginManagement );
419 
420         getLogger().debug( "Creating archetype's pom" );
421 
422         File archetypePomFile = new File( projectDir, Constants.ARCHETYPE_POM );
423 
424         archetypePomFile.getParentFile().mkdirs();
425 
426         copyResource( "pom-prototype.xml", archetypePomFile );
427 
428         pomManager.writePom( model, archetypePomFile, archetypePomFile );
429 
430         return archetypePomFile;
431     }
432 
433     private void copyResource( String name, File destination )
434         throws IOException
435     {
436         InputStream in = null;
437         OutputStream out = null;
438 
439         try
440         {
441             in = FilesetArchetypeCreator.class.getResourceAsStream( name );
442             out = new FileOutputStream( destination );
443 
444             IOUtil.copy( in, out );
445         }
446         finally
447         {
448             IOUtil.close( in );
449             IOUtil.close( out );
450         }
451     }
452 
453     private void addRequiredProperties( ArchetypeDescriptor archetypeDescriptor, Properties properties )
454     {
455         Properties requiredProperties = new Properties();
456         requiredProperties.putAll( properties );
457         requiredProperties.remove( Constants.ARCHETYPE_GROUP_ID );
458         requiredProperties.remove( Constants.ARCHETYPE_ARTIFACT_ID );
459         requiredProperties.remove( Constants.ARCHETYPE_VERSION );
460         requiredProperties.remove( Constants.GROUP_ID );
461         requiredProperties.remove( Constants.ARTIFACT_ID );
462         requiredProperties.remove( Constants.VERSION );
463         requiredProperties.remove( Constants.PACKAGE );
464 
465         for ( Iterator<?> propertiesIterator = requiredProperties.keySet().iterator(); propertiesIterator.hasNext(); )
466         {
467             String propertyKey = (String) propertiesIterator.next();
468 
469             RequiredProperty requiredProperty = new RequiredProperty();
470             requiredProperty.setKey( propertyKey );
471             requiredProperty.setDefaultValue( requiredProperties.getProperty( propertyKey ) );
472 
473             archetypeDescriptor.addRequiredProperty( requiredProperty );
474 
475             getLogger().debug(
476                 "Adding requiredProperty " + propertyKey + "=" + requiredProperties.getProperty( propertyKey )
477                     + " to archetype's descriptor" );
478         }
479     }
480 
481     private void createModulePoms( Properties pomReversedProperties, String rootArtifactId, String packageName,
482                                    File basedir, File archetypeFilesDirectory, boolean preserveCData,
483                                    boolean keepParent )
484         throws FileNotFoundException, IOException, XmlPullParserException
485     {
486         Model pom = pomManager.readPom( FileUtils.resolveFile( basedir, Constants.ARCHETYPE_POM ) );
487 
488         String parentArtifactId = pomReversedProperties.getProperty( Constants.PARENT_ARTIFACT_ID );
489         String artifactId = pom.getArtifactId();
490         setParentArtifactId( pomReversedProperties, pomReversedProperties.getProperty( Constants.ARTIFACT_ID ) );
491         setArtifactId( pomReversedProperties, pom.getArtifactId() );
492 
493         for ( Iterator<String> modules = pom.getModules().iterator(); modules.hasNext(); )
494         {
495             String subModuleId = modules.next();
496 
497             String subModuleIdDirectory = subModuleId;
498 
499             if ( subModuleId.indexOf( rootArtifactId ) >= 0 )
500             {
501                 subModuleIdDirectory = StringUtils.replace( subModuleId, rootArtifactId, "__rootArtifactId__" );
502             }
503 
504             createModulePoms( pomReversedProperties, rootArtifactId, packageName,
505                               FileUtils.resolveFile( basedir, subModuleId ),
506                               FileUtils.resolveFile( archetypeFilesDirectory, subModuleIdDirectory ), preserveCData,
507                               keepParent );
508         }
509 
510         createModulePom( pom, rootArtifactId, archetypeFilesDirectory, pomReversedProperties,
511                          FileUtils.resolveFile( basedir, Constants.ARCHETYPE_POM ), preserveCData, keepParent );
512 
513         restoreParentArtifactId( pomReversedProperties, parentArtifactId );
514         restoreArtifactId( pomReversedProperties, artifactId );
515     }
516 
517     private void createPoms( Model pom, String rootArtifactId, String artifactId, File archetypeFilesDirectory,
518                              File basedir, Properties pomReversedProperties, boolean preserveCData, boolean keepParent )
519         throws IOException, FileNotFoundException, XmlPullParserException
520     {
521         setArtifactId( pomReversedProperties, pom.getArtifactId() );
522 
523         for ( Iterator<String> modules = pom.getModules().iterator(); modules.hasNext(); )
524         {
525             String moduleId = modules.next();
526 
527             String moduleIdDirectory = moduleId;
528 
529             if ( moduleId.indexOf( rootArtifactId ) >= 0 )
530             {
531                 moduleIdDirectory = StringUtils.replace( moduleId, rootArtifactId, "__rootArtifactId__" );
532             }
533 
534             createModulePoms( pomReversedProperties, rootArtifactId, moduleId,
535                               FileUtils.resolveFile( basedir, moduleId ),
536                               new File( archetypeFilesDirectory, moduleIdDirectory ), preserveCData, keepParent );
537         }
538 
539         restoreParentArtifactId( pomReversedProperties, null );
540         restoreArtifactId( pomReversedProperties, artifactId );
541 
542         createArchetypePom( pom, archetypeFilesDirectory, pomReversedProperties,
543                             FileUtils.resolveFile( basedir, Constants.ARCHETYPE_POM ), preserveCData, keepParent );
544     }
545 
546     private String getPackageInPathFormat( String aPackage )
547     {
548         return StringUtils.replace( aPackage, ".", "/" );
549     }
550 
551     private void rewriteReferences( Model pom, String rootArtifactId, String groupId )
552     {
553         // rewrite Dependencies
554         if ( pom.getDependencies() != null && !pom.getDependencies().isEmpty() )
555         {
556             for ( Iterator<Dependency> dependencies = pom.getDependencies().iterator(); dependencies.hasNext(); )
557             {
558                 rewriteDependencyReferences( dependencies.next(), rootArtifactId, groupId );
559             }
560         }
561 
562         // rewrite DependencyManagement
563         if ( pom.getDependencyManagement() != null && pom.getDependencyManagement().getDependencies() != null
564             && !pom.getDependencyManagement().getDependencies().isEmpty() )
565         {
566             for ( Iterator<Dependency> dependencies = pom.getDependencyManagement().getDependencies().iterator();
567                   dependencies.hasNext(); )
568             {
569                 rewriteDependencyReferences( dependencies.next(), rootArtifactId, groupId );
570             }
571         }
572 
573         // rewrite Plugins
574         if ( pom.getBuild() != null && pom.getBuild().getPlugins() != null && !pom.getBuild().getPlugins().isEmpty() )
575         {
576             for ( Iterator<Plugin> plugins = pom.getBuild().getPlugins().iterator(); plugins.hasNext(); )
577             {
578                 rewritePluginReferences( plugins.next(), rootArtifactId, groupId );
579             }
580         }
581 
582         // rewrite PluginManagement
583         if ( pom.getBuild() != null && pom.getBuild().getPluginManagement() != null
584             && pom.getBuild().getPluginManagement().getPlugins() != null
585             && !pom.getBuild().getPluginManagement().getPlugins().isEmpty() )
586         {
587             for ( Iterator<Plugin> plugins = pom.getBuild().getPluginManagement().getPlugins().iterator();
588                   plugins.hasNext(); )
589             {
590                 rewritePluginReferences( plugins.next(), rootArtifactId, groupId );
591             }
592         }
593 
594         // rewrite Profiles
595         if ( pom.getProfiles() != null )
596         {
597             for ( Iterator<Profile> profiles = pom.getProfiles().iterator(); profiles.hasNext(); )
598             {
599                 Profile profile = profiles.next();
600 
601                 // rewrite Dependencies
602                 if ( profile.getDependencies() != null && !profile.getDependencies().isEmpty() )
603                 {
604                     for ( Iterator<Dependency> dependencies = profile.getDependencies().iterator();
605                           dependencies.hasNext(); )
606                     {
607                         rewriteDependencyReferences( dependencies.next(), rootArtifactId, groupId );
608                     }
609                 }
610 
611                 // rewrite DependencyManagement
612                 if ( profile.getDependencyManagement() != null
613                     && profile.getDependencyManagement().getDependencies() != null
614                     && !profile.getDependencyManagement().getDependencies().isEmpty() )
615                 {
616                     for ( Iterator<Dependency> dependencies =
617                               profile.getDependencyManagement().getDependencies().iterator(); dependencies.hasNext(); )
618                     {
619                         rewriteDependencyReferences( dependencies.next(), rootArtifactId, groupId );
620                     }
621                 }
622 
623                 // rewrite Plugins
624                 if ( profile.getBuild() != null && profile.getBuild().getPlugins() != null
625                     && !profile.getBuild().getPlugins().isEmpty() )
626                 {
627                     for ( Iterator<Plugin> plugins = profile.getBuild().getPlugins().iterator(); plugins.hasNext(); )
628                     {
629                         rewritePluginReferences( plugins.next(), rootArtifactId, groupId );
630                     }
631                 }
632 
633                 // rewrite PluginManagement
634                 if ( profile.getBuild() != null && profile.getBuild().getPluginManagement() != null
635                     && profile.getBuild().getPluginManagement().getPlugins() != null
636                     && !profile.getBuild().getPluginManagement().getPlugins().isEmpty() )
637                 {
638                     for ( Iterator<Plugin> plugins = profile.getBuild().getPluginManagement().getPlugins().iterator();
639                           plugins.hasNext(); )
640                     {
641                         rewritePluginReferences( plugins.next(), rootArtifactId, groupId );
642                     }
643                 }
644             }
645         }
646     }
647 
648     private void rewriteDependencyReferences( Dependency dependency, String rootArtifactId, String groupId )
649     {
650         if ( dependency.getArtifactId() != null && dependency.getArtifactId().indexOf( rootArtifactId ) >= 0 )
651         {
652             if ( dependency.getGroupId() != null )
653             {
654                 dependency.setGroupId(
655                     StringUtils.replace( dependency.getGroupId(), groupId, "${" + Constants.GROUP_ID + "}" ) );
656             }
657 
658             dependency.setArtifactId(
659                 StringUtils.replace( dependency.getArtifactId(), rootArtifactId, "${rootArtifactId}" ) );
660 
661             if ( dependency.getVersion() != null )
662             {
663                 dependency.setVersion( "${" + Constants.VERSION + "}" );
664             }
665         }
666     }
667 
668     private void rewritePluginReferences( Plugin plugin, String rootArtifactId, String groupId )
669     {
670         if ( plugin.getArtifactId() != null && plugin.getArtifactId().indexOf( rootArtifactId ) >= 0 )
671         {
672             if ( plugin.getGroupId() != null )
673             {
674                 String g = StringUtils.replace( plugin.getGroupId(), groupId, "${" + Constants.GROUP_ID + "}" );
675                 plugin.setGroupId( g );
676             }
677 
678             plugin.setArtifactId( StringUtils.replace( plugin.getArtifactId(), rootArtifactId, "${rootArtifactId}" ) );
679 
680             if ( plugin.getVersion() != null )
681             {
682                 plugin.setVersion( "${" + Constants.VERSION + "}" );
683             }
684         }
685 
686         if ( plugin.getArtifactId() != null && "maven-ear-plugin".equals( plugin.getArtifactId() ) )
687         {
688             rewriteEARPluginReferences( plugin, rootArtifactId, groupId );
689         }
690     }
691 
692     private void rewriteEARPluginReferences( Plugin plugin, String rootArtifactId, String groupId )
693     {
694         Xpp3Dom configuration = (Xpp3Dom) plugin.getConfiguration();
695         if ( configuration != null )
696         {
697             Xpp3Dom[] modules = configuration.getChild( "modules" ).getChildren();
698             for ( int i = 0; i < modules.length; i++ )
699             {
700                 Xpp3Dom module = modules[i];
701                 Xpp3Dom moduleGroupId = module.getChild( "groupId" );
702                 Xpp3Dom moduleArtifactId = module.getChild( "artifactId" );
703                 Xpp3Dom moduleBundleFileName = module.getChild( "bundleFileName" );
704                 Xpp3Dom moduleModuleId = module.getChild( "moduleId" );
705                 Xpp3Dom moduleContextRoot = module.getChild( "contextRoot" );
706 
707                 if ( moduleGroupId != null )
708                 {
709                     moduleGroupId.setValue(
710                         StringUtils.replace( moduleGroupId.getValue(), groupId, "${" + Constants.GROUP_ID + "}" ) );
711                 }
712 
713                 if ( moduleArtifactId != null )
714                 {
715                     moduleArtifactId.setValue(
716                         StringUtils.replace( moduleArtifactId.getValue(), rootArtifactId, "${rootArtifactId}" ) );
717                 }
718 
719                 if ( moduleBundleFileName != null )
720                 {
721                     moduleBundleFileName.setValue(
722                         StringUtils.replace( moduleBundleFileName.getValue(), rootArtifactId, "${rootArtifactId}" ) );
723                 }
724 
725                 if ( moduleModuleId != null )
726                 {
727                     moduleModuleId.setValue(
728                         StringUtils.replace( moduleModuleId.getValue(), rootArtifactId, "${rootArtifactId}" ) );
729                 }
730 
731                 if ( moduleContextRoot != null )
732                 {
733                     moduleContextRoot.setValue(
734                         StringUtils.replace( moduleContextRoot.getValue(), rootArtifactId, "${rootArtifactId}" ) );
735                 }
736             }
737         }
738     }
739 
740     private void setArtifactId( Properties properties, String artifactId )
741     {
742         properties.setProperty( Constants.ARTIFACT_ID, artifactId );
743     }
744 
745     private List<String> concatenateToList( List<String> toConcatenate, String with )
746     {
747         List<String> result = new ArrayList<String>( toConcatenate.size() );
748 
749         for ( String concatenate : toConcatenate )
750         {
751             result.add( ( ( with.length() > 0 ) ? ( with + "/" + concatenate ) : concatenate ) );
752         }
753 
754         return result;
755     }
756 
757     private void copyFiles( File basedir, File archetypeFilesDirectory, String directory, List<String> fileSetResources,
758                             boolean packaged, String packageName )
759         throws IOException
760     {
761         String packageAsDirectory = StringUtils.replace( packageName, ".", File.separator );
762 
763         getLogger().debug( "Package as Directory: Package:" + packageName + "->" + packageAsDirectory );
764 
765         for ( String inputFileName : fileSetResources )
766         {
767             String outputFileName = packaged
768                 ? StringUtils.replace( inputFileName, packageAsDirectory + File.separator, "" )
769                 : inputFileName;
770             getLogger().debug( "InputFileName:" + inputFileName );
771             getLogger().debug( "OutputFileName:" + outputFileName );
772 
773             File outputFile = new File( archetypeFilesDirectory, outputFileName );
774 
775             File inputFile = new File( basedir, inputFileName );
776 
777             outputFile.getParentFile().mkdirs();
778 
779             FileUtils.copyFile( inputFile, outputFile );
780         }
781     }
782 
783     private void createArchetypeFiles( Properties reverseProperties, List<FileSet> fileSets, String packageName,
784                                        File basedir, File archetypeFilesDirectory, String defaultEncoding )
785         throws IOException
786     {
787         getLogger().debug( "Creating Archetype/Module files from " + basedir + " to " + archetypeFilesDirectory );
788 
789         for ( FileSet fileSet : fileSets )
790         {
791             DirectoryScanner scanner = new DirectoryScanner();
792             scanner.setBasedir( basedir );
793             scanner.setIncludes( (String[]) concatenateToList( fileSet.getIncludes(), fileSet.getDirectory() ).toArray(
794                 new String[fileSet.getIncludes().size()] ) );
795             scanner.setExcludes( (String[]) fileSet.getExcludes().toArray( new String[fileSet.getExcludes().size()] ) );
796             scanner.addDefaultExcludes();
797             getLogger().debug( "Using fileset " + fileSet );
798             scanner.scan();
799 
800             List<String> fileSetResources = Arrays.asList( scanner.getIncludedFiles() );
801             getLogger().debug( "Scanned " + fileSetResources.size() + " resources" );
802 
803             if ( fileSet.isFiltered() )
804             {
805                 processFileSet( basedir, archetypeFilesDirectory, fileSet.getDirectory(), fileSetResources,
806                                 fileSet.isPackaged(), packageName, reverseProperties, defaultEncoding );
807                 getLogger().debug( "Processed " + fileSet.getDirectory() + " files" );
808             }
809             else
810             {
811                 copyFiles( basedir, archetypeFilesDirectory, fileSet.getDirectory(), fileSetResources,
812                            fileSet.isPackaged(), packageName );
813                 getLogger().debug( "Copied " + fileSet.getDirectory() + " files" );
814             }
815         }
816     }
817 
818     private void createArchetypePom( Model pom, File archetypeFilesDirectory, Properties pomReversedProperties,
819                                      File initialPomFile, boolean preserveCData, boolean keepParent )
820         throws IOException
821     {
822         File outputFile = FileUtils.resolveFile( archetypeFilesDirectory, Constants.ARCHETYPE_POM );
823 
824         if ( preserveCData )
825         {
826             getLogger().debug( "Preserving CDATA parts of pom" );
827             File inputFile = FileUtils.resolveFile( archetypeFilesDirectory, Constants.ARCHETYPE_POM + ".tmp" );
828 
829             FileUtils.copyFile( initialPomFile, inputFile );
830 
831             Reader in = null;
832             Writer out = null;
833             try
834             {
835                 in = ReaderFactory.newXmlReader( inputFile );
836 
837                 String initialcontent = IOUtil.toString( in );
838 
839                 String content = getReversedContent( initialcontent, pomReversedProperties );
840 
841                 outputFile.getParentFile().mkdirs();
842 
843                 out = WriterFactory.newXmlWriter( outputFile );
844 
845                 IOUtil.copy( content, out );
846             }
847             finally
848             {
849                 IOUtil.close( in );
850                 IOUtil.close( out );
851             }
852 
853             inputFile.delete();
854         }
855         else
856         {
857             if ( !keepParent )
858             {
859                 pom.setParent( null );
860             }
861 
862             pom.setModules( null );
863             pom.setGroupId( "${" + Constants.GROUP_ID + "}" );
864             pom.setArtifactId( "${" + Constants.ARTIFACT_ID + "}" );
865             pom.setVersion( "${" + Constants.VERSION + "}" );
866             pom.setName( getReversedPlainContent( pom.getName(), pomReversedProperties ) );
867             pom.setDescription( getReversedPlainContent( pom.getDescription(), pomReversedProperties ) );
868             pom.setUrl( getReversedPlainContent( pom.getUrl(), pomReversedProperties ) );
869 
870 
871             rewriteReferences( pom, pomReversedProperties.getProperty( Constants.ARTIFACT_ID ),
872                                pomReversedProperties.getProperty( Constants.GROUP_ID ) );
873 
874             pomManager.writePom( pom, outputFile, initialPomFile );
875         }
876 
877         Reader in = null;
878         try
879         {
880             in = ReaderFactory.newXmlReader( initialPomFile );
881             String initialcontent = IOUtil.toString( in );
882 
883             Iterator<?> properties = pomReversedProperties.keySet().iterator();
884             while ( properties.hasNext() )
885             {
886                 String property = (String) properties.next();
887 
888                 if ( initialcontent.indexOf( "${" + property + "}" ) > 0 )
889                 {
890                     getLogger().warn(
891                         "Archetype uses ${" + property + "} for internal processing, but file " + initialPomFile
892                             + " contains this property already" );
893                 }
894             }
895         }
896         finally
897         {
898             IOUtil.close( in );
899         }
900     }
901 
902     private FileSet createFileSet( final List<String> excludes, final boolean packaged, final boolean filtered,
903                                    final String group, final List<String> includes, String defaultEncoding )
904     {
905         FileSet fileSet = new FileSet();
906 
907         fileSet.setDirectory( group );
908         fileSet.setPackaged( packaged );
909         fileSet.setFiltered( filtered );
910         fileSet.setIncludes( includes );
911         fileSet.setExcludes( excludes );
912         fileSet.setEncoding( defaultEncoding );
913 
914         getLogger().debug( "Created Fileset " + fileSet );
915 
916         return fileSet;
917     }
918 
919     private List<FileSet> createFileSets( List<String> files, int level, boolean packaged, String packageName,
920                                           boolean filtered, String defaultEncoding )
921     {
922         List<FileSet> fileSets = new ArrayList<FileSet>();
923 
924         if ( !files.isEmpty() )
925         {
926             getLogger().debug( "Creating filesets" + ( packaged ? ( " packaged (" + packageName + ")" ) : "" ) + (
927                 filtered
928                     ? " filtered"
929                     : "" ) + " at level " + level );
930             if ( level == 0 )
931             {
932                 List<String> includes = new ArrayList<String>( files );
933                 List<String> excludes = new ArrayList<String>();
934 
935                 if ( !includes.isEmpty() )
936                 {
937                     fileSets.add( createFileSet( excludes, packaged, filtered, "", includes, defaultEncoding ) );
938                 }
939             }
940             else
941             {
942                 Map<String, List<String>> groups = getGroupsMap( files, level );
943 
944                 for ( String group : groups.keySet() )
945                 {
946                     getLogger().debug( "Creating filesets for group " + group );
947 
948                     if ( !packaged )
949                     {
950                         fileSets.add( getUnpackagedFileSet( filtered, group, groups.get( group ), defaultEncoding ) );
951                     }
952                     else
953                     {
954                         fileSets.addAll(
955                             getPackagedFileSets( filtered, group, groups.get( group ), packageName, defaultEncoding ) );
956                     }
957                 }
958             } // end if
959 
960             getLogger().debug( "Resolved fileSets " + fileSets );
961         } // end if
962 
963         return fileSets;
964     }
965 
966     private ModuleDescriptor createModule( Properties reverseProperties, String rootArtifactId, String moduleId,
967                                            String packageName, File basedir, File archetypeFilesDirectory,
968                                            List<String> languages, List<String> filtereds, String defaultEncoding,
969                                            boolean preserveCData, boolean keepParent )
970         throws IOException, XmlPullParserException
971     {
972         ModuleDescriptor archetypeDescriptor = new ModuleDescriptor();
973         getLogger().debug( "Starting module's descriptor " + moduleId );
974 
975         archetypeFilesDirectory.mkdirs();
976         getLogger().debug( "Module's files output directory " + archetypeFilesDirectory );
977 
978         Model pom = pomManager.readPom( FileUtils.resolveFile( basedir, Constants.ARCHETYPE_POM ) );
979         String replacementId = pom.getArtifactId();
980         String moduleDirectory = pom.getArtifactId();
981 
982         if ( replacementId.indexOf( rootArtifactId ) >= 0 )
983         {
984             replacementId = StringUtils.replace( replacementId, rootArtifactId, "${rootArtifactId}" );
985             moduleDirectory = StringUtils.replace( moduleId, rootArtifactId, "__rootArtifactId__" );
986         }
987 
988         if ( moduleId.indexOf( rootArtifactId ) >= 0 )
989         {
990             moduleDirectory = StringUtils.replace( moduleId, rootArtifactId, "__rootArtifactId__" );
991         }
992 
993         archetypeDescriptor.setName( replacementId );
994         archetypeDescriptor.setId( replacementId );
995         archetypeDescriptor.setDir( moduleDirectory );
996 
997         setArtifactId( reverseProperties, pom.getArtifactId() );
998 
999         List<String> excludePatterns =
1000             reverseProperties.getProperty( Constants.EXCLUDE_PATTERNS ) != null
1001                 ? Arrays.asList( StringUtils.split( reverseProperties.getProperty( Constants.EXCLUDE_PATTERNS ), "," ) )
1002                 : Collections.<String>emptyList();
1003 
1004         List<String> fileNames = resolveFileNames( pom, basedir, excludePatterns );
1005 
1006         List<FileSet> filesets = resolveFileSets( packageName, fileNames, languages, filtereds, defaultEncoding );
1007         getLogger().debug( "Resolved filesets for module " + archetypeDescriptor.getName() );
1008 
1009         archetypeDescriptor.setFileSets( filesets );
1010 
1011         createArchetypeFiles( reverseProperties, filesets, packageName, basedir, archetypeFilesDirectory,
1012                               defaultEncoding );
1013         getLogger().debug( "Created files for module " + archetypeDescriptor.getName() );
1014 
1015         String parentArtifactId = reverseProperties.getProperty( Constants.PARENT_ARTIFACT_ID );
1016         setParentArtifactId( reverseProperties, pom.getArtifactId() );
1017 
1018         for ( Iterator<String> modules = pom.getModules().iterator(); modules.hasNext(); )
1019         {
1020             String subModuleId = modules.next();
1021 
1022             String subModuleIdDirectory = subModuleId;
1023             if ( subModuleId.indexOf( rootArtifactId ) >= 0 )
1024             {
1025                 subModuleIdDirectory = StringUtils.replace( subModuleId, rootArtifactId, "__rootArtifactId__" );
1026             }
1027 
1028             getLogger().debug( "Creating module " + subModuleId );
1029 
1030             ModuleDescriptor moduleDescriptor =
1031                 createModule( reverseProperties, rootArtifactId, subModuleId, packageName,
1032                               FileUtils.resolveFile( basedir, subModuleId ),
1033                               FileUtils.resolveFile( archetypeFilesDirectory, subModuleIdDirectory ), languages,
1034                               filtereds, defaultEncoding, preserveCData, keepParent );
1035 
1036             archetypeDescriptor.addModule( moduleDescriptor );
1037 
1038             getLogger().debug( "Added module " + moduleDescriptor.getName() + " in " + archetypeDescriptor.getName() );
1039         }
1040 
1041         restoreParentArtifactId( reverseProperties, parentArtifactId );
1042         restoreArtifactId( reverseProperties, pom.getArtifactId() );
1043 
1044         getLogger().debug( "Created Module " + archetypeDescriptor.getName() + " pom" );
1045 
1046         return archetypeDescriptor;
1047     }
1048 
1049     private void createModulePom( Model pom, String rootArtifactId, File archetypeFilesDirectory,
1050                                   Properties pomReversedProperties, File initialPomFile, boolean preserveCData,
1051                                   boolean keepParent )
1052         throws IOException
1053     {
1054         File outputFile = FileUtils.resolveFile( archetypeFilesDirectory, Constants.ARCHETYPE_POM );
1055 
1056         if ( preserveCData )
1057         {
1058             getLogger().debug( "Preserving CDATA parts of pom" );
1059             File inputFile = FileUtils.resolveFile( archetypeFilesDirectory, Constants.ARCHETYPE_POM + ".tmp" );
1060 
1061             FileUtils.copyFile( initialPomFile, inputFile );
1062 
1063             Reader in = null;
1064             Writer out = null;
1065             try
1066             {
1067                 in = ReaderFactory.newXmlReader( inputFile );
1068 
1069                 String initialcontent = IOUtil.toString( in );
1070 
1071                 String content = getReversedContent( initialcontent, pomReversedProperties );
1072 
1073                 outputFile.getParentFile().mkdirs();
1074 
1075                 out = WriterFactory.newXmlWriter( outputFile );
1076 
1077                 IOUtil.copy( content, out );
1078             }
1079             finally
1080             {
1081                 IOUtil.close( in );
1082                 IOUtil.close( out );
1083             }
1084 
1085             inputFile.delete();
1086         }
1087         else
1088         {
1089             if ( pom.getParent() != null )
1090             {
1091                 pom.getParent().setGroupId( StringUtils.replace( pom.getParent().getGroupId(),
1092                                                                  pomReversedProperties.getProperty(
1093                                                                      Constants.GROUP_ID ),
1094                                                                  "${" + Constants.GROUP_ID + "}" ) );
1095                 if ( pom.getParent().getArtifactId() != null
1096                     && pom.getParent().getArtifactId().indexOf( rootArtifactId ) >= 0 )
1097                 {
1098                     pom.getParent().setArtifactId(
1099                         StringUtils.replace( pom.getParent().getArtifactId(), rootArtifactId, "${rootArtifactId}" ) );
1100                 }
1101                 if ( pom.getParent().getVersion() != null )
1102                 {
1103                     pom.getParent().setVersion( "${" + Constants.VERSION + "}" );
1104                 }
1105             }
1106             pom.setModules( null );
1107 
1108             if ( pom.getGroupId() != null )
1109             {
1110                 pom.setGroupId(
1111                     StringUtils.replace( pom.getGroupId(), pomReversedProperties.getProperty( Constants.GROUP_ID ),
1112                                          "${" + Constants.GROUP_ID + "}" ) );
1113             }
1114 
1115             pom.setArtifactId( "${" + Constants.ARTIFACT_ID + "}" );
1116 
1117             if ( pom.getVersion() != null )
1118             {
1119                 pom.setVersion( "${" + Constants.VERSION + "}" );
1120             }
1121 
1122             pom.setName( getReversedPlainContent( pom.getName(), pomReversedProperties ) );
1123             pom.setDescription( getReversedPlainContent( pom.getDescription(), pomReversedProperties ) );
1124             pom.setUrl( getReversedPlainContent( pom.getUrl(), pomReversedProperties ) );
1125 
1126             rewriteReferences( pom, rootArtifactId, pomReversedProperties.getProperty( Constants.GROUP_ID ) );
1127 
1128             pomManager.writePom( pom, outputFile, initialPomFile );
1129         }
1130 
1131         Reader in = null;
1132         try
1133         {
1134             in = ReaderFactory.newXmlReader( initialPomFile );
1135             String initialcontent = IOUtil.toString( in );
1136 
1137             for ( Iterator<?> properties = pomReversedProperties.keySet().iterator(); properties.hasNext(); )
1138             {
1139                 String property = (String) properties.next();
1140 
1141                 if ( initialcontent.indexOf( "${" + property + "}" ) > 0 )
1142                 {
1143                     getLogger().warn(
1144                         "OldArchetype uses ${" + property + "} for internal processing, but file " + initialPomFile
1145                             + " contains this property already" );
1146                 }
1147             }
1148         }
1149         finally
1150         {
1151             IOUtil.close( in );
1152         }
1153     }
1154 
1155     private Set<String> getExtensions( List<String> files )
1156     {
1157         Set<String> extensions = new HashSet<String>();
1158 
1159         for ( String file : files )
1160         {
1161             extensions.add( FileUtils.extension( file ) );
1162         }
1163 
1164         return extensions;
1165     }
1166 
1167     private Map<String, List<String>> getGroupsMap( final List<String> files, final int level )
1168     {
1169         Map<String, List<String>> groups = new HashMap<String, List<String>>();
1170 
1171         for ( String file : files )
1172         {
1173             String directory = PathUtils.getDirectory( file, level );
1174             // make all groups have unix style
1175             directory = StringUtils.replace( directory, File.separator, "/" );
1176 
1177             if ( !groups.containsKey( directory ) )
1178             {
1179                 groups.put( directory, new ArrayList<String>() );
1180             }
1181 
1182             List<String> group = groups.get( directory );
1183 
1184             String innerPath = file.substring( directory.length() + 1 );
1185             // make all groups have unix style
1186             innerPath = StringUtils.replace( innerPath, File.separator, "/" );
1187 
1188             group.add( innerPath );
1189         }
1190 
1191         getLogger().debug( "Sorted " + groups.size() + " groups in " + files.size() + " files" );
1192         getLogger().debug( "Sorted Files: " + files );
1193 
1194         return groups;
1195     }
1196 
1197     private FileSet getPackagedFileSet( final boolean filtered, final Set<String> packagedExtensions,
1198                                         final String group, final Set<String> unpackagedExtensions,
1199                                         final List<String> unpackagedFiles, String defaultEncoding )
1200     {
1201         List<String> includes = new ArrayList<String>();
1202         List<String> excludes = new ArrayList<String>();
1203 
1204         for ( String extension : packagedExtensions )
1205         {
1206             includes.add( "**/*." + extension );
1207 
1208             if ( unpackagedExtensions.contains( extension ) )
1209             {
1210                 excludes.addAll( archetypeFilesResolver.getFilesWithExtension( unpackagedFiles, extension ) );
1211             }
1212         }
1213 
1214         return createFileSet( excludes, true, filtered, group, includes, defaultEncoding );
1215     }
1216 
1217     private List<FileSet> getPackagedFileSets( final boolean filtered, final String group,
1218                                                final List<String> groupFiles, final String packageName,
1219                                                String defaultEncoding )
1220     {
1221         String packageAsDir = StringUtils.replace( packageName, ".", "/" );
1222 
1223         List<FileSet> packagedFileSets = new ArrayList<FileSet>();
1224         List<String> packagedFiles = archetypeFilesResolver.getPackagedFiles( groupFiles, packageAsDir );
1225         getLogger().debug( "Found packaged Files:" + packagedFiles );
1226 
1227         List<String> unpackagedFiles = archetypeFilesResolver.getUnpackagedFiles( groupFiles, packageAsDir );
1228         getLogger().debug( "Found unpackaged Files:" + unpackagedFiles );
1229 
1230         Set<String> packagedExtensions = getExtensions( packagedFiles );
1231         getLogger().debug( "Found packaged extensions " + packagedExtensions );
1232 
1233         Set<String> unpackagedExtensions = getExtensions( unpackagedFiles );
1234 
1235         if ( !packagedExtensions.isEmpty() )
1236         {
1237             packagedFileSets.add(
1238                 getPackagedFileSet( filtered, packagedExtensions, group, unpackagedExtensions, unpackagedFiles,
1239                                     defaultEncoding ) );
1240         }
1241 
1242         if ( !unpackagedExtensions.isEmpty() )
1243         {
1244             getLogger().debug( "Found unpackaged extensions " + unpackagedExtensions );
1245 
1246             packagedFileSets.add(
1247                 getUnpackagedFileSet( filtered, unpackagedExtensions, unpackagedFiles, group, packagedExtensions,
1248                                       defaultEncoding ) );
1249         }
1250 
1251         return packagedFileSets;
1252     }
1253 
1254     private void setParentArtifactId( Properties properties, String parentArtifactId )
1255     {
1256         properties.setProperty( Constants.PARENT_ARTIFACT_ID, parentArtifactId );
1257     }
1258 
1259     private void processFileSet( File basedir, File archetypeFilesDirectory, String directory,
1260                                  List<String> fileSetResources, boolean packaged, String packageName,
1261                                  Properties reverseProperties, String defaultEncoding )
1262         throws IOException
1263     {
1264         String packageAsDirectory = StringUtils.replace( packageName, ".", File.separator );
1265 
1266         getLogger().debug( "Package as Directory: Package:" + packageName + "->" + packageAsDirectory );
1267 
1268         for ( String inputFileName : fileSetResources )
1269         {
1270             String initialFilename = packaged
1271                 ? StringUtils.replace( inputFileName, packageAsDirectory + File.separator, "" )
1272                 : inputFileName;
1273 
1274             getLogger().debug( "InputFileName:" + inputFileName );
1275 
1276             File inputFile = new File( basedir, inputFileName );
1277 
1278             FileCharsetDetector detector = new FileCharsetDetector( inputFile );
1279 
1280             String fileEncoding = detector.isFound() ? detector.getCharset() : defaultEncoding;
1281 
1282             String initialcontent = IOUtil.toString( new FileInputStream( inputFile ), fileEncoding );
1283 
1284             for ( Iterator<?> properties = reverseProperties.keySet().iterator(); properties.hasNext(); )
1285             {
1286                 String property = (String) properties.next();
1287 
1288                 if ( initialcontent.indexOf( "${" + property + "}" ) > 0 )
1289                 {
1290                     getLogger().warn(
1291                         "Archetype uses ${" + property + "} for internal processing, but file " + inputFile
1292                             + " contains this property already" );
1293                 }
1294             }
1295 
1296             String content = getReversedContent( initialcontent, reverseProperties );
1297             String outputFilename = getReversedFilename( initialFilename, reverseProperties );
1298 
1299             getLogger().debug( "OutputFileName:" + outputFilename );
1300 
1301             File outputFile = new File( archetypeFilesDirectory, outputFilename );
1302             outputFile.getParentFile().mkdirs();
1303 
1304             org.apache.commons.io.IOUtils.write( content, new FileOutputStream( outputFile ), fileEncoding );
1305         }
1306     }
1307 
1308     private List<String> removePackage( List<String> sources, String packageAsDirectory )
1309     {
1310         if ( sources == null )
1311         {
1312             return null;
1313         }
1314 
1315         List<String> unpackagedSources = new ArrayList<String>( sources.size() );
1316 
1317         for ( String source : sources )
1318         {
1319             String unpackagedSource = StringUtils.replace( source, packageAsDirectory, "" );
1320 
1321             unpackagedSources.add( unpackagedSource );
1322         }
1323 
1324         return unpackagedSources;
1325     }
1326 
1327     private Properties getReversedProperties( ArchetypeDescriptor archetypeDescriptor, Properties properties )
1328     {
1329         Properties reversedProperties = new Properties();
1330 
1331         reversedProperties.putAll( properties );
1332         reversedProperties.remove( Constants.ARCHETYPE_GROUP_ID );
1333         reversedProperties.remove( Constants.ARCHETYPE_ARTIFACT_ID );
1334         reversedProperties.remove( Constants.ARCHETYPE_VERSION );
1335 
1336         String packageName = properties.getProperty( Constants.PACKAGE );
1337         String packageInPathFormat = getPackageInPathFormat( packageName );
1338         if ( !packageInPathFormat.equals( packageName ) )
1339         {
1340             reversedProperties.setProperty( Constants.PACKAGE_IN_PATH_FORMAT, packageInPathFormat );
1341         }
1342 
1343         // TODO check that reversed properties are all different and no one is a substring of another?
1344         // to avoid wrong variable replacements
1345 
1346         return reversedProperties;
1347     }
1348 
1349     private List<String> resolveFileNames( final Model pom, final File basedir, List<String> excludePatterns )
1350         throws IOException
1351     {
1352         getLogger().debug( "Resolving files for " + pom.getId() + " in " + basedir );
1353 
1354         StringBuffer buff = new StringBuffer( "pom.xml*,archetype.properties*,target/**," );
1355         for ( Iterator<String> modules = pom.getModules().iterator(); modules.hasNext(); )
1356         {
1357             buff.append( ',' ).append( modules.next() ).append( "/**" );
1358         }
1359 
1360         for ( String defaultExclude : ListScanner.DEFAULTEXCLUDES )
1361         {
1362             buff.append( ',' ).append( defaultExclude ).append( "/**" );
1363         }
1364 
1365         for ( String excludePattern : excludePatterns )
1366         {
1367             buff.append( ',' ).append( excludePattern );
1368         }
1369 
1370         String excludes = PathUtils.convertPathForOS( buff.toString() );
1371 
1372         List<String> fileNames = FileUtils.getFileNames( basedir, "**,.*,**/.*", excludes, false );
1373 
1374         getLogger().debug( "Resolved " + fileNames.size() + " files" );
1375         getLogger().debug( "Resolved Files:" + fileNames );
1376 
1377         return fileNames;
1378     }
1379 
1380     private List<FileSet> resolveFileSets( String packageName, List<String> fileNames, List<String> languages,
1381                                            List<String> filtereds, String defaultEncoding )
1382     {
1383         List<FileSet> resolvedFileSets = new ArrayList<FileSet>();
1384         getLogger().debug(
1385             "Resolving filesets with package=" + packageName + ", languages=" + languages + " and extentions="
1386                 + filtereds );
1387 
1388         List<String> files = new ArrayList<String>( fileNames );
1389 
1390         StringBuilder languageIncludes = new StringBuilder();
1391 
1392         for ( String language : languages )
1393         {
1394             languageIncludes.append( ( ( languageIncludes.length() == 0 ) ? "" : "," ) + language + "/**" );
1395         }
1396 
1397         getLogger().debug( "Using languages includes " + languageIncludes );
1398 
1399         StringBuilder filteredIncludes = new StringBuilder();
1400         for ( String filtered : filtereds )
1401         {
1402             filteredIncludes.append(
1403                 ( ( filteredIncludes.length() == 0 ) ? "" : "," ) + "**/" + ( filtered.startsWith( "." ) ? "" : "*." )
1404                     + filtered );
1405         }
1406 
1407         getLogger().debug( "Using filtered includes " + filteredIncludes );
1408 
1409         /* sourcesMainFiles */
1410         List<String> sourcesMainFiles =
1411             archetypeFilesResolver.findSourcesMainFiles( files, languageIncludes.toString() );
1412         if ( !sourcesMainFiles.isEmpty() )
1413         {
1414             files.removeAll( sourcesMainFiles );
1415 
1416             List<String> filteredFiles =
1417                 archetypeFilesResolver.getFilteredFiles( sourcesMainFiles, filteredIncludes.toString() );
1418             sourcesMainFiles.removeAll( filteredFiles );
1419 
1420             List<String> unfilteredFiles = sourcesMainFiles;
1421             if ( !filteredFiles.isEmpty() )
1422             {
1423                 resolvedFileSets.addAll( createFileSets( filteredFiles, 3, true, packageName, true, defaultEncoding ) );
1424             }
1425 
1426             if ( !unfilteredFiles.isEmpty() )
1427             {
1428                 resolvedFileSets.addAll(
1429                     createFileSets( unfilteredFiles, 3, true, packageName, false, defaultEncoding ) );
1430             }
1431         }
1432 
1433         /* resourcesMainFiles */
1434         List<String> resourcesMainFiles =
1435             archetypeFilesResolver.findResourcesMainFiles( files, languageIncludes.toString() );
1436         if ( !resourcesMainFiles.isEmpty() )
1437         {
1438             files.removeAll( resourcesMainFiles );
1439 
1440             List<String> filteredFiles =
1441                 archetypeFilesResolver.getFilteredFiles( resourcesMainFiles, filteredIncludes.toString() );
1442             resourcesMainFiles.removeAll( filteredFiles );
1443 
1444             List<String> unfilteredFiles = resourcesMainFiles;
1445             if ( !filteredFiles.isEmpty() )
1446             {
1447                 resolvedFileSets.addAll(
1448                     createFileSets( filteredFiles, 3, false, packageName, true, defaultEncoding ) );
1449             }
1450             if ( !unfilteredFiles.isEmpty() )
1451             {
1452                 resolvedFileSets.addAll(
1453                     createFileSets( unfilteredFiles, 3, false, packageName, false, defaultEncoding ) );
1454             }
1455         }
1456 
1457         /* sourcesTestFiles */
1458         List<String> sourcesTestFiles =
1459             archetypeFilesResolver.findSourcesTestFiles( files, languageIncludes.toString() );
1460         if ( !sourcesTestFiles.isEmpty() )
1461         {
1462             files.removeAll( sourcesTestFiles );
1463 
1464             List<String> filteredFiles =
1465                 archetypeFilesResolver.getFilteredFiles( sourcesTestFiles, filteredIncludes.toString() );
1466             sourcesTestFiles.removeAll( filteredFiles );
1467 
1468             List<String> unfilteredFiles = sourcesTestFiles;
1469             if ( !filteredFiles.isEmpty() )
1470             {
1471                 resolvedFileSets.addAll( createFileSets( filteredFiles, 3, true, packageName, true, defaultEncoding ) );
1472             }
1473             if ( !unfilteredFiles.isEmpty() )
1474             {
1475                 resolvedFileSets.addAll(
1476                     createFileSets( unfilteredFiles, 3, true, packageName, false, defaultEncoding ) );
1477             }
1478         }
1479 
1480         /* ressourcesTestFiles */
1481         List<String> resourcesTestFiles =
1482             archetypeFilesResolver.findResourcesTestFiles( files, languageIncludes.toString() );
1483         if ( !resourcesTestFiles.isEmpty() )
1484         {
1485             files.removeAll( resourcesTestFiles );
1486 
1487             List<String> filteredFiles =
1488                 archetypeFilesResolver.getFilteredFiles( resourcesTestFiles, filteredIncludes.toString() );
1489             resourcesTestFiles.removeAll( filteredFiles );
1490 
1491             List<String> unfilteredFiles = resourcesTestFiles;
1492             if ( !filteredFiles.isEmpty() )
1493             {
1494                 resolvedFileSets.addAll(
1495                     createFileSets( filteredFiles, 3, false, packageName, true, defaultEncoding ) );
1496             }
1497             if ( !unfilteredFiles.isEmpty() )
1498             {
1499                 resolvedFileSets.addAll(
1500                     createFileSets( unfilteredFiles, 3, false, packageName, false, defaultEncoding ) );
1501             }
1502         }
1503 
1504         /* siteFiles */
1505         List<String> siteFiles = archetypeFilesResolver.findSiteFiles( files, languageIncludes.toString() );
1506         if ( !siteFiles.isEmpty() )
1507         {
1508             files.removeAll( siteFiles );
1509 
1510             List<String> filteredFiles =
1511                 archetypeFilesResolver.getFilteredFiles( siteFiles, filteredIncludes.toString() );
1512             siteFiles.removeAll( filteredFiles );
1513 
1514             List<String> unfilteredFiles = siteFiles;
1515             if ( !filteredFiles.isEmpty() )
1516             {
1517                 resolvedFileSets.addAll(
1518                     createFileSets( filteredFiles, 2, false, packageName, true, defaultEncoding ) );
1519             }
1520             if ( !unfilteredFiles.isEmpty() )
1521             {
1522                 resolvedFileSets.addAll(
1523                     createFileSets( unfilteredFiles, 2, false, packageName, false, defaultEncoding ) );
1524             }
1525         }
1526 
1527         /* thirdLevelSourcesfiles */
1528         List<String> thirdLevelSourcesfiles =
1529             archetypeFilesResolver.findOtherSources( 3, files, languageIncludes.toString() );
1530         if ( !thirdLevelSourcesfiles.isEmpty() )
1531         {
1532             files.removeAll( thirdLevelSourcesfiles );
1533 
1534             List<String> filteredFiles =
1535                 archetypeFilesResolver.getFilteredFiles( thirdLevelSourcesfiles, filteredIncludes.toString() );
1536             thirdLevelSourcesfiles.removeAll( filteredFiles );
1537 
1538             List<String> unfilteredFiles = thirdLevelSourcesfiles;
1539             if ( !filteredFiles.isEmpty() )
1540             {
1541                 resolvedFileSets.addAll( createFileSets( filteredFiles, 3, true, packageName, true, defaultEncoding ) );
1542             }
1543             if ( !unfilteredFiles.isEmpty() )
1544             {
1545                 resolvedFileSets.addAll(
1546                     createFileSets( unfilteredFiles, 3, true, packageName, false, defaultEncoding ) );
1547             }
1548 
1549             /* thirdLevelResourcesfiles */
1550             List<String> thirdLevelResourcesfiles =
1551                 archetypeFilesResolver.findOtherResources( 3, files, thirdLevelSourcesfiles,
1552                                                            languageIncludes.toString() );
1553             if ( !thirdLevelResourcesfiles.isEmpty() )
1554             {
1555                 files.removeAll( thirdLevelResourcesfiles );
1556                 filteredFiles =
1557                     archetypeFilesResolver.getFilteredFiles( thirdLevelResourcesfiles, filteredIncludes.toString() );
1558                 thirdLevelResourcesfiles.removeAll( filteredFiles );
1559                 unfilteredFiles = thirdLevelResourcesfiles;
1560                 if ( !filteredFiles.isEmpty() )
1561                 {
1562                     resolvedFileSets.addAll(
1563                         createFileSets( filteredFiles, 3, false, packageName, true, defaultEncoding ) );
1564                 }
1565                 if ( !unfilteredFiles.isEmpty() )
1566                 {
1567                     resolvedFileSets.addAll(
1568                         createFileSets( unfilteredFiles, 3, false, packageName, false, defaultEncoding ) );
1569                 }
1570             }
1571         } // end if
1572 
1573         /* secondLevelSourcesfiles */
1574         List<String> secondLevelSourcesfiles =
1575             archetypeFilesResolver.findOtherSources( 2, files, languageIncludes.toString() );
1576         if ( !secondLevelSourcesfiles.isEmpty() )
1577         {
1578             files.removeAll( secondLevelSourcesfiles );
1579 
1580             List<String> filteredFiles =
1581                 archetypeFilesResolver.getFilteredFiles( secondLevelSourcesfiles, filteredIncludes.toString() );
1582             secondLevelSourcesfiles.removeAll( filteredFiles );
1583 
1584             List<String> unfilteredFiles = secondLevelSourcesfiles;
1585             if ( !filteredFiles.isEmpty() )
1586             {
1587                 resolvedFileSets.addAll( createFileSets( filteredFiles, 2, true, packageName, true, defaultEncoding ) );
1588             }
1589             if ( !unfilteredFiles.isEmpty() )
1590             {
1591                 resolvedFileSets.addAll(
1592                     createFileSets( unfilteredFiles, 2, true, packageName, false, defaultEncoding ) );
1593             }
1594         }
1595 
1596         /* secondLevelResourcesfiles */
1597         List<String> secondLevelResourcesfiles =
1598             archetypeFilesResolver.findOtherResources( 2, files, languageIncludes.toString() );
1599         if ( !secondLevelResourcesfiles.isEmpty() )
1600         {
1601             files.removeAll( secondLevelResourcesfiles );
1602 
1603             List<String> filteredFiles =
1604                 archetypeFilesResolver.getFilteredFiles( secondLevelResourcesfiles, filteredIncludes.toString() );
1605             secondLevelResourcesfiles.removeAll( filteredFiles );
1606 
1607             List<String> unfilteredFiles = secondLevelResourcesfiles;
1608             if ( !filteredFiles.isEmpty() )
1609             {
1610                 resolvedFileSets.addAll(
1611                     createFileSets( filteredFiles, 2, false, packageName, true, defaultEncoding ) );
1612             }
1613             if ( !unfilteredFiles.isEmpty() )
1614             {
1615                 resolvedFileSets.addAll(
1616                     createFileSets( unfilteredFiles, 2, false, packageName, false, defaultEncoding ) );
1617             }
1618         }
1619 
1620         /* rootResourcesfiles */
1621         List<String> rootResourcesfiles =
1622             archetypeFilesResolver.findOtherResources( 0, files, languageIncludes.toString() );
1623         if ( !rootResourcesfiles.isEmpty() )
1624         {
1625             files.removeAll( rootResourcesfiles );
1626 
1627             List<String> filteredFiles =
1628                 archetypeFilesResolver.getFilteredFiles( rootResourcesfiles, filteredIncludes.toString() );
1629             rootResourcesfiles.removeAll( filteredFiles );
1630 
1631             List<String> unfilteredFiles = rootResourcesfiles;
1632             if ( !filteredFiles.isEmpty() )
1633             {
1634                 resolvedFileSets.addAll(
1635                     createFileSets( filteredFiles, 0, false, packageName, true, defaultEncoding ) );
1636             }
1637             if ( !unfilteredFiles.isEmpty() )
1638             {
1639                 resolvedFileSets.addAll(
1640                     createFileSets( unfilteredFiles, 0, false, packageName, false, defaultEncoding ) );
1641             }
1642         }
1643 
1644         /**/
1645         if ( !files.isEmpty() )
1646         {
1647             getLogger().info( "Ignored files: " + files );
1648         }
1649 
1650         return resolvedFileSets;
1651     }
1652 
1653     private void restoreArtifactId( Properties properties, String artifactId )
1654     {
1655         if ( StringUtils.isEmpty( artifactId ) )
1656         {
1657             properties.remove( Constants.ARTIFACT_ID );
1658         }
1659         else
1660         {
1661             properties.setProperty( Constants.ARTIFACT_ID, artifactId );
1662         }
1663     }
1664 
1665     private void restoreParentArtifactId( Properties properties, String parentArtifactId )
1666     {
1667         if ( StringUtils.isEmpty( parentArtifactId ) )
1668         {
1669             properties.remove( Constants.PARENT_ARTIFACT_ID );
1670         }
1671         else
1672         {
1673             properties.setProperty( Constants.PARENT_ARTIFACT_ID, parentArtifactId );
1674         }
1675     }
1676 
1677     private String getReversedContent( String content, Properties properties )
1678     {
1679         String result =
1680             StringUtils.replace( StringUtils.replace( content, "$", "${symbol_dollar}" ), "\\", "${symbol_escape}" );
1681         result = getReversedPlainContent( result, properties );
1682 
1683         // TODO: Replace velocity to a better engine...
1684         return "#set( $symbol_pound = '#' )\n" + "#set( $symbol_dollar = '$' )\n" + "#set( $symbol_escape = '\\' )\n"
1685             + StringUtils.replace( result, "#", "${symbol_pound}" );
1686     }
1687 
1688     private String getReversedPlainContent( String content, Properties properties )
1689     {
1690         String result = content;
1691 
1692         for ( Iterator<?> propertyIterator = properties.keySet().iterator(); propertyIterator.hasNext(); )
1693         {
1694             String propertyKey = (String) propertyIterator.next();
1695 
1696             result = StringUtils.replace( result, properties.getProperty( propertyKey ), "${" + propertyKey + "}" );
1697         }
1698         return result;
1699     }
1700 
1701     private String getReversedFilename( String filename, Properties properties )
1702     {
1703         String result = filename;
1704 
1705         for ( Iterator<?> propertyIterator = properties.keySet().iterator(); propertyIterator.hasNext(); )
1706         {
1707             String propertyKey = (String) propertyIterator.next();
1708 
1709             result = StringUtils.replace( result, properties.getProperty( propertyKey ), "__" + propertyKey + "__" );
1710         }
1711 
1712         return result;
1713     }
1714 
1715     private String getTemplateOutputDirectory()
1716     {
1717         return Constants.SRC + File.separator + Constants.MAIN + File.separator + Constants.RESOURCES;
1718     }
1719 
1720     private FileSet getUnpackagedFileSet( final boolean filtered, final String group, final List<String> groupFiles,
1721                                           String defaultEncoding )
1722     {
1723         Set<String> extensions = getExtensions( groupFiles );
1724 
1725         List<String> includes = new ArrayList<String>();
1726         List<String> excludes = new ArrayList<String>();
1727 
1728         for ( String extension : extensions )
1729         {
1730             includes.add( "**/*." + extension );
1731         }
1732 
1733         return createFileSet( excludes, false, filtered, group, includes, defaultEncoding );
1734     }
1735 
1736     private FileSet getUnpackagedFileSet( final boolean filtered, final Set<String> unpackagedExtensions,
1737                                           final List<String> unpackagedFiles, final String group,
1738                                           final Set<String> packagedExtensions, String defaultEncoding )
1739     {
1740         List<String> includes = new ArrayList<String>();
1741         List<String> excludes = new ArrayList<String>();
1742 
1743         for ( String extension : unpackagedExtensions )
1744         {
1745             if ( packagedExtensions.contains( extension ) )
1746             {
1747                 includes.addAll( archetypeFilesResolver.getFilesWithExtension( unpackagedFiles, extension ) );
1748             }
1749             else
1750             {
1751                 includes.add( "**/*." + extension );
1752             }
1753         }
1754 
1755         return createFileSet( excludes, false, filtered, group, includes, defaultEncoding );
1756     }
1757 
1758     private static final String MAVEN_PROPERTIES =
1759         "META-INF/maven/org.apache.maven.archetype/archetype-common/pom.properties";
1760 
1761     public String getArchetypeVersion()
1762     {
1763         InputStream is = null;
1764 
1765         // This should actually come from the pom.properties at testing but it's not generated and put into the JAR, it
1766         // happens as part of the JAR plugin which is crap as it makes testing inconsistent.
1767         String version = "version";
1768 
1769         try
1770         {
1771             Properties properties = new Properties();
1772 
1773             is = getClass().getClassLoader().getResourceAsStream( MAVEN_PROPERTIES );
1774 
1775             if ( is != null )
1776             {
1777                 properties.load( is );
1778 
1779                 String property = properties.getProperty( "version" );
1780 
1781                 if ( property != null )
1782                 {
1783                     return property;
1784                 }
1785             }
1786 
1787             return version;
1788         }
1789         catch ( IOException e )
1790         {
1791             return version;
1792         }
1793         finally
1794         {
1795             IOUtil.close( is );
1796         }
1797     }
1798 }