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