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