1 package org.apache.maven.archiva.web.action;
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 com.opensymphony.xwork2.Validateable;
23 import org.apache.archiva.metadata.model.ArtifactMetadata;
24 import org.apache.archiva.metadata.model.Dependency;
25 import org.apache.archiva.metadata.model.MailingList;
26 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
27 import org.apache.archiva.metadata.model.ProjectVersionReference;
28 import org.apache.archiva.metadata.repository.MetadataRepository;
29 import org.apache.archiva.metadata.repository.MetadataResolutionException;
30 import org.apache.archiva.metadata.repository.MetadataResolver;
31 import org.apache.archiva.metadata.repository.storage.maven2.MavenArtifactFacet;
32 import org.apache.commons.lang.StringUtils;
33 import org.apache.maven.archiva.model.ArtifactReference;
34 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
35 import org.apache.maven.archiva.repository.RepositoryContentFactory;
36 import org.apache.maven.archiva.repository.RepositoryException;
37 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
39 import java.text.DecimalFormat;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.Comparator;
44 import java.util.LinkedHashMap;
45 import java.util.List;
49 * Browse the repository.
51 * TODO change name to ShowVersionedAction to conform to terminology.
53 * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="showArtifactAction" instantiation-strategy="per-lookup"
55 public class ShowArtifactAction
56 extends AbstractRepositoryBasedAction
57 implements Validateable
59 /* .\ Not Exposed \._____________________________________________ */
64 private MetadataResolver metadataResolver;
69 private RepositoryContentFactory repositoryFactory;
74 private MetadataRepository metadataRepository;
76 /* .\ Exposed Output Objects \.__________________________________ */
78 private String groupId;
80 private String artifactId;
82 private String version;
84 private String repositoryId;
87 * The model of this versioned project.
89 private ProjectVersionMetadata model;
92 * The list of artifacts that depend on this versioned project.
94 private List<ProjectVersionReference> dependees;
96 private List<MailingList> mailingLists;
98 private List<Dependency> dependencies;
100 private Map<String, List<ArtifactDownloadInfo>> artifacts;
102 private boolean dependencyTree = false;
104 private ProjectVersionMetadata projectMetadata;
107 * Show the versioned project information tab.
108 * TODO: Change name to 'project' - we are showing project versions here, not specific artifact information (though
109 * that is rendered in the download box).
111 public String artifact()
114 // In the future, this should be replaced by the repository grouping mechanism, so that we are only making
115 // simple resource requests here and letting the resolver take care of it
116 String errorMsg = null;
117 ProjectVersionMetadata versionMetadata = getProjectVersionMetadata();
119 if ( versionMetadata == null )
121 addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
125 if ( versionMetadata.isIncomplete() )
127 addIncompleteModelWarning();
130 model = versionMetadata;
135 private ProjectVersionMetadata getProjectVersionMetadata()
137 ProjectVersionMetadata versionMetadata = null;
138 artifacts = new LinkedHashMap<String, List<ArtifactDownloadInfo>>();
140 List<String> repos = getObservableRepos();
142 for ( String repoId : repos )
144 if ( versionMetadata == null )
146 // we don't want the implementation being that intelligent - so another resolver to do the
147 // "just-in-time" nature of picking up the metadata (if appropriate for the repository type) is used
150 versionMetadata = metadataResolver.getProjectVersion( repoId, groupId, artifactId, version );
152 catch ( MetadataResolutionException e )
154 addIncompleteModelWarning();
156 // TODO: need a consistent way to construct this - same in ArchivaMetadataCreationConsumer
157 versionMetadata = new ProjectVersionMetadata();
158 versionMetadata.setId( version );
160 if ( versionMetadata != null )
162 repositoryId = repoId;
164 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>(
165 metadataResolver.getArtifacts( repoId, groupId, artifactId, version ) );
166 Collections.sort( artifacts, new Comparator<ArtifactMetadata>()
168 public int compare( ArtifactMetadata o1, ArtifactMetadata o2 )
170 // sort by version (reverse), then ID
171 // TODO: move version sorting into repository handling (maven2 specific), and perhaps add a
172 // way to get latest instead
173 int result = new DefaultArtifactVersion( o2.getVersion() ).compareTo(
174 new DefaultArtifactVersion( o1.getVersion() ) );
175 return result != 0 ? result : o1.getId().compareTo( o2.getId() );
179 for ( ArtifactMetadata artifact : artifacts )
181 List<ArtifactDownloadInfo> l = this.artifacts.get( artifact.getVersion() );
184 l = new ArrayList<ArtifactDownloadInfo>();
185 this.artifacts.put( artifact.getVersion(), l );
187 l.add( new ArtifactDownloadInfo( artifact ) );
193 return versionMetadata;
196 private void addIncompleteModelWarning()
198 addActionMessage( "The model may be incomplete due to a previous error in resolving information. Refer to the repository problem reports for more information." );
202 * Show the artifact information tab.
204 public String dependencies()
206 String result = artifact();
208 this.dependencies = model.getDependencies();
214 * Show the mailing lists information tab.
216 public String mailingLists()
218 String result = artifact();
220 this.mailingLists = model.getMailingLists();
226 * Show the reports tab.
228 public String reports()
230 // TODO: hook up reports on project
236 * Show the dependees (other artifacts that depend on this project) tab.
238 public String dependees()
240 List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
241 // TODO: what if we get duplicates across repositories?
242 for ( String repoId : getObservableRepos() )
244 // TODO: what about if we want to see this irrespective of version?
245 references.addAll( metadataResolver.getProjectReferences( repoId, groupId, artifactId, version ) );
248 this.dependees = references;
250 // TODO: may need to note on the page that references will be incomplete if the other artifacts are not yet stored in the content repository
251 // (especially in the case of pre-population import)
257 * Show the dependencies of this versioned project tab.
259 public String dependencyTree()
261 // temporarily use this as we only need the model for the tag to perform, but we should be resolving the
262 // graph here instead
264 // TODO: may need to note on the page that tree will be incomplete if the other artifacts are not yet stored in the content repository
265 // (especially in the case of pre-population import)
267 // TODO: a bit ugly, should really be mapping all these results differently now
268 this.dependencyTree = true;
273 public String projectMetadata()
275 projectMetadata = getProjectVersionMetadata();
276 String errorMsg = null;
278 if ( projectMetadata == null )
280 addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
284 if ( projectMetadata.isIncomplete() )
286 addIncompleteModelWarning();
292 public String updateProjectMetadata()
294 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
300 public void validate()
302 if ( StringUtils.isBlank( groupId ) )
304 addActionError( "You must specify a group ID to browse" );
307 if ( StringUtils.isBlank( artifactId ) )
309 addActionError( "You must specify a artifact ID to browse" );
312 if ( StringUtils.isBlank( version ) )
314 addActionError( "You must specify a version to browse" );
318 public ProjectVersionMetadata getModel()
323 public String getGroupId()
328 public void setGroupId( String groupId )
330 this.groupId = groupId;
333 public String getArtifactId()
338 public void setArtifactId( String artifactId )
340 this.artifactId = artifactId;
343 public String getVersion()
348 public void setVersion( String version )
350 this.version = version;
353 public List<MailingList> getMailingLists()
358 public List<Dependency> getDependencies()
363 public List<ProjectVersionReference> getDependees()
368 public String getRepositoryId()
373 public void setRepositoryId( String repositoryId )
375 this.repositoryId = repositoryId;
378 public MetadataResolver getMetadataResolver()
380 return metadataResolver;
383 public Map<String, List<ArtifactDownloadInfo>> getArtifacts()
388 public Collection<String> getSnapshotVersions()
390 return artifacts.keySet();
393 public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
395 this.repositoryFactory = repositoryFactory;
398 public boolean isDependencyTree()
400 return dependencyTree;
403 public ProjectVersionMetadata getProjectMetadata()
405 return projectMetadata;
408 public void setProjectMetadata( ProjectVersionMetadata projectMetadata )
410 this.projectMetadata = projectMetadata;
413 // TODO: move this into the artifact metadata itself via facets where necessary
415 public class ArtifactDownloadInfo
419 private String namespace;
421 private String project;
427 private String repositoryId;
429 private String version;
433 public ArtifactDownloadInfo( ArtifactMetadata artifact )
435 repositoryId = artifact.getRepositoryId();
437 // TODO: use metadata resolver capability instead - maybe the storage path could be stored in the metadata
438 // though keep in mind the request may not necessarily need to reflect the storage
439 ManagedRepositoryContent repo;
442 repo = repositoryFactory.getManagedRepositoryContent( repositoryId );
444 catch ( RepositoryException e )
446 throw new RuntimeException( e );
449 ArtifactReference ref = new ArtifactReference();
450 ref.setArtifactId( artifact.getProject() );
451 ref.setGroupId( artifact.getNamespace() );
452 ref.setVersion( artifact.getVersion() );
453 path = repo.toPath( ref );
454 path = path.substring( 0, path.lastIndexOf( "/" ) + 1 ) + artifact.getId();
456 // TODO: need to accommodate Maven 1 layout too. Non-maven repository formats will need to generate this
457 // facet (perhaps on the fly) if wanting to display the Maven 2 elements on the Archiva pages
459 MavenArtifactFacet facet = (MavenArtifactFacet) artifact.getFacet( MavenArtifactFacet.FACET_ID );
462 type = facet.getType();
466 namespace = artifact.getNamespace();
467 project = artifact.getProject();
469 // TODO: find a reusable formatter for this
470 double s = artifact.getSize();
490 size = new DecimalFormat( "#,###.##" ).format( s ) + " " + symbol;
491 id = artifact.getId();
492 version = artifact.getVersion();
495 public String getNamespace()
500 public String getType()
505 public String getProject()
510 public String getSize()
515 public String getId()
520 public String getVersion()
525 public String getRepositoryId()
530 public String getPath()