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.utils.VersionUtil;
22 import org.apache.archiva.maven.metadata.MavenMetadataReader;
23 import org.apache.archiva.model.ArchivaRepositoryMetadata;
24 import org.apache.archiva.model.SnapshotVersion;
25 import org.apache.archiva.repository.content.ItemSelector;
26 import org.apache.archiva.repository.metadata.RepositoryMetadataException;
27 import org.apache.archiva.repository.storage.StorageAsset;
28 import org.apache.commons.lang3.StringUtils;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.springframework.stereotype.Service;
33 import javax.inject.Inject;
34 import javax.inject.Named;
35 import java.util.Comparator;
36 import java.util.LinkedList;
37 import java.util.regex.Pattern;
40 * Helper class that contains certain maven specific methods
42 @Service( "MavenContentHelper" )
43 public class MavenContentHelper
46 private static final Logger log = LoggerFactory.getLogger( MavenContentHelper.class );
47 public static final Pattern UNIQUE_SNAPSHOT_NUMBER_PATTERN = Pattern.compile( "^([0-9]{8}\\.[0-9]{6}-[0-9]+)(.*)" );
51 @Named( "metadataReader#maven" )
52 MavenMetadataReader metadataReader;
54 public static final String METADATA_FILENAME = "maven-metadata.xml";
55 public static final String METADATA_REPOSITORY_FILENAME = "maven-metadata-repository.xml";
57 public MavenContentHelper() {
61 public void setMetadataReader( MavenMetadataReader metadataReader )
63 this.metadataReader = metadataReader;
67 * Returns the namespace string for a given path in the repository
69 * @param namespacePath the path to the namespace in the directory
70 * @return the namespace string that matches the given path.
72 public static String getNamespaceFromNamespacePath( final StorageAsset namespacePath) {
73 LinkedList<String> names = new LinkedList<>( );
74 StorageAsset current = namespacePath;
75 while (current.hasParent()) {
76 names.addFirst( current.getName() );
77 current = current.getParent( );
79 return String.join( ".", names );
83 * Returns the artifact version for the given artifact directory and the item selector
85 public String getArtifactVersion( StorageAsset artifactDir, ItemSelector selector) {
86 if (selector.hasArtifactVersion()) {
87 return selector.getArtifactVersion();
88 } else if (selector.hasVersion()) {
89 if ( VersionUtil.isGenericSnapshot( selector.getVersion() ) ) {
90 return getLatestArtifactSnapshotVersion( artifactDir, selector.getVersion( ) );
92 return selector.getVersion( );
95 throw new IllegalArgumentException( "No version set on the selector " );
102 * Returns the latest snapshot version that is referenced by the metadata file.
104 * @param artifactDir the directory of the artifact
105 * @param snapshotVersion the generic snapshot version (must end with '-SNAPSHOT')
106 * @return the real version from the metadata
108 public String getLatestArtifactSnapshotVersion( StorageAsset artifactDir, String snapshotVersion) {
109 final StorageAsset metadataFile = artifactDir.resolve( METADATA_FILENAME );
110 StringBuilder version = new StringBuilder( );
113 ArchivaRepositoryMetadata metadata = metadataReader.read( metadataFile );
115 // re-adjust to timestamp if present, otherwise retain the original -SNAPSHOT filename
116 SnapshotVersion metadataVersion = metadata.getSnapshotVersion( );
117 if ( metadataVersion != null && StringUtils.isNotEmpty( metadataVersion.getTimestamp( ) ) )
119 version.append( snapshotVersion, 0, snapshotVersion.length( ) - 8 ); // remove SNAPSHOT from end
120 version.append( metadataVersion.getTimestamp( ) ).append( "-" ).append( metadataVersion.getBuildNumber( ) );
121 return version.toString( );
124 catch ( RepositoryMetadataException e )
126 // unable to parse metadata - LOGGER it, and continue with the version as the original SNAPSHOT version
127 log.warn( "Invalid metadata: {} - {}", metadataFile, e.getMessage( ) );
129 final String baseVersion = StringUtils.removeEnd( snapshotVersion, "-SNAPSHOT" );
130 final String prefix = metadataFile.getParent( ).getParent( ).getName( ) + "-"+baseVersion+"-";
131 return artifactDir.list( ).stream( ).filter( a -> a.getName( ).startsWith( prefix ) )
132 .map( a -> StringUtils.removeStart( a.getName( ), prefix ) )
133 .map( n -> UNIQUE_SNAPSHOT_NUMBER_PATTERN.matcher( n ) )
134 .filter( m -> m.matches( ) )
135 .map( m -> baseVersion+"-"+m.group( 1 ) )
136 .sorted( Comparator.reverseOrder() ).findFirst().orElse( snapshotVersion );
141 * Returns a artifact filename that corresponds to the given data.
142 * @param artifactId the selector data
143 * @param artifactVersion the artifactVersion
144 * @param classifier the artifact classifier
145 * @param extension the file extension
147 static String getArtifactFileName( String artifactId, String artifactVersion,
148 String classifier, String extension )
150 StringBuilder fileName = new StringBuilder( artifactId ).append( "-" );
151 fileName.append( artifactVersion );
152 if ( !StringUtils.isEmpty( classifier ) )
154 fileName.append( "-" ).append( classifier );
156 fileName.append( "." ).append( extension );
157 return fileName.toString( );
161 * Returns the classifier for a given selector. If the selector has no classifier, but
162 * a type set. The classifier is generated from the type.
164 * @param selector the artifact selector
165 * @return the classifier or empty string if no classifier was found
167 static String getClassifier( ItemSelector selector )
169 if ( selector.hasClassifier( ) )
171 return selector.getClassifier( );
173 else if ( selector.hasType( ) )
175 return getClassifierFromType( selector.getType( ) );
184 * Returns a classifier for a given type. It returns only classifier for the maven default types
187 * @param type the type of the artifact
188 * @return the classifier if one was found, otherwise a empty string
190 static String getClassifierFromType( final String type )
192 String testType = type.trim( ).toLowerCase( );
193 switch (testType.length( ))
196 if ("javadoc".equals(testType)) {
200 if ("test-jar".equals(testType))
205 if ("ejb-client".equals(testType)) {
209 if ("java-source".equals(testType)) {
219 * Returns the type that matches the given classifier and extension
221 * @param classifierArg the classifier
222 * @param extensionArg the extension
223 * @return the type that matches the combination of classifier and extension
225 static String getTypeFromClassifierAndExtension( String classifierArg, String extensionArg )
227 String extension = extensionArg.toLowerCase( ).trim( );
228 String classifier = classifierArg.toLowerCase( ).trim( );
229 if ( StringUtils.isEmpty( extension ) )
233 else if ( StringUtils.isEmpty( classifier ) )
237 else if ( classifier.equals( "tests" ) && extension.equals( "jar" ) )
241 else if ( classifier.equals( "client" ) && extension.equals( "jar" ) )
245 else if ( classifier.equals( "sources" ) && extension.equals( "jar" ) )
247 return "java-source";
249 else if ( classifier.equals( "javadoc" ) && extension.equals( "jar" ) )
260 * If the selector defines a type and no extension, the extension can be derived from
263 * @param selector the item selector
264 * @return the extension that matches the type or the default extension "jar" if the type is not known
266 static String getArtifactExtension( ItemSelector selector )
268 if ( selector.hasExtension( ) )
270 return selector.getExtension( );
272 else if ( selector.hasType( ) )
274 final String type = selector.getType( ).trim().toLowerCase( );
275 switch (type.length()) {
277 if ("pom".equals(type) || "war".equals(type) || "ear".equals(type) || "rar".equals(type)) {