]> source.dussan.org Git - archiva.git/blob
ff3b1dde1ea825b08e92d3f8950e95a7fb2a2ce4
[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             String timestamp = fmt.format( lastUpdatedTimestamp );
217
218             ManagedRepositoryConfiguration repoConfig =
219                 configuration.getConfiguration().findManagedRepositoryById( repositoryId );
220
221             VersionedReference ref = new VersionedReference();
222             ref.setArtifactId( artifactId );
223             ref.setGroupId( groupId );
224             ref.setVersion( version );
225
226             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
227
228             String path = repository.toMetadataPath( ref );
229             int index = path.lastIndexOf( '/' );
230             File targetPath = new File( repoConfig.getLocation(), path.substring( 0, index ) );
231
232             if ( !targetPath.exists() )
233             {
234                 throw new ContentNotFoundException( groupId + ":" + artifactId + ":" + version );
235             }
236
237             // delete from file system
238             repository.deleteVersion( ref );
239
240             File metadataFile = getMetadata( targetPath.getAbsolutePath() );
241             ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
242
243             updateMetadata( metadata, metadataFile, lastUpdatedTimestamp );
244
245             ArtifactVersionsConstraint constraint =
246                 new ArtifactVersionsConstraint( repositoryId, groupId, artifactId, false );
247             List<ArchivaArtifact> artifacts = null;
248
249             try
250             {
251                 artifacts = artifactDAO.queryArtifacts( constraint );
252
253                 if ( artifacts != null )
254                 {
255                     for ( ArchivaArtifact artifact : artifacts )
256                     {
257                         if ( artifact.getVersion().equals( version ) )
258                         {
259                             databaseConsumers.executeCleanupConsumer( artifact );
260                         }
261                     }
262                 }
263             }
264             catch ( ArchivaDatabaseException e )
265             {
266                 addActionError( "Error occurred while cleaning up database: " + e.getMessage() );
267                 return ERROR;
268             }
269
270             String msg =
271                 "Artifact \'" + groupId + ":" + artifactId + ":" + version +
272                     "\' was successfully deleted from repository \'" + repositoryId + "\'";
273
274             triggerAuditEvent( getPrincipal(), repositoryId, groupId + ":" + artifactId + ":" + version,
275                                AuditEvent.REMOVE_FILE );
276
277             addActionMessage( msg );
278
279             reset();
280             return SUCCESS;
281         }
282         catch ( ContentNotFoundException e )
283         {
284             addActionError( "Artifact does not exist: " + e.getMessage() );
285             return ERROR;
286         }
287         catch ( RepositoryNotFoundException e )
288         {
289             addActionError( "Target repository cannot be found: " + e.getMessage() );
290             return ERROR;
291         }
292         catch ( RepositoryException e )
293         {
294             addActionError( "Repository exception: " + e.getMessage() );
295             return ERROR;
296         }
297     }
298
299     private String getPrincipal()
300     {
301         return archivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
302     }
303
304     private File getMetadata( String targetPath )
305     {
306         String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
307
308         return new File( artifactPath, MetadataTools.MAVEN_METADATA );
309     }
310
311     private ArchivaRepositoryMetadata getMetadata( File metadataFile )
312         throws RepositoryMetadataException
313     {
314         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
315         if ( metadataFile.exists() )
316         {
317             metadata = RepositoryMetadataReader.read( metadataFile );
318         }
319         return metadata;
320     }
321
322     /**
323      * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
324      * 
325      * @param metadata
326      */
327     private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp )
328         throws RepositoryMetadataException
329     {
330         List<String> availableVersions = new ArrayList<String>();
331         String latestVersion = "";
332
333         if ( metadataFile.exists() )
334         {
335             if ( metadata.getAvailableVersions() != null )
336             {
337                 availableVersions = metadata.getAvailableVersions();
338
339                 if ( availableVersions.size() > 0 )
340                 {
341                     Collections.sort( availableVersions, VersionComparator.getInstance() );
342
343                     if ( availableVersions.contains( version ) )
344                     {
345                         availableVersions.remove( availableVersions.indexOf( version ) );
346                     }
347                     if ( availableVersions.size() > 0 )
348                     {
349                         latestVersion = availableVersions.get( availableVersions.size() - 1 );
350                     }
351                 }
352             }
353         }
354
355         if ( metadata.getGroupId() == null )
356         {
357             metadata.setGroupId( groupId );
358         }
359         if ( metadata.getArtifactId() == null )
360         {
361             metadata.setArtifactId( artifactId );
362         }
363
364         if ( !VersionUtil.isSnapshot( version ) )
365         {
366             if ( metadata.getReleasedVersion().equals( version ) )
367             {
368                 metadata.setReleasedVersion( latestVersion );
369             }
370         }
371
372         metadata.setLatestVersion( latestVersion );
373         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
374         metadata.setAvailableVersions( availableVersions );
375
376         RepositoryMetadataWriter.write( metadata, metadataFile );
377         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
378         checksum.fixChecksums( algorithms );
379     }
380
381     public void validate()
382     {
383         try
384         {
385             if ( !userRepositories.isAuthorizedToDeleteArtifacts( getPrincipal(), repositoryId ) )
386             {
387                 addActionError( "User is not authorized to delete artifacts in repository '" + repositoryId + "'." );
388             }
389
390             if ( ( version.length() > 0 ) && ( !VersionUtil.isVersion( version ) ) )
391             {
392                 addActionError( "Invalid version." );
393             }
394         }
395         catch ( RbacManagerException e )
396         {
397             addActionError( e.getMessage() );
398         }
399     }
400
401     public void addAuditListener( AuditListener listener )
402     {
403         this.auditListeners.add( listener );
404     }
405
406     public void clearAuditListeners()
407     {
408         this.auditListeners.clear();
409     }
410
411     public void removeAuditListener( AuditListener listener )
412     {
413         this.auditListeners.remove( listener );
414     }
415
416     private void triggerAuditEvent( String user, String repositoryId, String resource, String action )
417     {
418         AuditEvent event = new AuditEvent( repositoryId, user, resource, action );
419         event.setRemoteIP( ServletActionContext.getRequest().getRemoteAddr() );
420
421         for ( AuditListener listener : auditListeners )
422         {
423             listener.auditEvent( event );
424         }
425     }
426 }