This project has retired. For details please refer to its
Attic page.
AbstractRepositoryPurge xref
1 package org.apache.archiva.consumers.core.repository;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.archiva.common.utils.VersionUtil;
23 import org.apache.archiva.metadata.model.ArtifactMetadata;
24 import org.apache.archiva.metadata.model.facets.AuditEvent;
25 import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
26 import org.apache.archiva.metadata.repository.MetadataRepository;
27 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
28 import org.apache.archiva.metadata.repository.MetadataResolutionException;
29 import org.apache.archiva.metadata.repository.RepositorySession;
30 import org.apache.archiva.model.ArtifactReference;
31 import org.apache.archiva.repository.ContentNotFoundException;
32 import org.apache.archiva.repository.ManagedRepositoryContent;
33 import org.apache.archiva.repository.events.RepositoryListener;
34 import org.apache.commons.lang.StringUtils;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import java.io.IOException;
39 import java.nio.file.DirectoryStream;
40 import java.nio.file.FileVisitOption;
41 import java.nio.file.FileVisitResult;
42 import java.nio.file.Files;
43 import java.nio.file.Path;
44 import java.nio.file.SimpleFileVisitor;
45 import java.nio.file.attribute.BasicFileAttributes;
46 import java.util.Collection;
47 import java.util.HashMap;
48 import java.util.HashSet;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Set;
52
53
54
55
56 public abstract class AbstractRepositoryPurge
57 implements RepositoryPurge
58 {
59 protected Logger log = LoggerFactory.getLogger( getClass( ) );
60
61 protected final ManagedRepositoryContent repository;
62
63 protected final RepositorySession repositorySession;
64
65 protected final List<RepositoryListener> listeners;
66
67 private Logger logger = LoggerFactory.getLogger( "org.apache.archiva.AuditLog" );
68
69 private static final char DELIM = ' ';
70
71 public AbstractRepositoryPurge( ManagedRepositoryContent repository, RepositorySession repositorySession,
72 List<RepositoryListener> listeners )
73 {
74 this.repository = repository;
75 this.repositorySession = repositorySession;
76 this.listeners = listeners;
77 }
78
79
80
81
82
83 class ArtifactInfo
84 {
85 final String namespace;
86 final String name;
87 final String projectVersion;
88 String version;
89 String classifier;
90
91 ArtifactInfo( String namespace, String name, String projectVersion, String version )
92 {
93 this.namespace = namespace;
94 this.name = name;
95 this.projectVersion = projectVersion;
96 this.version = version;
97 }
98
99 ArtifactInfo( String namespace, String name, String projectVersion )
100 {
101 this.namespace = namespace;
102 this.name = name;
103 this.projectVersion = projectVersion;
104 }
105
106
107
108
109 ArtifactInfo projectVersionLevel( )
110 {
111 return new ArtifactInfo( this.namespace, this.name, this.projectVersion );
112 }
113
114 public void setClassifier( String classifier )
115 {
116 this.classifier = classifier;
117 }
118
119 public String getNamespace( )
120 {
121 return namespace;
122 }
123
124 public String getName( )
125 {
126 return name;
127 }
128
129 public String getProjectVersion( )
130 {
131 return projectVersion;
132 }
133
134 public String getVersion( )
135 {
136 return version;
137 }
138
139 public String getClassifier( )
140 {
141 return classifier;
142 }
143
144 public boolean hasClassifier( )
145 {
146 return classifier != null && !"".equals( classifier );
147 }
148
149 @Override
150 public boolean equals( Object o )
151 {
152 if ( this == o ) return true;
153 if ( o == null || getClass( ) != o.getClass( ) ) return false;
154
155 ArtifactInfo that = (ArtifactInfo) o;
156
157 if ( !namespace.equals( that.namespace ) ) return false;
158 if ( !name.equals( that.name ) ) return false;
159 if ( !projectVersion.equals( that.projectVersion ) ) return false;
160 if ( !( version != null ? version.equals( that.version ) : that.version == null ) ) return false;
161 return classifier != null ? classifier.equals( that.classifier ) : that.classifier == null;
162 }
163
164 @Override
165 public int hashCode( )
166 {
167 int result = namespace.hashCode( );
168 result = 31 * result + name.hashCode( );
169 result = 31 * result + projectVersion.hashCode( );
170 result = 31 * result + ( version != null ? version.hashCode( ) : 0 );
171 result = 31 * result + ( classifier != null ? classifier.hashCode( ) : 0 );
172 return result;
173 }
174
175 @Override
176 public String toString( )
177 {
178 final StringBuilder sb = new StringBuilder( "ArtifactInfo{" );
179 sb.append( "namespace='" ).append( namespace ).append( '\'' );
180 sb.append( ", name='" ).append( name ).append( '\'' );
181 sb.append( ", projectVersion='" ).append( projectVersion ).append( '\'' );
182 sb.append( ", version='" ).append( version ).append( '\'' );
183 sb.append( ", classifier='" ).append( classifier ).append( '\'' );
184 sb.append( '}' );
185 return sb.toString( );
186 }
187 }
188
189
190
191
192
193
194 protected void purge( Set<ArtifactReference> references )
195 {
196 if ( references != null && !references.isEmpty( ) )
197 {
198 MetadataRepository metadataRepository = repositorySession.getRepository( );
199 Map<ArtifactInfo, ArtifactMetadata> metaRemovalList = new HashMap<>( );
200 Map<String, Collection<ArtifactMetadata>> metaResolved = new HashMap<>( );
201 for ( ArtifactReference reference : references )
202 {
203 String baseVersion = VersionUtil.getBaseVersion( reference.getVersion( ) );
204
205 String metaBaseId = reference.getGroupId( ) + "/" + reference.getArtifactId( ) + "/" + baseVersion;
206
207 if ( !metaResolved.containsKey( metaBaseId ) )
208 {
209 try
210 {
211 metaResolved.put( metaBaseId, metadataRepository.getArtifacts( repository.getId( ), reference.getGroupId( ),
212 reference.getArtifactId( ), baseVersion ) );
213 }
214 catch ( MetadataResolutionException e )
215 {
216 log.error( "Error during metadata retrieval {}: {}", metaBaseId, e.getMessage( ) );
217 }
218 }
219 Path artifactFile = repository.toFile( reference ).toPath( );
220
221 for ( RepositoryListener listener : listeners )
222 {
223 listener.deleteArtifact( metadataRepository, repository.getId( ), reference.getGroupId( ),
224 reference.getArtifactId( ), reference.getVersion( ),
225 artifactFile.getFileName( ).toString( ) );
226 }
227 try
228 {
229 Files.delete( artifactFile );
230 log.debug( "File deleted: {}", artifactFile.toAbsolutePath( ) );
231 }
232 catch ( IOException e )
233 {
234 log.error( "Could not delete file {}: {}", artifactFile.toAbsolutePath( ), e.getMessage( ), e );
235 continue;
236 }
237 try
238 {
239 repository.deleteArtifact( reference );
240 }
241 catch ( ContentNotFoundException e )
242 {
243 log.warn( "skip error deleting artifact {}: {}", reference, e.getMessage( ) );
244 }
245
246 boolean snapshotVersion = VersionUtil.isSnapshot( reference.getVersion( ) );
247
248
249
250 if ( snapshotVersion )
251 {
252 Collection<ArtifactMetadata> artifacts =
253 metaResolved.get( metaBaseId );
254 if ( artifacts != null )
255 {
256
257 for ( ArtifactMetadata artifactMetadata : artifacts )
258 {
259
260 if ( artifactMetadata.getVersion( ).equals( reference.getVersion( ) ) )
261 {
262 ArtifactInfo info = new ArtifactInfo( artifactMetadata.getNamespace( ), artifactMetadata.getProject( ), artifactMetadata.getProjectVersion( ), artifactMetadata.getVersion( ) );
263 if ( StringUtils.isNotBlank( reference.getClassifier( ) ) )
264 {
265 info.setClassifier( reference.getClassifier( ) );
266 } else {
267 info.setClassifier( "" );
268 }
269
270 metaRemovalList.put( info, artifactMetadata );
271 }
272 }
273 }
274 }
275 else
276 {
277 ArtifactInfo info = new ArtifactInfo( reference.getGroupId( ), reference.getArtifactId( ), baseVersion, reference.getVersion( ) );
278 for ( ArtifactMetadata metadata : metaResolved.get( metaBaseId ) )
279 {
280 metaRemovalList.put( info, metadata );
281 }
282 }
283 triggerAuditEvent( repository.getRepository( ).getId( ), ArtifactReference.toKey( reference ),
284 AuditEvent.PURGE_ARTIFACT );
285 purgeSupportFiles( artifactFile );
286 }
287 purgeMetadata( metadataRepository, metaRemovalList );
288 repositorySession.save( );
289
290 }
291 }
292
293
294
295
296 private void purgeMetadata( MetadataRepository metadataRepository, Map<ArtifactInfo, ArtifactMetadata> dataList )
297 {
298 Set<ArtifactInfo> projectLevelMetadata = new HashSet<>( );
299 for ( Map.Entry<ArtifactInfo, ArtifactMetadata> infoEntry : dataList.entrySet( ) )
300 {
301 ArtifactInfo info = infoEntry.getKey( );
302 try
303 {
304 removeArtifact( metadataRepository, info, infoEntry.getValue( ) );
305 log.debug( "Removed artifact from MetadataRepository {}", info );
306 }
307 catch ( MetadataRepositoryException e )
308 {
309 log.error( "Could not remove artifact from MetadataRepository {}: {}", info, e.getMessage( ), e );
310 }
311 projectLevelMetadata.add( info.projectVersionLevel( ) );
312 }
313 metadataRepository.save( );
314 Collection<ArtifactMetadata> artifacts = null;
315
316 for ( ArtifactInfo info : projectLevelMetadata )
317 {
318 try
319 {
320 artifacts = metadataRepository.getArtifacts( repository.getId( ), info.getNamespace( ), info.getName( ),
321 info.getProjectVersion( ) );
322 if ( artifacts.size( ) == 0 )
323 {
324 metadataRepository.removeProjectVersion( repository.getId( ), info.getNamespace( ),
325 info.getName( ), info.getProjectVersion( ) );
326 log.debug( "Removed project version from MetadataRepository {}", info );
327 }
328 }
329 catch ( MetadataResolutionException | MetadataRepositoryException e )
330 {
331 log.error( "Could not remove project version from MetadataRepository {}: {}", info, e.getMessage( ), e );
332 }
333 }
334 metadataRepository.save( );
335
336 }
337
338
339
340
341 private void removeArtifact( MetadataRepository metadataRepository, ArtifactInfo artifactInfo, ArtifactMetadata artifactMetadata ) throws MetadataRepositoryException
342 {
343 if ( artifactInfo.hasClassifier( ) )
344 {
345
346 MavenArtifactFacet mavenArtifactFacet =
347 (MavenArtifactFacet) artifactMetadata.getFacet(
348 MavenArtifactFacet.FACET_ID );
349
350 if ( mavenArtifactFacet!= null && StringUtils.equals( artifactInfo.classifier,
351 mavenArtifactFacet.getClassifier( ) ) )
352 {
353 artifactMetadata.removeFacet( MavenArtifactFacet.FACET_ID );
354 String groupId = artifactInfo.getNamespace( ), artifactId =
355 artifactInfo.getName( ),
356 version = artifactInfo.getProjectVersion( );
357 MavenArtifactFacet mavenArtifactFacetToCompare = new MavenArtifactFacet( );
358 mavenArtifactFacetToCompare.setClassifier( artifactInfo.getClassifier( ) );
359 metadataRepository.removeArtifact( repository.getId( ), groupId, artifactId,
360 version, mavenArtifactFacetToCompare );
361 metadataRepository.save( );
362 }
363 }
364 else
365 {
366 metadataRepository.removeArtifact( artifactMetadata, artifactInfo.getProjectVersion( ) );
367 }
368 }
369
370 private void deleteSilently( Path path )
371 {
372 try
373 {
374 Files.deleteIfExists( path );
375 triggerAuditEvent( repository.getRepository( ).getId( ), path.toString( ), AuditEvent.PURGE_FILE );
376 }
377 catch ( IOException e )
378 {
379 log.error( "Error occured during file deletion {}: {} ", path, e.getMessage( ), e );
380 }
381 }
382
383
384
385
386
387
388
389
390
391
392
393 private void purgeSupportFiles( Path artifactFile )
394 {
395 Path parentDir = artifactFile.getParent( );
396
397 if ( !Files.exists( parentDir ) )
398 {
399 return;
400 }
401
402 final String artifactName = artifactFile.getFileName( ).toString( );
403
404 try
405 {
406 deleteArtifactFiles( parentDir, 3, artifactName );
407 }
408 catch ( IOException e )
409 {
410 log.error( "Purge of support files failed {}: {}", artifactFile, e.getMessage( ), e );
411 }
412
413 }
414
415 public static void deleteArtifactFiles(final Path directory, final int maxDepth, final String artifactName) throws IOException
416 {
417 Files.walkFileTree(directory, new HashSet<FileVisitOption>( ), maxDepth, new SimpleFileVisitor<Path>() {
418 @Override
419 public FileVisitResult visitFile( Path file, BasicFileAttributes attrs) throws IOException {
420 if (file.getFileName().toString().startsWith(artifactName)) {
421 try {
422 Files.delete( file );
423 } catch (IOException e) {
424
425 }
426 }
427 return FileVisitResult.CONTINUE;
428 }
429
430 @Override
431 public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
432 return FileVisitResult.CONTINUE;
433 }
434
435 });
436 }
437
438 private void triggerAuditEvent( String repoId, String resource, String action )
439 {
440 String msg =
441 repoId + DELIM + "<system-purge>" + DELIM + "<system>" + DELIM + '\"' + resource + '\"' + DELIM + '\"' +
442 action + '\"';
443
444 logger.info( msg );
445 }
446 }