]> source.dussan.org Git - archiva.git/blob
9b39137e3b8eefb901da2a5e539fcddd47a3401a
[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.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;
39
40 import java.io.IOException;
41 import java.net.URI;
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;
49 import java.util.Set;
50 import java.util.stream.Collectors;
51 import java.util.stream.Stream;
52
53 /**
54  * ManagedDefaultRepositoryContent
55  */
56 public class ManagedDefaultRepositoryContent
57     extends AbstractDefaultRepositoryContent
58     implements ManagedRepositoryContent
59 {
60
61     private FileTypes filetypes;
62
63     public void setFileTypes(FileTypes fileTypes) {
64         this.filetypes = fileTypes;
65     }
66
67     private ManagedRepository repository;
68
69     private Path repoDir;
70
71     FileLockManager lockManager;
72
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 );
78     }
79
80     public ManagedDefaultRepositoryContent( ManagedRepository repository, List<? extends ArtifactMappingProvider> artifactMappingProviders, FileTypes fileTypes, FileLockManager lockManager )
81     {
82         super(artifactMappingProviders==null ? Collections.singletonList( new DefaultArtifactMappingProvider() ) : artifactMappingProviders);
83         setFileTypes( fileTypes );
84         this.lockManager = lockManager;
85         setRepository( repository );
86
87     }
88
89     private Path getRepoDir() {
90         return repoDir;
91     }
92
93
94     @Override
95     public void deleteVersion( VersionedReference reference )
96     {
97         String path = toMetadataPath( reference );
98         Path projectPath = Paths.get( getRepoRoot(), path );
99
100         Path projectDir = projectPath.getParent();
101         if ( Files.exists(projectDir) && Files.isDirectory(projectDir) )
102         {
103             org.apache.archiva.common.utils.FileUtils.deleteQuietly( projectDir );
104         }
105     }
106
107     @Override
108     public void deleteProject( String namespace, String projectId )
109         throws RepositoryException
110     {
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) )
117         {
118             throw new ContentNotFoundException( "cannot found project " + namespace + ":" + projectId );
119         }
120         if ( Files.isDirectory(directory) )
121         {
122             try
123             {
124                 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
125             }
126             catch ( IOException e )
127             {
128                 throw new RepositoryException( e.getMessage(), e );
129             }
130         }
131         else
132         {
133             log.warn( "project {}:{} is not a directory", namespace, projectId );
134         }
135
136     }
137
138     @Override
139     public void deleteArtifact( ArtifactReference artifactReference )
140     {
141         String path = toPath( artifactReference );
142         Path filePath = Paths.get( getRepoRoot(), path );
143
144         if ( Files.exists(filePath) )
145         {
146             org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePath );
147         }
148
149         Path filePathmd5 = Paths.get( getRepoRoot(), path + ".md5" );
150
151         if ( Files.exists(filePathmd5) )
152         {
153             org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathmd5 );
154         }
155
156         Path filePathsha1 = Paths.get( getRepoRoot(), path + ".sha1" );
157
158         if ( Files.exists(filePathsha1) )
159         {
160             org.apache.archiva.common.utils.FileUtils.deleteQuietly( filePathsha1 );
161         }
162     }
163
164     @Override
165     public void deleteGroupId( String groupId )
166         throws ContentNotFoundException
167     {
168
169         String path = StringUtils.replaceChars( groupId, '.', '/' );
170
171         Path directory = Paths.get( getRepoRoot(), path );
172
173         if ( Files.exists(directory) )
174         {
175             try
176             {
177                 org.apache.archiva.common.utils.FileUtils.deleteDirectory( directory );
178             }
179             catch ( IOException e )
180             {
181                 log.warn( "skip error deleting directory {}:", directory, e );
182             }
183         }
184     }
185
186     @Override
187     public String getId()
188     {
189         return repository.getId();
190     }
191
192     @Override
193     public Set<ArtifactReference> getRelatedArtifacts( ArtifactReference reference )
194         throws ContentNotFoundException
195     {
196         StorageAsset artifactFile = toFile( reference );
197         StorageAsset repoBase = repository.getAsset( "" );
198         StorageAsset repoDir = artifactFile.getParent();
199
200         if ( !repoDir.exists())
201         {
202             throw new ContentNotFoundException(
203                 "Unable to get related artifacts using a non-existant directory: " + repoDir.getPath() );
204         }
205
206         if ( !repoDir.isContainer() )
207         {
208             throw new ContentNotFoundException(
209                 "Unable to get related artifacts using a non-directory: " + repoDir.getPath() );
210         }
211
212         Set<ArtifactReference> foundArtifacts;
213
214         // First gather up the versions found as artifacts in the managed repository.
215
216         try (Stream<StorageAsset> stream = repoDir.list().stream() ) {
217             foundArtifacts = stream.filter(asset -> !asset.isContainer()).map(path -> {
218                 try {
219                     ArtifactReference artifact = toArtifactReference(path.getPath());
220                     if( artifact.getGroupId().equals( reference.getGroupId() ) && artifact.getArtifactId().equals(
221                             reference.getArtifactId() ) && artifact.getVersion().equals( reference.getVersion() )) {
222                         return artifact;
223                     } else {
224                         return null;
225                     }
226                 } catch (LayoutException e) {
227                     log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
228                     return null;
229                 }
230             }).filter(Objects::nonNull).collect(Collectors.toSet());
231         }
232         return foundArtifacts;
233     }
234
235     @Override
236     public String getRepoRoot()
237     {
238         return convertUriToPath( repository.getLocation() );
239     }
240
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();
246         } else {
247             return uri.toString();
248         }
249     }
250
251     @Override
252     public org.apache.archiva.repository.ManagedRepository getRepository()
253     {
254         return repository;
255     }
256
257     /**
258      * Gather the Available Versions (on disk) for a specific Project Reference, based on filesystem
259      * information.
260      *
261      * @return the Set of available versions, based on the project reference.
262      * @throws LayoutException
263      */
264     @Override
265     public Set<String> getVersions( ProjectReference reference )
266         throws ContentNotFoundException, LayoutException
267     {
268         String path = toMetadataPath( reference );
269
270         int idx = path.lastIndexOf( '/' );
271         if ( idx > 0 )
272         {
273             path = path.substring( 0, idx );
274         }
275
276         Path repoDir = PathUtil.getPathFromUri( repository.getLocation() ).resolve( path );
277
278         if ( !Files.exists(repoDir) )
279         {
280             throw new ContentNotFoundException(
281                 "Unable to get Versions on a non-existant directory: " + repoDir.toAbsolutePath() );
282         }
283
284         if ( !Files.isDirectory(repoDir) )
285         {
286             throw new ContentNotFoundException(
287                 "Unable to get Versions on a non-directory: " + repoDir.toAbsolutePath() );
288         }
289
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();
302             } else {
303                 throw e;
304             }
305         }
306         return Collections.emptySet();
307     }
308
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);
314         return ref;
315     }
316
317     @Override
318     public Set<String> getVersions( VersionedReference reference )
319         throws ContentNotFoundException
320     {
321         String path = toMetadataPath( reference );
322
323         int idx = path.lastIndexOf( '/' );
324         if ( idx > 0 )
325         {
326             path = path.substring( 0, idx );
327         }
328
329         Path repoBase = PathUtil.getPathFromUri(repository.getLocation());
330         Path repoDir = repoBase.resolve( path );
331
332         if ( !Files.exists(repoDir) )
333         {
334             throw new ContentNotFoundException(
335                 "Unable to get versions on a non-existant directory: " + repoDir.toAbsolutePath() );
336         }
337
338         if ( !Files.isDirectory(repoDir) )
339         {
340             throw new ContentNotFoundException(
341                 "Unable to get versions on a non-directory: " + repoDir.toAbsolutePath() );
342         }
343
344         Set<String> foundVersions = new HashSet<>();
345
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)
351                     .map(path1 -> {
352                         try {
353                             return toArtifactReference(path1);
354                         } catch (LayoutException e) {
355                             log.debug( "Not processing file that is not an artifact: {}", e.getMessage() );
356                             return null;
357                         }
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);
363         }
364         return Collections.emptySet();
365     }
366
367     @Override
368     public boolean hasContent( ArtifactReference reference )
369     {
370         StorageAsset artifactFile = toFile( reference );
371         return artifactFile.exists() && !artifactFile.isContainer();
372     }
373
374     @Override
375     public boolean hasContent( ProjectReference reference )
376     {
377         try
378         {
379             Set<String> versions = getVersions( reference );
380             return !versions.isEmpty();
381         }
382         catch ( ContentNotFoundException | LayoutException e )
383         {
384             return false;
385         }
386     }
387
388     @Override
389     public boolean hasContent( VersionedReference reference )
390     {
391         try
392         {
393             return ( getFirstArtifact( reference ) != null );
394         }
395         catch ( IOException | LayoutException e )
396         {
397             return false;
398         }
399     }
400
401     @Override
402     public void setRepository( ManagedRepository repo )
403     {
404         this.repository = repo;
405         if (repo!=null) {
406             this.repoDir = PathUtil.getPathFromUri(repository.getLocation());
407             if (repository instanceof EditableManagedRepository) {
408                 ((EditableManagedRepository) repository).setContent(this);
409             }
410         }
411
412     }
413
414     /**
415      * Convert a path to an artifact reference.
416      *
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.
419      */
420     @Override
421     public ArtifactReference toArtifactReference( String path )
422         throws LayoutException
423     {
424         String repoPath = convertUriToPath( repository.getLocation() );
425         if ( ( path != null ) && path.startsWith( repoPath ) && repoPath.length() > 0 )
426         {
427             return super.toArtifactReference( path.substring( repoPath.length() + 1 ) );
428         } else {
429             repoPath = path;
430             if (repoPath!=null) {
431                 while (repoPath.startsWith("/")) {
432                     repoPath = repoPath.substring(1);
433                 }
434             }
435             return super.toArtifactReference( repoPath );
436         }
437     }
438
439     // The variant with runtime exception for stream usage
440     private ArtifactReference toArtifactRef(String path) {
441         try {
442             return toArtifactReference(path);
443         } catch (LayoutException e) {
444             throw new RuntimeException(e);
445         }
446     }
447
448
449
450     @Override
451     public StorageAsset toFile( ArtifactReference reference )
452     {
453         return repository.getAsset(toPath(reference));
454     }
455
456     @Override
457     public StorageAsset toFile( ArchivaArtifact reference )
458     {
459         return repository.getAsset( toPath( reference ) );
460     }
461
462     /**
463      * Get the first Artifact found in the provided VersionedReference location.
464      *
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
470      */
471     private ArtifactReference getFirstArtifact( VersionedReference reference )
472         throws LayoutException, IOException
473     {
474         String path = toMetadataPath( reference );
475
476         int idx = path.lastIndexOf( '/' );
477         if ( idx > 0 )
478         {
479             path = path.substring( 0, idx );
480         }
481
482         Path repoBase = PathUtil.getPathFromUri(repository.getLocation()).toAbsolutePath();
483         Path repoDir = repoBase.resolve( path );
484
485         if ( !Files.exists(repoDir) )
486         {
487             throw new IOException( "Unable to gather the list of snapshot versions on a non-existant directory: "
488                                        + repoDir.toAbsolutePath() );
489         }
490
491         if ( !Files.isDirectory(repoDir) )
492         {
493             throw new IOException(
494                 "Unable to gather the list of snapshot versions on a non-directory: " + repoDir.toAbsolutePath() );
495         }
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();
504             } else {
505                 throw e;
506             }
507         }
508
509     }
510
511     private boolean hasArtifact( VersionedReference reference )
512
513     {
514         try
515         {
516             return ( getFirstArtifact( reference ) != null );
517         }
518         catch ( IOException e )
519         {
520             return false;
521         } catch (LayoutException e) {
522             // We throw the runtime exception for better stream handling
523             throw new RuntimeException(e);
524         }
525     }
526
527     public void setFiletypes( FileTypes filetypes )
528     {
529         this.filetypes = filetypes;
530     }
531
532
533 }