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