1 package org.apache.maven.archiva.web.action;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
22 import com.opensymphony.xwork2.Preparable;
23 import com.opensymphony.xwork2.Validateable;
24 import org.apache.archiva.audit.AuditEvent;
25 import org.apache.archiva.audit.Auditable;
26 import org.apache.archiva.checksum.ChecksumAlgorithm;
27 import org.apache.archiva.checksum.ChecksummedFile;
28 import org.apache.archiva.metadata.model.ArtifactMetadata;
29 import org.apache.archiva.metadata.repository.MetadataRepository;
30 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
31 import org.apache.archiva.metadata.repository.MetadataResolutionException;
32 import org.apache.archiva.metadata.repository.RepositorySession;
33 import org.apache.archiva.repository.events.RepositoryListener;
34 import org.apache.commons.lang.StringUtils;
35 import org.apache.maven.archiva.common.utils.VersionComparator;
36 import org.apache.maven.archiva.common.utils.VersionUtil;
37 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
38 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
39 import org.apache.maven.archiva.model.ArchivaRepositoryMetadata;
40 import org.apache.maven.archiva.model.VersionedReference;
41 import org.apache.maven.archiva.repository.ContentNotFoundException;
42 import org.apache.maven.archiva.repository.ManagedRepositoryContent;
43 import org.apache.maven.archiva.repository.RepositoryContentFactory;
44 import org.apache.maven.archiva.repository.RepositoryException;
45 import org.apache.maven.archiva.repository.RepositoryNotFoundException;
46 import org.apache.maven.archiva.repository.metadata.MetadataTools;
47 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataException;
48 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataReader;
49 import org.apache.maven.archiva.repository.metadata.RepositoryMetadataWriter;
50 import org.apache.archiva.security.AccessDeniedException;
51 import org.apache.archiva.security.ArchivaSecurityException;
52 import org.apache.archiva.security.PrincipalNotFoundException;
53 import org.apache.archiva.security.UserRepositories;
54 import org.springframework.context.annotation.Scope;
55 import org.springframework.stereotype.Controller;
57 import javax.annotation.PostConstruct;
58 import javax.inject.Inject;
60 import java.text.DateFormat;
61 import java.text.SimpleDateFormat;
62 import java.util.ArrayList;
63 import java.util.Calendar;
64 import java.util.Collection;
65 import java.util.Collections;
66 import java.util.Date;
67 import java.util.List;
68 import java.util.TimeZone;
71 * Delete an artifact. Metadata will be updated if one exists, otherwise it would be created.
73 @Controller( "deleteArtifactAction" )
75 public class DeleteArtifactAction
76 extends AbstractActionSupport
77 implements Validateable, Preparable, Auditable
80 * The groupId of the artifact to be deleted.
82 private String groupId;
85 * The artifactId of the artifact to be deleted.
87 private String artifactId;
90 * The version of the artifact to be deleted.
92 private String version;
95 * The repository where the artifact is to be deleted.
97 private String repositoryId;
100 * List of managed repositories to delete from.
102 private List<String> managedRepos;
105 private UserRepositories userRepositories;
108 private ArchivaConfiguration configuration;
111 private RepositoryContentFactory repositoryFactory;
114 private List<RepositoryListener> listeners;
116 private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[]{ ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
119 public void initialize()
124 public String getGroupId()
129 public void setGroupId( String groupId )
131 this.groupId = groupId;
134 public String getArtifactId()
139 public void setArtifactId( String artifactId )
141 this.artifactId = artifactId;
144 public String getVersion()
149 public void setVersion( String version )
151 this.version = version;
154 public String getRepositoryId()
159 public void setRepositoryId( String repositoryId )
161 this.repositoryId = repositoryId;
164 public List<String> getManagedRepos()
169 public void setManagedRepos( List<String> managedRepos )
171 this.managedRepos = managedRepos;
174 public void prepare()
176 managedRepos = getManagableRepos();
179 public String input()
186 // reset the fields so the form is clear when
187 // the action returns to the jsp page
194 public String doDelete()
196 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
198 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
199 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
200 fmt.setTimeZone( timezone );
201 ManagedRepositoryConfiguration repoConfig =
202 configuration.getConfiguration().findManagedRepositoryById( repositoryId );
204 VersionedReference ref = new VersionedReference();
205 ref.setArtifactId( artifactId );
206 ref.setGroupId( groupId );
207 ref.setVersion( version );
209 RepositorySession repositorySession = repositorySessionFactory.createSession();
212 ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
214 String path = repository.toMetadataPath( ref );
215 int index = path.lastIndexOf( '/' );
216 path = path.substring( 0, index );
217 File targetPath = new File( repoConfig.getLocation(), path );
219 if ( !targetPath.exists() )
221 throw new ContentNotFoundException( groupId + ":" + artifactId + ":" + version );
224 // TODO: this should be in the storage mechanism so that it is all tied together
225 // delete from file system
226 repository.deleteVersion( ref );
228 File metadataFile = getMetadata( targetPath.getAbsolutePath() );
229 ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
231 updateMetadata( metadata, metadataFile, lastUpdatedTimestamp );
233 MetadataRepository metadataRepository = repositorySession.getRepository();
234 Collection<ArtifactMetadata> artifacts =
235 metadataRepository.getArtifacts( repositoryId, groupId, artifactId, version );
237 for ( ArtifactMetadata artifact : artifacts )
239 // TODO: mismatch between artifact (snapshot) version and project (base) version here
240 if ( artifact.getVersion().equals( version ) )
242 metadataRepository.removeArtifact( artifact.getRepositoryId(), artifact.getNamespace(),
243 artifact.getProject(), artifact.getVersion(), artifact.getId() );
245 // TODO: move into the metadata repository proper - need to differentiate attachment of
246 // repository metadata to an artifact
247 for ( RepositoryListener listener : listeners )
249 listener.deleteArtifact( metadataRepository, repository.getId(), artifact.getNamespace(),
250 artifact.getProject(), artifact.getVersion(), artifact.getId() );
253 triggerAuditEvent( repositoryId, path, AuditEvent.REMOVE_FILE );
256 repositorySession.save();
258 catch ( ContentNotFoundException e )
260 addActionError( "Artifact does not exist: " + e.getMessage() );
263 catch ( RepositoryNotFoundException e )
265 addActionError( "Target repository cannot be found: " + e.getMessage() );
268 catch ( RepositoryException e )
270 addActionError( "Repository exception: " + e.getMessage() );
273 catch ( MetadataResolutionException e )
275 addActionError( "Repository exception: " + e.getMessage() );
278 catch ( MetadataRepositoryException e )
280 addActionError( "Repository exception: " + e.getMessage() );
285 repositorySession.close();
288 String msg = "Artifact \'" + groupId + ":" + artifactId + ":" + version
289 + "\' was successfully deleted from repository \'" + repositoryId + "\'";
291 addActionMessage( msg );
297 private File getMetadata( String targetPath )
299 String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
301 return new File( artifactPath, MetadataTools.MAVEN_METADATA );
304 private ArchivaRepositoryMetadata getMetadata( File metadataFile )
305 throws RepositoryMetadataException
307 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
308 if ( metadataFile.exists() )
310 metadata = RepositoryMetadataReader.read( metadataFile );
316 * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
320 private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp )
321 throws RepositoryMetadataException
323 List<String> availableVersions = new ArrayList<String>();
324 String latestVersion = "";
326 if ( metadataFile.exists() )
328 if ( metadata.getAvailableVersions() != null )
330 availableVersions = metadata.getAvailableVersions();
332 if ( availableVersions.size() > 0 )
334 Collections.sort( availableVersions, VersionComparator.getInstance() );
336 if ( availableVersions.contains( version ) )
338 availableVersions.remove( availableVersions.indexOf( version ) );
340 if ( availableVersions.size() > 0 )
342 latestVersion = availableVersions.get( availableVersions.size() - 1 );
348 if ( metadata.getGroupId() == null )
350 metadata.setGroupId( groupId );
352 if ( metadata.getArtifactId() == null )
354 metadata.setArtifactId( artifactId );
357 if ( !VersionUtil.isSnapshot( version ) )
359 if ( metadata.getReleasedVersion() != null && metadata.getReleasedVersion().equals( version ) )
361 metadata.setReleasedVersion( latestVersion );
365 metadata.setLatestVersion( latestVersion );
366 metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
367 metadata.setAvailableVersions( availableVersions );
369 RepositoryMetadataWriter.write( metadata, metadataFile );
370 ChecksummedFile checksum = new ChecksummedFile( metadataFile );
371 checksum.fixChecksums( algorithms );
374 public void validate()
378 if ( !userRepositories.isAuthorizedToDeleteArtifacts( getPrincipal(), repositoryId ) )
380 addActionError( "User is not authorized to delete artifacts in repository '" + repositoryId + "'." );
383 if ( ( version.length() > 0 ) && ( !VersionUtil.isVersion( version ) ) )
385 addActionError( "Invalid version." );
388 catch ( AccessDeniedException e )
390 addActionError( e.getMessage() );
392 catch ( ArchivaSecurityException e )
394 addActionError( e.getMessage() );
397 // trims all request parameter values, since the trailing/leading white-spaces are ignored during validation.
398 trimAllRequestParameterValues();
401 private List<String> getManagableRepos()
405 return userRepositories.getManagableRepositoryIds( getPrincipal() );
407 catch ( PrincipalNotFoundException e )
409 log.warn( e.getMessage(), e );
411 catch ( AccessDeniedException e )
413 log.warn( e.getMessage(), e );
414 // TODO: pass this onto the screen.
416 catch ( ArchivaSecurityException e )
418 log.warn( e.getMessage(), e );
420 return Collections.emptyList();
423 private void trimAllRequestParameterValues()
425 if ( StringUtils.isNotEmpty( groupId ) )
427 groupId = groupId.trim();
430 if ( StringUtils.isNotEmpty( artifactId ) )
432 artifactId = artifactId.trim();
435 if ( StringUtils.isNotEmpty( version ) )
437 version = version.trim();
440 if ( StringUtils.isNotEmpty( repositoryId ) )
442 repositoryId = repositoryId.trim();
446 public List<RepositoryListener> getListeners()
451 public void setRepositoryFactory( RepositoryContentFactory repositoryFactory )
453 this.repositoryFactory = repositoryFactory;
456 public void setConfiguration( ArchivaConfiguration configuration )
458 this.configuration = configuration;