View Javadoc
1   package org.apache.maven.archetype.common;
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.commons.io.IOUtils;
23  import org.apache.maven.archetype.downloader.DownloadException;
24  import org.apache.maven.archetype.downloader.DownloadNotFoundException;
25  import org.apache.maven.archetype.downloader.Downloader;
26  import org.apache.maven.archetype.exception.UnknownArchetype;
27  import org.apache.maven.archetype.metadata.ArchetypeDescriptor;
28  import org.apache.maven.archetype.metadata.io.xpp3.ArchetypeDescriptorXpp3Reader;
29  import org.apache.maven.archetype.old.descriptor.ArchetypeDescriptorBuilder;
30  import org.apache.maven.artifact.repository.ArtifactRepository;
31  import org.apache.maven.model.Model;
32  import org.apache.maven.project.ProjectBuildingRequest;
33  import org.codehaus.plexus.component.annotations.Component;
34  import org.codehaus.plexus.component.annotations.Requirement;
35  import org.codehaus.plexus.logging.AbstractLogEnabled;
36  import org.codehaus.plexus.util.IOUtil;
37  import org.codehaus.plexus.util.ReaderFactory;
38  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
39  
40  import java.io.File;
41  import java.io.IOException;
42  import java.io.InputStream;
43  import java.io.Reader;
44  
45  import java.net.MalformedURLException;
46  import java.net.URL;
47  import java.net.URLClassLoader;
48  
49  import java.util.ArrayList;
50  import java.util.Enumeration;
51  import java.util.List;
52  import java.util.Map;
53  import java.util.TreeMap;
54  import java.util.zip.ZipEntry;
55  import java.util.zip.ZipException;
56  import java.util.zip.ZipFile;
57  
58  @Component( role = ArchetypeArtifactManager.class )
59  public class DefaultArchetypeArtifactManager
60      extends AbstractLogEnabled
61      implements ArchetypeArtifactManager
62  {
63      @Requirement
64      private Downloader downloader;
65  
66      @Requirement
67      private PomManager pomManager;
68  
69      private Map<String, File> archetypeCache = new TreeMap<String, File>();
70  
71      public File getArchetypeFile( final String groupId, final String artifactId, final String version,
72                                    ArtifactRepository archetypeRepository, final ArtifactRepository localRepository,
73                                    final List<ArtifactRepository> repositories, ProjectBuildingRequest buildingRequest )
74          throws UnknownArchetype
75      {
76          try
77          {
78              File archetype = getArchetype( groupId, artifactId, version );
79  
80              if ( archetype == null )
81              {
82                  archetype =
83                      downloader.download( groupId, artifactId, version, archetypeRepository, localRepository,
84                                           repositories, buildingRequest );
85  
86                  setArchetype( groupId, artifactId, version, archetype );
87              }
88              return archetype;
89          }
90          catch ( DownloadNotFoundException ex )
91          {
92              throw new UnknownArchetype( ex );
93          }
94          catch ( DownloadException ex )
95          {
96              throw new UnknownArchetype( ex );
97          }
98      }
99  
100     public ClassLoader getArchetypeJarLoader( File archetypeFile )
101         throws UnknownArchetype
102     {
103         try
104         {
105             URL[] urls = new URL[1];
106 
107             urls[0] = archetypeFile.toURI().toURL();
108 
109             return new URLClassLoader( urls );
110         }
111         catch ( MalformedURLException e )
112         {
113             throw new UnknownArchetype( e );
114         }
115     }
116 
117     public Model getArchetypePom( File jar )
118         throws XmlPullParserException, UnknownArchetype, IOException
119     {
120         ZipFile zipFile = null;
121         try
122         {
123             String pomFileName = null;
124             zipFile = getArchetypeZipFile( jar );
125 
126             Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
127             while ( enumeration.hasMoreElements() )
128             {
129                 ZipEntry el = (ZipEntry) enumeration.nextElement();
130 
131                 String entry = el.getName();
132                 if ( entry.startsWith( "META-INF" ) && entry.endsWith( "pom.xml" ) )
133                 {
134                     pomFileName = entry;
135                 }
136             }
137 
138             if ( pomFileName == null )
139             {
140                 return null;
141             }
142 
143             ZipEntry pom = zipFile.getEntry( pomFileName );
144 
145             if ( pom == null )
146             {
147                 return null;
148             }
149             return pomManager.readPom( zipFile.getInputStream( pom ) );
150         }
151         finally
152         {
153             closeZipFile( zipFile );
154         }
155     }
156 
157     public ZipFile getArchetypeZipFile( File archetypeFile )
158         throws UnknownArchetype
159     {
160         try
161         {
162             return new ZipFile( archetypeFile );
163         }
164         catch ( ZipException e )
165         {
166             throw new UnknownArchetype( e );
167         }
168         catch ( IOException e )
169         {
170             throw new UnknownArchetype( e );
171         }
172     }
173 
174     public boolean isFileSetArchetype( File archetypeFile )
175     {
176         ZipFile zipFile = null;
177         try
178         {
179             getLogger().debug( "checking fileset archetype status on " + archetypeFile );
180 
181             zipFile = getArchetypeZipFile( archetypeFile );
182 
183             return isFileSetArchetype( zipFile );
184         }
185         catch ( IOException e )
186         {
187             getLogger().debug( e.toString() );
188             return false;
189         }
190         catch ( UnknownArchetype e )
191         {
192             getLogger().debug( e.toString() );
193             return false;
194         }
195         finally
196         {
197             if ( zipFile != null )
198             {
199                 closeZipFile( zipFile );
200             }
201         }
202     }
203 
204     public boolean isFileSetArchetype( String groupId, String artifactId, String version,
205                                        ArtifactRepository archetypeRepository, ArtifactRepository localRepository,
206                                        List<ArtifactRepository> repositories, ProjectBuildingRequest buildingRequest )
207     {
208         try
209         {
210             File archetypeFile = getArchetypeFile( groupId, artifactId, version, archetypeRepository,
211                                                    localRepository, repositories, buildingRequest );
212 
213             return isFileSetArchetype( archetypeFile );
214         }
215         catch ( UnknownArchetype e )
216         {
217             getLogger().debug( e.toString() );
218             return false;
219         }
220     }
221 
222     public boolean isOldArchetype( File archetypeFile )
223     {
224         ZipFile zipFile = null;
225         try
226         {
227             getLogger().debug( "checking old archetype status on " + archetypeFile );
228 
229             zipFile = getArchetypeZipFile( archetypeFile );
230 
231             return isOldArchetype( zipFile );
232         }
233         catch ( IOException e )
234         {
235             getLogger().debug( e.toString() );
236             return false;
237         }
238         catch ( UnknownArchetype e )
239         {
240             getLogger().debug( e.toString() );
241             return false;
242         }
243         finally
244         {
245             if ( zipFile != null )
246             {
247                 closeZipFile( zipFile );
248             }
249         }
250     }
251 
252     public boolean isOldArchetype( String groupId, String artifactId, String version,
253                                    ArtifactRepository archetypeRepository, ArtifactRepository localRepository,
254                                    List<ArtifactRepository> repositories, ProjectBuildingRequest buildingRequest )
255     {
256         try
257         {
258             File archetypeFile = getArchetypeFile( groupId, artifactId, version, archetypeRepository,
259                                                    localRepository, repositories, buildingRequest );
260 
261             return isOldArchetype( archetypeFile );
262         }
263         catch ( UnknownArchetype e )
264         {
265             getLogger().debug( e.toString() );
266             return false;
267         }
268     }
269 
270     public boolean exists( String archetypeGroupId, String archetypeArtifactId, String archetypeVersion,
271                            ArtifactRepository archetypeRepository, ArtifactRepository localRepository,
272                            List<ArtifactRepository> remoteRepositories, ProjectBuildingRequest buildingRequest )
273     {
274         try
275         {
276             File archetype = getArchetype( archetypeGroupId, archetypeArtifactId, archetypeVersion );
277             if ( archetype == null )
278             {
279                 archetype =
280                     downloader.download( archetypeGroupId, archetypeArtifactId, archetypeVersion, archetypeRepository,
281                                          localRepository, remoteRepositories, buildingRequest );
282                 setArchetype( archetypeGroupId, archetypeArtifactId, archetypeVersion, archetype );
283             }
284 
285             return archetype.exists();
286         }
287         catch ( DownloadException e )
288         {
289             getLogger().debug(
290                                "Archetype " + archetypeGroupId + ":" + archetypeArtifactId + ":" + archetypeVersion
291                                    + " doesn't exist", e );
292             return false;
293         }
294         catch ( DownloadNotFoundException e )
295         {
296             getLogger().debug(
297                               "Archetype " + archetypeGroupId + ":" + archetypeArtifactId + ":" + archetypeVersion
298                                   + " doesn't exist", e );
299             return false;
300         }
301     }
302 
303     public String getPostGenerationScript( File archetypeFile ) throws UnknownArchetype
304     {
305         ZipFile zipFile = null;
306         try
307         {
308             zipFile = getArchetypeZipFile( archetypeFile );
309             Reader reader = getDescriptorReader( zipFile, Constants.ARCHETYPE_POST_GENERATION_SCRIPT );
310             return reader == null ? null : IOUtils.toString( reader );
311         }
312         catch ( IOException e )
313         {
314             throw new UnknownArchetype( e );
315         }
316         finally
317         {
318             closeZipFile( zipFile );
319         }
320     }
321 
322     public ArchetypeDescriptor getFileSetArchetypeDescriptor( File archetypeFile )
323         throws UnknownArchetype
324     {
325         ZipFile zipFile = null;
326         try
327         {
328             zipFile = getArchetypeZipFile( archetypeFile );
329 
330             return loadFileSetArchetypeDescriptor( zipFile );
331         }
332         catch ( XmlPullParserException e )
333         {
334             throw new UnknownArchetype( e );
335         }
336         catch ( IOException e )
337         {
338             throw new UnknownArchetype( e );
339         }
340         finally
341         {
342             closeZipFile( zipFile );
343         }
344     }
345 
346     public org.apache.maven.archetype.metadata.ArchetypeDescriptor getFileSetArchetypeDescriptor( String groupId,
347                                                                           String artifactId,
348                                                                           String version,
349                                                                           ArtifactRepository archetypeRepository,
350                                                                           ArtifactRepository localRepository,
351                                                                           List<ArtifactRepository> repositories,
352                                                                           ProjectBuildingRequest buildingRequest )
353         throws UnknownArchetype
354     {
355         File archetypeFile = getArchetypeFile( groupId, artifactId, version, archetypeRepository, localRepository,
356                                                repositories, buildingRequest );
357 
358         return getFileSetArchetypeDescriptor( archetypeFile );
359     }
360 
361     public List<String> getFilesetArchetypeResources( File archetypeFile )
362         throws UnknownArchetype
363     {
364         getLogger().debug( "getFilesetArchetypeResources( \"" + archetypeFile.getAbsolutePath() + "\" )" );
365         List<String> archetypeResources = new ArrayList<String>();
366 
367         ZipFile zipFile = null;
368         try
369         {
370             zipFile = getArchetypeZipFile( archetypeFile );
371 
372             Enumeration<? extends ZipEntry> enumeration = zipFile.entries();
373             while ( enumeration.hasMoreElements() )
374             {
375                 ZipEntry entry = (ZipEntry) enumeration.nextElement();
376 
377                 if ( entry.getName().startsWith( Constants.ARCHETYPE_RESOURCES ) )
378                 {
379                     // not supposed to be file.separator
380                     String resource = entry.getName().substring( Constants.ARCHETYPE_RESOURCES.length() + 1 );
381                     getLogger().debug( "  - found resource (" + Constants.ARCHETYPE_RESOURCES + "/)" + resource );
382                     // TODO:FIXME
383                     archetypeResources.add( resource );
384                 }
385                 else
386                 {
387                     getLogger().debug( "  - ignored resource " + entry.getName() );
388                 }
389             }
390             return archetypeResources;
391         }
392         finally
393         {
394             closeZipFile( zipFile );
395         }
396     }
397 
398     public org.apache.maven.archetype.old.descriptor.ArchetypeDescriptor getOldArchetypeDescriptor( File archetypeFile )
399         throws UnknownArchetype
400     {
401         ZipFile zipFile = null;
402         try
403         {
404             zipFile = getArchetypeZipFile( archetypeFile );
405 
406             return loadOldArchetypeDescriptor( zipFile );
407         }
408         catch ( XmlPullParserException e )
409         {
410             throw new UnknownArchetype( e );
411         }
412         catch ( IOException e )
413         {
414             throw new UnknownArchetype( e );
415         }
416         finally
417         {
418             closeZipFile( zipFile );
419         }
420     }
421 
422     public org.apache.maven.archetype.old.descriptor.ArchetypeDescriptor getOldArchetypeDescriptor( String groupId,
423                                                                             String artifactId,
424                                                                             String version,
425                                                                             ArtifactRepository archetypeRepository,
426                                                                             ArtifactRepository localRepository,
427                                                                             List<ArtifactRepository> repositories,
428                                                                             ProjectBuildingRequest buildingRequest )
429         throws UnknownArchetype
430     {
431         File archetypeFile = getArchetypeFile( groupId, artifactId, version, archetypeRepository, localRepository,
432                                                repositories, buildingRequest );
433 
434         return getOldArchetypeDescriptor( archetypeFile );
435     }
436 
437     private File getArchetype( String archetypeGroupId, String archetypeArtifactId, String archetypeVersion )
438     {
439         String key = archetypeGroupId + ":" + archetypeArtifactId + ":" + archetypeVersion;
440 
441         if ( archetypeCache.containsKey( key ) )
442         {
443             getLogger().debug( "Found archetype " + key + " in cache: " + archetypeCache.get( key ) );
444 
445             return archetypeCache.get( key );
446         }
447 
448         getLogger().debug( "Not found archetype " + key + " in cache" );
449         return null;
450     }
451 
452     private void setArchetype( String archetypeGroupId, String archetypeArtifactId, String archetypeVersion,
453                                File archetype )
454     {
455         String key = archetypeGroupId + ":" + archetypeArtifactId + ":" + archetypeVersion;
456 
457         archetypeCache.put( key, archetype );
458     }
459 
460     private boolean isFileSetArchetype( ZipFile zipFile )
461         throws IOException
462     {
463         Reader reader = null;
464         try
465         {
466             reader = getArchetypeDescriptorReader( zipFile );
467 
468             return ( reader != null );
469         }
470         finally
471         {
472             IOUtil.close( reader );
473         }
474     }
475 
476     private boolean isOldArchetype( ZipFile zipFile )
477         throws IOException
478     {
479         Reader reader = null;
480         try
481         {
482             reader = getOldArchetypeDescriptorReader( zipFile );
483 
484             return ( reader != null );
485         }
486         finally
487         {
488             IOUtil.close( reader );
489         }
490     }
491 
492     private org.apache.maven.archetype.metadata.ArchetypeDescriptor loadFileSetArchetypeDescriptor( ZipFile zipFile )
493         throws IOException, XmlPullParserException
494     {
495         Reader reader = null;
496         try
497         {
498             reader = getArchetypeDescriptorReader( zipFile );
499 
500             if ( reader == null )
501             {
502                 return null;
503             }
504 
505             ArchetypeDescriptorXpp3Reader archetypeReader = new ArchetypeDescriptorXpp3Reader();
506             return archetypeReader.read( reader, false );
507         }
508         catch ( IOException e )
509         {
510             throw e;
511         }
512         catch ( XmlPullParserException e )
513         {
514             throw e;
515         }
516         finally
517         {
518             IOUtil.close( reader );
519         }
520     }
521 
522     private org.apache.maven.archetype.old.descriptor.ArchetypeDescriptor loadOldArchetypeDescriptor( ZipFile zipFile )
523         throws IOException, XmlPullParserException
524     {
525         Reader reader = null;
526         try
527         {
528             reader = getOldArchetypeDescriptorReader( zipFile );
529 
530             if ( reader == null )
531             {
532                 return null;
533             }
534 
535             ArchetypeDescriptorBuilder builder = new ArchetypeDescriptorBuilder();
536             return builder.build( reader );
537         }
538         catch ( IOException ex )
539         {
540             throw ex;
541         }
542         catch ( XmlPullParserException ex )
543         {
544             throw ex;
545         }
546         finally
547         {
548             IOUtil.close( reader );
549         }
550     }
551 
552     private Reader getArchetypeDescriptorReader( ZipFile zipFile )
553         throws IOException
554     {
555         return getDescriptorReader( zipFile, Constants.ARCHETYPE_DESCRIPTOR );
556     }
557 
558     private Reader getOldArchetypeDescriptorReader( ZipFile zipFile )
559         throws IOException
560     {
561         Reader reader = getDescriptorReader( zipFile, Constants.OLD_ARCHETYPE_DESCRIPTOR );
562 
563         if ( reader == null )
564         {
565             reader = getDescriptorReader( zipFile, Constants.OLDER_ARCHETYPE_DESCRIPTOR );
566         }
567 
568         return reader;
569     }
570 
571     private Reader getDescriptorReader( ZipFile zipFile, String descriptor )
572         throws IOException
573     {
574         ZipEntry entry = searchEntry( zipFile, descriptor );
575 
576         if ( entry == null )
577         {
578             return null;
579         }
580 
581         InputStream is = zipFile.getInputStream( entry );
582 
583         if ( is == null )
584         {
585             throw new IOException( "The " + descriptor + " descriptor cannot be read in " + zipFile.getName() + "." );
586         }
587 
588         return ReaderFactory.newReader( is, ReaderFactory.UTF_8 );
589     }
590 
591     private ZipEntry searchEntry( ZipFile zipFile, String searchString )
592     {
593         getLogger().debug( "Searching for " + searchString + " inside " + zipFile.getName() );
594 
595         Enumeration<? extends ZipEntry> enu = zipFile.entries();
596         while ( enu.hasMoreElements() )
597         {
598             ZipEntry entryfound = (ZipEntry) enu.nextElement();
599             getLogger().debug( "  - " + entryfound.getName() );
600 
601             if ( searchString.equals( entryfound.getName() ) )
602             {
603                 getLogger().debug( "Entry found" );
604                 return entryfound;
605             }
606         }
607         return null;
608     }
609 
610     private void closeZipFile( ZipFile zipFile )
611     {
612         try
613         {
614             zipFile.close();
615         }
616         catch ( Exception e )
617         {
618             getLogger().error( "Failed to close " + zipFile.getName() + " zipFile." );
619         }
620     }
621 }