]> source.dussan.org Git - archiva.git/blob
eed67d57171f1f6e163f46ba369b2e890c9f4e2e
[archiva.git] /
1 package org.apache.maven.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
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.License;
28 import org.apache.archiva.metadata.model.MailingList;
29 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
30 import org.apache.archiva.metadata.model.ProjectVersionReference;
31 import org.apache.archiva.metadata.repository.MetadataRepository;
32 import org.apache.archiva.metadata.repository.MetadataResolutionException;
33 import org.apache.archiva.metadata.repository.MetadataResolver;
34 import org.apache.archiva.metadata.repository.storage.maven2.MavenArtifactFacet;
35 import org.apache.commons.lang.StringUtils;
36 import org.apache.maven.archiva.model.ArtifactReference;
37 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
38 import org.apache.maven.archiva.repository.RepositoryContentFactory;
39 import org.apache.maven.archiva.repository.RepositoryException;
40 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
41
42 import java.text.DecimalFormat;
43 import java.util.ArrayList;
44 import java.util.Collection;
45 import java.util.Collections;
46 import java.util.Comparator;
47 import java.util.HashMap;
48 import java.util.LinkedHashMap;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.TreeMap;
52
53 /**
54  * Browse the repository.
55  *
56  * TODO change name to ShowVersionedAction to conform to terminology.
57  *
58  * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="showArtifactAction" instantiation-strategy="per-lookup"
59  */
60 public class ShowArtifactAction
61     extends AbstractRepositoryBasedAction
62     implements Validateable
63 {
64     /* .\ Not Exposed \._____________________________________________ */
65
66     /**
67      * @plexus.requirement
68      */
69     private MetadataResolver metadataResolver;
70
71     /**
72      * @plexus.requirement
73      */
74     private RepositoryContentFactory repositoryFactory;
75
76     /**
77      * @plexus.requirement
78      */
79     private MetadataRepository metadataRepository;
80
81     /* .\ Exposed Output Objects \.__________________________________ */
82
83     private String groupId;
84
85     private String artifactId;
86
87     private String version;
88
89     private String repositoryId;
90
91     /**
92      * The model of this versioned project.
93      */
94     private ProjectVersionMetadata model;
95
96     /**
97      * The list of artifacts that depend on this versioned project.
98      */
99     private List<ProjectVersionReference> dependees;
100
101     private List<MailingList> mailingLists;
102
103     private List<Dependency> dependencies;
104
105     private Map<String, List<ArtifactDownloadInfo>> artifacts;
106
107     private boolean dependencyTree = false;
108
109     private ProjectVersionMetadata projectMetadata;
110     
111     private String deleteItem;
112     
113     private String itemValue;
114     
115     private Map<String, String> genericMetadata;
116     
117     private String propertyName;
118
119     private String propertyValue;
120    
121     
122     /**
123      * Show the versioned project information tab.
124      * TODO: Change name to 'project' - we are showing project versions here, not specific artifact information (though
125      * that is rendered in the download box).
126      */
127     public String artifact()
128     {
129
130         // In the future, this should be replaced by the repository grouping mechanism, so that we are only making
131         // simple resource requests here and letting the resolver take care of it
132         String errorMsg = null;
133         ProjectVersionMetadata versionMetadata = getProjectVersionMetadata();
134
135         if ( versionMetadata == null )
136         {
137             addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
138             return ERROR;
139         }
140
141         if ( versionMetadata.isIncomplete() )
142         {
143             addIncompleteModelWarning();
144         }
145
146         model = versionMetadata;
147
148         return SUCCESS;
149     }
150
151     private ProjectVersionMetadata getProjectVersionMetadata()
152     {
153         ProjectVersionMetadata versionMetadata = null;
154         artifacts = new LinkedHashMap<String, List<ArtifactDownloadInfo>>();
155         
156         List<String> repos = getObservableRepos();
157
158         for ( String repoId : repos )
159         {
160             if ( versionMetadata == null )
161             {
162                 // we don't want the implementation being that intelligent - so another resolver to do the
163                 // "just-in-time" nature of picking up the metadata (if appropriate for the repository type) is used
164                 try
165                 {
166                     versionMetadata = metadataResolver.getProjectVersion( repoId, groupId, artifactId, version );
167                 }
168                 catch ( MetadataResolutionException e )
169                 {
170                     addIncompleteModelWarning();
171
172                     // TODO: need a consistent way to construct this - same in ArchivaMetadataCreationConsumer
173                     versionMetadata = new ProjectVersionMetadata();
174                     versionMetadata.setId( version );
175                 }
176                 if ( versionMetadata != null )
177                 {
178                     repositoryId = repoId;
179
180                     List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>(
181                         metadataResolver.getArtifacts( repoId, groupId, artifactId, version ) );
182                     Collections.sort( artifacts, new Comparator<ArtifactMetadata>()
183                     {
184                         public int compare( ArtifactMetadata o1, ArtifactMetadata o2 )
185                         {
186                             // sort by version (reverse), then ID
187                             // TODO: move version sorting into repository handling (maven2 specific), and perhaps add a
188                             //       way to get latest instead
189                             int result = new DefaultArtifactVersion( o2.getVersion() ).compareTo(
190                                 new DefaultArtifactVersion( o1.getVersion() ) );
191                             return result != 0 ? result : o1.getId().compareTo( o2.getId() );
192                         }
193                     } );
194
195                     for ( ArtifactMetadata artifact : artifacts )
196                     {
197                         List<ArtifactDownloadInfo> l = this.artifacts.get( artifact.getVersion() );
198                         if ( l == null )
199                         {
200                             l = new ArrayList<ArtifactDownloadInfo>();
201                             this.artifacts.put( artifact.getVersion(), l );
202                         }
203                         l.add( new ArtifactDownloadInfo( artifact ) );
204                     }
205                 }
206             }
207         }
208
209         return versionMetadata;
210     }
211
212     private void addIncompleteModelWarning()
213     {
214         addActionMessage( "The model may be incomplete due to a previous error in resolving information. Refer to the repository problem reports for more information." );
215     }
216
217     /**
218      * Show the artifact information tab.
219      */
220     public String dependencies()
221     {
222         String result = artifact();
223
224         this.dependencies = model.getDependencies();
225
226         return result;
227     }
228
229     /**
230      * Show the mailing lists information tab.
231      */
232     public String mailingLists()
233     {
234         String result = artifact();
235
236         this.mailingLists = model.getMailingLists();
237
238         return result;
239     }
240
241     /**
242      * Show the reports tab.
243      */
244     public String reports()
245     {
246         // TODO: hook up reports on project
247
248         return SUCCESS;
249     }
250
251     /**
252      * Show the dependees (other artifacts that depend on this project) tab.
253      */
254     public String dependees()
255     {
256         List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
257         // TODO: what if we get duplicates across repositories?
258         for ( String repoId : getObservableRepos() )
259         {
260             // TODO: what about if we want to see this irrespective of version?
261             references.addAll( metadataResolver.getProjectReferences( repoId, groupId, artifactId, version ) );
262         }
263
264         this.dependees = references;
265
266         // 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
267         // (especially in the case of pre-population import)
268
269         return artifact();
270     }
271
272     /**
273      * Show the dependencies of this versioned project tab.
274      */
275     public String dependencyTree()
276     {
277         // temporarily use this as we only need the model for the tag to perform, but we should be resolving the
278         // graph here instead
279
280         // 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
281         // (especially in the case of pre-population import)
282
283         // TODO: a bit ugly, should really be mapping all these results differently now
284         this.dependencyTree = true;
285
286         return artifact();
287     }
288
289     public String projectMetadata()
290     {
291         String result = artifact();
292         
293         if( model.getFacet( GenericMetadataFacet.FACET_ID ) != null )
294         {
295             genericMetadata = model.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
296         }
297         
298         if( genericMetadata == null )
299         {
300             genericMetadata = new HashMap<String, String>();
301         }
302
303         return result;
304     }
305     
306     public String addMetadataProperty()
307     {
308         ProjectVersionMetadata projectMetadata = getProjectVersionMetadata();
309         String errorMsg = null;      
310         
311         if( projectMetadata == null )
312         {
313             addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
314             return ERROR;
315         }
316         
317         if( projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ) == null )
318         {
319             genericMetadata = new HashMap<String, String>();
320         }
321         else
322         {
323             genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
324         }
325         
326         genericMetadata.put( propertyName, propertyValue );
327         
328         GenericMetadataFacet genericMetadataFacet = new GenericMetadataFacet();
329         genericMetadataFacet.fromProperties( genericMetadata );
330                 
331         // add updated facet
332         projectMetadata.addFacet( genericMetadataFacet );
333                 
334         metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
335          
336         projectMetadata = getProjectVersionMetadata();
337         
338         genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
339         
340         model = projectMetadata;
341         
342         propertyName = "";
343         propertyValue = "";
344         
345         return SUCCESS;
346     }
347     
348     public String updateProjectMetadata()
349     {
350         metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
351
352         return SUCCESS;
353     }
354     
355     public String deleteMetadataEntry()
356     {   
357         projectMetadata = getProjectVersionMetadata();
358         
359         if ( !StringUtils.isEmpty( deleteItem ) && !StringUtils.isEmpty( itemValue ) )
360         {
361             if ( "dependency".equals( deleteItem ) )
362             {
363                 removeDependency();
364             }
365             else if ( "mailingList".equals( deleteItem ) )
366             {
367                 removeMailingList();
368             }
369             else if ( "license".equals( deleteItem ) )
370             {
371                 removeLicense();
372             }
373             
374             deleteItem = "";
375             itemValue = "";
376         }
377         
378         return updateProjectMetadata();
379     }
380     
381     private void removeDependency()
382     {
383         List<Dependency> dependencies = projectMetadata.getDependencies();
384         List<Dependency> newDependencies = new ArrayList<Dependency>();
385         
386         if ( dependencies != null )
387         {
388             for ( Dependency dependency : dependencies )
389             {
390                 if ( !StringUtils.equals( itemValue, dependency.getArtifactId() ) )
391                 {
392                     newDependencies.add( dependency );
393                 }
394             }
395         }
396         
397         projectMetadata.setDependencies( newDependencies );
398     }
399     
400     private void removeMailingList()
401     {
402         List<MailingList> mailingLists = projectMetadata.getMailingLists();
403         List<MailingList> newMailingLists = new ArrayList<MailingList>();
404         
405         if ( mailingLists != null )
406         {
407             for ( MailingList mailingList : mailingLists )
408             {
409                 if ( !StringUtils.equals( itemValue, mailingList.getName() ) )
410                 {
411                     newMailingLists.add( mailingList );
412                 }
413             }
414         }
415         
416         projectMetadata.setMailingLists( newMailingLists );
417     }
418     
419     private void removeLicense()
420     {
421         List<License> licenses = projectMetadata.getLicenses();
422         List<License> newLicenses = new ArrayList<License>();
423         
424         if ( licenses != null )
425         {
426             for ( License license : licenses )
427             {
428                 if ( !StringUtils.equals( itemValue, license.getName() ) )
429                 {
430                     newLicenses.add( license );
431                 }
432             }
433         }
434         
435         projectMetadata.setLicenses( newLicenses );
436     }
437     
438     @Override
439     public void validate()
440     {
441         if ( StringUtils.isBlank( groupId ) )
442         {
443             addActionError( "You must specify a group ID to browse" );
444         }
445
446         if ( StringUtils.isBlank( artifactId ) )
447         {
448             addActionError( "You must specify a artifact ID to browse" );
449         }
450
451         if ( StringUtils.isBlank( version ) )
452         {
453             addActionError( "You must specify a version to browse" );
454         }
455     }
456
457     public ProjectVersionMetadata getModel()
458     {
459         return model;
460     }
461
462     public String getGroupId()
463     {
464         return groupId;
465     }
466
467     public void setGroupId( String groupId )
468     {
469         this.groupId = groupId;
470     }
471
472     public String getArtifactId()
473     {
474         return artifactId;
475     }
476
477     public void setArtifactId( String artifactId )
478     {
479         this.artifactId = artifactId;
480     }
481
482     public String getVersion()
483     {
484         return version;
485     }
486
487     public void setVersion( String version )
488     {
489         this.version = version;
490     }
491
492     public List<MailingList> getMailingLists()
493     {
494         return mailingLists;
495     }
496
497     public List<Dependency> getDependencies()
498     {
499         return dependencies;
500     }
501
502     public List<ProjectVersionReference> getDependees()
503     {
504         return dependees;
505     }
506
507     public String getRepositoryId()
508     {
509         return repositoryId;
510     }
511
512     public void setRepositoryId( String repositoryId )
513     {
514         this.repositoryId = repositoryId;
515     }
516
517     public MetadataResolver getMetadataResolver()
518     {
519         return metadataResolver;
520     }
521
522     public Map<String, List<ArtifactDownloadInfo>> getArtifacts()
523     {
524         return artifacts;
525     }
526
527     public Collection<String> getSnapshotVersions()
528     {
529         return artifacts.keySet();
530     }
531
532     public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
533     {
534         this.repositoryFactory = repositoryFactory;
535     }
536
537     public boolean isDependencyTree()
538     {
539         return dependencyTree;
540     }
541
542     public ProjectVersionMetadata getProjectMetadata()
543     {
544         return projectMetadata;
545     }
546
547     public void setProjectMetadata( ProjectVersionMetadata projectMetadata )
548     {
549         this.projectMetadata = projectMetadata;
550     }
551
552     public void setDeleteItem( String deleteItem )
553     {
554         this.deleteItem = deleteItem; 
555     }
556     
557     public void setItemValue( String itemValue )
558     {
559         this.itemValue = itemValue;
560     }
561     
562     public Map<String, String> getGenericMetadata()
563     {
564         return genericMetadata;
565     }
566
567     public void setGenericMetadata( Map<String, String> genericMetadata )
568     {
569         this.genericMetadata = genericMetadata;
570     }
571     
572     public String getPropertyName()
573     {
574         return propertyName;
575     }
576
577     public void setPropertyName( String propertyName )
578     {
579         this.propertyName = propertyName;
580     }
581
582     public String getPropertyValue()
583     {
584         return propertyValue;
585     }
586
587     public void setPropertyValue( String propertyValue )
588     {
589         this.propertyValue = propertyValue;
590     }
591
592     // TODO: move this into the artifact metadata itself via facets where necessary
593
594     public class ArtifactDownloadInfo
595     {
596         private String type;
597
598         private String namespace;
599
600         private String project;
601
602         private String size;
603
604         private String id;
605
606         private String repositoryId;
607
608         private String version;
609
610         private String path;
611
612         public ArtifactDownloadInfo( ArtifactMetadata artifact )
613         {
614             repositoryId = artifact.getRepositoryId();
615
616             // TODO: use metadata resolver capability instead - maybe the storage path could be stored in the metadata
617             //       though keep in mind the request may not necessarily need to reflect the storage
618             ManagedRepositoryContent repo;
619             try
620             {
621                 repo = repositoryFactory.getManagedRepositoryContent( repositoryId );
622             }
623             catch ( RepositoryException e )
624             {
625                 throw new RuntimeException( e );
626             }
627
628             ArtifactReference ref = new ArtifactReference();
629             ref.setArtifactId( artifact.getProject() );
630             ref.setGroupId( artifact.getNamespace() );
631             ref.setVersion( artifact.getVersion() );
632             path = repo.toPath( ref );
633             path = path.substring( 0, path.lastIndexOf( "/" ) + 1 ) + artifact.getId();
634
635             // TODO: need to accommodate Maven 1 layout too. Non-maven repository formats will need to generate this
636             //       facet (perhaps on the fly) if wanting to display the Maven 2 elements on the Archiva pages
637             String type = null;
638             MavenArtifactFacet facet = (MavenArtifactFacet) artifact.getFacet( MavenArtifactFacet.FACET_ID );
639             if ( facet != null )
640             {
641                 type = facet.getType();
642             }
643             this.type = type;
644
645             namespace = artifact.getNamespace();
646             project = artifact.getProject();
647
648             // TODO: find a reusable formatter for this
649             double s = artifact.getSize();
650             String symbol = "b";
651             if ( s > 1024 )
652             {
653                 symbol = "K";
654                 s /= 1024;
655
656                 if ( s > 1024 )
657                 {
658                     symbol = "M";
659                     s /= 1024;
660
661                     if ( s > 1024 )
662                     {
663                         symbol = "G";
664                         s /= 1024;
665                     }
666                 }
667             }
668
669             size = new DecimalFormat( "#,###.##" ).format( s ) + " " + symbol;
670             id = artifact.getId();
671             version = artifact.getVersion();
672         }
673
674         public String getNamespace()
675         {
676             return namespace;
677         }
678
679         public String getType()
680         {
681             return type;
682         }
683
684         public String getProject()
685         {
686             return project;
687         }
688
689         public String getSize()
690         {
691             return size;
692         }
693
694         public String getId()
695         {
696             return id;
697         }
698
699         public String getVersion()
700         {
701             return version;
702         }
703
704         public String getRepositoryId()
705         {
706             return repositoryId;
707         }
708
709         public String getPath()
710         {
711             return path;
712         }
713     }
714 }