]> source.dussan.org Git - archiva.git/blob
d148be496da3ae0fe4a8e7cfeccba743ec476c6d
[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 import org.apache.archiva.metadata.model.ArtifactMetadata;
24 import org.apache.archiva.metadata.model.Dependency;
25 import org.apache.archiva.metadata.model.MailingList;
26 import org.apache.archiva.metadata.model.ProjectVersionMetadata;
27 import org.apache.archiva.metadata.model.ProjectVersionReference;
28 import org.apache.archiva.metadata.repository.MetadataRepository;
29 import org.apache.archiva.metadata.repository.MetadataResolutionException;
30 import org.apache.archiva.metadata.repository.MetadataResolver;
31 import org.apache.archiva.metadata.repository.storage.maven2.MavenArtifactFacet;
32 import org.apache.commons.lang.StringUtils;
33 import org.apache.maven.archiva.model.ArtifactReference;
34 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
35 import org.apache.maven.archiva.repository.RepositoryContentFactory;
36 import org.apache.maven.archiva.repository.RepositoryException;
37 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
38
39 import java.text.DecimalFormat;
40 import java.util.ArrayList;
41 import java.util.Collection;
42 import java.util.Collections;
43 import java.util.Comparator;
44 import java.util.LinkedHashMap;
45 import java.util.List;
46 import java.util.Map;
47
48 /**
49  * Browse the repository.
50  *
51  * TODO change name to ShowVersionedAction to conform to terminology.
52  *
53  * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="showArtifactAction" instantiation-strategy="per-lookup"
54  */
55 public class ShowArtifactAction
56     extends AbstractRepositoryBasedAction
57     implements Validateable
58 {
59     /* .\ Not Exposed \._____________________________________________ */
60
61     /**
62      * @plexus.requirement
63      */
64     private MetadataResolver metadataResolver;
65
66     /**
67      * @plexus.requirement
68      */
69     private RepositoryContentFactory repositoryFactory;
70
71     /**
72      * @plexus.requirement
73      */
74     private MetadataRepository metadataRepository;
75
76     /* .\ Exposed Output Objects \.__________________________________ */
77
78     private String groupId;
79
80     private String artifactId;
81
82     private String version;
83
84     private String repositoryId;
85
86     /**
87      * The model of this versioned project.
88      */
89     private ProjectVersionMetadata model;
90
91     /**
92      * The list of artifacts that depend on this versioned project.
93      */
94     private List<ProjectVersionReference> dependees;
95
96     private List<MailingList> mailingLists;
97
98     private List<Dependency> dependencies;
99
100     private Map<String, List<ArtifactDownloadInfo>> artifacts;
101
102     private boolean dependencyTree = false;
103
104     private ProjectVersionMetadata projectMetadata;
105    
106     /**
107      * Show the versioned project information tab.
108      * TODO: Change name to 'project' - we are showing project versions here, not specific artifact information (though
109      * that is rendered in the download box).
110      */
111     public String artifact()
112     {
113
114         // In the future, this should be replaced by the repository grouping mechanism, so that we are only making
115         // simple resource requests here and letting the resolver take care of it
116         String errorMsg = null;
117         ProjectVersionMetadata versionMetadata = getProjectVersionMetadata();
118
119         if ( versionMetadata == null )
120         {
121             addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
122             return ERROR;
123         }
124
125         if ( versionMetadata.isIncomplete() )
126         {
127             addIncompleteModelWarning();
128         }
129
130         model = versionMetadata;
131
132         return SUCCESS;
133     }
134
135     private ProjectVersionMetadata getProjectVersionMetadata()
136     {
137         ProjectVersionMetadata versionMetadata = null;
138         artifacts = new LinkedHashMap<String, List<ArtifactDownloadInfo>>();
139
140         List<String> repos = getObservableRepos();
141
142         for ( String repoId : repos )
143         {
144             if ( versionMetadata == null )
145             {
146                 // we don't want the implementation being that intelligent - so another resolver to do the
147                 // "just-in-time" nature of picking up the metadata (if appropriate for the repository type) is used
148                 try
149                 {
150                     versionMetadata = metadataResolver.getProjectVersion( repoId, groupId, artifactId, version );
151                 }
152                 catch ( MetadataResolutionException e )
153                 {
154                     addIncompleteModelWarning();
155
156                     // TODO: need a consistent way to construct this - same in ArchivaMetadataCreationConsumer
157                     versionMetadata = new ProjectVersionMetadata();
158                     versionMetadata.setId( version );
159                 }
160                 if ( versionMetadata != null )
161                 {
162                     repositoryId = repoId;
163
164                     List<ArtifactMetadata> artifacts = new ArrayList<ArtifactMetadata>(
165                         metadataResolver.getArtifacts( repoId, groupId, artifactId, version ) );
166                     Collections.sort( artifacts, new Comparator<ArtifactMetadata>()
167                     {
168                         public int compare( ArtifactMetadata o1, ArtifactMetadata o2 )
169                         {
170                             // sort by version (reverse), then ID
171                             // TODO: move version sorting into repository handling (maven2 specific), and perhaps add a
172                             //       way to get latest instead
173                             int result = new DefaultArtifactVersion( o2.getVersion() ).compareTo(
174                                 new DefaultArtifactVersion( o1.getVersion() ) );
175                             return result != 0 ? result : o1.getId().compareTo( o2.getId() );
176                         }
177                     } );
178
179                     for ( ArtifactMetadata artifact : artifacts )
180                     {
181                         List<ArtifactDownloadInfo> l = this.artifacts.get( artifact.getVersion() );
182                         if ( l == null )
183                         {
184                             l = new ArrayList<ArtifactDownloadInfo>();
185                             this.artifacts.put( artifact.getVersion(), l );
186                         }
187                         l.add( new ArtifactDownloadInfo( artifact ) );
188                     }
189                 }
190             }
191         }
192
193         return versionMetadata;
194     }
195
196     private void addIncompleteModelWarning()
197     {
198         addActionMessage( "The model may be incomplete due to a previous error in resolving information. Refer to the repository problem reports for more information." );
199     }
200
201     /**
202      * Show the artifact information tab.
203      */
204     public String dependencies()
205     {
206         String result = artifact();
207
208         this.dependencies = model.getDependencies();
209
210         return result;
211     }
212
213     /**
214      * Show the mailing lists information tab.
215      */
216     public String mailingLists()
217     {
218         String result = artifact();
219
220         this.mailingLists = model.getMailingLists();
221
222         return result;
223     }
224
225     /**
226      * Show the reports tab.
227      */
228     public String reports()
229     {
230         // TODO: hook up reports on project
231
232         return SUCCESS;
233     }
234
235     /**
236      * Show the dependees (other artifacts that depend on this project) tab.
237      */
238     public String dependees()
239     {
240         List<ProjectVersionReference> references = new ArrayList<ProjectVersionReference>();
241         // TODO: what if we get duplicates across repositories?
242         for ( String repoId : getObservableRepos() )
243         {
244             // TODO: what about if we want to see this irrespective of version?
245             references.addAll( metadataResolver.getProjectReferences( repoId, groupId, artifactId, version ) );
246         }
247
248         this.dependees = references;
249
250         // 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
251         // (especially in the case of pre-population import)
252
253         return artifact();
254     }
255
256     /**
257      * Show the dependencies of this versioned project tab.
258      */
259     public String dependencyTree()
260     {
261         // temporarily use this as we only need the model for the tag to perform, but we should be resolving the
262         // graph here instead
263
264         // 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
265         // (especially in the case of pre-population import)
266
267         // TODO: a bit ugly, should really be mapping all these results differently now
268         this.dependencyTree = true;
269
270         return artifact();
271     }
272
273     public String projectMetadata()
274     {
275         projectMetadata = getProjectVersionMetadata();
276         String errorMsg = null;
277
278         if ( projectMetadata == null )
279         {
280             addActionError( errorMsg != null ? errorMsg : "Artifact not found" );
281             return ERROR;
282         }
283
284         if ( projectMetadata.isIncomplete() )
285         {
286             addIncompleteModelWarning();
287         }
288
289         return SUCCESS;
290     }
291     
292     public String updateProjectMetadata()
293     {
294         metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectMetadata );
295
296         return SUCCESS;
297     }
298
299     @Override
300     public void validate()
301     {
302         if ( StringUtils.isBlank( groupId ) )
303         {
304             addActionError( "You must specify a group ID to browse" );
305         }
306
307         if ( StringUtils.isBlank( artifactId ) )
308         {
309             addActionError( "You must specify a artifact ID to browse" );
310         }
311
312         if ( StringUtils.isBlank( version ) )
313         {
314             addActionError( "You must specify a version to browse" );
315         }
316     }
317
318     public ProjectVersionMetadata getModel()
319     {
320         return model;
321     }
322
323     public String getGroupId()
324     {
325         return groupId;
326     }
327
328     public void setGroupId( String groupId )
329     {
330         this.groupId = groupId;
331     }
332
333     public String getArtifactId()
334     {
335         return artifactId;
336     }
337
338     public void setArtifactId( String artifactId )
339     {
340         this.artifactId = artifactId;
341     }
342
343     public String getVersion()
344     {
345         return version;
346     }
347
348     public void setVersion( String version )
349     {
350         this.version = version;
351     }
352
353     public List<MailingList> getMailingLists()
354     {
355         return mailingLists;
356     }
357
358     public List<Dependency> getDependencies()
359     {
360         return dependencies;
361     }
362
363     public List<ProjectVersionReference> getDependees()
364     {
365         return dependees;
366     }
367
368     public String getRepositoryId()
369     {
370         return repositoryId;
371     }
372
373     public void setRepositoryId( String repositoryId )
374     {
375         this.repositoryId = repositoryId;
376     }
377
378     public MetadataResolver getMetadataResolver()
379     {
380         return metadataResolver;
381     }
382
383     public Map<String, List<ArtifactDownloadInfo>> getArtifacts()
384     {
385         return artifacts;
386     }
387
388     public Collection<String> getSnapshotVersions()
389     {
390         return artifacts.keySet();
391     }
392
393     public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
394     {
395         this.repositoryFactory = repositoryFactory;
396     }
397
398     public boolean isDependencyTree()
399     {
400         return dependencyTree;
401     }
402
403     public ProjectVersionMetadata getProjectMetadata()
404     {
405         return projectMetadata;
406     }
407
408     public void setProjectMetadata( ProjectVersionMetadata projectMetadata )
409     {
410         this.projectMetadata = projectMetadata;
411     }
412
413     // TODO: move this into the artifact metadata itself via facets where necessary
414
415     public class ArtifactDownloadInfo
416     {
417         private String type;
418
419         private String namespace;
420
421         private String project;
422
423         private String size;
424
425         private String id;
426
427         private String repositoryId;
428
429         private String version;
430
431         private String path;
432
433         public ArtifactDownloadInfo( ArtifactMetadata artifact )
434         {
435             repositoryId = artifact.getRepositoryId();
436
437             // TODO: use metadata resolver capability instead - maybe the storage path could be stored in the metadata
438             //       though keep in mind the request may not necessarily need to reflect the storage
439             ManagedRepositoryContent repo;
440             try
441             {
442                 repo = repositoryFactory.getManagedRepositoryContent( repositoryId );
443             }
444             catch ( RepositoryException e )
445             {
446                 throw new RuntimeException( e );
447             }
448
449             ArtifactReference ref = new ArtifactReference();
450             ref.setArtifactId( artifact.getProject() );
451             ref.setGroupId( artifact.getNamespace() );
452             ref.setVersion( artifact.getVersion() );
453             path = repo.toPath( ref );
454             path = path.substring( 0, path.lastIndexOf( "/" ) + 1 ) + artifact.getId();
455
456             // TODO: need to accommodate Maven 1 layout too. Non-maven repository formats will need to generate this
457             //       facet (perhaps on the fly) if wanting to display the Maven 2 elements on the Archiva pages
458             String type = null;
459             MavenArtifactFacet facet = (MavenArtifactFacet) artifact.getFacet( MavenArtifactFacet.FACET_ID );
460             if ( facet != null )
461             {
462                 type = facet.getType();
463             }
464             this.type = type;
465
466             namespace = artifact.getNamespace();
467             project = artifact.getProject();
468
469             // TODO: find a reusable formatter for this
470             double s = artifact.getSize();
471             String symbol = "b";
472             if ( s > 1024 )
473             {
474                 symbol = "K";
475                 s /= 1024;
476
477                 if ( s > 1024 )
478                 {
479                     symbol = "M";
480                     s /= 1024;
481
482                     if ( s > 1024 )
483                     {
484                         symbol = "G";
485                         s /= 1024;
486                     }
487                 }
488             }
489
490             size = new DecimalFormat( "#,###.##" ).format( s ) + " " + symbol;
491             id = artifact.getId();
492             version = artifact.getVersion();
493         }
494
495         public String getNamespace()
496         {
497             return namespace;
498         }
499
500         public String getType()
501         {
502             return type;
503         }
504
505         public String getProject()
506         {
507             return project;
508         }
509
510         public String getSize()
511         {
512             return size;
513         }
514
515         public String getId()
516         {
517             return id;
518         }
519
520         public String getVersion()
521         {
522             return version;
523         }
524
525         public String getRepositoryId()
526         {
527             return repositoryId;
528         }
529
530         public String getPath()
531         {
532             return path;
533         }
534
535
536     }
537 }