1 package org.apache.maven.archiva.indexer.record;
4 * Copyright 2005-2006 The Apache Software Foundation.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
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;
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;
45 import java.util.zip.ZipEntry;
46 import java.util.zip.ZipException;
47 import java.util.zip.ZipFile;
50 * An index record type for the standard index.
52 * @author Edwin Punzalan
53 * @author Brett Porter
54 * @plexus.component role="org.apache.maven.archiva.indexer.record.RepositoryIndexRecordFactory" role-hint="standard"
56 public class StandardArtifactIndexRecordFactory
57 extends AbstractArtifactIndexRecordFactory
60 * A list of artifact types to treat as a zip archive.
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.
64 private static final Set ARCHIVE_TYPES =
65 new HashSet( Arrays.asList( new String[]{"jar", "ejb", "par", "sar", "war", "ear", "rar"} ) );
70 private ArtifactFactory artifactFactory;
75 private MavenProjectBuilder projectBuilder;
78 * @plexus.requirement role-hint="sha1"
80 protected Digester sha1Digester;
83 * @plexus.requirement role-hint="md5"
85 protected Digester md5Digester;
87 private static final String SITE_TEMPLATE_NAME = "META-INF/maven/site.vm";
89 private static final String SITE_CSS_NAME = "css/maven-theme.css";
91 private static final String PLUGIN_METADATA_NAME = "META-INF/maven/plugin.xml";
93 private static final String ARCHETYPE_METADATA_NAME = "META-INF/maven/archetype.xml";
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";
98 public RepositoryIndexRecord createRecord( Artifact artifact )
99 throws RepositoryIndexException
101 StandardArtifactIndexRecord record = null;
103 File file = artifact.getFile();
105 // TODO: is this condition really a possibility?
106 if ( file != null && file.exists() )
108 String md5 = readChecksum( file, md5Digester );
109 String sha1 = readChecksum( file, sha1Digester );
112 boolean archive = ARCHIVE_TYPES.contains( artifact.getType() );
117 files = readFilesInArchive( file );
120 catch ( IOException e )
122 getLogger().error( "Error reading artifact file, omitting from index: " + e.getMessage() );
125 // If it's an archive with no files, don't create a record
126 if ( !archive || files != null )
128 record = new StandardArtifactIndexRecord();
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() );
145 populateArchiveEntries( files, record, artifact.getFile() );
148 if ( !"pom".equals( artifact.getType() ) )
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() )
160 populatePomEntries( readPom( pomArtifact, artifact.getRepository() ), record );
162 catch ( ProjectBuildingException e )
164 getLogger().error( "Error reading POM file ["+pomFile+"] for " + artifact + ", not populating in index: " + e.getMessage() );
173 model = readPom( artifact, artifact.getRepository() );
175 if ( !"pom".equals( model.getPackaging() ) )
177 // Don't return a record for a POM that is does not belong on its own
182 populatePomEntries( model, record );
185 catch ( ProjectBuildingException e )
187 getLogger().error( "Error reading POM file for " + artifact + ", not populating in index: " + e.getMessage() );
196 private void populatePomEntries( Model pom, StandardArtifactIndexRecord record )
198 record.setPackaging( pom.getPackaging() );
199 record.setProjectName( pom.getName() );
200 record.setProjectDescription( pom.getDescription() );
201 record.setInceptionYear( pom.getInceptionYear() );
203 List dependencies = populateDependencies( pom.getDependencies() );
204 if ( !dependencies.isEmpty() )
206 record.setDependencies( dependencies );
208 List developers = populateDevelopers( pom.getDevelopers() );
209 if ( !developers.isEmpty() )
211 record.setDevelopers( developers );
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 );
221 private List populateDependencies( List dependencies )
223 List convertedDependencies = new ArrayList();
225 for ( Iterator i = dependencies.iterator(); i.hasNext(); )
227 Dependency dependency = (Dependency) i.next();
229 convertedDependencies.add(
230 dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion() );
233 return convertedDependencies;
236 private List populateDevelopers( List developers )
238 List convertedDevelopers = new ArrayList();
240 for ( Iterator i = developers.iterator(); i.hasNext(); )
242 Developer developer = (Developer) i.next();
244 convertedDevelopers.add( developer.getId() + ":" + developer.getName() + ":" + developer.getEmail() );
247 return convertedDevelopers;
250 private Model readPom( Artifact artifact, ArtifactRepository repository )
251 throws RepositoryIndexException, ProjectBuildingException
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?
258 MavenProject project = projectBuilder.buildFromRepository( artifact, Collections.EMPTY_LIST, repository );
259 return project.getModel();
261 catch ( InvalidArtifactRTException e )
263 throw new ProjectBuildingException( artifact.getId(), "Unable to build project from invalid artifact ["
264 + artifact + "]", e );
268 private void populateArchiveEntries( List files, StandardArtifactIndexRecord record, File artifactFile )
269 throws RepositoryIndexException
271 List classes = new ArrayList();
272 List fileList = new ArrayList();
274 for ( Iterator i = files.iterator(); i.hasNext(); )
276 String name = (String) i.next();
278 // ignore directories
279 if ( !name.endsWith( "/" ) )
281 fileList.add( name );
283 if ( isClass( name ) )
285 classes.add( name.substring( 0, name.length() - 6 ).replace( '/', '.' ) );
287 else if ( PLUGIN_METADATA_NAME.equals( name ) )
289 populatePluginEntries( readXmlMetadataFileInJar( artifactFile, PLUGIN_METADATA_NAME ), record );
291 else if ( ARCHETYPE_METADATA_NAME.equals( name ) || ARCHETYPE_METADATA_NAME_OLD.equals( name ) )
293 populateArchetypeEntries( record );
295 else if ( SITE_TEMPLATE_NAME.equals( name ) || SITE_CSS_NAME.equals( name ) )
297 populateSkinEntries( record );
302 if ( !classes.isEmpty() )
304 record.setClasses( classes );
306 if ( !fileList.isEmpty() )
308 record.setFiles( fileList );
312 private void populateArchetypeEntries( StandardArtifactIndexRecord record )
314 // Typically discovered as a JAR
315 record.setType( "maven-archetype" );
318 private void populateSkinEntries( StandardArtifactIndexRecord record )
320 // Typically discovered as a JAR
321 record.setType( "maven-skin" );
324 private Xpp3Dom readXmlMetadataFileInJar( File file, String name )
325 throws RepositoryIndexException
327 // TODO: would be more efficient with original ZipEntry still around
330 ZipFile zipFile = null;
333 zipFile = new ZipFile( file );
334 ZipEntry entry = zipFile.getEntry( name );
335 xpp3Dom = Xpp3DomBuilder.build( new InputStreamReader( zipFile.getInputStream( entry ) ) );
337 catch ( ZipException e )
339 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
341 catch ( IOException e )
343 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
345 catch ( XmlPullParserException e )
347 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
351 closeQuietly( zipFile );
356 public void populatePluginEntries( Xpp3Dom metadata, StandardArtifactIndexRecord record )
358 // Typically discovered as a JAR
359 record.setType( "maven-plugin" );
361 Xpp3Dom prefix = metadata.getChild( "goalPrefix" );
363 if ( prefix != null )
365 record.setPluginPrefix( prefix.getValue() );