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  
87              if ( s.endsWith( ".asc" ) )
88              {
89                  signature = true;
90                  signatureType = Gav.SignatureType.gpg;
91                  s = s.substring( 0, s.length() - 4 );
92              }
93  
94              if ( s.endsWith( "maven-metadata.xml" ) )
95              {
96                  return null;
97              }
98  
99              boolean snapshot = version.endsWith( "SNAPSHOT" );
100 
101             if ( snapshot )
102             {
103                 return getSnapshotGav( s, vEndPos, groupId, artifactId, version, fileName, checksum, signature,
104                     checksumType, signatureType );
105             }
106             else
107             {
108                 return getReleaseGav( s, vEndPos, groupId, artifactId, version, fileName, checksum, signature,
109                     checksumType, signatureType );
110             }
111         }
112         catch ( NumberFormatException e )
113         {
114             return null;
115         }
116         catch ( StringIndexOutOfBoundsException e )
117         {
118             return null;
119         }
120     }
121 
122     private Gav getReleaseGav( String s, int vEndPos, String groupId, String artifactId, String version,
123                                String fileName, boolean checksum, boolean signature, Gav.HashType checksumType,
124                                Gav.SignatureType signatureType )
125     {
126         if ( !fileName.startsWith( artifactId + "-" + version + "." )
127             && !fileName.startsWith( artifactId + "-" + version + "-" ) )
128         {
129             // The path does not represents an artifact (filename does not match artifactId-version)!
130             return null;
131         }
132 
133         int nTailPos = vEndPos + artifactId.length() + version.length() + 2;
134 
135         String tail = s.substring( nTailPos );
136 
137         int nExtPos = tail.indexOf( '.' );
138 
139         if ( nExtPos == -1 )
140         {
141             // NX-563: not allowing extensionless paths to be interpreted as artifact
142             return null;
143         }
144 
145         String ext = tail.substring( nExtPos + 1 );
146 
147         String classifier = tail.charAt( 0 ) == '-' ? tail.substring( 1, nExtPos ) : null;
148 
149         return new Gav( groupId, artifactId, version, classifier, ext, null, null, fileName, checksum, checksumType,
150             signature, signatureType );
151     }
152 
153     private Gav getSnapshotGav( String s, int vEndPos, String groupId, String artifactId, String version,
154                                 String fileName, boolean checksum, boolean signature, Gav.HashType checksumType,
155                                 Gav.SignatureType signatureType )
156     {
157 
158         Integer snapshotBuildNo = null;
159 
160         Long snapshotTimestamp = null;
161 
162         int vSnapshotStart = vEndPos + artifactId.length() + version.length() - 9 + 3;
163 
164         String vSnapshot = s.substring( vSnapshotStart, vSnapshotStart + 8 );
165 
166         String classifier = null;
167 
168         String ext = null;
169 
170         if ( "SNAPSHOT".equals( vSnapshot ) )
171         {
172             int nTailPos = vEndPos + artifactId.length() + version.length() + 2;
173 
174             String tail = s.substring( nTailPos );
175 
176             int nExtPos = tail.indexOf( '.' );
177 
178             if ( nExtPos == -1 )
179             {
180                 // NX-563: not allowing extensionless paths to be interpreted as artifact
181                 return null;
182             }
183 
184             ext = tail.substring( nExtPos + 1 );
185 
186             classifier = tail.charAt( 0 ) == '-' ? tail.substring( 1, nExtPos ) : null;
187         }
188         else
189         {
190             StringBuilder sb = new StringBuilder( vSnapshot );
191             sb.append( s.substring( vSnapshotStart + sb.length(), vSnapshotStart + sb.length() + 8 ) );
192 
193             try
194             {
195                 SimpleDateFormat df = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
196                 snapshotTimestamp = Long.valueOf( df.parse( sb.toString() ).getTime() );
197             }
198             catch ( ParseException e )
199             {
200             }
201 
202             int buildNumberPos = vSnapshotStart + sb.length();
203             StringBuilder bnr = new StringBuilder();
204             while ( s.charAt( buildNumberPos ) >= '0' && s.charAt( buildNumberPos ) <= '9' )
205             {
206                 sb.append( s.charAt( buildNumberPos ) );
207                 bnr.append( s.charAt( buildNumberPos ) );
208                 buildNumberPos++;
209             }
210             String snapshotBuildNumber = sb.toString();
211             snapshotBuildNo = Integer.parseInt( bnr.toString() );
212 
213             int n = version.length() > 9 ? version.length() - 9 + 1 : 0;
214 
215             String tail = s.substring( vEndPos + artifactId.length() + n + snapshotBuildNumber.length() + 2 );
216 
217             int nExtPos = tail.indexOf( '.' );
218 
219             if ( nExtPos == -1 )
220             {
221                 // NX-563: not allowing extensionless paths to be interpreted as artifact
222                 return null;
223             }
224 
225             ext = tail.substring( nExtPos + 1 );
226 
227             classifier = tail.charAt( 0 ) == '-' ? tail.substring( 1, nExtPos ) : null;
228 
229             version = version.substring( 0, version.length() - 8 ) + snapshotBuildNumber;
230         }
231 
232         return new Gav( groupId, artifactId, version, classifier, ext, snapshotBuildNo, snapshotTimestamp, fileName,
233             checksum, checksumType, signature, signatureType );
234     }
235 
236     public String gavToPath( Gav gav )
237     {
238         StringBuilder path = new StringBuilder( "/" );
239 
240         path.append( gav.getGroupId().replaceAll( "(?m)(.)\\.", "$1/" ) ); // replace all '.' except the first char
241 
242         path.append( "/" );
243 
244         path.append( gav.getArtifactId() );
245 
246         path.append( "/" );
247 
248         path.append( gav.getBaseVersion() );
249 
250         path.append( "/" );
251 
252         path.append( calculateArtifactName( gav ) );
253 
254         return path.toString();
255     }
256 
257     public String calculateArtifactName( Gav gav )
258     {
259         if ( gav.getName() != null && gav.getName().trim().length() > 0 )
260         {
261             return gav.getName();
262         }
263         else
264         {
265             StringBuilder path = new StringBuilder( gav.getArtifactId() );
266 
267             path.append( "-" );
268 
269             path.append( gav.getVersion() );
270 
271             if ( gav.getClassifier() != null && gav.getClassifier().trim().length() > 0 )
272             {
273                 path.append( "-" );
274 
275                 path.append( gav.getClassifier() );
276             }
277 
278             if ( gav.getExtension() != null )
279             {
280                 path.append( "." );
281 
282                 path.append( gav.getExtension() );
283             }
284 
285             if ( gav.isSignature() )
286             {
287                 path.append( "." );
288 
289                 path.append( gav.getSignatureType().toString() );
290             }
291 
292             if ( gav.isHash() )
293             {
294                 path.append( "." );
295 
296                 path.append( gav.getHashType().toString() );
297             }
298 
299             return path.toString();
300         }
301     }
302 
303 }