001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.eclipse.aether.internal.impl;
020
021import java.util.function.Function;
022
023import org.eclipse.aether.RepositorySystemSession;
024import org.eclipse.aether.artifact.Artifact;
025import org.eclipse.aether.metadata.Metadata;
026import org.eclipse.aether.repository.ArtifactRepository;
027import org.eclipse.aether.repository.RemoteRepository;
028import org.eclipse.aether.util.ConfigUtils;
029
030/**
031 * Support class for {@link LocalPathPrefixComposerFactory} implementations: it predefines and makes re-usable
032 * common configuration getters, and defines a support class for {@link LocalPathPrefixComposer} carrying same
033 * configuration and providing default implementation for all methods.
034 * <p>
035 * Implementors should extend this class to implement custom split strategies. If one needs to alter default
036 * configuration, they should override any configuration getter from this class.
037 *
038 * @see DefaultLocalPathPrefixComposerFactory
039 * @since 1.8.1
040 */
041public abstract class LocalPathPrefixComposerFactorySupport implements LocalPathPrefixComposerFactory {
042
043    /**
044     * Whether LRM should split local and remote artifacts.
045     *
046     * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
047     * @configurationType {@link java.lang.Boolean}
048     * @configurationDefaultValue {@link #DEFAULT_SPLIT}
049     */
050    public static final String CONFIG_PROP_SPLIT = EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "split";
051
052    public static final boolean DEFAULT_SPLIT = false;
053
054    /**
055     * The prefix to use for locally installed artifacts.
056     *
057     * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
058     * @configurationType {@link java.lang.String}
059     * @configurationDefaultValue {@link #DEFAULT_LOCAL_PREFIX}
060     */
061    public static final String CONFIG_PROP_LOCAL_PREFIX =
062            EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "localPrefix";
063
064    public static final String DEFAULT_LOCAL_PREFIX = "installed";
065
066    /**
067     * Whether locally installed artifacts should be split by version (release/snapshot).
068     *
069     * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
070     * @configurationType {@link java.lang.Boolean}
071     * @configurationDefaultValue {@link #DEFAULT_SPLIT_LOCAL}
072     */
073    public static final String CONFIG_PROP_SPLIT_LOCAL =
074            EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "splitLocal";
075
076    public static final boolean DEFAULT_SPLIT_LOCAL = false;
077
078    /**
079     * The prefix to use for remotely cached artifacts.
080     *
081     * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
082     * @configurationType {@link java.lang.String}
083     * @configurationDefaultValue {@link #DEFAULT_REMOTE_PREFIX}
084     */
085    public static final String CONFIG_PROP_REMOTE_PREFIX =
086            EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "remotePrefix";
087
088    public static final String DEFAULT_REMOTE_PREFIX = "cached";
089
090    /**
091     * Whether cached artifacts should be split by version (release/snapshot).
092     *
093     * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
094     * @configurationType {@link java.lang.Boolean}
095     * @configurationDefaultValue {@link #DEFAULT_SPLIT_REMOTE}
096     */
097    public static final String CONFIG_PROP_SPLIT_REMOTE =
098            EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "splitRemote";
099
100    public static final boolean DEFAULT_SPLIT_REMOTE = false;
101
102    /**
103     * Whether cached artifacts should be split by origin repository (repository ID).
104     *
105     * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
106     * @configurationType {@link java.lang.Boolean}
107     * @configurationDefaultValue {@link #DEFAULT_SPLIT_REMOTE_REPOSITORY}
108     */
109    public static final String CONFIG_PROP_SPLIT_REMOTE_REPOSITORY =
110            EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "splitRemoteRepository";
111
112    public static final boolean DEFAULT_SPLIT_REMOTE_REPOSITORY = false;
113
114    /**
115     * For cached artifacts, if both splitRemote and splitRemoteRepository are set to true sets the splitting order:
116     * by default it is repositoryId/version (false) or version/repositoryId (true)
117     *
118     * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
119     * @configurationType {@link java.lang.Boolean}
120     * @configurationDefaultValue {@link #DEFAULT_SPLIT_REMOTE_REPOSITORY_LAST}
121     */
122    public static final String CONFIG_PROP_SPLIT_REMOTE_REPOSITORY_LAST =
123            EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "splitRemoteRepositoryLast";
124
125    public static final boolean DEFAULT_SPLIT_REMOTE_REPOSITORY_LAST = false;
126
127    /**
128     * The prefix to use for release artifacts.
129     *
130     * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
131     * @configurationType {@link java.lang.String}
132     * @configurationDefaultValue {@link #DEFAULT_RELEASES_PREFIX}
133     */
134    public static final String CONFIG_PROP_RELEASES_PREFIX =
135            EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "releasesPrefix";
136
137    public static final String DEFAULT_RELEASES_PREFIX = "releases";
138
139    /**
140     * The prefix to use for snapshot artifacts.
141     *
142     * @configurationSource {@link RepositorySystemSession#getConfigProperties()}
143     * @configurationType {@link java.lang.String}
144     * @configurationDefaultValue {@link #DEFAULT_SNAPSHOTS_PREFIX}
145     */
146    public static final String CONFIG_PROP_SNAPSHOTS_PREFIX =
147            EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "snapshotsPrefix";
148
149    public static final String DEFAULT_SNAPSHOTS_PREFIX = "snapshots";
150
151    // Legacy support: properties were renamed in Resolver 2.0.x, but we should support 1.9.x properties as well
152    // These below are Resolver 1.9.x properties, are undocumented and shall be removed with Resolver 2.1.x (or later).
153
154    private static final String R1_CONF_PROP_SPLIT = "aether.enhancedLocalRepository.split";
155
156    private static final String R1_CONF_PROP_LOCAL_PREFIX = "aether.enhancedLocalRepository.localPrefix";
157
158    private static final String R1_CONF_PROP_SPLIT_LOCAL = "aether.enhancedLocalRepository.splitLocal";
159
160    private static final String R1_CONF_PROP_REMOTE_PREFIX = "aether.enhancedLocalRepository.remotePrefix";
161
162    private static final String R1_CONF_PROP_SPLIT_REMOTE = "aether.enhancedLocalRepository.splitRemote";
163
164    private static final String R1_CONF_PROP_SPLIT_REMOTE_REPOSITORY =
165            "aether.enhancedLocalRepository.splitRemoteRepository";
166
167    private static final String R1_CONF_PROP_SPLIT_REMOTE_REPOSITORY_LAST =
168            "aether.enhancedLocalRepository.splitRemoteRepositoryLast";
169
170    private static final String R1_CONF_PROP_RELEASES_PREFIX = "aether.enhancedLocalRepository.releasesPrefix";
171
172    private static final String R1_CONF_PROP_SNAPSHOTS_PREFIX = "aether.enhancedLocalRepository.snapshotsPrefix";
173
174    protected boolean isSplit(RepositorySystemSession session) {
175        return ConfigUtils.getBoolean(session, DEFAULT_SPLIT, CONFIG_PROP_SPLIT, R1_CONF_PROP_SPLIT);
176    }
177
178    protected String getLocalPrefix(RepositorySystemSession session) {
179        return ConfigUtils.getString(
180                session, DEFAULT_LOCAL_PREFIX, CONFIG_PROP_LOCAL_PREFIX, R1_CONF_PROP_LOCAL_PREFIX);
181    }
182
183    protected boolean isSplitLocal(RepositorySystemSession session) {
184        return ConfigUtils.getBoolean(session, DEFAULT_SPLIT_LOCAL, CONFIG_PROP_SPLIT_LOCAL, R1_CONF_PROP_SPLIT_LOCAL);
185    }
186
187    protected String getRemotePrefix(RepositorySystemSession session) {
188        return ConfigUtils.getString(
189                session, DEFAULT_REMOTE_PREFIX, CONFIG_PROP_REMOTE_PREFIX, R1_CONF_PROP_REMOTE_PREFIX);
190    }
191
192    protected boolean isSplitRemote(RepositorySystemSession session) {
193        return ConfigUtils.getBoolean(
194                session, DEFAULT_SPLIT_REMOTE, CONFIG_PROP_SPLIT_REMOTE, R1_CONF_PROP_SPLIT_REMOTE);
195    }
196
197    protected boolean isSplitRemoteRepository(RepositorySystemSession session) {
198        return ConfigUtils.getBoolean(
199                session,
200                DEFAULT_SPLIT_REMOTE_REPOSITORY,
201                CONFIG_PROP_SPLIT_REMOTE_REPOSITORY,
202                R1_CONF_PROP_SPLIT_REMOTE_REPOSITORY);
203    }
204
205    protected boolean isSplitRemoteRepositoryLast(RepositorySystemSession session) {
206        return ConfigUtils.getBoolean(
207                session,
208                DEFAULT_SPLIT_REMOTE_REPOSITORY_LAST,
209                CONFIG_PROP_SPLIT_REMOTE_REPOSITORY_LAST,
210                R1_CONF_PROP_SPLIT_REMOTE_REPOSITORY_LAST);
211    }
212
213    protected String getReleasesPrefix(RepositorySystemSession session) {
214        return ConfigUtils.getString(
215                session, DEFAULT_RELEASES_PREFIX, CONFIG_PROP_RELEASES_PREFIX, R1_CONF_PROP_RELEASES_PREFIX);
216    }
217
218    protected String getSnapshotsPrefix(RepositorySystemSession session) {
219        return ConfigUtils.getString(
220                session, DEFAULT_SNAPSHOTS_PREFIX, CONFIG_PROP_SNAPSHOTS_PREFIX, R1_CONF_PROP_SNAPSHOTS_PREFIX);
221    }
222
223    /**
224     * Support class for composers: it defines protected members for all the predefined configuration values and
225     * provides default implementation for methods. Implementors may change it's behaviour by overriding methods.
226     */
227    @SuppressWarnings("checkstyle:parameternumber")
228    protected abstract static class LocalPathPrefixComposerSupport implements LocalPathPrefixComposer {
229        protected final boolean split;
230
231        protected final String localPrefix;
232
233        protected final boolean splitLocal;
234
235        protected final String remotePrefix;
236
237        protected final boolean splitRemote;
238
239        protected final boolean splitRemoteRepository;
240
241        protected final boolean splitRemoteRepositoryLast;
242
243        protected final String releasesPrefix;
244
245        protected final String snapshotsPrefix;
246
247        protected final Function<ArtifactRepository, String> idToPathSegmentFunction;
248
249        protected LocalPathPrefixComposerSupport(
250                boolean split,
251                String localPrefix,
252                boolean splitLocal,
253                String remotePrefix,
254                boolean splitRemote,
255                boolean splitRemoteRepository,
256                boolean splitRemoteRepositoryLast,
257                String releasesPrefix,
258                String snapshotsPrefix,
259                Function<ArtifactRepository, String> idToPathSegmentFunction) {
260            this.split = split;
261            this.localPrefix = localPrefix;
262            this.splitLocal = splitLocal;
263            this.remotePrefix = remotePrefix;
264            this.splitRemote = splitRemote;
265            this.splitRemoteRepository = splitRemoteRepository;
266            this.splitRemoteRepositoryLast = splitRemoteRepositoryLast;
267            this.releasesPrefix = releasesPrefix;
268            this.snapshotsPrefix = snapshotsPrefix;
269            this.idToPathSegmentFunction = idToPathSegmentFunction;
270        }
271
272        @Override
273        public String getPathPrefixForLocalArtifact(Artifact artifact) {
274            if (!split) {
275                return null;
276            }
277            String result = localPrefix;
278            if (splitLocal) {
279                result += "/" + (artifact.isSnapshot() ? snapshotsPrefix : releasesPrefix);
280            }
281            return result;
282        }
283
284        @Override
285        public String getPathPrefixForRemoteArtifact(Artifact artifact, RemoteRepository repository) {
286            if (!split) {
287                return null;
288            }
289            String result = remotePrefix;
290            if (!splitRemoteRepositoryLast && splitRemoteRepository) {
291                result += "/" + idToPathSegmentFunction.apply(repository);
292            }
293            if (splitRemote) {
294                result += "/" + (artifact.isSnapshot() ? snapshotsPrefix : releasesPrefix);
295            }
296            if (splitRemoteRepositoryLast && splitRemoteRepository) {
297                result += "/" + idToPathSegmentFunction.apply(repository);
298            }
299            return result;
300        }
301
302        @Override
303        public String getPathPrefixForLocalMetadata(Metadata metadata) {
304            if (!split) {
305                return null;
306            }
307            String result = localPrefix;
308            if (splitLocal) {
309                result += "/" + (isSnapshot(metadata) ? snapshotsPrefix : releasesPrefix);
310            }
311            return result;
312        }
313
314        @Override
315        public String getPathPrefixForRemoteMetadata(Metadata metadata, RemoteRepository repository) {
316            if (!split) {
317                return null;
318            }
319            String result = remotePrefix;
320            if (!splitRemoteRepositoryLast && splitRemoteRepository) {
321                result += "/" + idToPathSegmentFunction.apply(repository);
322            }
323            if (splitRemote) {
324                result += "/" + (isSnapshot(metadata) ? snapshotsPrefix : releasesPrefix);
325            }
326            if (splitRemoteRepositoryLast && splitRemoteRepository) {
327                result += "/" + idToPathSegmentFunction.apply(repository);
328            }
329            return result;
330        }
331
332        protected boolean isSnapshot(Metadata metadata) {
333            return !metadata.getVersion().isEmpty() && metadata.getVersion().endsWith("-SNAPSHOT");
334        }
335    }
336}