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.admin.model.RepositoryAdminException; 023import org.apache.archiva.admin.model.beans.ManagedRepository; 024import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin; 025import org.apache.archiva.common.utils.VersionComparator; 026import org.apache.archiva.common.utils.VersionUtil; 027import org.apache.archiva.metadata.repository.MetadataRepository; 028import org.apache.archiva.metadata.repository.MetadataRepositoryException; 029import org.apache.archiva.metadata.repository.RepositorySession; 030import org.apache.archiva.model.ArtifactReference; 031import org.apache.archiva.model.ProjectReference; 032import org.apache.archiva.model.VersionedReference; 033import org.apache.archiva.repository.ContentNotFoundException; 034import org.apache.archiva.repository.ManagedRepositoryContent; 035import org.apache.archiva.repository.RepositoryContentFactory; 036import org.apache.archiva.repository.RepositoryException; 037import org.apache.archiva.repository.RepositoryNotFoundException; 038import org.apache.archiva.repository.events.RepositoryListener; 039import org.apache.archiva.repository.layout.LayoutException; 040import org.apache.archiva.repository.metadata.MetadataTools; 041import org.apache.archiva.repository.metadata.RepositoryMetadataException; 042 043import java.io.File; 044import java.io.IOException; 045import java.util.ArrayList; 046import java.util.Collections; 047import java.util.List; 048 049/** 050 * <p> 051 * This will look in a single managed repository, and purge any snapshots that are present 052 * that have a corresponding released version on the same repository. 053 * </p> 054 * <p> 055 * So, if you have the following (presented in the m2/default layout form) ... 056 * <pre> 057 * /com/foo/foo-tool/1.0-SNAPSHOT/foo-tool-1.0-SNAPSHOT.jar 058 * /com/foo/foo-tool/1.1-SNAPSHOT/foo-tool-1.1-SNAPSHOT.jar 059 * /com/foo/foo-tool/1.2.1-SNAPSHOT/foo-tool-1.2.1-SNAPSHOT.jar 060 * /com/foo/foo-tool/1.2.1/foo-tool-1.2.1.jar 061 * /com/foo/foo-tool/2.0-SNAPSHOT/foo-tool-2.0-SNAPSHOT.jar 062 * /com/foo/foo-tool/2.0/foo-tool-2.0.jar 063 * /com/foo/foo-tool/2.1-SNAPSHOT/foo-tool-2.1-SNAPSHOT.jar 064 * </pre> 065 * then the current highest ranked released (non-snapshot) version is 2.0, which means 066 * the snapshots from 1.0-SNAPSHOT, 1.1-SNAPSHOT, 1.2.1-SNAPSHOT, and 2.0-SNAPSHOT can 067 * be purged. Leaving 2.1-SNAPSHOT in alone. 068 */ 069public class CleanupReleasedSnapshotsRepositoryPurge 070 extends AbstractRepositoryPurge 071{ 072 private MetadataTools metadataTools; 073 074 private ManagedRepositoryAdmin managedRepositoryAdmin; 075 076 private RepositoryContentFactory repoContentFactory; 077 078 public CleanupReleasedSnapshotsRepositoryPurge( ManagedRepositoryContent repository, MetadataTools metadataTools, 079 ManagedRepositoryAdmin managedRepositoryAdmin, 080 RepositoryContentFactory repoContentFactory, 081 RepositorySession repositorySession, 082 List<RepositoryListener> listeners ) 083 { 084 super( repository, repositorySession, listeners ); 085 this.metadataTools = metadataTools; 086 this.managedRepositoryAdmin = managedRepositoryAdmin; 087 this.repoContentFactory = repoContentFactory; 088 } 089 090 @Override 091 public void process( String path ) 092 throws RepositoryPurgeException 093 { 094 try 095 { 096 File artifactFile = new File( repository.getRepoRoot( ), path ); 097 098 if ( !artifactFile.exists( ) ) 099 { 100 // Nothing to do here, file doesn't exist, skip it. 101 return; 102 } 103 104 ArtifactReference artifactRef = repository.toArtifactReference( path ); 105 106 if ( !VersionUtil.isSnapshot( artifactRef.getVersion( ) ) ) 107 { 108 // Nothing to do here, not a snapshot, skip it. 109 return; 110 } 111 112 ProjectReference reference = new ProjectReference( ); 113 reference.setGroupId( artifactRef.getGroupId( ) ); 114 reference.setArtifactId( artifactRef.getArtifactId( ) ); 115 116 // Gether the released versions 117 List<String> releasedVersions = new ArrayList<>( ); 118 119 List<ManagedRepository> repos = managedRepositoryAdmin.getManagedRepositories( ); 120 for ( ManagedRepository repo : repos ) 121 { 122 if ( repo.isReleases( ) ) 123 { 124 try 125 { 126 ManagedRepositoryContent repoContent = 127 repoContentFactory.getManagedRepositoryContent( repo.getId( ) ); 128 for ( String version : repoContent.getVersions( reference ) ) 129 { 130 if ( !VersionUtil.isSnapshot( version ) ) 131 { 132 releasedVersions.add( version ); 133 } 134 } 135 } 136 catch ( RepositoryNotFoundException e ) 137 { 138 // swallow 139 } 140 catch ( RepositoryException e ) 141 { 142 // swallow 143 } 144 } 145 } 146 147 Collections.sort( releasedVersions, VersionComparator.getInstance( ) ); 148 149 // Now clean out any version that is earlier than the highest released version. 150 boolean needsMetadataUpdate = false; 151 152 VersionedReference versionRef = new VersionedReference( ); 153 versionRef.setGroupId( artifactRef.getGroupId( ) ); 154 versionRef.setArtifactId( artifactRef.getArtifactId( ) ); 155 156 MetadataRepository metadataRepository = repositorySession.getRepository( ); 157 158 if ( releasedVersions.contains( VersionUtil.getReleaseVersion( artifactRef.getVersion( ) ) ) ) 159 { 160 versionRef.setVersion( artifactRef.getVersion( ) ); 161 repository.deleteVersion( versionRef ); 162 163 for ( RepositoryListener listener : listeners ) 164 { 165 listener.deleteArtifact( metadataRepository, repository.getId( ), artifactRef.getGroupId( ), 166 artifactRef.getArtifactId( ), artifactRef.getVersion( ), 167 artifactFile.getName( ) ); 168 } 169 metadataRepository.removeProjectVersion( repository.getId( ), artifactRef.getGroupId( ), 170 artifactRef.getArtifactId( ), artifactRef.getVersion( ) ); 171 172 needsMetadataUpdate = true; 173 } 174 175 if ( needsMetadataUpdate ) 176 { 177 updateMetadata( artifactRef ); 178 } 179 } 180 catch ( RepositoryAdminException e ) 181 { 182 throw new RepositoryPurgeException( e.getMessage( ), e ); 183 } 184 catch ( LayoutException e ) 185 { 186 log.debug( "Not processing file that is not an artifact: {}", e.getMessage( ) ); 187 } 188 catch ( ContentNotFoundException e ) 189 { 190 throw new RepositoryPurgeException( e.getMessage( ), e ); 191 } 192 catch ( MetadataRepositoryException e ) 193 { 194 log.error( "Could not remove metadata during cleanup of released snapshots of {}", path, e ); 195 } 196 } 197 198 private void updateMetadata( ArtifactReference artifact ) 199 { 200 VersionedReference versionRef = new VersionedReference( ); 201 versionRef.setGroupId( artifact.getGroupId( ) ); 202 versionRef.setArtifactId( artifact.getArtifactId( ) ); 203 versionRef.setVersion( artifact.getVersion( ) ); 204 205 ProjectReference projectRef = new ProjectReference( ); 206 projectRef.setGroupId( artifact.getGroupId( ) ); 207 projectRef.setArtifactId( artifact.getArtifactId( ) ); 208 209 try 210 { 211 metadataTools.updateMetadata( repository, versionRef ); 212 } 213 catch ( ContentNotFoundException e ) 214 { 215 // Ignore. (Just means we have no snapshot versions left to reference). 216 } 217 catch ( RepositoryMetadataException e ) 218 { 219 // Ignore. 220 } 221 catch ( IOException e ) 222 { 223 // Ignore. 224 } 225 catch ( LayoutException e ) 226 { 227 // Ignore. 228 } 229 230 try 231 { 232 metadataTools.updateMetadata( repository, projectRef ); 233 } 234 catch ( ContentNotFoundException e ) 235 { 236 // Ignore. (Just means we have no snapshot versions left to reference). 237 } 238 catch ( RepositoryMetadataException e ) 239 { 240 // Ignore. 241 } 242 catch ( IOException e ) 243 { 244 // Ignore. 245 } 246 catch ( LayoutException e ) 247 { 248 // Ignore. 249 } 250 } 251}