1 package org.apache.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.generic.GenericMetadataFacet;
24 import org.apache.archiva.metadata.model.ArtifactMetadata;
25 import org.apache.archiva.metadata.model.Dependency;
26 import org.apache.archiva.metadata.model.MailingList;
27 import org.apache.archiva.metadata.model.MetadataFacet;
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.MetadataRepositoryException;
32 import org.apache.archiva.metadata.repository.MetadataResolutionException;
33 import org.apache.archiva.metadata.repository.MetadataResolver;
34 import org.apache.archiva.metadata.repository.RepositorySession;
35 import org.apache.archiva.reports.RepositoryProblemFacet;
36 import org.apache.archiva.repository.RepositoryContentFactory;
37 import org.apache.archiva.repository.RepositoryException;
38 import org.apache.archiva.repository.RepositoryNotFoundException;
39 import org.apache.archiva.rest.api.model.ArtifactDownloadInfo;
40 import org.apache.archiva.rest.services.utils.ArtifactDownloadInfoBuilder;
41 import org.apache.commons.lang.StringUtils;
42 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
43 import org.springframework.context.annotation.Scope;
44 import org.springframework.stereotype.Controller;
46 import javax.inject.Inject;
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.Collections;
50 import java.util.Comparator;
51 import java.util.HashMap;
52 import java.util.LinkedHashMap;
53 import java.util.List;
57 * Browse the repository.
59 * TODO change name to ShowVersionedAction to conform to terminology.
61 @SuppressWarnings( "serial" )
62 @Controller( "showArtifactAction" )
64 public class ShowArtifactAction
65 extends AbstractRepositoryBasedAction
66 implements Validateable
68 /* .\ Not Exposed \._____________________________________________ */
71 private RepositoryContentFactory repositoryFactory;
73 /* .\ Exposed Output Objects \.__________________________________ */
75 private String groupId;
77 private String artifactId;
79 private String version;
81 private String repositoryId;
84 * The model of this versioned project.
86 private ProjectVersionMetadata model;
89 * The list of artifacts that depend on this versioned project.
91 private List<ProjectVersionReference> dependees;
93 private List<MailingList> mailingLists;
95 private List<Dependency> dependencies;
97 private Map<String, List<ArtifactDownloadInfo>> artifacts;
99 private boolean dependencyTree = false;
101 private String deleteItem;
103 private Map<String, String> genericMetadata;
105 private String propertyName;
107 private String propertyValue;
110 * Show the versioned project information tab. TODO: Change name to 'project' - we are showing project versions
111 * here, not specific artifact information (though that is rendered in the download box).
113 public String artifact()
115 RepositorySession repositorySession = repositorySessionFactory.createSession();
118 return handleArtifact( repositorySession );
120 catch ( Exception e )
122 log.warn( "Unable to getProjectVersionMetadata: " + e.getMessage(), e );
123 addActionError( "Unable to getProjectVersionMetadata - consult application logs." );
129 repositorySession.close();
134 private String handleArtifact( RepositorySession session )
135 throws RepositoryNotFoundException, RepositoryException
137 // In the future, this should be replaced by the repository grouping mechanism, so that we are only making
138 // simple resource requests here and letting the resolver take care of it
139 ProjectVersionMetadata versionMetadata = getProjectVersionMetadata( session );
141 if ( versionMetadata == null )
143 addActionError( "Artifact not found" );
147 if ( versionMetadata.isIncomplete() )
149 addIncompleteModelWarning( "Artifact metadata is incomplete." );
152 model = versionMetadata;
157 private ProjectVersionMetadata getProjectVersionMetadata( RepositorySession session )
158 throws RepositoryNotFoundException, RepositoryException
160 ProjectVersionMetadata versionMetadata = null;
161 artifacts = new LinkedHashMap<String, List<ArtifactDownloadInfo>>();
163 List<String> repos = getObservableRepos();
165 MetadataResolver metadataResolver = session.getResolver();
166 for ( String repoId : repos )
168 if ( versionMetadata == null )
170 // we don't want the implementation being that intelligent - so another resolver to do the
171 // "just-in-time" nature of picking up the metadata (if appropriate for the repository type) is used
175 metadataResolver.resolveProjectVersion( session, repoId, groupId, artifactId, version );
176 if ( versionMetadata != null )
178 MetadataFacet repoProbFacet;
179 if ( ( repoProbFacet = versionMetadata.getFacet( RepositoryProblemFacet.FACET_ID ) ) != null )
181 addIncompleteModelWarning( "Artifact metadata is incomplete: "
182 + ( (RepositoryProblemFacet) repoProbFacet ).getProblem() );
183 //set metadata to complete so that no additional 'Artifact metadata is incomplete' warning is logged
184 versionMetadata.setIncomplete( false );
189 catch ( MetadataResolutionException e )
191 addIncompleteModelWarning( "Error resolving artifact metadata: " + e.getMessage() );
193 // TODO: need a consistent way to construct this - same in ArchivaMetadataCreationConsumer
194 versionMetadata = new ProjectVersionMetadata();
195 versionMetadata.setId( version );
197 if ( versionMetadata != null )
199 repositoryId = repoId;
201 List<ArtifactMetadata> artifacts;
204 artifacts = new ArrayList<ArtifactMetadata>(
205 metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
207 catch ( MetadataResolutionException e )
209 addIncompleteModelWarning( "Error resolving artifact metadata: " + e.getMessage() );
210 artifacts = Collections.emptyList();
212 Collections.sort( artifacts, new Comparator<ArtifactMetadata>()
214 public int compare( ArtifactMetadata o1, ArtifactMetadata o2 )
216 // sort by version (reverse), then ID
217 // TODO: move version sorting into repository handling (maven2 specific), and perhaps add a
218 // way to get latest instead
219 int result = new DefaultArtifactVersion( o2.getVersion() ).compareTo(
220 new DefaultArtifactVersion( o1.getVersion() ) );
221 return result != 0 ? result : o1.getId().compareTo( o2.getId() );
225 for ( ArtifactMetadata artifact : artifacts )
227 List<ArtifactDownloadInfo> l = this.artifacts.get( artifact.getVersion() );
230 l = new ArrayList<ArtifactDownloadInfo>();
231 this.artifacts.put( artifact.getVersion(), l );
233 ArtifactDownloadInfoBuilder builder = new ArtifactDownloadInfoBuilder().forArtifactMetadata(
234 artifact ).withManagedRepositoryContent(
235 repositoryFactory.getManagedRepositoryContent( repositoryId ) );
236 l.add( builder.build() );
242 return versionMetadata;
245 private void addIncompleteModelWarning( String warningMessage )
247 addActionError( warningMessage );
248 //"The model may be incomplete due to a previous error in resolving information. Refer to the repository problem reports for more information." );
252 * Show the artifact information tab.
254 public String dependencies()
256 String result = artifact();
258 this.dependencies = model.getDependencies();
264 * Show the mailing lists information tab.
266 public String mailingLists()
268 String result = artifact();
270 this.mailingLists = model.getMailingLists();
276 * Show the reports tab.
278 public String reports()
280 // TODO: hook up reports on project
286 * Show the dependees (other artifacts that depend on this project) tab.
288 public String dependees()
289 throws MetadataResolutionException
291 List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
292 // TODO: what if we get duplicates across repositories?
293 RepositorySession repositorySession = repositorySessionFactory.createSession();
296 MetadataResolver metadataResolver = repositorySession.getResolver();
297 for ( String repoId : getObservableRepos() )
299 // TODO: what about if we want to see this irrespective of version?
301 metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
307 repositorySession.close();
310 this.dependees = references;
312 // TODO: may need to note on the page that references will be incomplete if the other artifacts are not yet
313 // stored in the content repository
314 // (especially in the case of pre-population import)
320 * Show the dependencies of this versioned project tab.
322 public String dependencyTree()
324 // temporarily use this as we only need the model for the tag to perform, but we should be resolving the
325 // graph here instead
327 // TODO: may need to note on the page that tree will be incomplete if the other artifacts are not yet stored in
328 // the content repository
329 // (especially in the case of pre-population import)
331 // TODO: a bit ugly, should really be mapping all these results differently now
332 this.dependencyTree = true;
337 public String projectMetadata()
339 String result = artifact();
341 if ( model.getFacet( GenericMetadataFacet.FACET_ID ) != null )
343 genericMetadata = model.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
346 if ( genericMetadata == null )
348 genericMetadata = new HashMap<String, String>();
354 public String addMetadataProperty()
356 RepositorySession repositorySession = repositorySessionFactory.createSession();
357 ProjectVersionMetadata projectMetadata;
360 MetadataRepository metadataRepository = repositorySession.getRepository();
361 projectMetadata = getProjectVersionMetadata( repositorySession );
362 if ( projectMetadata == null )
364 addActionError( "Artifact not found" );
368 if ( projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ) == null )
370 genericMetadata = new HashMap<String, String>();
374 genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
377 if ( propertyName == null || "".equals( propertyName.trim() ) || propertyValue == null || "".equals(
378 propertyValue.trim() ) )
380 model = projectMetadata;
381 addActionError( "Property Name and Property Value are required." );
385 genericMetadata.put( propertyName, propertyValue );
389 updateProjectMetadata( projectMetadata, metadataRepository );
390 repositorySession.save();
392 catch ( MetadataRepositoryException e )
394 log.warn( "Unable to persist modified project metadata after adding entry: " + e.getMessage(), e );
396 "Unable to add metadata item to underlying content storage - consult application logs." );
400 // TODO: why re-retrieve?
401 projectMetadata = getProjectVersionMetadata( repositorySession );
403 catch ( Exception e )
405 log.warn( "Unable to getProjectVersionMetadata: " + e.getMessage(), e );
406 addActionError( "Unable to getProjectVersionMetadata - consult application logs." );
411 repositorySession.close();
414 genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
416 model = projectMetadata;
424 public String deleteMetadataEntry()
426 RepositorySession repositorySession = repositorySessionFactory.createSession();
429 MetadataRepository metadataRepository = repositorySession.getRepository();
430 ProjectVersionMetadata projectMetadata = getProjectVersionMetadata( repositorySession );
432 if ( projectMetadata == null )
434 addActionError( "Artifact not found" );
438 if ( projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ) != null )
440 genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
442 if ( !StringUtils.isEmpty( deleteItem ) )
444 genericMetadata.remove( deleteItem );
448 updateProjectMetadata( projectMetadata, metadataRepository );
449 repositorySession.save();
451 catch ( MetadataRepositoryException e )
453 log.warn( "Unable to persist modified project metadata after removing entry: " + e.getMessage(),
456 "Unable to remove metadata item to underlying content storage - consult application logs." );
460 // TODO: why re-retrieve?
461 projectMetadata = getProjectVersionMetadata( repositorySession );
463 genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
465 model = projectMetadata;
467 addActionMessage( "Property successfully deleted." );
474 addActionError( "No generic metadata facet for this artifact." );
478 catch ( Exception e )
480 log.warn( "Unable to getProjectVersionMetadata: " + e.getMessage(), e );
481 addActionError( "Unable to getProjectVersionMetadata - consult application logs." );
487 repositorySession.close();
493 private void updateProjectMetadata( ProjectVersionMetadata projectMetadata, MetadataRepository metadataRepository )
494 throws MetadataRepositoryException
496 GenericMetadataFacet genericMetadataFacet = new GenericMetadataFacet();
497 genericMetadataFacet.fromProperties( genericMetadata );
499 projectMetadata.addFacet( genericMetadataFacet );
501 metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
505 public void validate()
507 if ( StringUtils.isBlank( groupId ) )
509 addActionError( "You must specify a group ID to browse" );
512 if ( StringUtils.isBlank( artifactId ) )
514 addActionError( "You must specify a artifact ID to browse" );
517 if ( StringUtils.isBlank( version ) )
519 addActionError( "You must specify a version to browse" );
523 public ProjectVersionMetadata getModel()
528 public String getGroupId()
533 public void setGroupId( String groupId )
535 this.groupId = groupId;
538 public String getArtifactId()
543 public void setArtifactId( String artifactId )
545 this.artifactId = artifactId;
548 public String getVersion()
553 public void setVersion( String version )
555 this.version = version;
558 public List<MailingList> getMailingLists()
563 public List<Dependency> getDependencies()
568 public List<ProjectVersionReference> getDependees()
573 public String getRepositoryId()
578 public void setRepositoryId( String repositoryId )
580 this.repositoryId = repositoryId;
583 public Map<String, List<ArtifactDownloadInfo>> getArtifacts()
588 public Collection<String> getSnapshotVersions()
590 return artifacts.keySet();
593 public boolean isDependencyTree()
595 return dependencyTree;
598 public void setDeleteItem( String deleteItem )
600 this.deleteItem = deleteItem;
603 public Map<String, String> getGenericMetadata()
605 return genericMetadata;
608 public void setGenericMetadata( Map<String, String> genericMetadata )
610 this.genericMetadata = genericMetadata;
613 public String getPropertyName()
618 public void setPropertyName( String propertyName )
620 this.propertyName = propertyName;
623 public String getPropertyValue()
625 return propertyValue;
628 public void setPropertyValue( String propertyValue )
630 this.propertyValue = propertyValue;
633 public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
635 this.repositoryFactory = repositoryFactory;