]> source.dussan.org Git - archiva.git/blob
219b6691efaa862d60eaf297c7973dfb70d19e00
[archiva.git] /
1 package org.apache.maven.archiva.indexer.record;
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.archiva.indexer.RepositoryIndexException;
23 import org.apache.maven.artifact.Artifact;
24 import org.apache.maven.artifact.InvalidArtifactRTException;
25 import org.apache.maven.artifact.factory.ArtifactFactory;
26 import org.apache.maven.artifact.repository.ArtifactRepository;
27 import org.apache.maven.model.Dependency;
28 import org.apache.maven.model.Developer;
29 import org.apache.maven.model.Model;
30 import org.apache.maven.project.MavenProject;
31 import org.apache.maven.project.MavenProjectBuilder;
32 import org.apache.maven.project.ProjectBuildingException;
33 import org.codehaus.plexus.digest.Digester;
34 import org.codehaus.plexus.util.xml.Xpp3Dom;
35 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
36 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
37
38 import java.io.File;
39 import java.io.IOException;
40 import java.io.InputStreamReader;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collections;
44 import java.util.HashSet;
45 import java.util.Iterator;
46 import java.util.List;
47 import java.util.Set;
48 import java.util.zip.ZipEntry;
49 import java.util.zip.ZipException;
50 import java.util.zip.ZipFile;
51
52 /**
53  * An index record type for the standard index.
54  *
55  * @author Edwin Punzalan
56  * @author Brett Porter
57  * @plexus.component role="org.apache.maven.archiva.indexer.record.RepositoryIndexRecordFactory" role-hint="standard"
58  */
59 public class StandardArtifactIndexRecordFactory
60     extends AbstractArtifactIndexRecordFactory
61 {
62     /**
63      * A list of artifact types to treat as a zip archive.
64      *
65      * @todo this should be smarter (perhaps use plexus archiver to look for an unarchiver, and make the ones for zip configurable since sar, par, etc can be added at random.
66      */
67     private static final Set ARCHIVE_TYPES =
68         new HashSet( Arrays.asList( new String[]{"jar", "ejb", "par", "sar", "war", "ear", "rar"} ) );
69
70     /**
71      * @plexus.requirement
72      */
73     private ArtifactFactory artifactFactory;
74
75     /**
76      * @plexus.requirement
77      */
78     private MavenProjectBuilder projectBuilder;
79
80     /**
81      * @plexus.requirement role-hint="sha1"
82      */
83     protected Digester sha1Digester;
84
85     /**
86      * @plexus.requirement role-hint="md5"
87      */
88     protected Digester md5Digester;
89
90     private static final String SITE_TEMPLATE_NAME = "META-INF/maven/site.vm";
91
92     private static final String SITE_CSS_NAME = "css/maven-theme.css";
93
94     private static final String PLUGIN_METADATA_NAME = "META-INF/maven/plugin.xml";
95
96     private static final String ARCHETYPE_METADATA_NAME = "META-INF/maven/archetype.xml";
97
98     // some current/old archetypes have the archetype.xml at different location.
99     private static final String ARCHETYPE_METADATA_NAME_OLD = "META-INF/archetype.xml";
100
101     public RepositoryIndexRecord createRecord( Artifact artifact )
102         throws RepositoryIndexException
103     {
104         StandardArtifactIndexRecord record = null;
105
106         File file = artifact.getFile();
107
108         // TODO: is this condition really a possibility?
109         if ( file != null && file.exists() )
110         {
111             String md5 = readChecksum( file, md5Digester );
112             String sha1 = readChecksum( file, sha1Digester );
113
114             List files = null;
115             boolean archive = ARCHIVE_TYPES.contains( artifact.getType() );
116             try
117             {
118                 if ( archive )
119                 {
120                     files = readFilesInArchive( file );
121                 }
122             }
123             catch ( IOException e )
124             {
125                 getLogger().error( "Error reading artifact file, omitting from index: " + e.getMessage() );
126             }
127
128             // If it's an archive with no files, don't create a record
129             if ( !archive || files != null )
130             {
131                 record = new StandardArtifactIndexRecord();
132
133                 record.setGroupId( artifact.getGroupId() );
134                 record.setArtifactId( artifact.getArtifactId() );
135                 record.setBaseVersion( artifact.getBaseVersion() );
136                 record.setVersion( artifact.getVersion() );
137                 record.setClassifier( artifact.getClassifier() );
138                 record.setType( artifact.getType() );
139                 record.setMd5Checksum( md5 );
140                 record.setSha1Checksum( sha1 );
141                 record.setFilename( artifact.getRepository().pathOf( artifact ) );
142                 record.setLastModified( file.lastModified() );
143                 record.setSize( file.length() );
144                 record.setRepository( artifact.getRepository().getId() );
145
146                 if ( files != null )
147                 {
148                     populateArchiveEntries( files, record, artifact.getFile() );
149                 }
150
151                 if ( !"pom".equals( artifact.getType() ) )
152                 {
153                     Artifact pomArtifact = artifactFactory.createProjectArtifact( artifact.getGroupId(),
154                                                                                   artifact.getArtifactId(),
155                                                                                   artifact.getVersion() );
156                     pomArtifact.isSnapshot(); // gross hack around bug in maven-artifact
157                     File pomFile = new File( artifact.getRepository().getBasedir(),
158                                              artifact.getRepository().pathOf( pomArtifact ) );
159                     if ( pomFile.exists() )
160                     {
161                         try
162                         {
163                             populatePomEntries( readPom( pomArtifact, artifact.getRepository() ), record );
164                         }
165                         catch ( ProjectBuildingException e )
166                         {
167                             getLogger().error( "Error reading POM file [" + pomFile + "] for " + artifact +
168                                 ", not populating in index: " + e.getMessage() );
169                         }
170                     }
171                 }
172                 else
173                 {
174                     Model model;
175                     try
176                     {
177                         model = readPom( artifact, artifact.getRepository() );
178
179                         if ( !"pom".equals( model.getPackaging() ) )
180                         {
181                             // Don't return a record for a POM that is does not belong on its own
182                             record = null;
183                         }
184                         else
185                         {
186                             populatePomEntries( model, record );
187                         }
188                     }
189                     catch ( ProjectBuildingException e )
190                     {
191                         getLogger().error(
192                             "Error reading POM file for " + artifact + ", not populating in index: " + e.getMessage() );
193                     }
194                 }
195             }
196         }
197
198         return record;
199     }
200
201     private void populatePomEntries( Model pom, StandardArtifactIndexRecord record )
202     {
203         record.setPackaging( pom.getPackaging() );
204         record.setProjectName( pom.getName() );
205         record.setProjectDescription( pom.getDescription() );
206         record.setInceptionYear( pom.getInceptionYear() );
207
208         List dependencies = populateDependencies( pom.getDependencies() );
209         if ( !dependencies.isEmpty() )
210         {
211             record.setDependencies( dependencies );
212         }
213         List developers = populateDevelopers( pom.getDevelopers() );
214         if ( !developers.isEmpty() )
215         {
216             record.setDevelopers( developers );
217         }
218
219 /* TODO: fields for later
220                 indexPlugins( doc, FLD_PLUGINS_BUILD, pom.getBuild().getPlugins().iterator() );
221                 indexReportPlugins( doc, FLD_PLUGINS_REPORT, pom.getReporting().getPlugins().iterator() );
222                 record.setLicenses( licenses );
223 */
224     }
225
226     private List populateDependencies( List dependencies )
227     {
228         List convertedDependencies = new ArrayList();
229
230         for ( Iterator i = dependencies.iterator(); i.hasNext(); )
231         {
232             Dependency dependency = (Dependency) i.next();
233
234             convertedDependencies.add(
235                 dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion() );
236         }
237
238         return convertedDependencies;
239     }
240
241     private List populateDevelopers( List developers )
242     {
243         List convertedDevelopers = new ArrayList();
244
245         for ( Iterator i = developers.iterator(); i.hasNext(); )
246         {
247             Developer developer = (Developer) i.next();
248
249             convertedDevelopers.add( developer.getId() + ":" + developer.getName() + ":" + developer.getEmail() );
250         }
251
252         return convertedDevelopers;
253     }
254
255     private Model readPom( Artifact artifact, ArtifactRepository repository )
256         throws RepositoryIndexException, ProjectBuildingException
257     {
258         // TODO: this can create a -SNAPSHOT.pom when it didn't exist and a timestamped one did. This is harmless, but should be avoided
259         // TODO: will this pollute with local repo metadata?
260
261         try
262         {
263             MavenProject project = projectBuilder.buildFromRepository( artifact, Collections.EMPTY_LIST, repository );
264             return project.getModel();
265         }
266         catch ( InvalidArtifactRTException e )
267         {
268             throw new ProjectBuildingException( artifact.getId(),
269                                                 "Unable to build project from invalid artifact [" + artifact + "]", e );
270         }
271     }
272
273     private void populateArchiveEntries( List files, StandardArtifactIndexRecord record, File artifactFile )
274         throws RepositoryIndexException
275     {
276         List classes = new ArrayList();
277         List fileList = new ArrayList();
278
279         for ( Iterator i = files.iterator(); i.hasNext(); )
280         {
281             String name = (String) i.next();
282
283             // ignore directories
284             if ( !name.endsWith( "/" ) )
285             {
286                 fileList.add( name );
287
288                 if ( isClass( name ) )
289                 {
290                     classes.add( name.substring( 0, name.length() - 6 ).replace( '/', '.' ) );
291                 }
292                 else if ( PLUGIN_METADATA_NAME.equals( name ) )
293                 {
294                     populatePluginEntries( readXmlMetadataFileInJar( artifactFile, PLUGIN_METADATA_NAME ), record );
295                 }
296                 else if ( ARCHETYPE_METADATA_NAME.equals( name ) || ARCHETYPE_METADATA_NAME_OLD.equals( name ) )
297                 {
298                     populateArchetypeEntries( record );
299                 }
300                 else if ( SITE_TEMPLATE_NAME.equals( name ) || SITE_CSS_NAME.equals( name ) )
301                 {
302                     populateSkinEntries( record );
303                 }
304             }
305         }
306
307         if ( !classes.isEmpty() )
308         {
309             record.setClasses( classes );
310         }
311         if ( !fileList.isEmpty() )
312         {
313             record.setFiles( fileList );
314         }
315     }
316
317     private void populateArchetypeEntries( StandardArtifactIndexRecord record )
318     {
319         // Typically discovered as a JAR
320         record.setType( "maven-archetype" );
321     }
322
323     private void populateSkinEntries( StandardArtifactIndexRecord record )
324     {
325         // Typically discovered as a JAR
326         record.setType( "maven-skin" );
327     }
328
329     private Xpp3Dom readXmlMetadataFileInJar( File file, String name )
330         throws RepositoryIndexException
331     {
332         // TODO: would be more efficient with original ZipEntry still around
333
334         Xpp3Dom xpp3Dom;
335         ZipFile zipFile = null;
336         try
337         {
338             zipFile = new ZipFile( file );
339             ZipEntry entry = zipFile.getEntry( name );
340             xpp3Dom = Xpp3DomBuilder.build( new InputStreamReader( zipFile.getInputStream( entry ) ) );
341         }
342         catch ( ZipException e )
343         {
344             throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
345         }
346         catch ( IOException e )
347         {
348             throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
349         }
350         catch ( XmlPullParserException e )
351         {
352             throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
353         }
354         finally
355         {
356             closeQuietly( zipFile );
357         }
358         return xpp3Dom;
359     }
360
361     public void populatePluginEntries( Xpp3Dom metadata, StandardArtifactIndexRecord record )
362     {
363         // Typically discovered as a JAR
364         record.setType( "maven-plugin" );
365
366         Xpp3Dom prefix = metadata.getChild( "goalPrefix" );
367
368         if ( prefix != null )
369         {
370             record.setPluginPrefix( prefix.getValue() );
371         }
372     }
373 }