View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.artifact.repository;
20  
21  import java.io.File;
22  import java.util.Collections;
23  import java.util.List;
24  import java.util.Objects;
25  
26  import org.apache.maven.artifact.Artifact;
27  import org.apache.maven.artifact.metadata.ArtifactMetadata;
28  import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
29  import org.apache.maven.repository.Proxy;
30  
31  /**
32   * Abstraction of an artifact repository. Artifact repositories can be remote, local, or even build reactor or
33   * IDE workspace.
34   */
35  // TODO completely separate local and remote artifact repositories
36  public class MavenArtifactRepository implements ArtifactRepository {
37      private String id;
38  
39      private String url;
40  
41      private String basedir;
42  
43      private String protocol;
44  
45      private ArtifactRepositoryLayout layout;
46  
47      private ArtifactRepositoryPolicy snapshots;
48  
49      private ArtifactRepositoryPolicy releases;
50  
51      private Authentication authentication;
52  
53      private Proxy proxy;
54  
55      private List<ArtifactRepository> mirroredRepositories = Collections.emptyList();
56  
57      private boolean blocked;
58  
59      public MavenArtifactRepository() {}
60  
61      /**
62       * Create a remote download repository.
63       *
64       * @param id        the unique identifier of the repository
65       * @param url       the URL of the repository
66       * @param layout    the layout of the repository
67       * @param snapshots the policies to use for snapshots
68       * @param releases  the policies to use for releases
69       */
70      public MavenArtifactRepository(
71              String id,
72              String url,
73              ArtifactRepositoryLayout layout,
74              ArtifactRepositoryPolicy snapshots,
75              ArtifactRepositoryPolicy releases) {
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          return layout.pathOf(artifact);
90      }
91  
92      public String pathOfRemoteRepositoryMetadata(ArtifactMetadata artifactMetadata) {
93          return layout.pathOfRemoteRepositoryMetadata(artifactMetadata);
94      }
95  
96      public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
97          return layout.pathOfLocalRepositoryMetadata(metadata, repository);
98      }
99  
100     public void setLayout(ArtifactRepositoryLayout layout) {
101         this.layout = layout;
102     }
103 
104     public ArtifactRepositoryLayout getLayout() {
105         return layout;
106     }
107 
108     public void setSnapshotUpdatePolicy(ArtifactRepositoryPolicy snapshots) {
109         this.snapshots = snapshots;
110     }
111 
112     public ArtifactRepositoryPolicy getSnapshots() {
113         return snapshots;
114     }
115 
116     public void setReleaseUpdatePolicy(ArtifactRepositoryPolicy releases) {
117         this.releases = releases;
118     }
119 
120     public ArtifactRepositoryPolicy getReleases() {
121         return releases;
122     }
123 
124     public String getKey() {
125         return getId();
126     }
127 
128     public String toString() {
129         StringBuilder sb = new StringBuilder(256);
130 
131         sb.append("      id: ").append(getId()).append('\n');
132         sb.append("      url: ").append(getUrl()).append('\n');
133         sb.append("   layout: ").append(layout != null ? layout : "none").append('\n');
134 
135         if (proxy != null) {
136             sb.append("    proxy: ")
137                     .append(proxy.getHost())
138                     .append(':')
139                     .append(proxy.getPort())
140                     .append('\n');
141         }
142 
143         if (snapshots != null) {
144             sb.append("snapshots: [enabled => ").append(snapshots.isEnabled());
145             sb.append(", update => ").append(snapshots.getUpdatePolicy()).append("]\n");
146         }
147 
148         if (releases != null) {
149             sb.append(" releases: [enabled => ").append(releases.isEnabled());
150             sb.append(", update => ").append(releases.getUpdatePolicy()).append("]\n");
151         }
152 
153         sb.append("   blocked: ").append(isBlocked()).append('\n');
154 
155         return sb.toString();
156     }
157 
158     public Artifact find(Artifact artifact) {
159         File artifactFile = new File(getBasedir(), pathOf(artifact));
160 
161         // We need to set the file here or the resolver will fail with an NPE, not fully equipped to deal
162         // with multiple local repository implementations yet.
163         artifact.setFile(artifactFile);
164 
165         return artifact;
166     }
167 
168     public List<String> findVersions(Artifact artifact) {
169         return Collections.emptyList();
170     }
171 
172     public String getId() {
173         return id;
174     }
175 
176     public String getUrl() {
177         return url;
178     }
179 
180     public String getBasedir() {
181         return basedir;
182     }
183 
184     public String getProtocol() {
185         return protocol;
186     }
187 
188     public void setId(String id) {
189         this.id = id;
190     }
191 
192     public void setUrl(String url) {
193         this.url = url;
194 
195         this.protocol = protocol(url);
196         this.basedir = basedir(url);
197     }
198 
199     // Path Utils
200 
201     /**
202      * Return the protocol name.
203      * <br>
204      * E.g: for input
205      * <code>http://www.codehaus.org</code> this method will return <code>http</code>
206      *
207      * @param url the url
208      * @return the host name
209      */
210     private static String protocol(final String url) {
211         final int pos = url.indexOf(':');
212 
213         if (pos == -1) {
214             return "";
215         }
216         return url.substring(0, pos).trim();
217     }
218 
219     /**
220      * Derive the path portion of the given URL.
221      *
222      * @param url the repository URL
223      * @return the basedir of the repository
224      * TODO need to URL decode for spaces?
225      */
226     private String basedir(String url) {
227         String retValue = null;
228 
229         if (protocol.equalsIgnoreCase("file")) {
230             retValue = url.substring(protocol.length() + 1);
231             retValue = decode(retValue);
232             // special case: if omitted // on protocol, keep path as is
233             if (retValue.startsWith("//")) {
234                 retValue = retValue.substring(2);
235 
236                 if (retValue.length() >= 2 && (retValue.charAt(1) == '|' || retValue.charAt(1) == ':')) {
237                     // special case: if there is a windows drive letter, then keep the original return value
238                     retValue = retValue.charAt(0) + ":" + retValue.substring(2);
239                 } else {
240                     // Now we expect the host
241                     int index = retValue.indexOf('/');
242                     if (index >= 0) {
243                         retValue = retValue.substring(index + 1);
244                     }
245 
246                     // special case: if there is a windows drive letter, then keep the original return value
247                     if (retValue.length() >= 2 && (retValue.charAt(1) == '|' || retValue.charAt(1) == ':')) {
248                         retValue = retValue.charAt(0) + ":" + retValue.substring(2);
249                     } else if (index >= 0) {
250                         // leading / was previously stripped
251                         retValue = "/" + retValue;
252                     }
253                 }
254             }
255 
256             // special case: if there is a windows drive letter using |, switch to :
257             if (retValue.length() >= 2 && retValue.charAt(1) == '|') {
258                 retValue = retValue.charAt(0) + ":" + retValue.substring(2);
259             }
260 
261             // normalize separators
262             retValue = new File(retValue).getPath();
263         }
264 
265         if (retValue == null) {
266             retValue = "/";
267         }
268         return retValue.trim();
269     }
270 
271     /**
272      * Decodes the specified (portion of a) URL. <strong>Note:</strong> This decoder assumes that ISO-8859-1 is used to
273      * convert URL-encoded bytes to characters.
274      *
275      * @param url The URL to decode, may be <code>null</code>.
276      * @return The decoded URL or <code>null</code> if the input was <code>null</code>.
277      */
278     private static String decode(String url) {
279         String decoded = url;
280         if (url != null) {
281             int pos = -1;
282             while ((pos = decoded.indexOf('%', pos + 1)) >= 0) {
283                 if (pos + 2 < decoded.length()) {
284                     String hexStr = decoded.substring(pos + 1, pos + 3);
285                     char ch = (char) Integer.parseInt(hexStr, 16);
286                     decoded = decoded.substring(0, pos) + ch + decoded.substring(pos + 3);
287                 }
288             }
289         }
290         return decoded;
291     }
292 
293     public int hashCode() {
294         final int prime = 31;
295         int result = 1;
296         result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
297         return result;
298     }
299 
300     public boolean equals(Object obj) {
301         if (this == obj) {
302             return true;
303         }
304         if (obj == null) {
305             return false;
306         }
307         if (getClass() != obj.getClass()) {
308             return false;
309         }
310 
311         ArtifactRepository other = (ArtifactRepository) obj;
312 
313         return eq(getId(), other.getId());
314     }
315 
316     protected static <T> boolean eq(T s1, T s2) {
317         return Objects.equals(s1, s2);
318     }
319 
320     public Authentication getAuthentication() {
321         return authentication;
322     }
323 
324     public void setAuthentication(Authentication authentication) {
325         this.authentication = authentication;
326     }
327 
328     public Proxy getProxy() {
329         return proxy;
330     }
331 
332     public void setProxy(Proxy proxy) {
333         this.proxy = proxy;
334     }
335 
336     public boolean isBlacklisted() {
337         return false;
338     }
339 
340     public void setBlacklisted(boolean blackListed) {
341         // no op
342     }
343 
344     public boolean isUniqueVersion() {
345         return true;
346     }
347 
348     public boolean isProjectAware() {
349         return false;
350     }
351 
352     public List<ArtifactRepository> getMirroredRepositories() {
353         return mirroredRepositories;
354     }
355 
356     public void setMirroredRepositories(List<ArtifactRepository> mirroredRepositories) {
357         if (mirroredRepositories != null) {
358             this.mirroredRepositories = Collections.unmodifiableList(mirroredRepositories);
359         } else {
360             this.mirroredRepositories = Collections.emptyList();
361         }
362     }
363 
364     public boolean isBlocked() {
365         return blocked;
366     }
367 
368     public void setBlocked(boolean blocked) {
369         this.blocked = blocked;
370     }
371 }