001package org.eclipse.aether.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.util.ArrayList; 023import java.util.Arrays; 024import java.util.Collections; 025import java.util.List; 026import java.util.regex.Matcher; 027import java.util.regex.Pattern; 028 029/** 030 * A repository on a remote server. 031 */ 032public final class RemoteRepository 033 implements ArtifactRepository 034{ 035 036 private static final Pattern URL_PATTERN = 037 Pattern.compile( "([^:/]+(:[^:/]{2,}+(?=://))?):(//([^@/]*@)?([^/:]+))?.*" ); 038 039 private final String id; 040 041 private final String type; 042 043 private final String url; 044 045 private final String host; 046 047 private final String protocol; 048 049 private final RepositoryPolicy releasePolicy; 050 051 private final RepositoryPolicy snapshotPolicy; 052 053 private final Proxy proxy; 054 055 private final Authentication authentication; 056 057 private final List<RemoteRepository> mirroredRepositories; 058 059 private final boolean repositoryManager; 060 061 RemoteRepository( Builder builder ) 062 { 063 if ( builder.prototype != null ) 064 { 065 id = ( builder.delta & Builder.ID ) != 0 ? builder.id : builder.prototype.id; 066 type = ( builder.delta & Builder.TYPE ) != 0 ? builder.type : builder.prototype.type; 067 url = ( builder.delta & Builder.URL ) != 0 ? builder.url : builder.prototype.url; 068 releasePolicy = 069 ( builder.delta & Builder.RELEASES ) != 0 ? builder.releasePolicy : builder.prototype.releasePolicy; 070 snapshotPolicy = 071 ( builder.delta & Builder.SNAPSHOTS ) != 0 ? builder.snapshotPolicy : builder.prototype.snapshotPolicy; 072 proxy = ( builder.delta & Builder.PROXY ) != 0 ? builder.proxy : builder.prototype.proxy; 073 authentication = 074 ( builder.delta & Builder.AUTH ) != 0 ? builder.authentication : builder.prototype.authentication; 075 repositoryManager = 076 ( builder.delta & Builder.REPOMAN ) != 0 ? builder.repositoryManager 077 : builder.prototype.repositoryManager; 078 mirroredRepositories = 079 ( builder.delta & Builder.MIRRORED ) != 0 ? copy( builder.mirroredRepositories ) 080 : builder.prototype.mirroredRepositories; 081 } 082 else 083 { 084 id = builder.id; 085 type = builder.type; 086 url = builder.url; 087 releasePolicy = builder.releasePolicy; 088 snapshotPolicy = builder.snapshotPolicy; 089 proxy = builder.proxy; 090 authentication = builder.authentication; 091 repositoryManager = builder.repositoryManager; 092 mirroredRepositories = copy( builder.mirroredRepositories ); 093 } 094 095 Matcher m = URL_PATTERN.matcher( url ); 096 if ( m.matches() ) 097 { 098 protocol = m.group( 1 ); 099 String host = m.group( 5 ); 100 this.host = ( host != null ) ? host : ""; 101 } 102 else 103 { 104 protocol = host = ""; 105 } 106 } 107 108 private static List<RemoteRepository> copy( List<RemoteRepository> repos ) 109 { 110 if ( repos == null || repos.isEmpty() ) 111 { 112 return Collections.emptyList(); 113 } 114 return Collections.unmodifiableList( Arrays.asList( repos.toArray( new RemoteRepository[repos.size()] ) ) ); 115 } 116 117 public String getId() 118 { 119 return id; 120 } 121 122 public String getContentType() 123 { 124 return type; 125 } 126 127 /** 128 * Gets the (base) URL of this repository. 129 * 130 * @return The (base) URL of this repository, never {@code null}. 131 */ 132 public String getUrl() 133 { 134 return url; 135 } 136 137 /** 138 * Gets the protocol part from the repository's URL, for example {@code file} or {@code http}. As suggested by RFC 139 * 2396, section 3.1 "Scheme Component", the protocol name should be treated case-insensitively. 140 * 141 * @return The protocol or an empty string if none, never {@code null}. 142 */ 143 public String getProtocol() 144 { 145 return protocol; 146 } 147 148 /** 149 * Gets the host part from the repository's URL. 150 * 151 * @return The host or an empty string if none, never {@code null}. 152 */ 153 public String getHost() 154 { 155 return host; 156 } 157 158 /** 159 * Gets the policy to apply for snapshot/release artifacts. 160 * 161 * @param snapshot {@code true} to retrieve the snapshot policy, {@code false} to retrieve the release policy. 162 * @return The requested repository policy, never {@code null}. 163 */ 164 public RepositoryPolicy getPolicy( boolean snapshot ) 165 { 166 return snapshot ? snapshotPolicy : releasePolicy; 167 } 168 169 /** 170 * Gets the proxy that has been selected for this repository. 171 * 172 * @return The selected proxy or {@code null} if none. 173 */ 174 public Proxy getProxy() 175 { 176 return proxy; 177 } 178 179 /** 180 * Gets the authentication that has been selected for this repository. 181 * 182 * @return The selected authentication or {@code null} if none. 183 */ 184 public Authentication getAuthentication() 185 { 186 return authentication; 187 } 188 189 /** 190 * Gets the repositories that this repository serves as a mirror for. 191 * 192 * @return The (read-only) repositories being mirrored by this repository, never {@code null}. 193 */ 194 public List<RemoteRepository> getMirroredRepositories() 195 { 196 return mirroredRepositories; 197 } 198 199 /** 200 * Indicates whether this repository refers to a repository manager or not. 201 * 202 * @return {@code true} if this repository is a repository manager, {@code false} otherwise. 203 */ 204 public boolean isRepositoryManager() 205 { 206 return repositoryManager; 207 } 208 209 @Override 210 public String toString() 211 { 212 StringBuilder buffer = new StringBuilder( 256 ); 213 buffer.append( getId() ); 214 buffer.append( " (" ).append( getUrl() ); 215 buffer.append( ", " ).append( getContentType() ); 216 boolean r = getPolicy( false ).isEnabled(), s = getPolicy( true ).isEnabled(); 217 if ( r && s ) 218 { 219 buffer.append( ", releases+snapshots" ); 220 } 221 else if ( r ) 222 { 223 buffer.append( ", releases" ); 224 } 225 else if ( s ) 226 { 227 buffer.append( ", snapshots" ); 228 } 229 else 230 { 231 buffer.append( ", disabled" ); 232 } 233 if ( isRepositoryManager() ) 234 { 235 buffer.append( ", managed" ); 236 } 237 buffer.append( ")" ); 238 return buffer.toString(); 239 } 240 241 @Override 242 public boolean equals( Object obj ) 243 { 244 if ( this == obj ) 245 { 246 return true; 247 } 248 if ( obj == null || !getClass().equals( obj.getClass() ) ) 249 { 250 return false; 251 } 252 253 RemoteRepository that = (RemoteRepository) obj; 254 255 return eq( url, that.url ) && eq( type, that.type ) && eq( id, that.id ) 256 && eq( releasePolicy, that.releasePolicy ) && eq( snapshotPolicy, that.snapshotPolicy ) 257 && eq( proxy, that.proxy ) && eq( authentication, that.authentication ) 258 && eq( mirroredRepositories, that.mirroredRepositories ) && repositoryManager == that.repositoryManager; 259 } 260 261 private static <T> boolean eq( T s1, T s2 ) 262 { 263 return s1 != null ? s1.equals( s2 ) : s2 == null; 264 } 265 266 @Override 267 public int hashCode() 268 { 269 int hash = 17; 270 hash = hash * 31 + hash( url ); 271 hash = hash * 31 + hash( type ); 272 hash = hash * 31 + hash( id ); 273 hash = hash * 31 + hash( releasePolicy ); 274 hash = hash * 31 + hash( snapshotPolicy ); 275 hash = hash * 31 + hash( proxy ); 276 hash = hash * 31 + hash( authentication ); 277 hash = hash * 31 + hash( mirroredRepositories ); 278 hash = hash * 31 + ( repositoryManager ? 1 : 0 ); 279 return hash; 280 } 281 282 private static int hash( Object obj ) 283 { 284 return obj != null ? obj.hashCode() : 0; 285 } 286 287 /** 288 * A builder to create remote repositories. 289 */ 290 public static final class Builder 291 { 292 293 private static final RepositoryPolicy DEFAULT_POLICY = new RepositoryPolicy(); 294 295 static final int ID = 0x0001, TYPE = 0x0002, URL = 0x0004, RELEASES = 0x0008, SNAPSHOTS = 0x0010, 296 PROXY = 0x0020, AUTH = 0x0040, MIRRORED = 0x0080, REPOMAN = 0x0100; 297 298 int delta; 299 300 RemoteRepository prototype; 301 302 String id; 303 304 String type; 305 306 String url; 307 308 RepositoryPolicy releasePolicy = DEFAULT_POLICY; 309 310 RepositoryPolicy snapshotPolicy = DEFAULT_POLICY; 311 312 Proxy proxy; 313 314 Authentication authentication; 315 316 List<RemoteRepository> mirroredRepositories; 317 318 boolean repositoryManager; 319 320 /** 321 * Creates a new repository builder. 322 * 323 * @param id The identifier of the repository, may be {@code null}. 324 * @param type The type of the repository, may be {@code null}. 325 * @param url The (base) URL of the repository, may be {@code null}. 326 */ 327 public Builder( String id, String type, String url ) 328 { 329 this.id = ( id != null ) ? id : ""; 330 this.type = ( type != null ) ? type : ""; 331 this.url = ( url != null ) ? url : ""; 332 } 333 334 /** 335 * Creates a new repository builder which uses the specified remote repository as a prototype for the new one. 336 * All properties which have not been set on the builder will be copied from the prototype when building the 337 * repository. 338 * 339 * @param prototype The remote repository to use as prototype, must not be {@code null}. 340 */ 341 public Builder( RemoteRepository prototype ) 342 { 343 if ( prototype == null ) 344 { 345 throw new IllegalArgumentException( "repository prototype missing" ); 346 } 347 this.prototype = prototype; 348 } 349 350 /** 351 * Builds a new remote repository from the current values of this builder. The state of the builder itself 352 * remains unchanged. 353 * 354 * @return The remote repository, never {@code null}. 355 */ 356 public RemoteRepository build() 357 { 358 if ( prototype != null && delta == 0 ) 359 { 360 return prototype; 361 } 362 return new RemoteRepository( this ); 363 } 364 365 private <T> void delta( int flag, T builder, T prototype ) 366 { 367 boolean equal = ( builder != null ) ? builder.equals( prototype ) : prototype == null; 368 if ( equal ) 369 { 370 delta &= ~flag; 371 } 372 else 373 { 374 delta |= flag; 375 } 376 } 377 378 /** 379 * Sets the identifier of the repository. 380 * 381 * @param id The identifier of the repository, may be {@code null}. 382 * @return This builder for chaining, never {@code null}. 383 */ 384 public Builder setId( String id ) 385 { 386 this.id = ( id != null ) ? id : ""; 387 if ( prototype != null ) 388 { 389 delta( ID, this.id, prototype.getId() ); 390 } 391 return this; 392 } 393 394 /** 395 * Sets the type of the repository, e.g. "default". 396 * 397 * @param type The type of the repository, may be {@code null}. 398 * @return This builder for chaining, never {@code null}. 399 */ 400 public Builder setContentType( String type ) 401 { 402 this.type = ( type != null ) ? type : ""; 403 if ( prototype != null ) 404 { 405 delta( TYPE, this.type, prototype.getContentType() ); 406 } 407 return this; 408 } 409 410 /** 411 * Sets the (base) URL of the repository. 412 * 413 * @param url The URL of the repository, may be {@code null}. 414 * @return This builder for chaining, never {@code null}. 415 */ 416 public Builder setUrl( String url ) 417 { 418 this.url = ( url != null ) ? url : ""; 419 if ( prototype != null ) 420 { 421 delta( URL, this.url, prototype.getUrl() ); 422 } 423 return this; 424 } 425 426 /** 427 * Sets the policy to apply for snapshot and release artifacts. 428 * 429 * @param policy The repository policy to set, may be {@code null} to use a default policy. 430 * @return This builder for chaining, never {@code null}. 431 */ 432 public Builder setPolicy( RepositoryPolicy policy ) 433 { 434 this.releasePolicy = this.snapshotPolicy = ( policy != null ) ? policy : DEFAULT_POLICY; 435 if ( prototype != null ) 436 { 437 delta( RELEASES, this.releasePolicy, prototype.getPolicy( false ) ); 438 delta( SNAPSHOTS, this.snapshotPolicy, prototype.getPolicy( true ) ); 439 } 440 return this; 441 } 442 443 /** 444 * Sets the policy to apply for release artifacts. 445 * 446 * @param releasePolicy The repository policy to set, may be {@code null} to use a default policy. 447 * @return This builder for chaining, never {@code null}. 448 */ 449 public Builder setReleasePolicy( RepositoryPolicy releasePolicy ) 450 { 451 this.releasePolicy = ( releasePolicy != null ) ? releasePolicy : DEFAULT_POLICY; 452 if ( prototype != null ) 453 { 454 delta( RELEASES, this.releasePolicy, prototype.getPolicy( false ) ); 455 } 456 return this; 457 } 458 459 /** 460 * Sets the policy to apply for snapshot artifacts. 461 * 462 * @param snapshotPolicy The repository policy to set, may be {@code null} to use a default policy. 463 * @return This builder for chaining, never {@code null}. 464 */ 465 public Builder setSnapshotPolicy( RepositoryPolicy snapshotPolicy ) 466 { 467 this.snapshotPolicy = ( snapshotPolicy != null ) ? snapshotPolicy : DEFAULT_POLICY; 468 if ( prototype != null ) 469 { 470 delta( SNAPSHOTS, this.snapshotPolicy, prototype.getPolicy( true ) ); 471 } 472 return this; 473 } 474 475 /** 476 * Sets the proxy to use in order to access the repository. 477 * 478 * @param proxy The proxy to use, may be {@code null}. 479 * @return This builder for chaining, never {@code null}. 480 */ 481 public Builder setProxy( Proxy proxy ) 482 { 483 this.proxy = proxy; 484 if ( prototype != null ) 485 { 486 delta( PROXY, this.proxy, prototype.getProxy() ); 487 } 488 return this; 489 } 490 491 /** 492 * Sets the authentication to use in order to access the repository. 493 * 494 * @param authentication The authentication to use, may be {@code null}. 495 * @return This builder for chaining, never {@code null}. 496 */ 497 public Builder setAuthentication( Authentication authentication ) 498 { 499 this.authentication = authentication; 500 if ( prototype != null ) 501 { 502 delta( AUTH, this.authentication, prototype.getAuthentication() ); 503 } 504 return this; 505 } 506 507 /** 508 * Sets the repositories being mirrored by the repository. 509 * 510 * @param mirroredRepositories The repositories being mirrored by the repository, may be {@code null}. 511 * @return This builder for chaining, never {@code null}. 512 */ 513 public Builder setMirroredRepositories( List<RemoteRepository> mirroredRepositories ) 514 { 515 if ( this.mirroredRepositories == null ) 516 { 517 this.mirroredRepositories = new ArrayList<RemoteRepository>(); 518 } 519 else 520 { 521 this.mirroredRepositories.clear(); 522 } 523 if ( mirroredRepositories != null ) 524 { 525 this.mirroredRepositories.addAll( mirroredRepositories ); 526 } 527 if ( prototype != null ) 528 { 529 delta( MIRRORED, this.mirroredRepositories, prototype.getMirroredRepositories() ); 530 } 531 return this; 532 } 533 534 /** 535 * Adds the specified repository to the list of repositories being mirrored by the repository. If this builder 536 * was {@link #RemoteRepository.Builder(RemoteRepository) constructed from a prototype}, the given repository 537 * will be added to the list of mirrored repositories from the prototype. 538 * 539 * @param mirroredRepository The repository being mirrored by the repository, may be {@code null}. 540 * @return This builder for chaining, never {@code null}. 541 */ 542 public Builder addMirroredRepository( RemoteRepository mirroredRepository ) 543 { 544 if ( mirroredRepository != null ) 545 { 546 if ( this.mirroredRepositories == null ) 547 { 548 this.mirroredRepositories = new ArrayList<RemoteRepository>(); 549 if ( prototype != null ) 550 { 551 mirroredRepositories.addAll( prototype.getMirroredRepositories() ); 552 } 553 } 554 mirroredRepositories.add( mirroredRepository ); 555 if ( prototype != null ) 556 { 557 delta |= MIRRORED; 558 } 559 } 560 return this; 561 } 562 563 /** 564 * Marks the repository as a repository manager or not. 565 * 566 * @param repositoryManager {@code true} if the repository points at a repository manager, {@code false} if the 567 * repository is just serving static contents. 568 * @return This builder for chaining, never {@code null}. 569 */ 570 public Builder setRepositoryManager( boolean repositoryManager ) 571 { 572 this.repositoryManager = repositoryManager; 573 if ( prototype != null ) 574 { 575 delta( REPOMAN, this.repositoryManager, prototype.isRepositoryManager() ); 576 } 577 return this; 578 } 579 580 } 581 582}