]> source.dussan.org Git - archiva.git/blob
373c3eaff8746b0db19ad356d738af0601dce3c2
[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         String errorMsg = null;
309         
310         ProjectVersionMetadata projectMetadata = getProjectVersionMetadata();
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         if( propertyName == null || "".equals( propertyName.trim() ) || propertyValue == null || "".equals( propertyValue.trim() ) )
327         {
328             model = projectMetadata;            
329             addActionError( errorMsg != null ? errorMsg : "Property Name and Property Value are required." );
330             return INPUT;
331         }
332         
333         genericMetadata.put( propertyName, propertyValue );
334         
335         GenericMetadataFacet genericMetadataFacet = new GenericMetadataFacet();
336         genericMetadataFacet.fromProperties( genericMetadata );
337                 
338         // add updated facet
339         projectMetadata.addFacet( genericMetadataFacet );
340                 
341         metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
342          
343         projectMetadata = getProjectVersionMetadata();
344         
345         genericMetadata = projectMetadata.getFacet( GenericMetadataFacet.FACET_ID ).toProperties();
346         
347         model = projectMetadata;
348         
349         propertyName = "";
350         propertyValue = "";
351         
352         return SUCCESS;
353     }
354     
355     public String updateProjectMetadata()
356     {
357         metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
358
359         return SUCCESS;
360     }
361     
362     public String deleteMetadataEntry()
363     {   
364         projectMetadata = getProjectVersionMetadata();
365         
366         if ( !StringUtils.isEmpty( deleteItem ) && !StringUtils.isEmpty( itemValue ) )
367         {
368             if ( "dependency".equals( deleteItem ) )
369             {
370                 removeDependency();
371             }
372             else if ( "mailingList".equals( deleteItem ) )
373             {
374                 removeMailingList();
375             }
376             else if ( "license".equals( deleteItem ) )
377             {
378                 removeLicense();
379             }
380             
381             deleteItem = "";
382             itemValue = "";
383         }
384         
385         return updateProjectMetadata();
386     }
387     
388     private void removeDependency()
389     {
390         List<Dependency> dependencies = projectMetadata.getDependencies();
391         List<Dependency> newDependencies = new ArrayList<Dependency>();
392         
393         if ( dependencies != null )
394         {
395             for ( Dependency dependency : dependencies )
396             {
397                 if ( !StringUtils.equals( itemValue, dependency.getArtifactId() ) )
398                 {
399                     newDependencies.add( dependency );
400                 }
401             }
402         }
403         
404         projectMetadata.setDependencies( newDependencies );
405     }
406     
407     private void removeMailingList()
408     {
409         List<MailingList> mailingLists = projectMetadata.getMailingLists();
410         List<MailingList> newMailingLists = new ArrayList<MailingList>();
411         
412         if ( mailingLists != null )
413         {
414             for ( MailingList mailingList : mailingLists )
415             {
416                 if ( !StringUtils.equals( itemValue, mailingList.getName() ) )
417                 {
418                     newMailingLists.add( mailingList );
419                 }
420             }
421         }
422         
423         projectMetadata.setMailingLists( newMailingLists );
424     }
425     
426     private void removeLicense()
427     {
428         List<License> licenses = projectMetadata.getLicenses();
429         List<License> newLicenses = new ArrayList<License>();
430         
431         if ( licenses != null )
432         {
433             for ( License license : licenses )
434             {
435                 if ( !StringUtils.equals( itemValue, license.getName() ) )
436                 {
437                     newLicenses.add( license );
438                 }
439             }
440         }
441         
442         projectMetadata.setLicenses( newLicenses );
443     }
444     
445     @Override
446     public void validate()
447     {
448         if ( StringUtils.isBlank( groupId ) )
449         {
450             addActionError( "You must specify a group ID to browse" );
451         }
452
453         if ( StringUtils.isBlank( artifactId ) )
454         {
455             addActionError( "You must specify a artifact ID to browse" );
456         }
457
458         if ( StringUtils.isBlank( version ) )
459         {
460             addActionError( "You must specify a version to browse" );
461         }
462     }
463
464     public ProjectVersionMetadata getModel()
465     {
466         return model;
467     }
468
469     public String getGroupId()
470     {
471         return groupId;
472     }
473
474     public void setGroupId( String groupId )
475     {
476         this.groupId = groupId;
477     }
478
479     public String getArtifactId()
480     {
481         return artifactId;
482     }
483
484     public void setArtifactId( String artifactId )
485     {
486         this.artifactId = artifactId;
487     }
488
489     public String getVersion()
490     {
491         return version;
492     }
493
494     public void setVersion( String version )
495     {
496         this.version = version;
497     }
498
499     public List<MailingList> getMailingLists()
500     {
501         return mailingLists;
502     }
503
504     public List<Dependency> getDependencies()
505     {
506         return dependencies;
507     }
508
509     public List<ProjectVersionReference> getDependees()
510     {
511         return dependees;
512     }
513
514     public String getRepositoryId()
515     {
516         return repositoryId;
517     }
518
519     public void setRepositoryId( String repositoryId )
520     {
521         this.repositoryId = repositoryId;
522     }
523
524     public MetadataResolver getMetadataResolver()
525     {
526         return metadataResolver;
527     }
528
529     public Map<String, List<ArtifactDownloadInfo>> getArtifacts()
530     {
531         return artifacts;
532     }
533
534     public Collection<String> getSnapshotVersions()
535     {
536         return artifacts.keySet();
537     }
538
539     public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
540     {
541         this.repositoryFactory = repositoryFactory;
542     }
543
544     public boolean isDependencyTree()
545     {
546         return dependencyTree;
547     }
548
549     public ProjectVersionMetadata getProjectMetadata()
550     {
551         return projectMetadata;
552     }
553
554     public void setProjectMetadata( ProjectVersionMetadata projectMetadata )
555     {
556         this.projectMetadata = projectMetadata;
557     }
558
559     public void setDeleteItem( String deleteItem )
560     {
561         this.deleteItem = deleteItem; 
562     }
563     
564     public void setItemValue( String itemValue )
565     {
566         this.itemValue = itemValue;
567     }
568     
569     public Map<String, String> getGenericMetadata()
570     {
571         return genericMetadata;
572     }
573
574     public void setGenericMetadata( Map<String, String> genericMetadata )
575     {
576         this.genericMetadata = genericMetadata;
577     }
578     
579     public String getPropertyName()
580     {
581         return propertyName;
582     }
583
584     public void setPropertyName( String propertyName )
585     {
586         this.propertyName = propertyName;
587     }
588
589     public String getPropertyValue()
590     {
591         return propertyValue;
592     }
593
594     public void setPropertyValue( String propertyValue )
595     {
596         this.propertyValue = propertyValue;
597     }
598
599     // TODO: move this into the artifact metadata itself via facets where necessary
600
601     public class ArtifactDownloadInfo
602     {
603         private String type;
604
605         private String namespace;
606
607         private String project;
608
609         private String size;
610
611         private String id;
612
613         private String repositoryId;
614
615         private String version;
616
617         private String path;
618
619         public ArtifactDownloadInfo( ArtifactMetadata artifact )
620         {
621             repositoryId = artifact.getRepositoryId();
622
623             // TODO: use metadata resolver capability instead - maybe the storage path could be stored in the metadata
624             //       though keep in mind the request may not necessarily need to reflect the storage
625             ManagedRepositoryContent repo;
626             try
627             {
628                 repo = repositoryFactory.getManagedRepositoryContent( repositoryId );
629             }
630             catch ( RepositoryException e )
631             {
632                 throw new RuntimeException( e );
633             }
634
635             ArtifactReference ref = new ArtifactReference();
636             ref.setArtifactId( artifact.getProject() );
637             ref.setGroupId( artifact.getNamespace() );
638             ref.setVersion( artifact.getVersion() );
639             path = repo.toPath( ref );
640             path = path.substring( 0, path.lastIndexOf( "/" ) + 1 ) + artifact.getId();
641
642             // TODO: need to accommodate Maven 1 layout too. Non-maven repository formats will need to generate this
643             //       facet (perhaps on the fly) if wanting to display the Maven 2 elements on the Archiva pages
644             String type = null;
645             MavenArtifactFacet facet = (MavenArtifactFacet) artifact.getFacet( MavenArtifactFacet.FACET_ID );
646             if ( facet != null )
647             {
648                 type = facet.getType();
649             }
650             this.type = type;
651
652             namespace = artifact.getNamespace();
653             project = artifact.getProject();
654
655             // TODO: find a reusable formatter for this
656             double s = artifact.getSize();
657             String symbol = "b";
658             if ( s > 1024 )
659             {
660                 symbol = "K";
661                 s /= 1024;
662
663                 if ( s > 1024 )
664                 {
665                     symbol = "M";
666                     s /= 1024;
667
668                     if ( s > 1024 )
669                     {
670                         symbol = "G";
671                         s /= 1024;
672                     }
673                 }
674             }
675
676             size = new DecimalFormat( "#,###.##" ).format( s ) + " " + symbol;
677             id = artifact.getId();
678             version = artifact.getVersion();
679         }
680
681         public String getNamespace()
682         {
683             return namespace;
684         }
685
686         public String getType()
687         {
688             return type;
689         }
690
691         public String getProject()
692         {
693             return project;
694         }
695
696         public String getSize()
697         {
698             return size;
699         }
700
701         public String getId()
702         {
703             return id;
704         }
705
706         public String getVersion()
707         {
708             return version;
709         }
710
711         public String getRepositoryId()
712         {
713             return repositoryId;
714         }
715
716         public String getPath()
717         {
718             return path;
719         }
720     }
721 }