]> source.dussan.org Git - archiva.git/blob
35796659377611789efd2bd354091aefb3aaf71c
[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.Preparable;
23 import com.opensymphony.xwork2.Validateable;
24 import org.apache.archiva.admin.model.RepositoryAdminException;
25 import org.apache.archiva.admin.model.beans.ManagedRepository;
26 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
27 import org.apache.archiva.audit.AuditEvent;
28 import org.apache.archiva.audit.Auditable;
29 import org.apache.archiva.checksum.ChecksumAlgorithm;
30 import org.apache.archiva.checksum.ChecksummedFile;
31 import org.apache.archiva.metadata.model.ArtifactMetadata;
32 import org.apache.archiva.metadata.repository.MetadataRepository;
33 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
34 import org.apache.archiva.metadata.repository.MetadataResolutionException;
35 import org.apache.archiva.metadata.repository.RepositorySession;
36 import org.apache.archiva.model.ArtifactReference;
37 import org.apache.archiva.repository.events.RepositoryListener;
38 import org.apache.archiva.security.AccessDeniedException;
39 import org.apache.archiva.security.ArchivaSecurityException;
40 import org.apache.archiva.security.PrincipalNotFoundException;
41 import org.apache.archiva.security.UserRepositories;
42 import org.apache.commons.lang.StringUtils;
43 import org.apache.archiva.common.utils.VersionComparator;
44 import org.apache.archiva.common.utils.VersionUtil;
45 import org.apache.archiva.model.ArchivaRepositoryMetadata;
46 import org.apache.archiva.model.VersionedReference;
47 import org.apache.archiva.repository.ContentNotFoundException;
48 import org.apache.archiva.repository.ManagedRepositoryContent;
49 import org.apache.archiva.repository.RepositoryContentFactory;
50 import org.apache.archiva.repository.RepositoryException;
51 import org.apache.archiva.repository.RepositoryNotFoundException;
52 import org.apache.archiva.repository.metadata.MetadataTools;
53 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
54 import org.apache.archiva.repository.metadata.RepositoryMetadataReader;
55 import org.apache.archiva.repository.metadata.RepositoryMetadataWriter;
56 import org.springframework.context.annotation.Scope;
57 import org.springframework.stereotype.Controller;
58
59 import javax.annotation.PostConstruct;
60 import javax.inject.Inject;
61 import java.io.File;
62 import java.text.DateFormat;
63 import java.text.SimpleDateFormat;
64 import java.util.ArrayList;
65 import java.util.Calendar;
66 import java.util.Collection;
67 import java.util.Collections;
68 import java.util.Date;
69 import java.util.List;
70 import java.util.TimeZone;
71
72 /**
73  * Delete an artifact. Metadata will be updated if one exists, otherwise it would be created.
74  */
75 @Controller( "deleteArtifactAction" )
76 @Scope( "prototype" )
77 public class DeleteArtifactAction
78     extends AbstractActionSupport
79     implements Validateable, Preparable, Auditable
80 {
81     /**
82      * The groupId of the artifact to be deleted.
83      */
84     private String groupId;
85
86     /**
87      * The artifactId of the artifact to be deleted.
88      */
89     private String artifactId;
90
91     /**
92      * The version of the artifact to be deleted.
93      */
94     private String version;
95
96     /**
97      * @since 1.4-M2
98      * The classifier of the artifact to be deleted (optionnal)
99      */
100     private String classifier;
101
102     /**
103      * @since 1.4-M2
104      * The type of the artifact to be deleted (optionnal) (default jar)
105      */
106     private String type;
107
108     /**
109      * The repository where the artifact is to be deleted.
110      */
111     private String repositoryId;
112
113     /**
114      * List of managed repositories to delete from.
115      */
116     private List<String> managedRepos;
117
118     @Inject
119     private UserRepositories userRepositories;
120
121     @Inject
122     private RepositoryContentFactory repositoryFactory;
123
124     @Inject
125     private List<RepositoryListener> listeners;
126
127     @Inject
128     private ManagedRepositoryAdmin managedRepositoryAdmin;
129
130     private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
131
132     @PostConstruct
133     public void initialize()
134     {
135         super.initialize();
136     }
137
138     public String getGroupId()
139     {
140         return groupId;
141     }
142
143     public void setGroupId( String groupId )
144     {
145         this.groupId = groupId;
146     }
147
148     public String getArtifactId()
149     {
150         return artifactId;
151     }
152
153     public void setArtifactId( String artifactId )
154     {
155         this.artifactId = artifactId;
156     }
157
158     public String getVersion()
159     {
160         return version;
161     }
162
163     public void setVersion( String version )
164     {
165         this.version = version;
166     }
167
168     public String getRepositoryId()
169     {
170         return repositoryId;
171     }
172
173     public void setRepositoryId( String repositoryId )
174     {
175         this.repositoryId = repositoryId;
176     }
177
178     public List<String> getManagedRepos()
179     {
180         return managedRepos;
181     }
182
183     public void setManagedRepos( List<String> managedRepos )
184     {
185         this.managedRepos = managedRepos;
186     }
187
188     public void prepare()
189     {
190         managedRepos = getManagableRepos();
191     }
192
193     public String getClassifier()
194     {
195         return classifier;
196     }
197
198     public void setClassifier( String classifier )
199     {
200         this.classifier = classifier;
201     }
202
203     public String getType()
204     {
205         return type;
206     }
207
208     public void setType( String type )
209     {
210         this.type = type;
211     }
212
213     public String input()
214     {
215         return INPUT;
216     }
217
218     private void reset()
219     {
220         // reset the fields so the form is clear when 
221         // the action returns to the jsp page
222         groupId = "";
223         artifactId = "";
224         version = "";
225         repositoryId = "";
226         classifier = "";
227         type = "";
228     }
229
230     public String doDelete()
231     {
232
233         RepositorySession repositorySession = repositorySessionFactory.createSession();
234         try
235         {
236             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
237
238             TimeZone timezone = TimeZone.getTimeZone( "UTC" );
239             DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
240             fmt.setTimeZone( timezone );
241             ManagedRepository repoConfig = getManagedRepositoryAdmin().getManagedRepository( repositoryId );
242
243             VersionedReference ref = new VersionedReference();
244             ref.setArtifactId( artifactId );
245             ref.setGroupId( groupId );
246             ref.setVersion( version );
247
248             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
249
250             if ( StringUtils.isNotBlank( classifier ) )
251             {
252                 if (StringUtils.isBlank( type ))
253                 {
254                     addFieldError( "type", "You must configure a type when using classifier" );
255                     return INPUT;
256                 }
257                 ArtifactReference artifactReference = new ArtifactReference();
258                 artifactReference.setArtifactId( artifactId );
259                 artifactReference.setGroupId( groupId );
260                 artifactReference.setVersion( version );
261                 artifactReference.setClassifier( classifier );
262                 artifactReference.setType( type );
263                 repository.deleteArtifact( artifactReference );
264
265                 String msg = "Artifact \'" + groupId + ":" + artifactId + ":" + classifier + ":" + version
266                     + "\' was successfully deleted from repository \'" + repositoryId + "\'";
267
268                 addActionMessage( msg );
269
270                 reset();
271                 // TODO cleanup facet which contains classifier information
272                 return SUCCESS;
273             }
274
275
276             String path = repository.toMetadataPath( ref );
277             int index = path.lastIndexOf( '/' );
278             path = path.substring( 0, index );
279             File targetPath = new File( repoConfig.getLocation(), path );
280
281             if ( !targetPath.exists() )
282             {
283                 throw new ContentNotFoundException( groupId + ":" + artifactId + ":" + version );
284             }
285
286             // TODO: this should be in the storage mechanism so that it is all tied together
287             // delete from file system
288             repository.deleteVersion( ref );
289
290             File metadataFile = getMetadata( targetPath.getAbsolutePath() );
291             ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
292
293             updateMetadata( metadata, metadataFile, lastUpdatedTimestamp );
294
295             MetadataRepository metadataRepository = repositorySession.getRepository();
296
297             Collection<ArtifactMetadata> artifacts =
298                 metadataRepository.getArtifacts( repositoryId, groupId, artifactId, version );
299
300             for ( ArtifactMetadata artifact : artifacts )
301             {
302                 // TODO: mismatch between artifact (snapshot) version and project (base) version here
303                 if ( artifact.getVersion().equals( version ) )
304                 {
305                     metadataRepository.removeArtifact( artifact.getRepositoryId(), artifact.getNamespace(),
306                                                        artifact.getProject(), artifact.getVersion(), artifact.getId() );
307
308                     // TODO: move into the metadata repository proper - need to differentiate attachment of
309                     //       repository metadata to an artifact
310                     for ( RepositoryListener listener : listeners )
311                     {
312                         listener.deleteArtifact( metadataRepository, repository.getId(), artifact.getNamespace(),
313                                                  artifact.getProject(), artifact.getVersion(), artifact.getId() );
314                     }
315
316                     triggerAuditEvent( repositoryId, path, AuditEvent.REMOVE_FILE );
317                 }
318             }
319             repositorySession.save();
320         }
321         catch ( ContentNotFoundException e )
322         {
323             addActionError( "Artifact does not exist: " + e.getMessage() );
324             return ERROR;
325         }
326         catch ( RepositoryNotFoundException e )
327         {
328             addActionError( "Target repository cannot be found: " + e.getMessage() );
329             return ERROR;
330         }
331         catch ( RepositoryException e )
332         {
333             addActionError( "Repository exception: " + e.getMessage() );
334             return ERROR;
335         }
336         catch ( MetadataResolutionException e )
337         {
338             addActionError( "Repository exception: " + e.getMessage() );
339             return ERROR;
340         }
341         catch ( MetadataRepositoryException e )
342         {
343             addActionError( "Repository exception: " + e.getMessage() );
344             return ERROR;
345         }
346         catch ( RepositoryAdminException e )
347         {
348             addActionError( "RepositoryAdmin exception: " + e.getMessage() );
349             return ERROR;
350         }
351         finally
352         {
353             repositorySession.close();
354         }
355
356         String msg = "Artifact \'" + groupId + ":" + artifactId + ":" + version
357             + "\' was successfully deleted from repository \'" + repositoryId + "\'";
358
359         addActionMessage( msg );
360
361         reset();
362         return SUCCESS;
363     }
364
365     private File getMetadata( String targetPath )
366     {
367         String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
368
369         return new File( artifactPath, MetadataTools.MAVEN_METADATA );
370     }
371
372     private ArchivaRepositoryMetadata getMetadata( File metadataFile )
373         throws RepositoryMetadataException
374     {
375         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
376         if ( metadataFile.exists() )
377         {
378             metadata = RepositoryMetadataReader.read( metadataFile );
379         }
380         return metadata;
381     }
382
383     /**
384      * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
385      *
386      * @param metadata
387      */
388     private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp )
389         throws RepositoryMetadataException
390     {
391         List<String> availableVersions = new ArrayList<String>();
392         String latestVersion = "";
393
394         if ( metadataFile.exists() )
395         {
396             if ( metadata.getAvailableVersions() != null )
397             {
398                 availableVersions = metadata.getAvailableVersions();
399
400                 if ( availableVersions.size() > 0 )
401                 {
402                     Collections.sort( availableVersions, VersionComparator.getInstance() );
403
404                     if ( availableVersions.contains( version ) )
405                     {
406                         availableVersions.remove( availableVersions.indexOf( version ) );
407                     }
408                     if ( availableVersions.size() > 0 )
409                     {
410                         latestVersion = availableVersions.get( availableVersions.size() - 1 );
411                     }
412                 }
413             }
414         }
415
416         if ( metadata.getGroupId() == null )
417         {
418             metadata.setGroupId( groupId );
419         }
420         if ( metadata.getArtifactId() == null )
421         {
422             metadata.setArtifactId( artifactId );
423         }
424
425         if ( !VersionUtil.isSnapshot( version ) )
426         {
427             if ( metadata.getReleasedVersion() != null && metadata.getReleasedVersion().equals( version ) )
428             {
429                 metadata.setReleasedVersion( latestVersion );
430             }
431         }
432
433         metadata.setLatestVersion( latestVersion );
434         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
435         metadata.setAvailableVersions( availableVersions );
436
437         RepositoryMetadataWriter.write( metadata, metadataFile );
438         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
439         checksum.fixChecksums( algorithms );
440     }
441
442     public void validate()
443     {
444         try
445         {
446             if ( !userRepositories.isAuthorizedToDeleteArtifacts( getPrincipal(), repositoryId ) )
447             {
448                 addActionError( "User is not authorized to delete artifacts in repository '" + repositoryId + "'." );
449             }
450
451             if ( ( version.length() > 0 ) && ( !VersionUtil.isVersion( version ) ) )
452             {
453                 addActionError( "Invalid version." );
454             }
455         }
456         catch ( AccessDeniedException e )
457         {
458             addActionError( e.getMessage() );
459         }
460         catch ( ArchivaSecurityException e )
461         {
462             addActionError( e.getMessage() );
463         }
464
465         // trims all request parameter values, since the trailing/leading white-spaces are ignored during validation.
466         trimAllRequestParameterValues();
467     }
468
469     private List<String> getManagableRepos()
470     {
471         try
472         {
473             return userRepositories.getManagableRepositoryIds( getPrincipal() );
474         }
475         catch ( PrincipalNotFoundException e )
476         {
477             log.warn( e.getMessage(), e );
478         }
479         catch ( AccessDeniedException e )
480         {
481             log.warn( e.getMessage(), e );
482             // TODO: pass this onto the screen.
483         }
484         catch ( ArchivaSecurityException e )
485         {
486             log.warn( e.getMessage(), e );
487         }
488         return Collections.emptyList();
489     }
490
491     private void trimAllRequestParameterValues()
492     {
493         if ( StringUtils.isNotEmpty( groupId ) )
494         {
495             groupId = groupId.trim();
496         }
497
498         if ( StringUtils.isNotEmpty( artifactId ) )
499         {
500             artifactId = artifactId.trim();
501         }
502
503         if ( StringUtils.isNotEmpty( version ) )
504         {
505             version = version.trim();
506         }
507
508         if ( StringUtils.isNotEmpty( repositoryId ) )
509         {
510             repositoryId = repositoryId.trim();
511         }
512     }
513
514     public List<RepositoryListener> getListeners()
515     {
516         return listeners;
517     }
518
519     public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
520     {
521         this.repositoryFactory = repositoryFactory;
522     }
523
524     public ManagedRepositoryAdmin getManagedRepositoryAdmin()
525     {
526         return managedRepositoryAdmin;
527     }
528
529     public void setManagedRepositoryAdmin( ManagedRepositoryAdmin managedRepositoryAdmin )
530     {
531         this.managedRepositoryAdmin = managedRepositoryAdmin;
532     }
533 }