]> source.dussan.org Git - archiva.git/blob
7d2d62b2569e794a5fb84d10d1d8ac7e02e31220
[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.Auditable;
52 import org.apache.maven.archiva.repository.metadata.MetadataTools;
53 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
54 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
55 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
56 import org.apache.maven.archiva.security.AccessDeniedException;
57 import org.apache.maven.archiva.security.ArchivaSecurityException;
58 import org.apache.maven.archiva.security.PrincipalNotFoundException;
59 import org.apache.maven.archiva.security.UserRepositories;
60
61 import com.opensymphony.xwork2.Preparable;
62 import com.opensymphony.xwork2.Validateable;
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     private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[] { ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
124
125     public String getGroupId()
126     {
127         return groupId;
128     }
129
130     public void setGroupId( String groupId )
131     {
132         this.groupId = groupId;
133     }
134
135     public String getArtifactId()
136     {
137         return artifactId;
138     }
139
140     public void setArtifactId( String artifactId )
141     {
142         this.artifactId = artifactId;
143     }
144
145     public String getVersion()
146     {
147         return version;
148     }
149
150     public void setVersion( String version )
151     {
152         this.version = version;
153     }
154
155     public String getRepositoryId()
156     {
157         return repositoryId;
158     }
159
160     public void setRepositoryId( String repositoryId )
161     {
162         this.repositoryId = repositoryId;
163     }
164
165     public List<String> getManagedRepos()
166     {
167         return managedRepos;
168     }
169
170     public void setManagedRepos( List<String> managedRepos )
171     {
172         this.managedRepos = managedRepos;
173     }
174
175     public void prepare()
176     {
177         managedRepos = getManagableRepos();
178     }
179
180     public String input()
181     {
182         return INPUT;
183     }
184
185     private void reset()
186     {
187         // reset the fields so the form is clear when 
188         // the action returns to the jsp page
189         groupId = "";
190         artifactId = "";
191         version = "";
192         repositoryId = "";
193     }
194
195     public String doDelete()
196     {
197         try
198         {
199             Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
200
201             TimeZone timezone = TimeZone.getTimeZone( "UTC" );
202             DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
203             fmt.setTimeZone( timezone );
204             ManagedRepositoryConfiguration repoConfig =
205                 configuration.getConfiguration().findManagedRepositoryById( repositoryId );
206
207             VersionedReference ref = new VersionedReference();
208             ref.setArtifactId( artifactId );
209             ref.setGroupId( groupId );
210             ref.setVersion( version );
211
212             ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
213
214             String path = repository.toMetadataPath( ref );
215             int index = path.lastIndexOf( '/' );
216             File targetPath = new File( repoConfig.getLocation(), path.substring( 0, index ) );
217
218             if ( !targetPath.exists() )
219             {
220                 throw new ContentNotFoundException( groupId + ":" + artifactId + ":" + version );
221             }
222
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             ArtifactVersionsConstraint constraint =
232                 new ArtifactVersionsConstraint( repositoryId, groupId, artifactId, false );
233             List<ArchivaArtifact> artifacts = null;
234
235             try
236             {
237                 artifacts = artifactDAO.queryArtifacts( constraint );
238
239                 if ( artifacts != null )
240                 {
241                     for ( ArchivaArtifact artifact : artifacts )
242                     {
243                         if ( artifact.getVersion().equals( version ) )
244                         {
245                             databaseConsumers.executeCleanupConsumer( artifact );
246                         }
247                     }
248                 }
249             }
250             catch ( ArchivaDatabaseException e )
251             {
252                 addActionError( "Error occurred while cleaning up database: " + e.getMessage() );
253                 return ERROR;
254             }
255
256             String msg =
257                 "Artifact \'" + groupId + ":" + artifactId + ":" + version +
258                     "\' was successfully deleted from repository \'" + repositoryId + "\'";
259
260             triggerAuditEvent( repositoryId, groupId + ":" + artifactId + ":" + version,
261                                AuditEvent.REMOVE_FILE );
262
263             addActionMessage( msg );
264
265             reset();
266             return SUCCESS;
267         }
268         catch ( ContentNotFoundException e )
269         {
270             addActionError( "Artifact does not exist: " + e.getMessage() );
271             return ERROR;
272         }
273         catch ( RepositoryNotFoundException e )
274         {
275             addActionError( "Target repository cannot be found: " + e.getMessage() );
276             return ERROR;
277         }
278         catch ( RepositoryException e )
279         {
280             addActionError( "Repository exception: " + e.getMessage() );
281             return ERROR;
282         }
283     }
284
285     private File getMetadata( String targetPath )
286     {
287         String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
288
289         return new File( artifactPath, MetadataTools.MAVEN_METADATA );
290     }
291
292     private ArchivaRepositoryMetadata getMetadata( File metadataFile )
293         throws RepositoryMetadataException
294     {
295         ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
296         if ( metadataFile.exists() )
297         {
298             metadata = RepositoryMetadataReader.read( metadataFile );
299         }
300         return metadata;
301     }
302
303     /**
304      * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
305      * 
306      * @param metadata
307      */
308     private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp )
309         throws RepositoryMetadataException
310     {
311         List<String> availableVersions = new ArrayList<String>();
312         String latestVersion = "";
313
314         if ( metadataFile.exists() )
315         {
316             if ( metadata.getAvailableVersions() != null )
317             {
318                 availableVersions = metadata.getAvailableVersions();
319
320                 if ( availableVersions.size() > 0 )
321                 {
322                     Collections.sort( availableVersions, VersionComparator.getInstance() );
323
324                     if ( availableVersions.contains( version ) )
325                     {
326                         availableVersions.remove( availableVersions.indexOf( version ) );
327                     }
328                     if ( availableVersions.size() > 0 )
329                     {
330                         latestVersion = availableVersions.get( availableVersions.size() - 1 );
331                     }
332                 }
333             }
334         }
335
336         if ( metadata.getGroupId() == null )
337         {
338             metadata.setGroupId( groupId );
339         }
340         if ( metadata.getArtifactId() == null )
341         {
342             metadata.setArtifactId( artifactId );
343         }
344
345         if ( !VersionUtil.isSnapshot( version ) )
346         {
347             if ( metadata.getReleasedVersion().equals( version ) )
348             {
349                 metadata.setReleasedVersion( latestVersion );
350             }
351         }
352
353         metadata.setLatestVersion( latestVersion );
354         metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
355         metadata.setAvailableVersions( availableVersions );
356
357         RepositoryMetadataWriter.write( metadata, metadataFile );
358         ChecksummedFile checksum = new ChecksummedFile( metadataFile );
359         checksum.fixChecksums( algorithms );
360     }
361
362     public void validate()
363     {
364         try
365         {
366             if ( !userRepositories.isAuthorizedToDeleteArtifacts( getPrincipal(), repositoryId ) )
367             {
368                 addActionError( "User is not authorized to delete artifacts in repository '" + repositoryId + "'." );
369             }
370
371             if ( ( version.length() > 0 ) && ( !VersionUtil.isVersion( version ) ) )
372             {
373                 addActionError( "Invalid version." );
374             }
375         }
376         catch ( AccessDeniedException e )
377         {
378             addActionError( e.getMessage() );
379         }
380         catch ( ArchivaSecurityException e )
381         {
382             addActionError( e.getMessage() );
383         }
384     }
385
386     private List<String> getManagableRepos()
387     {
388         try
389         {
390             return userRepositories.getManagableRepositoryIds( getPrincipal() );
391         }
392         catch ( PrincipalNotFoundException e )
393         {
394             log.warn( e.getMessage(), e );
395         }
396         catch ( AccessDeniedException e )
397         {
398             log.warn( e.getMessage(), e );
399             // TODO: pass this onto the screen.
400         }
401         catch ( ArchivaSecurityException e )
402         {
403             log.warn( e.getMessage(), e );
404         }
405         return Collections.emptyList();
406     }
407 }