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.utils.PathUtil;
23 import org.apache.archiva.configuration.FileTypes;
24 import org.apache.archiva.metadata.repository.storage.maven2.ArtifactMappingProvider;
25 import org.apache.archiva.metadata.repository.storage.maven2.DefaultArtifactMappingProvider;
26 import org.apache.archiva.model.ArchivaArtifact;
27 import org.apache.archiva.model.ArtifactReference;
28 import org.apache.archiva.model.ProjectReference;
29 import org.apache.archiva.model.VersionedReference;
30 import org.apache.archiva.repository.ContentNotFoundException;
31 import org.apache.archiva.repository.ManagedRepositoryContent;
32 import org.apache.archiva.repository.RepositoryException;
33 import org.apache.archiva.repository.layout.LayoutException;
34 import org.apache.commons.lang.StringUtils;
36 import java.io.IOException;
38 import java.nio.file.Files;
39 import java.nio.file.Path;
40 import java.nio.file.Paths;
41 import java.util.Collections;
42 import java.util.HashSet;
43 import java.util.List;
44 import java.util.Objects;
46 import java.util.stream.Collectors;
47 import java.util.stream.Stream;
50 * ManagedDefaultRepositoryContent
52 public class ManagedDefaultRepositoryContent
53 extends AbstractDefaultRepositoryContent
54 implements ManagedRepositoryContent
57 private FileTypes filetypes;
59 public void setFileTypes(FileTypes fileTypes) {
60 this.filetypes = fileTypes;
65 private org.apache.archiva.repository.ManagedRepository repository;
67 public ManagedDefaultRepositoryContent(FileTypes fileTypes) {
68 super(Collections.singletonList( new DefaultArtifactMappingProvider() ));
69 setFileTypes( fileTypes );
71 public ManagedDefaultRepositoryContent( List<? extends ArtifactMappingProvider> artifactMappingProviders, FileTypes fileTypes )
73 super(artifactMappingProviders==null ? Collections.singletonList( new DefaultArtifactMappingProvider() ) : artifactMappingProviders);
74 setFileTypes( fileTypes );
78 public void deleteVersion( VersionedReference reference )
80 String path = toMetadataPath( reference );
81 Path projectPath = Paths.get( getRepoRoot(), path );
83 Path projectDir = projectPath.getParent();
84 if ( Files.exists(projectDir) && Files.isDirectory(projectDir) )
86 org.apache.archiva.common.utils.FileUtils.deleteQuietly( projectDir );
91 public void deleteProject( String namespace, String projectId )
92 throws RepositoryException
94 ArtifactReference artifactReference = new ArtifactReference();
95 artifactReference.setGroupId( namespace );
96 artifactReference.setArtifactId( projectId );
97 String path = toPath( artifactReference );
98 Path directory = Paths.get( getRepoRoot(), path );
99 if ( !Files.exists(directory) )
101 throw new ContentNotFoundException( "cannot found project " + namespace + ":" + projectId );
103 if ( Files.isDirectory(directory) )
107 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
109 catch ( IOException e )
111 throw new RepositoryException( e.getMessage(), e );
116 log.warn( "project {}:{} is not a directory", namespace, projectId );
122 public void deleteArtifact( ArtifactReference artifactReference )
124 String path = toPath( artifactReference );
125 Path filePath = Paths.get( getRepoRoot(), path );
127 if ( Files.exists(filePath) )
129 org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePath );
132 Path filePathmd5 = Paths.get( getRepoRoot(), path + ".md5" );
134 if ( Files.exists(filePathmd5) )
136 org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathmd5 );
139 Path filePathsha1 = Paths.get( getRepoRoot(), path + ".sha1" );
141 if ( Files.exists(filePathsha1) )
143 org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathsha1 );
148 public void deleteGroupId( String groupId )
149 throws ContentNotFoundException
152 String path = StringUtils.replaceChars( groupId, '.', '/' );
154 Path directory = Paths.get( getRepoRoot(), path );
156 if ( Files.exists(directory) )
160 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
162 catch ( IOException e )
164 log.warn( "skip error deleting directory {}:", directory, e );
170 public String getId()
172 return repository.getId();
176 public Set<ArtifactReference> getRelatedArtifacts( ArtifactReference reference )
177 throws ContentNotFoundException
179 Path artifactFile = toFile( reference );
180 Path repoBase = PathUtil.getPathFromUri(repository.getLocation()).toAbsolutePath();
181 Path repoDir = artifactFile.getParent().toAbsolutePath();
183 if ( !Files.exists(repoDir))
185 throw new ContentNotFoundException(
186 "Unable to get related artifacts using a non-existant directory: " + repoDir.toAbsolutePath() );
189 if ( !Files.isDirectory( repoDir ) )
191 throw new ContentNotFoundException(
192 "Unable to get related artifacts using a non-directory: " + repoDir.toAbsolutePath() );
195 Set<ArtifactReference> foundArtifacts;
197 // First gather up the versions found as artifacts in the managed repository.
199 try (Stream<Path> stream = Files.list(repoDir)) {
200 foundArtifacts = stream.filter(Files::isRegularFile).map(path -> {
202 ArtifactReference artifact = toArtifactReference(repoBase.relativize(path).toString());
203 if( artifact.getGroupId().equals( reference.getGroupId() ) && artifact.getArtifactId().equals(
204 reference.getArtifactId() ) && artifact.getVersion().equals( reference.getVersion() )) {
209 } catch (LayoutException e) {
210 log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
213 }).filter(Objects::nonNull).collect(Collectors.toSet());
214 } catch (IOException e) {
215 log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
216 return Collections.emptySet();
218 return foundArtifacts;
222 public String getRepoRoot()
224 return convertUriToPath( repository.getLocation() );
227 private String convertUriToPath( URI uri ) {
228 if (uri.getScheme()==null) {
229 return Paths.get(uri.getPath()).toString();
230 } else if ("file".equals(uri.getScheme())) {
231 return Paths.get(uri).toString();
233 return uri.toString();
238 public org.apache.archiva.repository.ManagedRepository getRepository()
244 * Gather the Available Versions (on disk) for a specific Project Reference, based on filesystem
247 * @return the Set of available versions, based on the project reference.
248 * @throws org.apache.archiva.repository.layout.LayoutException
249 * @throws org.apache.archiva.repository.layout.LayoutException
252 public Set<String> getVersions( ProjectReference reference )
253 throws ContentNotFoundException, LayoutException
255 String path = toMetadataPath( reference );
257 int idx = path.lastIndexOf( '/' );
260 path = path.substring( 0, idx );
263 Path repoDir = PathUtil.getPathFromUri( repository.getLocation() ).resolve( path );
265 if ( !Files.exists(repoDir) )
267 throw new ContentNotFoundException(
268 "Unable to get Versions on a non-existant directory: " + repoDir.toAbsolutePath() );
271 if ( !Files.isDirectory(repoDir) )
273 throw new ContentNotFoundException(
274 "Unable to get Versions on a non-directory: " + repoDir.toAbsolutePath() );
277 final String groupId = reference.getGroupId();
278 final String artifactId = reference.getArtifactId();
279 try(Stream<Path> stream = Files.list(repoDir)) {
280 return stream.filter(Files::isDirectory).map(
281 p -> newVersionedRef(groupId, artifactId, p.getFileName().toString())
282 ).filter(this::hasArtifact).map(ref -> ref.getVersion())
283 .collect(Collectors.toSet());
284 } catch (IOException e) {
285 log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
286 } catch (RuntimeException e) {
287 if (e.getCause()!=null && e.getCause() instanceof LayoutException) {
288 throw (LayoutException)e.getCause();
293 return Collections.emptySet();
296 static final VersionedReference newVersionedRef(final String groupId, final String artifactId, final String version) {
297 VersionedReference ref = new VersionedReference();
298 ref.setGroupId(groupId);
299 ref.setArtifactId(artifactId);
300 ref.setVersion(version);
305 public Set<String> getVersions( VersionedReference reference )
306 throws ContentNotFoundException
308 String path = toMetadataPath( reference );
310 int idx = path.lastIndexOf( '/' );
313 path = path.substring( 0, idx );
316 Path repoBase = PathUtil.getPathFromUri(repository.getLocation());
317 Path repoDir = repoBase.resolve( path );
319 if ( !Files.exists(repoDir) )
321 throw new ContentNotFoundException(
322 "Unable to get versions on a non-existant directory: " + repoDir.toAbsolutePath() );
325 if ( !Files.isDirectory(repoDir) )
327 throw new ContentNotFoundException(
328 "Unable to get versions on a non-directory: " + repoDir.toAbsolutePath() );
331 Set<String> foundVersions = new HashSet<>();
333 try(Stream<Path> stream = Files.list(repoDir)) {
334 return stream.filter(Files::isRegularFile)
335 .map(p -> repoBase.relativize(p).toString())
336 .filter(p -> !filetypes.matchesDefaultExclusions(p))
337 .filter(filetypes::matchesArtifactPattern)
340 return toArtifactReference(path1);
341 } catch (LayoutException e) {
342 log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
345 }).filter(Objects::nonNull)
346 .map(ar -> ar.getVersion())
347 .collect(Collectors.toSet());
348 } catch (IOException e) {
349 log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
351 return Collections.emptySet();
355 public boolean hasContent( ArtifactReference reference )
357 Path artifactFile = toFile( reference );
358 return Files.exists(artifactFile) && Files.isRegularFile( artifactFile );
362 public boolean hasContent( ProjectReference reference )
366 Set<String> versions = getVersions( reference );
367 return !versions.isEmpty();
369 catch ( ContentNotFoundException | LayoutException e )
376 public boolean hasContent( VersionedReference reference )
380 return ( getFirstArtifact( reference ) != null );
382 catch ( IOException | LayoutException e )
389 public void setRepository( org.apache.archiva.repository.ManagedRepository repository )
391 this.repository = repository;
395 * Convert a path to an artifact reference.
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.
401 public ArtifactReference toArtifactReference( String path )
402 throws LayoutException
404 String repoPath = convertUriToPath( repository.getLocation() );
405 if ( ( path != null ) && path.startsWith( repoPath ) && repoPath.length() > 0 )
407 return super.toArtifactReference( path.substring( repoPath.length() + 1 ) );
410 return super.toArtifactReference( path );
413 // The variant with runtime exception for stream usage
414 private ArtifactReference toArtifactRef(String path) {
416 return toArtifactReference(path);
417 } catch (LayoutException e) {
418 throw new RuntimeException(e);
425 public Path toFile( ArtifactReference reference )
427 return PathUtil.getPathFromUri( repository.getLocation()).resolve( toPath( reference ) );
431 public Path toFile( ArchivaArtifact reference )
433 return PathUtil.getPathFromUri( repository.getLocation()).resolve( toPath( reference ) );
437 * Get the first Artifact found in the provided VersionedReference location.
439 * @param reference the reference to the versioned reference to search within
440 * @return the ArtifactReference to the first artifact located within the versioned reference. or null if
441 * no artifact was found within the versioned reference.
442 * @throws java.io.IOException if the versioned reference is invalid (example: doesn't exist, or isn't a directory)
443 * @throws org.apache.archiva.repository.layout.LayoutException
445 private ArtifactReference getFirstArtifact( VersionedReference reference )
446 throws LayoutException, IOException
448 String path = toMetadataPath( reference );
450 int idx = path.lastIndexOf( '/' );
453 path = path.substring( 0, idx );
456 Path repoBase = PathUtil.getPathFromUri(repository.getLocation()).toAbsolutePath();
457 Path repoDir = repoBase.resolve( path );
459 if ( !Files.exists(repoDir) )
461 throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: "
462 + repoDir.toAbsolutePath() );
465 if ( !Files.isDirectory(repoDir) )
467 throw new IOException(
468 "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.toAbsolutePath() );
470 try(Stream<Path> stream = Files.list(repoDir)) {
471 return stream.filter(Files::isRegularFile)
472 .map(p -> repoBase.relativize(p).toString())
473 .filter(filetypes::matchesArtifactPattern)
474 .map(this::toArtifactRef).findFirst().orElse(null);
475 } catch (RuntimeException e) {
476 if (e.getCause()!=null && e.getCause() instanceof LayoutException) {
477 throw (LayoutException)e.getCause();
485 private boolean hasArtifact( VersionedReference reference )
490 return ( getFirstArtifact( reference ) != null );
492 catch ( IOException e )
495 } catch (LayoutException e) {
496 // We throw the runtime exception for better stream handling
497 throw new RuntimeException(e);
501 public void setFiletypes( FileTypes filetypes )
503 this.filetypes = filetypes;