]> source.dussan.org Git - archiva.git/blob
aae9ac6924213f4297ab8a94e508913e1102ffa9
[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.Preparable;
23 import com.opensymphony.xwork2.Validateable;
24 import org.apache.archiva.checksum.ChecksumAlgorithm;
25 import org.apache.archiva.checksum.ChecksummedFile;
26 import org.apache.archiva.metadata.model.ArtifactMetadata;
27 import org.apache.archiva.metadata.repository.MetadataRepository;
28 import org.apache.archiva.repository.events.RepositoryListener;
29 import org.apache.maven.archiva.common.utils.VersionComparator;
30 import org.apache.maven.archiva.common.utils.VersionUtil;
31 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
32 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
33 import org.apache.maven.archiva.model.ArchivaRepositoryMetadata;
34 import org.apache.maven.archiva.model.VersionedReference;
35 import org.apache.maven.archiva.repository.ContentNotFoundException;
36 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
37 import org.apache.maven.archiva.repository.RepositoryContentFactory;
38 import org.apache.maven.archiva.repository.RepositoryException;
39 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
40 import org.apache.maven.archiva.repository.audit.AuditEvent;
41 import org.apache.maven.archiva.repository.audit.Auditable;
42 import org.apache.maven.archiva.repository.metadata.MetadataTools;
43 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
44 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
45 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
46 import org.apache.maven.archiva.security.AccessDeniedException;
47 import org.apache.maven.archiva.security.ArchivaSecurityException;
48 import org.apache.maven.archiva.security.PrincipalNotFoundException;
49 import org.apache.maven.archiva.security.UserRepositories;
50
51 import java.io.File;
52 import java.text.DateFormat;
53 import java.text.SimpleDateFormat;
54 import java.util.ArrayList;
55 import java.util.Calendar;
56 import java.util.Collection;
57 import java.util.Collections;
58 import java.util.Date;
59 import java.util.List;
60 import java.util.TimeZone;
61
62 /**
63  * Delete an artifact. Metadata will be updated if one exists, otherwise it would be created.
64  *
65  * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="deleteArtifactAction" instantiation-strategy="per-lookup"
66  */
67 public class DeleteArtifactAction
68     extends PlexusActionSupport
69     implements Validateable, Preparable, Auditable
70 {
71     /**
72      * The groupId of the artifact to be deleted.
73      */
74     private String groupId;
75
76     /**
77      * The artifactId of the artifact to be deleted.
78      */
79     private String artifactId;
80
81     /**
82      * The version of the artifact to be deleted.
83      */
84     private String version;
85
86     /**
87      * The repository where the artifact is to be deleted.
88      */
89     private String repositoryId;
90
91     /**
92      * List of managed repositories to delete from.
93      */
94     private List<String> managedRepos;
95
96     /**
97      * @plexus.requirement
98      */
99     private UserRepositories userRepositories;
100
101     /**
102      * @plexus.requirement role-hint="default"
103      */
104     private ArchivaConfiguration configuration;
105
106     /**
107      * @plexus.requirement
108      */
109     private RepositoryContentFactory repositoryFactory;
110
111     /**
112      * @plexus.requirement role="org.apache.archiva.repository.events.RepositoryListener"
113      */
114     private List<RepositoryListener> listeners;
115
116     private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5};
117
118     /**
119      * @plexus.requirement
120      */
121     private MetadataRepository metadataRepository;
122
123     public String getGroupId()
124     {
125         return groupId;
126     }
127
128     public void setGroupId( String groupId )
129     {
130         this.groupId = groupId;
131     }
132
133     public String getArtifactId()
134     {
135         return artifactId;
136     }
137
138     public void setArtifactId( String artifactId )
139     {
140         this.artifactId = artifactId;
141     }
142
143     public String getVersion()
144     {
145         return version;
146     }
147
148     public void setVersion( String version )
149     {
150         this.version = version;
151     }
152
153     public String getRepositoryId()
154     {
155         return repositoryId;
156     }
157
158     public void setRepositoryId( String repositoryId )
159     {
160         this.repositoryId = repositoryId;
161     }
162
163     public List<String> getManagedRepos()
164     {
165         return managedRepos;
166     }
167
168     public void setManagedRepos( List<String> managedRepos )
169     {
170         this.managedRepos = managedRepos;
171     }
172
173     public void prepare()
174     {
175         managedRepos = getManagableRepos();
176     }
177
178     public String input()
179     {
180         return INPUT;
181     }
182
183     private void reset()
184     {
185         // reset the fields so the form is clear when 
186         // the action returns to the jsp page
187         groupId = "";
188         artifactId = "";
189         version = "";
190         repositoryId = "";
191     }
192
193     public String doDelete()
194     {
195         try
196         {
197             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
198
199             TimeZone timezone = TimeZone.getTimeZone( "UTC" );
200             DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
201             fmt.setTimeZone( timezone );
202             ManagedRepositoryConfiguration repoConfig =
203                 configuration.getConfiguration().findManagedRepositoryById( repositoryId );
204
205             VersionedReference ref = new VersionedReference();
206             ref.setArtifactId( artifactId );
207             ref.setGroupId( groupId );
208             ref.setVersion( version );
209
210             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
211
212             String path = repository.toMetadataPath( ref );
213             int index = path.lastIndexOf( '/' );
214             path = path.substring( 0, index );
215             File targetPath = new File( repoConfig.getLocation(), path );
216
217             if ( !targetPath.exists() )
218             {
219                 throw new ContentNotFoundException( groupId + ":" + artifactId + ":" + version );
220             }
221
222             // TODO: this should be in the storage mechanism so that it is all tied together
223             // delete from file system
224             repository.deleteVersion( ref );
225
226             File metadataFile = getMetadata( targetPath.getAbsolutePath() );
227             ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
228
229             updateMetadata( metadata, metadataFile, lastUpdatedTimestamp );
230
231             Collection<ArtifactMetadata> artifacts =
232                 metadataRepository.getArtifacts( repositoryId, groupId, artifactId, version );
233
234             for ( ArtifactMetadata artifact : artifacts )
235             {
236                 // TODO: mismatch between artifact (snapshot) version and project (base) version here
237                 if ( artifact.getVersion().equals( version ) )
238                 {
239                     metadataRepository.deleteArtifact( artifact.getRepositoryId(), artifact.getNamespace(),
240                                                        artifact.getProject(), artifact.getVersion(),
241                                                        artifact.getId() );
242
243                     // TODO: move into the metadata repository proper - need to differentiate attachment of
244                     //       repository metadata to an artifact
245                     for ( RepositoryListener listener : listeners )
246                     {
247                         listener.deleteArtifact( repository.getId(), artifact.getNamespace(), artifact.getProject(),
248                                                  artifact.getVersion(), artifact.getId() );
249                     }
250
251                     triggerAuditEvent( repositoryId, path, AuditEvent.REMOVE_FILE );
252                 }
253             }
254
255             String msg = "Artifact \'" + groupId + ":" + artifactId + ":" + version +
256                 "\' was successfully deleted from repository \'" + repositoryId + "\'";
257
258             addActionMessage( msg );
259
260             reset();
261             return SUCCESS;
262         }
263         catch ( ContentNotFoundException e )
264         {
265             addActionError( "Artifact does not exist: " + e.getMessage() );
266             return ERROR;
267         }
268         catch ( RepositoryNotFoundException e )
269         {
270             addActionError( "Target repository cannot be found: " + e.getMessage() );
271             return ERROR;
272         }
273         catch ( RepositoryException e )
274         {
275             addActionError( "Repository exception: " + e.getMessage() );
276             return ERROR;
277         }
278     }
279
280     private File getMetadata( String targetPath )
281     {
282         String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
283
284         return new File( artifactPath, MetadataTools.MAVEN_METADATA );
285     }
286
287     private ArchivaRepositoryMetadata getMetadata( File metadataFile )
288         throws RepositoryMetadataException
289     {
290         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
291         if ( metadataFile.exists() )
292         {
293             metadata = RepositoryMetadataReader.read( metadataFile );
294         }
295         return metadata;
296     }
297
298     /**
299      * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
300      *
301      * @param metadata
302      */
303     private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp )
304         throws RepositoryMetadataException
305     {
306         List<String> availableVersions = new ArrayList<String>();
307         String latestVersion = "";
308
309         if ( metadataFile.exists() )
310         {
311             if ( metadata.getAvailableVersions() != null )
312             {
313                 availableVersions = metadata.getAvailableVersions();
314
315                 if ( availableVersions.size() > 0 )
316                 {
317                     Collections.sort( availableVersions, VersionComparator.getInstance() );
318
319                     if ( availableVersions.contains( version ) )
320                     {
321                         availableVersions.remove( availableVersions.indexOf( version ) );
322                     }
323                     if ( availableVersions.size() > 0 )
324                     {
325                         latestVersion = availableVersions.get( availableVersions.size() - 1 );
326                     }
327                 }
328             }
329         }
330
331         if ( metadata.getGroupId() == null )
332         {
333             metadata.setGroupId( groupId );
334         }
335         if ( metadata.getArtifactId() == null )
336         {
337             metadata.setArtifactId( artifactId );
338         }
339
340         if ( !VersionUtil.isSnapshot( version ) )
341         {
342             if ( metadata.getReleasedVersion().equals( version ) )
343             {
344                 metadata.setReleasedVersion( latestVersion );
345             }
346         }
347
348         metadata.setLatestVersion( latestVersion );
349         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
350         metadata.setAvailableVersions( availableVersions );
351
352         RepositoryMetadataWriter.write( metadata, metadataFile );
353         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
354         checksum.fixChecksums( algorithms );
355     }
356
357     public void validate()
358     {
359         try
360         {
361             if ( !userRepositories.isAuthorizedToDeleteArtifacts( getPrincipal(), repositoryId ) )
362             {
363                 addActionError( "User is not authorized to delete artifacts in repository '" + repositoryId + "'." );
364             }
365
366             if ( ( version.length() > 0 ) && ( !VersionUtil.isVersion( version ) ) )
367             {
368                 addActionError( "Invalid version." );
369             }
370         }
371         catch ( AccessDeniedException e )
372         {
373             addActionError( e.getMessage() );
374         }
375         catch ( ArchivaSecurityException e )
376         {
377             addActionError( e.getMessage() );
378         }
379     }
380
381     private List<String> getManagableRepos()
382     {
383         try
384         {
385             return userRepositories.getManagableRepositoryIds( getPrincipal() );
386         }
387         catch ( PrincipalNotFoundException e )
388         {
389             log.warn( e.getMessage(), e );
390         }
391         catch ( AccessDeniedException e )
392         {
393             log.warn( e.getMessage(), e );
394             // TODO: pass this onto the screen.
395         }
396         catch ( ArchivaSecurityException e )
397         {
398             log.warn( e.getMessage(), e );
399         }
400         return Collections.emptyList();
401     }
402
403     public List<RepositoryListener> getListeners()
404     {
405         return listeners;
406     }
407 }