This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.repository.content.maven2;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *  http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.archiva.common.filelock.FileLockManager;
023import org.apache.archiva.common.utils.PathUtil;
024import org.apache.archiva.configuration.FileTypes;
025import org.apache.archiva.metadata.repository.storage.maven2.ArtifactMappingProvider;
026import org.apache.archiva.metadata.repository.storage.maven2.DefaultArtifactMappingProvider;
027import org.apache.archiva.model.ArchivaArtifact;
028import org.apache.archiva.model.ArtifactReference;
029import org.apache.archiva.model.ProjectReference;
030import org.apache.archiva.model.VersionedReference;
031import org.apache.archiva.repository.ContentNotFoundException;
032import org.apache.archiva.repository.EditableManagedRepository;
033import org.apache.archiva.repository.LayoutException;
034import org.apache.archiva.repository.ManagedRepository;
035import org.apache.archiva.repository.ManagedRepositoryContent;
036import org.apache.archiva.repository.RepositoryException;
037import org.apache.archiva.repository.storage.StorageAsset;
038import org.apache.commons.lang3.StringUtils;
039
040import java.io.IOException;
041import java.net.URI;
042import java.nio.file.Files;
043import java.nio.file.Path;
044import java.nio.file.Paths;
045import java.util.Collections;
046import java.util.HashSet;
047import java.util.List;
048import java.util.Objects;
049import java.util.Set;
050import java.util.stream.Collectors;
051import java.util.stream.Stream;
052
053/**
054 * ManagedDefaultRepositoryContent
055 */
056public class ManagedDefaultRepositoryContent
057    extends AbstractDefaultRepositoryContent
058    implements ManagedRepositoryContent
059{
060
061    private FileTypes filetypes;
062
063    public void setFileTypes(FileTypes fileTypes) {
064        this.filetypes = fileTypes;
065    }
066
067    private ManagedRepository repository;
068
069    private Path repoDir;
070
071    FileLockManager lockManager;
072
073    public ManagedDefaultRepositoryContent(ManagedRepository repository, FileTypes fileTypes, FileLockManager lockManager) {
074        super(Collections.singletonList( new DefaultArtifactMappingProvider() ));
075        setFileTypes( fileTypes );
076        this.lockManager = lockManager;
077        setRepository( repository );
078    }
079
080    public ManagedDefaultRepositoryContent( ManagedRepository repository, List<? extends ArtifactMappingProvider> artifactMappingProviders, FileTypes fileTypes, FileLockManager lockManager )
081    {
082        super(artifactMappingProviders==null ? Collections.singletonList( new DefaultArtifactMappingProvider() ) : artifactMappingProviders);
083        setFileTypes( fileTypes );
084        this.lockManager = lockManager;
085        setRepository( repository );
086
087    }
088
089    private Path getRepoDir() {
090        return repoDir;
091    }
092
093
094    @Override
095    public void deleteVersion( VersionedReference reference )
096    {
097        String path = toMetadataPath( reference );
098        Path projectPath = Paths.get( getRepoRoot(), path );
099
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}