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.DefaultArtifactMappingProvider;
25 import org.apache.archiva.model.ArchivaArtifact;
26 import org.apache.archiva.model.ArtifactReference;
27 import org.apache.archiva.model.ProjectReference;
28 import org.apache.archiva.model.VersionedReference;
29 import org.apache.archiva.repository.ContentNotFoundException;
30 import org.apache.archiva.repository.ManagedRepositoryContent;
31 import org.apache.archiva.repository.RepositoryException;
32 import org.apache.archiva.repository.layout.LayoutException;
33 import org.apache.commons.lang.StringUtils;
34 import org.springframework.context.annotation.Scope;
35 import org.springframework.stereotype.Service;
37 import javax.inject.Inject;
38 import javax.inject.Named;
39 import java.io.IOException;
41 import java.nio.file.Files;
42 import java.nio.file.Path;
43 import java.nio.file.Paths;
44 import java.util.Collections;
45 import java.util.HashSet;
46 import java.util.Objects;
48 import java.util.stream.Collectors;
49 import java.util.stream.Stream;
52 * ManagedDefaultRepositoryContent
54 @Service ("managedRepositoryContent#maven")
56 public class ManagedDefaultRepositoryContent
57 extends AbstractDefaultRepositoryContent
58 implements ManagedRepositoryContent
61 @Named ( "fileTypes" )
62 private FileTypes filetypes;
64 private org.apache.archiva.repository.ManagedRepository repository;
66 public ManagedDefaultRepositoryContent()
68 // default to use if there are none supplied as components
69 this.artifactMappingProviders = Collections.singletonList( new DefaultArtifactMappingProvider() );
73 public void deleteVersion( VersionedReference reference )
75 String path = toMetadataPath( reference );
76 Path projectPath = Paths.get( getRepoRoot(), path );
78 Path projectDir = projectPath.getParent();
79 if ( Files.exists(projectDir) && Files.isDirectory(projectDir) )
81 org.apache.archiva.common.utils.FileUtils.deleteQuietly( projectDir );
86 public void deleteProject( String namespace, String projectId )
87 throws RepositoryException
89 ArtifactReference artifactReference = new ArtifactReference();
90 artifactReference.setGroupId( namespace );
91 artifactReference.setArtifactId( projectId );
92 String path = toPath( artifactReference );
93 Path directory = Paths.get( getRepoRoot(), path );
94 if ( !Files.exists(directory) )
96 throw new ContentNotFoundException( "cannot found project " + namespace + ":" + projectId );
98 if ( Files.isDirectory(directory) )
102 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
104 catch ( IOException e )
106 throw new RepositoryException( e.getMessage(), e );
111 log.warn( "project {}:{} is not a directory", namespace, projectId );
117 public void deleteArtifact( ArtifactReference artifactReference )
119 String path = toPath( artifactReference );
120 Path filePath = Paths.get( getRepoRoot(), path );
122 if ( Files.exists(filePath) )
124 org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePath );
127 Path filePathmd5 = Paths.get( getRepoRoot(), path + ".md5" );
129 if ( Files.exists(filePathmd5) )
131 org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathmd5 );
134 Path filePathsha1 = Paths.get( getRepoRoot(), path + ".sha1" );
136 if ( Files.exists(filePathsha1) )
138 org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathsha1 );
143 public void deleteGroupId( String groupId )
144 throws ContentNotFoundException
147 String path = StringUtils.replaceChars( groupId, '.', '/' );
149 Path directory = Paths.get( getRepoRoot(), path );
151 if ( Files.exists(directory) )
155 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
157 catch ( IOException e )
159 log.warn( "skip error deleting directory {}:", directory, e );
165 public String getId()
167 return repository.getId();
171 public Set<ArtifactReference> getRelatedArtifacts( ArtifactReference reference )
172 throws ContentNotFoundException
174 Path artifactFile = toFile( reference );
175 Path repoBase = PathUtil.getPathFromUri(repository.getLocation()).toAbsolutePath();
176 Path repoDir = artifactFile.getParent().toAbsolutePath();
178 if ( !Files.exists(repoDir))
180 throw new ContentNotFoundException(
181 "Unable to get related artifacts using a non-existant directory: " + repoDir.toAbsolutePath() );
184 if ( !Files.isDirectory( repoDir ) )
186 throw new ContentNotFoundException(
187 "Unable to get related artifacts using a non-directory: " + repoDir.toAbsolutePath() );
190 Set<ArtifactReference> foundArtifacts;
192 // First gather up the versions found as artifacts in the managed repository.
194 try (Stream<Path> stream = Files.list(repoDir)) {
195 foundArtifacts = stream.filter(Files::isRegularFile).map(path -> {
197 ArtifactReference artifact = toArtifactReference(repoBase.relativize(path).toString());
198 if( artifact.getGroupId().equals( reference.getGroupId() ) && artifact.getArtifactId().equals(
199 reference.getArtifactId() ) && artifact.getVersion().equals( reference.getVersion() )) {
204 } catch (LayoutException e) {
205 log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
208 }).filter(Objects::nonNull).collect(Collectors.toSet());
209 } catch (IOException e) {
210 log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
211 return Collections.emptySet();
213 return foundArtifacts;
217 public String getRepoRoot()
219 return convertUriToPath( repository.getLocation() );
222 private String convertUriToPath( URI uri ) {
223 if (uri.getScheme()==null) {
224 return Paths.get(uri.getPath()).toString();
225 } else if ("file".equals(uri.getScheme())) {
226 return Paths.get(uri).toString();
228 return uri.toString();
233 public org.apache.archiva.repository.ManagedRepository getRepository()
239 * Gather the Available Versions (on disk) for a specific Project Reference, based on filesystem
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
247 public Set<String> getVersions( ProjectReference reference )
248 throws ContentNotFoundException, LayoutException
250 String path = toMetadataPath( reference );
252 int idx = path.lastIndexOf( '/' );
255 path = path.substring( 0, idx );
258 Path repoDir = PathUtil.getPathFromUri( repository.getLocation() ).resolve( path );
260 if ( !Files.exists(repoDir) )
262 throw new ContentNotFoundException(
263 "Unable to get Versions on a non-existant directory: " + repoDir.toAbsolutePath() );
266 if ( !Files.isDirectory(repoDir) )
268 throw new ContentNotFoundException(
269 "Unable to get Versions on a non-directory: " + repoDir.toAbsolutePath() );
272 final String groupId = reference.getGroupId();
273 final String artifactId = reference.getArtifactId();
274 try(Stream<Path> stream = Files.list(repoDir)) {
275 return stream.filter(Files::isDirectory).map(
276 p -> newVersionedRef(groupId, artifactId, p.getFileName().toString())
277 ).filter(this::hasArtifact).map(ref -> ref.getVersion())
278 .collect(Collectors.toSet());
279 } catch (IOException e) {
280 log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
281 } catch (RuntimeException e) {
282 if (e.getCause()!=null && e.getCause() instanceof LayoutException) {
283 throw (LayoutException)e.getCause();
288 return Collections.emptySet();
291 static final VersionedReference newVersionedRef(final String groupId, final String artifactId, final String version) {
292 VersionedReference ref = new VersionedReference();
293 ref.setGroupId(groupId);
294 ref.setArtifactId(artifactId);
295 ref.setVersion(version);
300 public Set<String> getVersions( VersionedReference reference )
301 throws ContentNotFoundException
303 String path = toMetadataPath( reference );
305 int idx = path.lastIndexOf( '/' );
308 path = path.substring( 0, idx );
311 Path repoBase = PathUtil.getPathFromUri(repository.getLocation());
312 Path repoDir = repoBase.resolve( path );
314 if ( !Files.exists(repoDir) )
316 throw new ContentNotFoundException(
317 "Unable to get versions on a non-existant directory: " + repoDir.toAbsolutePath() );
320 if ( !Files.isDirectory(repoDir) )
322 throw new ContentNotFoundException(
323 "Unable to get versions on a non-directory: " + repoDir.toAbsolutePath() );
326 Set<String> foundVersions = new HashSet<>();
328 try(Stream<Path> stream = Files.list(repoDir)) {
329 return stream.filter(Files::isRegularFile)
330 .map(p -> repoBase.relativize(p).toString())
331 .filter(p -> !filetypes.matchesDefaultExclusions(p))
332 .filter(filetypes::matchesArtifactPattern)
335 return toArtifactReference(path1);
336 } catch (LayoutException e) {
337 log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
340 }).filter(Objects::nonNull)
341 .map(ar -> ar.getVersion())
342 .collect(Collectors.toSet());
343 } catch (IOException e) {
344 log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
346 return Collections.emptySet();
350 public boolean hasContent( ArtifactReference reference )
352 Path artifactFile = toFile( reference );
353 return Files.exists(artifactFile) && Files.isRegularFile( artifactFile );
357 public boolean hasContent( ProjectReference reference )
361 Set<String> versions = getVersions( reference );
362 return !versions.isEmpty();
364 catch ( ContentNotFoundException | LayoutException e )
371 public boolean hasContent( VersionedReference reference )
375 return ( getFirstArtifact( reference ) != null );
377 catch ( IOException | LayoutException e )
384 public void setRepository( org.apache.archiva.repository.ManagedRepository repository )
386 this.repository = repository;
390 * Convert a path to an artifact reference.
392 * @param path the path to convert. (relative or full location path)
393 * @throws org.apache.archiva.repository.layout.LayoutException if the path cannot be converted to an artifact reference.
396 public ArtifactReference toArtifactReference( String path )
397 throws LayoutException
399 String repoPath = convertUriToPath( repository.getLocation() );
400 if ( ( path != null ) && path.startsWith( repoPath ) && repoPath.length() > 0 )
402 return super.toArtifactReference( path.substring( repoPath.length() + 1 ) );
405 return super.toArtifactReference( path );
408 // The variant with runtime exception for stream usage
409 private ArtifactReference toArtifactRef(String path) {
411 return toArtifactReference(path);
412 } catch (LayoutException e) {
413 throw new RuntimeException(e);
420 public Path toFile( ArtifactReference reference )
422 return PathUtil.getPathFromUri( repository.getLocation()).resolve( toPath( reference ) );
426 public Path toFile( ArchivaArtifact reference )
428 return PathUtil.getPathFromUri( repository.getLocation()).resolve( toPath( reference ) );
432 * Get the first Artifact found in the provided VersionedReference location.
434 * @param reference the reference to the versioned reference to search within
435 * @return the ArtifactReference to the first artifact located within the versioned reference. or null if
436 * no artifact was found within the versioned reference.
437 * @throws java.io.IOException if the versioned reference is invalid (example: doesn't exist, or isn't a directory)
438 * @throws org.apache.archiva.repository.layout.LayoutException
440 private ArtifactReference getFirstArtifact( VersionedReference reference )
441 throws LayoutException, IOException
443 String path = toMetadataPath( reference );
445 int idx = path.lastIndexOf( '/' );
448 path = path.substring( 0, idx );
451 Path repoBase = PathUtil.getPathFromUri(repository.getLocation()).toAbsolutePath();
452 Path repoDir = repoBase.resolve( path );
454 if ( !Files.exists(repoDir) )
456 throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: "
457 + repoDir.toAbsolutePath() );
460 if ( !Files.isDirectory(repoDir) )
462 throw new IOException(
463 "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.toAbsolutePath() );
465 try(Stream<Path> stream = Files.list(repoDir)) {
466 return stream.filter(Files::isRegularFile)
467 .map(p -> repoBase.relativize(p).toString())
468 .filter(filetypes::matchesArtifactPattern)
469 .map(this::toArtifactRef).findFirst().orElse(null);
470 } catch (RuntimeException e) {
471 if (e.getCause()!=null && e.getCause() instanceof LayoutException) {
472 throw (LayoutException)e.getCause();
480 private boolean hasArtifact( VersionedReference reference )
485 return ( getFirstArtifact( reference ) != null );
487 catch ( IOException e )
490 } catch (LayoutException e) {
491 // We throw the runtime exception for better stream handling
492 throw new RuntimeException(e);
496 public void setFiletypes( FileTypes filetypes )
498 this.filetypes = filetypes;