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