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 java.util.regex.Matcher;
27  import java.util.regex.Pattern;
28  
29  /**
30   * A repository on a remote server.
31   */
32  public final class RemoteRepository
33      implements ArtifactRepository
34  {
35  
36      private static final Pattern URL_PATTERN =
37          Pattern.compile( "([^:/]+(:[^:/]{2,}+(?=://))?):(//([^@/]*@)?([^/:]+))?.*" );
38  
39      private final String id;
40  
41      private final String type;
42  
43      private final String url;
44  
45      private final String host;
46  
47      private final String protocol;
48  
49      private final RepositoryPolicy releasePolicy;
50  
51      private final RepositoryPolicy snapshotPolicy;
52  
53      private final Proxy proxy;
54  
55      private final Authentication authentication;
56  
57      private final List<RemoteRepository> mirroredRepositories;
58  
59      private final boolean repositoryManager;
60  
61      RemoteRepository( Builder builder )
62      {
63          if ( builder.prototype != null )
64          {
65              id = ( builder.delta & Builder.ID ) != 0 ? builder.id : builder.prototype.id;
66              type = ( builder.delta & Builder.TYPE ) != 0 ? builder.type : builder.prototype.type;
67              url = ( builder.delta & Builder.URL ) != 0 ? builder.url : builder.prototype.url;
68              releasePolicy =
69                  ( builder.delta & Builder.RELEASES ) != 0 ? builder.releasePolicy : builder.prototype.releasePolicy;
70              snapshotPolicy =
71                  ( builder.delta & Builder.SNAPSHOTS ) != 0 ? builder.snapshotPolicy : builder.prototype.snapshotPolicy;
72              proxy = ( builder.delta & Builder.PROXY ) != 0 ? builder.proxy : builder.prototype.proxy;
73              authentication =
74                  ( builder.delta & Builder.AUTH ) != 0 ? builder.authentication : builder.prototype.authentication;
75              repositoryManager =
76                  ( builder.delta & Builder.REPOMAN ) != 0 ? builder.repositoryManager
77                                  : builder.prototype.repositoryManager;
78              mirroredRepositories =
79                  ( builder.delta & Builder.MIRRORED ) != 0 ? copy( builder.mirroredRepositories )
80                                  : builder.prototype.mirroredRepositories;
81          }
82          else
83          {
84              id = builder.id;
85              type = builder.type;
86              url = builder.url;
87              releasePolicy = builder.releasePolicy;
88              snapshotPolicy = builder.snapshotPolicy;
89              proxy = builder.proxy;
90              authentication = builder.authentication;
91              repositoryManager = builder.repositoryManager;
92              mirroredRepositories = copy( builder.mirroredRepositories );
93          }
94  
95          Matcher m = URL_PATTERN.matcher( url );
96          if ( m.matches() )
97          {
98              protocol = m.group( 1 );
99              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 }