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.digest.Digester;
20 import org.apache.maven.archiva.indexer.RepositoryIndexException;
21 import org.apache.maven.artifact.Artifact;
22 import org.apache.maven.artifact.factory.ArtifactFactory;
23 import org.apache.maven.artifact.repository.ArtifactRepository;
24 import org.apache.maven.model.Model;
25 import org.apache.maven.project.MavenProject;
26 import org.apache.maven.project.MavenProjectBuilder;
27 import org.apache.maven.project.ProjectBuildingException;
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.archiva.indexer.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 SITE_TEMPLATE_NAME = "META-INF/maven/site.vm";
86 private static final String SITE_CSS_NAME = "css/maven-theme.css";
88 private static final String PLUGIN_METADATA_NAME = "META-INF/maven/plugin.xml";
90 private static final String ARCHETYPE_METADATA_NAME = "META-INF/maven/archetype.xml";
92 // some current/old archetypes have the archetype.xml at different location.
93 private static final String ARCHETYPE_METADATA_NAME_OLD = "META-INF/archetype.xml";
95 public RepositoryIndexRecord createRecord( Artifact artifact )
96 throws RepositoryIndexException
98 StandardArtifactIndexRecord record = null;
100 File file = artifact.getFile();
102 // TODO: is this condition really a possibility?
103 if ( file != null && file.exists() )
105 String md5 = readChecksum( file, md5Digester );
106 String sha1 = readChecksum( file, sha1Digester );
109 boolean archive = ARCHIVE_TYPES.contains( artifact.getType() );
114 files = readFilesInArchive( file );
117 catch ( IOException e )
119 getLogger().error( "Error reading artifact file, omitting from index: " + e.getMessage() );
122 // If it's an archive with no files, don't create a record
123 if ( !archive || files != null )
125 record = new StandardArtifactIndexRecord();
127 record.setGroupId( artifact.getGroupId() );
128 record.setArtifactId( artifact.getArtifactId() );
129 record.setBaseVersion( artifact.getBaseVersion() );
130 record.setVersion( artifact.getVersion() );
131 record.setClassifier( artifact.getClassifier() );
132 record.setType( artifact.getType() );
133 record.setMd5Checksum( md5 );
134 record.setSha1Checksum( sha1 );
135 record.setFilename( artifact.getRepository().pathOf( artifact ) );
136 record.setLastModified( file.lastModified() );
137 record.setSize( file.length() );
138 record.setRepository( artifact.getRepository().getId() );
141 populateArchiveEntries( files, record, artifact.getFile() );
144 if ( !"pom".equals( artifact.getType() ) )
146 Artifact pomArtifact = artifactFactory.createProjectArtifact( artifact.getGroupId(),
147 artifact.getArtifactId(),
148 artifact.getVersion() );
149 pomArtifact.isSnapshot(); // gross hack around bug in maven-artifact
150 File pomFile = new File( artifact.getRepository().getBasedir(),
151 artifact.getRepository().pathOf( pomArtifact ) );
152 if ( pomFile.exists() )
156 populatePomEntries( readPom( pomArtifact, artifact.getRepository() ), record );
158 catch ( ProjectBuildingException e )
160 getLogger().error( "Error reading POM file, not populating in index: " + e.getMessage() );
169 model = readPom( artifact, artifact.getRepository() );
171 if ( !"pom".equals( model.getPackaging() ) )
173 // Don't return a record for a POM that is does not belong on its own
178 populatePomEntries( model, record );
181 catch ( ProjectBuildingException e )
183 getLogger().error( "Error reading POM file, not populating in index: " + e.getMessage() );
192 private void populatePomEntries( Model pom, StandardArtifactIndexRecord record )
194 record.setPackaging( pom.getPackaging() );
195 record.setProjectName( pom.getName() );
196 record.setProjectDescription( pom.getDescription() );
197 record.setInceptionYear( pom.getInceptionYear() );
199 /* TODO: fields for later
200 indexPlugins( doc, FLD_PLUGINS_BUILD, pom.getBuild().getPlugins().iterator() );
201 indexReportPlugins( doc, FLD_PLUGINS_REPORT, pom.getReporting().getPlugins().iterator() );
202 record.setDependencies( dependencies );
203 record.setLicenses( licenses );
207 private Model readPom( Artifact artifact, ArtifactRepository repository )
208 throws RepositoryIndexException, ProjectBuildingException
210 // TODO: this can create a -SNAPSHOT.pom when it didn't exist and a timestamped one did. This is harmless, but should be avoided
211 // TODO: will this pollute with local repo metadata?
212 MavenProject project = projectBuilder.buildFromRepository( artifact, Collections.EMPTY_LIST, repository );
213 return project.getModel();
216 private void populateArchiveEntries( List files, StandardArtifactIndexRecord record, File artifactFile )
217 throws RepositoryIndexException
219 List classes = new ArrayList();
220 List fileList = new ArrayList();
222 for ( Iterator i = files.iterator(); i.hasNext(); )
224 String name = (String) i.next();
226 // ignore directories
227 if ( !name.endsWith( "/" ) )
229 fileList.add( name );
231 if ( isClass( name ) )
233 classes.add( name.substring( 0, name.length() - 6 ).replace( '/', '.' ) );
235 else if ( PLUGIN_METADATA_NAME.equals( name ) )
237 populatePluginEntries( readXmlMetadataFileInJar( artifactFile, PLUGIN_METADATA_NAME ), record );
239 else if ( ARCHETYPE_METADATA_NAME.equals( name ) || ARCHETYPE_METADATA_NAME_OLD.equals( name ) )
241 populateArchetypeEntries( record );
243 else if ( SITE_TEMPLATE_NAME.equals( name ) || SITE_CSS_NAME.equals( name ) )
245 populateSkinEntries( record );
250 if ( !classes.isEmpty() )
252 record.setClasses( classes );
254 if ( !fileList.isEmpty() )
256 record.setFiles( fileList );
260 private void populateArchetypeEntries( StandardArtifactIndexRecord record )
262 // Typically discovered as a JAR
263 record.setType( "maven-archetype" );
266 private void populateSkinEntries( StandardArtifactIndexRecord record )
268 // Typically discovered as a JAR
269 record.setType( "maven-skin" );
272 private Xpp3Dom readXmlMetadataFileInJar( File file, String name )
273 throws RepositoryIndexException
275 // TODO: would be more efficient with original ZipEntry still around
278 ZipFile zipFile = null;
281 zipFile = new ZipFile( file );
282 ZipEntry entry = zipFile.getEntry( name );
283 xpp3Dom = Xpp3DomBuilder.build( new InputStreamReader( zipFile.getInputStream( entry ) ) );
285 catch ( ZipException e )
287 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
289 catch ( IOException e )
291 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
293 catch ( XmlPullParserException e )
295 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
299 closeQuietly( zipFile );
304 public void populatePluginEntries( Xpp3Dom metadata, StandardArtifactIndexRecord record )
306 // Typically discovered as a JAR
307 record.setType( "maven-plugin" );
309 Xpp3Dom prefix = metadata.getChild( "goalPrefix" );
311 if ( prefix != null )
313 record.setPluginPrefix( prefix.getValue() );