]> source.dussan.org Git - archiva.git/blob
f0d81e2463d52ae09e5f074ed5d86f42a171a1c1
[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.filelock.FileLockException;
23 import org.apache.archiva.common.filelock.FileLockManager;
24 import org.apache.archiva.common.filelock.FileLockTimeoutException;
25 import org.apache.archiva.common.filelock.Lock;
26 import org.apache.archiva.common.utils.PathUtil;
27 import org.apache.archiva.configuration.FileTypes;
28 import org.apache.archiva.metadata.repository.storage.maven2.ArtifactMappingProvider;
29 import org.apache.archiva.metadata.repository.storage.maven2.DefaultArtifactMappingProvider;
30 import org.apache.archiva.model.ArchivaArtifact;
31 import org.apache.archiva.model.ArtifactReference;
32 import org.apache.archiva.model.ProjectReference;
33 import org.apache.archiva.model.VersionedReference;
34 import org.apache.archiva.repository.ContentNotFoundException;
35 import org.apache.archiva.repository.EditableManagedRepository;
36 import org.apache.archiva.repository.LayoutException;
37 import org.apache.archiva.repository.ManagedRepository;
38 import org.apache.archiva.repository.ManagedRepositoryContent;
39 import org.apache.archiva.repository.RepositoryException;
40 import org.apache.archiva.repository.content.FilesystemAsset;
41 import org.apache.archiva.repository.content.FilesystemStorage;
42 import org.apache.archiva.repository.content.StorageAsset;
43 import org.apache.commons.io.FileUtils;
44 import org.apache.commons.lang.StringUtils;
45
46 import java.io.FileNotFoundException;
47 import java.io.IOException;
48 import java.io.InputStream;
49 import java.net.URI;
50 import java.nio.file.Files;
51 import java.nio.file.Path;
52 import java.nio.file.Paths;
53 import java.util.Collections;
54 import java.util.HashSet;
55 import java.util.List;
56 import java.util.Objects;
57 import java.util.Set;
58 import java.util.function.Consumer;
59 import java.util.stream.Collectors;
60 import java.util.stream.Stream;
61
62 /**
63  * ManagedDefaultRepositoryContent
64  */
65 public class ManagedDefaultRepositoryContent
66     extends AbstractDefaultRepositoryContent
67     implements ManagedRepositoryContent
68 {
69
70     private final FilesystemStorage storage;
71
72     private FileTypes filetypes;
73
74     public void setFileTypes(FileTypes fileTypes) {
75         this.filetypes = fileTypes;
76     }
77
78     private ManagedRepository repository;
79
80     private Path repoDir;
81
82     public ManagedDefaultRepositoryContent(ManagedRepository repository, FileTypes fileTypes, FileLockManager lockManager) {
83         super(Collections.singletonList( new DefaultArtifactMappingProvider() ));
84         setFileTypes( fileTypes );
85         setRepository( repository );
86         try {
87             storage = new FilesystemStorage(getRepoDir(), lockManager);
88         } catch (IOException e) {
89             log.error("Could not initialize the filesystem storage to repository: {}", getRepoDir());
90             throw new RuntimeException("Fatal error. Could not initialize the filesystem storage for "+getRepoDir());
91         }
92     }
93
94     public ManagedDefaultRepositoryContent( ManagedRepository repository, List<? extends ArtifactMappingProvider> artifactMappingProviders, FileTypes fileTypes, FileLockManager lockManager )
95     {
96         super(artifactMappingProviders==null ? Collections.singletonList( new DefaultArtifactMappingProvider() ) : artifactMappingProviders);
97         setFileTypes( fileTypes );
98         setRepository( repository );
99         try {
100             storage = new FilesystemStorage(getRepoDir(), lockManager);
101         } catch (IOException e) {
102             log.error("Could not initialize the filesystem storage to repository: {}", getRepoDir());
103             throw new RuntimeException("Fatal error. Could not initialize the filesystem storage for "+getRepoDir());
104         }
105     }
106
107     private Path getRepoDir() {
108         return repoDir;
109     }
110
111
112     @Override
113     public void deleteVersion( VersionedReference reference )
114     {
115         String path = toMetadataPath( reference );
116         Path projectPath = Paths.get( getRepoRoot(), path );
117
118         Path projectDir = projectPath.getParent();
119         if ( Files.exists(projectDir) && Files.isDirectory(projectDir) )
120         {
121             org.apache.archiva.common.utils.FileUtils.deleteQuietly( projectDir );
122         }
123     }
124
125     @Override
126     public void deleteProject( String namespace, String projectId )
127         throws RepositoryException
128     {
129         ArtifactReference artifactReference = new ArtifactReference();
130         artifactReference.setGroupId( namespace );
131         artifactReference.setArtifactId( projectId );
132         String path = toPath( artifactReference );
133         Path directory = Paths.get( getRepoRoot(), path );
134         if ( !Files.exists(directory) )
135         {
136             throw new ContentNotFoundException( "cannot found project " + namespace + ":" + projectId );
137         }
138         if ( Files.isDirectory(directory) )
139         {
140             try
141             {
142                 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
143             }
144             catch ( IOException e )
145             {
146                 throw new RepositoryException( e.getMessage(), e );
147             }
148         }
149         else
150         {
151             log.warn( "project {}:{} is not a directory", namespace, projectId );
152         }
153
154     }
155
156     @Override
157     public void deleteArtifact( ArtifactReference artifactReference )
158     {
159         String path = toPath( artifactReference );
160         Path filePath = Paths.get( getRepoRoot(), path );
161
162         if ( Files.exists(filePath) )
163         {
164             org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePath );
165         }
166
167         Path filePathmd5 = Paths.get( getRepoRoot(), path + ".md5" );
168
169         if ( Files.exists(filePathmd5) )
170         {
171             org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathmd5 );
172         }
173
174         Path filePathsha1 = Paths.get( getRepoRoot(), path + ".sha1" );
175
176         if ( Files.exists(filePathsha1) )
177         {
178             org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathsha1 );
179         }
180     }
181
182     @Override
183     public void deleteGroupId( String groupId )
184         throws ContentNotFoundException
185     {
186
187         String path = StringUtils.replaceChars( groupId, '.', '/' );
188
189         Path directory = Paths.get( getRepoRoot(), path );
190
191         if ( Files.exists(directory) )
192         {
193             try
194             {
195                 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
196             }
197             catch ( IOException e )
198             {
199                 log.warn( "skip error deleting directory {}:", directory, e );
200             }
201         }
202     }
203
204     @Override
205     public String getId()
206     {
207         return repository.getId();
208     }
209
210     @Override
211     public Set<ArtifactReference> getRelatedArtifacts( ArtifactReference reference )
212         throws ContentNotFoundException
213     {
214         Path artifactFile = toFile( reference );
215         Path repoBase = PathUtil.getPathFromUri(repository.getLocation()).toAbsolutePath();
216         Path repoDir = artifactFile.getParent().toAbsolutePath();
217
218         if ( !Files.exists(repoDir))
219         {
220             throw new ContentNotFoundException(
221                 "Unable to get related artifacts using a non-existant directory: " + repoDir.toAbsolutePath() );
222         }
223
224         if ( !Files.isDirectory( repoDir ) )
225         {
226             throw new ContentNotFoundException(
227                 "Unable to get related artifacts using a non-directory: " + repoDir.toAbsolutePath() );
228         }
229
230         Set<ArtifactReference> foundArtifacts;
231
232         // First gather up the versions found as artifacts in the managed repository.
233
234         try (Stream<Path> stream = Files.list(repoDir)) {
235             foundArtifacts = stream.filter(Files::isRegularFile).map(path -> {
236                 try {
237                     ArtifactReference artifact = toArtifactReference(repoBase.relativize(path).toString());
238                     if( artifact.getGroupId().equals( reference.getGroupId() ) && artifact.getArtifactId().equals(
239                             reference.getArtifactId() ) && artifact.getVersion().equals( reference.getVersion() )) {
240                         return artifact;
241                     } else {
242                         return null;
243                     }
244                 } catch (LayoutException e) {
245                     log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
246                     return null;
247                 }
248             }).filter(Objects::nonNull).collect(Collectors.toSet());
249         } catch (IOException e) {
250             log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
251             return Collections.emptySet();
252         }
253         return foundArtifacts;
254     }
255
256     @Override
257     public String getRepoRoot()
258     {
259         return convertUriToPath( repository.getLocation() );
260     }
261
262     private String convertUriToPath( URI uri ) {
263         if (uri.getScheme()==null) {
264             return Paths.get(uri.getPath()).toString();
265         } else if ("file".equals(uri.getScheme())) {
266             return Paths.get(uri).toString();
267         } else {
268             return uri.toString();
269         }
270     }
271
272     @Override
273     public org.apache.archiva.repository.ManagedRepository getRepository()
274     {
275         return repository;
276     }
277
278     /**
279      * Gather the Available Versions (on disk) for a specific Project Reference, based on filesystem
280      * information.
281      *
282      * @return the Set of available versions, based on the project reference.
283      * @throws LayoutException
284      */
285     @Override
286     public Set<String> getVersions( ProjectReference reference )
287         throws ContentNotFoundException, LayoutException
288     {
289         String path = toMetadataPath( reference );
290
291         int idx = path.lastIndexOf( '/' );
292         if ( idx > 0 )
293         {
294             path = path.substring( 0, idx );
295         }
296
297         Path repoDir = PathUtil.getPathFromUri( repository.getLocation() ).resolve( path );
298
299         if ( !Files.exists(repoDir) )
300         {
301             throw new ContentNotFoundException(
302                 "Unable to get Versions on a non-existant directory: " + repoDir.toAbsolutePath() );
303         }
304
305         if ( !Files.isDirectory(repoDir) )
306         {
307             throw new ContentNotFoundException(
308                 "Unable to get Versions on a non-directory: " + repoDir.toAbsolutePath() );
309         }
310
311         final String groupId = reference.getGroupId();
312         final String artifactId = reference.getArtifactId();
313         try(Stream<Path> stream = Files.list(repoDir)) {
314             return stream.filter(Files::isDirectory).map(
315                     p -> newVersionedRef(groupId, artifactId, p.getFileName().toString())
316             ).filter(this::hasArtifact).map(ref -> ref.getVersion())
317                     .collect(Collectors.toSet());
318         } catch (IOException e) {
319             log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
320         } catch (RuntimeException e) {
321             if (e.getCause()!=null && e.getCause() instanceof LayoutException) {
322                 throw (LayoutException)e.getCause();
323             } else {
324                 throw e;
325             }
326         }
327         return Collections.emptySet();
328     }
329
330     static final VersionedReference newVersionedRef(final String groupId, final String artifactId, final String version) {
331         VersionedReference ref = new VersionedReference();
332         ref.setGroupId(groupId);
333         ref.setArtifactId(artifactId);
334         ref.setVersion(version);
335         return ref;
336     }
337
338     @Override
339     public Set<String> getVersions( VersionedReference reference )
340         throws ContentNotFoundException
341     {
342         String path = toMetadataPath( reference );
343
344         int idx = path.lastIndexOf( '/' );
345         if ( idx > 0 )
346         {
347             path = path.substring( 0, idx );
348         }
349
350         Path repoBase = PathUtil.getPathFromUri(repository.getLocation());
351         Path repoDir = repoBase.resolve( path );
352
353         if ( !Files.exists(repoDir) )
354         {
355             throw new ContentNotFoundException(
356                 "Unable to get versions on a non-existant directory: " + repoDir.toAbsolutePath() );
357         }
358
359         if ( !Files.isDirectory(repoDir) )
360         {
361             throw new ContentNotFoundException(
362                 "Unable to get versions on a non-directory: " + repoDir.toAbsolutePath() );
363         }
364
365         Set<String> foundVersions = new HashSet<>();
366
367         try(Stream<Path> stream = Files.list(repoDir)) {
368             return stream.filter(Files::isRegularFile)
369                     .map(p -> repoBase.relativize(p).toString())
370                     .filter(p -> !filetypes.matchesDefaultExclusions(p))
371                     .filter(filetypes::matchesArtifactPattern)
372                     .map(path1 -> {
373                         try {
374                             return toArtifactReference(path1);
375                         } catch (LayoutException e) {
376                             log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
377                             return null;
378                         }
379                     }).filter(Objects::nonNull)
380                     .map(ar -> ar.getVersion())
381                     .collect(Collectors.toSet());
382         } catch (IOException e) {
383             log.error("Could not read directory {}: {}", repoDir, e.getMessage(), e);
384         }
385         return Collections.emptySet();
386     }
387
388     @Override
389     public boolean hasContent( ArtifactReference reference )
390     {
391         Path artifactFile = toFile( reference );
392         return Files.exists(artifactFile) && Files.isRegularFile( artifactFile );
393     }
394
395     @Override
396     public boolean hasContent( ProjectReference reference )
397     {
398         try
399         {
400             Set<String> versions = getVersions( reference );
401             return !versions.isEmpty();
402         }
403         catch ( ContentNotFoundException | LayoutException e )
404         {
405             return false;
406         }
407     }
408
409     @Override
410     public boolean hasContent( VersionedReference reference )
411     {
412         try
413         {
414             return ( getFirstArtifact( reference ) != null );
415         }
416         catch ( IOException | LayoutException e )
417         {
418             return false;
419         }
420     }
421
422     @Override
423     public void setRepository( ManagedRepository repo )
424     {
425         this.repository = repo;
426         if (repo!=null) {
427             this.repoDir = PathUtil.getPathFromUri(repository.getLocation());
428             if (repository instanceof EditableManagedRepository) {
429                 ((EditableManagedRepository) repository).setContent(this);
430             }
431         }
432
433     }
434
435     /**
436      * Convert a path to an artifact reference.
437      *
438      * @param path the path to convert. (relative or full location path)
439      * @throws LayoutException if the path cannot be converted to an artifact reference.
440      */
441     @Override
442     public ArtifactReference toArtifactReference( String path )
443         throws LayoutException
444     {
445         String repoPath = convertUriToPath( repository.getLocation() );
446         if ( ( path != null ) && path.startsWith( repoPath ) && repoPath.length() > 0 )
447         {
448             return super.toArtifactReference( path.substring( repoPath.length() + 1 ) );
449         }
450
451         return super.toArtifactReference( path );
452     }
453
454     // The variant with runtime exception for stream usage
455     private ArtifactReference toArtifactRef(String path) {
456         try {
457             return toArtifactReference(path);
458         } catch (LayoutException e) {
459             throw new RuntimeException(e);
460         }
461     }
462
463
464
465     @Override
466     public Path toFile( ArtifactReference reference )
467     {
468         return PathUtil.getPathFromUri( repository.getLocation()).resolve( toPath( reference ) );
469     }
470
471     @Override
472     public Path toFile( ArchivaArtifact reference )
473     {
474         return PathUtil.getPathFromUri( repository.getLocation()).resolve( toPath( reference ) );
475     }
476
477     /**
478      * Get the first Artifact found in the provided VersionedReference location.
479      *
480      * @param reference the reference to the versioned reference to search within
481      * @return the ArtifactReference to the first artifact located within the versioned reference. or null if
482      *         no artifact was found within the versioned reference.
483      * @throws java.io.IOException     if the versioned reference is invalid (example: doesn't exist, or isn't a directory)
484      * @throws LayoutException
485      */
486     private ArtifactReference getFirstArtifact( VersionedReference reference )
487         throws LayoutException, IOException
488     {
489         String path = toMetadataPath( reference );
490
491         int idx = path.lastIndexOf( '/' );
492         if ( idx > 0 )
493         {
494             path = path.substring( 0, idx );
495         }
496
497         Path repoBase = PathUtil.getPathFromUri(repository.getLocation()).toAbsolutePath();
498         Path repoDir = repoBase.resolve( path );
499
500         if ( !Files.exists(repoDir) )
501         {
502             throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: "
503                                        + repoDir.toAbsolutePath() );
504         }
505
506         if ( !Files.isDirectory(repoDir) )
507         {
508             throw new IOException(
509                 "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.toAbsolutePath() );
510         }
511         try(Stream<Path> stream = Files.list(repoDir)) {
512             return stream.filter(Files::isRegularFile)
513                 .map(p -> repoBase.relativize(p).toString())
514                     .filter(filetypes::matchesArtifactPattern)
515                     .map(this::toArtifactRef).findFirst().orElse(null);
516         } catch (RuntimeException e) {
517             if (e.getCause()!=null && e.getCause() instanceof LayoutException) {
518                 throw (LayoutException)e.getCause();
519             } else {
520                 throw e;
521             }
522         }
523
524     }
525
526     private boolean hasArtifact( VersionedReference reference )
527
528     {
529         try
530         {
531             return ( getFirstArtifact( reference ) != null );
532         }
533         catch ( IOException e )
534         {
535             return false;
536         } catch (LayoutException e) {
537             // We throw the runtime exception for better stream handling
538             throw new RuntimeException(e);
539         }
540     }
541
542     public void setFiletypes( FileTypes filetypes )
543     {
544         this.filetypes = filetypes;
545     }
546
547
548     @Override
549     public void consumeData( StorageAsset asset, Consumer<InputStream> consumerFunction, boolean readLock ) throws IOException
550     {
551         storage.consumeData(asset, consumerFunction, readLock);
552     }
553
554
555     @Override
556     public StorageAsset getAsset( String path )
557     {
558         return storage.getAsset(path);
559     }
560
561     @Override
562     public StorageAsset addAsset( String path, boolean container )
563     {
564         return storage.addAsset(path, container);
565     }
566
567     @Override
568     public void removeAsset( StorageAsset asset ) throws IOException
569     {
570         storage.removeAsset(asset);
571     }
572
573     @Override
574     public StorageAsset moveAsset( StorageAsset origin, String destination ) throws IOException
575     {
576         return storage.moveAsset(origin, destination);
577     }
578
579     @Override
580     public StorageAsset copyAsset( StorageAsset origin, String destination ) throws IOException
581     {
582         return storage.copyAsset(origin, destination);
583     }
584
585
586 }