This project has retired. For details please refer to its Attic page.
Source code
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.common.utils.VersionComparator;
023import org.apache.archiva.common.utils.VersionUtil;
024import org.apache.archiva.metadata.repository.RepositorySession;
025import org.apache.archiva.model.ArtifactReference;
026import org.apache.archiva.model.VersionedReference;
027import org.apache.archiva.repository.ContentNotFoundException;
028import org.apache.archiva.repository.LayoutException;
029import org.apache.archiva.repository.ManagedRepositoryContent;
030import org.apache.archiva.metadata.audit.RepositoryListener;
031import org.apache.archiva.repository.storage.StorageAsset;
032
033import java.nio.file.Files;
034import java.nio.file.Path;
035import java.nio.file.Paths;
036import java.text.ParseException;
037import java.text.SimpleDateFormat;
038import java.util.*;
039import java.util.regex.Matcher;
040
041/**
042 * Purge from repository all snapshots older than the specified days in the repository configuration.
043 */
044public class DaysOldRepositoryPurge
045    extends AbstractRepositoryPurge
046{
047    private SimpleDateFormat timestampParser;
048
049    private int retentionPeriod;
050
051    private int retentionCount;
052
053    public DaysOldRepositoryPurge( ManagedRepositoryContent repository, int retentionPeriod, int retentionCount,
054                                   RepositorySession repositorySession, List<RepositoryListener> listeners )
055    {
056        super( repository, repositorySession, listeners );
057        this.retentionPeriod = retentionPeriod;
058        this.retentionCount = retentionCount;
059        timestampParser = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
060        timestampParser.setTimeZone( TimeZone.getTimeZone("UTC"));
061    }
062
063    @Override
064    public void process( String path )
065        throws RepositoryPurgeException
066    {
067        try
068        {
069            Path artifactFile = Paths.get( repository.getRepoRoot( ), path );
070
071            if ( !Files.exists(artifactFile) )
072            {
073                return;
074            }
075
076            ArtifactReference artifact = repository.toArtifactReference( path );
077
078            Calendar olderThanThisDate = Calendar.getInstance( TimeZone.getTimeZone("UTC") );
079            olderThanThisDate.add( Calendar.DATE, -retentionPeriod );
080
081            // respect retention count
082            VersionedReference reference = new VersionedReference( );
083            reference.setGroupId( artifact.getGroupId( ) );
084            reference.setArtifactId( artifact.getArtifactId( ) );
085            reference.setVersion( artifact.getVersion( ) );
086
087            List<String> versions = new ArrayList<>( repository.getVersions( reference ) );
088
089            Collections.sort( versions, VersionComparator.getInstance( ) );
090
091            if ( retentionCount > versions.size( ) )
092            {
093                // Done. nothing to do here. skip it.
094                return;
095            }
096
097            int countToPurge = versions.size( ) - retentionCount;
098
099            Set<ArtifactReference> artifactsToDelete = new HashSet<>( );
100            for ( String version : versions )
101            {
102                if ( countToPurge-- <= 0 )
103                {
104                    break;
105                }
106
107                ArtifactReference newArtifactReference = repository.toArtifactReference(
108                    artifactFile.toAbsolutePath( ).toString() );
109                newArtifactReference.setVersion( version );
110
111                StorageAsset newArtifactFile = repository.toFile( newArtifactReference );
112
113                // Is this a generic snapshot "1.0-SNAPSHOT" ?
114                if ( VersionUtil.isGenericSnapshot( newArtifactReference.getVersion( ) ) )
115                {
116                    if ( newArtifactFile.getModificationTime().toEpochMilli() < olderThanThisDate.getTimeInMillis( ) )
117                    {
118                        artifactsToDelete.addAll( repository.getRelatedArtifacts( newArtifactReference ) );
119                    }
120                }
121                // Is this a timestamp snapshot "1.0-20070822.123456-42" ?
122                else if ( VersionUtil.isUniqueSnapshot( newArtifactReference.getVersion( ) ) )
123                {
124                    Calendar timestampCal = uniqueSnapshotToCalendar( newArtifactReference.getVersion( ) );
125
126                    if ( timestampCal.getTimeInMillis( ) < olderThanThisDate.getTimeInMillis( ) )
127                    {
128                        artifactsToDelete.addAll( repository.getRelatedArtifacts( newArtifactReference ) );
129                    }
130                }
131            }
132            purge( artifactsToDelete );
133        }
134        catch ( ContentNotFoundException e )
135        {
136            throw new RepositoryPurgeException( e.getMessage( ), e );
137        }
138        catch ( LayoutException e )
139        {
140            log.debug( "Not processing file that is not an artifact: {}", e.getMessage( ) );
141        }
142    }
143
144    private Calendar uniqueSnapshotToCalendar( String version )
145    {
146        // The latestVersion will contain the full version string "1.0-alpha-5-20070821.213044-8"
147        // This needs to be broken down into ${base}-${timestamp}-${build_number}
148
149        Matcher m = VersionUtil.UNIQUE_SNAPSHOT_PATTERN.matcher( version );
150        if ( m.matches( ) )
151        {
152            Matcher mtimestamp = VersionUtil.TIMESTAMP_PATTERN.matcher( m.group( 2 ) );
153            if ( mtimestamp.matches( ) )
154            {
155                String tsDate = mtimestamp.group( 1 );
156                String tsTime = mtimestamp.group( 2 );
157
158                Date versionDate;
159                try
160                {
161                    versionDate = timestampParser.parse( tsDate + "." + tsTime );
162                    Calendar cal = Calendar.getInstance( TimeZone.getTimeZone("UTC") );
163                    cal.setTime( versionDate );
164
165                    return cal;
166                }
167                catch ( ParseException e )
168                {
169                    // Invalid Date/Time
170                    return null;
171                }
172            }
173        }
174        return null;
175    }
176
177}