001package org.apache.archiva.repository.content.maven2; 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.beans.ManagedRepository; 023import org.apache.archiva.common.utils.PathUtil; 024import org.apache.archiva.configuration.FileTypes; 025import org.apache.archiva.metadata.repository.storage.maven2.DefaultArtifactMappingProvider; 026import org.apache.archiva.model.ArchivaArtifact; 027import org.apache.archiva.model.ArtifactReference; 028import org.apache.archiva.model.ProjectReference; 029import org.apache.archiva.model.VersionedReference; 030import org.apache.archiva.repository.ContentNotFoundException; 031import org.apache.archiva.repository.ManagedRepositoryContent; 032import org.apache.archiva.repository.RepositoryException; 033import org.apache.archiva.repository.layout.LayoutException; 034import org.apache.commons.io.FileUtils; 035import org.apache.commons.lang.StringUtils; 036import org.springframework.context.annotation.Scope; 037import org.springframework.stereotype.Service; 038 039import javax.inject.Inject; 040import javax.inject.Named; 041import java.io.File; 042import java.io.IOException; 043import java.util.Collections; 044import java.util.HashSet; 045import java.util.Set; 046 047/** 048 * ManagedDefaultRepositoryContent 049 */ 050@Service ("managedRepositoryContent#default") 051@Scope ("prototype") 052public class ManagedDefaultRepositoryContent 053 extends AbstractDefaultRepositoryContent 054 implements ManagedRepositoryContent 055{ 056 @Inject 057 @Named ( "fileTypes" ) 058 private FileTypes filetypes; 059 060 private ManagedRepository repository; 061 062 public ManagedDefaultRepositoryContent() 063 { 064 // default to use if there are none supplied as components 065 this.artifactMappingProviders = Collections.singletonList( new DefaultArtifactMappingProvider() ); 066 } 067 068 @Override 069 public void deleteVersion( VersionedReference reference ) 070 { 071 String path = toMetadataPath( reference ); 072 File projectPath = new File( getRepoRoot(), path ); 073 074 File projectDir = projectPath.getParentFile(); 075 if ( projectDir.exists() && projectDir.isDirectory() ) 076 { 077 FileUtils.deleteQuietly( projectDir ); 078 } 079 } 080 081 @Override 082 public void deleteProject( String namespace, String projectId ) 083 throws RepositoryException, ContentNotFoundException 084 { 085 ArtifactReference artifactReference = new ArtifactReference(); 086 artifactReference.setGroupId( namespace ); 087 artifactReference.setArtifactId( projectId ); 088 String path = toPath( artifactReference ); 089 File directory = new File( getRepoRoot(), path ); 090 if ( !directory.exists() ) 091 { 092 throw new ContentNotFoundException( "cannot found project " + namespace + ":" + projectId ); 093 } 094 if ( directory.isDirectory() ) 095 { 096 try 097 { 098 FileUtils.deleteDirectory( directory ); 099 } 100 catch ( IOException e ) 101 { 102 throw new RepositoryException( e.getMessage(), e ); 103 } 104 } 105 else 106 { 107 log.warn( "project {}:{} is not a directory", namespace, projectId ); 108 } 109 110 } 111 112 @Override 113 public void deleteArtifact( ArtifactReference artifactReference ) 114 { 115 String path = toPath( artifactReference ); 116 File filePath = new File( getRepoRoot(), path ); 117 118 if ( filePath.exists() ) 119 { 120 FileUtils.deleteQuietly( filePath ); 121 } 122 123 File filePathmd5 = new File( getRepoRoot(), path + ".md5" ); 124 125 if ( filePathmd5.exists() ) 126 { 127 FileUtils.deleteQuietly( filePathmd5 ); 128 } 129 130 File filePathsha1 = new File( getRepoRoot(), path + ".sha1" ); 131 132 if ( filePathsha1.exists() ) 133 { 134 FileUtils.deleteQuietly( filePathsha1 ); 135 } 136 } 137 138 @Override 139 public void deleteGroupId( String groupId ) 140 throws ContentNotFoundException 141 { 142 143 String path = StringUtils.replaceChars( groupId, '.', '/' ); 144 145 File directory = new File( getRepoRoot(), path ); 146 147 if ( directory.exists() ) 148 { 149 try 150 { 151 FileUtils.deleteDirectory( directory ); 152 } 153 catch ( IOException e ) 154 { 155 log.warn( "skip error deleting directory {}:", directory.getPath(), e ); 156 } 157 } 158 } 159 160 @Override 161 public String getId() 162 { 163 return repository.getId(); 164 } 165 166 @Override 167 public Set<ArtifactReference> getRelatedArtifacts( ArtifactReference reference ) 168 throws ContentNotFoundException 169 { 170 File artifactFile = toFile( reference ); 171 File repoDir = artifactFile.getParentFile(); 172 173 if ( !repoDir.exists() ) 174 { 175 throw new ContentNotFoundException( 176 "Unable to get related artifacts using a non-existant directory: " + repoDir.getAbsolutePath() ); 177 } 178 179 if ( !repoDir.isDirectory() ) 180 { 181 throw new ContentNotFoundException( 182 "Unable to get related artifacts using a non-directory: " + repoDir.getAbsolutePath() ); 183 } 184 185 Set<ArtifactReference> foundArtifacts = new HashSet<>(); 186 187 // First gather up the versions found as artifacts in the managed repository. 188 File repoFiles[] = repoDir.listFiles(); 189 for (File repoFile : repoFiles) 190 { 191 if (repoFile.isDirectory()) { 192 // Skip it. it's a directory. 193 continue; 194 } 195 String relativePath = PathUtil.getRelative(repository.getLocation(), repoFile); 196 if ( filetypes.matchesArtifactPattern( relativePath ) ) 197 { 198 try 199 { 200 ArtifactReference artifact = toArtifactReference( relativePath ); 201 202 // Test for related, groupId / artifactId / version must match. 203 if ( artifact.getGroupId().equals( reference.getGroupId() ) && artifact.getArtifactId().equals( 204 reference.getArtifactId() ) && artifact.getVersion().equals( reference.getVersion() ) ) 205 { 206 foundArtifacts.add( artifact ); 207 } 208 } 209 catch ( LayoutException e ) 210 { 211 log.debug( "Not processing file that is not an artifact: {}", e.getMessage() ); 212 } 213 } 214 } 215 216 return foundArtifacts; 217 } 218 219 @Override 220 public String getRepoRoot() 221 { 222 return repository.getLocation(); 223 } 224 225 @Override 226 public ManagedRepository getRepository() 227 { 228 return repository; 229 } 230 231 /** 232 * Gather the Available Versions (on disk) for a specific Project Reference, based on filesystem 233 * information. 234 * 235 * @return the Set of available versions, based on the project reference. 236 * @throws org.apache.archiva.repository.layout.LayoutException 237 * @throws org.apache.archiva.repository.layout.LayoutException 238 */ 239 @Override 240 public Set<String> getVersions( ProjectReference reference ) 241 throws ContentNotFoundException, LayoutException 242 { 243 String path = toMetadataPath( reference ); 244 245 int idx = path.lastIndexOf( '/' ); 246 if ( idx > 0 ) 247 { 248 path = path.substring( 0, idx ); 249 } 250 251 File repoDir = new File( repository.getLocation(), path ); 252 253 if ( !repoDir.exists() ) 254 { 255 throw new ContentNotFoundException( 256 "Unable to get Versions on a non-existant directory: " + repoDir.getAbsolutePath() ); 257 } 258 259 if ( !repoDir.isDirectory() ) 260 { 261 throw new ContentNotFoundException( 262 "Unable to get Versions on a non-directory: " + repoDir.getAbsolutePath() ); 263 } 264 265 Set<String> foundVersions = new HashSet<>(); 266 VersionedReference versionRef = new VersionedReference(); 267 versionRef.setGroupId( reference.getGroupId() ); 268 versionRef.setArtifactId( reference.getArtifactId() ); 269 270 File repoFiles[] = repoDir.listFiles(); 271 for (File repoFile : repoFiles) 272 { 273 if (!repoFile.isDirectory()) { 274 // Skip it. not a directory. 275 continue; 276 } 277 // Test if dir has an artifact, which proves to us that it is a valid version directory. 278 String version = repoFile.getName(); 279 versionRef.setVersion( version ); 280 if ( hasArtifact( versionRef ) ) 281 { 282 // Found an artifact, must be a valid version. 283 foundVersions.add( version ); 284 } 285 } 286 287 return foundVersions; 288 } 289 290 @Override 291 public Set<String> getVersions( VersionedReference reference ) 292 throws ContentNotFoundException 293 { 294 String path = toMetadataPath( reference ); 295 296 int idx = path.lastIndexOf( '/' ); 297 if ( idx > 0 ) 298 { 299 path = path.substring( 0, idx ); 300 } 301 302 File repoDir = new File( repository.getLocation(), path ); 303 304 if ( !repoDir.exists() ) 305 { 306 throw new ContentNotFoundException( 307 "Unable to get versions on a non-existant directory: " + repoDir.getAbsolutePath() ); 308 } 309 310 if ( !repoDir.isDirectory() ) 311 { 312 throw new ContentNotFoundException( 313 "Unable to get versions on a non-directory: " + repoDir.getAbsolutePath() ); 314 } 315 316 Set<String> foundVersions = new HashSet<>(); 317 318 // First gather up the versions found as artifacts in the managed repository. 319 File repoFiles[] = repoDir.listFiles(); 320 for (File repoFile : repoFiles) 321 { 322 if (repoFile.isDirectory()) { 323 // Skip it. it's a directory. 324 continue; 325 } 326 String relativePath = PathUtil.getRelative(repository.getLocation(), repoFile); 327 if ( filetypes.matchesDefaultExclusions( relativePath ) ) 328 { 329 // Skip it, it's metadata or similar 330 continue; 331 } 332 if ( filetypes.matchesArtifactPattern( relativePath ) ) 333 { 334 try 335 { 336 ArtifactReference artifact = toArtifactReference( relativePath ); 337 338 foundVersions.add( artifact.getVersion() ); 339 } 340 catch ( LayoutException e ) 341 { 342 log.debug( "Not processing file that is not an artifact: {}", e.getMessage() ); 343 } 344 } 345 } 346 347 return foundVersions; 348 } 349 350 @Override 351 public boolean hasContent( ArtifactReference reference ) 352 { 353 File artifactFile = toFile( reference ); 354 return artifactFile.exists() && artifactFile.isFile(); 355 } 356 357 @Override 358 public boolean hasContent( ProjectReference reference ) 359 { 360 try 361 { 362 Set<String> versions = getVersions( reference ); 363 return !versions.isEmpty(); 364 } 365 catch ( ContentNotFoundException | LayoutException e ) 366 { 367 return false; 368 } 369 } 370 371 @Override 372 public boolean hasContent( VersionedReference reference ) 373 { 374 try 375 { 376 return ( getFirstArtifact( reference ) != null ); 377 } 378 catch ( IOException | LayoutException e ) 379 { 380 return false; 381 } 382 } 383 384 @Override 385 public void setRepository( ManagedRepository repository ) 386 { 387 this.repository = repository; 388 } 389 390 /** 391 * Convert a path to an artifact reference. 392 * 393 * @param path the path to convert. (relative or full location path) 394 * @throws org.apache.archiva.repository.layout.LayoutException if the path cannot be converted to an artifact reference. 395 */ 396 @Override 397 public ArtifactReference toArtifactReference( String path ) 398 throws LayoutException 399 { 400 if ( ( path != null ) && path.startsWith( repository.getLocation() ) && repository.getLocation().length() > 0 ) 401 { 402 return super.toArtifactReference( path.substring( repository.getLocation().length() + 1 ) ); 403 } 404 405 return super.toArtifactReference( path ); 406 } 407 408 @Override 409 public File toFile( ArtifactReference reference ) 410 { 411 return new File( repository.getLocation(), toPath( reference ) ); 412 } 413 414 @Override 415 public File toFile( ArchivaArtifact reference ) 416 { 417 return new File( repository.getLocation(), toPath( reference ) ); 418 } 419 420 /** 421 * Get the first Artifact found in the provided VersionedReference location. 422 * 423 * @param reference the reference to the versioned reference to search within 424 * @return the ArtifactReference to the first artifact located within the versioned reference. or null if 425 * no artifact was found within the versioned reference. 426 * @throws java.io.IOException if the versioned reference is invalid (example: doesn't exist, or isn't a directory) 427 * @throws org.apache.archiva.repository.layout.LayoutException 428 */ 429 private ArtifactReference getFirstArtifact( VersionedReference reference ) 430 throws LayoutException, IOException 431 { 432 String path = toMetadataPath( reference ); 433 434 int idx = path.lastIndexOf( '/' ); 435 if ( idx > 0 ) 436 { 437 path = path.substring( 0, idx ); 438 } 439 440 File repoDir = new File( repository.getLocation(), path ); 441 442 if ( !repoDir.exists() ) 443 { 444 throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: " 445 + repoDir.getAbsolutePath() ); 446 } 447 448 if ( !repoDir.isDirectory() ) 449 { 450 throw new IOException( 451 "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.getAbsolutePath() ); 452 } 453 454 File repoFiles[] = repoDir.listFiles(); 455 for (File repoFile : repoFiles) 456 { 457 if (repoFile.isDirectory()) { 458 // Skip it. it's a directory. 459 continue; 460 } 461 String relativePath = PathUtil.getRelative(repository.getLocation(), repoFile); 462 if ( filetypes.matchesArtifactPattern( relativePath ) ) 463 { 464 ArtifactReference artifact = toArtifactReference( relativePath ); 465 466 return artifact; 467 } 468 } 469 470 // No artifact was found. 471 return null; 472 } 473 474 private boolean hasArtifact( VersionedReference reference ) 475 throws LayoutException 476 { 477 try 478 { 479 return ( getFirstArtifact( reference ) != null ); 480 } 481 catch ( IOException e ) 482 { 483 return false; 484 } 485 } 486 487 public void setFiletypes( FileTypes filetypes ) 488 { 489 this.filetypes = filetypes; 490 } 491}