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