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.MetadataResolutionException;
29 import org.apache.archiva.metadata.repository.MetadataResolver;
30 import org.apache.archiva.metadata.repository.storage.maven2.MavenArtifactFacet;
31 import org.apache.commons.lang.StringUtils;
32 import org.apache.maven.archiva.model.ArtifactReference;
33 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
34 import org.apache.maven.archiva.repository.RepositoryContentFactory;
35 import org.apache.maven.archiva.repository.RepositoryException;
36 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
38 import java.text.DecimalFormat;
39 import java.util.ArrayList;
40 import java.util.Collection;
41 import java.util.Collections;
42 import java.util.Comparator;
43 import java.util.LinkedHashMap;
44 import java.util.List;
48 * Browse the repository.
50 * TODO change name to ShowVersionedAction to conform to terminology.
52 * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="showArtifactAction" instantiation-strategy="per-lookup"
54 public class ShowArtifactAction
55 extends AbstractRepositoryBasedAction
56 implements Validateable
58 /* .\ Not Exposed \._____________________________________________ */
63 private MetadataResolver metadataResolver;
68 private RepositoryContentFactory repositoryFactory;
70 /* .\ Exposed Output Objects \.__________________________________ */
72 private String groupId;
74 private String artifactId;
76 private String version;
78 private String repositoryId;
81 * The model of this versioned project.
83 private ProjectVersionMetadata model;
86 * The list of artifacts that depend on this versioned project.
88 private List<ProjectVersionReference> dependees;
90 private List<MailingList> mailingLists;
92 private List<Dependency> dependencies;
94 private Map<String, List<ArtifactDownloadInfo>> artifacts;
96 private boolean dependencyTree = false;
99 * Show the versioned project information tab.
100 * TODO: Change name to 'project' - we are showing project versions here, not specific artifact information (though
101 * that is rendered in the download box).
103 public String artifact()
105 ProjectVersionMetadata versionMetadata = null;
106 artifacts = new LinkedHashMap<String, List<ArtifactDownloadInfo>>();
108 List<String> repos = getObservableRepos();
109 // In the future, this should be replaced by the repository grouping mechanism, so that we are only making
110 // simple resource requests here and letting the resolver take care of it
111 String errorMsg = null;
112 for ( String repoId : repos )
114 if ( versionMetadata == null )
116 // we don't want the implementation being that intelligent - so another resolver to do the
117 // "just-in-time" nature of picking up the metadata (if appropriate for the repository type) is used
120 versionMetadata = metadataResolver.getProjectVersion( repoId, groupId, artifactId, version );
122 catch ( MetadataResolutionException e )
124 addIncompleteModelWarning();
126 // TODO: need a consistent way to construct this - same in ArchivaMetadataCreationConsumer
127 versionMetadata = new ProjectVersionMetadata();
128 versionMetadata.setId( version );
130 if ( versionMetadata != null )
132 repositoryId = repoId;
134 List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>(
135 metadataResolver.getArtifacts( repoId, groupId, artifactId, version ) );
136 Collections.sort( artifacts, new Comparator<ArtifactMetadata>()
138 public int compare( ArtifactMetadata o1, ArtifactMetadata o2 )
140 // sort by version (reverse), then ID
141 // TODO: move version sorting into repository handling (maven2 specific), and perhaps add a
142 // way to get latest instead
143 int result = new DefaultArtifactVersion( o2.getVersion() ).compareTo(
144 new DefaultArtifactVersion( o1.getVersion() ) );
145 return result != 0 ? result : o1.getId().compareTo( o2.getId() );
149 for ( ArtifactMetadata artifact : artifacts )
151 List<ArtifactDownloadInfo> l = this.artifacts.get( artifact.getVersion() );
154 l = new ArrayList<ArtifactDownloadInfo>();
155 this.artifacts.put( artifact.getVersion(), l );
157 l.add( new ArtifactDownloadInfo( artifact ) );
163 if ( versionMetadata == null )
165 addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
169 if ( versionMetadata.isIncomplete() )
171 addIncompleteModelWarning();
174 model = versionMetadata;
179 private void addIncompleteModelWarning()
181 addActionMessage( "The model may be incomplete due to a previous error in resolving information. Refer to the repository problem reports for more information." );
185 * Show the artifact information tab.
187 public String dependencies()
189 String result = artifact();
191 this.dependencies = model.getDependencies();
197 * Show the mailing lists information tab.
199 public String mailingLists()
201 String result = artifact();
203 this.mailingLists = model.getMailingLists();
209 * Show the reports tab.
211 public String reports()
213 // TODO: hook up reports on project
219 * Show the dependees (other artifacts that depend on this project) tab.
221 public String dependees()
223 List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
224 // TODO: what if we get duplicates across repositories?
225 for ( String repoId : getObservableRepos() )
227 // TODO: what about if we want to see this irrespective of version?
228 references.addAll( metadataResolver.getProjectReferences( repoId, groupId, artifactId, version ) );
231 this.dependees = references;
233 // 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
234 // (especially in the case of pre-population import)
240 * Show the dependencies of this versioned project tab.
242 public String dependencyTree()
244 // temporarily use this as we only need the model for the tag to perform, but we should be resolving the
245 // graph here instead
247 // 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
248 // (especially in the case of pre-population import)
250 // TODO: a bit ugly, should really be mapping all these results differently now
251 this.dependencyTree = true;
257 public void validate()
259 if ( StringUtils.isBlank( groupId ) )
261 addActionError( "You must specify a group ID to browse" );
264 if ( StringUtils.isBlank( artifactId ) )
266 addActionError( "You must specify a artifact ID to browse" );
269 if ( StringUtils.isBlank( version ) )
271 addActionError( "You must specify a version to browse" );
275 public ProjectVersionMetadata getModel()
280 public String getGroupId()
285 public void setGroupId( String groupId )
287 this.groupId = groupId;
290 public String getArtifactId()
295 public void setArtifactId( String artifactId )
297 this.artifactId = artifactId;
300 public String getVersion()
305 public void setVersion( String version )
307 this.version = version;
310 public List<MailingList> getMailingLists()
315 public List<Dependency> getDependencies()
320 public List<ProjectVersionReference> getDependees()
325 public String getRepositoryId()
330 public void setRepositoryId( String repositoryId )
332 this.repositoryId = repositoryId;
335 public MetadataResolver getMetadataResolver()
337 return metadataResolver;
340 public Map<String, List<ArtifactDownloadInfo>> getArtifacts()
345 public Collection<String> getSnapshotVersions()
347 return artifacts.keySet();
350 public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
352 this.repositoryFactory = repositoryFactory;
355 public boolean isDependencyTree()
357 return dependencyTree;
360 // TODO: move this into the artifact metadata itself via facets where necessary
362 public class ArtifactDownloadInfo
366 private String namespace;
368 private String project;
374 private String repositoryId;
376 private String version;
380 public ArtifactDownloadInfo( ArtifactMetadata artifact )
382 repositoryId = artifact.getRepositoryId();
384 // TODO: use metadata resolver capability instead - maybe the storage path could be stored in the metadata
385 // though keep in mind the request may not necessarily need to reflect the storage
386 ManagedRepositoryContent repo;
389 repo = repositoryFactory.getManagedRepositoryContent( repositoryId );
391 catch ( RepositoryException e )
393 throw new RuntimeException( e );
396 ArtifactReference ref = new ArtifactReference();
397 ref.setArtifactId( artifact.getProject() );
398 ref.setGroupId( artifact.getNamespace() );
399 ref.setVersion( artifact.getVersion() );
400 path = repo.toPath( ref );
401 path = path.substring( 0, path.lastIndexOf( "/" ) + 1 ) + artifact.getId();
403 // TODO: need to accommodate Maven 1 layout too. Non-maven repository formats will need to generate this
404 // facet (perhaps on the fly) if wanting to display the Maven 2 elements on the Archiva pages
406 MavenArtifactFacet facet = (MavenArtifactFacet) artifact.getFacet( MavenArtifactFacet.FACET_ID );
409 type = facet.getType();
413 namespace = artifact.getNamespace();
414 project = artifact.getProject();
416 // TODO: find a reusable formatter for this
417 double s = artifact.getSize();
437 size = new DecimalFormat( "#,###.##" ).format( s ) + " " + symbol;
438 id = artifact.getId();
439 version = artifact.getVersion();
442 public String getNamespace()
447 public String getType()
452 public String getProject()
457 public String getSize()
462 public String getId()
467 public String getVersion()
472 public String getRepositoryId()
477 public String getPath()