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.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.util.xml.Xpp3Dom;
31 import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
32 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
35 import java.io.IOException;
36 import java.io.InputStreamReader;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Collections;
40 import java.util.HashSet;
41 import java.util.Iterator;
42 import java.util.List;
44 import java.util.zip.ZipEntry;
45 import java.util.zip.ZipException;
46 import java.util.zip.ZipFile;
49 * An index record type for the standard index.
51 * @author Edwin Punzalan
52 * @author Brett Porter
53 * @plexus.component role="org.apache.maven.archiva.indexer.record.RepositoryIndexRecordFactory" role-hint="standard"
55 public class StandardArtifactIndexRecordFactory
56 extends AbstractArtifactIndexRecordFactory
59 * A list of artifact types to treat as a zip archive.
61 * @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 private static final Set ARCHIVE_TYPES =
64 new HashSet( Arrays.asList( new String[]{"jar", "ejb", "par", "sar", "war", "ear", "rar"} ) );
69 private ArtifactFactory artifactFactory;
74 private MavenProjectBuilder projectBuilder;
77 * @plexus.requirement role-hint="sha1"
79 protected Digester sha1Digester;
82 * @plexus.requirement role-hint="md5"
84 protected Digester md5Digester;
86 private static final String SITE_TEMPLATE_NAME = "META-INF/maven/site.vm";
88 private static final String SITE_CSS_NAME = "css/maven-theme.css";
90 private static final String PLUGIN_METADATA_NAME = "META-INF/maven/plugin.xml";
92 private static final String ARCHETYPE_METADATA_NAME = "META-INF/maven/archetype.xml";
94 // some current/old archetypes have the archetype.xml at different location.
95 private static final String ARCHETYPE_METADATA_NAME_OLD = "META-INF/archetype.xml";
97 public RepositoryIndexRecord createRecord( Artifact artifact )
98 throws RepositoryIndexException
100 StandardArtifactIndexRecord record = null;
102 File file = artifact.getFile();
104 // TODO: is this condition really a possibility?
105 if ( file != null && file.exists() )
107 String md5 = readChecksum( file, md5Digester );
108 String sha1 = readChecksum( file, sha1Digester );
111 boolean archive = ARCHIVE_TYPES.contains( artifact.getType() );
116 files = readFilesInArchive( file );
119 catch ( IOException e )
121 getLogger().error( "Error reading artifact file, omitting from index: " + e.getMessage() );
124 // If it's an archive with no files, don't create a record
125 if ( !archive || files != null )
127 record = new StandardArtifactIndexRecord();
129 record.setGroupId( artifact.getGroupId() );
130 record.setArtifactId( artifact.getArtifactId() );
131 record.setBaseVersion( artifact.getBaseVersion() );
132 record.setVersion( artifact.getVersion() );
133 record.setClassifier( artifact.getClassifier() );
134 record.setType( artifact.getType() );
135 record.setMd5Checksum( md5 );
136 record.setSha1Checksum( sha1 );
137 record.setFilename( artifact.getRepository().pathOf( artifact ) );
138 record.setLastModified( file.lastModified() );
139 record.setSize( file.length() );
140 record.setRepository( artifact.getRepository().getId() );
144 populateArchiveEntries( files, record, artifact.getFile() );
147 if ( !"pom".equals( artifact.getType() ) )
149 Artifact pomArtifact = artifactFactory.createProjectArtifact( artifact.getGroupId(),
150 artifact.getArtifactId(),
151 artifact.getVersion() );
152 pomArtifact.isSnapshot(); // gross hack around bug in maven-artifact
153 File pomFile = new File( artifact.getRepository().getBasedir(),
154 artifact.getRepository().pathOf( pomArtifact ) );
155 if ( pomFile.exists() )
159 populatePomEntries( readPom( pomArtifact, artifact.getRepository() ), record );
161 catch ( ProjectBuildingException e )
163 getLogger().error( "Error reading POM file, not populating in index: " + e.getMessage() );
172 model = readPom( artifact, artifact.getRepository() );
174 if ( !"pom".equals( model.getPackaging() ) )
176 // Don't return a record for a POM that is does not belong on its own
181 populatePomEntries( model, record );
184 catch ( ProjectBuildingException e )
186 getLogger().error( "Error reading POM file, not populating in index: " + e.getMessage() );
195 private void populatePomEntries( Model pom, StandardArtifactIndexRecord record )
197 record.setPackaging( pom.getPackaging() );
198 record.setProjectName( pom.getName() );
199 record.setProjectDescription( pom.getDescription() );
200 record.setInceptionYear( pom.getInceptionYear() );
202 List dependencies = populateDependencies( pom.getDependencies() );
203 if ( !dependencies.isEmpty() )
205 record.setDependencies( dependencies );
207 List developers = populateDevelopers( pom.getDevelopers() );
208 if ( !developers.isEmpty() )
210 record.setDevelopers( developers );
213 /* TODO: fields for later
214 indexPlugins( doc, FLD_PLUGINS_BUILD, pom.getBuild().getPlugins().iterator() );
215 indexReportPlugins( doc, FLD_PLUGINS_REPORT, pom.getReporting().getPlugins().iterator() );
216 record.setLicenses( licenses );
220 private List populateDependencies( List dependencies )
222 List convertedDependencies = new ArrayList();
224 for ( Iterator i = dependencies.iterator(); i.hasNext(); )
226 Dependency dependency = (Dependency) i.next();
228 convertedDependencies.add(
229 dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion() );
232 return convertedDependencies;
235 private List populateDevelopers( List developers )
237 List convertedDevelopers = new ArrayList();
239 for ( Iterator i = developers.iterator(); i.hasNext(); )
241 Developer developer = (Developer) i.next();
243 convertedDevelopers.add( developer.getId() + ":" + developer.getName() + ":" + developer.getEmail() );
246 return convertedDevelopers;
249 private Model readPom( Artifact artifact, ArtifactRepository repository )
250 throws RepositoryIndexException, ProjectBuildingException
252 // TODO: this can create a -SNAPSHOT.pom when it didn't exist and a timestamped one did. This is harmless, but should be avoided
253 // TODO: will this pollute with local repo metadata?
254 MavenProject project = projectBuilder.buildFromRepository( artifact, Collections.EMPTY_LIST, repository );
255 return project.getModel();
258 private void populateArchiveEntries( List files, StandardArtifactIndexRecord record, File artifactFile )
259 throws RepositoryIndexException
261 List classes = new ArrayList();
262 List fileList = new ArrayList();
264 for ( Iterator i = files.iterator(); i.hasNext(); )
266 String name = (String) i.next();
268 // ignore directories
269 if ( !name.endsWith( "/" ) )
271 fileList.add( name );
273 if ( isClass( name ) )
275 classes.add( name.substring( 0, name.length() - 6 ).replace( '/', '.' ) );
277 else if ( PLUGIN_METADATA_NAME.equals( name ) )
279 populatePluginEntries( readXmlMetadataFileInJar( artifactFile, PLUGIN_METADATA_NAME ), record );
281 else if ( ARCHETYPE_METADATA_NAME.equals( name ) || ARCHETYPE_METADATA_NAME_OLD.equals( name ) )
283 populateArchetypeEntries( record );
285 else if ( SITE_TEMPLATE_NAME.equals( name ) || SITE_CSS_NAME.equals( name ) )
287 populateSkinEntries( record );
292 if ( !classes.isEmpty() )
294 record.setClasses( classes );
296 if ( !fileList.isEmpty() )
298 record.setFiles( fileList );
302 private void populateArchetypeEntries( StandardArtifactIndexRecord record )
304 // Typically discovered as a JAR
305 record.setType( "maven-archetype" );
308 private void populateSkinEntries( StandardArtifactIndexRecord record )
310 // Typically discovered as a JAR
311 record.setType( "maven-skin" );
314 private Xpp3Dom readXmlMetadataFileInJar( File file, String name )
315 throws RepositoryIndexException
317 // TODO: would be more efficient with original ZipEntry still around
320 ZipFile zipFile = null;
323 zipFile = new ZipFile( file );
324 ZipEntry entry = zipFile.getEntry( name );
325 xpp3Dom = Xpp3DomBuilder.build( new InputStreamReader( zipFile.getInputStream( entry ) ) );
327 catch ( ZipException e )
329 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
331 catch ( IOException e )
333 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
335 catch ( XmlPullParserException e )
337 throw new RepositoryIndexException( "Unable to read plugin metadata: " + e.getMessage(), e );
341 closeQuietly( zipFile );
346 public void populatePluginEntries( Xpp3Dom metadata, StandardArtifactIndexRecord record )
348 // Typically discovered as a JAR
349 record.setType( "maven-plugin" );
351 Xpp3Dom prefix = metadata.getChild( "goalPrefix" );
353 if ( prefix != null )
355 record.setPluginPrefix( prefix.getValue() );