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