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.eclipse.aether.internal.impl;
20  
21  import org.eclipse.aether.RepositorySystemSession;
22  import org.eclipse.aether.artifact.Artifact;
23  import org.eclipse.aether.metadata.Metadata;
24  import org.eclipse.aether.repository.RemoteRepository;
25  import org.eclipse.aether.repository.RepositoryKeyFunction;
26  import org.eclipse.aether.util.ConfigUtils;
27  import org.eclipse.aether.util.PathUtils;
28  
29  /**
30   * Support class for {@link LocalPathPrefixComposerFactory} implementations: it predefines and makes re-usable
31   * common configuration getters, and defines a support class for {@link LocalPathPrefixComposer} carrying same
32   * configuration and providing default implementation for all methods.
33   * <p>
34   * Implementors should extend this class to implement custom split strategies. If one needs to alter default
35   * configuration, they should override any configuration getter from this class.
36   *
37   * @see DefaultLocalPathPrefixComposerFactory
38   * @since 1.8.1
39   */
40  public abstract class LocalPathPrefixComposerFactorySupport implements LocalPathPrefixComposerFactory {
41  
42      /**
43       * Whether LRM should split local and remote artifacts.
44       *
45       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
46       * @configurationType {@link java.lang.Boolean}
47       * @configurationDefaultValue {@link #DEFAULT_SPLIT}
48       */
49      public static final String CONFIG_PROP_SPLIT = EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "split";
50  
51      public static final boolean DEFAULT_SPLIT = false;
52  
53      /**
54       * The prefix to use for locally installed artifacts.
55       *
56       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
57       * @configurationType {@link java.lang.String}
58       * @configurationDefaultValue {@link #DEFAULT_LOCAL_PREFIX}
59       */
60      public static final String CONFIG_PROP_LOCAL_PREFIX =
61              EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "localPrefix";
62  
63      public static final String DEFAULT_LOCAL_PREFIX = "installed";
64  
65      /**
66       * Whether locally installed artifacts should be split by version (release/snapshot).
67       *
68       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
69       * @configurationType {@link java.lang.Boolean}
70       * @configurationDefaultValue {@link #DEFAULT_SPLIT_LOCAL}
71       */
72      public static final String CONFIG_PROP_SPLIT_LOCAL =
73              EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "splitLocal";
74  
75      public static final boolean DEFAULT_SPLIT_LOCAL = false;
76  
77      /**
78       * The prefix to use for remotely cached artifacts.
79       *
80       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
81       * @configurationType {@link java.lang.String}
82       * @configurationDefaultValue {@link #DEFAULT_REMOTE_PREFIX}
83       */
84      public static final String CONFIG_PROP_REMOTE_PREFIX =
85              EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "remotePrefix";
86  
87      public static final String DEFAULT_REMOTE_PREFIX = "cached";
88  
89      /**
90       * Whether cached artifacts should be split by version (release/snapshot).
91       *
92       * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
93       * @configurationType {@link java.lang.Boolean}
94       * @configurationDefaultValue {@link #DEFAULT_SPLIT_REMOTE}
95       */
96      public static final String CONFIG_PROP_SPLIT_REMOTE =
97              EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "splitRemote";
98  
99      public static final boolean DEFAULT_SPLIT_REMOTE = false;
100 
101     /**
102      * Whether cached artifacts should be split by origin repository (repository ID).
103      *
104      * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
105      * @configurationType {@link java.lang.Boolean}
106      * @configurationDefaultValue {@link #DEFAULT_SPLIT_REMOTE_REPOSITORY}
107      */
108     public static final String CONFIG_PROP_SPLIT_REMOTE_REPOSITORY =
109             EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "splitRemoteRepository";
110 
111     public static final boolean DEFAULT_SPLIT_REMOTE_REPOSITORY = false;
112 
113     /**
114      * For cached artifacts, if both splitRemote and splitRemoteRepository are set to true sets the splitting order:
115      * by default it is repositoryId/version (false) or version/repositoryId (true)
116      *
117      * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
118      * @configurationType {@link java.lang.Boolean}
119      * @configurationDefaultValue {@link #DEFAULT_SPLIT_REMOTE_REPOSITORY_LAST}
120      */
121     public static final String CONFIG_PROP_SPLIT_REMOTE_REPOSITORY_LAST =
122             EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "splitRemoteRepositoryLast";
123 
124     public static final boolean DEFAULT_SPLIT_REMOTE_REPOSITORY_LAST = false;
125 
126     /**
127      * The prefix to use for release artifacts.
128      *
129      * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
130      * @configurationType {@link java.lang.String}
131      * @configurationDefaultValue {@link #DEFAULT_RELEASES_PREFIX}
132      */
133     public static final String CONFIG_PROP_RELEASES_PREFIX =
134             EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "releasesPrefix";
135 
136     public static final String DEFAULT_RELEASES_PREFIX = "releases";
137 
138     /**
139      * The prefix to use for snapshot artifacts.
140      *
141      * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
142      * @configurationType {@link java.lang.String}
143      * @configurationDefaultValue {@link #DEFAULT_SNAPSHOTS_PREFIX}
144      */
145     public static final String CONFIG_PROP_SNAPSHOTS_PREFIX =
146             EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "snapshotsPrefix";
147 
148     public static final String DEFAULT_SNAPSHOTS_PREFIX = "snapshots";
149 
150     // Legacy support: properties were renamed in Resolver 2.0.x, but we should support 1.9.x properties as well
151     // These below are Resolver 1.9.x properties, are undocumented and shall be removed with Resolver 2.1.x (or later).
152 
153     private static final String R1_CONF_PROP_SPLIT = "aether.enhancedLocalRepository.split";
154 
155     private static final String R1_CONF_PROP_LOCAL_PREFIX = "aether.enhancedLocalRepository.localPrefix";
156 
157     private static final String R1_CONF_PROP_SPLIT_LOCAL = "aether.enhancedLocalRepository.splitLocal";
158 
159     private static final String R1_CONF_PROP_REMOTE_PREFIX = "aether.enhancedLocalRepository.remotePrefix";
160 
161     private static final String R1_CONF_PROP_SPLIT_REMOTE = "aether.enhancedLocalRepository.splitRemote";
162 
163     private static final String R1_CONF_PROP_SPLIT_REMOTE_REPOSITORY =
164             "aether.enhancedLocalRepository.splitRemoteRepository";
165 
166     private static final String R1_CONF_PROP_SPLIT_REMOTE_REPOSITORY_LAST =
167             "aether.enhancedLocalRepository.splitRemoteRepositoryLast";
168 
169     private static final String R1_CONF_PROP_RELEASES_PREFIX = "aether.enhancedLocalRepository.releasesPrefix";
170 
171     private static final String R1_CONF_PROP_SNAPSHOTS_PREFIX = "aether.enhancedLocalRepository.snapshotsPrefix";
172 
173     protected boolean isSplit(RepositorySystemSession session) {
174         return ConfigUtils.getBoolean(session, DEFAULT_SPLIT, CONFIG_PROP_SPLIT, R1_CONF_PROP_SPLIT);
175     }
176 
177     protected String getLocalPrefix(RepositorySystemSession session) {
178         return ConfigUtils.getString(
179                 session, DEFAULT_LOCAL_PREFIX, CONFIG_PROP_LOCAL_PREFIX, R1_CONF_PROP_LOCAL_PREFIX);
180     }
181 
182     protected boolean isSplitLocal(RepositorySystemSession session) {
183         return ConfigUtils.getBoolean(session, DEFAULT_SPLIT_LOCAL, CONFIG_PROP_SPLIT_LOCAL, R1_CONF_PROP_SPLIT_LOCAL);
184     }
185 
186     protected String getRemotePrefix(RepositorySystemSession session) {
187         return ConfigUtils.getString(
188                 session, DEFAULT_REMOTE_PREFIX, CONFIG_PROP_REMOTE_PREFIX, R1_CONF_PROP_REMOTE_PREFIX);
189     }
190 
191     protected boolean isSplitRemote(RepositorySystemSession session) {
192         return ConfigUtils.getBoolean(
193                 session, DEFAULT_SPLIT_REMOTE, CONFIG_PROP_SPLIT_REMOTE, R1_CONF_PROP_SPLIT_REMOTE);
194     }
195 
196     protected boolean isSplitRemoteRepository(RepositorySystemSession session) {
197         return ConfigUtils.getBoolean(
198                 session,
199                 DEFAULT_SPLIT_REMOTE_REPOSITORY,
200                 CONFIG_PROP_SPLIT_REMOTE_REPOSITORY,
201                 R1_CONF_PROP_SPLIT_REMOTE_REPOSITORY);
202     }
203 
204     protected boolean isSplitRemoteRepositoryLast(RepositorySystemSession session) {
205         return ConfigUtils.getBoolean(
206                 session,
207                 DEFAULT_SPLIT_REMOTE_REPOSITORY_LAST,
208                 CONFIG_PROP_SPLIT_REMOTE_REPOSITORY_LAST,
209                 R1_CONF_PROP_SPLIT_REMOTE_REPOSITORY_LAST);
210     }
211 
212     protected String getReleasesPrefix(RepositorySystemSession session) {
213         return ConfigUtils.getString(
214                 session, DEFAULT_RELEASES_PREFIX, CONFIG_PROP_RELEASES_PREFIX, R1_CONF_PROP_RELEASES_PREFIX);
215     }
216 
217     protected String getSnapshotsPrefix(RepositorySystemSession session) {
218         return ConfigUtils.getString(
219                 session, DEFAULT_SNAPSHOTS_PREFIX, CONFIG_PROP_SNAPSHOTS_PREFIX, R1_CONF_PROP_SNAPSHOTS_PREFIX);
220     }
221 
222     /**
223      * Support class for composers: it defines protected members for all the predefined configuration values and
224      * provides default implementation for methods. Implementors may change it's behaviour by overriding methods.
225      */
226     @SuppressWarnings("checkstyle:parameternumber")
227     protected abstract static class LocalPathPrefixComposerSupport implements LocalPathPrefixComposer {
228         protected final boolean split;
229 
230         protected final String localPrefix;
231 
232         protected final boolean splitLocal;
233 
234         protected final String remotePrefix;
235 
236         protected final boolean splitRemote;
237 
238         protected final boolean splitRemoteRepository;
239 
240         protected final boolean splitRemoteRepositoryLast;
241 
242         protected final String releasesPrefix;
243 
244         protected final String snapshotsPrefix;
245 
246         protected final RepositoryKeyFunction repositoryKeyFunction;
247 
248         protected LocalPathPrefixComposerSupport(
249                 boolean split,
250                 String localPrefix,
251                 boolean splitLocal,
252                 String remotePrefix,
253                 boolean splitRemote,
254                 boolean splitRemoteRepository,
255                 boolean splitRemoteRepositoryLast,
256                 String releasesPrefix,
257                 String snapshotsPrefix,
258                 RepositoryKeyFunction repositoryKeyFunction) {
259             this.split = split;
260             this.localPrefix = localPrefix;
261             this.splitLocal = splitLocal;
262             this.remotePrefix = remotePrefix;
263             this.splitRemote = splitRemote;
264             this.splitRemoteRepository = splitRemoteRepository;
265             this.splitRemoteRepositoryLast = splitRemoteRepositoryLast;
266             this.releasesPrefix = releasesPrefix;
267             this.snapshotsPrefix = snapshotsPrefix;
268             this.repositoryKeyFunction = repositoryKeyFunction;
269         }
270 
271         @Override
272         public String getPathPrefixForLocalArtifact(Artifact artifact) {
273             if (!split) {
274                 return null;
275             }
276             String result = localPrefix;
277             if (splitLocal) {
278                 result += "/" + (artifact.isSnapshot() ? snapshotsPrefix : releasesPrefix);
279             }
280             return result;
281         }
282 
283         @Override
284         public String getPathPrefixForRemoteArtifact(Artifact artifact, RemoteRepository repository) {
285             if (!split) {
286                 return null;
287             }
288             String result = remotePrefix;
289             if (!splitRemoteRepositoryLast && splitRemoteRepository) {
290                 result += "/" + repositoryKeySegment(repository);
291             }
292             if (splitRemote) {
293                 result += "/" + (artifact.isSnapshot() ? snapshotsPrefix : releasesPrefix);
294             }
295             if (splitRemoteRepositoryLast && splitRemoteRepository) {
296                 result += "/" + repositoryKeySegment(repository);
297             }
298             return result;
299         }
300 
301         @Override
302         public String getPathPrefixForLocalMetadata(Metadata metadata) {
303             if (!split) {
304                 return null;
305             }
306             String result = localPrefix;
307             if (splitLocal) {
308                 result += "/" + (isSnapshot(metadata) ? snapshotsPrefix : releasesPrefix);
309             }
310             return result;
311         }
312 
313         @Override
314         public String getPathPrefixForRemoteMetadata(Metadata metadata, RemoteRepository repository) {
315             if (!split) {
316                 return null;
317             }
318             String result = remotePrefix;
319             if (!splitRemoteRepositoryLast && splitRemoteRepository) {
320                 result += "/" + repositoryKeySegment(repository);
321             }
322             if (splitRemote) {
323                 result += "/" + (isSnapshot(metadata) ? snapshotsPrefix : releasesPrefix);
324             }
325             if (splitRemoteRepositoryLast && splitRemoteRepository) {
326                 result += "/" + repositoryKeySegment(repository);
327             }
328             return result;
329         }
330 
331         protected boolean isSnapshot(Metadata metadata) {
332             return !metadata.getVersion().isEmpty() && metadata.getVersion().endsWith("-SNAPSHOT");
333         }
334 
335         /**
336          * Defense in depth: the repository key is spliced into the local repository path prefix, so it
337          * must be a safe path segment.
338          */
339         private String repositoryKeySegment(RemoteRepository repository) {
340             String key = repositoryKeyFunction.apply(repository, null);
341             PathUtils.validatePathComponent(key, "repository key");
342             return key;
343         }
344     }
345 }