View Javadoc
1   package org.apache.maven.index.artifact;
2   
3   /*
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
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import javax.inject.Named;
23  import javax.inject.Singleton;
24  import java.text.ParseException;
25  import java.text.SimpleDateFormat;
26  
27  /**
28   * An M2 <code>GavCalculator</code>.
29   * 
30   * @author Jason van Zyl
31   * @author Tamas Cservenak
32   */
33  @Singleton
34  @Named( "maven2" )
35  public class M2GavCalculator
36      implements GavCalculator
37  {
38      public Gav pathToGav( String str )
39      {
40          try
41          {
42              String s = str.startsWith( "/" ) ? str.substring( 1 ) : str;
43  
44              int vEndPos = s.lastIndexOf( '/' );
45  
46              if ( vEndPos == -1 )
47              {
48                  return null;
49              }
50  
51              int aEndPos = s.lastIndexOf( '/', vEndPos - 1 );
52  
53              if ( aEndPos == -1 )
54              {
55                  return null;
56              }
57  
58              int gEndPos = s.lastIndexOf( '/', aEndPos - 1 );
59  
60              if ( gEndPos == -1 )
61              {
62                  return null;
63              }
64  
65              String groupId = s.substring( 0, gEndPos ).replace( '/', '.' );
66              String artifactId = s.substring( gEndPos + 1, aEndPos );
67              String version = s.substring( aEndPos + 1, vEndPos );
68              String fileName = s.substring( vEndPos + 1 );
69  
70              boolean checksum = false;
71              boolean signature = false;
72              Gav.HashType checksumType = null;
73              Gav.SignatureType signatureType = null;
74              if ( s.endsWith( ".md5" ) )
75              {
76                  checksum = true;
77                  checksumType = Gav.HashType.md5;
78                  s = s.substring( 0, s.length() - 4 );
79              }
80              else if ( s.endsWith( ".sha1" ) )
81              {
82                  checksum = true;
83                  checksumType = Gav.HashType.sha1;
84                  s = s.substring( 0, s.length() - 5 );
85              }
86              else if ( s.endsWith( ".sha256" ) )
87              {
88                  checksum = true;
89                  checksumType = Gav.HashType.sha256;
90                  s = s.substring( 0, s.length() - 7 );
91              }
92              else if ( s.endsWith( ".sha512" ) )
93              {
94                  checksum = true;
95                  checksumType = Gav.HashType.sha512;
96                  s = s.substring( 0, s.length() - 7 );
97              }
98  
99              if ( s.endsWith( ".asc" ) )
100             {
101                 signature = true;
102                 signatureType = Gav.SignatureType.gpg;
103                 s = s.substring( 0, s.length() - 4 );
104             }
105 
106             if ( s.endsWith( "maven-metadata.xml" )
107                     || ( fileName.startsWith( "maven-metadata-" ) && fileName.contains( ".xml" ) )
108                     || ( fileName.startsWith( "_" ) && fileName.endsWith( ".repositories" ) ) )
109             {
110                 return null;
111             }
112 
113             boolean snapshot = version.endsWith( "SNAPSHOT" );
114 
115             if ( snapshot )
116             {
117                 return getSnapshotGav( s, vEndPos, groupId, artifactId, version, fileName, checksum, signature,
118                     checksumType, signatureType );
119             }
120             else
121             {
122                 return getReleaseGav( s, vEndPos, groupId, artifactId, version, fileName, checksum, signature,
123                     checksumType, signatureType );
124             }
125         }
126         catch ( NumberFormatException | StringIndexOutOfBoundsException e )
127         {
128             return null;
129         }
130     }
131 
132     private Gav getReleaseGav( String s, int vEndPos, String groupId, String artifactId, String version,
133                                String fileName, boolean checksum, boolean signature, Gav.HashType checksumType,
134                                Gav.SignatureType signatureType )
135     {
136         if ( !fileName.startsWith( artifactId + "-" + version + "." )
137             && !fileName.startsWith( artifactId + "-" + version + "-" ) )
138         {
139             // The path does not represents an artifact (filename does not match artifactId-version)!
140             return null;
141         }
142 
143         int nTailPos = vEndPos + artifactId.length() + version.length() + 2;
144 
145         String tail = s.substring( nTailPos );
146 
147         int nExtPos = tail.indexOf( '.' );
148 
149         if ( nExtPos == -1 )
150         {
151             // NX-563: not allowing extensionless paths to be interpreted as artifact
152             return null;
153         }
154 
155         String ext = tail.substring( nExtPos + 1 );
156 
157         String classifier = tail.charAt( 0 ) == '-' ? tail.substring( 1, nExtPos ) : null;
158 
159         return new Gav( groupId, artifactId, version, classifier, ext, null, null, fileName, checksum, checksumType,
160             signature, signatureType );
161     }
162 
163     private Gav getSnapshotGav( String s, int vEndPos, String groupId, String artifactId, String version,
164                                 String fileName, boolean checksum, boolean signature, Gav.HashType checksumType,
165                                 Gav.SignatureType signatureType )
166     {
167 
168         Integer snapshotBuildNo = null;
169 
170         Long snapshotTimestamp = null;
171 
172         int vSnapshotStart = vEndPos + artifactId.length() + version.length() - 9 + 3;
173 
174         String vSnapshot = s.substring( vSnapshotStart, vSnapshotStart + 8 );
175 
176         String classifier;
177 
178         String ext;
179 
180         if ( "SNAPSHOT".equals( vSnapshot ) )
181         {
182             int nTailPos = vEndPos + artifactId.length() + version.length() + 2;
183 
184             String tail = s.substring( nTailPos );
185 
186             int nExtPos = tail.indexOf( '.' );
187 
188             if ( nExtPos == -1 )
189             {
190                 // NX-563: not allowing extensionless paths to be interpreted as artifact
191                 return null;
192             }
193 
194             ext = tail.substring( nExtPos + 1 );
195 
196             classifier = tail.charAt( 0 ) == '-' ? tail.substring( 1, nExtPos ) : null;
197         }
198         else
199         {
200             StringBuilder sb = new StringBuilder( vSnapshot );
201             sb.append( s, vSnapshotStart + sb.length(), vSnapshotStart + sb.length() + 8 );
202 
203             try
204             {
205                 SimpleDateFormat df = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
206                 snapshotTimestamp = df.parse( sb.toString() ).getTime();
207             }
208             catch ( ParseException e )
209             {
210             }
211 
212             int buildNumberPos = vSnapshotStart + sb.length();
213             StringBuilder bnr = new StringBuilder();
214             while ( s.charAt( buildNumberPos ) >= '0' && s.charAt( buildNumberPos ) <= '9' )
215             {
216                 sb.append( s.charAt( buildNumberPos ) );
217                 bnr.append( s.charAt( buildNumberPos ) );
218                 buildNumberPos++;
219             }
220             String snapshotBuildNumber = sb.toString();
221             snapshotBuildNo = Integer.parseInt( bnr.toString() );
222 
223             int n = version.length() > 9 ? version.length() - 9 + 1 : 0;
224 
225             String tail = s.substring( vEndPos + artifactId.length() + n + snapshotBuildNumber.length() + 2 );
226 
227             int nExtPos = tail.indexOf( '.' );
228 
229             if ( nExtPos == -1 )
230             {
231                 // NX-563: not allowing extensionless paths to be interpreted as artifact
232                 return null;
233             }
234 
235             ext = tail.substring( nExtPos + 1 );
236 
237             classifier = tail.charAt( 0 ) == '-' ? tail.substring( 1, nExtPos ) : null;
238 
239             version = version.substring( 0, version.length() - 8 ) + snapshotBuildNumber;
240         }
241 
242         return new Gav( groupId, artifactId, version, classifier, ext, snapshotBuildNo, snapshotTimestamp, fileName,
243             checksum, checksumType, signature, signatureType );
244     }
245 
246     public String gavToPath( Gav gav )
247     {
248 
249         return "/" + gav.getGroupId().replaceAll( "(?m)(.)\\.",
250                 "$1/" ) // replace all '.' except the first char
251                 + "/" + gav.getArtifactId() + "/" + gav.getBaseVersion() + "/" + calculateArtifactName( gav );
252     }
253 
254     public String calculateArtifactName( Gav gav )
255     {
256         if ( gav.getName() != null && gav.getName().trim().length() > 0 )
257         {
258             return gav.getName();
259         }
260         else
261         {
262             StringBuilder path = new StringBuilder( gav.getArtifactId() );
263 
264             path.append( "-" );
265 
266             path.append( gav.getVersion() );
267 
268             if ( gav.getClassifier() != null && gav.getClassifier().trim().length() > 0 )
269             {
270                 path.append( "-" );
271 
272                 path.append( gav.getClassifier() );
273             }
274 
275             if ( gav.getExtension() != null )
276             {
277                 path.append( "." );
278 
279                 path.append( gav.getExtension() );
280             }
281 
282             if ( gav.isSignature() )
283             {
284                 path.append( "." );
285 
286                 path.append( gav.getSignatureType().toString() );
287             }
288 
289             if ( gav.isHash() )
290             {
291                 path.append( "." );
292 
293                 path.append( gav.getHashType().toString() );
294             }
295 
296             return path.toString();
297         }
298     }
299 
300 }