1 package org.apache.archiva.repository.maven.content;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
21 import org.apache.archiva.common.filelock.FileLockManager;
22 import org.apache.archiva.common.utils.FileUtils;
23 import org.apache.archiva.configuration.FileTypes;
24 import org.apache.archiva.metadata.maven.MavenMetadataReader;
25 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
26 import org.apache.archiva.model.ArtifactReference;
27 import org.apache.archiva.repository.BaseRepositoryContentLayout;
28 import org.apache.archiva.repository.ContentAccessException;
29 import org.apache.archiva.repository.EditableManagedRepository;
30 import org.apache.archiva.repository.ItemDeleteStatus;
31 import org.apache.archiva.repository.LayoutException;
32 import org.apache.archiva.repository.LayoutRuntimeException;
33 import org.apache.archiva.repository.ManagedRepository;
34 import org.apache.archiva.repository.ManagedRepositoryContent;
35 import org.apache.archiva.repository.ManagedRepositoryContentLayout;
36 import org.apache.archiva.repository.content.Artifact;
37 import org.apache.archiva.repository.content.ArtifactType;
38 import org.apache.archiva.repository.content.BaseArtifactTypes;
39 import org.apache.archiva.repository.content.ContentItem;
40 import org.apache.archiva.repository.content.DataItem;
41 import org.apache.archiva.repository.content.ItemNotFoundException;
42 import org.apache.archiva.repository.content.ItemSelector;
43 import org.apache.archiva.repository.content.Namespace;
44 import org.apache.archiva.repository.content.Project;
45 import org.apache.archiva.repository.content.Version;
46 import org.apache.archiva.repository.content.base.ArchivaContentItem;
47 import org.apache.archiva.repository.content.base.ArchivaItemSelector;
48 import org.apache.archiva.repository.content.base.ArchivaNamespace;
49 import org.apache.archiva.repository.content.base.ArchivaProject;
50 import org.apache.archiva.repository.content.base.ArchivaVersion;
51 import org.apache.archiva.repository.content.base.builder.ArtifactOptBuilder;
52 import org.apache.archiva.repository.maven.metadata.storage.ArtifactMappingProvider;
53 import org.apache.archiva.repository.maven.metadata.storage.DefaultArtifactMappingProvider;
54 import org.apache.archiva.repository.storage.RepositoryStorage;
55 import org.apache.archiva.repository.storage.StorageAsset;
56 import org.apache.archiva.repository.storage.util.StorageUtil;
57 import org.apache.commons.collections4.map.ReferenceMap;
58 import org.apache.commons.lang3.StringUtils;
60 import javax.inject.Inject;
61 import javax.inject.Named;
62 import java.io.IOException;
64 import java.nio.file.Files;
65 import java.nio.file.Path;
66 import java.nio.file.Paths;
67 import java.util.Collections;
68 import java.util.List;
69 import java.util.Objects;
70 import java.util.Optional;
71 import java.util.function.Consumer;
72 import java.util.function.Predicate;
73 import java.util.regex.Matcher;
74 import java.util.regex.Pattern;
75 import java.util.stream.Collectors;
76 import java.util.stream.Stream;
79 * ManagedDefaultRepositoryContent
81 public class ManagedDefaultRepositoryContent
82 extends AbstractDefaultRepositoryContent
83 implements ManagedRepositoryContent, BaseRepositoryContentLayout
86 // attribute flag that marks version objects that point to a snapshot artifact version
87 public static final String SNAPSHOT_ARTIFACT_VERSION = "maven.snav";
89 private FileTypes filetypes;
91 public void setFileTypes( FileTypes fileTypes )
93 this.filetypes = fileTypes;
96 private ManagedRepository repository;
98 private FileLockManager lockManager;
101 @Named( "repositoryPathTranslator#maven2" )
102 private RepositoryPathTranslator pathTranslator;
105 @Named( "metadataReader#maven" )
106 MavenMetadataReader metadataReader;
109 @Named( "MavenContentHelper" )
110 MavenContentHelper mavenContentHelper;
112 public static final String SNAPSHOT = "SNAPSHOT";
114 public static final Pattern UNIQUE_SNAPSHOT_PATTERN = Pattern.compile( "^(SNAPSHOT|[0-9]{8}\\.[0-9]{6}-[0-9]+)(.*)" );
115 public static final Pattern CLASSIFIER_PATTERN = Pattern.compile( "^-([^.]+)(\\..*)" );
116 public static final Pattern COMMON_EXTENSIONS = Pattern.compile( "^(jar|war|ear|dar|tar|zip|pom|xml)$" );
118 public static final Pattern TIMESTAMP_PATTERN = Pattern.compile( "^([0-9]{8})\\.([0-9]{6})$" );
120 public static final Pattern GENERIC_SNAPSHOT_PATTERN = Pattern.compile( "^(.*)-" + SNAPSHOT );
123 * We are caching content items in a weak reference map. To avoid always recreating the
124 * the hierarchical structure.
125 * TODO: Better use a object cache? E.g. our spring cache implementation?
127 private ReferenceMap<StorageAsset, ContentItem> itemMap = new ReferenceMap<>( );
128 private ReferenceMap<StorageAsset, DataItem> dataItemMap = new ReferenceMap<>( );
130 public ManagedDefaultRepositoryContent( )
132 super( Collections.singletonList( new DefaultArtifactMappingProvider( ) ) );
135 public ManagedDefaultRepositoryContent( ManagedRepository repository, FileTypes fileTypes, FileLockManager lockManager )
137 super( Collections.singletonList( new DefaultArtifactMappingProvider( ) ) );
138 setFileTypes( fileTypes );
139 this.lockManager = lockManager;
140 setRepository( repository );
143 public ManagedDefaultRepositoryContent( ManagedRepository repository, List<? extends ArtifactMappingProvider> artifactMappingProviders, FileTypes fileTypes, FileLockManager lockManager )
145 super( artifactMappingProviders == null ? Collections.singletonList( new DefaultArtifactMappingProvider( ) ) : artifactMappingProviders );
146 setFileTypes( fileTypes );
147 this.lockManager = lockManager;
148 setRepository( repository );
152 private StorageAsset getAssetByPath( String assetPath )
154 return getStorage( ).getAsset( assetPath );
157 private StorageAsset getAsset( String namespace )
159 String namespacePath = formatAsDirectory( namespace.trim( ) );
160 if ( StringUtils.isEmpty( namespacePath ) )
164 return getAssetByPath( namespacePath );
167 private StorageAsset getAsset( String namespace, String project )
169 return getAsset( namespace ).resolve( project );
172 private StorageAsset getAsset( String namespace, String project, String version )
174 return getAsset( namespace, project ).resolve( version );
177 private StorageAsset getAsset( String namespace, String project, String version, String fileName )
179 return getAsset( namespace, project, version ).resolve( fileName );
183 /// ************* Start of new generation interface ******************
187 public <T extends ContentItem> T adaptItem( Class<T> clazz, ContentItem item ) throws LayoutException
189 if (clazz.isAssignableFrom( Version.class ))
191 if ( !item.hasCharacteristic( Version.class ) )
193 item.setCharacteristic( Version.class, createVersionFromPath( item.getAsset() ) );
195 return (T) item.adapt( Version.class );
196 } else if ( clazz.isAssignableFrom( Project.class )) {
197 if ( !item.hasCharacteristic( Project.class ) )
199 item.setCharacteristic( Project.class, createProjectFromPath( item.getAsset() ) );
201 return (T) item.adapt( Project.class );
202 } else if ( clazz.isAssignableFrom( Namespace.class )) {
203 if ( !item.hasCharacteristic( Namespace.class ) )
205 item.setCharacteristic( Namespace.class, createNamespaceFromPath( item.getAsset() ) );
207 return (T) item.adapt( Namespace.class );
208 } else if ( clazz.isAssignableFrom( Artifact.class )) {
209 if (!item.hasCharacteristic( Artifact.class )) {
210 item.setCharacteristic( Artifact.class, createArtifactFromPath( item.getAsset( ) ) );
212 return (T) item.adapt( Artifact.class );
214 throw new LayoutException( "Could not convert item to class " + clazz);
219 public void deleteAllItems( ItemSelector selector, Consumer<ItemDeleteStatus> consumer ) throws ContentAccessException, IllegalArgumentException
221 try ( Stream<? extends ContentItem> stream = newItemStream( selector, false ) )
223 stream.forEach( item -> {
227 consumer.accept( new ItemDeleteStatus( item ) );
229 catch ( ItemNotFoundException e )
231 consumer.accept( new ItemDeleteStatus( item, ItemDeleteStatus.ITEM_NOT_FOUND, e ) );
233 catch ( Exception e )
235 consumer.accept( new ItemDeleteStatus( item, ItemDeleteStatus.DELETION_FAILED, e ) );
237 catch ( Throwable e )
239 consumer.accept( new ItemDeleteStatus( item, ItemDeleteStatus.UNKNOWN, e ) );
246 * Removes the item from the filesystem. For namespaces, projects and versions it deletes
248 * For namespaces you have to be careful, because maven repositories may have sub namespaces
249 * parallel to projects. Which means deleting a namespaces also deletes the sub namespaces and
250 * not only the projects of the given namespace. Better run the delete for each project of
253 * Artifacts are deleted as provided. No related artifacts will be deleted.
255 * @param item the item that should be removed
256 * @throws ItemNotFoundException if the item does not exist
257 * @throws ContentAccessException if some error occurred while accessing the filesystem
260 public void deleteItem( ContentItem item ) throws ItemNotFoundException, ContentAccessException
262 final Path baseDirectory = getRepoDir( );
263 final Path itemPath = item.getAsset( ).getFilePath( );
264 if ( !Files.exists( itemPath ) )
266 throw new ItemNotFoundException( "The item " + item.toString( ) + "does not exist in the repository " + getId( ) );
268 if ( !itemPath.toAbsolutePath( ).startsWith( baseDirectory.toAbsolutePath( ) ) )
270 log.error( "The namespace {} to delete from repository {} is not a subdirectory of the repository base.", item, getId( ) );
271 log.error( "Namespace directory: {}", itemPath );
272 log.error( "Repository directory: {}", baseDirectory );
273 throw new ContentAccessException( "Inconsistent directories found. Could not delete namespace." );
277 if ( Files.isDirectory( itemPath ) )
279 FileUtils.deleteDirectory( itemPath );
283 Files.deleteIfExists( itemPath );
286 catch ( IOException e )
288 log.error( "Could not delete item from path {}: {}", itemPath, e.getMessage( ), e );
289 throw new ContentAccessException( "Error occured while deleting item " + item + ": " + e.getMessage( ), e );
294 public ContentItem getItem( ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
296 if ( selector.hasVersion( ) && selector.hasArtifactId( ) )
298 return getArtifact( selector );
300 else if ( selector.hasProjectId( ) && selector.hasVersion( ) )
302 return getVersion( selector );
304 else if ( selector.hasProjectId( ) )
306 return getProject( selector );
310 return getNamespace( selector );
315 public Namespace getNamespace( final ItemSelector namespaceSelector ) throws ContentAccessException, IllegalArgumentException
317 StorageAsset nsPath = getAsset( namespaceSelector.getNamespace() );
320 return getNamespaceFromPath( nsPath );
322 catch ( LayoutException e )
324 throw new IllegalArgumentException( "Not a valid selector " + e.getMessage( ), e );
330 public Project getProject( final ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
332 if ( !selector.hasProjectId( ) )
334 throw new IllegalArgumentException( "Project id must be set" );
336 final StorageAsset path = getAsset( selector.getNamespace( ), selector.getProjectId( ) );
339 return getProjectFromPath( path );
341 catch ( LayoutException e )
343 throw new IllegalArgumentException( "Not a valid selector " + e.getMessage( ), e );
349 public Version getVersion( final ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
351 if ( !selector.hasProjectId( ) )
353 throw new IllegalArgumentException( "Project id must be set" );
355 if ( !selector.hasVersion( ) )
357 throw new IllegalArgumentException( "Version must be set" );
359 final StorageAsset path = getAsset( selector.getNamespace( ), selector.getProjectId( ), selector.getVersion( ) );
362 return getVersionFromPath( path );
364 catch ( LayoutException e )
366 throw new IllegalArgumentException( "Not a valid selector " + e.getMessage( ), e );
371 public Artifact createArtifact( final StorageAsset artifactPath, final ItemSelector selector,
372 final String classifier )
374 Version version = getVersion( selector );
375 ArtifactOptBuilder builder = org.apache.archiva.repository.content.base.ArchivaArtifact.withAsset( artifactPath )
376 .withVersion( version )
377 .withId( selector.getArtifactId( ) )
378 .withArtifactVersion( mavenContentHelper.getArtifactVersion( artifactPath, selector ) )
379 .withClassifier( classifier );
380 if ( selector.hasType( ) )
382 builder.withType( selector.getType( ) );
384 return builder.build( );
387 public Namespace getNamespaceFromArtifactPath( final StorageAsset artifactPath ) throws LayoutException
389 if (artifactPath == null) {
390 throw new LayoutException( "Path null is not valid for artifact" );
392 final StorageAsset namespacePath = artifactPath.getParent( ).getParent( ).getParent( );
393 return getNamespaceFromPath( namespacePath );
396 public Namespace getNamespaceFromPath( final StorageAsset nsPath ) throws LayoutException
398 if (nsPath == null) {
399 throw new LayoutException( "Path null is not valid for namespace" );
405 item = itemMap.computeIfAbsent( nsPath,
406 path -> createNamespaceFromPath( nsPath ) );
408 catch ( LayoutRuntimeException e )
410 throw new LayoutException( e.getMessage( ), e.getCause() );
412 if (!item.hasCharacteristic( Namespace.class )) {
413 item.setCharacteristic( Namespace.class, createNamespaceFromPath( nsPath ) );
415 return item.adapt( Namespace.class );
418 public Namespace createNamespaceFromPath( final StorageAsset namespacePath) throws LayoutRuntimeException
420 if (namespacePath == null) {
421 throw new LayoutRuntimeException( "Path null is not valid for namespace" );
423 final String namespace = MavenContentHelper.getNamespaceFromNamespacePath( namespacePath );
424 return ArchivaNamespace.withRepository( this )
425 .withAsset( namespacePath )
426 .withNamespace( namespace )
430 private Project getProjectFromPath( final StorageAsset path ) throws LayoutException
433 throw new LayoutException( "Path null is not valid for project" );
438 item = itemMap.computeIfAbsent( path, this::createProjectFromPath );
440 catch ( LayoutRuntimeException e )
442 throw new LayoutException( e.getMessage( ), e.getCause( ) );
444 if (!item.hasCharacteristic( Project.class )) {
445 item.setCharacteristic( Project.class, createProjectFromPath( path ) );
447 return item.adapt( Project.class );
450 private Project createProjectFromPath( final StorageAsset projectPath ) throws LayoutRuntimeException
452 if (projectPath==null) {
453 throw new LayoutRuntimeException( "Path null is not valid for project" );
458 namespace = getNamespaceFromPath( projectPath.getParent( ) );
460 catch ( LayoutException e )
462 throw new LayoutRuntimeException( e.getMessage( ), e.getCause() );
464 return ArchivaProject.withRepository( this ).withAsset( projectPath )
465 .withNamespace( namespace )
466 .withId( projectPath.getName( ) ).build( );
469 private Project getProjectFromArtifactPath( final StorageAsset artifactPath ) throws LayoutException
471 if (artifactPath == null) {
472 throw new LayoutException( "Path null is not valid for artifact" );
474 final StorageAsset projectPath = artifactPath.getParent( ).getParent( );
475 return getProjectFromPath( projectPath );
478 private Version getVersionFromArtifactPath( final StorageAsset artifactPath ) throws LayoutException
480 if (artifactPath==null) {
481 throw new LayoutException( "Path null is not valid for version" );
483 final StorageAsset versionPath = artifactPath.getParent( );
484 return getVersionFromPath( versionPath );
487 private Version getVersionFromPath( StorageAsset path ) throws LayoutException
490 throw new LayoutException( "Path null is not valid for version" );
495 item = itemMap.computeIfAbsent( path, this::createVersionFromPath );
497 catch ( LayoutRuntimeException e )
499 throw new LayoutException( e.getMessage( ), e.getCause( ) );
501 if (!item.hasCharacteristic( Version.class )) {
502 item.setCharacteristic( Version.class, createVersionFromPath( path ) );
504 return item.adapt( Version.class );
507 private Version createVersionFromPath(StorageAsset path) throws LayoutRuntimeException
510 throw new LayoutRuntimeException( "Path null is not valid for version" );
515 proj = getProjectFromPath( path.getParent( ) );
517 catch ( LayoutException e )
519 throw new LayoutRuntimeException( e.getMessage( ), e );
521 return ArchivaVersion.withRepository( this ).withAsset( path )
522 .withProject( proj ).withVersion(path.getName()).build();
525 private Optional<Artifact> getOptionalArtifactFromPath( final StorageAsset artifactPath) {
528 return Optional.of( getArtifactFromPath( artifactPath ) );
530 catch ( LayoutException e )
532 log.error( "Could not get artifact from path {}", artifactPath.getPath( ) );
533 return Optional.empty( );
537 private Artifact getArtifactFromPath( final StorageAsset artifactPath ) throws LayoutException
539 if (artifactPath==null) {
540 throw new LayoutException( "Path null is not valid for artifact" );
545 item = dataItemMap.computeIfAbsent( artifactPath, this::createArtifactFromPath );
547 catch ( LayoutRuntimeException e )
549 throw new LayoutException( e.getMessage( ), e.getCause() );
551 if (!item.hasCharacteristic( Artifact.class )) {
552 item.setCharacteristic( Artifact.class, createArtifactFromPath( artifactPath ) );
554 return item.adapt( Artifact.class );
557 private Artifact createArtifactFromPath( final StorageAsset artifactPath ) throws LayoutRuntimeException
559 if (artifactPath==null) {
560 throw new LayoutRuntimeException( "Path null is not valid for artifact" );
562 final Version version;
565 version = getVersionFromArtifactPath( artifactPath );
567 catch ( LayoutException e )
569 throw new LayoutRuntimeException( e.getMessage( ), e );
571 final ArtifactInfo info = getArtifactInfoFromPath( version.getId( ), artifactPath );
572 return org.apache.archiva.repository.content.base.ArchivaArtifact.withAsset( artifactPath )
573 .withVersion( version )
575 .withClassifier( info.classifier )
576 .withRemainder( info.remainder )
577 .withType( info.type )
578 .withArtifactVersion( info.version )
579 .withContentType( info.contentType )
580 .withArtifactType( info.artifactType )
584 private String getContentType(StorageAsset artifactPath) {
587 return Files.probeContentType( artifactPath.getFilePath( ) );
590 catch ( IOException e )
596 private DataItem getDataItemFromPath( final StorageAsset artifactPath )
598 final String contentType = getContentType( artifactPath );
599 return dataItemMap.computeIfAbsent( artifactPath, myArtifactPath ->
600 org.apache.archiva.repository.content.base.ArchivaDataItem.withAsset( artifactPath )
601 .withId( artifactPath.getName( ) )
602 .withContentType( contentType )
608 private ContentItem getItemFromPath( final StorageAsset itemPath )
610 if ( itemPath.isLeaf( ) )
612 if (dataItemMap.containsKey( itemPath )) {
613 return dataItemMap.get( itemPath );
615 return getDataItemFromPath( itemPath );
619 if (itemMap.containsKey( itemPath )) {
620 return itemMap.get( itemPath );
622 return ArchivaContentItem.withRepository( this ).withAsset( itemPath ).build();
628 public ManagedRepositoryContent getGenericContent( )
633 // Simple object to hold artifact information
634 private static class ArtifactInfo
637 private String version;
638 private String extension;
639 private String remainder;
641 private String classifier;
642 private String contentType;
643 private StorageAsset asset;
644 private ArtifactType artifactType = BaseArtifactTypes.MAIN;
647 private ArtifactInfo getArtifactInfoFromPath( String genericVersion, StorageAsset path )
649 final ArtifactInfo info = new ArtifactInfo( );
651 info.id = path.getParent( ).getParent( ).getName( );
652 final String fileName = path.getName( );
653 if ( genericVersion.endsWith( "-" + SNAPSHOT ) )
655 String baseVersion = StringUtils.substringBeforeLast( genericVersion, "-" + SNAPSHOT );
656 String prefix = info.id + "-" + baseVersion + "-";
657 if ( fileName.startsWith( prefix ) )
659 String versionPostfix = StringUtils.removeStart( fileName, prefix );
660 Matcher matcher = UNIQUE_SNAPSHOT_PATTERN.matcher( versionPostfix );
661 if ( matcher.matches( ) )
663 info.version = baseVersion + "-" + matcher.group( 1 );
664 String newPrefix = info.id + "-" + info.version;
665 if ( fileName.startsWith( newPrefix ) )
667 String classPostfix = StringUtils.removeStart( fileName, newPrefix );
668 Matcher cMatch = CLASSIFIER_PATTERN.matcher( classPostfix );
669 if ( cMatch.matches( ) )
671 info.classifier = cMatch.group( 1 );
672 info.remainder = cMatch.group( 2 );
676 info.classifier = "";
677 info.remainder = classPostfix;
682 log.debug( "Artifact does not match the maven name pattern {}", path );
683 info.artifactType = BaseArtifactTypes.UNKNOWN;
684 info.classifier = "";
685 info.remainder = StringUtils.substringAfter( fileName, prefix );
690 log.debug( "Artifact does not match the snapshot version pattern {}", path );
692 info.artifactType = BaseArtifactTypes.UNKNOWN;
693 // This is just a guess. No guarantee to the get a usable version.
694 info.version = StringUtils.removeStart( fileName, info.id + '-' );
695 String postfix = StringUtils.substringAfterLast( info.version, "." ).toLowerCase( );
696 while ( COMMON_EXTENSIONS.matcher( postfix ).matches( ) )
698 info.version = StringUtils.substringBeforeLast( info.version, "." );
699 postfix = StringUtils.substringAfterLast( info.version, "." ).toLowerCase( );
701 info.classifier = "";
702 info.remainder = StringUtils.substringAfter( fileName, prefix );
707 log.debug( "Artifact does not match the maven name pattern: {}", path );
708 if ( fileName.contains( "-" + baseVersion ) )
710 info.id = StringUtils.substringBefore( fileName, "-" + baseVersion );
716 info.artifactType = BaseArtifactTypes.UNKNOWN;
718 info.classifier = "";
719 info.remainder = StringUtils.substringAfterLast( fileName, "." );
724 String prefix = info.id + "-" + genericVersion;
725 if ( fileName.startsWith( prefix ) )
727 info.version = genericVersion;
728 String classPostfix = StringUtils.removeStart( fileName, prefix );
729 Matcher cMatch = CLASSIFIER_PATTERN.matcher( classPostfix );
730 if ( cMatch.matches( ) )
732 info.classifier = cMatch.group( 1 );
733 info.remainder = cMatch.group( 2 );
737 info.classifier = "";
738 info.remainder = classPostfix;
743 if ( fileName.contains( "-" + genericVersion ) )
745 info.id = StringUtils.substringBefore( fileName, "-" + genericVersion );
751 log.debug( "Artifact does not match the version pattern {}", path );
752 info.artifactType = BaseArtifactTypes.UNKNOWN;
754 info.classifier = "";
755 info.remainder = StringUtils.substringAfterLast( fileName, "." );
758 info.extension = StringUtils.substringAfterLast( fileName, "." );
759 info.type = MavenContentHelper.getTypeFromClassifierAndExtension( info.classifier, info.extension );
762 info.contentType = Files.probeContentType( path.getFilePath( ) );
764 catch ( IOException e )
766 info.contentType = "";
769 if ( MavenContentHelper.METADATA_FILENAME.equalsIgnoreCase( fileName ) )
771 info.artifactType = BaseArtifactTypes.METADATA;
773 else if ( MavenContentHelper.METADATA_REPOSITORY_FILENAME.equalsIgnoreCase( fileName ) )
775 info.artifactType = MavenTypes.REPOSITORY_METADATA;
777 else if ( StringUtils.isNotEmpty( info.remainder ) && StringUtils.countMatches( info.remainder, "." ) >= 2 )
779 String mainFile = StringUtils.substringBeforeLast( fileName, "." );
780 if ( path.getParent( ).resolve( mainFile ).exists( ) )
782 info.artifactType = BaseArtifactTypes.RELATED;
790 public Artifact getArtifact( final ItemSelector selector ) throws ContentAccessException
792 if ( !selector.hasProjectId( ) )
794 throw new IllegalArgumentException( "Project id must be set" );
796 if ( !selector.hasVersion( ) )
798 throw new IllegalArgumentException( "Version must be set" );
800 if ( !selector.hasArtifactId( ) )
802 throw new IllegalArgumentException( "Artifact id must be set" );
804 final StorageAsset artifactDir = getAsset( selector.getNamespace( ), selector.getProjectId( ),
805 selector.getVersion( ) );
806 final String artifactVersion = mavenContentHelper.getArtifactVersion( artifactDir, selector );
807 final String classifier = MavenContentHelper.getClassifier( selector );
808 final String extension = MavenContentHelper.getArtifactExtension( selector );
809 final String artifactId = StringUtils.isEmpty( selector.getArtifactId( ) ) ? selector.getProjectId( ) : selector.getArtifactId( );
810 final String fileName = MavenContentHelper.getArtifactFileName( artifactId, artifactVersion, classifier, extension );
811 final StorageAsset path = getAsset( selector.getNamespace( ), selector.getProjectId( ),
812 selector.getVersion( ), fileName );
815 return getArtifactFromPath( path );
817 catch ( LayoutException e )
819 throw new IllegalArgumentException( "The selector is not valid " + e.getMessage( ), e );
824 public Artifact getArtifact( String path ) throws LayoutException, ContentAccessException
826 StorageAsset asset = getAssetByPath( path );
827 return getArtifactFromPath( asset );
831 * Returns all the subdirectories of the given namespace directory as project.
834 public List<? extends Project> getProjects( Namespace namespace )
836 return namespace.getAsset( ).list( ).stream( )
837 .filter( StorageAsset::isContainer )
841 return getProjectFromPath( a );
843 catch ( LayoutException e )
845 log.error( "Not a valid project path " + a.getPath( ), e );
849 .filter( Objects::nonNull )
850 .collect( Collectors.toList( ) );
854 public List<? extends Project> getProjects( ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
856 return getProjects( getNamespace( selector ) );
860 * Returns a version object for each directory that is a direct child of the project directory.
862 * @param project the project for which the versions should be returned
863 * @return the list of versions or a empty list, if not version was found
866 public List<? extends Version> getVersions( final Project project )
868 StorageAsset asset = getAsset( project.getNamespace( ).getId( ), project.getId( ) );
869 return asset.list( ).stream( ).filter( StorageAsset::isContainer )
870 .map( a -> ArchivaVersion.withAsset( a )
871 .withProject( project )
872 .withVersion( a.getName( ) ).build( ) )
873 .collect( Collectors.toList( ) );
877 * Returns the versions that can be found for the given selector.
879 * @param selector the item selector. At least namespace and projectId must be set.
880 * @return the list of version objects or a empty list, if the selector does not match a version
881 * @throws ContentAccessException if the access to the underlying backend failed
882 * @throws IllegalArgumentException if the selector has no projectId specified
885 public List<? extends Version> getVersions( final ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
887 if ( !selector.hasProjectId( ) )
889 log.error( "Bad item selector for version list: {}", selector );
890 throw new IllegalArgumentException( "Project id not set, while retrieving versions." );
892 final Project project = getProject( selector );
893 if ( selector.hasVersion( ) )
895 final StorageAsset asset = getAsset( selector.getNamespace( ), selector.getProjectId( ), selector.getVersion( ) );
896 return asset.list( ).stream( ).map( a -> getArtifactInfoFromPath( selector.getVersion( ), a ) )
897 .filter( ai -> StringUtils.isNotEmpty( ai.version ) )
901 return getVersionFromArtifactPath( v.asset );
903 catch ( LayoutException e )
905 log.error( "Could not get version from asset " + v.asset.getPath( ) );
909 .filter( Objects::nonNull )
911 .collect( Collectors.toList( ) );
915 return getVersions( project );
919 public List<String> getArtifactVersions( final ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
921 if ( !selector.hasProjectId( ) )
923 log.error( "Bad item selector for version list: {}", selector );
924 throw new IllegalArgumentException( "Project id not set, while retrieving versions." );
926 final Project project = getProject( selector );
927 if ( selector.hasVersion( ) )
929 final StorageAsset asset = getAsset( selector.getNamespace( ), selector.getProjectId( ), selector.getVersion( ) );
930 return asset.list( ).stream( ).map( a -> getArtifactInfoFromPath( selector.getVersion( ), a ) )
931 .filter( ai -> StringUtils.isNotEmpty( ai.version ) )
932 .map( v -> v.version )
934 .collect( Collectors.toList( ) );
938 return project.getAsset( ).list( ).stream( ).map( a -> {
941 return getVersionFromPath( a );
943 catch ( LayoutException e )
945 log.error( "Could not get version from path " + a.getPath( ) );
948 } ).filter( Objects::nonNull )
949 .flatMap( v -> v.getAsset( ).list( ).stream( ).map( a -> getArtifactInfoFromPath( v.getId( ), a ) ) )
950 .filter( ai -> StringUtils.isNotEmpty( ai.version ) )
951 .map( v -> v.version )
953 .collect( Collectors.toList( ) );
959 * See {@link #newArtifactStream(ItemSelector)}. This method collects the stream into a list.
961 * @param selector the selector for the artifacts
962 * @return the list of artifacts
963 * @throws ContentAccessException if the access to the underlying filesystem failed
966 public List<? extends Artifact> getArtifacts( ItemSelector selector ) throws ContentAccessException
968 try ( Stream<? extends Artifact> stream = newArtifactStream( selector ) )
970 return stream.collect( Collectors.toList( ) );
976 * File filter to select certain artifacts using the selector data.
978 private Predicate<StorageAsset> getArtifactFileFilterFromSelector( final ItemSelector selector )
980 Predicate<StorageAsset> p = StorageAsset::isLeaf;
981 StringBuilder fileNamePattern = new StringBuilder( "^" );
982 if ( selector.hasArtifactId( ) )
984 fileNamePattern.append( Pattern.quote( selector.getArtifactId( ) ) ).append( "-" );
988 fileNamePattern.append( "[A-Za-z0-9_\\-.]+-" );
990 if ( selector.hasArtifactVersion( ) )
992 if ( selector.getArtifactVersion( ).contains( "*" ) )
994 String[] tokens = StringUtils.splitByWholeSeparator( selector.getArtifactVersion( ), "*" );
995 for ( String currentToken : tokens )
997 if ( !currentToken.equals( "" ) )
999 fileNamePattern.append( Pattern.quote( currentToken ) );
1001 fileNamePattern.append( "[A-Za-z0-9_\\-.]*" );
1006 fileNamePattern.append( Pattern.quote( selector.getArtifactVersion( ) ) );
1011 fileNamePattern.append( "[A-Za-z0-9_\\-.]+" );
1013 String classifier = selector.hasClassifier( ) ? selector.getClassifier( ) :
1014 ( selector.hasType( ) ? MavenContentHelper.getClassifierFromType( selector.getType( ) ) : null );
1015 if ( classifier != null )
1017 if ( "*".equals( classifier ) )
1019 fileNamePattern.append( "(-[A-Za-z0-9]+)?\\." );
1023 fileNamePattern.append( "-" ).append( Pattern.quote( classifier ) ).append( "\\." );
1028 fileNamePattern.append( "\\." );
1030 String extension = selector.hasExtension( ) ? selector.getExtension( ) :
1031 ( selector.hasType( ) ? MavenContentHelper.getArtifactExtension( selector ) : null );
1032 if ( extension != null )
1034 if ( selector.includeRelatedArtifacts( ) )
1036 fileNamePattern.append( Pattern.quote( extension ) ).append( "(\\.[A-Za-z0-9]+)?" );
1040 fileNamePattern.append( Pattern.quote( extension ) );
1045 fileNamePattern.append( "[A-Za-z0-9.]+" );
1047 final Pattern pattern = Pattern.compile( fileNamePattern.toString( ) );
1048 return p.and( a -> pattern.matcher( a.getName( ) ).matches( ) );
1053 * Returns the artifacts. The number of artifacts returned depend on the selector.
1054 * If the selector sets the flag {@link ItemSelector#includeRelatedArtifacts()} to <code>true</code>,
1055 * additional to the matching artifacts, related artifacts like hash values or signatures are included in the artifact
1057 * If the selector sets the flag {@link ItemSelector#recurse()} to <code>true</code>, artifacts of the given
1058 * namespace and from all sub namespaces that start with the given namespace are returned.
1060 * <li>If only a namespace is given, all artifacts with the given namespace or starting with the given
1061 * namespace (see {@link ItemSelector#recurse()} are returned.</li>
1062 * <li>If a namespace and a project id, or artifact id is given, the artifacts of all versions of the given
1063 * namespace and project are returned.</li>
1064 * <li>If a namespace and a project id or artifact id and a version is given, the artifacts of the given
1065 * version are returned</li>
1066 * <li>If no artifact version or artifact id is given, it will return all "artifacts" found in the directory.
1067 * To select only artifacts that match the layout you should add the artifact id and artifact version
1068 * (can contain a '*' pattern).</li>
1071 * The '*' pattern can be used in classifiers and artifact versions and match zero or more characters.
1073 * There is no determinate order of the elements in the stream.
1075 * Returned streams are auto closable and should be used in a try-with-resources statement.
1077 * @param selector the item selector
1078 * @throws ContentAccessException if the access to the underlying filesystem failed
1081 public Stream<? extends Artifact> newArtifactStream( ItemSelector selector ) throws ContentAccessException
1083 String projectId = selector.hasProjectId( ) ? selector.getProjectId( ) : ( selector.hasArtifactId( ) ? selector.getArtifactId( )
1085 final Predicate<StorageAsset> filter = getArtifactFileFilterFromSelector( selector );
1086 if ( projectId != null && selector.hasVersion( ) )
1088 return getAsset( selector.getNamespace( ), projectId, selector.getVersion( ) )
1089 .list( ).stream( ).filter( filter )
1090 .map( this::getOptionalArtifactFromPath )
1091 .filter( Optional::isPresent ).map( Optional::get );
1093 else if ( projectId != null )
1095 final StorageAsset projDir = getAsset( selector.getNamespace( ), projectId );
1096 return projDir.list( ).stream( )
1097 .map( a -> a.isContainer( ) ? a.list( ) : Collections.singletonList( a ) )
1098 .flatMap( List::stream )
1100 .map( this::getOptionalArtifactFromPath )
1101 .filter( Optional::isPresent ).map( Optional::get );
1105 StorageAsset namespaceDir = getAsset( selector.getNamespace( ) );
1106 if ( selector.recurse( ) )
1108 return StorageUtil.newAssetStream( namespaceDir, true )
1110 .map( this::getOptionalArtifactFromPath )
1111 .filter( Optional::isPresent ).map( Optional::get );
1115 // We descend into 2 subdirectories (project and version)
1116 return namespaceDir.list( ).stream( )
1117 .map( a -> a.isContainer( ) ? a.list( ) : Collections.singletonList( a ) )
1118 .flatMap( List::stream )
1119 .map( a -> a.isContainer( ) ? a.list( ) : Collections.singletonList( a ) )
1120 .flatMap( List::stream )
1122 .map( this::getOptionalArtifactFromPath )
1123 .filter( Optional::isPresent ).map( Optional::get );
1129 * Same as {@link #newArtifactStream(ContentItem)} but returns the collected stream as list.
1131 * @param item the item the parent item
1132 * @return the list of artifacts or a empty list of no artifacts where found
1135 public List<? extends Artifact> getArtifacts( ContentItem item )
1137 try ( Stream<? extends Artifact> stream = newArtifactStream( item ) )
1139 return stream.collect( Collectors.toList( ) );
1144 * Returns all artifacts
1146 * @param item the namespace to search for artifacts
1147 * @return the stream of artifacts
1148 * @throws ContentAccessException if the access to the underlying storage failed
1150 public Stream<? extends Artifact> newArtifactStream( Namespace item ) throws ContentAccessException
1152 return newArtifactStream( ArchivaItemSelector.builder( ).withNamespace( item.getId( ) ).build( ) );
1155 public Stream<? extends Artifact> newArtifactStream( Project item ) throws ContentAccessException
1157 return newArtifactStream( ArchivaItemSelector.builder( ).withNamespace( item.getNamespace( ).getId( ) )
1158 .withProjectId( item.getId( ) ).build( ) );
1161 public Stream<? extends Artifact> newArtifactStream( Version item ) throws ContentAccessException
1163 return newArtifactStream( ArchivaItemSelector.builder( ).withNamespace( item.getProject( ).getNamespace( ).getId( ) )
1164 .withProjectId( item.getProject( ).getId( ) )
1165 .withVersion( item.getId( ) ).build( ) );
1169 * Returns all related artifacts that match the given artifact. That means all artifacts that have
1170 * the same filename plus an additional extension, e.g. ${fileName}.sha2
1172 * @param item the artifact
1173 * @return the stream of artifacts
1174 * @throws ContentAccessException if access to the underlying storage failed
1176 public Stream<? extends Artifact> newArtifactStream( Artifact item ) throws ContentAccessException
1178 final Version v = item.getVersion( );
1179 final String fileName = item.getFileName( );
1180 final Predicate<StorageAsset> filter = ( StorageAsset a ) ->
1181 a.getName( ).startsWith( fileName + "." );
1182 return v.getAsset( ).list( ).stream( ).filter( filter )
1186 return getArtifactFromPath( a );
1188 catch ( LayoutException e )
1190 log.error( "Not a valid artifact path " + a.getPath( ), e );
1193 } ).filter( Objects::nonNull );
1197 * Returns the stream of artifacts that are children of the given item.
1199 * @param item the item from where the artifacts should be returned
1200 * @return the stream of artifacts
1201 * @throws ContentAccessException if access to the underlying storage failed
1204 public Stream<? extends Artifact> newArtifactStream( ContentItem item ) throws ContentAccessException
1206 if ( item instanceof Namespace )
1208 return newArtifactStream( ( (Namespace) item ) );
1210 else if ( item instanceof Project )
1212 return newArtifactStream( (Project) item );
1214 else if ( item instanceof Version )
1216 return newArtifactStream( (Version) item );
1218 else if ( item instanceof Artifact )
1220 return newArtifactStream( (Artifact) item );
1224 log.warn( "newArtifactStream for unsupported item requested: {}", item.getClass( ).getName( ) );
1225 return Stream.empty( );
1229 private void appendPatternRegex( StringBuilder builder, String name )
1231 String[] patternArray = name.split( "[*]" );
1232 for ( int i = 0; i < patternArray.length - 1; i++ )
1234 builder.append( Pattern.quote( patternArray[i] ) )
1235 .append( "[A-Za-z0-9_\\-]*" );
1237 builder.append( Pattern.quote( patternArray[patternArray.length - 1] ) );
1240 Predicate<StorageAsset> getItemFileFilterFromSelector( ItemSelector selector )
1242 if ( !selector.hasNamespace( ) && !selector.hasProjectId( ) )
1244 throw new IllegalArgumentException( "Selector must have at least namespace and projectid" );
1246 StringBuilder pathMatcher = new StringBuilder( "^" );
1247 if ( selector.hasNamespace( ) )
1249 String path = "/" + String.join( "/", selector.getNamespace( ).split( "\\." ) );
1250 if ( path.contains( "*" ) )
1252 appendPatternRegex( pathMatcher, path );
1256 pathMatcher.append( Pattern.quote( path ) );
1260 if ( selector.hasProjectId( ) )
1262 pathMatcher.append( "/" );
1263 if ( selector.getProjectId( ).contains( "*" ) )
1265 appendPatternRegex( pathMatcher, selector.getProjectId( ) );
1269 pathMatcher.append( Pattern.quote( selector.getProjectId( ) ) );
1272 if ( selector.hasVersion( ) )
1274 pathMatcher.append( "/" );
1275 if ( selector.getVersion( ).contains( "*" ) )
1277 appendPatternRegex( pathMatcher, selector.getVersion( ) );
1281 pathMatcher.append( Pattern.quote( selector.getVersion( ) ) );
1284 pathMatcher.append( ".*" );
1285 final Pattern pathPattern = Pattern.compile( pathMatcher.toString( ) );
1286 final Predicate<StorageAsset> pathPredicate = ( StorageAsset asset ) -> pathPattern.matcher( asset.getPath( ) ).matches( );
1287 if ( selector.hasArtifactId( ) || selector.hasArtifactVersion( ) || selector.hasClassifier( )
1288 || selector.hasType( ) || selector.hasExtension( ) )
1290 return getArtifactFileFilterFromSelector( selector ).and( pathPredicate );
1294 return pathPredicate;
1299 * Returns a concatenation of the asset and its children as stream, if they exist.
1300 * It descends <code>level+1</code> levels down.
1302 * @param a the asset to start from
1303 * @param level the number of child levels to descend. 0 means only the children of the given asset, 1 means the children of childrens of the given asset, ...
1304 * @return the stream of storage assets
1306 private Stream<StorageAsset> getChildrenDF( StorageAsset a, int level )
1308 if ( a.isContainer( ) )
1311 return Stream.concat( a.list().stream( ).flatMap( ch -> getChildrenDF( ch, level - 1 ) ), Stream.of( a ) );
1314 return Stream.concat( a.list( ).stream( ), Stream.of( a ) );
1319 return Stream.of( a );
1324 public Stream<? extends ContentItem> newItemStream( ItemSelector selector, boolean parallel ) throws ContentAccessException, IllegalArgumentException
1326 final Predicate<StorageAsset> filter = getItemFileFilterFromSelector( selector );
1327 StorageAsset startDir;
1328 if (selector.getNamespace().contains("*")) {
1329 startDir = getAsset("");
1330 } else if ( selector.hasProjectId( ) && selector.getProjectId().contains("*") )
1332 startDir = getAsset( selector.getNamespace( ) );
1333 } else if ( selector.hasProjectId() && selector.hasVersion() && selector.getVersion().contains("*")) {
1334 startDir = getAsset( selector.getNamespace( ), selector.getProjectId( ) );
1336 else if ( selector.hasProjectId( ) && selector.hasVersion( ) )
1338 startDir = getAsset( selector.getNamespace( ), selector.getProjectId( ), selector.getVersion() );
1340 else if ( selector.hasProjectId( ) )
1342 startDir = getAsset( selector.getNamespace( ), selector.getProjectId( ) );
1346 startDir = getAsset( selector.getNamespace( ) );
1347 if ( !selector.recurse( ) )
1349 // We descend into 2 subdirectories (project and version)
1350 return startDir.list( ).stream( )
1351 .flatMap( a -> getChildrenDF( a, 1 ) )
1352 .map( this::getItemFromPath );
1355 return StorageUtil.newAssetStream( startDir, parallel )
1357 .map( this::getItemFromPath );
1362 * Checks, if the asset/file queried by the given selector exists.
1365 public boolean hasContent( ItemSelector selector )
1367 return getItem( selector ).getAsset( ).exists( );
1371 public ContentItem getParent( ContentItem item )
1373 return getItemFromPath( item.getAsset( ).getParent( ) );
1377 public List<? extends ContentItem> getChildren( ContentItem item )
1379 if (item.getAsset().isLeaf()) {
1380 return Collections.emptyList( );
1382 return item.getAsset( ).list( ).stream( ).map( this::getItemFromPath ).collect( Collectors.toList( ) );
1387 public <T extends ContentItem> T applyCharacteristic( Class<T> clazz, ContentItem item ) throws LayoutException
1389 if (item.getAsset().isLeaf()) {
1390 if (clazz.isAssignableFrom( Artifact.class )) {
1391 Artifact artifact = getArtifactFromPath( item.getAsset( ) );
1392 item.setCharacteristic( Artifact.class, artifact );
1393 return (T) artifact;
1395 throw new LayoutException( "Could not adapt file to clazz " + clazz );
1398 if (clazz.isAssignableFrom( Version.class )) {
1399 Version version = getVersionFromPath( item.getAsset( ) );
1400 item.setCharacteristic( Version.class, version );
1402 } else if (clazz.isAssignableFrom( Project.class )) {
1403 Project project = getProjectFromPath( item.getAsset( ) );
1404 item.setCharacteristic( Project.class, project );
1406 } else if (clazz.isAssignableFrom( Namespace.class )) {
1407 Namespace ns = getNamespaceFromPath( item.getAsset( ) );
1408 item.setCharacteristic( Namespace.class, ns );
1411 throw new LayoutException( "Cannot adapt directory to clazz " + clazz );
1417 public <T extends ManagedRepositoryContentLayout> T getLayout( Class<T> clazz ) throws LayoutException
1419 if (clazz.isAssignableFrom( this.getClass() )) {
1422 throw new LayoutException( "Cannot convert to layout " + clazz );
1427 public <T extends ManagedRepositoryContentLayout> boolean supportsLayout( Class<T> clazz )
1429 return clazz.isAssignableFrom( this.getClass( ) );
1433 * Moves the file to the artifact destination
1436 public void addArtifact( Path sourceFile, Artifact destination ) throws IllegalArgumentException, ContentAccessException
1440 StorageAsset asset = destination.getAsset( );
1441 if ( !asset.exists( ) )
1445 asset.replaceDataFromFile( sourceFile );
1447 catch ( IOException e )
1449 log.error( "Could not push data to asset source={} destination={}. {}", sourceFile, destination.getAsset( ).getFilePath( ), e.getMessage( ) );
1450 throw new ContentAccessException( e.getMessage( ), e );
1455 public ContentItem toItem( String path ) throws LayoutException
1457 StorageAsset asset = getRepository( ).getAsset( path );
1458 if ( asset.isLeaf( ) )
1460 ItemSelector selector = getPathParser( ).toItemSelector( path );
1461 return getItem( selector );
1465 return getItemFromPath( asset );
1470 public ContentItem toItem( StorageAsset assetPath ) throws LayoutException
1472 return toItem( assetPath.getPath( ) );
1475 /// ************* End of new generation interface ******************
1478 public String toPath( ContentItem item ) {
1479 return item.getAsset( ).getPath( );
1483 public DataItem getMetadataItem( Version version ) {
1484 StorageAsset metaPath = version.getAsset( ).resolve( MAVEN_METADATA );
1485 return getDataItemFromPath( metaPath );
1489 public DataItem getMetadataItem( Project project )
1491 StorageAsset metaPath = project.getAsset( ).resolve( MAVEN_METADATA );
1492 return getDataItemFromPath( metaPath );
1497 public String getId( )
1499 return repository.getId( );
1503 * Create the filter for various combinations of classifier and type
1505 private Predicate<ArtifactReference> getChecker( ArtifactReference referenceObject, String extension )
1507 // TODO: Check, if extension is the correct parameter here
1508 // We compare type with extension which works for artifacts like .jar.md5 but may
1509 // be not the best way.
1511 if ( referenceObject.getClassifier( ) != null && referenceObject.getType( ) != null )
1513 return ( ( ArtifactReference a ) ->
1514 referenceObject.getGroupId( ).equals( a.getGroupId( ) )
1515 && referenceObject.getArtifactId( ).equals( a.getArtifactId( ) )
1516 && referenceObject.getVersion( ).equals( a.getVersion( ) )
1517 && ( ( a.getType( ) == null )
1518 || referenceObject.getType( ).equals( a.getType( ) )
1519 || a.getType( ).startsWith( extension ) )
1520 && referenceObject.getClassifier( ).equals( a.getClassifier( ) )
1523 else if ( referenceObject.getClassifier( ) != null && referenceObject.getType( ) == null )
1525 return ( ( ArtifactReference a ) ->
1526 referenceObject.getGroupId( ).equals( a.getGroupId( ) )
1527 && referenceObject.getArtifactId( ).equals( a.getArtifactId( ) )
1528 && referenceObject.getVersion( ).equals( a.getVersion( ) )
1529 && referenceObject.getClassifier( ).equals( a.getClassifier( ) )
1532 else if ( referenceObject.getClassifier( ) == null && referenceObject.getType( ) != null )
1534 return ( ( ArtifactReference a ) ->
1535 referenceObject.getGroupId( ).equals( a.getGroupId( ) )
1536 && referenceObject.getArtifactId( ).equals( a.getArtifactId( ) )
1537 && referenceObject.getVersion( ).equals( a.getVersion( ) )
1538 && ( ( a.getType( ) == null )
1539 || referenceObject.getType( ).equals( a.getType( ) )
1540 || a.getType( ).startsWith( extension ) )
1545 return ( ( ArtifactReference a ) ->
1546 referenceObject.getGroupId( ).equals( a.getGroupId( ) )
1547 && referenceObject.getArtifactId( ).equals( a.getArtifactId( ) )
1548 && referenceObject.getVersion( ).equals( a.getVersion( ) )
1555 private String convertUriToPath( URI uri )
1557 if ( uri.getScheme( ) == null )
1559 return Paths.get( uri.getPath( ) ).toString( );
1561 else if ( "file".equals( uri.getScheme( ) ) )
1563 return Paths.get( uri ).toString( );
1567 return uri.toString( );
1572 public ManagedRepository getRepository( )
1578 public void setRepository( final ManagedRepository repo )
1580 this.repository = repo;
1583 if ( repository instanceof EditableManagedRepository )
1585 ( (EditableManagedRepository) repository ).setContent( this );
1590 private Path getRepoDir( )
1592 return repository.getRoot().getFilePath( );
1595 private RepositoryStorage getStorage( )
1597 return repository.getRoot().getStorage( );
1601 * Convert a path to an artifact reference.
1603 * @param path the path to convert. (relative or full location path)
1604 * @throws LayoutException if the path cannot be converted to an artifact reference.
1607 public ArtifactReference toArtifactReference( String path )
1608 throws LayoutException
1610 String repoPath = convertUriToPath( repository.getLocation( ) );
1611 if ( ( path != null ) && path.startsWith( repoPath ) && repoPath.length( ) > 0 )
1613 return super.toArtifactReference( path.substring( repoPath.length( ) + 1 ) );
1618 if ( repoPath != null )
1620 while ( repoPath.startsWith( "/" ) )
1622 repoPath = repoPath.substring( 1 );
1625 return super.toArtifactReference( repoPath );
1630 // The variant with runtime exception for stream usage
1631 private ArtifactReference toArtifactRef( String path )
1635 return toArtifactReference( path );
1637 catch ( LayoutException e )
1639 throw new RuntimeException( e );
1643 public void setFiletypes( FileTypes filetypes )
1645 this.filetypes = filetypes;
1648 public void setMavenContentHelper( MavenContentHelper contentHelper )
1650 this.mavenContentHelper = contentHelper;
1654 public MavenMetadataReader getMetadataReader( )
1656 return metadataReader;
1659 public void setMetadataReader( MavenMetadataReader metadataReader )
1661 this.metadataReader = metadataReader;