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