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