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