1 package org.apache.archiva.repository.maven2;
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
22 import org.apache.archiva.common.utils.PathUtil;
23 import org.apache.archiva.configuration.AbstractRepositoryConfiguration;
24 import org.apache.archiva.configuration.ArchivaConfiguration;
25 import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
26 import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
27 import org.apache.archiva.repository.*;
28 import org.apache.archiva.repository.features.ArtifactCleanupFeature;
29 import org.apache.archiva.repository.features.IndexCreationFeature;
30 import org.apache.archiva.repository.features.RemoteIndexFeature;
31 import org.apache.archiva.repository.features.StagingRepositoryFeature;
32 import org.apache.commons.lang.StringUtils;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35 import org.springframework.stereotype.Service;
37 import javax.inject.Inject;
38 import java.io.IOException;
40 import java.net.URISyntaxException;
41 import java.nio.file.Files;
42 import java.nio.file.Path;
43 import java.nio.file.Paths;
44 import java.time.Duration;
45 import java.time.Period;
46 import java.time.temporal.ChronoUnit;
47 import java.util.HashSet;
51 * Provider for the maven2 repository implementations
53 @Service("mavenRepositoryProvider")
54 public class MavenRepositoryProvider implements RepositoryProvider {
58 private ArchivaConfiguration archivaConfiguration;
60 private static final Logger log = LoggerFactory.getLogger(MavenRepositoryProvider.class);
62 static final Set<RepositoryType> TYPES = new HashSet<>();
65 TYPES.add(RepositoryType.MAVEN);
69 public Set<RepositoryType> provides() {
74 public EditableManagedRepository createManagedInstance(String id, String name) {
75 return new MavenManagedRepository(id, name, archivaConfiguration.getRepositoryBaseDir());
79 public EditableRemoteRepository createRemoteInstance(String id, String name) {
80 return new MavenRemoteRepository(id, name, archivaConfiguration.getRemoteRepositoryBaseDir());
83 private URI getURIFromString(String uriStr) throws RepositoryException {
86 if (StringUtils.isEmpty(uriStr)) {
89 if (uriStr.startsWith("/")) {
90 // only absolute paths are prepended with file scheme
91 uri = new URI("file://" + uriStr);
93 uri = new URI(uriStr);
95 if (uri.getScheme() != null && !"file".equals(uri.getScheme())) {
96 log.error("Bad URI scheme found: {}, URI={}", uri.getScheme(), uri);
97 throw new RepositoryException("The uri " + uriStr + " is not valid. Only file:// URI is allowed for maven.");
99 } catch (URISyntaxException e) {
100 String newCfg = "file://" + uriStr;
102 uri = new URI(newCfg);
103 } catch (URISyntaxException e1) {
104 log.error("Could not create URI from {} -> ", uriStr, newCfg);
105 throw new RepositoryException("The config entry " + uriStr + " cannot be converted to URI.");
108 log.debug("Setting location uri: {}", uri);
113 public ManagedRepository createManagedInstance(ManagedRepositoryConfiguration cfg) throws RepositoryException {
114 MavenManagedRepository repo = new MavenManagedRepository(cfg.getId(), cfg.getName(), archivaConfiguration.getRepositoryBaseDir());
115 updateManagedInstance(repo, cfg);
120 public void updateManagedInstance(EditableManagedRepository repo, ManagedRepositoryConfiguration cfg) throws RepositoryException {
122 repo.setLocation(getURIFromString(cfg.getLocation()));
123 } catch (UnsupportedURIException e) {
124 throw new RepositoryException("The location entry is not a valid uri: " + cfg.getLocation());
126 setBaseConfig(repo, cfg);
127 Path repoDir = repo.getLocalPath();
128 if (!Files.exists(repoDir)) {
129 log.debug("Creating repo directory {}", repoDir);
131 Files.createDirectories(repoDir);
132 } catch (IOException e) {
133 log.error("Could not create directory {} for repository {}", repo.getLocalPath(), repo.getId(), e);
134 throw new RepositoryException("Could not create directory for repository " + repo.getLocalPath());
137 repo.setSchedulingDefinition(cfg.getRefreshCronExpression());
138 repo.setBlocksRedeployment(cfg.isBlockRedeployments());
139 repo.setScanned(cfg.isScanned());
140 if (cfg.isReleases()) {
141 repo.addActiveReleaseScheme(ReleaseScheme.RELEASE);
143 if (cfg.isSnapshots()) {
144 repo.addActiveReleaseScheme(ReleaseScheme.SNAPSHOT);
147 StagingRepositoryFeature stagingRepositoryFeature = repo.getFeature(StagingRepositoryFeature.class).get();
148 stagingRepositoryFeature.setStageRepoNeeded(cfg.isStageRepoNeeded());
150 IndexCreationFeature indexCreationFeature = repo.getFeature(IndexCreationFeature.class).get();
151 indexCreationFeature.setSkipPackedIndexCreation(cfg.isSkipPackedIndexCreation());
152 indexCreationFeature.setIndexPath(getURIFromString(cfg.getIndexDir()));
154 if (indexCreationFeature.getIndexPath().getScheme() == null) {
155 indexPath = Paths.get(indexCreationFeature.getIndexPath().getPath());
157 indexPath = Paths.get(indexCreationFeature.getIndexPath());
159 Path absoluteIndexPath;
160 if (indexPath.isAbsolute()) {
161 absoluteIndexPath = indexPath;
163 absoluteIndexPath = PathUtil.getPathFromUri(repo.getLocation()).resolve(indexCreationFeature.getIndexPath().getPath());
166 Files.createDirectories(absoluteIndexPath);
167 } catch (IOException e) {
168 log.error("Could not create index directory {}", absoluteIndexPath);
169 throw new RepositoryException("Could not create index directory " + absoluteIndexPath);
172 ArtifactCleanupFeature artifactCleanupFeature = repo.getFeature(ArtifactCleanupFeature.class).get();
174 artifactCleanupFeature.setDeleteReleasedSnapshots(cfg.isDeleteReleasedSnapshots());
175 artifactCleanupFeature.setRetentionCount(cfg.getRetentionCount());
176 artifactCleanupFeature.setRetentionPeriod(Period.ofDays(cfg.getRetentionPeriod()));
181 public ManagedRepository createStagingInstance(ManagedRepositoryConfiguration baseConfiguration) throws RepositoryException {
182 log.debug("Creating staging instance for {}", baseConfiguration.getId());
183 return createManagedInstance(getStageRepoConfig(baseConfiguration));
188 public RemoteRepository createRemoteInstance(RemoteRepositoryConfiguration cfg) throws RepositoryException {
189 MavenRemoteRepository repo = new MavenRemoteRepository(cfg.getId(), cfg.getName(), archivaConfiguration.getRemoteRepositoryBaseDir());
190 updateRemoteInstance(repo, cfg);
194 private String convertUriToPath(URI uri) {
195 if (uri.getScheme() == null) {
196 return uri.getPath();
197 } else if ("file".equals(uri.getScheme())) {
198 return Paths.get(uri).toString();
200 return uri.toString();
205 public void updateRemoteInstance(EditableRemoteRepository repo, RemoteRepositoryConfiguration cfg) throws RepositoryException {
206 setBaseConfig(repo, cfg);
207 repo.setCheckPath(cfg.getCheckPath());
208 repo.setSchedulingDefinition(cfg.getRefreshCronExpression());
210 repo.setLocation(new URI(cfg.getUrl()));
211 } catch (UnsupportedURIException | URISyntaxException e) {
212 log.error("Could not set remote url " + cfg.getUrl());
213 throw new RepositoryException("The url config is not a valid uri: " + cfg.getUrl());
215 repo.setTimeout(Duration.ofSeconds(cfg.getTimeout()));
216 RemoteIndexFeature remoteIndexFeature = repo.getFeature(RemoteIndexFeature.class).get();
217 remoteIndexFeature.setDownloadRemoteIndex(cfg.isDownloadRemoteIndex());
218 remoteIndexFeature.setDownloadRemoteIndexOnStartup(cfg.isDownloadRemoteIndexOnStartup());
219 remoteIndexFeature.setDownloadTimeout(Duration.ofSeconds(cfg.getRemoteDownloadTimeout()));
220 remoteIndexFeature.setProxyId(cfg.getRemoteDownloadNetworkProxyId());
221 if (cfg.isDownloadRemoteIndex()) {
223 remoteIndexFeature.setIndexUri(new URI(cfg.getRemoteIndexUrl()));
224 } catch (URISyntaxException e) {
225 log.error("Could not set remote index url " + cfg.getRemoteIndexUrl());
226 remoteIndexFeature.setDownloadRemoteIndex(false);
227 remoteIndexFeature.setDownloadRemoteIndexOnStartup(false);
230 repo.setExtraHeaders(cfg.getExtraHeaders());
231 repo.setExtraParameters(cfg.getExtraParameters());
232 PasswordCredentials credentials = new PasswordCredentials("", new char[0]);
233 if (cfg.getPassword() != null && cfg.getUsername() != null) {
234 credentials.setPassword(cfg.getPassword().toCharArray());
235 credentials.setUsername(cfg.getUsername());
236 repo.setCredentials(credentials);
238 credentials.setPassword(new char[0]);
240 if (cfg.getIndexDir() != null) {
241 IndexCreationFeature indexCreationFeature = repo.getFeature(IndexCreationFeature.class).get();
242 indexCreationFeature.setIndexPath(getURIFromString(cfg.getIndexDir()));
247 public RemoteRepositoryConfiguration getRemoteConfiguration(RemoteRepository remoteRepository) throws RepositoryException {
248 if (!(remoteRepository instanceof MavenRemoteRepository)) {
249 log.error("Wrong remote repository type " + remoteRepository.getClass().getName());
250 throw new RepositoryException("The given repository type cannot be handled by the maven provider: " + remoteRepository.getClass().getName());
252 RemoteRepositoryConfiguration cfg = new RemoteRepositoryConfiguration();
253 cfg.setType(remoteRepository.getType().toString());
254 cfg.setId(remoteRepository.getId());
255 cfg.setName(remoteRepository.getName());
256 cfg.setDescription(remoteRepository.getDescription());
257 cfg.setUrl(remoteRepository.getLocation().toString());
258 cfg.setTimeout((int) remoteRepository.getTimeout().toMillis() / 1000);
259 cfg.setCheckPath(remoteRepository.getCheckPath());
260 RepositoryCredentials creds = remoteRepository.getLoginCredentials();
262 if (creds instanceof PasswordCredentials) {
263 PasswordCredentials pCreds = (PasswordCredentials) creds;
264 cfg.setPassword(new String(pCreds.getPassword()));
265 cfg.setUsername(pCreds.getUsername());
268 cfg.setLayout(remoteRepository.getLayout());
269 cfg.setExtraParameters(remoteRepository.getExtraParameters());
270 cfg.setExtraHeaders(remoteRepository.getExtraHeaders());
271 cfg.setRefreshCronExpression(remoteRepository.getSchedulingDefinition());
273 IndexCreationFeature indexCreationFeature = remoteRepository.getFeature(IndexCreationFeature.class).get();
274 cfg.setIndexDir(convertUriToPath(indexCreationFeature.getIndexPath()));
276 RemoteIndexFeature remoteIndexFeature = remoteRepository.getFeature(RemoteIndexFeature.class).get();
277 cfg.setRemoteIndexUrl(remoteIndexFeature.getIndexUri().toString());
278 cfg.setRemoteDownloadTimeout((int) remoteIndexFeature.getDownloadTimeout().get(ChronoUnit.SECONDS));
279 cfg.setDownloadRemoteIndexOnStartup(remoteIndexFeature.isDownloadRemoteIndexOnStartup());
280 cfg.setDownloadRemoteIndex(remoteIndexFeature.isDownloadRemoteIndex());
281 cfg.setRemoteDownloadNetworkProxyId(remoteIndexFeature.getProxyId());
289 public ManagedRepositoryConfiguration getManagedConfiguration(ManagedRepository managedRepository) throws RepositoryException {
290 if (!(managedRepository instanceof MavenManagedRepository || managedRepository instanceof BasicManagedRepository)) {
291 log.error("Wrong remote repository type " + managedRepository.getClass().getName());
292 throw new RepositoryException("The given repository type cannot be handled by the maven provider: " + managedRepository.getClass().getName());
294 ManagedRepositoryConfiguration cfg = new ManagedRepositoryConfiguration();
295 cfg.setType(managedRepository.getType().toString());
296 cfg.setId(managedRepository.getId());
297 cfg.setName(managedRepository.getName());
298 cfg.setDescription(managedRepository.getDescription());
299 cfg.setLocation(convertUriToPath(managedRepository.getLocation()));
300 cfg.setLayout(managedRepository.getLayout());
301 cfg.setRefreshCronExpression(managedRepository.getSchedulingDefinition());
302 cfg.setScanned(managedRepository.isScanned());
303 cfg.setBlockRedeployments(managedRepository.blocksRedeployments());
304 StagingRepositoryFeature stagingRepositoryFeature = managedRepository.getFeature(StagingRepositoryFeature.class).get();
305 cfg.setStageRepoNeeded(stagingRepositoryFeature.isStageRepoNeeded());
306 IndexCreationFeature indexCreationFeature = managedRepository.getFeature(IndexCreationFeature.class).get();
307 cfg.setIndexDir(convertUriToPath(indexCreationFeature.getIndexPath()));
308 cfg.setSkipPackedIndexCreation(indexCreationFeature.isSkipPackedIndexCreation());
310 ArtifactCleanupFeature artifactCleanupFeature = managedRepository.getFeature(ArtifactCleanupFeature.class).get();
311 cfg.setRetentionCount(artifactCleanupFeature.getRetentionCount());
312 cfg.setRetentionPeriod(artifactCleanupFeature.getRetentionPeriod().getDays());
313 cfg.setDeleteReleasedSnapshots(artifactCleanupFeature.isDeleteReleasedSnapshots());
315 if (managedRepository.getActiveReleaseSchemes().contains(ReleaseScheme.RELEASE)) {
316 cfg.setReleases(true);
318 cfg.setReleases(false);
320 if (managedRepository.getActiveReleaseSchemes().contains(ReleaseScheme.SNAPSHOT)) {
321 cfg.setSnapshots(true);
323 cfg.setSnapshots(false);
329 private ManagedRepositoryConfiguration getStageRepoConfig(ManagedRepositoryConfiguration repository) {
330 ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
331 stagingRepository.setId(repository.getId() + StagingRepositoryFeature.STAGING_REPO_POSTFIX);
332 stagingRepository.setLayout(repository.getLayout());
333 stagingRepository.setName(repository.getName() + StagingRepositoryFeature.STAGING_REPO_POSTFIX);
334 stagingRepository.setBlockRedeployments(repository.isBlockRedeployments());
335 stagingRepository.setRetentionPeriod(repository.getRetentionPeriod());
336 stagingRepository.setDeleteReleasedSnapshots(repository.isDeleteReleasedSnapshots());
337 stagingRepository.setStageRepoNeeded(false);
339 String path = repository.getLocation();
340 int lastIndex = path.replace('\\', '/').lastIndexOf('/');
341 stagingRepository.setLocation(path.substring(0, lastIndex) + "/" + stagingRepository.getId());
343 if (StringUtils.isNotBlank(repository.getIndexDir())) {
344 Path indexDir = null;
346 indexDir = Paths.get(new URI(repository.getIndexDir().startsWith("file://") ? repository.getIndexDir() : "file://" + repository.getIndexDir()));
347 if (indexDir.isAbsolute()) {
348 Path newDir = Paths.get(new URI(stagingRepository.getLocation().startsWith("file://") ? stagingRepository.getLocation() : "file://" + stagingRepository.getLocation())).resolve(".index");
349 log.debug("Changing index directory {} -> {}", indexDir, newDir);
350 stagingRepository.setIndexDir(newDir.toString());
352 log.debug("Keeping index directory {}", repository.getIndexDir());
353 stagingRepository.setIndexDir(repository.getIndexDir());
355 } catch (URISyntaxException e) {
356 log.error("Could not parse index path as uri {}", repository.getIndexDir());
357 stagingRepository.setIndexDir("");
359 // in case of absolute dir do not use the same
361 stagingRepository.setRefreshCronExpression(repository.getRefreshCronExpression());
362 stagingRepository.setReleases(repository.isReleases());
363 stagingRepository.setRetentionCount(repository.getRetentionCount());
364 stagingRepository.setScanned(repository.isScanned());
365 stagingRepository.setSnapshots(repository.isSnapshots());
366 stagingRepository.setSkipPackedIndexCreation(repository.isSkipPackedIndexCreation());
367 // do not duplicate description
368 //stagingRepository.getDescription("")
369 return stagingRepository;
372 private void setBaseConfig(EditableRepository repo, AbstractRepositoryConfiguration cfg) throws RepositoryException {
374 URI baseUri = archivaConfiguration.getRepositoryBaseDir().toUri();
375 repo.setBaseUri(baseUri);
377 repo.setName(repo.getPrimaryLocale(), cfg.getName());
378 repo.setDescription(repo.getPrimaryLocale(), cfg.getDescription());
379 repo.setLayout(cfg.getLayout());
382 public ArchivaConfiguration getArchivaConfiguration() {
383 return archivaConfiguration;
386 public void setArchivaConfiguration(ArchivaConfiguration archivaConfiguration) {
387 this.archivaConfiguration = archivaConfiguration;
391 public <T> void raise(RepositoryEvent<T> event) {