1 package org.apache.maven.archiva.repository.layout;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.maven.archiva.common.utils.VersionUtil;
24 import org.apache.maven.archiva.model.ArchivaArtifact;
25 import org.apache.maven.archiva.model.ArtifactReference;
26 import org.apache.maven.archiva.repository.content.ArtifactExtensionMapping;
29 * DefaultBidirectionalRepositoryLayout - the layout mechanism for use by Maven 2.x repositories.
31 * @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
33 * @plexus.component role-hint="default"
35 public class DefaultBidirectionalRepositoryLayout
36 implements BidirectionalRepositoryLayout
40 public String groupId;
42 public String artifactId;
44 public String baseVersion;
48 public FilenameParts fileParts;
50 public void appendGroupId( String part )
52 if ( groupId == null )
58 groupId += "." + part;
62 private static final char PATH_SEPARATOR = '/';
64 private static final char GROUP_SEPARATOR = '.';
66 private static final char ARTIFACT_SEPARATOR = '-';
73 public ArchivaArtifact toArtifact( String path )
74 throws LayoutException
76 PathReferences pathrefs = toPathReferences( path );
78 ArchivaArtifact artifact = new ArchivaArtifact( pathrefs.groupId, pathrefs.artifactId,
79 pathrefs.fileParts.version, pathrefs.fileParts.classifier,
85 public ArtifactReference toArtifactReference( String path )
86 throws LayoutException
88 PathReferences pathrefs = toPathReferences( path );
90 ArtifactReference reference = new ArtifactReference();
91 reference.setGroupId( pathrefs.groupId );
92 reference.setArtifactId( pathrefs.artifactId );
93 reference.setVersion( pathrefs.fileParts.version );
94 reference.setClassifier( pathrefs.fileParts.classifier );
95 reference.setType( pathrefs.type );
100 public String toPath( ArchivaArtifact artifact )
102 if ( artifact == null )
104 throw new IllegalArgumentException( "Artifact cannot be null" );
107 return toPath( artifact.getGroupId(), artifact.getArtifactId(), artifact.getBaseVersion(), artifact
108 .getVersion(), artifact.getClassifier(), artifact.getType() );
111 public String toPath( ArtifactReference reference )
113 if ( reference == null )
115 throw new IllegalArgumentException( "Artifact reference cannot be null" );
118 String baseVersion = VersionUtil.getBaseVersion( reference.getVersion() );
119 return toPath( reference.getGroupId(), reference.getArtifactId(), baseVersion, reference.getVersion(),
120 reference.getClassifier(), reference.getType() );
123 private String formatAsDirectory( String directory )
125 return directory.replace( GROUP_SEPARATOR, PATH_SEPARATOR );
128 private String toPath( String groupId, String artifactId, String baseVersion, String version, String classifier,
131 StringBuffer path = new StringBuffer();
133 path.append( formatAsDirectory( groupId ) ).append( PATH_SEPARATOR );
134 path.append( artifactId ).append( PATH_SEPARATOR );
136 if ( baseVersion != null )
138 path.append( baseVersion ).append( PATH_SEPARATOR );
139 if ( ( version != null ) && ( type != null ) )
141 path.append( artifactId ).append( ARTIFACT_SEPARATOR ).append( version );
143 if ( StringUtils.isNotBlank( classifier ) )
145 path.append( ARTIFACT_SEPARATOR ).append( classifier );
148 path.append( GROUP_SEPARATOR ).append( ArtifactExtensionMapping.getExtension( type ) );
152 return path.toString();
155 public boolean isValidPath( String path )
159 toPathReferences( path );
162 catch ( LayoutException e )
168 private PathReferences toPathReferences( String path )
169 throws LayoutException
171 if ( StringUtils.isBlank( path ) )
173 throw new LayoutException( "Unable to convert blank path." );
176 PathReferences prefs = new PathReferences();
178 String normalizedPath = StringUtils.replace( path, "\\", "/" );
179 String pathParts[] = StringUtils.split( normalizedPath, '/' );
183 * path = "commons-lang/commons-lang/2.1/commons-lang-2.1.jar"
184 * path[0] = "commons-lang"; // The Group ID
185 * path[1] = "commons-lang"; // The Artifact ID
186 * path[2] = "2.1"; // The Version
187 * path[3] = "commons-lang-2.1.jar" // The filename.
190 if ( pathParts.length < 4 )
192 // Illegal Path Parts Length.
193 throw new LayoutException( "Not enough parts to the path [" + path
194 + "] to construct an ArchivaArtifact from. (Requires at least 4 parts)" );
198 int partCount = pathParts.length;
199 int filenamePos = partCount - 1;
200 int baseVersionPos = partCount - 2;
201 int artifactIdPos = partCount - 3;
202 int groupIdPos = partCount - 4;
204 // Second to last is the baseVersion (the directory version)
205 prefs.baseVersion = pathParts[baseVersionPos];
207 // Third to last is the artifact Id.
208 prefs.artifactId = pathParts[artifactIdPos];
210 // Remaining pieces are the groupId.
211 for ( int i = 0; i <= groupIdPos; i++ )
213 prefs.appendGroupId( pathParts[i] );
218 // Last part is the filename
219 String filename = pathParts[filenamePos];
221 // Now we need to parse the filename to get the artifact version Id.
222 prefs.fileParts = RepositoryLayoutUtils.splitFilename( filename, prefs.artifactId, prefs.baseVersion );
224 /* If classifier is discovered, see if it deserves to be.
226 * Filenames like "comm-3.0-u1.jar" might be identified as having a version of "3.0"
227 * and a classifier of "u1".
229 * This routine will take the version + classifier and compare it to the prefs.baseVersion and
230 * move the classifierensure that
232 * javax/comm/3.0-u1/comm-3.0-u1.jar
234 if ( StringUtils.isNotBlank( prefs.fileParts.classifier ) )
236 String conjoinedVersion = prefs.fileParts.version + "-" + prefs.fileParts.classifier;
238 if( StringUtils.equals( prefs.baseVersion, conjoinedVersion ) )
240 prefs.fileParts.version = conjoinedVersion;
241 prefs.fileParts.classifier = null;
245 prefs.type = ArtifactExtensionMapping.guessTypeFromFilename( filename );
247 catch ( LayoutException e )
253 if ( prefs.fileParts != null )
255 /* Compare artifact version to path baseversion.
257 * Version naming in the wild can be strange at times.
258 * Sometimes what is seen as a classifier is actually part of the version id.
260 * To compensate for this, the path is checked against the artifact.version and
261 * the concatenation of the artifact.version + "-" + artifact.classifier
263 String pathVersion = prefs.baseVersion;
264 String artifactVersion = prefs.fileParts.version;
266 // Do we have a snapshot version?
267 if ( VersionUtil.isSnapshot( artifactVersion ) )
269 // Rules are different for SNAPSHOTS
270 if ( !VersionUtil.isGenericSnapshot( pathVersion ) )
272 String baseVersion = VersionUtil.getBaseVersion( prefs.fileParts.version );
273 throw new LayoutException( "Invalid snapshot artifact location, version directory should be "
279 // Non SNAPSHOT rules.
280 // Do we pass the simple test?
281 if ( !StringUtils.equals( pathVersion, artifactVersion ) )
283 // Do we have a classifier? If so, test the conjoined case.
284 if ( StringUtils.isNotBlank( prefs.fileParts.classifier ) )
286 String artifactLongVersion = artifactVersion + "-" + prefs.fileParts.classifier;
287 if ( !StringUtils.equals( pathVersion, artifactLongVersion ) )
289 throw new LayoutException( "Invalid artifact: version declared in directory path does"
290 + " not match what was found in the artifact filename." );
295 throw new LayoutException( "Invalid artifact: version declared in directory path does"
296 + " not match what was found in the artifact filename." );
301 // Test if the artifactId present on the directory path is the same as the artifactId filename.
302 if ( !prefs.artifactId.equals( prefs.fileParts.artifactId ) )
304 throw new LayoutException( "Invalid artifact Id" );