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