1 package org.apache.archiva.repository.content.maven2;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
22 import org.apache.archiva.common.filelock.FileLockManager;
23 import org.apache.archiva.common.utils.PathUtil;
24 import org.apache.archiva.configuration.FileTypes;
25 import org.apache.archiva.metadata.repository.storage.maven2.ArtifactMappingProvider;
26 import org.apache.archiva.metadata.repository.storage.maven2.DefaultArtifactMappingProvider;
27 import org.apache.archiva.model.ArchivaArtifact;
28 import org.apache.archiva.model.ArtifactReference;
29 import org.apache.archiva.model.ProjectReference;
30 import org.apache.archiva.model.VersionedReference;
31 import org.apache.archiva.repository.ContentNotFoundException;
32 import org.apache.archiva.repository.EditableManagedRepository;
33 import org.apache.archiva.repository.LayoutException;
34 import org.apache.archiva.repository.ManagedRepository;
35 import org.apache.archiva.repository.ManagedRepositoryContent;
36 import org.apache.archiva.repository.RepositoryException;
37 import org.apache.archiva.repository.storage.StorageAsset;
38 import org.apache.commons.lang3.StringUtils;
40 import java.io.IOException;
42 import java.nio.file.Files;
43 import java.nio.file.Path;
44 import java.nio.file.Paths;
45 import java.util.Collections;
46 import java.util.HashSet;
47 import java.util.List;
48 import java.util.Objects;
50 import java.util.stream.Collectors;
51 import java.util.stream.Stream;
54 * ManagedDefaultRepositoryContent
56 public class ManagedDefaultRepositoryContent
57 extends AbstractDefaultRepositoryContent
58 implements ManagedRepositoryContent
61 private FileTypes filetypes;
63 public void setFileTypes(FileTypes fileTypes) {
64 this.filetypes = fileTypes;
67 private ManagedRepository repository;
71 FileLockManager lockManager;
73 public ManagedDefaultRepositoryContent(ManagedRepository repository, FileTypes fileTypes, FileLockManager lockManager) {
74 super(Collections.singletonList( new DefaultArtifactMappingProvider() ));
75 setFileTypes( fileTypes );
76 this.lockManager = lockManager;
77 setRepository( repository );
80 public ManagedDefaultRepositoryContent( ManagedRepository repository, List<? extends ArtifactMappingProvider> artifactMappingProviders, FileTypes fileTypes, FileLockManager lockManager )
82 super(artifactMappingProviders==null ? Collections.singletonList( new DefaultArtifactMappingProvider() ) : artifactMappingProviders);
83 setFileTypes( fileTypes );
84 this.lockManager = lockManager;
85 setRepository( repository );
89 private Path getRepoDir() {
95 public void deleteVersion( VersionedReference reference )
97 String path = toMetadataPath( reference );
98 Path projectPath = Paths.get( getRepoRoot(), path );
100 Path projectDir = projectPath.getParent();
101 if ( Files.exists(projectDir) && Files.isDirectory(projectDir) )
103 org.apache.archiva.common.utils.FileUtils.deleteQuietly( projectDir );
108 public void deleteProject( String namespace, String projectId )
109 throws RepositoryException
111 ArtifactReference artifactReference = new ArtifactReference();
112 artifactReference.setGroupId( namespace );
113 artifactReference.setArtifactId( projectId );
114 String path = toPath( artifactReference );
115 Path directory = Paths.get( getRepoRoot(), path );
116 if ( !Files.exists(directory) )
118 throw new ContentNotFoundException( "cannot found project " + namespace + ":" + projectId );
120 if ( Files.isDirectory(directory) )
124 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
126 catch ( IOException e )
128 throw new RepositoryException( e.getMessage(), e );
133 log.warn( "project {}:{} is not a directory", namespace, projectId );
139 public void deleteArtifact( ArtifactReference artifactReference )
141 String path = toPath( artifactReference );
142 Path filePath = Paths.get( getRepoRoot(), path );
144 if ( Files.exists(filePath) )
146 org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePath );
149 Path filePathmd5 = Paths.get( getRepoRoot(), path + ".md5" );
151 if ( Files.exists(filePathmd5) )
153 org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathmd5 );
156 Path filePathsha1 = Paths.get( getRepoRoot(), path + ".sha1" );
158 if ( Files.exists(filePathsha1) )
160 org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathsha1 );
165 public void deleteGroupId( String groupId )
166 throws ContentNotFoundException
169 String path = StringUtils.replaceChars( groupId, '.', '/' );
171 Path directory = Paths.get( getRepoRoot(), path );
173 if ( Files.exists(directory) )
177 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
179 catch ( IOException e )
181 log.warn( "skip error deleting directory {}:", directory, e );
187 public String getId()
189 return repository.getId();
193 public Set<ArtifactReference> getRelatedArtifacts( ArtifactReference reference )
194 throws ContentNotFoundException
196 StorageAsset artifactFile = toFile( reference );
197 StorageAsset repoBase = repository.getAsset( "" );
198 StorageAsset repoDir = artifactFile.getParent();
200 if ( !repoDir.exists())
202 throw new ContentNotFoundException(
203 "Unable to get related artifacts using a non-existant directory: " + repoDir.getPath() );
206 if ( !repoDir.isContainer() )
208 throw new ContentNotFoundException(
209 "Unable to get related artifacts using a non-directory: " + repoDir.getPath() );
212 Set<ArtifactReference> foundArtifacts;
214 // First gather up the versions found as artifacts in the managed repository.
216 try (Stream<StorageAsset> stream = repoDir.list().stream() ) {
217 foundArtifacts = stream.filter(asset -> !asset.isContainer()).map(path -> {
219 ArtifactReference artifact = toArtifactReference(path.getPath());
220 if( artifact.getGroupId().equals( reference.getGroupId() ) && artifact.getArtifactId().equals(
221 reference.getArtifactId() ) && artifact.getVersion().equals( reference.getVersion() )) {
226 } catch (LayoutException e) {
227 log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
230 }).filter(Objects::nonNull).collect(Collectors.toSet());
232 return foundArtifacts;
236 public String getRepoRoot()
238 return convertUriToPath( repository.getLocation() );
241 private String convertUriToPath( URI uri ) {
242 if (uri.getScheme()==null) {
243 return Paths.get(uri.getPath()).toString();
244 } else if ("file".equals(uri.getScheme())) {
245 return Paths.get(uri).toString();
247 return uri.toString();
252 public org.apache.archiva.repository.ManagedRepository getRepository()
258 * Gather the Available Versions (on disk) for a specific Project Reference, based on filesystem
261 * @return the Set of available versions, based on the project reference.
262 * @throws LayoutException
265 public Set<String> getVersions( ProjectReference reference )
266 throws ContentNotFoundException, LayoutException
268 String path = toMetadataPath( reference );
270 int idx = path.lastIndexOf( '/' );
273 path = path.substring( 0, idx );
276 Path repoDir = PathUtil.getPathFromUri( repository.getLocation() ).resolve( path );
278 if ( !Files.exists(repoDir) )
280 throw new ContentNotFoundException(
281 "Unable to get Versions on a non-existant directory: " + repoDir.toAbsolutePath() );
284 if ( !Files.isDirectory(repoDir) )
286 throw new ContentNotFoundException(
287 "Unable to get Versions on a non-directory: " + repoDir.toAbsolutePath() );
290 final String groupId = reference.getGroupId();
291 final String artifactId = reference.getArtifactId();
292 try(Stream<Path> stream = Files.list(repoDir)) {
293 return stream.filter(Files::isDirectory).map(
294 p -> newVersionedRef(groupId, artifactId, p.getFileName().toString())
295 ).filter(this::hasArtifact).map(ref -> ref.getVersion())
296 .collect(Collectors.toSet());
297 } catch (IOException e) {
298 log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
299 } catch (RuntimeException e) {
300 if (e.getCause()!=null && e.getCause() instanceof LayoutException) {
301 throw (LayoutException)e.getCause();
306 return Collections.emptySet();
309 static final VersionedReference newVersionedRef(final String groupId, final String artifactId, final String version) {
310 VersionedReference ref = new VersionedReference();
311 ref.setGroupId(groupId);
312 ref.setArtifactId(artifactId);
313 ref.setVersion(version);
318 public Set<String> getVersions( VersionedReference reference )
319 throws ContentNotFoundException
321 String path = toMetadataPath( reference );
323 int idx = path.lastIndexOf( '/' );
326 path = path.substring( 0, idx );
329 Path repoBase = PathUtil.getPathFromUri(repository.getLocation());
330 Path repoDir = repoBase.resolve( path );
332 if ( !Files.exists(repoDir) )
334 throw new ContentNotFoundException(
335 "Unable to get versions on a non-existant directory: " + repoDir.toAbsolutePath() );
338 if ( !Files.isDirectory(repoDir) )
340 throw new ContentNotFoundException(
341 "Unable to get versions on a non-directory: " + repoDir.toAbsolutePath() );
344 Set<String> foundVersions = new HashSet<>();
346 try(Stream<Path> stream = Files.list(repoDir)) {
347 return stream.filter(Files::isRegularFile)
348 .map(p -> repoBase.relativize(p).toString())
349 .filter(p -> !filetypes.matchesDefaultExclusions(p))
350 .filter(filetypes::matchesArtifactPattern)
353 return toArtifactReference(path1);
354 } catch (LayoutException e) {
355 log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
358 }).filter(Objects::nonNull)
359 .map(ar -> ar.getVersion())
360 .collect(Collectors.toSet());
361 } catch (IOException e) {
362 log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
364 return Collections.emptySet();
368 public boolean hasContent( ArtifactReference reference )
370 StorageAsset artifactFile = toFile( reference );
371 return artifactFile.exists() && !artifactFile.isContainer();
375 public boolean hasContent( ProjectReference reference )
379 Set<String> versions = getVersions( reference );
380 return !versions.isEmpty();
382 catch ( ContentNotFoundException | LayoutException e )
389 public boolean hasContent( VersionedReference reference )
393 return ( getFirstArtifact( reference ) != null );
395 catch ( IOException | LayoutException e )
402 public void setRepository( ManagedRepository repo )
404 this.repository = repo;
406 this.repoDir = PathUtil.getPathFromUri(repository.getLocation());
407 if (repository instanceof EditableManagedRepository) {
408 ((EditableManagedRepository) repository).setContent(this);
415 * Convert a path to an artifact reference.
417 * @param path the path to convert. (relative or full location path)
418 * @throws LayoutException if the path cannot be converted to an artifact reference.
421 public ArtifactReference toArtifactReference( String path )
422 throws LayoutException
424 String repoPath = convertUriToPath( repository.getLocation() );
425 if ( ( path != null ) && path.startsWith( repoPath ) && repoPath.length() > 0 )
427 return super.toArtifactReference( path.substring( repoPath.length() + 1 ) );
430 if (repoPath!=null) {
431 while (repoPath.startsWith("/")) {
432 repoPath = repoPath.substring(1);
435 return super.toArtifactReference( repoPath );
439 // The variant with runtime exception for stream usage
440 private ArtifactReference toArtifactRef(String path) {
442 return toArtifactReference(path);
443 } catch (LayoutException e) {
444 throw new RuntimeException(e);
451 public StorageAsset toFile( ArtifactReference reference )
453 return repository.getAsset(toPath(reference));
457 public StorageAsset toFile( ArchivaArtifact reference )
459 return repository.getAsset( toPath( reference ) );
463 * Get the first Artifact found in the provided VersionedReference location.
465 * @param reference the reference to the versioned reference to search within
466 * @return the ArtifactReference to the first artifact located within the versioned reference. or null if
467 * no artifact was found within the versioned reference.
468 * @throws java.io.IOException if the versioned reference is invalid (example: doesn't exist, or isn't a directory)
469 * @throws LayoutException
471 private ArtifactReference getFirstArtifact( VersionedReference reference )
472 throws LayoutException, IOException
474 String path = toMetadataPath( reference );
476 int idx = path.lastIndexOf( '/' );
479 path = path.substring( 0, idx );
482 Path repoBase = PathUtil.getPathFromUri(repository.getLocation()).toAbsolutePath();
483 Path repoDir = repoBase.resolve( path );
485 if ( !Files.exists(repoDir) )
487 throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: "
488 + repoDir.toAbsolutePath() );
491 if ( !Files.isDirectory(repoDir) )
493 throw new IOException(
494 "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.toAbsolutePath() );
496 try(Stream<Path> stream = Files.list(repoDir)) {
497 return stream.filter(Files::isRegularFile)
498 .map(p -> repoBase.relativize(p).toString())
499 .filter(filetypes::matchesArtifactPattern)
500 .map(this::toArtifactRef).findFirst().orElse(null);
501 } catch (RuntimeException e) {
502 if (e.getCause()!=null && e.getCause() instanceof LayoutException) {
503 throw (LayoutException)e.getCause();
511 private boolean hasArtifact( VersionedReference reference )
516 return ( getFirstArtifact( reference ) != null );
518 catch ( IOException e )
521 } catch (LayoutException e) {
522 // We throw the runtime exception for better stream handling
523 throw new RuntimeException(e);
527 public void setFiletypes( FileTypes filetypes )
529 this.filetypes = filetypes;