]> source.dussan.org Git - archiva.git/blob
5e09669e9a86c87c75376249916b62476cd78a8b
[archiva.git] /
1 package org.apache.archiva.web.action;
2
3 /*
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
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
21
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.metadata.repository.storage.maven2.ArtifactMetadataVersionComparator;
36 import org.apache.archiva.reports.RepositoryProblemFacet;
37 import org.apache.archiva.repository.RepositoryContentFactory;
38 import org.apache.archiva.repository.RepositoryException;
39 import org.apache.archiva.repository.RepositoryNotFoundException;
40 import org.apache.archiva.rest.api.model.Artifact;
41 import org.apache.archiva.rest.services.utils.ArtifactDownloadInfoBuilder;
42 import org.apache.commons.lang.StringUtils;
43 import org.springframework.context.annotation.Scope;
44 import org.springframework.stereotype.Controller;
45
46 import javax.inject.Inject;
47 import java.util.ArrayList;
48 import java.util.Collection;
49 import java.util.Collections;
50 import java.util.HashMap;
51 import java.util.LinkedHashMap;
52 import java.util.List;
53 import java.util.Map;
54
55 /**
56  * Browse the repository.
57  * <p/>
58  * TODO change name to ShowVersionedAction to conform to terminology.
59  */
60 @SuppressWarnings( "serial" )
61 @Controller( "showArtifactAction" )
62 @Scope( "prototype" )
63 public class ShowArtifactAction
64     extends AbstractRepositoryBasedAction
65     implements Validateable
66 {
67     /* .\ Not Exposed \._____________________________________________ */
68
69     @Inject
70     private RepositoryContentFactory repositoryFactory;
71
72     /* .\ Exposed Output Objects \.__________________________________ */
73
74     private String groupId;
75
76     private String artifactId;
77
78     private String version;
79
80     private String repositoryId;
81
82     /**
83      * The model of this versioned project.
84      */
85     private ProjectVersionMetadata model;
86
87     /**
88      * The list of artifacts that depend on this versioned project.
89      */
90     private List<ProjectVersionReference> dependees;
91
92     private List<MailingList> mailingLists;
93
94     private List<Dependency> dependencies;
95
96     private Map<String, List<Artifact>> artifacts;
97
98     private boolean dependencyTree = false;
99
100     private String deleteItem;
101
102     private Map<String, String> genericMetadata;
103
104     private String propertyName;
105
106     private String propertyValue;
107
108     /**
109      * Show the versioned project information tab. TODO: Change name to 'project' - we are showing project versions
110      * here, not specific artifact information (though that is rendered in the download box).
111      */
112     public String artifact()
113     {
114         RepositorySession repositorySession = repositorySessionFactory.createSession();
115         try
116         {
117             return handleArtifact( repositorySession );
118         }
119         catch ( Exception e )
120         {
121             log.warn( "Unable to getProjectVersionMetadata: " + e.getMessage(), e );
122             addActionError( "Unable to getProjectVersionMetadata - consult application logs." );
123             return ERROR;
124         }
125         finally
126
127         {
128             repositorySession.close();
129         }
130
131     }
132
133     private String handleArtifact( RepositorySession session )
134         throws RepositoryNotFoundException, RepositoryException
135     {
136         // In the future, this should be replaced by the repository grouping mechanism, so that we are only making
137         // simple resource requests here and letting the resolver take care of it
138         ProjectVersionMetadata versionMetadata = getProjectVersionMetadata( session );
139
140         if ( versionMetadata == null )
141         {
142             addActionError( "Artifact not found" );
143             return ERROR;
144         }
145
146         if ( versionMetadata.isIncomplete() )
147         {
148             addIncompleteModelWarning( "Artifact metadata is incomplete." );
149         }
150
151         model = versionMetadata;
152
153         return SUCCESS;
154     }
155
156     private ProjectVersionMetadata getProjectVersionMetadata( RepositorySession session )
157         throws RepositoryNotFoundException, RepositoryException
158     {
159         ProjectVersionMetadata versionMetadata = null;
160         artifacts = new LinkedHashMap<String, List<Artifact>>();
161
162         List<String> repos = getObservableRepos();
163
164         MetadataResolver metadataResolver = session.getResolver();
165         for ( String repoId : repos )
166         {
167             if ( versionMetadata == null )
168             {
169                 // we don't want the implementation being that intelligent - so another resolver to do the
170                 // "just-in-time" nature of picking up the metadata (if appropriate for the repository type) is used
171                 try
172                 {
173                     versionMetadata =
174                         metadataResolver.resolveProjectVersion( session, repoId, groupId, artifactId, version );
175                     if ( versionMetadata != null )
176                     {
177                         MetadataFacet repoProbFacet;
178                         if ( ( repoProbFacet = versionMetadata.getFacet( RepositoryProblemFacet.FACET_ID ) ) != null )
179                         {
180                             addIncompleteModelWarning( "Artifact metadata is incomplete: "
181                                                            + ( (RepositoryProblemFacet) repoProbFacet ).getProblem() );
182                             //set metadata to complete so that no additional 'Artifact metadata is incomplete' warning is logged
183                             versionMetadata.setIncomplete( false );
184                         }
185                     }
186
187                 }
188                 catch ( MetadataResolutionException e )
189                 {
190                     addIncompleteModelWarning( "Error resolving artifact metadata: " + e.getMessage() );
191
192                     // TODO: need a consistent way to construct this - same in ArchivaMetadataCreationConsumer
193                     versionMetadata = new ProjectVersionMetadata();
194                     versionMetadata.setId( version );
195                 }
196                 if ( versionMetadata != null )
197                 {
198                     repositoryId = repoId;
199
200                     List<ArtifactMetadata> artifacts;
201                     try
202                     {
203                         artifacts = new ArrayList<ArtifactMetadata>(
204                             metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
205                     }
206                     catch ( MetadataResolutionException e )
207                     {
208                         addIncompleteModelWarning( "Error resolving artifact metadata: " + e.getMessage() );
209                         artifacts = Collections.emptyList();
210                     }
211                     Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
212
213                     for ( ArtifactMetadata artifact : artifacts )
214                     {
215                         List<Artifact> l = this.artifacts.get( artifact.getVersion() );
216                         if ( l == null )
217                         {
218                             l = new ArrayList<Artifact>();
219                             this.artifacts.put( artifact.getVersion(), l );
220                         }
221
222                         ArtifactDownloadInfoBuilder builder = new ArtifactDownloadInfoBuilder().forArtifactMetadata(
223                             artifact ).withManagedRepositoryContent(
224                             repositoryFactory.getManagedRepositoryContent( repositoryId ) );
225                         l.add( builder.build() );
226                     }
227                 }
228             }
229         }
230
231         return versionMetadata;
232     }
233
234     private void addIncompleteModelWarning( String warningMessage )
235     {
236         addActionError( warningMessage );
237         //"The model may be incomplete due to a previous error in resolving information. Refer to the repository problem reports for more information." );
238     }
239
240     /**
241      * Show the artifact information tab.
242      */
243     public String dependencies()
244     {
245         String result = artifact();
246
247         this.dependencies = model.getDependencies();
248
249         return result;
250     }
251
252     /**
253      * Show the mailing lists information tab.
254      */
255     public String mailingLists()
256     {
257         String result = artifact();
258
259         this.mailingLists = model.getMailingLists();
260
261         return result;
262     }
263
264     /**
265      * Show the reports tab.
266      */
267     public String reports()
268     {
269         // TODO: hook up reports on project
270
271         return SUCCESS;
272     }
273
274     /**
275      * Show the dependees (other artifacts that depend on this project) tab.
276      */
277     public String dependees()
278         throws MetadataResolutionException
279     {
280         List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
281         // TODO: what if we get duplicates across repositories?
282         RepositorySession repositorySession = repositorySessionFactory.createSession();
283         try
284         {
285             MetadataResolver metadataResolver = repositorySession.getResolver();
286             for ( String repoId : getObservableRepos() )
287             {
288                 // TODO: what about if we want to see this irrespective of version?
289                 references.addAll(
290                     metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
291                                                                version ) );
292             }
293         }
294         finally
295         {
296             repositorySession.close();
297         }
298
299         this.dependees = references;
300
301         // TODO: may need to note on the page that references will be incomplete if the other artifacts are not yet
302         // stored in the content repository
303         // (especially in the case of pre-population import)
304
305         return artifact();
306     }
307
308     /**
309      * Show the dependencies of this versioned project tab.
310      */
311     public String dependencyTree()
312     {
313         // temporarily use this as we only need the model for the tag to perform, but we should be resolving the
314         // graph here instead
315
316         // TODO: may need to note on the page that tree will be incomplete if the other artifacts are not yet stored in
317         // the content repository
318         // (especially in the case of pre-population import)
319
320         // TODO: a bit ugly, should really be mapping all these results differently now
321         this.dependencyTree = true;
322
323         return artifact();
324     }
325
326     public String projectMetadata()
327     {
328         String result = artifact();
329
330         if ( model.getFacet( GenericMetadataFacet.FACET_ID ) != null )
331         {
332             genericMetadata = model.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
333         }
334
335         if ( genericMetadata == null )
336         {
337             genericMetadata = new HashMap<String, String>();
338         }
339
340         return result;
341     }
342
343     public String addMetadataProperty()
344     {
345         RepositorySession repositorySession = repositorySessionFactory.createSession();
346         ProjectVersionMetadata projectMetadata;
347         try
348         {
349             MetadataRepository metadataRepository = repositorySession.getRepository();
350             projectMetadata = getProjectVersionMetadata( repositorySession );
351             if ( projectMetadata == null )
352             {
353                 addActionError( "Artifact not found" );
354                 return ERROR;
355             }
356
357             if ( projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ) == null )
358             {
359                 genericMetadata = new HashMap<String, String>();
360             }
361             else
362             {
363                 genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
364             }
365
366             if ( propertyName == null || "".equals( propertyName.trim() ) || propertyValue == null || "".equals(
367                 propertyValue.trim() ) )
368             {
369                 model = projectMetadata;
370                 addActionError( "Property Name and Property Value are required." );
371                 return INPUT;
372             }
373
374             genericMetadata.put( propertyName, propertyValue );
375
376             try
377             {
378                 updateProjectMetadata( projectMetadata, metadataRepository );
379                 repositorySession.save();
380             }
381             catch ( MetadataRepositoryException e )
382             {
383                 log.warn( "Unable to persist modified project metadata after adding entry: " + e.getMessage(), e );
384                 addActionError(
385                     "Unable to add metadata item to underlying content storage - consult application logs." );
386                 return ERROR;
387             }
388
389             // TODO: why re-retrieve?
390             projectMetadata = getProjectVersionMetadata( repositorySession );
391         }
392         catch ( Exception e )
393         {
394             log.warn( "Unable to getProjectVersionMetadata: " + e.getMessage(), e );
395             addActionError( "Unable to getProjectVersionMetadata - consult application logs." );
396             return ERROR;
397         }
398         finally
399         {
400             repositorySession.close();
401         }
402
403         genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
404
405         model = projectMetadata;
406
407         propertyName = "";
408         propertyValue = "";
409
410         return SUCCESS;
411     }
412
413     public String deleteMetadataEntry()
414     {
415         RepositorySession repositorySession = repositorySessionFactory.createSession();
416         try
417         {
418             MetadataRepository metadataRepository = repositorySession.getRepository();
419             ProjectVersionMetadata projectMetadata = getProjectVersionMetadata( repositorySession );
420
421             if ( projectMetadata == null )
422             {
423                 addActionError( "Artifact not found" );
424                 return ERROR;
425             }
426
427             if ( projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ) != null )
428             {
429                 genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
430
431                 if ( !StringUtils.isEmpty( deleteItem ) )
432                 {
433                     genericMetadata.remove( deleteItem );
434
435                     try
436                     {
437                         updateProjectMetadata( projectMetadata, metadataRepository );
438                         repositorySession.save();
439                     }
440                     catch ( MetadataRepositoryException e )
441                     {
442                         log.warn( "Unable to persist modified project metadata after removing entry: " + e.getMessage(),
443                                   e );
444                         addActionError(
445                             "Unable to remove metadata item to underlying content storage - consult application logs." );
446                         return ERROR;
447                     }
448
449                     // TODO: why re-retrieve?
450                     projectMetadata = getProjectVersionMetadata( repositorySession );
451
452                     genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
453
454                     model = projectMetadata;
455
456                     addActionMessage( "Property successfully deleted." );
457                 }
458
459                 deleteItem = "";
460             }
461             else
462             {
463                 addActionError( "No generic metadata facet for this artifact." );
464                 return ERROR;
465             }
466         }
467         catch ( Exception e )
468         {
469             log.warn( "Unable to getProjectVersionMetadata: " + e.getMessage(), e );
470             addActionError( "Unable to getProjectVersionMetadata - consult application logs." );
471             return ERROR;
472
473         }
474         finally
475         {
476             repositorySession.close();
477         }
478
479         return SUCCESS;
480     }
481
482     private void updateProjectMetadata( ProjectVersionMetadata projectMetadata, MetadataRepository metadataRepository )
483         throws MetadataRepositoryException
484     {
485         GenericMetadataFacet genericMetadataFacet = new GenericMetadataFacet();
486         genericMetadataFacet.fromProperties( genericMetadata );
487
488         projectMetadata.addFacet( genericMetadataFacet );
489
490         metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
491     }
492
493     @Override
494     public void validate()
495     {
496         if ( StringUtils.isBlank( groupId ) )
497         {
498             addActionError( "You must specify a group ID to browse" );
499         }
500
501         if ( StringUtils.isBlank( artifactId ) )
502         {
503             addActionError( "You must specify a artifact ID to browse" );
504         }
505
506         if ( StringUtils.isBlank( version ) )
507         {
508             addActionError( "You must specify a version to browse" );
509         }
510     }
511
512     public ProjectVersionMetadata getModel()
513     {
514         return model;
515     }
516
517     public String getGroupId()
518     {
519         return groupId;
520     }
521
522     public void setGroupId( String groupId )
523     {
524         this.groupId = groupId;
525     }
526
527     public String getArtifactId()
528     {
529         return artifactId;
530     }
531
532     public void setArtifactId( String artifactId )
533     {
534         this.artifactId = artifactId;
535     }
536
537     public String getVersion()
538     {
539         return version;
540     }
541
542     public void setVersion( String version )
543     {
544         this.version = version;
545     }
546
547     public List<MailingList> getMailingLists()
548     {
549         return mailingLists;
550     }
551
552     public List<Dependency> getDependencies()
553     {
554         return dependencies;
555     }
556
557     public List<ProjectVersionReference> getDependees()
558     {
559         return dependees;
560     }
561
562     public String getRepositoryId()
563     {
564         return repositoryId;
565     }
566
567     public void setRepositoryId( String repositoryId )
568     {
569         this.repositoryId = repositoryId;
570     }
571
572     public Map<String, List<Artifact>> getArtifacts()
573     {
574         return artifacts;
575     }
576
577     public Collection<String> getSnapshotVersions()
578     {
579         return artifacts.keySet();
580     }
581
582     public boolean isDependencyTree()
583     {
584         return dependencyTree;
585     }
586
587     public void setDeleteItem( String deleteItem )
588     {
589         this.deleteItem = deleteItem;
590     }
591
592     public Map<String, String> getGenericMetadata()
593     {
594         return genericMetadata;
595     }
596
597     public void setGenericMetadata( Map<String, String> genericMetadata )
598     {
599         this.genericMetadata = genericMetadata;
600     }
601
602     public String getPropertyName()
603     {
604         return propertyName;
605     }
606
607     public void setPropertyName( String propertyName )
608     {
609         this.propertyName = propertyName;
610     }
611
612     public String getPropertyValue()
613     {
614         return propertyValue;
615     }
616
617     public void setPropertyValue( String propertyValue )
618     {
619         this.propertyValue = propertyValue;
620     }
621
622     public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
623     {
624         this.repositoryFactory = repositoryFactory;
625     }
626
627
628 }