This project has retired. For details please refer to its Attic page.
Maven2RepositoryPathTranslator xref
View Javadoc
1   package org.apache.archiva.metadata.repository.storage.maven2;
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 org.apache.archiva.common.utils.VersionUtil;
23  import org.apache.archiva.metadata.model.ArtifactMetadata;
24  import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
25  import org.apache.archiva.metadata.repository.storage.RepositoryPathTranslator;
26  import org.apache.archiva.repository.storage.StorageAsset;
27  import org.slf4j.Logger;
28  import org.slf4j.LoggerFactory;
29  import org.springframework.stereotype.Service;
30  
31  import javax.annotation.PostConstruct;
32  import javax.inject.Inject;
33  import java.nio.file.Path;
34  import java.util.List;
35  import java.util.regex.Matcher;
36  import java.util.regex.Pattern;
37  
38  /**
39   *
40   */
41  @Service( "repositoryPathTranslator#maven2" )
42  public class Maven2RepositoryPathTranslator
43      implements RepositoryPathTranslator
44  {
45  
46      private Logger log = LoggerFactory.getLogger( getClass() );
47  
48      private static final char GROUP_SEPARATOR = '.';
49  
50      private static final Pattern TIMESTAMP_PATTERN = Pattern.compile( "([0-9]{8}.[0-9]{6})-([0-9]+).*" );
51      
52  
53      private static final Pattern MAVEN_PLUGIN_PATTERN = Pattern.compile( "^(maven-.*-plugin)|(.*-maven-plugin)$" );    
54  
55      /**
56       *
57       * see #initialize
58       */
59      @Inject
60      private List<ArtifactMappingProvider> artifactMappingProviders;
61  
62      public Maven2RepositoryPathTranslator()
63      {
64          // noop
65      }
66  
67      @PostConstruct
68      public void initialize()
69      {
70          //artifactMappingProviders = new ArrayList<ArtifactMappingProvider>(
71          //    applicationContext.getBeansOfType( ArtifactMappingProvider.class ).values() );
72  
73      }
74  
75  
76      public Maven2RepositoryPathTranslator( List<ArtifactMappingProvider> artifactMappingProviders )
77      {
78          this.artifactMappingProviders = artifactMappingProviders;
79      }
80  
81      @Override
82      public StorageAsset../../../../../../org/apache/archiva/repository/storage/StorageAsset.html#StorageAsset">StorageAsset toFile(StorageAsset basedir, String namespace, String projectId, String projectVersion, String filename )
83      {
84          return basedir.resolve( toPath( namespace, projectId, projectVersion, filename ) );
85      }
86  
87      @Override
88      public StorageAsset./../../../../../org/apache/archiva/repository/storage/StorageAsset.html#StorageAsset">StorageAsset toFile( StorageAsset basedir, String namespace, String projectId, String projectVersion )
89      {
90          return basedir.resolve( toPath( namespace, projectId, projectVersion ) );
91      }
92  
93      @Override
94      public String toPath( String namespace, String projectId, String projectVersion, String filename )
95      {
96          StringBuilder path = new StringBuilder();
97  
98          appendNamespaceToProjectVersion( path, namespace, projectId, projectVersion );
99          path.append( PATH_SEPARATOR );
100         path.append( filename );
101 
102         return path.toString();
103     }
104 
105     private void appendNamespaceToProjectVersion( StringBuilder path, String namespace, String projectId,
106                                                   String projectVersion )
107     {
108         appendNamespaceAndProject( path, namespace, projectId );
109         path.append( projectVersion );
110     }
111 
112     public String toPath( String namespace, String projectId, String projectVersion )
113     {
114         StringBuilder path = new StringBuilder();
115 
116         appendNamespaceToProjectVersion( path, namespace, projectId, projectVersion );
117 
118         return path.toString();
119     }
120 
121     public String toPath( String namespace )
122     {
123         StringBuilder path = new StringBuilder();
124 
125         appendNamespace( path, namespace );
126 
127         return path.toString();
128     }
129 
130     @Override
131     public String toPath( String namespace, String projectId )
132     {
133         StringBuilder path = new StringBuilder();
134 
135         appendNamespaceAndProject( path, namespace, projectId );
136 
137         return path.toString();
138     }
139 
140     private void appendNamespaceAndProject( StringBuilder path, String namespace, String projectId )
141     {
142         appendNamespace( path, namespace );
143         path.append( projectId ).append( PATH_SEPARATOR );
144     }
145 
146     private void appendNamespace( StringBuilder path, String namespace )
147     {
148         path.append( formatAsDirectory( namespace ) ).append( PATH_SEPARATOR );
149     }
150 
151     @Override
152     public StorageAsset./../../../../../org/apache/archiva/repository/storage/StorageAsset.html#StorageAsset">StorageAsset toFile( StorageAsset basedir, String namespace, String projectId )
153     {
154         return basedir.resolve( toPath( namespace, projectId ) );
155     }
156 
157     @Override
158     public StorageAsset./../../../../../org/apache/archiva/repository/storage/StorageAsset.html#StorageAsset">StorageAsset toFile( StorageAsset basedir, String namespace )
159     {
160         return basedir.resolve( toPath( namespace ) );
161     }
162 
163     private String formatAsDirectory( String directory )
164     {
165         return directory.replace( GROUP_SEPARATOR, PATH_SEPARATOR );
166     }
167 
168     @Override
169     public ArtifactMetadata getArtifactForPath( String repoId, String relativePath )
170     {
171         String[] parts = relativePath.replace( '\\', '/' ).split( "/" );
172 
173         int len = parts.length;
174         if ( len < 4 )
175         {
176             throw new IllegalArgumentException(
177                 "Not a valid artifact path in a Maven 2 repository, not enough directories: " + relativePath );
178         }
179 
180         String id = parts[--len];
181         String baseVersion = parts[--len];
182         String artifactId = parts[--len];
183         StringBuilder groupIdBuilder = new StringBuilder();
184         for ( int i = 0; i < len - 1; i++ )
185         {
186             groupIdBuilder.append( parts[i] );
187             groupIdBuilder.append( '.' );
188         }
189         groupIdBuilder.append( parts[len - 1] );
190 
191         return getArtifactFromId( repoId, groupIdBuilder.toString(), artifactId, baseVersion, id );
192     }
193 
194     @Override
195     public ArtifactMetadata getArtifactFromId( String repoId, String namespace, String projectId, String projectVersion,
196                                                String id )
197     {
198         if ( !id.startsWith( projectId + "-" ) )
199         {
200             throw new IllegalArgumentException( "Not a valid artifact path in a Maven 2 repository, filename '" + id
201                                                     + "' doesn't start with artifact ID '" + projectId + "'" );
202         }
203 
204         MavenArtifactFacetdel/maven2/MavenArtifactFacet.html#MavenArtifactFacet">MavenArtifactFacet facet = new MavenArtifactFacet();
205 
206         int index = projectId.length() + 1;
207         String version;
208         String idSubStrFromVersion = id.substring( index );
209         if ( idSubStrFromVersion.startsWith( projectVersion ) && !VersionUtil.isUniqueSnapshot( projectVersion ) )
210         {
211             // non-snapshot versions, or non-timestamped snapshot versions
212             version = projectVersion;
213         }
214         else if ( VersionUtil.isGenericSnapshot( projectVersion ) )
215         {
216             // timestamped snapshots
217             try
218             {
219                 int mainVersionLength = projectVersion.length() - 8; // 8 is length of "SNAPSHOT"
220                 if ( mainVersionLength == 0 )
221                 {
222                     throw new IllegalArgumentException(
223                         "Timestamped snapshots must contain the main version, filename was '" + id + "'" );
224                 }
225 
226                 Matcher m = TIMESTAMP_PATTERN.matcher( idSubStrFromVersion.substring( mainVersionLength ) );
227                 m.matches();
228                 String timestamp = m.group( 1 );
229                 String buildNumber = m.group( 2 );
230                 facet.setTimestamp( timestamp );
231                 facet.setBuildNumber( Integer.parseInt( buildNumber ) );
232                 version = idSubStrFromVersion.substring( 0, mainVersionLength ) + timestamp + "-" + buildNumber;
233             }
234             catch ( IllegalStateException e )
235             {
236                 throw new IllegalArgumentException( "Not a valid artifact path in a Maven 2 repository, filename '" + id
237                                                         + "' doesn't contain a timestamped version matching snapshot '"
238                                                         + projectVersion + "'", e);
239             }
240         }
241         else
242         {
243             // invalid
244             throw new IllegalArgumentException(
245                 "Not a valid artifact path in a Maven 2 repository, filename '" + id + "' doesn't contain version '"
246                     + projectVersion + "'" );
247         }
248 
249         String classifier;
250         String ext;
251         index += version.length();
252         if ( index == id.length() )
253         {
254             // no classifier or extension
255             classifier = null;
256             ext = null;
257         }
258         else
259         {
260             char c = id.charAt( index );
261             if ( c == '-' )
262             {
263                 // classifier up until '.'
264                 int extIndex = id.indexOf( '.', index );
265                 if ( extIndex >= 0 )
266                 {
267                     classifier = id.substring( index + 1, extIndex );
268                     ext = id.substring( extIndex + 1 );
269                 }
270                 else
271                 {
272                     classifier = id.substring( index + 1 );
273                     ext = null;
274                 }
275             }
276             else if ( c == '.' )
277             {
278                 // rest is the extension
279                 classifier = null;
280                 ext = id.substring( index + 1 );
281             }
282             else
283             {
284                 throw new IllegalArgumentException( "Not a valid artifact path in a Maven 2 repository, filename '" + id
285                                                         + "' expected classifier or extension but got '"
286                                                         + id.substring( index ) + "'" );
287             }
288         }
289 
290         ArtifactMetadatael/ArtifactMetadata.html#ArtifactMetadata">ArtifactMetadata metadata = new ArtifactMetadata();
291         metadata.setId( id );
292         metadata.setNamespace( namespace );
293         metadata.setProject( projectId );
294         metadata.setRepositoryId( repoId );
295         metadata.setProjectVersion( projectVersion );
296         metadata.setVersion( version );
297 
298         facet.setClassifier( classifier );
299 
300         // we use our own provider here instead of directly accessing Maven's artifact handlers as it has no way
301         // to select the correct order to apply multiple extensions mappings to a preferred type
302         // TODO: this won't allow the user to decide order to apply them if there are conflicts or desired changes -
303         //       perhaps the plugins could register missing entries in configuration, then we just use configuration
304         //       here?
305 
306         String type = null;
307         for ( ArtifactMappingProvider mapping : artifactMappingProviders )
308         {
309             type = mapping.mapClassifierAndExtensionToType( classifier, ext );
310             if ( type != null )
311             {
312                 break;
313             }
314         }
315 
316         // TODO: this is cheating! We should check the POM metadata instead
317         if ( type == null && "jar".equals( ext ) && isArtifactIdValidMavenPlugin( projectId ) )
318         {
319             type = "maven-plugin";
320         }
321 
322         // use extension as default
323         if ( type == null )
324         {
325             type = ext;
326         }
327 
328         // TODO: should we allow this instead?
329         if ( type == null )
330         {
331             throw new IllegalArgumentException(
332                 "Not a valid artifact path in a Maven 2 repository, filename '" + id + "' does not have a type" );
333         }
334 
335         facet.setType( type );
336         metadata.addFacet( facet );
337 
338         return metadata;
339     }
340 
341 
342     public boolean isArtifactIdValidMavenPlugin( String artifactId )
343     {
344         return MAVEN_PLUGIN_PATTERN.matcher( artifactId ).matches();
345     }
346 }