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;
24 import org.apache.archiva.metadata.generic.GenericMetadataFacet;
25 import org.apache.archiva.metadata.model.ArtifactMetadata;
26 import org.apache.archiva.metadata.model.Dependency;
27 import org.apache.archiva.metadata.model.MailingList;
28 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
29 import org.apache.archiva.metadata.model.ProjectVersionReference;
30 import org.apache.archiva.metadata.repository.MetadataRepository;
31 import org.apache.archiva.metadata.repository.MetadataResolutionException;
32 import org.apache.archiva.metadata.repository.MetadataResolver;
33 import org.apache.archiva.metadata.repository.storage.maven2.MavenArtifactFacet;
34 import org.apache.commons.lang.StringUtils;
35 import org.apache.maven.archiva.model.ArtifactReference;
36 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
37 import org.apache.maven.archiva.repository.RepositoryContentFactory;
38 import org.apache.maven.archiva.repository.RepositoryException;
39 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
41 import java.text.DecimalFormat;
42 import java.util.ArrayList;
43 import java.util.Collection;
44 import java.util.Collections;
45 import java.util.Comparator;
46 import java.util.HashMap;
47 import java.util.LinkedHashMap;
48 import java.util.List;
52 * Browse the repository.
54 * TODO change name to ShowVersionedAction to conform to terminology.
56 * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="showArtifactAction"
57 * instantiation-strategy="per-lookup"
59 @SuppressWarnings( "serial" )
60 public class ShowArtifactAction
61 extends AbstractRepositoryBasedAction
62 implements Validateable
64 /* .\ Not Exposed \._____________________________________________ */
69 private MetadataResolver metadataResolver;
74 private RepositoryContentFactory repositoryFactory;
79 private MetadataRepository metadataRepository;
81 /* .\ Exposed Output Objects \.__________________________________ */
83 private String groupId;
85 private String artifactId;
87 private String version;
89 private String repositoryId;
92 * The model of this versioned project.
94 private ProjectVersionMetadata model;
97 * The list of artifacts that depend on this versioned project.
99 private List<ProjectVersionReference> dependees;
101 private List<MailingList> mailingLists;
103 private List<Dependency> dependencies;
105 private Map<String, List<ArtifactDownloadInfo>> artifacts;
107 private boolean dependencyTree = false;
109 private String deleteItem;
111 private Map<String, String> genericMetadata;
113 private String propertyName;
115 private String propertyValue;
118 * Show the versioned project information tab. TODO: Change name to 'project' - we are showing project versions
119 * here, not specific artifact information (though that is rendered in the download box).
121 public String artifact()
124 // In the future, this should be replaced by the repository grouping mechanism, so that we are only making
125 // simple resource requests here and letting the resolver take care of it
126 String errorMsg = null;
127 ProjectVersionMetadata versionMetadata = getProjectVersionMetadata();
129 if ( versionMetadata == null )
131 addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
135 if ( versionMetadata.isIncomplete() )
137 addIncompleteModelWarning();
140 model = versionMetadata;
145 private ProjectVersionMetadata getProjectVersionMetadata()
147 ProjectVersionMetadata versionMetadata = null;
148 artifacts = new LinkedHashMap<String, List<ArtifactDownloadInfo>>();
150 List<String> repos = getObservableRepos();
152 for ( String repoId : repos )
154 if ( versionMetadata == null )
156 // we don't want the implementation being that intelligent - so another resolver to do the
157 // "just-in-time" nature of picking up the metadata (if appropriate for the repository type) is used
160 versionMetadata = metadataResolver.getProjectVersion( repoId, groupId, artifactId, version );
162 catch ( MetadataResolutionException e )
164 addIncompleteModelWarning();
166 // TODO: need a consistent way to construct this - same in ArchivaMetadataCreationConsumer
167 versionMetadata = new ProjectVersionMetadata();
168 versionMetadata.setId( version );
170 if ( versionMetadata != null )
172 repositoryId = repoId;
174 List<ArtifactMetadata> artifacts =
175 new ArrayList<ArtifactMetadata>( metadataResolver.getArtifacts( repoId, groupId, artifactId,
177 Collections.sort( artifacts, new Comparator<ArtifactMetadata>()
179 public int compare( ArtifactMetadata o1, ArtifactMetadata o2 )
181 // sort by version (reverse), then ID
182 // TODO: move version sorting into repository handling (maven2 specific), and perhaps add a
183 // way to get latest instead
185 new DefaultArtifactVersion( o2.getVersion() ).compareTo( new DefaultArtifactVersion(
187 return result != 0 ? result : o1.getId().compareTo( o2.getId() );
191 for ( ArtifactMetadata artifact : artifacts )
193 List<ArtifactDownloadInfo> l = this.artifacts.get( artifact.getVersion() );
196 l = new ArrayList<ArtifactDownloadInfo>();
197 this.artifacts.put( artifact.getVersion(), l );
199 l.add( new ArtifactDownloadInfo( artifact ) );
205 return versionMetadata;
208 private void addIncompleteModelWarning()
210 addActionMessage( "The model may be incomplete due to a previous error in resolving information. Refer to the repository problem reports for more information." );
214 * Show the artifact information tab.
216 public String dependencies()
218 String result = artifact();
220 this.dependencies = model.getDependencies();
226 * Show the mailing lists information tab.
228 public String mailingLists()
230 String result = artifact();
232 this.mailingLists = model.getMailingLists();
238 * Show the reports tab.
240 public String reports()
242 // TODO: hook up reports on project
248 * Show the dependees (other artifacts that depend on this project) tab.
250 public String dependees()
252 List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
253 // TODO: what if we get duplicates across repositories?
254 for ( String repoId : getObservableRepos() )
256 // TODO: what about if we want to see this irrespective of version?
257 references.addAll( metadataResolver.getProjectReferences( repoId, groupId, artifactId, version ) );
260 this.dependees = references;
262 // TODO: may need to note on the page that references will be incomplete if the other artifacts are not yet
263 // stored in the content repository
264 // (especially in the case of pre-population import)
270 * Show the dependencies of this versioned project tab.
272 public String dependencyTree()
274 // temporarily use this as we only need the model for the tag to perform, but we should be resolving the
275 // graph here instead
277 // TODO: may need to note on the page that tree will be incomplete if the other artifacts are not yet stored in
278 // the content repository
279 // (especially in the case of pre-population import)
281 // TODO: a bit ugly, should really be mapping all these results differently now
282 this.dependencyTree = true;
287 public String projectMetadata()
289 String result = artifact();
291 if ( model.getFacet( GenericMetadataFacet.FACET_ID ) != null )
293 genericMetadata = model.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
296 if ( genericMetadata == null )
298 genericMetadata = new HashMap<String, String>();
304 public String addMetadataProperty()
306 String errorMsg = null;
308 ProjectVersionMetadata projectMetadata = getProjectVersionMetadata();
309 if ( projectMetadata == null )
311 addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
315 if ( projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ) == null )
317 genericMetadata = new HashMap<String, String>();
321 genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
324 if ( propertyName == null || "".equals( propertyName.trim() ) || propertyValue == null ||
325 "".equals( propertyValue.trim() ) )
327 model = projectMetadata;
328 addActionError( errorMsg != null ? errorMsg : "Property Name and Property Value are required." );
332 genericMetadata.put( propertyName, propertyValue );
334 updateProjectMetadata( projectMetadata );
336 projectMetadata = getProjectVersionMetadata();
338 genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
340 model = projectMetadata;
348 public String deleteMetadataEntry()
350 ProjectVersionMetadata projectMetadata = getProjectVersionMetadata();
351 String errorMsg = null;
353 if ( projectMetadata == null )
355 addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
359 if ( projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ) != null )
361 genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
363 if ( !StringUtils.isEmpty( deleteItem ) )
365 genericMetadata.remove( deleteItem );
367 updateProjectMetadata( projectMetadata );
369 projectMetadata = getProjectVersionMetadata();
371 genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
373 model = projectMetadata;
375 addActionMessage( "Property successfully deleted." );
382 addActionError( errorMsg != null ? errorMsg : "No generic metadata facet for this artifact." );
389 private void updateProjectMetadata( ProjectVersionMetadata projectMetadata )
391 GenericMetadataFacet genericMetadataFacet = new GenericMetadataFacet();
392 genericMetadataFacet.fromProperties( genericMetadata );
394 projectMetadata.addFacet( genericMetadataFacet );
396 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
400 public void validate()
402 if ( StringUtils.isBlank( groupId ) )
404 addActionError( "You must specify a group ID to browse" );
407 if ( StringUtils.isBlank( artifactId ) )
409 addActionError( "You must specify a artifact ID to browse" );
412 if ( StringUtils.isBlank( version ) )
414 addActionError( "You must specify a version to browse" );
418 public ProjectVersionMetadata getModel()
423 public String getGroupId()
428 public void setGroupId( String groupId )
430 this.groupId = groupId;
433 public String getArtifactId()
438 public void setArtifactId( String artifactId )
440 this.artifactId = artifactId;
443 public String getVersion()
448 public void setVersion( String version )
450 this.version = version;
453 public List<MailingList> getMailingLists()
458 public List<Dependency> getDependencies()
463 public List<ProjectVersionReference> getDependees()
468 public String getRepositoryId()
473 public void setRepositoryId( String repositoryId )
475 this.repositoryId = repositoryId;
478 public MetadataResolver getMetadataResolver()
480 return metadataResolver;
483 public Map<String, List<ArtifactDownloadInfo>> getArtifacts()
488 public Collection<String> getSnapshotVersions()
490 return artifacts.keySet();
493 public boolean isDependencyTree()
495 return dependencyTree;
498 public void setDeleteItem( String deleteItem )
500 this.deleteItem = deleteItem;
503 public Map<String, String> getGenericMetadata()
505 return genericMetadata;
508 public void setGenericMetadata( Map<String, String> genericMetadata )
510 this.genericMetadata = genericMetadata;
513 public String getPropertyName()
518 public void setPropertyName( String propertyName )
520 this.propertyName = propertyName;
523 public String getPropertyValue()
525 return propertyValue;
528 public void setPropertyValue( String propertyValue )
530 this.propertyValue = propertyValue;
533 public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
535 this.repositoryFactory = repositoryFactory;
538 public void setMetadataRepository( MetadataRepository metadataRepository )
540 this.metadataRepository = metadataRepository;
543 // TODO: move this into the artifact metadata itself via facets where necessary
545 public class ArtifactDownloadInfo
549 private String namespace;
551 private String project;
557 private String repositoryId;
559 private String version;
563 public ArtifactDownloadInfo( ArtifactMetadata artifact )
565 repositoryId = artifact.getRepositoryId();
567 // TODO: use metadata resolver capability instead - maybe the storage path could be stored in the metadata
568 // though keep in mind the request may not necessarily need to reflect the storage
569 ManagedRepositoryContent repo;
572 repo = repositoryFactory.getManagedRepositoryContent( repositoryId );
574 catch ( RepositoryException e )
576 throw new RuntimeException( e );
579 ArtifactReference ref = new ArtifactReference();
580 ref.setArtifactId( artifact.getProject() );
581 ref.setGroupId( artifact.getNamespace() );
582 ref.setVersion( artifact.getVersion() );
583 path = repo.toPath( ref );
584 path = path.substring( 0, path.lastIndexOf( "/" ) + 1 ) + artifact.getId();
586 // TODO: need to accommodate Maven 1 layout too. Non-maven repository formats will need to generate this
587 // facet (perhaps on the fly) if wanting to display the Maven 2 elements on the Archiva pages
589 MavenArtifactFacet facet = (MavenArtifactFacet) artifact.getFacet( MavenArtifactFacet.FACET_ID );
592 type = facet.getType();
596 namespace = artifact.getNamespace();
597 project = artifact.getProject();
599 // TODO: find a reusable formatter for this
600 double s = artifact.getSize();
620 size = new DecimalFormat( "#,###.##" ).format( s ) + " " + symbol;
621 id = artifact.getId();
622 version = artifact.getVersion();
625 public String getNamespace()
630 public String getType()
635 public String getProject()
640 public String getSize()
645 public String getId()
650 public String getVersion()
655 public String getRepositoryId()
660 public String getPath()