1 package org.apache.archiva.repository.content.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.model.ArtifactReference;
23 import org.apache.archiva.repository.*;
24 import org.apache.archiva.repository.content.PathParser;
25 import org.apache.archiva.repository.features.RepositoryFeature;
26 import org.apache.archiva.repository.metadata.base.MetadataTools;
27 import org.apache.commons.lang3.StringUtils;
28
29 /**
30 * RepositoryRequest is used to determine the type of request that is incoming, and convert it to an appropriate
31 * ArtifactReference.
32 */
33 public class MavenRepositoryRequestInfo implements RepositoryRequestInfo
34 {
35 private PathParser defaultPathParser = new DefaultPathParser();
36
37 ManagedRepository repository;
38
39 public MavenRepositoryRequestInfo(ManagedRepository repository)
40 {
41 this.repository = repository;
42 }
43
44 /**
45 * Takes an incoming requested path (in "/" format) and gleans the layout
46 * and ArtifactReference appropriate for that content.
47 *
48 * @param requestedPath the relative path to the content.
49 * @return the ArtifactReference for the requestedPath.
50 * @throws LayoutException if the request path is not layout valid.
51 */
52 public ArtifactReference toArtifactReference( String requestedPath )
53 throws LayoutException
54 {
55 if ( StringUtils.isBlank( requestedPath ) )
56 {
57 throw new LayoutException( "Blank request path is not a valid." );
58 }
59
60 String path = requestedPath;
61 while ( path.startsWith( "/" ) )
62 {
63 path = path.substring( 1 );
64
65 // Only slash? that's bad, mmm-kay?
66 if ( "/".equals( path ) )
67 {
68 throw new LayoutException( "Invalid request path: Slash only." );
69 }
70 }
71
72 if ( isDefault( path ) )
73 {
74 return defaultPathParser.toArtifactReference( path );
75 }
76 else if ( isLegacy( path ) )
77 {
78 throw new LayoutException( "Legacy Maven1 repository not supported anymore." );
79 }
80 else
81 {
82 throw new LayoutException( "Not a valid request path layout, too short." );
83 }
84 }
85
86 /**
87 * <p>
88 * Tests the path to see if it conforms to the expectations of a metadata request.
89 * </p>
90 * <p>
91 * NOTE: This does a cursory check on the path's last element. A result of true
92 * from this method is not a guarantee that the metadata is in a valid format, or
93 * that it even contains data.
94 * </p>
95 *
96 * @param requestedPath the path to test.
97 * @return true if the requestedPath is likely a metadata request.
98 */
99 public boolean isMetadata( String requestedPath )
100 {
101 return requestedPath.endsWith( "/" + MetadataTools.MAVEN_METADATA );
102 }
103
104 /**
105 * @param requestedPath
106 * @return true if the requestedPath is likely an archetype catalog request.
107 */
108 public boolean isArchetypeCatalog( String requestedPath )
109 {
110 return requestedPath.endsWith( "/" + MetadataTools.MAVEN_ARCHETYPE_CATALOG );
111 }
112
113 /**
114 * <p>
115 * Tests the path to see if it conforms to the expectations of a support file request.
116 * </p>
117 * <p>
118 * Tests for <code>.sha1</code>, <code>.md5</code>, <code>.asc</code>, and <code>.php</code>.
119 * </p>
120 * <p>
121 * NOTE: This does a cursory check on the path's extension only. A result of true
122 * from this method is not a guarantee that the support resource is in a valid format, or
123 * that it even contains data.
124 * </p>
125 *
126 * @param requestedPath the path to test.
127 * @return true if the requestedPath is likely that of a support file request.
128 */
129 public boolean isSupportFile( String requestedPath )
130 {
131 int idx = requestedPath.lastIndexOf( '.' );
132 if ( idx <= 0 )
133 {
134 return false;
135 }
136
137 String ext = requestedPath.substring( idx );
138 return ( ".sha1".equals( ext ) || ".md5".equals( ext ) || ".asc".equals( ext ) || ".pgp".equals( ext ) );
139 }
140
141 public boolean isMetadataSupportFile( String requestedPath )
142 {
143 if ( isSupportFile( requestedPath ) )
144 {
145 String basefilePath = StringUtils.substring( requestedPath, 0, requestedPath.lastIndexOf( '.' ) );
146 if ( isMetadata( basefilePath ) )
147 {
148 return true;
149 }
150 }
151
152 return false;
153 }
154
155 @Override
156 public String getLayout(String requestPath) {
157 if (isDefault(requestPath)) {
158 return "default";
159 } else if (isLegacy(requestPath)) {
160 return "legacy";
161 } else {
162 return "unknown";
163 }
164 }
165
166 /**
167 * <p>
168 * Tests the path to see if it conforms to the expectations of a default layout request.
169 * </p>
170 * <p>
171 * NOTE: This does a cursory check on the count of path elements only. A result of
172 * true from this method is not a guarantee that the path sections are valid and
173 * can be resolved to an artifact reference. use {@link #toArtifactReference(String)}
174 * if you want a more complete analysis of the validity of the path.
175 * </p>
176 *
177 * @param requestedPath the path to test.
178 * @return true if the requestedPath is likely that of a default layout request.
179 */
180 private boolean isDefault( String requestedPath )
181 {
182 if ( StringUtils.isBlank( requestedPath ) )
183 {
184 return false;
185 }
186
187 String pathParts[] = StringUtils.splitPreserveAllTokens( requestedPath, '/' );
188 if ( pathParts.length > 3 )
189 {
190 return true;
191 }
192 else if ( pathParts.length == 3 )
193 {
194 // check if artifact-level metadata (ex. eclipse/jdtcore/maven-metadata.xml)
195 if ( isMetadata( requestedPath ) )
196 {
197 return true;
198 }
199 else
200 {
201 // check if checksum of artifact-level metadata (ex. eclipse/jdtcore/maven-metadata.xml.sha1)
202 int idx = requestedPath.lastIndexOf( '.' );
203 if ( idx > 0 )
204 {
205 String base = requestedPath.substring( 0, idx );
206 if ( isMetadata( base ) && isSupportFile( requestedPath ) )
207 {
208 return true;
209 }
210 }
211
212 return false;
213 }
214 }
215 else
216 {
217 return false;
218 }
219 }
220
221 /**
222 * <p>
223 * Tests the path to see if it conforms to the expectations of a legacy layout request.
224 * </p>
225 * <p>
226 * NOTE: This does a cursory check on the count of path elements only. A result of
227 * true from this method is not a guarantee that the path sections are valid and
228 * can be resolved to an artifact reference. use {@link #toArtifactReference(String)}
229 * if you want a more complete analysis of the validity of the path.
230 * </p>
231 *
232 * @param requestedPath the path to test.
233 * @return true if the requestedPath is likely that of a legacy layout request.
234 */
235 private boolean isLegacy( String requestedPath )
236 {
237 if ( StringUtils.isBlank( requestedPath ) )
238 {
239 return false;
240 }
241
242 String pathParts[] = StringUtils.splitPreserveAllTokens( requestedPath, '/' );
243 return pathParts.length == 3;
244 }
245
246 /**
247 * Adjust the requestedPath to conform to the native layout of the provided {@link org.apache.archiva.repository.ManagedRepositoryContent}.
248 *
249 * @param requestedPath the incoming requested path.
250 * @return the adjusted (to native) path.
251 * @throws LayoutException if the path cannot be parsed.
252 */
253 public String toNativePath( String requestedPath)
254 throws LayoutException
255 {
256 if ( StringUtils.isBlank( requestedPath ) )
257 {
258 throw new LayoutException( "Request Path is blank." );
259 }
260
261 String referencedResource = requestedPath;
262 // No checksum by default.
263 String supportfile = "";
264
265 // Figure out support file, and actual referencedResource.
266 if ( isSupportFile( requestedPath ) )
267 {
268 int idx = requestedPath.lastIndexOf( '.' );
269 referencedResource = requestedPath.substring( 0, idx );
270 supportfile = requestedPath.substring( idx );
271 }
272
273 if ( isMetadata( referencedResource ) )
274 {
275 /* Nothing to translate.
276 * Default layout is the only layout that can contain maven-metadata.xml files, and
277 * if the managedRepository is layout legacy, this request would never occur.
278 */
279 return requestedPath;
280 }
281
282 // Treat as an artifact reference.
283 ArtifactReference ref = toArtifactReference( referencedResource );
284 String adjustedPath = repository.getContent().toPath( ref );
285 return adjustedPath + supportfile;
286 }
287
288 @Override
289 public <T extends RepositoryFeature<T>> RepositoryFeature<T> getFeature(Class<T> clazz) throws UnsupportedFeatureException {
290 return null;
291 }
292
293 @Override
294 public <T extends RepositoryFeature<T>> boolean supportsFeature(Class<T> clazz) {
295 return false;
296 }
297 }