001 package org.apache.maven.artifact.repository;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import java.io.File;
023 import java.util.Collections;
024 import java.util.List;
025
026 import org.apache.maven.artifact.Artifact;
027 import org.apache.maven.artifact.metadata.ArtifactMetadata;
028 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
029 import org.apache.maven.repository.Proxy;
030
031 //TODO: completely separate local and remote artifact repositories
032 public class MavenArtifactRepository
033 implements ArtifactRepository
034 {
035 private String id;
036
037 private String url;
038
039 private String basedir;
040
041 private String protocol;
042
043 private ArtifactRepositoryLayout layout;
044
045 private ArtifactRepositoryPolicy snapshots;
046
047 private ArtifactRepositoryPolicy releases;
048
049 private Authentication authentication;
050
051 private Proxy proxy;
052
053 private List<ArtifactRepository> mirroredRepositories = Collections.emptyList();
054
055 public MavenArtifactRepository()
056 {
057 }
058
059 /**
060 * Create a remote download repository.
061 *
062 * @param id the unique identifier of the repository
063 * @param url the URL of the repository
064 * @param layout the layout of the repository
065 * @param snapshots the policies to use for snapshots
066 * @param releases the policies to use for releases
067 */
068 public MavenArtifactRepository( String id, String url, ArtifactRepositoryLayout layout,
069 ArtifactRepositoryPolicy snapshots, ArtifactRepositoryPolicy releases )
070 {
071 this.id = id;
072 this.url = url;
073 this.layout = layout;
074 this.snapshots = snapshots;
075 this.releases = releases;
076 //
077 // Derive these from the URL
078 //
079 this.protocol = protocol( url );
080 this.basedir = basedir( url );
081 }
082
083 public String pathOf( Artifact artifact )
084 {
085 return layout.pathOf( artifact );
086 }
087
088 public String pathOfRemoteRepositoryMetadata( ArtifactMetadata artifactMetadata )
089 {
090 return layout.pathOfRemoteRepositoryMetadata( artifactMetadata );
091 }
092
093 public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
094 {
095 return layout.pathOfLocalRepositoryMetadata( metadata, repository );
096 }
097
098 public void setLayout( ArtifactRepositoryLayout layout )
099 {
100 this.layout = layout;
101 }
102
103 public ArtifactRepositoryLayout getLayout()
104 {
105 return layout;
106 }
107
108 public void setSnapshotUpdatePolicy( ArtifactRepositoryPolicy snapshots )
109 {
110 this.snapshots = snapshots;
111 }
112
113 public ArtifactRepositoryPolicy getSnapshots()
114 {
115 return snapshots;
116 }
117
118 public void setReleaseUpdatePolicy( ArtifactRepositoryPolicy releases )
119 {
120 this.releases = releases;
121 }
122
123 public ArtifactRepositoryPolicy getReleases()
124 {
125 return releases;
126 }
127
128 public String getKey()
129 {
130 return getId();
131 }
132
133 public String toString()
134 {
135 StringBuilder sb = new StringBuilder();
136
137 sb.append( " id: " ).append( getId() ).append( "\n" );
138 sb.append( " url: " ).append( getUrl() ).append( "\n" );
139 sb.append( " layout: " ).append( layout != null ? layout : "none" ).append( "\n" );
140
141 if ( snapshots != null )
142 {
143 sb.append( "snapshots: [enabled => " ).append( snapshots.isEnabled() );
144 sb.append( ", update => " ).append( snapshots.getUpdatePolicy() ).append( "]\n" );
145 }
146
147 if ( releases != null )
148 {
149 sb.append( " releases: [enabled => " ).append( releases.isEnabled() );
150 sb.append( ", update => " ).append( releases.getUpdatePolicy() ).append( "]\n" );
151 }
152
153 return sb.toString();
154 }
155
156 public Artifact find( Artifact artifact )
157 {
158 File artifactFile = new File( getBasedir(), pathOf( artifact ) );
159
160 // We need to set the file here or the resolver will fail with an NPE, not fully equipped to deal
161 // with multiple local repository implementations yet.
162 artifact.setFile( artifactFile );
163
164 return artifact;
165 }
166
167 public List<String> findVersions( Artifact artifact )
168 {
169 return Collections.emptyList();
170 }
171
172 public String getId()
173 {
174 return id;
175 }
176
177 public String getUrl()
178 {
179 return url;
180 }
181
182 public String getBasedir()
183 {
184 return basedir;
185 }
186
187 public String getProtocol()
188 {
189 return protocol;
190 }
191
192 public void setId( String id )
193 {
194 this.id = id;
195 }
196
197 public void setUrl( String url )
198 {
199 this.url = url;
200
201 this.protocol = protocol( url );
202 this.basedir = basedir( url );
203 }
204
205 // Path Utils
206
207 /**
208 * Return the protocol name.
209 * <br/>
210 * E.g: for input
211 * <code>http://www.codehause.org</code> this method will return <code>http</code>
212 *
213 * @param url the url
214 * @return the host name
215 */
216 private static String protocol( final String url )
217 {
218 final int pos = url.indexOf( ":" );
219
220 if ( pos == -1 )
221 {
222 return "";
223 }
224 return url.substring( 0, pos ).trim();
225 }
226
227 /**
228 * Derive the path portion of the given URL.
229 *
230 * @param url the repository URL
231 * @return the basedir of the repository
232 * @todo need to URL decode for spaces?
233 */
234 private String basedir( String url )
235 {
236 String retValue = null;
237
238 if ( protocol.equalsIgnoreCase( "file" ) )
239 {
240 retValue = url.substring( protocol.length() + 1 );
241 retValue = decode( retValue );
242 // special case: if omitted // on protocol, keep path as is
243 if ( retValue.startsWith( "//" ) )
244 {
245 retValue = retValue.substring( 2 );
246
247 if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
248 {
249 // special case: if there is a windows drive letter, then keep the original return value
250 retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
251 }
252 else
253 {
254 // Now we expect the host
255 int index = retValue.indexOf( "/" );
256 if ( index >= 0 )
257 {
258 retValue = retValue.substring( index + 1 );
259 }
260
261 // special case: if there is a windows drive letter, then keep the original return value
262 if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
263 {
264 retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
265 }
266 else if ( index >= 0 )
267 {
268 // leading / was previously stripped
269 retValue = "/" + retValue;
270 }
271 }
272 }
273
274 // special case: if there is a windows drive letter using |, switch to :
275 if ( retValue.length() >= 2 && retValue.charAt( 1 ) == '|' )
276 {
277 retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
278 }
279
280 // normalize separators
281 retValue = new File( retValue ).getPath();
282 }
283
284 if ( retValue == null )
285 {
286 retValue = "/";
287 }
288 return retValue.trim();
289 }
290
291 /**
292 * Decodes the specified (portion of a) URL. <strong>Note:</strong> This decoder assumes that ISO-8859-1 is used to
293 * convert URL-encoded bytes to characters.
294 *
295 * @param url The URL to decode, may be <code>null</code>.
296 * @return The decoded URL or <code>null</code> if the input was <code>null</code>.
297 */
298 private static String decode( String url )
299 {
300 String decoded = url;
301 if ( url != null )
302 {
303 int pos = -1;
304 while ( ( pos = decoded.indexOf( '%', pos + 1 ) ) >= 0 )
305 {
306 if ( pos + 2 < decoded.length() )
307 {
308 String hexStr = decoded.substring( pos + 1, pos + 3 );
309 char ch = (char) Integer.parseInt( hexStr, 16 );
310 decoded = decoded.substring( 0, pos ) + ch + decoded.substring( pos + 3 );
311 }
312 }
313 }
314 return decoded;
315 }
316
317 public int hashCode()
318 {
319 final int prime = 31;
320 int result = 1;
321 result = prime * result + ( ( getId() == null ) ? 0 : getId().hashCode() );
322 return result;
323 }
324
325 public boolean equals( Object obj )
326 {
327 if ( this == obj )
328 {
329 return true;
330 }
331 if ( obj == null )
332 {
333 return false;
334 }
335 if ( getClass() != obj.getClass() )
336 {
337 return false;
338 }
339
340 ArtifactRepository other = (ArtifactRepository) obj;
341
342 return eq( getId(), other.getId() );
343 }
344
345 protected static <T> boolean eq( T s1, T s2 )
346 {
347 return s1 != null ? s1.equals( s2 ) : s2 == null;
348 }
349
350 public Authentication getAuthentication()
351 {
352 return authentication;
353 }
354
355 public void setAuthentication( Authentication authentication )
356 {
357 this.authentication = authentication;
358 }
359
360 public Proxy getProxy()
361 {
362 return proxy;
363 }
364
365 public void setProxy( Proxy proxy )
366 {
367 this.proxy = proxy;
368 }
369
370 public boolean isBlacklisted()
371 {
372 return false;
373 }
374
375 public void setBlacklisted( boolean blackListed )
376 {
377 // no op
378 }
379
380 public boolean isUniqueVersion()
381 {
382 return true;
383 }
384
385 public boolean isProjectAware()
386 {
387 return false;
388 }
389
390 public List<ArtifactRepository> getMirroredRepositories()
391 {
392 return mirroredRepositories;
393 }
394
395 public void setMirroredRepositories( List<ArtifactRepository> mirroredRepositories )
396 {
397 if ( mirroredRepositories != null )
398 {
399 this.mirroredRepositories = mirroredRepositories;
400 }
401 else
402 {
403 this.mirroredRepositories = Collections.emptyList();
404 }
405 }
406
407 }