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