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 org.eclipse.aether.RepositorySystemSession; 022import org.eclipse.aether.artifact.Artifact; 023import org.eclipse.aether.metadata.Metadata; 024import org.eclipse.aether.repository.RemoteRepository; 025import org.eclipse.aether.repository.RepositoryKeyFunction; 026import org.eclipse.aether.util.ConfigUtils; 027import org.eclipse.aether.util.PathUtils; 028 029/** 030 * Support class for {@link LocalPathPrefixComposerFactory} implementations: it predefines and makes re-usable 031 * common configuration getters, and defines a support class for {@link LocalPathPrefixComposer} carrying same 032 * configuration and providing default implementation for all methods. 033 * <p> 034 * Implementors should extend this class to implement custom split strategies. If one needs to alter default 035 * configuration, they should override any configuration getter from this class. 036 * 037 * @see DefaultLocalPathPrefixComposerFactory 038 * @since 1.8.1 039 */ 040public abstract class LocalPathPrefixComposerFactorySupport implements LocalPathPrefixComposerFactory { 041 042 /** 043 * Whether LRM should split local and remote artifacts. 044 * 045 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 046 * @configurationType {@link java.lang.Boolean} 047 * @configurationDefaultValue {@link #DEFAULT_SPLIT} 048 */ 049 public static final String CONFIG_PROP_SPLIT = EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "split"; 050 051 public static final boolean DEFAULT_SPLIT = false; 052 053 /** 054 * The prefix to use for locally installed artifacts. 055 * 056 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 057 * @configurationType {@link java.lang.String} 058 * @configurationDefaultValue {@link #DEFAULT_LOCAL_PREFIX} 059 */ 060 public static final String CONFIG_PROP_LOCAL_PREFIX = 061 EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "localPrefix"; 062 063 public static final String DEFAULT_LOCAL_PREFIX = "installed"; 064 065 /** 066 * Whether locally installed artifacts should be split by version (release/snapshot). 067 * 068 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 069 * @configurationType {@link java.lang.Boolean} 070 * @configurationDefaultValue {@link #DEFAULT_SPLIT_LOCAL} 071 */ 072 public static final String CONFIG_PROP_SPLIT_LOCAL = 073 EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "splitLocal"; 074 075 public static final boolean DEFAULT_SPLIT_LOCAL = false; 076 077 /** 078 * The prefix to use for remotely cached artifacts. 079 * 080 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 081 * @configurationType {@link java.lang.String} 082 * @configurationDefaultValue {@link #DEFAULT_REMOTE_PREFIX} 083 */ 084 public static final String CONFIG_PROP_REMOTE_PREFIX = 085 EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "remotePrefix"; 086 087 public static final String DEFAULT_REMOTE_PREFIX = "cached"; 088 089 /** 090 * Whether cached artifacts should be split by version (release/snapshot). 091 * 092 * @configurationSource {@link RepositorySystemSession#getConfigProperties()} 093 * @configurationType {@link java.lang.Boolean} 094 * @configurationDefaultValue {@link #DEFAULT_SPLIT_REMOTE} 095 */ 096 public static final String CONFIG_PROP_SPLIT_REMOTE = 097 EnhancedLocalRepositoryManagerFactory.CONFIG_PROPS_PREFIX + "splitRemote"; 098 099 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}