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.common.utils.VersionUtil;
24 import org.apache.archiva.configuration.FileTypes;
25 import org.apache.archiva.metadata.maven.MavenMetadataReader;
26 import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
27 import org.apache.archiva.model.ArtifactReference;
28 import org.apache.archiva.repository.BaseRepositoryContentLayout;
29 import org.apache.archiva.repository.ContentAccessException;
30 import org.apache.archiva.repository.EditableManagedRepository;
31 import org.apache.archiva.repository.ItemDeleteStatus;
32 import org.apache.archiva.repository.LayoutException;
33 import org.apache.archiva.repository.LayoutRuntimeException;
34 import org.apache.archiva.repository.ManagedRepository;
35 import org.apache.archiva.repository.ManagedRepositoryContent;
36 import org.apache.archiva.repository.ManagedRepositoryContentLayout;
37 import org.apache.archiva.repository.content.Artifact;
38 import org.apache.archiva.repository.content.ArtifactType;
39 import org.apache.archiva.repository.content.BaseArtifactTypes;
40 import org.apache.archiva.repository.content.ContentItem;
41 import org.apache.archiva.repository.content.DataItem;
42 import org.apache.archiva.repository.content.ItemNotFoundException;
43 import org.apache.archiva.repository.content.ItemSelector;
44 import org.apache.archiva.repository.content.Namespace;
45 import org.apache.archiva.repository.content.Project;
46 import org.apache.archiva.repository.content.Version;
47 import org.apache.archiva.repository.content.base.ArchivaContentItem;
48 import org.apache.archiva.repository.content.base.ArchivaItemSelector;
49 import org.apache.archiva.repository.content.base.ArchivaNamespace;
50 import org.apache.archiva.repository.content.base.ArchivaProject;
51 import org.apache.archiva.repository.content.base.ArchivaVersion;
52 import org.apache.archiva.repository.content.base.builder.ArtifactOptBuilder;
53 import org.apache.archiva.repository.maven.metadata.storage.ArtifactMappingProvider;
54 import org.apache.archiva.repository.maven.metadata.storage.DefaultArtifactMappingProvider;
55 import org.apache.archiva.repository.storage.RepositoryStorage;
56 import org.apache.archiva.repository.storage.StorageAsset;
57 import org.apache.archiva.repository.storage.util.StorageUtil;
58 import org.apache.commons.collections4.map.ReferenceMap;
59 import org.apache.commons.lang3.StringUtils;
61 import javax.inject.Inject;
62 import javax.inject.Named;
63 import java.io.IOException;
65 import java.nio.file.Files;
66 import java.nio.file.Path;
67 import java.nio.file.Paths;
68 import java.util.Arrays;
69 import java.util.Collections;
70 import java.util.List;
71 import java.util.Objects;
72 import java.util.Optional;
73 import java.util.function.Consumer;
74 import java.util.function.Predicate;
75 import java.util.regex.Matcher;
76 import java.util.regex.Pattern;
77 import java.util.stream.Collectors;
78 import java.util.stream.Stream;
81 * ManagedDefaultRepositoryContent
83 public class ManagedDefaultRepositoryContent
84 extends AbstractDefaultRepositoryContent
85 implements ManagedRepositoryContent, BaseRepositoryContentLayout
88 // attribute flag that marks version objects that point to a snapshot artifact version
89 public static final String SNAPSHOT_ARTIFACT_VERSION = "maven.snav";
91 private FileTypes filetypes;
93 public void setFileTypes( FileTypes fileTypes )
95 this.filetypes = fileTypes;
98 private ManagedRepository repository;
100 private FileLockManager lockManager;
103 @Named( "repositoryPathTranslator#maven2" )
104 private RepositoryPathTranslator pathTranslator;
107 @Named( "metadataReader#maven" )
108 MavenMetadataReader metadataReader;
111 @Named( "MavenContentHelper" )
112 MavenContentHelper mavenContentHelper;
114 public static final String SNAPSHOT = "SNAPSHOT";
116 public static final Pattern UNIQUE_SNAPSHOT_PATTERN = Pattern.compile( "^(SNAPSHOT|[0-9]{8}\\.[0-9]{6}-[0-9]+)(.*)" );
117 public static final Pattern CLASSIFIER_PATTERN = Pattern.compile( "^-([^.]+)(\\..*)" );
118 public static final Pattern COMMON_EXTENSIONS = Pattern.compile( "^(jar|war|ear|dar|tar|zip|pom|xml)$" );
120 public static final Pattern TIMESTAMP_PATTERN = Pattern.compile( "^([0-9]{8})\\.([0-9]{6})$" );
122 public static final Pattern GENERIC_SNAPSHOT_PATTERN = Pattern.compile( "^(.*)-" + SNAPSHOT );
124 private static final List<Class<? extends ManagedRepositoryContentLayout>> LAYOUTS = Arrays.asList( BaseRepositoryContentLayout.class );
127 * We are caching content items in a weak reference map. To avoid always recreating the
128 * the hierarchical structure.
129 * TODO: Better use a object cache? E.g. our spring cache implementation?
131 private ReferenceMap<StorageAsset, ContentItem> itemMap = new ReferenceMap<>( );
132 private ReferenceMap<StorageAsset, DataItem> dataItemMap = new ReferenceMap<>( );
134 public ManagedDefaultRepositoryContent( )
136 super( Collections.singletonList( new DefaultArtifactMappingProvider( ) ) );
139 public ManagedDefaultRepositoryContent( ManagedRepository repository, FileTypes fileTypes, FileLockManager lockManager )
141 super( Collections.singletonList( new DefaultArtifactMappingProvider( ) ) );
142 setFileTypes( fileTypes );
143 this.lockManager = lockManager;
144 setRepository( repository );
147 public ManagedDefaultRepositoryContent( ManagedRepository repository, List<? extends ArtifactMappingProvider> artifactMappingProviders, FileTypes fileTypes, FileLockManager lockManager )
149 super( artifactMappingProviders == null ? Collections.singletonList( new DefaultArtifactMappingProvider( ) ) : artifactMappingProviders );
150 setFileTypes( fileTypes );
151 this.lockManager = lockManager;
152 setRepository( repository );
156 private StorageAsset getAssetByPath( String assetPath )
158 return getStorage( ).getAsset( assetPath );
161 private StorageAsset getAsset( String namespace )
163 String namespacePath = formatAsDirectory( namespace.trim( ) );
164 if ( StringUtils.isEmpty( namespacePath ) )
168 return getAssetByPath( namespacePath );
171 private StorageAsset getAsset( String namespace, String project )
173 return getAsset( namespace ).resolve( project );
176 private StorageAsset getAsset( String namespace, String project, String version )
178 return getAsset( namespace, project ).resolve( version );
181 private StorageAsset getAsset( String namespace, String project, String version, String fileName )
183 return getAsset( namespace, project, version ).resolve( fileName );
187 /// ************* Start of new generation interface ******************
191 public <T extends ContentItem> T adaptItem( Class<T> clazz, ContentItem item ) throws LayoutException
195 if ( clazz.isAssignableFrom( Version.class ) )
197 if ( !item.hasCharacteristic( Version.class ) )
199 item.setCharacteristic( Version.class, createVersionFromPath( item.getAsset( ) ) );
201 return (T) item.adapt( Version.class );
203 else if ( clazz.isAssignableFrom( Project.class ) )
205 if ( !item.hasCharacteristic( Project.class ) )
207 item.setCharacteristic( Project.class, createProjectFromPath( item.getAsset( ) ) );
209 return (T) item.adapt( Project.class );
211 else if ( clazz.isAssignableFrom( Namespace.class ) )
213 if ( !item.hasCharacteristic( Namespace.class ) )
215 item.setCharacteristic( Namespace.class, createNamespaceFromPath( item.getAsset( ) ) );
217 return (T) item.adapt( Namespace.class );
219 else if ( clazz.isAssignableFrom( Artifact.class ) )
221 if ( !item.hasCharacteristic( Artifact.class ) )
223 item.setCharacteristic( Artifact.class, createArtifactFromPath( item.getAsset( ) ) );
225 return (T) item.adapt( Artifact.class );
227 } catch (LayoutRuntimeException e) {
228 throw new LayoutException( e.getMessage( ), e );
230 throw new LayoutException( "Could not convert item to class " + clazz);
235 public void deleteAllItems( ItemSelector selector, Consumer<ItemDeleteStatus> consumer ) throws ContentAccessException, IllegalArgumentException
237 try ( Stream<? extends ContentItem> stream = newItemStream( selector, false ) )
239 stream.forEach( item -> {
243 consumer.accept( new ItemDeleteStatus( item ) );
245 catch ( ItemNotFoundException e )
247 consumer.accept( new ItemDeleteStatus( item, ItemDeleteStatus.ITEM_NOT_FOUND, e ) );
249 catch ( Exception e )
251 consumer.accept( new ItemDeleteStatus( item, ItemDeleteStatus.DELETION_FAILED, e ) );
253 catch ( Throwable e )
255 consumer.accept( new ItemDeleteStatus( item, ItemDeleteStatus.UNKNOWN, e ) );
262 * Removes the item from the filesystem. For namespaces, projects and versions it deletes
264 * For namespaces you have to be careful, because maven repositories may have sub namespaces
265 * parallel to projects. Which means deleting a namespaces also deletes the sub namespaces and
266 * not only the projects of the given namespace. Better run the delete for each project of
269 * Artifacts are deleted as provided. No related artifacts will be deleted.
271 * @param item the item that should be removed
272 * @throws ItemNotFoundException if the item does not exist
273 * @throws ContentAccessException if some error occurred while accessing the filesystem
276 public void deleteItem( ContentItem item ) throws ItemNotFoundException, ContentAccessException
278 final Path baseDirectory = getRepoDir( );
279 final Path itemPath = item.getAsset( ).getFilePath( );
280 if ( !Files.exists( itemPath ) )
282 throw new ItemNotFoundException( "The item " + item.toString( ) + "does not exist in the repository " + getId( ) );
284 if ( !itemPath.toAbsolutePath( ).startsWith( baseDirectory.toAbsolutePath( ) ) )
286 log.error( "The namespace {} to delete from repository {} is not a subdirectory of the repository base.", item, getId( ) );
287 log.error( "Namespace directory: {}", itemPath );
288 log.error( "Repository directory: {}", baseDirectory );
289 throw new ContentAccessException( "Inconsistent directories found. Could not delete namespace." );
293 if ( Files.isDirectory( itemPath ) )
295 FileUtils.deleteDirectory( itemPath );
299 Files.deleteIfExists( itemPath );
302 catch ( IOException e )
304 log.error( "Could not delete item from path {}: {}", itemPath, e.getMessage( ), e );
305 throw new ContentAccessException( "Error occured while deleting item " + item + ": " + e.getMessage( ), e );
310 public ContentItem getItem( ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
312 if ( selector.hasVersion( ) && selector.hasArtifactId( ) )
314 return getArtifact( selector );
316 else if ( selector.hasProjectId( ) && selector.hasVersion( ) )
318 return getVersion( selector );
320 else if ( selector.hasProjectId( ) )
322 return getProject( selector );
326 return getNamespace( selector );
331 public Namespace getNamespace( final ItemSelector namespaceSelector ) throws ContentAccessException, IllegalArgumentException
333 StorageAsset nsPath = getAsset( namespaceSelector.getNamespace() );
336 return getNamespaceFromPath( nsPath );
338 catch ( LayoutException e )
340 throw new IllegalArgumentException( "Not a valid selector " + e.getMessage( ), e );
346 public Project getProject( final ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
348 if ( !selector.hasProjectId( ) )
350 throw new IllegalArgumentException( "Project id must be set" );
352 final StorageAsset path = getAsset( selector.getNamespace( ), selector.getProjectId( ) );
355 return getProjectFromPath( path );
357 catch ( LayoutException e )
359 throw new IllegalArgumentException( "Not a valid selector " + e.getMessage( ), e );
365 public Version getVersion( final ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
367 if ( !selector.hasProjectId( ) )
369 throw new IllegalArgumentException( "Project id must be set" );
371 if ( !selector.hasVersion( ) )
373 throw new IllegalArgumentException( "Version must be set" );
375 final StorageAsset path = getAsset( selector.getNamespace( ), selector.getProjectId( ), selector.getVersion( ) );
378 return getVersionFromPath( path );
380 catch ( LayoutException e )
382 throw new IllegalArgumentException( "Not a valid selector " + e.getMessage( ), e );
387 public Artifact createArtifact( final StorageAsset artifactPath, final ItemSelector selector,
388 final String classifier )
390 Version version = getVersion( selector );
391 ArtifactOptBuilder builder = org.apache.archiva.repository.content.base.ArchivaArtifact.withAsset( artifactPath )
392 .withVersion( version )
393 .withId( selector.getArtifactId( ) )
394 .withArtifactVersion( mavenContentHelper.getArtifactVersion( artifactPath, selector ) )
395 .withClassifier( classifier );
396 if ( selector.hasType( ) )
398 builder.withType( selector.getType( ) );
400 return builder.build( );
403 public Namespace getNamespaceFromArtifactPath( final StorageAsset artifactPath ) throws LayoutException
405 if (artifactPath == null) {
406 throw new LayoutException( "Path null is not valid for artifact" );
408 final StorageAsset namespacePath = artifactPath.getParent( ).getParent( ).getParent( );
409 return getNamespaceFromPath( namespacePath );
412 public Namespace getNamespaceFromPath( final StorageAsset nsPath ) throws LayoutException
414 if (nsPath == null) {
415 throw new LayoutException( "Path null is not valid for namespace" );
421 item = itemMap.computeIfAbsent( nsPath,
422 path -> createNamespaceFromPath( nsPath ) );
424 catch ( LayoutRuntimeException e )
426 throw new LayoutException( e.getMessage( ), e.getCause() );
428 if (!item.hasCharacteristic( Namespace.class )) {
429 item.setCharacteristic( Namespace.class, createNamespaceFromPath( nsPath ) );
431 return item.adapt( Namespace.class );
434 public Namespace createNamespaceFromPath( final StorageAsset namespacePath) throws LayoutRuntimeException
436 if (namespacePath == null) {
437 throw new LayoutRuntimeException( "Path null is not valid for namespace" );
439 final String namespace = MavenContentHelper.getNamespaceFromNamespacePath( namespacePath );
440 return ArchivaNamespace.withRepository( this )
441 .withAsset( namespacePath )
442 .withNamespace( namespace )
446 private Project getProjectFromPath( final StorageAsset path ) throws LayoutException
449 throw new LayoutException( "Path null is not valid for project" );
454 item = itemMap.computeIfAbsent( path, this::createProjectFromPath );
456 catch ( LayoutRuntimeException e )
458 throw new LayoutException( e.getMessage( ), e.getCause( ) );
460 if (!item.hasCharacteristic( Project.class )) {
461 item.setCharacteristic( Project.class, createProjectFromPath( path ) );
463 return item.adapt( Project.class );
466 private Project createProjectFromPath( final StorageAsset projectPath ) throws LayoutRuntimeException
468 if (projectPath==null) {
469 throw new LayoutRuntimeException( "Path null is not valid for project" );
474 namespace = getNamespaceFromPath( projectPath.getParent( ) );
476 catch ( LayoutException e )
478 throw new LayoutRuntimeException( e.getMessage( ), e.getCause() );
480 return ArchivaProject.withRepository( this ).withAsset( projectPath )
481 .withNamespace( namespace )
482 .withId( projectPath.getName( ) ).build( );
485 private Project getProjectFromArtifactPath( final StorageAsset artifactPath ) throws LayoutException
487 if (artifactPath == null) {
488 throw new LayoutException( "Path null is not valid for artifact" );
490 final StorageAsset projectPath = artifactPath.getParent( ).getParent( );
491 return getProjectFromPath( projectPath );
494 private Version getVersionFromArtifactPath( final StorageAsset artifactPath ) throws LayoutException
496 if (artifactPath==null) {
497 throw new LayoutException( "Path null is not valid for version" );
499 final StorageAsset versionPath = artifactPath.getParent( );
500 return getVersionFromPath( versionPath );
503 private Version getVersionFromPath( StorageAsset path ) throws LayoutException
506 throw new LayoutException( "Path null is not valid for version" );
511 item = itemMap.computeIfAbsent( path, this::createVersionFromPath );
513 catch ( LayoutRuntimeException e )
515 throw new LayoutException( e.getMessage( ), e.getCause( ) );
517 if (!item.hasCharacteristic( Version.class )) {
518 item.setCharacteristic( Version.class, createVersionFromPath( path ) );
520 return item.adapt( Version.class );
523 private Version createVersionFromPath(StorageAsset path) throws LayoutRuntimeException
526 throw new LayoutRuntimeException( "Path null is not valid for version" );
531 proj = getProjectFromPath( path.getParent( ) );
533 catch ( LayoutException e )
535 throw new LayoutRuntimeException( e.getMessage( ), e );
537 return ArchivaVersion.withRepository( this ).withAsset( path )
538 .withProject( proj ).withVersion(path.getName()).build();
541 private Optional<Artifact> getOptionalArtifactFromPath( final StorageAsset artifactPath) {
544 return Optional.of( getArtifactFromPath( artifactPath ) );
546 catch ( LayoutException e )
548 log.error( "Could not get artifact from path {}", artifactPath.getPath( ) );
549 return Optional.empty( );
553 private Artifact getArtifactFromPath( final StorageAsset artifactPath ) throws LayoutException
555 if (artifactPath==null) {
556 throw new LayoutException( "Path null is not valid for artifact" );
561 item = dataItemMap.computeIfAbsent( artifactPath, this::createArtifactFromPath );
563 catch ( LayoutRuntimeException e )
565 throw new LayoutException( e.getMessage( ), e.getCause() );
567 if (!item.hasCharacteristic( Artifact.class )) {
568 item.setCharacteristic( Artifact.class, createArtifactFromPath( artifactPath ) );
570 return item.adapt( Artifact.class );
573 private Artifact createArtifactFromPath( final StorageAsset artifactPath ) throws LayoutRuntimeException
575 if (artifactPath==null) {
576 throw new LayoutRuntimeException( "Path null is not valid for artifact" );
578 final Version version;
581 version = getVersionFromArtifactPath( artifactPath );
583 catch ( LayoutException e )
585 throw new LayoutRuntimeException( e.getMessage( ), e );
587 final ArtifactInfo info = getArtifactInfoFromPath( version.getId( ), artifactPath );
588 return org.apache.archiva.repository.content.base.ArchivaArtifact.withAsset( artifactPath )
589 .withVersion( version )
591 .withClassifier( info.classifier )
592 .withRemainder( info.remainder )
593 .withType( info.type )
594 .withArtifactVersion( info.version )
595 .withContentType( info.contentType )
596 .withArtifactType( info.artifactType )
600 private String getContentType(StorageAsset artifactPath) {
603 return Files.probeContentType( artifactPath.getFilePath( ) );
606 catch ( IOException e )
613 private DataItem getDataItemFromPath( final StorageAsset artifactPath )
615 final String contentType = getContentType( artifactPath );
616 return dataItemMap.computeIfAbsent( artifactPath, myArtifactPath ->
617 org.apache.archiva.repository.content.base.ArchivaDataItem.withAsset( artifactPath )
618 .withId( artifactPath.getName( ) )
619 .withContentType( contentType )
625 private ContentItem getItemFromPath( final StorageAsset itemPath )
627 if ( itemPath.isLeaf( ) )
629 if (dataItemMap.containsKey( itemPath )) {
630 return dataItemMap.get( itemPath );
632 return getDataItemFromPath( itemPath );
636 if (itemMap.containsKey( itemPath )) {
637 return itemMap.get( itemPath );
639 return ArchivaContentItem.withRepository( this ).withAsset( itemPath ).build();
645 public ManagedRepositoryContent getGenericContent( )
650 // Simple object to hold artifact information
651 private static class ArtifactInfo
654 private String version;
655 private String extension;
656 private String remainder;
658 private String classifier;
659 private String contentType;
660 private StorageAsset asset;
661 private ArtifactType artifactType = BaseArtifactTypes.MAIN;
664 private ArtifactInfo getArtifactInfoFromPath( final String genericVersion, final StorageAsset path )
666 final ArtifactInfo info = new ArtifactInfo( );
668 info.id = path.getParent( ).getParent( ).getName( );
669 final String fileName = path.getName( );
670 if ( VersionUtil.isGenericSnapshot( genericVersion ) )
672 String baseVersion = StringUtils.substringBeforeLast( genericVersion, "-" + SNAPSHOT );
673 String prefix = info.id + "-" + baseVersion + "-";
674 if ( fileName.startsWith( prefix ) )
676 String versionPostfix = StringUtils.removeStart( fileName, prefix );
677 Matcher matcher = UNIQUE_SNAPSHOT_PATTERN.matcher( versionPostfix );
678 if ( matcher.matches( ) )
680 info.version = baseVersion + "-" + matcher.group( 1 );
681 String newPrefix = info.id + "-" + info.version;
682 if ( fileName.startsWith( newPrefix ) )
684 String classPostfix = StringUtils.removeStart( fileName, newPrefix );
685 Matcher cMatch = CLASSIFIER_PATTERN.matcher( classPostfix );
686 if ( cMatch.matches( ) )
688 info.classifier = cMatch.group( 1 );
689 info.remainder = cMatch.group( 2 );
693 info.classifier = "";
694 info.remainder = classPostfix;
699 log.debug( "Artifact does not match the maven name pattern {}", path );
700 info.artifactType = BaseArtifactTypes.UNKNOWN;
701 info.classifier = "";
702 info.remainder = StringUtils.substringAfter( fileName, prefix );
707 log.debug( "Artifact does not match the snapshot version pattern {}", path );
709 info.artifactType = BaseArtifactTypes.UNKNOWN;
710 // This is just a guess. No guarantee to the get a usable version.
711 info.version = StringUtils.removeStart( fileName, info.id + '-' );
712 String postfix = StringUtils.substringAfterLast( info.version, "." ).toLowerCase( );
713 while ( COMMON_EXTENSIONS.matcher( postfix ).matches( ) )
715 info.version = StringUtils.substringBeforeLast( info.version, "." );
716 postfix = StringUtils.substringAfterLast( info.version, "." ).toLowerCase( );
718 info.classifier = "";
719 info.remainder = StringUtils.substringAfter( fileName, prefix );
724 log.debug( "Artifact does not match the maven name pattern: {}", path );
725 if ( fileName.contains( "-" + baseVersion ) )
727 info.id = StringUtils.substringBefore( fileName, "-" + baseVersion );
733 info.artifactType = BaseArtifactTypes.UNKNOWN;
735 info.classifier = "";
736 info.remainder = StringUtils.substringAfterLast( fileName, "." );
741 String prefix = info.id + "-" + genericVersion;
742 if ( fileName.startsWith( prefix + "-") )
744 info.version = genericVersion;
745 String classPostfix = StringUtils.removeStart( fileName, prefix );
746 Matcher cMatch = CLASSIFIER_PATTERN.matcher( classPostfix );
747 if ( cMatch.matches( ) )
749 info.classifier = cMatch.group( 1 );
750 info.remainder = cMatch.group( 2 );
754 info.classifier = "";
755 info.remainder = classPostfix;
757 } else if (fileName.startsWith(prefix + ".")) {
758 info.version = genericVersion;
759 info.remainder = StringUtils.removeStart( fileName, prefix );
760 info.classifier = "";
761 } else if (fileName.startsWith(info.id+"-")) {
762 String postFix = StringUtils.removeStart( fileName, info.id + "-" );
763 String versionPart = StringUtils.substringBefore( postFix, "." );
764 if (VersionUtil.isVersion(versionPart)) {
765 info.version = versionPart;
766 info.remainder = StringUtils.removeStart( postFix, versionPart );
767 info.classifier = "";
770 info.classifier = "";
771 int dotPos = fileName.indexOf( "." );
772 info.remainder = fileName.substring( dotPos );
778 if ( fileName.contains( "-" + genericVersion ) )
780 info.id = StringUtils.substringBefore( fileName, "-" + genericVersion );
787 log.debug( "Artifact does not match the version pattern {}", path );
788 info.artifactType = BaseArtifactTypes.UNKNOWN;
789 info.classifier = "";
790 info.remainder = StringUtils.substringAfterLast( fileName, "." );
793 info.extension = StringUtils.substringAfterLast( fileName, "." );
794 info.type = MavenContentHelper.getTypeFromClassifierAndExtension( info.classifier, info.extension );
797 info.contentType = Files.probeContentType( path.getFilePath( ) );
799 catch ( IOException e )
801 info.contentType = "";
804 if ( MavenContentHelper.METADATA_FILENAME.equalsIgnoreCase( fileName ) )
806 info.artifactType = BaseArtifactTypes.METADATA;
808 else if ( MavenContentHelper.METADATA_REPOSITORY_FILENAME.equalsIgnoreCase( fileName ) )
810 info.artifactType = MavenTypes.REPOSITORY_METADATA;
812 else if ( StringUtils.isNotEmpty( info.remainder ) && StringUtils.countMatches( info.remainder, "." ) >= 2 )
814 String mainFile = StringUtils.substringBeforeLast( fileName, "." );
815 if ( path.getParent( ).resolve( mainFile ).exists( ) )
817 info.artifactType = BaseArtifactTypes.RELATED;
825 public Artifact getArtifact( final ItemSelector selector ) throws ContentAccessException
827 if ( !selector.hasProjectId( ) )
829 throw new IllegalArgumentException( "Project id must be set" );
831 if ( !selector.hasVersion( ) )
833 throw new IllegalArgumentException( "Version must be set" );
835 if ( !selector.hasArtifactId( ) )
837 throw new IllegalArgumentException( "Artifact id must be set" );
839 final StorageAsset artifactDir = getAsset( selector.getNamespace( ), selector.getProjectId( ),
840 selector.getVersion( ) );
841 final String artifactVersion = mavenContentHelper.getArtifactVersion( artifactDir, selector );
842 final String classifier = MavenContentHelper.getClassifier( selector );
843 final String extension = MavenContentHelper.getArtifactExtension( selector );
844 final String artifactId = StringUtils.isEmpty( selector.getArtifactId( ) ) ? selector.getProjectId( ) : selector.getArtifactId( );
845 final String fileName = MavenContentHelper.getArtifactFileName( artifactId, artifactVersion, classifier, extension );
846 final StorageAsset path = getAsset( selector.getNamespace( ), selector.getProjectId( ),
847 selector.getVersion( ), fileName );
850 return getArtifactFromPath( path );
852 catch ( LayoutException e )
854 throw new IllegalArgumentException( "The selector is not valid " + e.getMessage( ), e );
859 public Artifact getArtifact( String path ) throws LayoutException, ContentAccessException
861 StorageAsset asset = getAssetByPath( path );
862 return getArtifactFromPath( asset );
866 * Returns all the subdirectories of the given namespace directory as project.
869 public List<? extends Project> getProjects( Namespace namespace )
871 return namespace.getAsset( ).list( ).stream( )
872 .filter( StorageAsset::isContainer )
876 return getProjectFromPath( a );
878 catch ( LayoutException e )
880 log.error( "Not a valid project path " + a.getPath( ), e );
884 .filter( Objects::nonNull )
885 .collect( Collectors.toList( ) );
889 public List<? extends Project> getProjects( ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
891 return getProjects( getNamespace( selector ) );
895 * Returns a version object for each directory that is a direct child of the project directory.
897 * @param project the project for which the versions should be returned
898 * @return the list of versions or a empty list, if not version was found
901 public List<? extends Version> getVersions( final Project project )
903 StorageAsset asset = getAsset( project.getNamespace( ).getId( ), project.getId( ) );
904 return asset.list( ).stream( ).filter( StorageAsset::isContainer )
905 .map( a -> ArchivaVersion.withAsset( a )
906 .withProject( project )
907 .withVersion( a.getName( ) ).build( ) )
908 .collect( Collectors.toList( ) );
912 * Returns the versions that can be found for the given selector.
914 * @param selector the item selector. At least namespace and projectId must be set.
915 * @return the list of version objects or a empty list, if the selector does not match a version
916 * @throws ContentAccessException if the access to the underlying backend failed
917 * @throws IllegalArgumentException if the selector has no projectId specified
920 public List<? extends Version> getVersions( final ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
922 if ( !selector.hasProjectId( ) )
924 log.error( "Bad item selector for version list: {}", selector );
925 throw new IllegalArgumentException( "Project id not set, while retrieving versions." );
927 final Project project = getProject( selector );
928 if ( selector.hasVersion( ) )
930 final StorageAsset asset = getAsset( selector.getNamespace( ), selector.getProjectId( ), selector.getVersion( ) );
931 return asset.list( ).stream( ).map( a -> getArtifactInfoFromPath( selector.getVersion( ), a ) )
932 .filter( ai -> StringUtils.isNotEmpty( ai.version ) )
936 return getVersionFromArtifactPath( v.asset );
938 catch ( LayoutException e )
940 log.error( "Could not get version from asset " + v.asset.getPath( ) );
944 .filter( Objects::nonNull )
946 .collect( Collectors.toList( ) );
950 return getVersions( project );
954 public List<String> getArtifactVersions( final ItemSelector selector ) throws ContentAccessException, IllegalArgumentException
956 if ( !selector.hasProjectId( ) )
958 log.error( "Bad item selector for version list: {}", selector );
959 throw new IllegalArgumentException( "Project id not set, while retrieving versions." );
961 final Project project = getProject( selector );
962 if ( selector.hasVersion( ) )
964 final StorageAsset asset = getAsset( selector.getNamespace( ), selector.getProjectId( ), selector.getVersion( ) );
965 return asset.list( ).stream( ).map( a -> getArtifactInfoFromPath( selector.getVersion( ), a ) )
966 .filter( ai -> StringUtils.isNotEmpty( ai.version ) )
967 .map( v -> v.version )
969 .collect( Collectors.toList( ) );
973 return project.getAsset( ).list( ).stream( ).map( a -> {
976 return getVersionFromPath( a );
978 catch ( LayoutException e )
980 log.error( "Could not get version from path " + a.getPath( ) );
983 } ).filter( Objects::nonNull )
984 .flatMap( v -> v.getAsset( ).list( ).stream( ).map( a -> getArtifactInfoFromPath( v.getId( ), a ) ) )
985 .filter( ai -> StringUtils.isNotEmpty( ai.version ) )
986 .map( v -> v.version )
988 .collect( Collectors.toList( ) );
994 * See {@link #newArtifactStream(ItemSelector)}. This method collects the stream into a list.
996 * @param selector the selector for the artifacts
997 * @return the list of artifacts
998 * @throws ContentAccessException if the access to the underlying filesystem failed
1001 public List<? extends Artifact> getArtifacts( ItemSelector selector ) throws ContentAccessException
1003 try ( Stream<? extends Artifact> stream = newArtifactStream( selector ) )
1005 return stream.collect( Collectors.toList( ) );
1011 * File filter to select certain artifacts using the selector data.
1013 private Predicate<StorageAsset> getArtifactFileFilterFromSelector( final ItemSelector selector )
1015 Predicate<StorageAsset> p = StorageAsset::isLeaf;
1016 StringBuilder fileNamePattern = new StringBuilder( "^" );
1017 if ( selector.hasArtifactId( ) )
1019 fileNamePattern.append( Pattern.quote( selector.getArtifactId( ) ) ).append( "-" );
1023 fileNamePattern.append( "[A-Za-z0-9_\\-.]+-" );
1025 if ( selector.hasArtifactVersion( ) )
1027 if ( selector.getArtifactVersion( ).contains( "*" ) )
1029 String[] tokens = StringUtils.splitByWholeSeparator( selector.getArtifactVersion( ), "*" );
1030 for ( String currentToken : tokens )
1032 if ( !currentToken.equals( "" ) )
1034 fileNamePattern.append( Pattern.quote( currentToken ) );
1036 fileNamePattern.append( "[A-Za-z0-9_\\-.]*" );
1041 fileNamePattern.append( Pattern.quote( selector.getArtifactVersion( ) ) );
1046 fileNamePattern.append( "[A-Za-z0-9_\\-.]+" );
1048 String classifier = selector.hasClassifier( ) ? selector.getClassifier( ) :
1049 ( selector.hasType( ) ? MavenContentHelper.getClassifierFromType( selector.getType( ) ) : null );
1050 if ( classifier != null )
1052 if ( "*".equals( classifier ) )
1054 fileNamePattern.append( "(-[A-Za-z0-9]+)?\\." );
1058 fileNamePattern.append( "-" ).append( Pattern.quote( classifier ) ).append( "\\." );
1063 fileNamePattern.append( "\\." );
1065 String extension = selector.hasExtension( ) ? selector.getExtension( ) :
1066 ( selector.hasType( ) ? MavenContentHelper.getArtifactExtension( selector ) : null );
1067 if ( extension != null )
1069 if ( selector.includeRelatedArtifacts( ) )
1071 fileNamePattern.append( Pattern.quote( extension ) ).append( "(\\.[A-Za-z0-9]+)?" );
1075 fileNamePattern.append( Pattern.quote( extension ) );
1080 fileNamePattern.append( "[A-Za-z0-9.]+" );
1082 final Pattern pattern = Pattern.compile( fileNamePattern.toString( ) );
1083 return p.and( a -> pattern.matcher( a.getName( ) ).matches( ) );
1088 * Returns the artifacts. The number of artifacts returned depend on the selector.
1089 * If the selector sets the flag {@link ItemSelector#includeRelatedArtifacts()} to <code>true</code>,
1090 * additional to the matching artifacts, related artifacts like hash values or signatures are included in the artifact
1092 * If the selector sets the flag {@link ItemSelector#recurse()} to <code>true</code>, artifacts of the given
1093 * namespace and from all sub namespaces that start with the given namespace are returned.
1095 * <li>If only a namespace is given, all artifacts with the given namespace or starting with the given
1096 * namespace (see {@link ItemSelector#recurse()} are returned.</li>
1097 * <li>If a namespace and a project id, or artifact id is given, the artifacts of all versions of the given
1098 * namespace and project are returned.</li>
1099 * <li>If a namespace and a project id or artifact id and a version is given, the artifacts of the given
1100 * version are returned</li>
1101 * <li>If no artifact version or artifact id is given, it will return all "artifacts" found in the directory.
1102 * To select only artifacts that match the layout you should add the artifact id and artifact version
1103 * (can contain a '*' pattern).</li>
1106 * The '*' pattern can be used in classifiers and artifact versions and match zero or more characters.
1108 * There is no determinate order of the elements in the stream.
1110 * Returned streams are auto closable and should be used in a try-with-resources statement.
1112 * @param selector the item selector
1113 * @throws ContentAccessException if the access to the underlying filesystem failed
1116 public Stream<? extends Artifact> newArtifactStream( ItemSelector selector ) throws ContentAccessException
1118 String projectId = selector.hasProjectId( ) ? selector.getProjectId( ) : ( selector.hasArtifactId( ) ? selector.getArtifactId( )
1120 final Predicate<StorageAsset> filter = getArtifactFileFilterFromSelector( selector );
1121 if ( projectId != null && selector.hasVersion( ) )
1123 return getAsset( selector.getNamespace( ), projectId, selector.getVersion( ) )
1124 .list( ).stream( ).filter( filter )
1125 .map( this::getOptionalArtifactFromPath )
1126 .filter( Optional::isPresent ).map( Optional::get );
1128 else if ( projectId != null )
1130 final StorageAsset projDir = getAsset( selector.getNamespace( ), projectId );
1131 return projDir.list( ).stream( )
1132 .map( a -> a.isContainer( ) ? a.list( ) : Collections.singletonList( a ) )
1133 .flatMap( List::stream )
1135 .map( this::getOptionalArtifactFromPath )
1136 .filter( Optional::isPresent ).map( Optional::get );
1140 StorageAsset namespaceDir = getAsset( selector.getNamespace( ) );
1141 if ( selector.recurse( ) )
1143 return StorageUtil.newAssetStream( namespaceDir, true )
1145 .map( this::getOptionalArtifactFromPath )
1146 .filter( Optional::isPresent ).map( Optional::get );
1150 // We descend into 2 subdirectories (project and version)
1151 return namespaceDir.list( ).stream( )
1152 .map( a -> a.isContainer( ) ? a.list( ) : Collections.singletonList( a ) )
1153 .flatMap( List::stream )
1154 .map( a -> a.isContainer( ) ? a.list( ) : Collections.singletonList( a ) )
1155 .flatMap( List::stream )
1157 .map( this::getOptionalArtifactFromPath )
1158 .filter( Optional::isPresent ).map( Optional::get );
1164 * Same as {@link #newArtifactStream(ContentItem)} but returns the collected stream as list.
1166 * @param item the item the parent item
1167 * @return the list of artifacts or a empty list of no artifacts where found
1170 public List<? extends Artifact> getArtifacts( ContentItem item )
1172 try ( Stream<? extends Artifact> stream = newArtifactStream( item ) )
1174 return stream.collect( Collectors.toList( ) );
1179 * Returns all artifacts
1181 * @param item the namespace to search for artifacts
1182 * @return the stream of artifacts
1183 * @throws ContentAccessException if the access to the underlying storage failed
1185 public Stream<? extends Artifact> newArtifactStream( Namespace item ) throws ContentAccessException
1187 return newArtifactStream( ArchivaItemSelector.builder( ).withNamespace( item.getId( ) ).build( ) );
1190 public Stream<? extends Artifact> newArtifactStream( Project item ) throws ContentAccessException
1192 return newArtifactStream( ArchivaItemSelector.builder( ).withNamespace( item.getNamespace( ).getId( ) )
1193 .withProjectId( item.getId( ) ).build( ) );
1196 public Stream<? extends Artifact> newArtifactStream( Version item ) throws ContentAccessException
1198 return newArtifactStream( ArchivaItemSelector.builder( ).withNamespace( item.getProject( ).getNamespace( ).getId( ) )
1199 .withProjectId( item.getProject( ).getId( ) )
1200 .withVersion( item.getId( ) ).build( ) );
1204 * Returns all related artifacts that match the given artifact. That means all artifacts that have
1205 * the same filename plus an additional extension, e.g. ${fileName}.sha2
1207 * @param item the artifact
1208 * @return the stream of artifacts
1209 * @throws ContentAccessException if access to the underlying storage failed
1211 public Stream<? extends Artifact> newArtifactStream( Artifact item ) throws ContentAccessException
1213 final Version v = item.getVersion( );
1214 final String fileName = item.getFileName( );
1215 final Predicate<StorageAsset> filter = ( StorageAsset a ) ->
1216 a.getName( ).startsWith( fileName + "." );
1217 return v.getAsset( ).list( ).stream( ).filter( filter )
1221 return getArtifactFromPath( a );
1223 catch ( LayoutException e )
1225 log.error( "Not a valid artifact path " + a.getPath( ), e );
1228 } ).filter( Objects::nonNull );
1232 * Returns the stream of artifacts that are children of the given item.
1234 * @param item the item from where the artifacts should be returned
1235 * @return the stream of artifacts
1236 * @throws ContentAccessException if access to the underlying storage failed
1239 public Stream<? extends Artifact> newArtifactStream( ContentItem item ) throws ContentAccessException
1241 if ( item instanceof Namespace )
1243 return newArtifactStream( ( (Namespace) item ) );
1245 else if ( item instanceof Project )
1247 return newArtifactStream( (Project) item );
1249 else if ( item instanceof Version )
1251 return newArtifactStream( (Version) item );
1253 else if ( item instanceof Artifact )
1255 return newArtifactStream( (Artifact) item );
1259 log.warn( "newArtifactStream for unsupported item requested: {}", item.getClass( ).getName( ) );
1260 return Stream.empty( );
1264 private void appendPatternRegex( StringBuilder builder, String name )
1266 String[] patternArray = name.split( "[*]" );
1267 for ( int i = 0; i < patternArray.length - 1; i++ )
1269 builder.append( Pattern.quote( patternArray[i] ) )
1270 .append( "[A-Za-z0-9_\\-]*" );
1272 builder.append( Pattern.quote( patternArray[patternArray.length - 1] ) );
1275 Predicate<StorageAsset> getItemFileFilterFromSelector( ItemSelector selector )
1277 if ( !selector.hasNamespace( ) && !selector.hasProjectId( ) )
1279 throw new IllegalArgumentException( "Selector must have at least namespace and projectid" );
1281 StringBuilder pathMatcher = new StringBuilder( "^" );
1282 if ( selector.hasNamespace( ) )
1284 String path = "/" + String.join( "/", selector.getNamespace( ).split( "\\." ) );
1285 if ( path.contains( "*" ) )
1287 appendPatternRegex( pathMatcher, path );
1291 pathMatcher.append( Pattern.quote( path ) );
1295 if ( selector.hasProjectId( ) )
1297 pathMatcher.append( "/" );
1298 if ( selector.getProjectId( ).contains( "*" ) )
1300 appendPatternRegex( pathMatcher, selector.getProjectId( ) );
1304 pathMatcher.append( Pattern.quote( selector.getProjectId( ) ) );
1307 if ( selector.hasVersion( ) )
1309 pathMatcher.append( "/" );
1310 if ( selector.getVersion( ).contains( "*" ) )
1312 appendPatternRegex( pathMatcher, selector.getVersion( ) );
1316 pathMatcher.append( Pattern.quote( selector.getVersion( ) ) );
1319 pathMatcher.append( ".*" );
1320 final Pattern pathPattern = Pattern.compile( pathMatcher.toString( ) );
1321 final Predicate<StorageAsset> pathPredicate = ( StorageAsset asset ) -> pathPattern.matcher( asset.getPath( ) ).matches( );
1322 if ( selector.hasArtifactId( ) || selector.hasArtifactVersion( ) || selector.hasClassifier( )
1323 || selector.hasType( ) || selector.hasExtension( ) )
1325 return getArtifactFileFilterFromSelector( selector ).and( pathPredicate );
1329 return pathPredicate;
1334 * Returns a concatenation of the asset and its children as stream, if they exist.
1335 * It descends <code>level+1</code> levels down.
1337 * @param a the asset to start from
1338 * @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, ...
1339 * @return the stream of storage assets
1341 private Stream<StorageAsset> getChildrenDF( StorageAsset a, int level )
1343 if ( a.isContainer( ) )
1346 return Stream.concat( a.list().stream( ).flatMap( ch -> getChildrenDF( ch, level - 1 ) ), Stream.of( a ) );
1349 return Stream.concat( a.list( ).stream( ), Stream.of( a ) );
1354 return Stream.of( a );
1359 public Stream<? extends ContentItem> newItemStream( ItemSelector selector, boolean parallel ) throws ContentAccessException, IllegalArgumentException
1361 final Predicate<StorageAsset> filter = getItemFileFilterFromSelector( selector );
1362 StorageAsset startDir;
1363 if (selector.getNamespace().contains("*")) {
1364 startDir = getAsset("");
1365 } else if ( selector.hasProjectId( ) && selector.getProjectId().contains("*") )
1367 startDir = getAsset( selector.getNamespace( ) );
1368 } else if ( selector.hasProjectId() && selector.hasVersion() && selector.getVersion().contains("*")) {
1369 startDir = getAsset( selector.getNamespace( ), selector.getProjectId( ) );
1371 else if ( selector.hasProjectId( ) && selector.hasVersion( ) )
1373 startDir = getAsset( selector.getNamespace( ), selector.getProjectId( ), selector.getVersion() );
1375 else if ( selector.hasProjectId( ) )
1377 startDir = getAsset( selector.getNamespace( ), selector.getProjectId( ) );
1381 startDir = getAsset( selector.getNamespace( ) );
1382 if ( !selector.recurse( ) )
1384 // We descend into 2 subdirectories (project and version)
1385 return startDir.list( ).stream( )
1386 .flatMap( a -> getChildrenDF( a, 1 ) )
1387 .map( this::getItemFromPath );
1390 return StorageUtil.newAssetStream( startDir, parallel )
1392 .map( this::getItemFromPath );
1397 * Checks, if the asset/file queried by the given selector exists.
1400 public boolean hasContent( ItemSelector selector )
1402 return getItem( selector ).getAsset( ).exists( );
1406 public ContentItem getParent( ContentItem item )
1408 return getItemFromPath( item.getAsset( ).getParent( ) );
1412 public List<? extends ContentItem> getChildren( ContentItem item )
1414 if (item.getAsset().isLeaf()) {
1415 return Collections.emptyList( );
1417 return item.getAsset( ).list( ).stream( ).map( this::getItemFromPath ).collect( Collectors.toList( ) );
1422 public <T extends ContentItem> T applyCharacteristic( Class<T> clazz, ContentItem item ) throws LayoutException
1424 if (item.getAsset().isLeaf()) {
1425 if (clazz.isAssignableFrom( Artifact.class )) {
1426 Artifact artifact = getArtifactFromPath( item.getAsset( ) );
1427 item.setCharacteristic( Artifact.class, artifact );
1428 return (T) artifact;
1430 throw new LayoutException( "Could not adapt file to clazz " + clazz );
1433 if (clazz.isAssignableFrom( Version.class )) {
1434 Version version = getVersionFromPath( item.getAsset( ) );
1435 item.setCharacteristic( Version.class, version );
1437 } else if (clazz.isAssignableFrom( Project.class )) {
1438 Project project = getProjectFromPath( item.getAsset( ) );
1439 item.setCharacteristic( Project.class, project );
1441 } else if (clazz.isAssignableFrom( Namespace.class )) {
1442 Namespace ns = getNamespaceFromPath( item.getAsset( ) );
1443 item.setCharacteristic( Namespace.class, ns );
1446 throw new LayoutException( "Cannot adapt directory to clazz " + clazz );
1452 public <T extends ManagedRepositoryContentLayout> T getLayout( Class<T> clazz ) throws LayoutException
1454 if (clazz.isAssignableFrom( this.getClass() )) {
1457 throw new LayoutException( "Cannot convert to layout " + clazz );
1462 public <T extends ManagedRepositoryContentLayout> boolean supportsLayout( Class<T> clazz )
1464 return clazz.isAssignableFrom( this.getClass( ) );
1468 public List<Class<? extends ManagedRepositoryContentLayout>> getSupportedLayouts( )
1474 * Moves the file to the artifact destination
1477 public void addArtifact( Path sourceFile, Artifact destination ) throws IllegalArgumentException, ContentAccessException
1481 StorageAsset asset = destination.getAsset( );
1482 if ( !asset.exists( ) )
1486 asset.replaceDataFromFile( sourceFile );
1488 catch ( IOException e )
1490 log.error( "Could not push data to asset source={} destination={}. {}", sourceFile, destination.getAsset( ).getFilePath( ), e.getMessage( ) );
1491 throw new ContentAccessException( e.getMessage( ), e );
1496 public ContentItem toItem( String path ) throws LayoutException
1499 StorageAsset asset = getRepository( ).getAsset( path );
1500 ContentItem item = getItemFromPath( asset );
1501 if (item instanceof DataItem) {
1502 Artifact artifact = adaptItem( Artifact.class, item );
1503 if (asset.getParent()==null) {
1504 throw new LayoutException( "Path too short for maven artifact "+path );
1506 String version = asset.getParent( ).getName( );
1507 if (asset.getParent().getParent()==null) {
1508 throw new LayoutException( "Path too short for maven artifact " + path );
1510 String project = item.getAsset( ).getParent( ).getParent( ).getName( );
1511 DataItem dataItem = (DataItem) item;
1512 if (StringUtils.isEmpty( dataItem.getExtension())) {
1513 throw new LayoutException( "Missing type on maven artifact" );
1515 if (!project.equals(artifact.getId())) {
1516 throw new LayoutException( "The maven artifact id "+artifact.getId() +" does not match the project id: " + project);
1518 boolean versionIsGenericSnapshot = VersionUtil.isGenericSnapshot( version );
1519 boolean artifactVersionIsSnapshot = VersionUtil.isSnapshot( artifact.getArtifactVersion() );
1520 if ( versionIsGenericSnapshot && !artifactVersionIsSnapshot ) {
1521 throw new LayoutException( "The maven artifact has no snapshot version in snapshot directory " + dataItem );
1523 if ( !versionIsGenericSnapshot && artifactVersionIsSnapshot) {
1524 throw new LayoutException( "The maven artifact version " + artifact.getArtifactVersion() + " is a snapshot version but inside a non snapshot directory " + version );
1526 if ( !versionIsGenericSnapshot && !version.equals( artifact.getArtifactVersion() ) )
1528 throw new LayoutException( "The maven artifact version " + artifact.getArtifactVersion() + " does not match the version directory " + version );
1535 public ContentItem toItem( StorageAsset assetPath ) throws LayoutException
1537 return toItem( assetPath.getPath( ) );
1540 /// ************* End of new generation interface ******************
1543 public String toPath( ContentItem item ) {
1544 return item.getAsset( ).getPath( );
1548 public DataItem getMetadataItem( Version version ) {
1549 StorageAsset metaPath = version.getAsset( ).resolve( MAVEN_METADATA );
1550 return getDataItemFromPath( metaPath );
1554 public DataItem getMetadataItem( Project project )
1556 StorageAsset metaPath = project.getAsset( ).resolve( MAVEN_METADATA );
1557 return getDataItemFromPath( metaPath );
1562 public String getId( )
1564 return repository.getId( );
1568 * Create the filter for various combinations of classifier and type
1570 private Predicate<ArtifactReference> getChecker( ArtifactReference referenceObject, String extension )
1572 // TODO: Check, if extension is the correct parameter here
1573 // We compare type with extension which works for artifacts like .jar.md5 but may
1574 // be not the best way.
1576 if ( referenceObject.getClassifier( ) != null && referenceObject.getType( ) != null )
1578 return ( ( ArtifactReference a ) ->
1579 referenceObject.getGroupId( ).equals( a.getGroupId( ) )
1580 && referenceObject.getArtifactId( ).equals( a.getArtifactId( ) )
1581 && referenceObject.getVersion( ).equals( a.getVersion( ) )
1582 && ( ( a.getType( ) == null )
1583 || referenceObject.getType( ).equals( a.getType( ) )
1584 || a.getType( ).startsWith( extension ) )
1585 && referenceObject.getClassifier( ).equals( a.getClassifier( ) )
1588 else if ( referenceObject.getClassifier( ) != null && referenceObject.getType( ) == null )
1590 return ( ( ArtifactReference a ) ->
1591 referenceObject.getGroupId( ).equals( a.getGroupId( ) )
1592 && referenceObject.getArtifactId( ).equals( a.getArtifactId( ) )
1593 && referenceObject.getVersion( ).equals( a.getVersion( ) )
1594 && referenceObject.getClassifier( ).equals( a.getClassifier( ) )
1597 else if ( referenceObject.getClassifier( ) == null && referenceObject.getType( ) != null )
1599 return ( ( ArtifactReference a ) ->
1600 referenceObject.getGroupId( ).equals( a.getGroupId( ) )
1601 && referenceObject.getArtifactId( ).equals( a.getArtifactId( ) )
1602 && referenceObject.getVersion( ).equals( a.getVersion( ) )
1603 && ( ( a.getType( ) == null )
1604 || referenceObject.getType( ).equals( a.getType( ) )
1605 || a.getType( ).startsWith( extension ) )
1610 return ( ( ArtifactReference a ) ->
1611 referenceObject.getGroupId( ).equals( a.getGroupId( ) )
1612 && referenceObject.getArtifactId( ).equals( a.getArtifactId( ) )
1613 && referenceObject.getVersion( ).equals( a.getVersion( ) )
1620 private String convertUriToPath( URI uri )
1622 if ( uri.getScheme( ) == null )
1624 return Paths.get( uri.getPath( ) ).toString( );
1626 else if ( "file".equals( uri.getScheme( ) ) )
1628 return Paths.get( uri ).toString( );
1632 return uri.toString( );
1637 public ManagedRepository getRepository( )
1643 public void setRepository( final ManagedRepository repo )
1645 this.repository = repo;
1648 if ( repository instanceof EditableManagedRepository )
1650 ( (EditableManagedRepository) repository ).setContent( this );
1655 private Path getRepoDir( )
1657 return repository.getRoot().getFilePath( );
1660 private RepositoryStorage getStorage( )
1662 return repository.getRoot().getStorage( );
1665 public void setFiletypes( FileTypes filetypes )
1667 this.filetypes = filetypes;
1670 public void setMavenContentHelper( MavenContentHelper contentHelper )
1672 this.mavenContentHelper = contentHelper;
1676 public MavenMetadataReader getMetadataReader( )
1678 return metadataReader;
1681 public void setMetadataReader( MavenMetadataReader metadataReader )
1683 this.metadataReader = metadataReader;