This project has retired. For details please refer to its Attic page.
ManagedDefaultRepositoryContent xref
View Javadoc
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         ArtifactReferencetml#ArtifactReference">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         VersionedReferencenedReference.html#VersionedReference">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 }