1 package org.apache.maven.archiva.indexer.record;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
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;
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;
48 import java.util.zip.ZipEntry;
49 import java.util.zip.ZipException;
50 import java.util.zip.ZipFile;
53 * An index record type for the standard index.
55 * @author Edwin Punzalan
56 * @author Brett Porter
57 * @plexus.component role="org.apache.maven.archiva.indexer.record.RepositoryIndexRecordFactory" role-hint="standard"
59 public class StandardArtifactIndexRecordFactory
60 extends AbstractArtifactIndexRecordFactory
63 * A list of artifact types to treat as a zip archive.
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.
67 private static final Set ARCHIVE_TYPES =
68 new HashSet( Arrays.asList( new String[]{"jar", "ejb", "par", "sar", "war", "ear", "rar"} ) );
73 private ArtifactFactory artifactFactory;
78 private MavenProjectBuilder projectBuilder;
81 * @plexus.requirement role-hint="sha1"
83 protected Digester sha1Digester;
86 * @plexus.requirement role-hint="md5"
88 protected Digester md5Digester;
90 private static final String SITE_TEMPLATE_NAME = "META-INF/maven/site.vm";
92 private static final String SITE_CSS_NAME = "css/maven-theme.css";
94 private static final String PLUGIN_METADATA_NAME = "META-INF/maven/plugin.xml";
96 private static final String ARCHETYPE_METADATA_NAME = "META-INF/maven/archetype.xml";
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";
101 public RepositoryIndexRecord createRecord( Artifact artifact )
102 throws RepositoryIndexException
104 StandardArtifactIndexRecord record = null;
106 File file = artifact.getFile();
108 // TODO: is this condition really a possibility?
109 if ( file != null && file.exists() )
111 String md5 = readChecksum( file, md5Digester );
112 String sha1 = readChecksum( file, sha1Digester );
115 boolean archive = ARCHIVE_TYPES.contains( artifact.getType() );
120 files = readFilesInArchive( file );
123 catch ( IOException e )
125 getLogger().error( "Error reading artifact file, omitting from index: " + e.getMessage() );
128 // If it's an archive with no files, don't create a record
129 if ( !archive || files != null )
131 record = new StandardArtifactIndexRecord();
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() );
148 populateArchiveEntries( files, record, artifact.getFile() );
151 if ( !"pom".equals( artifact.getType() ) )
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() )
163 populatePomEntries( readPom( pomArtifact, artifact.getRepository() ), record );
165 catch ( ProjectBuildingException e )
167 getLogger().error( "Error reading POM file [" + pomFile + "] for " + artifact +
168 ", not populating in index: " + e.getMessage() );
177 model = readPom( artifact, artifact.getRepository() );
179 if ( !"pom".equals( model.getPackaging() ) )
181 // Don't return a record for a POM that is does not belong on its own
186 populatePomEntries( model, record );
189 catch ( ProjectBuildingException e )
192 "Error reading POM file for " + artifact + ", not populating in index: " + e.getMessage() );
201 private void populatePomEntries( Model pom, StandardArtifactIndexRecord record )
203 record.setPackaging( pom.getPackaging() );
204 record.setProjectName( pom.getName() );
205 record.setProjectDescription( pom.getDescription() );
206 record.setInceptionYear( pom.getInceptionYear() );
208 List dependencies = populateDependencies( pom.getDependencies() );
209 if ( !dependencies.isEmpty() )
211 record.setDependencies( dependencies );
213 List developers = populateDevelopers( pom.getDevelopers() );
214 if ( !developers.isEmpty() )
216 record.setDevelopers( developers );
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 );
226 private List populateDependencies( List dependencies )
228 List convertedDependencies = new ArrayList();
230 for ( Iterator i = dependencies.iterator(); i.hasNext(); )
232 Dependency dependency = (Dependency) i.next();
234 convertedDependencies.add(
235 dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion() );
238 return convertedDependencies;
241 private List populateDevelopers( List developers )
243 List convertedDevelopers = new ArrayList();
245 for ( Iterator i = developers.iterator(); i.hasNext(); )
247 Developer developer = (Developer) i.next();
249 convertedDevelopers.add( developer.getId() + ":" + developer.getName() + ":" + developer.getEmail() );
252 return convertedDevelopers;
255 private Model readPom( Artifact artifact, ArtifactRepository repository )
256 throws RepositoryIndexException, ProjectBuildingException
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?
263 MavenProject project = projectBuilder.buildFromRepository( artifact, Collections.EMPTY_LIST, repository );
264 return project.getModel();
266 catch ( InvalidArtifactRTException e )
268 throw new ProjectBuildingException( artifact.getId(),
269 "Unable to build project from invalid artifact [" + artifact + "]", e );
273 private void populateArchiveEntries( List files, StandardArtifactIndexRecord record, File artifactFile )
274 throws RepositoryIndexException
276 List classes = new ArrayList();
277 List fileList = new ArrayList();
279 for ( Iterator i = files.iterator(); i.hasNext(); )
281 String name = (String) i.next();
283 // ignore directories
284 if ( !name.endsWith( "/" ) )
286 fileList.add( name );
288 if ( isClass( name ) )
290 classes.add( name.substring( 0, name.length() - 6 ).replace( '/', '.' ) );
292 else if ( PLUGIN_METADATA_NAME.equals( name ) )
294 populatePluginEntries( readXmlMetadataFileInJar( artifactFile, PLUGIN_METADATA_NAME ), record );
296 else if ( ARCHETYPE_METADATA_NAME.equals( name ) || ARCHETYPE_METADATA_NAME_OLD.equals( name ) )
298 populateArchetypeEntries( record );
300 else if ( SITE_TEMPLATE_NAME.equals( name ) || SITE_CSS_NAME.equals( name ) )
302 populateSkinEntries( record );
307 if ( !classes.isEmpty() )
309 record.setClasses( classes );
311 if ( !fileList.isEmpty() )
313 record.setFiles( fileList );
317 private void populateArchetypeEntries( StandardArtifactIndexRecord record )
319 // Typically discovered as a JAR
320 record.setType( "maven-archetype" );
323 private void populateSkinEntries( StandardArtifactIndexRecord record )
325 // Typically discovered as a JAR
326 record.setType( "maven-skin" );
329 private Xpp3Dom readXmlMetadataFileInJar( File file, String name )
330 throws RepositoryIndexException
332 // TODO: would be more efficient with original ZipEntry still around
335 ZipFile zipFile = null;
338 zipFile = new ZipFile( file );
339 ZipEntry entry = zipFile.getEntry( name );
340 xpp3Dom = Xpp3DomBuilder.build( new InputStreamReader( zipFile.getInputStream( entry ) ) );
342 catch ( ZipException e )
344 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
346 catch ( IOException e )
348 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
350 catch ( XmlPullParserException e )
352 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
356 closeQuietly( zipFile );
361 public void populatePluginEntries( Xpp3Dom metadata, StandardArtifactIndexRecord record )
363 // Typically discovered as a JAR
364 record.setType( "maven-plugin" );
366 Xpp3Dom prefix = metadata.getChild( "goalPrefix" );
368 if ( prefix != null )
370 record.setPluginPrefix( prefix.getValue() );