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.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;
64 import com.opensymphony.xwork2.ActionContext;
65 import com.opensymphony.xwork2.Preparable;
66 import com.opensymphony.xwork2.Validateable;
69 * Delete an artifact. Metadata will be updated if one exists, otherwise it would be created.
71 * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="deleteArtifactAction" instantiation-strategy="per-lookup"
73 public class DeleteArtifactAction
74 extends PlexusActionSupport
75 implements Validateable, Preparable, Auditable
80 private ArchivaXworkUser archivaXworkUser;
83 * The groupId of the artifact to be deleted.
85 private String groupId;
88 * The artifactId of the artifact to be deleted.
90 private String artifactId;
93 * The version of the artifact to be deleted.
95 private String version;
98 * The repository where the artifact is to be deleted.
100 private String repositoryId;
103 * List of managed repositories to delete from.
105 private List<String> managedRepos;
108 * @plexus.requirement
110 private UserRepositories userRepositories;
113 * @plexus.requirement role-hint="default"
115 private ArchivaConfiguration configuration;
118 * @plexus.requirement
120 private RepositoryContentFactory repositoryFactory;
123 * @plexus.requirement role-hint="jdo"
125 private ArtifactDAO artifactDAO;
128 * @plexus.requirement
130 private DatabaseConsumers databaseConsumers;
133 * @plexus.requirement role="org.apache.maven.archiva.repository.audit.AuditListener"
135 private List<AuditListener> auditListeners = new ArrayList<AuditListener>();
137 private ChecksumAlgorithm[] algorithms = new ChecksumAlgorithm[] { ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 };
139 public String getGroupId()
144 public void setGroupId( String groupId )
146 this.groupId = groupId;
149 public String getArtifactId()
154 public void setArtifactId( String artifactId )
156 this.artifactId = artifactId;
159 public String getVersion()
164 public void setVersion( String version )
166 this.version = version;
169 public String getRepositoryId()
174 public void setRepositoryId( String repositoryId )
176 this.repositoryId = repositoryId;
179 public List<String> getManagedRepos()
184 public void setManagedRepos( List<String> managedRepos )
186 this.managedRepos = managedRepos;
189 public void prepare()
191 managedRepos = getManagableRepos();
194 public String input()
201 // reset the fields so the form is clear when
202 // the action returns to the jsp page
209 public String doDelete()
213 Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
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 );
221 VersionedReference ref = new VersionedReference();
222 ref.setArtifactId( artifactId );
223 ref.setGroupId( groupId );
224 ref.setVersion( version );
226 ManagedRepositoryContent repository = repositoryFactory.getManagedRepositoryContent( repositoryId );
228 String path = repository.toMetadataPath( ref );
229 int index = path.lastIndexOf( '/' );
230 File targetPath = new File( repoConfig.getLocation(), path.substring( 0, index ) );
232 if ( !targetPath.exists() )
234 throw new ContentNotFoundException( groupId + ":" + artifactId + ":" + version );
237 // delete from file system
238 repository.deleteVersion( ref );
240 File metadataFile = getMetadata( targetPath.getAbsolutePath() );
241 ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
243 updateMetadata( metadata, metadataFile, lastUpdatedTimestamp );
245 ArtifactVersionsConstraint constraint =
246 new ArtifactVersionsConstraint( repositoryId, groupId, artifactId, false );
247 List<ArchivaArtifact> artifacts = null;
251 artifacts = artifactDAO.queryArtifacts( constraint );
253 if ( artifacts != null )
255 for ( ArchivaArtifact artifact : artifacts )
257 if ( artifact.getVersion().equals( version ) )
259 databaseConsumers.executeCleanupConsumer( artifact );
264 catch ( ArchivaDatabaseException e )
266 addActionError( "Error occurred while cleaning up database: " + e.getMessage() );
271 "Artifact \'" + groupId + ":" + artifactId + ":" + version +
272 "\' was successfully deleted from repository \'" + repositoryId + "\'";
274 triggerAuditEvent( getPrincipal(), repositoryId, groupId + ":" + artifactId + ":" + version,
275 AuditEvent.REMOVE_FILE );
277 addActionMessage( msg );
282 catch ( ContentNotFoundException e )
284 addActionError( "Artifact does not exist: " + e.getMessage() );
287 catch ( RepositoryNotFoundException e )
289 addActionError( "Target repository cannot be found: " + e.getMessage() );
292 catch ( RepositoryException e )
294 addActionError( "Repository exception: " + e.getMessage() );
299 @SuppressWarnings("unchecked")
300 private String getPrincipal()
302 return archivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
305 private File getMetadata( String targetPath )
307 String artifactPath = targetPath.substring( 0, targetPath.lastIndexOf( File.separatorChar ) );
309 return new File( artifactPath, MetadataTools.MAVEN_METADATA );
312 private ArchivaRepositoryMetadata getMetadata( File metadataFile )
313 throws RepositoryMetadataException
315 ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
316 if ( metadataFile.exists() )
318 metadata = RepositoryMetadataReader.read( metadataFile );
324 * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
328 private void updateMetadata( ArchivaRepositoryMetadata metadata, File metadataFile, Date lastUpdatedTimestamp )
329 throws RepositoryMetadataException
331 List<String> availableVersions = new ArrayList<String>();
332 String latestVersion = "";
334 if ( metadataFile.exists() )
336 if ( metadata.getAvailableVersions() != null )
338 availableVersions = metadata.getAvailableVersions();
340 if ( availableVersions.size() > 0 )
342 Collections.sort( availableVersions, VersionComparator.getInstance() );
344 if ( availableVersions.contains( version ) )
346 availableVersions.remove( availableVersions.indexOf( version ) );
348 if ( availableVersions.size() > 0 )
350 latestVersion = availableVersions.get( availableVersions.size() - 1 );
356 if ( metadata.getGroupId() == null )
358 metadata.setGroupId( groupId );
360 if ( metadata.getArtifactId() == null )
362 metadata.setArtifactId( artifactId );
365 if ( !VersionUtil.isSnapshot( version ) )
367 if ( metadata.getReleasedVersion().equals( version ) )
369 metadata.setReleasedVersion( latestVersion );
373 metadata.setLatestVersion( latestVersion );
374 metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
375 metadata.setAvailableVersions( availableVersions );
377 RepositoryMetadataWriter.write( metadata, metadataFile );
378 ChecksummedFile checksum = new ChecksummedFile( metadataFile );
379 checksum.fixChecksums( algorithms );
382 public void validate()
386 if ( !userRepositories.isAuthorizedToDeleteArtifacts( getPrincipal(), repositoryId ) )
388 addActionError( "User is not authorized to delete artifacts in repository '" + repositoryId + "'." );
391 if ( ( version.length() > 0 ) && ( !VersionUtil.isVersion( version ) ) )
393 addActionError( "Invalid version." );
396 catch ( AccessDeniedException e )
398 addActionError( e.getMessage() );
400 catch ( ArchivaSecurityException e )
402 addActionError( e.getMessage() );
406 public void addAuditListener( AuditListener listener )
408 this.auditListeners.add( listener );
411 public void clearAuditListeners()
413 this.auditListeners.clear();
416 public void removeAuditListener( AuditListener listener )
418 this.auditListeners.remove( listener );
421 private List<String> getManagableRepos()
425 return userRepositories.getManagableRepositoryIds( getPrincipal() );
427 catch ( PrincipalNotFoundException e )
429 log.warn( e.getMessage(), e );
431 catch ( AccessDeniedException e )
433 log.warn( e.getMessage(), e );
434 // TODO: pass this onto the screen.
436 catch ( ArchivaSecurityException e )
438 log.warn( e.getMessage(), e );
440 return Collections.emptyList();
443 private void triggerAuditEvent( String user, String repositoryId, String resource, String action )
445 AuditEvent event = new AuditEvent( repositoryId, user, resource, action );
446 event.setRemoteIP( ServletActionContext.getRequest().getRemoteAddr() );
448 for ( AuditListener listener : auditListeners )
450 listener.auditEvent( event );