]> source.dussan.org Git - archiva.git/blob
da2f1ebb7e1a2bba98fe19eb8dee6fcbb8713ccf
[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.ArchivaDatabaseException;
39 import org.apache.maven.archiva.database.ArtifactDAO;
40 import org.apache.maven.archiva.database.constraints.ArtifactVersionsConstraint;
41 import org.apache.maven.archiva.database.updater.DatabaseConsumers;
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.ContentNotFoundException;
46 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
47 import org.apache.maven.archiva.repository.RepositoryContentFactory;
48 import org.apache.maven.archiva.repository.RepositoryException;
49 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
50 import org.apache.maven.archiva.repository.audit.AuditEvent;
51 import org.apache.maven.archiva.repository.audit.AuditListener;
52 import org.apache.maven.archiva.repository.audit.Auditable;
53 import org.apache.maven.archiva.repository.metadata.MetadataTools;
54 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
55 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
56 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
57 import org.apache.maven.archiva.security.AccessDeniedException;
58 import org.apache.maven.archiva.security.ArchivaSecurityException;
59 import org.apache.maven.archiva.security.ArchivaXworkUser;
60 import org.apache.maven.archiva.security.PrincipalNotFoundException;
61 import org.apache.maven.archiva.security.UserRepositories;
62 import org.apache.struts2.ServletActionContext;
63
64 import com.opensymphony.xwork2.ActionContext;
65 import com.opensymphony.xwork2.Preparable;
66 import com.opensymphony.xwork2.Validateable;
67
68 /**
69  * Delete an artifact. Metadata will be updated if one exists, otherwise it would be created.
70  * 
71  * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="deleteArtifactAction" instantiation-strategy="per-lookup"
72  */
73 public class DeleteArtifactAction
74     extends PlexusActionSupport
75     implements Validateable, Preparable, Auditable
76 {
77     /**
78      * @plexus.requirement
79      */
80     private ArchivaXworkUser archivaXworkUser;
81
82     /**
83      * The groupId of the artifact to be deleted.
84      */
85     private String groupId;
86
87     /**
88      * The artifactId of the artifact to be deleted.
89      */
90     private String artifactId;
91
92     /**
93      * The version of the artifact to be deleted.
94      */
95     private String version;
96
97     /**
98      * The repository where the artifact is to be deleted.
99      */
100     private String repositoryId;
101
102     /**
103      * List of managed repositories to delete from.
104      */
105     private List<String> managedRepos;
106
107     /**
108      * @plexus.requirement
109      */
110     private UserRepositories userRepositories;
111
112     /**
113      * @plexus.requirement role-hint="default"
114      */
115     private ArchivaConfiguration configuration;
116
117     /**
118      * @plexus.requirement
119      */
120     private RepositoryContentFactory repositoryFactory;
121
122     /**
123      * @plexus.requirement role-hint="jdo"
124      */
125     private ArtifactDAO artifactDAO;
126
127     /**
128      * @plexus.requirement 
129      */
130     private DatabaseConsumers databaseConsumers;
131
132     /**
133      * @plexus.requirement role="org.apache.maven.archiva.repository.audit.AuditListener"
134      */
135     private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
136
137     private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[] { ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
138
139     public String getGroupId()
140     {
141         return groupId;
142     }
143
144     public void setGroupId( String groupId )
145     {
146         this.groupId = groupId;
147     }
148
149     public String getArtifactId()
150     {
151         return artifactId;
152     }
153
154     public void setArtifactId( String artifactId )
155     {
156         this.artifactId = artifactId;
157     }
158
159     public String getVersion()
160     {
161         return version;
162     }
163
164     public void setVersion( String version )
165     {
166         this.version = version;
167     }
168
169     public String getRepositoryId()
170     {
171         return repositoryId;
172     }
173
174     public void setRepositoryId( String repositoryId )
175     {
176         this.repositoryId = repositoryId;
177     }
178
179     public List<String> getManagedRepos()
180     {
181         return managedRepos;
182     }
183
184     public void setManagedRepos( List<String> managedRepos )
185     {
186         this.managedRepos = managedRepos;
187     }
188
189     public void prepare()
190     {
191         managedRepos = getManagableRepos();
192     }
193
194     public String input()
195     {
196         return INPUT;
197     }
198
199     private void reset()
200     {
201         // reset the fields so the form is clear when 
202         // the action returns to the jsp page
203         groupId = "";
204         artifactId = "";
205         version = "";
206         repositoryId = "";
207     }
208
209     public String doDelete()
210     {
211         try
212         {
213             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
214
215             TimeZone timezone = TimeZone.getTimeZone( "UTC" );
216             DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
217             fmt.setTimeZone( timezone );
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     @SuppressWarnings("unchecked")
300     private String getPrincipal()
301     {
302         return archivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
303     }
304
305     private File getMetadata( String targetPath )
306     {
307         String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
308
309         return new File( artifactPath, MetadataTools.MAVEN_METADATA );
310     }
311
312     private ArchivaRepositoryMetadata getMetadata( File metadataFile )
313         throws RepositoryMetadataException
314     {
315         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
316         if ( metadataFile.exists() )
317         {
318             metadata = RepositoryMetadataReader.read( metadataFile );
319         }
320         return metadata;
321     }
322
323     /**
324      * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
325      * 
326      * @param metadata
327      */
328     private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp )
329         throws RepositoryMetadataException
330     {
331         List<String> availableVersions = new ArrayList<String>();
332         String latestVersion = "";
333
334         if ( metadataFile.exists() )
335         {
336             if ( metadata.getAvailableVersions() != null )
337             {
338                 availableVersions = metadata.getAvailableVersions();
339
340                 if ( availableVersions.size() > 0 )
341                 {
342                     Collections.sort( availableVersions, VersionComparator.getInstance() );
343
344                     if ( availableVersions.contains( version ) )
345                     {
346                         availableVersions.remove( availableVersions.indexOf( version ) );
347                     }
348                     if ( availableVersions.size() > 0 )
349                     {
350                         latestVersion = availableVersions.get( availableVersions.size() - 1 );
351                     }
352                 }
353             }
354         }
355
356         if ( metadata.getGroupId() == null )
357         {
358             metadata.setGroupId( groupId );
359         }
360         if ( metadata.getArtifactId() == null )
361         {
362             metadata.setArtifactId( artifactId );
363         }
364
365         if ( !VersionUtil.isSnapshot( version ) )
366         {
367             if ( metadata.getReleasedVersion().equals( version ) )
368             {
369                 metadata.setReleasedVersion( latestVersion );
370             }
371         }
372
373         metadata.setLatestVersion( latestVersion );
374         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
375         metadata.setAvailableVersions( availableVersions );
376
377         RepositoryMetadataWriter.write( metadata, metadataFile );
378         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
379         checksum.fixChecksums( algorithms );
380     }
381
382     public void validate()
383     {
384         try
385         {
386             if ( !userRepositories.isAuthorizedToDeleteArtifacts( getPrincipal(), repositoryId ) )
387             {
388                 addActionError( "User is not authorized to delete artifacts in repository '" + repositoryId + "'." );
389             }
390
391             if ( ( version.length() > 0 ) && ( !VersionUtil.isVersion( version ) ) )
392             {
393                 addActionError( "Invalid version." );
394             }
395         }
396         catch ( AccessDeniedException e )
397         {
398             addActionError( e.getMessage() );
399         }
400         catch ( ArchivaSecurityException e )
401         {
402             addActionError( e.getMessage() );
403         }
404     }
405
406     public void addAuditListener( AuditListener listener )
407     {
408         this.auditListeners.add( listener );
409     }
410
411     public void clearAuditListeners()
412     {
413         this.auditListeners.clear();
414     }
415
416     public void removeAuditListener( AuditListener listener )
417     {
418         this.auditListeners.remove( listener );
419     }
420
421     private List<String> getManagableRepos()
422     {
423         try
424         {
425             return userRepositories.getManagableRepositoryIds( getPrincipal() );
426         }
427         catch ( PrincipalNotFoundException e )
428         {
429             log.warn( e.getMessage(), e );
430         }
431         catch ( AccessDeniedException e )
432         {
433             log.warn( e.getMessage(), e );
434             // TODO: pass this onto the screen.
435         }
436         catch ( ArchivaSecurityException e )
437         {
438             log.warn( e.getMessage(), e );
439         }
440         return Collections.emptyList();
441     }
442
443     private void triggerAuditEvent( String user, String repositoryId, String resource, String action )
444     {
445         AuditEvent event = new AuditEvent( repositoryId, user, resource, action );
446         event.setRemoteIP( ServletActionContext.getRequest().getRemoteAddr() );
447
448         for ( AuditListener listener : auditListeners )
449         {
450             listener.auditEvent( event );
451         }
452     }
453 }