001package org.apache.archiva.consumers.core.repository; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.archiva.metadata.repository.RepositorySession; 023import org.apache.archiva.repository.events.RepositoryListener; 024import org.apache.commons.lang.time.DateUtils; 025import org.apache.archiva.common.utils.VersionComparator; 026import org.apache.archiva.common.utils.VersionUtil; 027import org.apache.archiva.model.ArtifactReference; 028import org.apache.archiva.model.VersionedReference; 029import org.apache.archiva.repository.ContentNotFoundException; 030import org.apache.archiva.repository.ManagedRepositoryContent; 031import org.apache.archiva.repository.layout.LayoutException; 032 033import java.io.File; 034import java.text.ParseException; 035import java.text.SimpleDateFormat; 036import java.util.ArrayList; 037import java.util.Calendar; 038import java.util.Collections; 039import java.util.Date; 040import java.util.List; 041import java.util.Set; 042import java.util.regex.Matcher; 043 044/** 045 * Purge from repository all snapshots older than the specified days in the repository configuration. 046 */ 047public class DaysOldRepositoryPurge 048 extends AbstractRepositoryPurge 049{ 050 private SimpleDateFormat timestampParser; 051 052 private int daysOlder; 053 054 private int retentionCount; 055 056 public DaysOldRepositoryPurge( ManagedRepositoryContent repository, int daysOlder, int retentionCount, 057 RepositorySession repositorySession, List<RepositoryListener> listeners ) 058 { 059 super( repository, repositorySession, listeners ); 060 this.daysOlder = daysOlder; 061 this.retentionCount = retentionCount; 062 timestampParser = new SimpleDateFormat( "yyyyMMdd.HHmmss" ); 063 timestampParser.setTimeZone( DateUtils.UTC_TIME_ZONE ); 064 } 065 066 @Override 067 public void process( String path ) 068 throws RepositoryPurgeException 069 { 070 try 071 { 072 File artifactFile = new File( repository.getRepoRoot(), path ); 073 074 if ( !artifactFile.exists() ) 075 { 076 return; 077 } 078 079 ArtifactReference artifact = repository.toArtifactReference( path ); 080 081 Calendar olderThanThisDate = Calendar.getInstance( DateUtils.UTC_TIME_ZONE ); 082 olderThanThisDate.add( Calendar.DATE, -daysOlder ); 083 084 // respect retention count 085 VersionedReference reference = new VersionedReference(); 086 reference.setGroupId( artifact.getGroupId() ); 087 reference.setArtifactId( artifact.getArtifactId() ); 088 reference.setVersion( artifact.getVersion() ); 089 090 List<String> versions = new ArrayList<>( repository.getVersions( reference ) ); 091 092 Collections.sort( versions, VersionComparator.getInstance() ); 093 094 if ( retentionCount > versions.size() ) 095 { 096 // Done. nothing to do here. skip it. 097 return; 098 } 099 100 int countToPurge = versions.size() - retentionCount; 101 102 for ( String version : versions ) 103 { 104 if ( countToPurge-- <= 0 ) 105 { 106 break; 107 } 108 109 ArtifactReference newArtifactReference = repository.toArtifactReference( 110 artifactFile.getAbsolutePath() ); 111 newArtifactReference.setVersion( version ); 112 113 File newArtifactFile = repository.toFile( newArtifactReference ); 114 115 // Is this a generic snapshot "1.0-SNAPSHOT" ? 116 if ( VersionUtil.isGenericSnapshot( newArtifactReference.getVersion() ) ) 117 { 118 if ( newArtifactFile.lastModified() < olderThanThisDate.getTimeInMillis() ) 119 { 120 doPurgeAllRelated( newArtifactReference ); 121 } 122 } 123 // Is this a timestamp snapshot "1.0-20070822.123456-42" ? 124 else if ( VersionUtil.isUniqueSnapshot( newArtifactReference.getVersion() ) ) 125 { 126 Calendar timestampCal = uniqueSnapshotToCalendar( newArtifactReference.getVersion() ); 127 128 if ( timestampCal.getTimeInMillis() < olderThanThisDate.getTimeInMillis() ) 129 { 130 doPurgeAllRelated( newArtifactReference ); 131 } 132 } 133 } 134 } 135 catch ( ContentNotFoundException e ) 136 { 137 throw new RepositoryPurgeException( e.getMessage(), e ); 138 } 139 catch ( LayoutException e ) 140 { 141 log.debug( "Not processing file that is not an artifact: {}", e.getMessage() ); 142 } 143 } 144 145 private Calendar uniqueSnapshotToCalendar( String version ) 146 { 147 // The latestVersion will contain the full version string "1.0-alpha-5-20070821.213044-8" 148 // This needs to be broken down into ${base}-${timestamp}-${build_number} 149 150 Matcher m = VersionUtil.UNIQUE_SNAPSHOT_PATTERN.matcher( version ); 151 if ( m.matches() ) 152 { 153 Matcher mtimestamp = VersionUtil.TIMESTAMP_PATTERN.matcher( m.group( 2 ) ); 154 if ( mtimestamp.matches() ) 155 { 156 String tsDate = mtimestamp.group( 1 ); 157 String tsTime = mtimestamp.group( 2 ); 158 159 Date versionDate; 160 try 161 { 162 versionDate = timestampParser.parse( tsDate + "." + tsTime ); 163 Calendar cal = Calendar.getInstance( DateUtils.UTC_TIME_ZONE ); 164 cal.setTime( versionDate ); 165 166 return cal; 167 } 168 catch ( ParseException e ) 169 { 170 // Invalid Date/Time 171 return null; 172 } 173 } 174 } 175 return null; 176 } 177 178 private void doPurgeAllRelated( ArtifactReference reference ) 179 { 180 try 181 { 182 Set<ArtifactReference> related = repository.getRelatedArtifacts( reference ); 183 purge( related ); 184 } 185 catch ( ContentNotFoundException e ) 186 { 187 // Nothing to do here - it means the repository would have been constructed incorrectly 188 log.debug( e.getMessage(), e ); 189 } 190 } 191}