View Javadoc
1   package org.apache.maven.artifact.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.io.File;
23  import java.util.Collections;
24  import java.util.List;
25  import java.util.Objects;
26  
27  import org.apache.maven.artifact.Artifact;
28  import org.apache.maven.artifact.metadata.ArtifactMetadata;
29  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
30  import org.apache.maven.repository.Proxy;
31  
32  /**
33   * Abstraction of an artifact repository. Artifact repositories can be remote, local, or even build reactor or
34   * IDE workspace.
35   */
36  //TODO completely separate local and remote artifact repositories
37  public class MavenArtifactRepository
38      implements ArtifactRepository
39  {
40      private static final String LS = System.lineSeparator();
41  
42      private String id;
43  
44      private String url;
45  
46      private String basedir;
47  
48      private String protocol;
49  
50      private ArtifactRepositoryLayout layout;
51  
52      private ArtifactRepositoryPolicy snapshots;
53  
54      private ArtifactRepositoryPolicy releases;
55  
56      private Authentication authentication;
57  
58      private Proxy proxy;
59  
60      private List<ArtifactRepository> mirroredRepositories = Collections.emptyList();
61  
62      private boolean blocked;
63  
64      public MavenArtifactRepository()
65      {
66      }
67  
68      /**
69       * Create a remote download repository.
70       *
71       * @param id        the unique identifier of the repository
72       * @param url       the URL of the repository
73       * @param layout    the layout of the repository
74       * @param snapshots the policies to use for snapshots
75       * @param releases  the policies to use for releases
76       */
77      public MavenArtifactRepository( String id, String url, ArtifactRepositoryLayout layout,
78                                      ArtifactRepositoryPolicy snapshots, ArtifactRepositoryPolicy releases )
79      {
80          this.id = id;
81          this.url = url;
82          this.layout = layout;
83          this.snapshots = snapshots;
84          this.releases = releases;
85          //
86          // Derive these from the URL
87          //
88          this.protocol = protocol( url );
89          this.basedir = basedir( url );
90      }
91  
92      public String pathOf( Artifact artifact )
93      {
94          return layout.pathOf( artifact );
95      }
96  
97      public String pathOfRemoteRepositoryMetadata( ArtifactMetadata artifactMetadata )
98      {
99          return layout.pathOfRemoteRepositoryMetadata( artifactMetadata );
100     }
101 
102     public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
103     {
104         return layout.pathOfLocalRepositoryMetadata( metadata, repository );
105     }
106 
107     public void setLayout( ArtifactRepositoryLayout layout )
108     {
109         this.layout = layout;
110     }
111 
112     public ArtifactRepositoryLayout getLayout()
113     {
114         return layout;
115     }
116 
117     public void setSnapshotUpdatePolicy( ArtifactRepositoryPolicy snapshots )
118     {
119         this.snapshots = snapshots;
120     }
121 
122     public ArtifactRepositoryPolicy getSnapshots()
123     {
124         return snapshots;
125     }
126 
127     public void setReleaseUpdatePolicy( ArtifactRepositoryPolicy releases )
128     {
129         this.releases = releases;
130     }
131 
132     public ArtifactRepositoryPolicy getReleases()
133     {
134         return releases;
135     }
136 
137     public String getKey()
138     {
139         return getId();
140     }
141 
142     public String toString()
143     {
144         StringBuilder sb = new StringBuilder( 256 );
145 
146         sb.append( "      id: " ).append( getId() ).append( LS );
147         sb.append( "      url: " ).append( getUrl() ).append( LS );
148         sb.append( "   layout: " ).append( layout != null ? layout : "none" );
149 
150         if ( proxy != null )
151         {
152             sb.append( LS ).append( "    proxy: " ).append( proxy.getHost() ).append( ':' ).append( proxy.getPort() );
153         }
154 
155         if ( snapshots != null )
156         {
157             sb.append( LS ).append( "snapshots: [enabled => " ).append( snapshots.isEnabled() );
158             sb.append( ", update => " ).append( snapshots.getUpdatePolicy() ).append( ']' );
159         }
160 
161         if ( releases != null )
162         {
163             sb.append( LS ).append( "releases: [enabled => " ).append( releases.isEnabled() );
164             sb.append( ", update => " ).append( releases.getUpdatePolicy() ).append( ']' );
165         }
166 
167         sb.append( "   blocked: " ).append( isBlocked() ).append( '\n' );
168 
169         return sb.toString();
170     }
171 
172     public Artifact find( Artifact artifact )
173     {
174         File artifactFile = new File( getBasedir(), pathOf( artifact ) );
175 
176         // We need to set the file here or the resolver will fail with an NPE, not fully equipped to deal
177         // with multiple local repository implementations yet.
178         artifact.setFile( artifactFile );
179 
180         return artifact;
181     }
182 
183     public List<String> findVersions( Artifact artifact )
184     {
185         return Collections.emptyList();
186     }
187 
188     public String getId()
189     {
190         return id;
191     }
192 
193     public String getUrl()
194     {
195         return url;
196     }
197 
198     public String getBasedir()
199     {
200         return basedir;
201     }
202 
203     public String getProtocol()
204     {
205         return protocol;
206     }
207 
208     public void setId( String id )
209     {
210         this.id = id;
211     }
212 
213     public void setUrl( String url )
214     {
215         this.url = url;
216 
217         this.protocol = protocol( url );
218         this.basedir = basedir( url );
219     }
220 
221     // Path Utils
222 
223     /**
224      * Return the protocol name.
225      * <br>
226      * E.g: for input
227      * <code>http://www.codehaus.org</code> this method will return <code>http</code>
228      *
229      * @param url the url
230      * @return the host name
231      */
232     private static String protocol( final String url )
233     {
234         final int pos = url.indexOf( ':' );
235 
236         if ( pos == -1 )
237         {
238             return "";
239         }
240         return url.substring( 0, pos ).trim();
241     }
242 
243     /**
244      * Derive the path portion of the given URL.
245      *
246      * @param url the repository URL
247      * @return the basedir of the repository
248      * TODO need to URL decode for spaces?
249      */
250     private String basedir( String url )
251     {
252         String retValue = null;
253 
254         if ( protocol.equalsIgnoreCase( "file" ) )
255         {
256             retValue = url.substring( protocol.length() + 1 );
257             retValue = decode( retValue );
258             // special case: if omitted // on protocol, keep path as is
259             if ( retValue.startsWith( "//" ) )
260             {
261                 retValue = retValue.substring( 2 );
262 
263                 if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
264                 {
265                     // special case: if there is a windows drive letter, then keep the original return value
266                     retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
267                 }
268                 else
269                 {
270                     // Now we expect the host
271                     int index = retValue.indexOf( '/' );
272                     if ( index >= 0 )
273                     {
274                         retValue = retValue.substring( index + 1 );
275                     }
276 
277                     // special case: if there is a windows drive letter, then keep the original return value
278                     if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
279                     {
280                         retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
281                     }
282                     else if ( index >= 0 )
283                     {
284                         // leading / was previously stripped
285                         retValue = "/" + retValue;
286                     }
287                 }
288             }
289 
290             // special case: if there is a windows drive letter using |, switch to :
291             if ( retValue.length() >= 2 && retValue.charAt( 1 ) == '|' )
292             {
293                 retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
294             }
295 
296             // normalize separators
297             retValue = new File( retValue ).getPath();
298         }
299 
300         if ( retValue == null )
301         {
302             retValue = "/";
303         }
304         return retValue.trim();
305     }
306 
307     /**
308      * Decodes the specified (portion of a) URL. <strong>Note:</strong> This decoder assumes that ISO-8859-1 is used to
309      * convert URL-encoded bytes to characters.
310      *
311      * @param url The URL to decode, may be <code>null</code>.
312      * @return The decoded URL or <code>null</code> if the input was <code>null</code>.
313      */
314     private static String decode( String url )
315     {
316         String decoded = url;
317         if ( url != null )
318         {
319             int pos = -1;
320             while ( ( pos = decoded.indexOf( '%', pos + 1 ) ) >= 0 )
321             {
322                 if ( pos + 2 < decoded.length() )
323                 {
324                     String hexStr = decoded.substring( pos + 1, pos + 3 );
325                     char ch = (char) Integer.parseInt( hexStr, 16 );
326                     decoded = decoded.substring( 0, pos ) + ch + decoded.substring( pos + 3 );
327                 }
328             }
329         }
330         return decoded;
331     }
332 
333     public int hashCode()
334     {
335         final int prime = 31;
336         int result = 1;
337         result = prime * result + ( ( getId() == null ) ? 0 : getId().hashCode() );
338         return result;
339     }
340 
341     public boolean equals( Object obj )
342     {
343         if ( this == obj )
344         {
345             return true;
346         }
347         if ( obj == null )
348         {
349             return false;
350         }
351         if ( getClass() != obj.getClass() )
352         {
353             return false;
354         }
355 
356         ArtifactRepository other = (ArtifactRepository) obj;
357 
358         return eq( getId(), other.getId() );
359     }
360 
361     protected static <T> boolean eq( T s1, T s2 )
362     {
363         return Objects.equals( s1, s2 );
364     }
365 
366     public Authentication getAuthentication()
367     {
368         return authentication;
369     }
370 
371     public void setAuthentication( Authentication authentication )
372     {
373         this.authentication = authentication;
374     }
375 
376     public Proxy getProxy()
377     {
378         return proxy;
379     }
380 
381     public void setProxy( Proxy proxy )
382     {
383         this.proxy = proxy;
384     }
385 
386     public boolean isBlacklisted()
387     {
388         return false;
389     }
390 
391     public void setBlacklisted( boolean blackListed )
392     {
393         // no op
394     }
395 
396     public boolean isUniqueVersion()
397     {
398         return true;
399     }
400 
401     public boolean isProjectAware()
402     {
403         return false;
404     }
405 
406     public List<ArtifactRepository> getMirroredRepositories()
407     {
408         return mirroredRepositories;
409     }
410 
411     public void setMirroredRepositories( List<ArtifactRepository> mirroredRepositories )
412     {
413         if ( mirroredRepositories != null )
414         {
415             this.mirroredRepositories = Collections.unmodifiableList( mirroredRepositories );
416         }
417         else
418         {
419             this.mirroredRepositories = Collections.emptyList();
420         }
421     }
422 
423     public boolean isBlocked()
424     {
425         return blocked;
426     }
427 
428     public void setBlocked( boolean blocked )
429     {
430         this.blocked = blocked;
431     }
432 
433 }