1 package org.apache.maven.repository.indexing.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.artifact.Artifact;
20 import org.apache.maven.artifact.factory.ArtifactFactory;
21 import org.apache.maven.artifact.repository.ArtifactRepository;
22 import org.apache.maven.model.Model;
23 import org.apache.maven.project.MavenProject;
24 import org.apache.maven.project.MavenProjectBuilder;
25 import org.apache.maven.project.ProjectBuildingException;
26 import org.apache.maven.repository.digest.Digester;
27 import org.apache.maven.repository.indexing.RepositoryIndexException;
28 import org.codehaus.plexus.util.xml.Xpp3Dom;
29 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
30 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
33 import java.io.IOException;
34 import java.io.InputStreamReader;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.Collections;
38 import java.util.HashSet;
39 import java.util.Iterator;
40 import java.util.List;
42 import java.util.zip.ZipEntry;
43 import java.util.zip.ZipException;
44 import java.util.zip.ZipFile;
47 * An index record type for the standard index.
49 * @author Edwin Punzalan
50 * @author Brett Porter
51 * @plexus.component role="org.apache.maven.repository.indexing.record.RepositoryIndexRecordFactory" role-hint="standard"
53 public class StandardArtifactIndexRecordFactory
54 extends AbstractArtifactIndexRecordFactory
57 * A list of artifact types to treat as a zip archive.
59 * @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.
61 private static final Set ARCHIVE_TYPES =
62 new HashSet( Arrays.asList( new String[]{"jar", "ejb", "par", "sar", "war", "ear", "rar"} ) );
67 private ArtifactFactory artifactFactory;
72 private MavenProjectBuilder projectBuilder;
75 * @plexus.requirement role-hint="sha1"
77 protected Digester sha1Digester;
80 * @plexus.requirement role-hint="md5"
82 protected Digester md5Digester;
84 private static final String PLUGIN_METADATA_NAME = "META-INF/maven/plugin.xml";
86 private static final String ARCHETYPE_METADATA_NAME = "META-INF/maven/archetype.xml";
88 // some current/old archetypes have the archetype.xml at different location.
89 private static final String ARCHETYPE_METADATA_NAME_OLD = "META-INF/archetype.xml";
91 public RepositoryIndexRecord createRecord( Artifact artifact )
92 throws RepositoryIndexException
94 StandardArtifactIndexRecord record = null;
96 File file = artifact.getFile();
98 // TODO: is this condition really a possibility?
99 if ( file != null && file.exists() )
101 String md5 = readChecksum( file, md5Digester );
102 String sha1 = readChecksum( file, sha1Digester );
105 boolean archive = ARCHIVE_TYPES.contains( artifact.getType() );
110 files = readFilesInArchive( file );
113 catch ( IOException e )
115 getLogger().error( "Error reading artifact file, omitting from index: " + e.getMessage() );
118 // If it's an archive with no files, don't create a record
119 if ( !archive || files != null )
121 record = new StandardArtifactIndexRecord();
123 record.setGroupId( artifact.getGroupId() );
124 record.setArtifactId( artifact.getArtifactId() );
125 record.setBaseVersion( artifact.getBaseVersion() );
126 record.setVersion( artifact.getVersion() );
127 record.setClassifier( artifact.getClassifier() );
128 record.setType( artifact.getType() );
129 record.setMd5Checksum( md5 );
130 record.setSha1Checksum( sha1 );
131 record.setFilename( artifact.getRepository().pathOf( artifact ) );
132 record.setLastModified( file.lastModified() );
133 record.setSize( file.length() );
134 record.setRepository( artifact.getRepository().getId() );
137 populateArchiveEntries( files, record, artifact.getFile() );
140 if ( !"pom".equals( artifact.getType() ) )
142 Artifact pomArtifact = artifactFactory.createProjectArtifact( artifact.getGroupId(),
143 artifact.getArtifactId(),
144 artifact.getVersion() );
145 pomArtifact.isSnapshot(); // gross hack around bug in maven-artifact
146 File pomFile = new File( artifact.getRepository().getBasedir(),
147 artifact.getRepository().pathOf( pomArtifact ) );
148 if ( pomFile.exists() )
152 populatePomEntries( readPom( pomArtifact, artifact.getRepository() ), record );
154 catch ( ProjectBuildingException e )
156 getLogger().error( "Error reading POM file, not populating in index: " + e.getMessage() );
165 model = readPom( artifact, artifact.getRepository() );
167 if ( !"pom".equals( model.getPackaging() ) )
169 // Don't return a record for a POM that is does not belong on its own
174 populatePomEntries( model, record );
177 catch ( ProjectBuildingException e )
179 getLogger().error( "Error reading POM file, not populating in index: " + e.getMessage() );
188 private void populatePomEntries( Model pom, StandardArtifactIndexRecord record )
190 record.setPackaging( pom.getPackaging() );
191 record.setProjectName( pom.getName() );
192 record.setProjectDescription( pom.getDescription() );
193 record.setInceptionYear( pom.getInceptionYear() );
195 /* TODO: fields for later
196 indexPlugins( doc, FLD_PLUGINS_BUILD, pom.getBuild().getPlugins().iterator() );
197 indexReportPlugins( doc, FLD_PLUGINS_REPORT, pom.getReporting().getPlugins().iterator() );
198 record.setDependencies( dependencies );
199 record.setLicenses( licenses );
203 private Model readPom( Artifact artifact, ArtifactRepository repository )
204 throws RepositoryIndexException, ProjectBuildingException
206 // TODO: this can create a -SNAPSHOT.pom when it didn't exist and a timestamped one did. This is harmless, but should be avoided
207 // TODO: will this pollute with local repo metadata?
208 MavenProject project = projectBuilder.buildFromRepository( artifact, Collections.EMPTY_LIST, repository );
209 return project.getModel();
212 private void populateArchiveEntries( List files, StandardArtifactIndexRecord record, File artifactFile )
213 throws RepositoryIndexException
215 List classes = new ArrayList();
216 List fileList = new ArrayList();
218 for ( Iterator i = files.iterator(); i.hasNext(); )
220 String name = (String) i.next();
222 // ignore directories
223 if ( !name.endsWith( "/" ) )
225 fileList.add( name );
227 if ( isClass( name ) )
229 classes.add( name.substring( 0, name.length() - 6 ).replace( '/', '.' ) );
231 else if ( PLUGIN_METADATA_NAME.equals( name ) )
233 populatePluginEntries( readXmlMetadataFileInJar( artifactFile, PLUGIN_METADATA_NAME ), record );
235 else if ( ARCHETYPE_METADATA_NAME.equals( name ) || ARCHETYPE_METADATA_NAME_OLD.equals( name ) )
237 populateArchetypeEntries( record );
242 if ( !classes.isEmpty() )
244 record.setClasses( classes );
246 if ( !fileList.isEmpty() )
248 record.setFiles( fileList );
252 private void populateArchetypeEntries( StandardArtifactIndexRecord record )
254 // Typically discovered as a JAR
255 record.setType( "maven-archetype" );
258 private Xpp3Dom readXmlMetadataFileInJar( File file, String name )
259 throws RepositoryIndexException
261 // TODO: would be more efficient with original ZipEntry still around
264 ZipFile zipFile = null;
267 zipFile = new ZipFile( file );
268 ZipEntry entry = zipFile.getEntry( name );
269 xpp3Dom = Xpp3DomBuilder.build( new InputStreamReader( zipFile.getInputStream( entry ) ) );
271 catch ( ZipException e )
273 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
275 catch ( IOException e )
277 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
279 catch ( XmlPullParserException e )
281 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
285 closeQuietly( zipFile );
290 public void populatePluginEntries( Xpp3Dom metadata, StandardArtifactIndexRecord record )
292 // Typically discovered as a JAR
293 record.setType( "maven-plugin" );
295 Xpp3Dom prefix = metadata.getChild( "goalPrefix" );
297 if ( prefix != null )
299 record.setPluginPrefix( prefix.getValue() );