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