]> source.dussan.org Git - archiva.git/blob
298aa5d18c3d6475db3f42e83a5709deab012283
[archiva.git] /
1 package org.apache.archiva.repository.content.maven2;
2
3 /*
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
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
21
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;
36
37 import javax.inject.Inject;
38 import javax.inject.Named;
39 import java.io.IOException;
40 import java.net.URI;
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;
47 import java.util.Set;
48 import java.util.stream.Collectors;
49 import java.util.stream.Stream;
50
51 /**
52  * ManagedDefaultRepositoryContent
53  */
54 @Service ("managedRepositoryContent#maven")
55 @Scope ("prototype")
56 public class ManagedDefaultRepositoryContent
57     extends AbstractDefaultRepositoryContent
58     implements ManagedRepositoryContent
59 {
60     @Inject
61     @Named ( "fileTypes" )
62     private FileTypes filetypes;
63
64     private org.apache.archiva.repository.ManagedRepository repository;
65
66     public ManagedDefaultRepositoryContent()
67     {
68         // default to use if there are none supplied as components
69         this.artifactMappingProviders = Collections.singletonList( new DefaultArtifactMappingProvider() );
70     }
71
72     @Override
73     public void deleteVersion( VersionedReference reference )
74     {
75         String path = toMetadataPath( reference );
76         Path projectPath = Paths.get( getRepoRoot(), path );
77
78         Path projectDir = projectPath.getParent();
79         if ( Files.exists(projectDir) && Files.isDirectory(projectDir) )
80         {
81             org.apache.archiva.common.utils.FileUtils.deleteQuietly( projectDir );
82         }
83     }
84
85     @Override
86     public void deleteProject( String namespace, String projectId )
87         throws RepositoryException
88     {
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) )
95         {
96             throw new ContentNotFoundException( "cannot found project " + namespace + ":" + projectId );
97         }
98         if ( Files.isDirectory(directory) )
99         {
100             try
101             {
102                 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
103             }
104             catch ( IOException e )
105             {
106                 throw new RepositoryException( e.getMessage(), e );
107             }
108         }
109         else
110         {
111             log.warn( "project {}:{} is not a directory", namespace, projectId );
112         }
113
114     }
115
116     @Override
117     public void deleteArtifact( ArtifactReference artifactReference )
118     {
119         String path = toPath( artifactReference );
120         Path filePath = Paths.get( getRepoRoot(), path );
121
122         if ( Files.exists(filePath) )
123         {
124             org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePath );
125         }
126
127         Path filePathmd5 = Paths.get( getRepoRoot(), path + ".md5" );
128
129         if ( Files.exists(filePathmd5) )
130         {
131             org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathmd5 );
132         }
133
134         Path filePathsha1 = Paths.get( getRepoRoot(), path + ".sha1" );
135
136         if ( Files.exists(filePathsha1) )
137         {
138             org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathsha1 );
139         }
140     }
141
142     @Override
143     public void deleteGroupId( String groupId )
144         throws ContentNotFoundException
145     {
146
147         String path = StringUtils.replaceChars( groupId, '.', '/' );
148
149         Path directory = Paths.get( getRepoRoot(), path );
150
151         if ( Files.exists(directory) )
152         {
153             try
154             {
155                 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
156             }
157             catch ( IOException e )
158             {
159                 log.warn( "skip error deleting directory {}:", directory, e );
160             }
161         }
162     }
163
164     @Override
165     public String getId()
166     {
167         return repository.getId();
168     }
169
170     @Override
171     public Set<ArtifactReference> getRelatedArtifacts( ArtifactReference reference )
172         throws ContentNotFoundException
173     {
174         Path artifactFile = toFile( reference );
175         Path repoBase = PathUtil.getPathFromUri(repository.getLocation()).toAbsolutePath();
176         Path repoDir = artifactFile.getParent().toAbsolutePath();
177
178         if ( !Files.exists(repoDir))
179         {
180             throw new ContentNotFoundException(
181                 "Unable to get related artifacts using a non-existant directory: " + repoDir.toAbsolutePath() );
182         }
183
184         if ( !Files.isDirectory( repoDir ) )
185         {
186             throw new ContentNotFoundException(
187                 "Unable to get related artifacts using a non-directory: " + repoDir.toAbsolutePath() );
188         }
189
190         Set<ArtifactReference> foundArtifacts;
191
192         // First gather up the versions found as artifacts in the managed repository.
193
194         try (Stream<Path> stream = Files.list(repoDir)) {
195             foundArtifacts = stream.filter(Files::isRegularFile).map(path -> {
196                 try {
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() )) {
200                         return artifact;
201                     } else {
202                         return null;
203                     }
204                 } catch (LayoutException e) {
205                     log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
206                     return null;
207                 }
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();
212         }
213         return foundArtifacts;
214     }
215
216     @Override
217     public String getRepoRoot()
218     {
219         return convertUriToPath( repository.getLocation() );
220     }
221
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();
227         } else {
228             return uri.toString();
229         }
230     }
231
232     @Override
233     public org.apache.archiva.repository.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         Path repoDir = PathUtil.getPathFromUri( repository.getLocation() ).resolve( path );
259
260         if ( !Files.exists(repoDir) )
261         {
262             throw new ContentNotFoundException(
263                 "Unable to get Versions on a non-existant directory: " + repoDir.toAbsolutePath() );
264         }
265
266         if ( !Files.isDirectory(repoDir) )
267         {
268             throw new ContentNotFoundException(
269                 "Unable to get Versions on a non-directory: " + repoDir.toAbsolutePath() );
270         }
271
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();
284             } else {
285                 throw e;
286             }
287         }
288         return Collections.emptySet();
289     }
290
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);
296         return ref;
297     }
298
299     @Override
300     public Set<String> getVersions( VersionedReference reference )
301         throws ContentNotFoundException
302     {
303         String path = toMetadataPath( reference );
304
305         int idx = path.lastIndexOf( '/' );
306         if ( idx > 0 )
307         {
308             path = path.substring( 0, idx );
309         }
310
311         Path repoBase = PathUtil.getPathFromUri(repository.getLocation());
312         Path repoDir = repoBase.resolve( path );
313
314         if ( !Files.exists(repoDir) )
315         {
316             throw new ContentNotFoundException(
317                 "Unable to get versions on a non-existant directory: " + repoDir.toAbsolutePath() );
318         }
319
320         if ( !Files.isDirectory(repoDir) )
321         {
322             throw new ContentNotFoundException(
323                 "Unable to get versions on a non-directory: " + repoDir.toAbsolutePath() );
324         }
325
326         Set<String> foundVersions = new HashSet<>();
327
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)
333                     .map(path1 -> {
334                         try {
335                             return toArtifactReference(path1);
336                         } catch (LayoutException e) {
337                             log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
338                             return null;
339                         }
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);
345         }
346         return Collections.emptySet();
347     }
348
349     @Override
350     public boolean hasContent( ArtifactReference reference )
351     {
352         Path artifactFile = toFile( reference );
353         return Files.exists(artifactFile) && Files.isRegularFile( artifactFile );
354     }
355
356     @Override
357     public boolean hasContent( ProjectReference reference )
358     {
359         try
360         {
361             Set<String> versions = getVersions( reference );
362             return !versions.isEmpty();
363         }
364         catch ( ContentNotFoundException | LayoutException e )
365         {
366             return false;
367         }
368     }
369
370     @Override
371     public boolean hasContent( VersionedReference reference )
372     {
373         try
374         {
375             return ( getFirstArtifact( reference ) != null );
376         }
377         catch ( IOException | LayoutException e )
378         {
379             return false;
380         }
381     }
382
383     @Override
384     public void setRepository( org.apache.archiva.repository.ManagedRepository repository )
385     {
386         this.repository = repository;
387     }
388
389     /**
390      * Convert a path to an artifact reference.
391      *
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.
394      */
395     @Override
396     public ArtifactReference toArtifactReference( String path )
397         throws LayoutException
398     {
399         String repoPath = convertUriToPath( repository.getLocation() );
400         if ( ( path != null ) && path.startsWith( repoPath ) && repoPath.length() > 0 )
401         {
402             return super.toArtifactReference( path.substring( repoPath.length() + 1 ) );
403         }
404
405         return super.toArtifactReference( path );
406     }
407
408     // The variant with runtime exception for stream usage
409     private ArtifactReference toArtifactRef(String path) {
410         try {
411             return toArtifactReference(path);
412         } catch (LayoutException e) {
413             throw new RuntimeException(e);
414         }
415     }
416
417
418
419     @Override
420     public Path toFile( ArtifactReference reference )
421     {
422         return PathUtil.getPathFromUri( repository.getLocation()).resolve( toPath( reference ) );
423     }
424
425     @Override
426     public Path toFile( ArchivaArtifact reference )
427     {
428         return PathUtil.getPathFromUri( repository.getLocation()).resolve( toPath( reference ) );
429     }
430
431     /**
432      * Get the first Artifact found in the provided VersionedReference location.
433      *
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
439      */
440     private ArtifactReference getFirstArtifact( VersionedReference reference )
441         throws LayoutException, IOException
442     {
443         String path = toMetadataPath( reference );
444
445         int idx = path.lastIndexOf( '/' );
446         if ( idx > 0 )
447         {
448             path = path.substring( 0, idx );
449         }
450
451         Path repoBase = PathUtil.getPathFromUri(repository.getLocation()).toAbsolutePath();
452         Path repoDir = repoBase.resolve( path );
453
454         if ( !Files.exists(repoDir) )
455         {
456             throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: "
457                                        + repoDir.toAbsolutePath() );
458         }
459
460         if ( !Files.isDirectory(repoDir) )
461         {
462             throw new IOException(
463                 "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.toAbsolutePath() );
464         }
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();
473             } else {
474                 throw e;
475             }
476         }
477
478     }
479
480     private boolean hasArtifact( VersionedReference reference )
481
482     {
483         try
484         {
485             return ( getFirstArtifact( reference ) != null );
486         }
487         catch ( IOException e )
488         {
489             return false;
490         } catch (LayoutException e) {
491             // We throw the runtime exception for better stream handling
492             throw new RuntimeException(e);
493         }
494     }
495
496     public void setFiletypes( FileTypes filetypes )
497     {
498         this.filetypes = filetypes;
499     }
500 }