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