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