View Javadoc
1   package org.eclipse.aether.repository;
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 java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.Collections;
25  import java.util.List;
26  import static java.util.Objects.requireNonNull;
27  
28  import java.util.Objects;
29  import java.util.regex.Matcher;
30  import java.util.regex.Pattern;
31  
32  /**
33   * A repository on a remote server.
34   */
35  public final class RemoteRepository
36      implements ArtifactRepository
37  {
38  
39      private static final Pattern URL_PATTERN =
40          Pattern.compile( "([^:/]+(:[^:/]{2,}+(?=://))?):(//([^@/]*@)?([^/:]+))?.*" );
41  
42      private final String id;
43  
44      private final String type;
45  
46      private final String url;
47  
48      private final String host;
49  
50      private final String protocol;
51  
52      private final RepositoryPolicy releasePolicy;
53  
54      private final RepositoryPolicy snapshotPolicy;
55  
56      private final Proxy proxy;
57  
58      private final Authentication authentication;
59  
60      private final List<RemoteRepository> mirroredRepositories;
61  
62      private final boolean repositoryManager;
63  
64      private final boolean blocked;
65  
66      RemoteRepository( Builder builder )
67      {
68          if ( builder.prototype != null )
69          {
70              id = ( builder.delta & Builder.ID ) != 0 ? builder.id : builder.prototype.id;
71              type = ( builder.delta & Builder.TYPE ) != 0 ? builder.type : builder.prototype.type;
72              url = ( builder.delta & Builder.URL ) != 0 ? builder.url : builder.prototype.url;
73              releasePolicy =
74                  ( builder.delta & Builder.RELEASES ) != 0 ? builder.releasePolicy : builder.prototype.releasePolicy;
75              snapshotPolicy =
76                  ( builder.delta & Builder.SNAPSHOTS ) != 0 ? builder.snapshotPolicy : builder.prototype.snapshotPolicy;
77              proxy = ( builder.delta & Builder.PROXY ) != 0 ? builder.proxy : builder.prototype.proxy;
78              authentication =
79                  ( builder.delta & Builder.AUTH ) != 0 ? builder.authentication : builder.prototype.authentication;
80              repositoryManager =
81                  ( builder.delta & Builder.REPOMAN ) != 0 ? builder.repositoryManager
82                                  : builder.prototype.repositoryManager;
83              blocked = ( builder.delta & Builder.BLOCKED ) != 0 ? builder.blocked : builder.prototype.blocked;
84              mirroredRepositories =
85                  ( builder.delta & Builder.MIRRORED ) != 0 ? copy( builder.mirroredRepositories )
86                                  : builder.prototype.mirroredRepositories;
87          }
88          else
89          {
90              id = builder.id;
91              type = builder.type;
92              url = builder.url;
93              releasePolicy = builder.releasePolicy;
94              snapshotPolicy = builder.snapshotPolicy;
95              proxy = builder.proxy;
96              authentication = builder.authentication;
97              repositoryManager = builder.repositoryManager;
98              blocked = builder.blocked;
99              mirroredRepositories = copy( builder.mirroredRepositories );
100         }
101 
102         Matcher m = URL_PATTERN.matcher( url );
103         if ( m.matches() )
104         {
105             protocol = m.group( 1 );
106             String host = m.group( 5 );
107             this.host = ( host != null ) ? host : "";
108         }
109         else
110         {
111             protocol = "";
112             host = "";
113         }
114     }
115 
116     private static List<RemoteRepository> copy( List<RemoteRepository> repos )
117     {
118         if ( repos == null || repos.isEmpty() )
119         {
120             return Collections.emptyList();
121         }
122         return Collections.unmodifiableList( Arrays.asList( repos.toArray( new RemoteRepository[repos.size()] ) ) );
123     }
124 
125     public String getId()
126     {
127         return id;
128     }
129 
130     public String getContentType()
131     {
132         return type;
133     }
134 
135     /**
136      * Gets the (base) URL of this repository.
137      * 
138      * @return The (base) URL of this repository, never {@code null}.
139      */
140     public String getUrl()
141     {
142         return url;
143     }
144 
145     /**
146      * Gets the protocol part from the repository's URL, for example {@code file} or {@code http}. As suggested by RFC
147      * 2396, section 3.1 "Scheme Component", the protocol name should be treated case-insensitively.
148      * 
149      * @return The protocol or an empty string if none, never {@code null}.
150      */
151     public String getProtocol()
152     {
153         return protocol;
154     }
155 
156     /**
157      * Gets the host part from the repository's URL.
158      * 
159      * @return The host or an empty string if none, never {@code null}.
160      */
161     public String getHost()
162     {
163         return host;
164     }
165 
166     /**
167      * Gets the policy to apply for snapshot/release artifacts.
168      * 
169      * @param snapshot {@code true} to retrieve the snapshot policy, {@code false} to retrieve the release policy.
170      * @return The requested repository policy, never {@code null}.
171      */
172     public RepositoryPolicy getPolicy( boolean snapshot )
173     {
174         return snapshot ? snapshotPolicy : releasePolicy;
175     }
176 
177     /**
178      * Gets the proxy that has been selected for this repository.
179      * 
180      * @return The selected proxy or {@code null} if none.
181      */
182     public Proxy getProxy()
183     {
184         return proxy;
185     }
186 
187     /**
188      * Gets the authentication that has been selected for this repository.
189      * 
190      * @return The selected authentication or {@code null} if none.
191      */
192     public Authentication getAuthentication()
193     {
194         return authentication;
195     }
196 
197     /**
198      * Gets the repositories that this repository serves as a mirror for.
199      * 
200      * @return The (read-only) repositories being mirrored by this repository, never {@code null}.
201      */
202     public List<RemoteRepository> getMirroredRepositories()
203     {
204         return mirroredRepositories;
205     }
206 
207     /**
208      * Indicates whether this repository refers to a repository manager or not.
209      * 
210      * @return {@code true} if this repository is a repository manager, {@code false} otherwise.
211      */
212     public boolean isRepositoryManager()
213     {
214         return repositoryManager;
215     }
216 
217     /**
218      * Indicates whether this repository is blocked from performing any download requests.
219      * 
220      * @return {@code true} if this repository is blocked from performing any download requests,
221      *         {@code false} otherwise.
222      */
223     public boolean isBlocked()
224     {
225         return blocked;
226     }
227 
228     @Override
229     public String toString()
230     {
231         StringBuilder buffer = new StringBuilder( 256 );
232         buffer.append( getId() );
233         buffer.append( " (" ).append( getUrl() );
234         buffer.append( ", " ).append( getContentType() );
235         boolean r = getPolicy( false ).isEnabled(), s = getPolicy( true ).isEnabled();
236         if ( r && s )
237         {
238             buffer.append( ", releases+snapshots" );
239         }
240         else if ( r )
241         {
242             buffer.append( ", releases" );
243         }
244         else if ( s )
245         {
246             buffer.append( ", snapshots" );
247         }
248         else
249         {
250             buffer.append( ", disabled" );
251         }
252         if ( isRepositoryManager() )
253         {
254             buffer.append( ", managed" );
255         }
256         if ( isBlocked() )
257         {
258             buffer.append( ", blocked" );
259         }
260         buffer.append( ")" );
261         return buffer.toString();
262     }
263 
264     @Override
265     public boolean equals( Object obj )
266     {
267         if ( this == obj )
268         {
269             return true;
270         }
271         if ( obj == null || !getClass().equals( obj.getClass() ) )
272         {
273             return false;
274         }
275 
276         RemoteRepository that = (RemoteRepository) obj;
277 
278         return Objects.equals( url, that.url ) && Objects.equals( type, that.type )
279                 && Objects.equals( id, that.id ) && Objects.equals( releasePolicy, that.releasePolicy )
280                 && Objects.equals( snapshotPolicy, that.snapshotPolicy ) && Objects.equals( proxy, that.proxy )
281                 && Objects.equals( authentication, that.authentication )
282                 && Objects.equals( mirroredRepositories, that.mirroredRepositories )
283                 && repositoryManager == that.repositoryManager;
284     }
285 
286     @Override
287     public int hashCode()
288     {
289         int hash = 17;
290         hash = hash * 31 + hash( url );
291         hash = hash * 31 + hash( type );
292         hash = hash * 31 + hash( id );
293         hash = hash * 31 + hash( releasePolicy );
294         hash = hash * 31 + hash( snapshotPolicy );
295         hash = hash * 31 + hash( proxy );
296         hash = hash * 31 + hash( authentication );
297         hash = hash * 31 + hash( mirroredRepositories );
298         hash = hash * 31 + ( repositoryManager ? 1 : 0 );
299         return hash;
300     }
301 
302     private static int hash( Object obj )
303     {
304         return obj != null ? obj.hashCode() : 0;
305     }
306 
307     /**
308      * A builder to create remote repositories.
309      */
310     public static final class Builder
311     {
312 
313         private static final RepositoryPolicy DEFAULT_POLICY = new RepositoryPolicy();
314 
315         static final int ID = 0x0001, TYPE = 0x0002, URL = 0x0004, RELEASES = 0x0008, SNAPSHOTS = 0x0010,
316                         PROXY = 0x0020, AUTH = 0x0040, MIRRORED = 0x0080, REPOMAN = 0x0100, BLOCKED = 0x0200;
317 
318         int delta;
319 
320         RemoteRepository prototype;
321 
322         String id;
323 
324         String type;
325 
326         String url;
327 
328         RepositoryPolicy releasePolicy = DEFAULT_POLICY;
329 
330         RepositoryPolicy snapshotPolicy = DEFAULT_POLICY;
331 
332         Proxy proxy;
333 
334         Authentication authentication;
335 
336         List<RemoteRepository> mirroredRepositories;
337 
338         boolean repositoryManager;
339 
340         boolean blocked;
341 
342         /**
343          * Creates a new repository builder.
344          * 
345          * @param id The identifier of the repository, may be {@code null}.
346          * @param type The type of the repository, may be {@code null}.
347          * @param url The (base) URL of the repository, may be {@code null}.
348          */
349         public Builder( String id, String type, String url )
350         {
351             this.id = ( id != null ) ? id : "";
352             this.type = ( type != null ) ? type : "";
353             this.url = ( url != null ) ? url : "";
354         }
355 
356         /**
357          * Creates a new repository builder which uses the specified remote repository as a prototype for the new one.
358          * All properties which have not been set on the builder will be copied from the prototype when building the
359          * repository.
360          *
361          * @param prototype The remote repository to use as prototype, must not be {@code null}.
362          */
363         public Builder( RemoteRepository prototype )
364         {
365             this.prototype = requireNonNull( prototype, "remote repository prototype cannot be null" );
366         }
367 
368         /**
369          * Builds a new remote repository from the current values of this builder. The state of the builder itself
370          * remains unchanged.
371          *
372          * @return The remote repository, never {@code null}.
373          */
374         public RemoteRepository build()
375         {
376             if ( prototype != null && delta == 0 )
377             {
378                 return prototype;
379             }
380             return new RemoteRepository( this );
381         }
382 
383         private <T> void delta( int flag, T builder, T prototype )
384         {
385             boolean equal = Objects.equals( builder, prototype );
386             if ( equal )
387             {
388                 delta &= ~flag;
389             }
390             else
391             {
392                 delta |= flag;
393             }
394         }
395 
396         /**
397          * Sets the identifier of the repository.
398          * 
399          * @param id The identifier of the repository, may be {@code null}.
400          * @return This builder for chaining, never {@code null}.
401          */
402         public Builder setId( String id )
403         {
404             this.id = ( id != null ) ? id : "";
405             if ( prototype != null )
406             {
407                 delta( ID, this.id, prototype.getId() );
408             }
409             return this;
410         }
411 
412         /**
413          * Sets the type of the repository, e.g. "default".
414          * 
415          * @param type The type of the repository, may be {@code null}.
416          * @return This builder for chaining, never {@code null}.
417          */
418         public Builder setContentType( String type )
419         {
420             this.type = ( type != null ) ? type : "";
421             if ( prototype != null )
422             {
423                 delta( TYPE, this.type, prototype.getContentType() );
424             }
425             return this;
426         }
427 
428         /**
429          * Sets the (base) URL of the repository.
430          * 
431          * @param url The URL of the repository, may be {@code null}.
432          * @return This builder for chaining, never {@code null}.
433          */
434         public Builder setUrl( String url )
435         {
436             this.url = ( url != null ) ? url : "";
437             if ( prototype != null )
438             {
439                 delta( URL, this.url, prototype.getUrl() );
440             }
441             return this;
442         }
443 
444         /**
445          * Sets the policy to apply for snapshot and release artifacts.
446          * 
447          * @param policy The repository policy to set, may be {@code null} to use a default policy.
448          * @return This builder for chaining, never {@code null}.
449          */
450         public Builder setPolicy( RepositoryPolicy policy )
451         {
452             this.releasePolicy = ( policy != null ) ? policy : DEFAULT_POLICY;
453             this.snapshotPolicy = ( policy != null ) ? policy : DEFAULT_POLICY;
454             if ( prototype != null )
455             {
456                 delta( RELEASES, this.releasePolicy, prototype.getPolicy( false ) );
457                 delta( SNAPSHOTS, this.snapshotPolicy, prototype.getPolicy( true ) );
458             }
459             return this;
460         }
461 
462         /**
463          * Sets the policy to apply for release artifacts.
464          * 
465          * @param releasePolicy The repository policy to set, may be {@code null} to use a default policy.
466          * @return This builder for chaining, never {@code null}.
467          */
468         public Builder setReleasePolicy( RepositoryPolicy releasePolicy )
469         {
470             this.releasePolicy = ( releasePolicy != null ) ? releasePolicy : DEFAULT_POLICY;
471             if ( prototype != null )
472             {
473                 delta( RELEASES, this.releasePolicy, prototype.getPolicy( false ) );
474             }
475             return this;
476         }
477 
478         /**
479          * Sets the policy to apply for snapshot artifacts.
480          * 
481          * @param snapshotPolicy The repository policy to set, may be {@code null} to use a default policy.
482          * @return This builder for chaining, never {@code null}.
483          */
484         public Builder setSnapshotPolicy( RepositoryPolicy snapshotPolicy )
485         {
486             this.snapshotPolicy = ( snapshotPolicy != null ) ? snapshotPolicy : DEFAULT_POLICY;
487             if ( prototype != null )
488             {
489                 delta( SNAPSHOTS, this.snapshotPolicy, prototype.getPolicy( true ) );
490             }
491             return this;
492         }
493 
494         /**
495          * Sets the proxy to use in order to access the repository.
496          * 
497          * @param proxy The proxy to use, may be {@code null}.
498          * @return This builder for chaining, never {@code null}.
499          */
500         public Builder setProxy( Proxy proxy )
501         {
502             this.proxy = proxy;
503             if ( prototype != null )
504             {
505                 delta( PROXY, this.proxy, prototype.getProxy() );
506             }
507             return this;
508         }
509 
510         /**
511          * Sets the authentication to use in order to access the repository.
512          * 
513          * @param authentication The authentication to use, may be {@code null}.
514          * @return This builder for chaining, never {@code null}.
515          */
516         public Builder setAuthentication( Authentication authentication )
517         {
518             this.authentication = authentication;
519             if ( prototype != null )
520             {
521                 delta( AUTH, this.authentication, prototype.getAuthentication() );
522             }
523             return this;
524         }
525 
526         /**
527          * Sets the repositories being mirrored by the repository.
528          * 
529          * @param mirroredRepositories The repositories being mirrored by the repository, may be {@code null}.
530          * @return This builder for chaining, never {@code null}.
531          */
532         public Builder setMirroredRepositories( List<RemoteRepository> mirroredRepositories )
533         {
534             if ( this.mirroredRepositories == null )
535             {
536                 this.mirroredRepositories = new ArrayList<>();
537             }
538             else
539             {
540                 this.mirroredRepositories.clear();
541             }
542             if ( mirroredRepositories != null )
543             {
544                 this.mirroredRepositories.addAll( mirroredRepositories );
545             }
546             if ( prototype != null )
547             {
548                 delta( MIRRORED, this.mirroredRepositories, prototype.getMirroredRepositories() );
549             }
550             return this;
551         }
552 
553         /**
554          * Adds the specified repository to the list of repositories being mirrored by the repository. If this builder
555          * was {@link Builder constructed from a prototype}, the given repository
556          * will be added to the list of mirrored repositories from the prototype.
557          * 
558          * @param mirroredRepository The repository being mirrored by the repository, may be {@code null}.
559          * @return This builder for chaining, never {@code null}.
560          */
561         public Builder addMirroredRepository( RemoteRepository mirroredRepository )
562         {
563             if ( mirroredRepository != null )
564             {
565                 if ( this.mirroredRepositories == null )
566                 {
567                     this.mirroredRepositories = new ArrayList<>();
568                     if ( prototype != null )
569                     {
570                         mirroredRepositories.addAll( prototype.getMirroredRepositories() );
571                     }
572                 }
573                 mirroredRepositories.add( mirroredRepository );
574                 if ( prototype != null )
575                 {
576                     delta |= MIRRORED;
577                 }
578             }
579             return this;
580         }
581 
582         /**
583          * Marks the repository as a repository manager or not.
584          * 
585          * @param repositoryManager {@code true} if the repository points at a repository manager, {@code false} if the
586          *            repository is just serving static contents.
587          * @return This builder for chaining, never {@code null}.
588          */
589         public Builder setRepositoryManager( boolean repositoryManager )
590         {
591             this.repositoryManager = repositoryManager;
592             if ( prototype != null )
593             {
594                 delta( REPOMAN, this.repositoryManager, prototype.isRepositoryManager() );
595             }
596             return this;
597         }
598 
599 
600         /**
601          * Marks the repository as blocked or not.
602          * 
603          * @param blocked {@code true} if the repository should not be allowed to perform any requests.
604          * @return This builder for chaining, never {@code null}.
605          */
606         public Builder setBlocked( boolean blocked )
607         {
608             this.blocked = blocked;
609             if ( prototype != null )
610             {
611                 delta( BLOCKED, this.blocked, prototype.isBlocked() );
612             }
613             return this;
614         }
615     }
616 
617 }