View Javadoc
1   package org.apache.archiva.consumers.core.repository;
2   
3   /*
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
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
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
19   * under the License.
20   */
21  
22  import org.apache.archiva.metadata.repository.RepositorySession;
23  import org.apache.archiva.repository.events.RepositoryListener;
24  import org.apache.commons.lang.time.DateUtils;
25  import org.apache.archiva.common.utils.VersionComparator;
26  import org.apache.archiva.common.utils.VersionUtil;
27  import org.apache.archiva.model.ArtifactReference;
28  import org.apache.archiva.model.VersionedReference;
29  import org.apache.archiva.repository.ContentNotFoundException;
30  import org.apache.archiva.repository.ManagedRepositoryContent;
31  import org.apache.archiva.repository.layout.LayoutException;
32  
33  import java.io.File;
34  import java.text.ParseException;
35  import java.text.SimpleDateFormat;
36  import java.util.ArrayList;
37  import java.util.Calendar;
38  import java.util.Collections;
39  import java.util.Date;
40  import java.util.List;
41  import java.util.Set;
42  import java.util.regex.Matcher;
43  
44  /**
45   * Purge from repository all snapshots older than the specified days in the repository configuration.
46   */
47  public class DaysOldRepositoryPurge
48      extends AbstractRepositoryPurge
49  {
50      private SimpleDateFormat timestampParser;
51  
52      private int daysOlder;
53  
54      private int retentionCount;
55  
56      public DaysOldRepositoryPurge( ManagedRepositoryContent repository, int daysOlder, int retentionCount,
57                                     RepositorySession repositorySession, List<RepositoryListener> listeners )
58      {
59          super( repository, repositorySession, listeners );
60          this.daysOlder = daysOlder;
61          this.retentionCount = retentionCount;
62          timestampParser = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
63          timestampParser.setTimeZone( DateUtils.UTC_TIME_ZONE );
64      }
65  
66      @Override
67      public void process( String path )
68          throws RepositoryPurgeException
69      {
70          try
71          {
72              File artifactFile = new File( repository.getRepoRoot(), path );
73  
74              if ( !artifactFile.exists() )
75              {
76                  return;
77              }
78  
79              ArtifactReference artifact = repository.toArtifactReference( path );
80  
81              Calendar olderThanThisDate = Calendar.getInstance( DateUtils.UTC_TIME_ZONE );
82              olderThanThisDate.add( Calendar.DATE, -daysOlder );
83  
84              // respect retention count
85              VersionedReference reference = new VersionedReference();
86              reference.setGroupId( artifact.getGroupId() );
87              reference.setArtifactId( artifact.getArtifactId() );
88              reference.setVersion( artifact.getVersion() );
89  
90              List<String> versions = new ArrayList<>( repository.getVersions( reference ) );
91  
92              Collections.sort( versions, VersionComparator.getInstance() );
93  
94              if ( retentionCount > versions.size() )
95              {
96                  // Done. nothing to do here. skip it.
97                  return;
98              }
99  
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 }