package org.apache.maven.index.artifact; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import javax.inject.Named; import javax.inject.Singleton; import java.text.ParseException; import java.text.SimpleDateFormat; /** * An M2 <code>GavCalculator</code>. * * @author Jason van Zyl * @author Tamas Cservenak */ @Singleton @Named ("maven2") public class M2GavCalculator implements GavCalculator { public Gav pathToGav( String str ) { try { String s = str.startsWith( "/" ) ? str.substring( 1 ) : str; int vEndPos = s.lastIndexOf( '/' ); if ( vEndPos == -1 ) { return null; } int aEndPos = s.lastIndexOf( '/', vEndPos - 1 ); if ( aEndPos == -1 ) { return null; } int gEndPos = s.lastIndexOf( '/', aEndPos - 1 ); if ( gEndPos == -1 ) { return null; } String groupId = s.substring( 0, gEndPos ).replace( '/', '.' ); String artifactId = s.substring( gEndPos + 1, aEndPos ); String version = s.substring( aEndPos + 1, vEndPos ); String fileName = s.substring( vEndPos + 1 ); boolean checksum = false; boolean signature = false; Gav.HashType checksumType = null; Gav.SignatureType signatureType = null; if ( s.endsWith( ".md5" ) ) { checksum = true; checksumType = Gav.HashType.md5; s = s.substring( 0, s.length() - 4 ); } else if ( s.endsWith( ".sha1" ) ) { checksum = true; checksumType = Gav.HashType.sha1; s = s.substring( 0, s.length() - 5 ); } if ( s.endsWith( ".asc" ) ) { signature = true; signatureType = Gav.SignatureType.gpg; s = s.substring( 0, s.length() - 4 ); } if ( s.endsWith( "maven-metadata.xml" ) ) { return null; } boolean snapshot = version.endsWith( "SNAPSHOT" ); if ( snapshot ) { return getSnapshotGav( s, vEndPos, groupId, artifactId, version, fileName, checksum, signature, checksumType, signatureType ); } else { return getReleaseGav( s, vEndPos, groupId, artifactId, version, fileName, checksum, signature, checksumType, signatureType ); } } catch ( NumberFormatException e ) { return null; } catch ( StringIndexOutOfBoundsException e ) { return null; } } private Gav getReleaseGav( String s, int vEndPos, String groupId, String artifactId, String version, String fileName, boolean checksum, boolean signature, Gav.HashType checksumType, Gav.SignatureType signatureType ) { if ( !fileName.startsWith( artifactId + "-" + version + "." ) && !fileName.startsWith( artifactId + "-" + version + "-" ) ) { // The path does not represents an artifact (filename does not match artifactId-version)! return null; } int nTailPos = vEndPos + artifactId.length() + version.length() + 2; String tail = s.substring( nTailPos ); int nExtPos = tail.indexOf( '.' ); if ( nExtPos == -1 ) { // NX-563: not allowing extensionless paths to be interpreted as artifact return null; } String ext = tail.substring( nExtPos + 1 ); String classifier = tail.charAt( 0 ) == '-' ? tail.substring( 1, nExtPos ) : null; return new Gav( groupId, artifactId, version, classifier, ext, null, null, fileName, checksum, checksumType, signature, signatureType ); } private Gav getSnapshotGav( String s, int vEndPos, String groupId, String artifactId, String version, String fileName, boolean checksum, boolean signature, Gav.HashType checksumType, Gav.SignatureType signatureType ) { Integer snapshotBuildNo = null; Long snapshotTimestamp = null; int vSnapshotStart = vEndPos + artifactId.length() + version.length() - 9 + 3; String vSnapshot = s.substring( vSnapshotStart, vSnapshotStart + 8 ); String classifier = null; String ext = null; if ( "SNAPSHOT".equals( vSnapshot ) ) { int nTailPos = vEndPos + artifactId.length() + version.length() + 2; String tail = s.substring( nTailPos ); int nExtPos = tail.indexOf( '.' ); if ( nExtPos == -1 ) { // NX-563: not allowing extensionless paths to be interpreted as artifact return null; } ext = tail.substring( nExtPos + 1 ); classifier = tail.charAt( 0 ) == '-' ? tail.substring( 1, nExtPos ) : null; } else { StringBuilder sb = new StringBuilder( vSnapshot ); sb.append( s.substring( vSnapshotStart + sb.length(), vSnapshotStart + sb.length() + 8 ) ); try { SimpleDateFormat df = new SimpleDateFormat( "yyyyMMdd.HHmmss" ); snapshotTimestamp = Long.valueOf( df.parse( sb.toString() ).getTime() ); } catch ( ParseException e ) { } int buildNumberPos = vSnapshotStart + sb.length(); StringBuilder bnr = new StringBuilder(); while ( s.charAt( buildNumberPos ) >= '0' && s.charAt( buildNumberPos ) <= '9' ) { sb.append( s.charAt( buildNumberPos ) ); bnr.append( s.charAt( buildNumberPos ) ); buildNumberPos++; } String snapshotBuildNumber = sb.toString(); snapshotBuildNo = Integer.parseInt( bnr.toString() ); int n = version.length() > 9 ? version.length() - 9 + 1 : 0; String tail = s.substring( vEndPos + artifactId.length() + n + snapshotBuildNumber.length() + 2 ); int nExtPos = tail.indexOf( '.' ); if ( nExtPos == -1 ) { // NX-563: not allowing extensionless paths to be interpreted as artifact return null; } ext = tail.substring( nExtPos + 1 ); classifier = tail.charAt( 0 ) == '-' ? tail.substring( 1, nExtPos ) : null; version = version.substring( 0, version.length() - 8 ) + snapshotBuildNumber; } return new Gav( groupId, artifactId, version, classifier, ext, snapshotBuildNo, snapshotTimestamp, fileName, checksum, checksumType, signature, signatureType ); } public String gavToPath( Gav gav ) { StringBuilder path = new StringBuilder( "/" ); path.append( gav.getGroupId().replaceAll( "(?m)(.)\\.", "$1/" ) ); // replace all '.' except the first char path.append( "/" ); path.append( gav.getArtifactId() ); path.append( "/" ); path.append( gav.getBaseVersion() ); path.append( "/" ); path.append( calculateArtifactName( gav ) ); return path.toString(); } public String calculateArtifactName( Gav gav ) { if ( gav.getName() != null && gav.getName().trim().length() > 0 ) { return gav.getName(); } else { StringBuilder path = new StringBuilder( gav.getArtifactId() ); path.append( "-" ); path.append( gav.getVersion() ); if ( gav.getClassifier() != null && gav.getClassifier().trim().length() > 0 ) { path.append( "-" ); path.append( gav.getClassifier() ); } if ( gav.getExtension() != null ) { path.append( "." ); path.append( gav.getExtension() ); } if ( gav.isSignature() ) { path.append( "." ); path.append( gav.getSignatureType().toString() ); } if ( gav.isHash() ) { path.append( "." ); path.append( gav.getHashType().toString() ); } return path.toString(); } } }