001package 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 022import java.io.File; 023import java.util.Collections; 024import java.util.List; 025 026import org.apache.maven.artifact.Artifact; 027import org.apache.maven.artifact.metadata.ArtifactMetadata; 028import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; 029import org.apache.maven.repository.Proxy; 030 031//TODO: completely separate local and remote artifact repositories 032public 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}