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
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;
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.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.codehaus.plexus.redback.rbac.RbacManagerException;
64 import org.apache.struts2.ServletActionContext;
65 import com.opensymphony.xwork2.ActionContext;
66 import com.opensymphony.xwork2.Preparable;
67 import com.opensymphony.xwork2.Validateable;
70 * Delete an artifact. Metadata will be updated if one exists, otherwise it would be created.
72 * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="deleteArtifactAction" instantiation-strategy="per-lookup"
74 public class DeleteArtifactAction
75 extends PlexusActionSupport
76 implements Validateable, Preparable, Auditable
81 private ArchivaXworkUser archivaXworkUser;
84 * The groupId of the artifact to be deleted.
86 private String groupId;
89 * The artifactId of the artifact to be deleted.
91 private String artifactId;
94 * The version of the artifact to be deleted.
96 private String version;
99 * The repository where the artifact is to be deleted.
101 private String repositoryId;
104 * List of managed repositories to delete from.
106 private List<String> managedRepos;
109 * @plexus.requirement
111 private UserRepositories userRepositories;
114 * @plexus.requirement role-hint="default"
116 private ArchivaConfiguration configuration;
119 * @plexus.requirement
121 private RepositoryContentFactory repositoryFactory;
124 * @plexus.requirement role-hint="jdo"
126 private ArtifactDAO artifactDAO;
129 * @plexus.requirement
131 private DatabaseConsumers databaseConsumers;
134 * @plexus.requirement role="org.apache.maven.archiva.repository.audit.AuditListener"
136 private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
138 private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[] { ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
140 public String getGroupId()
145 public void setGroupId( String groupId )
147 this.groupId = groupId;
150 public String getArtifactId()
155 public void setArtifactId( String artifactId )
157 this.artifactId = artifactId;
160 public String getVersion()
165 public void setVersion( String version )
167 this.version = version;
170 public String getRepositoryId()
175 public void setRepositoryId( String repositoryId )
177 this.repositoryId = repositoryId;
180 public List<String> getManagedRepos()
185 public void setManagedRepos( List<String> managedRepos )
187 this.managedRepos = managedRepos;
190 public void prepare()
192 managedRepos = getManagableRepos();
195 public String input()
202 // reset the fields so the form is clear when
203 // the action returns to the jsp page
210 public String doDelete()
214 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
216 TimeZone timezone = TimeZone.getTimeZone( "UTC" );
217 DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
218 fmt.setTimeZone( timezone );
219 ManagedRepositoryConfiguration repoConfig =
220 configuration.getConfiguration().findManagedRepositoryById( repositoryId );
222 VersionedReference ref = new VersionedReference();
223 ref.setArtifactId( artifactId );
224 ref.setGroupId( groupId );
225 ref.setVersion( version );
227 ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
229 String path = repository.toMetadataPath( ref );
230 int index = path.lastIndexOf( '/' );
231 File targetPath = new File( repoConfig.getLocation(), path.substring( 0, index ) );
233 if ( !targetPath.exists() )
235 throw new ContentNotFoundException( groupId + ":" + artifactId + ":" + version );
238 // delete from file system
239 repository.deleteVersion( ref );
241 File metadataFile = getMetadata( targetPath.getAbsolutePath() );
242 ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
244 updateMetadata( metadata, metadataFile, lastUpdatedTimestamp );
246 ArtifactVersionsConstraint constraint =
247 new ArtifactVersionsConstraint( repositoryId, groupId, artifactId, false );
248 List<ArchivaArtifact> artifacts = null;
252 artifacts = artifactDAO.queryArtifacts( constraint );
254 if ( artifacts != null )
256 for ( ArchivaArtifact artifact : artifacts )
258 if ( artifact.getVersion().equals( version ) )
260 databaseConsumers.executeCleanupConsumer( artifact );
265 catch ( ArchivaDatabaseException e )
267 addActionError( "Error occurred while cleaning up database: " + e.getMessage() );
272 "Artifact \'" + groupId + ":" + artifactId + ":" + version +
273 "\' was successfully deleted from repository \'" + repositoryId + "\'";
275 triggerAuditEvent( getPrincipal(), repositoryId, groupId + ":" + artifactId + ":" + version,
276 AuditEvent.REMOVE_FILE );
278 addActionMessage( msg );
283 catch ( ContentNotFoundException e )
285 addActionError( "Artifact does not exist: " + e.getMessage() );
288 catch ( RepositoryNotFoundException e )
290 addActionError( "Target repository cannot be found: " + e.getMessage() );
293 catch ( RepositoryException e )
295 addActionError( "Repository exception: " + e.getMessage() );
300 @SuppressWarnings("unchecked")
301 private String getPrincipal()
303 return archivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
306 private File getMetadata( String targetPath )
308 String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
310 return new File( artifactPath, MetadataTools.MAVEN_METADATA );
313 private ArchivaRepositoryMetadata getMetadata( File metadataFile )
314 throws RepositoryMetadataException
316 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
317 if ( metadataFile.exists() )
319 metadata = RepositoryMetadataReader.read( metadataFile );
325 * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
329 private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp )
330 throws RepositoryMetadataException
332 List<String> availableVersions = new ArrayList<String>();
333 String latestVersion = "";
335 if ( metadataFile.exists() )
337 if ( metadata.getAvailableVersions() != null )
339 availableVersions = metadata.getAvailableVersions();
341 if ( availableVersions.size() > 0 )
343 Collections.sort( availableVersions, VersionComparator.getInstance() );
345 if ( availableVersions.contains( version ) )
347 availableVersions.remove( availableVersions.indexOf( version ) );
349 if ( availableVersions.size() > 0 )
351 latestVersion = availableVersions.get( availableVersions.size() - 1 );
357 if ( metadata.getGroupId() == null )
359 metadata.setGroupId( groupId );
361 if ( metadata.getArtifactId() == null )
363 metadata.setArtifactId( artifactId );
366 if ( !VersionUtil.isSnapshot( version ) )
368 if ( metadata.getReleasedVersion().equals( version ) )
370 metadata.setReleasedVersion( latestVersion );
374 metadata.setLatestVersion( latestVersion );
375 metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
376 metadata.setAvailableVersions( availableVersions );
378 RepositoryMetadataWriter.write( metadata, metadataFile );
379 ChecksummedFile checksum = new ChecksummedFile( metadataFile );
380 checksum.fixChecksums( algorithms );
383 public void validate()
387 if ( !userRepositories.isAuthorizedToDeleteArtifacts( getPrincipal(), repositoryId ) )
389 addActionError( "User is not authorized to delete artifacts in repository '" + repositoryId + "'." );
392 if ( ( version.length() > 0 ) && ( !VersionUtil.isVersion( version ) ) )
394 addActionError( "Invalid version." );
397 catch ( RbacManagerException e )
399 addActionError( e.getMessage() );
403 public void addAuditListener( AuditListener listener )
405 this.auditListeners.add( listener );
408 public void clearAuditListeners()
410 this.auditListeners.clear();
413 public void removeAuditListener( AuditListener listener )
415 this.auditListeners.remove( listener );
418 private List<String> getManagableRepos()
422 return userRepositories.getManagableRepositoryIds( getPrincipal() );
424 catch ( PrincipalNotFoundException e )
426 log.warn( e.getMessage(), e );
428 catch ( AccessDeniedException e )
430 log.warn( e.getMessage(), e );
431 // TODO: pass this onto the screen.
433 catch ( ArchivaSecurityException e )
435 log.warn( e.getMessage(), e );
437 return Collections.emptyList();
440 private void triggerAuditEvent( String user, String repositoryId, String resource, String action )
442 AuditEvent event = new AuditEvent( repositoryId, user, resource, action );
443 event.setRemoteIP( ServletActionContext.getRequest().getRemoteAddr() );
445 for ( AuditListener listener : auditListeners )
447 listener.auditEvent( event );