You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MavenRepositoryProvider.java 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. package org.apache.archiva.repository.maven2;
  2. /*
  3. * Licensed to the Apache Software Foundation (ASF) under one
  4. * or more contributor license agreements. See the NOTICE file
  5. * distributed with this work for additional information
  6. * regarding copyright ownership. The ASF licenses this file
  7. * to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance
  9. * with the License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing,
  14. * software distributed under the License is distributed on an
  15. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  16. * KIND, either express or implied. See the License for the
  17. * specific language governing permissions and limitations
  18. * under the License.
  19. */
  20. import org.apache.archiva.configuration.AbstractRepositoryConfiguration;
  21. import org.apache.archiva.configuration.ArchivaConfiguration;
  22. import org.apache.archiva.configuration.ManagedRepositoryConfiguration;
  23. import org.apache.archiva.configuration.RemoteRepositoryConfiguration;
  24. import org.apache.archiva.repository.BasicManagedRepository;
  25. import org.apache.archiva.repository.EditableManagedRepository;
  26. import org.apache.archiva.repository.EditableRemoteRepository;
  27. import org.apache.archiva.repository.EditableRepository;
  28. import org.apache.archiva.repository.ManagedRepository;
  29. import org.apache.archiva.repository.PasswordCredentials;
  30. import org.apache.archiva.repository.ReleaseScheme;
  31. import org.apache.archiva.repository.RemoteRepository;
  32. import org.apache.archiva.repository.RepositoryCredentials;
  33. import org.apache.archiva.repository.RepositoryEvent;
  34. import org.apache.archiva.repository.RepositoryException;
  35. import org.apache.archiva.repository.RepositoryProvider;
  36. import org.apache.archiva.repository.RepositoryType;
  37. import org.apache.archiva.repository.UnsupportedURIException;
  38. import org.apache.archiva.repository.features.ArtifactCleanupFeature;
  39. import org.apache.archiva.repository.features.IndexCreationFeature;
  40. import org.apache.archiva.repository.features.RemoteIndexFeature;
  41. import org.apache.archiva.repository.features.StagingRepositoryFeature;
  42. import org.apache.commons.lang.StringUtils;
  43. import org.slf4j.Logger;
  44. import org.slf4j.LoggerFactory;
  45. import org.springframework.stereotype.Service;
  46. import javax.inject.Inject;
  47. import java.io.IOException;
  48. import java.net.URI;
  49. import java.net.URISyntaxException;
  50. import java.nio.file.Files;
  51. import java.nio.file.Path;
  52. import java.nio.file.Paths;
  53. import java.time.Duration;
  54. import java.time.Period;
  55. import java.time.temporal.ChronoUnit;
  56. import java.util.HashSet;
  57. import java.util.Map;
  58. import java.util.Set;
  59. import java.util.stream.Collectors;
  60. /**
  61. * Provider for the maven2 repository implementations
  62. */
  63. @Service("mavenRepositoryProvider")
  64. public class MavenRepositoryProvider implements RepositoryProvider {
  65. @Inject
  66. private ArchivaConfiguration archivaConfiguration;
  67. private static final Logger log = LoggerFactory.getLogger(MavenRepositoryProvider.class);
  68. static final Set<RepositoryType> TYPES = new HashSet<>();
  69. static {
  70. TYPES.add(RepositoryType.MAVEN);
  71. }
  72. @Override
  73. public Set<RepositoryType> provides() {
  74. return TYPES;
  75. }
  76. @Override
  77. public EditableManagedRepository createManagedInstance(String id, String name) {
  78. return new MavenManagedRepository(id, name, archivaConfiguration.getRepositoryBaseDir());
  79. }
  80. @Override
  81. public EditableRemoteRepository createRemoteInstance(String id, String name) {
  82. return new MavenRemoteRepository(id, name, archivaConfiguration.getRemoteRepositoryBaseDir());
  83. }
  84. private URI getURIFromString(String uriStr) throws RepositoryException {
  85. URI uri;
  86. try {
  87. if (StringUtils.isEmpty(uriStr)) {
  88. return new URI("");
  89. }
  90. if (uriStr.startsWith("/")) {
  91. // only absolute paths are prepended with file scheme
  92. uri = new URI("file://" + uriStr);
  93. } else {
  94. uri = new URI(uriStr);
  95. }
  96. if (uri.getScheme() != null && !"file".equals(uri.getScheme())) {
  97. log.error("Bad URI scheme found: {}, URI={}", uri.getScheme(), uri);
  98. throw new RepositoryException("The uri " + uriStr + " is not valid. Only file:// URI is allowed for maven.");
  99. }
  100. } catch (URISyntaxException e) {
  101. String newCfg = "file://" + uriStr;
  102. try {
  103. uri = new URI(newCfg);
  104. } catch (URISyntaxException e1) {
  105. log.error("Could not create URI from {} -> ", uriStr, newCfg);
  106. throw new RepositoryException("The config entry " + uriStr + " cannot be converted to URI.");
  107. }
  108. }
  109. log.debug("Setting location uri: {}", uri);
  110. return uri;
  111. }
  112. @Override
  113. public ManagedRepository createManagedInstance(ManagedRepositoryConfiguration cfg) throws RepositoryException {
  114. MavenManagedRepository repo = new MavenManagedRepository(cfg.getId(), cfg.getName(), archivaConfiguration.getRepositoryBaseDir());
  115. updateManagedInstance(repo, cfg);
  116. return repo;
  117. }
  118. @Override
  119. public void updateManagedInstance(EditableManagedRepository repo, ManagedRepositoryConfiguration cfg) throws RepositoryException {
  120. try {
  121. repo.setLocation(getURIFromString(cfg.getLocation()));
  122. } catch (UnsupportedURIException e) {
  123. throw new RepositoryException("The location entry is not a valid uri: " + cfg.getLocation());
  124. }
  125. setBaseConfig(repo, cfg);
  126. Path repoDir = repo.getLocalPath();
  127. if (!Files.exists(repoDir)) {
  128. log.debug("Creating repo directory {}", repoDir);
  129. try {
  130. Files.createDirectories(repoDir);
  131. } catch (IOException e) {
  132. log.error("Could not create directory {} for repository {}", repo.getLocalPath(), repo.getId(), e);
  133. throw new RepositoryException("Could not create directory for repository " + repo.getLocalPath());
  134. }
  135. }
  136. repo.setSchedulingDefinition(cfg.getRefreshCronExpression());
  137. repo.setBlocksRedeployment(cfg.isBlockRedeployments());
  138. repo.setScanned(cfg.isScanned());
  139. if (cfg.isReleases()) {
  140. repo.addActiveReleaseScheme(ReleaseScheme.RELEASE);
  141. }
  142. if (cfg.isSnapshots()) {
  143. repo.addActiveReleaseScheme(ReleaseScheme.SNAPSHOT);
  144. }
  145. StagingRepositoryFeature stagingRepositoryFeature = repo.getFeature(StagingRepositoryFeature.class).get();
  146. stagingRepositoryFeature.setStageRepoNeeded(cfg.isStageRepoNeeded());
  147. IndexCreationFeature indexCreationFeature = repo.getFeature(IndexCreationFeature.class).get();
  148. indexCreationFeature.setSkipPackedIndexCreation(cfg.isSkipPackedIndexCreation());
  149. indexCreationFeature.setIndexPath(getURIFromString(cfg.getIndexDir()));
  150. indexCreationFeature.setPackedIndexPath(getURIFromString(cfg.getPackedIndexDir()));
  151. /* -> Should be created by MavenIndexProvider
  152. Path indexPath;
  153. if (indexCreationFeature.getIndexPath().getScheme() == null) {
  154. indexPath = Paths.get(indexCreationFeature.getIndexPath().getPath());
  155. } else {
  156. indexPath = Paths.get(indexCreationFeature.getIndexPath());
  157. }
  158. Path absoluteIndexPath;
  159. if (indexPath.isAbsolute()) {
  160. absoluteIndexPath = indexPath;
  161. } else {
  162. absoluteIndexPath = PathUtil.getPathFromUri(repo.getLocation()).resolve(indexCreationFeature.getIndexPath().getPath());
  163. }
  164. try {
  165. Files.createDirectories(absoluteIndexPath);
  166. } catch (IOException e) {
  167. log.error("Could not create index directory {}", absoluteIndexPath);
  168. throw new RepositoryException("Could not create index directory " + absoluteIndexPath);
  169. }*/
  170. ArtifactCleanupFeature artifactCleanupFeature = repo.getFeature(ArtifactCleanupFeature.class).get();
  171. artifactCleanupFeature.setDeleteReleasedSnapshots(cfg.isDeleteReleasedSnapshots());
  172. artifactCleanupFeature.setRetentionCount(cfg.getRetentionCount());
  173. artifactCleanupFeature.setRetentionPeriod(Period.ofDays(cfg.getRetentionPeriod()));
  174. }
  175. @Override
  176. public ManagedRepository createStagingInstance(ManagedRepositoryConfiguration baseConfiguration) throws RepositoryException {
  177. log.debug("Creating staging instance for {}", baseConfiguration.getId());
  178. return createManagedInstance(getStageRepoConfig(baseConfiguration));
  179. }
  180. @Override
  181. public RemoteRepository createRemoteInstance(RemoteRepositoryConfiguration cfg) throws RepositoryException {
  182. MavenRemoteRepository repo = new MavenRemoteRepository(cfg.getId(), cfg.getName(), archivaConfiguration.getRemoteRepositoryBaseDir());
  183. updateRemoteInstance(repo, cfg);
  184. return repo;
  185. }
  186. private String convertUriToPath(URI uri) {
  187. if (uri.getScheme() == null) {
  188. return uri.getPath();
  189. } else if ("file".equals(uri.getScheme())) {
  190. return Paths.get(uri).toString();
  191. } else {
  192. return uri.toString();
  193. }
  194. }
  195. @Override
  196. public void updateRemoteInstance(EditableRemoteRepository repo, RemoteRepositoryConfiguration cfg) throws RepositoryException {
  197. setBaseConfig(repo, cfg);
  198. repo.setCheckPath(cfg.getCheckPath());
  199. repo.setSchedulingDefinition(cfg.getRefreshCronExpression());
  200. try {
  201. repo.setLocation(new URI(cfg.getUrl()));
  202. } catch (UnsupportedURIException | URISyntaxException e) {
  203. log.error("Could not set remote url " + cfg.getUrl());
  204. throw new RepositoryException("The url config is not a valid uri: " + cfg.getUrl());
  205. }
  206. repo.setTimeout(Duration.ofSeconds(cfg.getTimeout()));
  207. RemoteIndexFeature remoteIndexFeature = repo.getFeature(RemoteIndexFeature.class).get();
  208. remoteIndexFeature.setDownloadRemoteIndex(cfg.isDownloadRemoteIndex());
  209. remoteIndexFeature.setDownloadRemoteIndexOnStartup(cfg.isDownloadRemoteIndexOnStartup());
  210. remoteIndexFeature.setDownloadTimeout(Duration.ofSeconds(cfg.getRemoteDownloadTimeout()));
  211. remoteIndexFeature.setProxyId(cfg.getRemoteDownloadNetworkProxyId());
  212. if (cfg.isDownloadRemoteIndex()) {
  213. try {
  214. remoteIndexFeature.setIndexUri(new URI(cfg.getRemoteIndexUrl()));
  215. } catch (URISyntaxException e) {
  216. log.error("Could not set remote index url " + cfg.getRemoteIndexUrl());
  217. remoteIndexFeature.setDownloadRemoteIndex(false);
  218. remoteIndexFeature.setDownloadRemoteIndexOnStartup(false);
  219. }
  220. }
  221. for ( Object key : cfg.getExtraHeaders().keySet() ) {
  222. repo.addExtraHeader( key.toString(), cfg.getExtraHeaders().get(key).toString() );
  223. }
  224. for ( Object key : cfg.getExtraParameters().keySet() ) {
  225. repo.addExtraParameter( key.toString(), cfg.getExtraParameters().get(key).toString() );
  226. }
  227. PasswordCredentials credentials = new PasswordCredentials("", new char[0]);
  228. if (cfg.getPassword() != null && cfg.getUsername() != null) {
  229. credentials.setPassword(cfg.getPassword().toCharArray());
  230. credentials.setUsername(cfg.getUsername());
  231. repo.setCredentials(credentials);
  232. } else {
  233. credentials.setPassword(new char[0]);
  234. }
  235. IndexCreationFeature indexCreationFeature = repo.getFeature(IndexCreationFeature.class).get();
  236. if (cfg.getIndexDir() != null) {
  237. indexCreationFeature.setIndexPath(getURIFromString(cfg.getIndexDir()));
  238. }
  239. if (cfg.getPackedIndexDir() != null) {
  240. indexCreationFeature.setPackedIndexPath(getURIFromString(cfg.getPackedIndexDir()));
  241. }
  242. log.debug("Updated remote instance {}", repo);
  243. }
  244. @Override
  245. public RemoteRepositoryConfiguration getRemoteConfiguration(RemoteRepository remoteRepository) throws RepositoryException {
  246. if (!(remoteRepository instanceof MavenRemoteRepository)) {
  247. log.error("Wrong remote repository type " + remoteRepository.getClass().getName());
  248. throw new RepositoryException("The given repository type cannot be handled by the maven provider: " + remoteRepository.getClass().getName());
  249. }
  250. RemoteRepositoryConfiguration cfg = new RemoteRepositoryConfiguration();
  251. cfg.setType(remoteRepository.getType().toString());
  252. cfg.setId(remoteRepository.getId());
  253. cfg.setName(remoteRepository.getName());
  254. cfg.setDescription(remoteRepository.getDescription());
  255. cfg.setUrl(remoteRepository.getLocation().toString());
  256. cfg.setTimeout((int) remoteRepository.getTimeout().toMillis() / 1000);
  257. cfg.setCheckPath(remoteRepository.getCheckPath());
  258. RepositoryCredentials creds = remoteRepository.getLoginCredentials();
  259. if (creds != null) {
  260. if (creds instanceof PasswordCredentials) {
  261. PasswordCredentials pCreds = (PasswordCredentials) creds;
  262. cfg.setPassword(new String(pCreds.getPassword()));
  263. cfg.setUsername(pCreds.getUsername());
  264. }
  265. }
  266. cfg.setLayout(remoteRepository.getLayout());
  267. cfg.setExtraParameters(remoteRepository.getExtraParameters());
  268. cfg.setExtraHeaders(remoteRepository.getExtraHeaders());
  269. cfg.setRefreshCronExpression(remoteRepository.getSchedulingDefinition());
  270. IndexCreationFeature indexCreationFeature = remoteRepository.getFeature(IndexCreationFeature.class).get();
  271. cfg.setIndexDir(convertUriToPath(indexCreationFeature.getIndexPath()));
  272. cfg.setPackedIndexDir(convertUriToPath(indexCreationFeature.getPackedIndexPath()));
  273. RemoteIndexFeature remoteIndexFeature = remoteRepository.getFeature(RemoteIndexFeature.class).get();
  274. cfg.setRemoteIndexUrl(remoteIndexFeature.getIndexUri().toString());
  275. cfg.setRemoteDownloadTimeout((int) remoteIndexFeature.getDownloadTimeout().get(ChronoUnit.SECONDS));
  276. cfg.setDownloadRemoteIndexOnStartup(remoteIndexFeature.isDownloadRemoteIndexOnStartup());
  277. cfg.setDownloadRemoteIndex(remoteIndexFeature.isDownloadRemoteIndex());
  278. cfg.setRemoteDownloadNetworkProxyId(remoteIndexFeature.getProxyId());
  279. return cfg;
  280. }
  281. @Override
  282. public ManagedRepositoryConfiguration getManagedConfiguration(ManagedRepository managedRepository) throws RepositoryException {
  283. if (!(managedRepository instanceof MavenManagedRepository || managedRepository instanceof BasicManagedRepository)) {
  284. log.error("Wrong remote repository type " + managedRepository.getClass().getName());
  285. throw new RepositoryException("The given repository type cannot be handled by the maven provider: " + managedRepository.getClass().getName());
  286. }
  287. ManagedRepositoryConfiguration cfg = new ManagedRepositoryConfiguration();
  288. cfg.setType(managedRepository.getType().toString());
  289. cfg.setId(managedRepository.getId());
  290. cfg.setName(managedRepository.getName());
  291. cfg.setDescription(managedRepository.getDescription());
  292. cfg.setLocation(convertUriToPath(managedRepository.getLocation()));
  293. cfg.setLayout(managedRepository.getLayout());
  294. cfg.setRefreshCronExpression(managedRepository.getSchedulingDefinition());
  295. cfg.setScanned(managedRepository.isScanned());
  296. cfg.setBlockRedeployments(managedRepository.blocksRedeployments());
  297. StagingRepositoryFeature stagingRepositoryFeature = managedRepository.getFeature(StagingRepositoryFeature.class).get();
  298. cfg.setStageRepoNeeded(stagingRepositoryFeature.isStageRepoNeeded());
  299. IndexCreationFeature indexCreationFeature = managedRepository.getFeature(IndexCreationFeature.class).get();
  300. cfg.setIndexDir(convertUriToPath(indexCreationFeature.getIndexPath()));
  301. cfg.setPackedIndexDir(convertUriToPath(indexCreationFeature.getPackedIndexPath()));
  302. cfg.setSkipPackedIndexCreation(indexCreationFeature.isSkipPackedIndexCreation());
  303. ArtifactCleanupFeature artifactCleanupFeature = managedRepository.getFeature(ArtifactCleanupFeature.class).get();
  304. cfg.setRetentionCount(artifactCleanupFeature.getRetentionCount());
  305. cfg.setRetentionPeriod(artifactCleanupFeature.getRetentionPeriod().getDays());
  306. cfg.setDeleteReleasedSnapshots(artifactCleanupFeature.isDeleteReleasedSnapshots());
  307. if (managedRepository.getActiveReleaseSchemes().contains(ReleaseScheme.RELEASE)) {
  308. cfg.setReleases(true);
  309. } else {
  310. cfg.setReleases(false);
  311. }
  312. if (managedRepository.getActiveReleaseSchemes().contains(ReleaseScheme.SNAPSHOT)) {
  313. cfg.setSnapshots(true);
  314. } else {
  315. cfg.setSnapshots(false);
  316. }
  317. return cfg;
  318. }
  319. private ManagedRepositoryConfiguration getStageRepoConfig(ManagedRepositoryConfiguration repository) {
  320. ManagedRepositoryConfiguration stagingRepository = new ManagedRepositoryConfiguration();
  321. stagingRepository.setId(repository.getId() + StagingRepositoryFeature.STAGING_REPO_POSTFIX);
  322. stagingRepository.setLayout(repository.getLayout());
  323. stagingRepository.setName(repository.getName() + StagingRepositoryFeature.STAGING_REPO_POSTFIX);
  324. stagingRepository.setBlockRedeployments(repository.isBlockRedeployments());
  325. stagingRepository.setRetentionPeriod(repository.getRetentionPeriod());
  326. stagingRepository.setDeleteReleasedSnapshots(repository.isDeleteReleasedSnapshots());
  327. stagingRepository.setStageRepoNeeded(false);
  328. String path = repository.getLocation();
  329. int lastIndex = path.replace('\\', '/').lastIndexOf('/');
  330. stagingRepository.setLocation(path.substring(0, lastIndex) + "/" + stagingRepository.getId());
  331. if (StringUtils.isNotBlank(repository.getIndexDir())) {
  332. Path indexDir = null;
  333. try {
  334. indexDir = Paths.get(new URI(repository.getIndexDir().startsWith("file://") ? repository.getIndexDir() : "file://" + repository.getIndexDir()));
  335. if (indexDir.isAbsolute()) {
  336. Path newDir = indexDir.getParent().resolve(indexDir.getFileName() + StagingRepositoryFeature.STAGING_REPO_POSTFIX);
  337. log.debug("Changing index directory {} -> {}", indexDir, newDir);
  338. stagingRepository.setIndexDir(newDir.toString());
  339. } else {
  340. log.debug("Keeping index directory {}", repository.getIndexDir());
  341. stagingRepository.setIndexDir(repository.getIndexDir());
  342. }
  343. } catch (URISyntaxException e) {
  344. log.error("Could not parse index path as uri {}", repository.getIndexDir());
  345. stagingRepository.setIndexDir("");
  346. }
  347. // in case of absolute dir do not use the same
  348. }
  349. if (StringUtils.isNotBlank(repository.getPackedIndexDir())) {
  350. Path packedIndexDir = null;
  351. try {
  352. packedIndexDir = Paths.get(new URI(repository.getPackedIndexDir().startsWith("file://") ? repository.getPackedIndexDir() : "file://" + repository.getPackedIndexDir()));
  353. if (packedIndexDir.isAbsolute()) {
  354. Path newDir = packedIndexDir.getParent().resolve(packedIndexDir.getFileName() + StagingRepositoryFeature.STAGING_REPO_POSTFIX);
  355. log.debug("Changing index directory {} -> {}", packedIndexDir, newDir);
  356. stagingRepository.setPackedIndexDir(newDir.toString());
  357. } else {
  358. log.debug("Keeping index directory {}", repository.getPackedIndexDir());
  359. stagingRepository.setPackedIndexDir(repository.getPackedIndexDir());
  360. }
  361. } catch (URISyntaxException e) {
  362. log.error("Could not parse index path as uri {}", repository.getPackedIndexDir());
  363. stagingRepository.setPackedIndexDir("");
  364. }
  365. // in case of absolute dir do not use the same
  366. }
  367. stagingRepository.setRefreshCronExpression(repository.getRefreshCronExpression());
  368. stagingRepository.setReleases(repository.isReleases());
  369. stagingRepository.setRetentionCount(repository.getRetentionCount());
  370. stagingRepository.setScanned(repository.isScanned());
  371. stagingRepository.setSnapshots(repository.isSnapshots());
  372. stagingRepository.setSkipPackedIndexCreation(repository.isSkipPackedIndexCreation());
  373. // do not duplicate description
  374. //stagingRepository.getDescription("")
  375. return stagingRepository;
  376. }
  377. private void setBaseConfig(EditableRepository repo, AbstractRepositoryConfiguration cfg) throws RepositoryException {
  378. URI baseUri = archivaConfiguration.getRepositoryBaseDir().toUri();
  379. repo.setBaseUri(baseUri);
  380. repo.setName(repo.getPrimaryLocale(), cfg.getName());
  381. repo.setDescription(repo.getPrimaryLocale(), cfg.getDescription());
  382. repo.setLayout(cfg.getLayout());
  383. }
  384. public ArchivaConfiguration getArchivaConfiguration() {
  385. return archivaConfiguration;
  386. }
  387. public void setArchivaConfiguration(ArchivaConfiguration archivaConfiguration) {
  388. this.archivaConfiguration = archivaConfiguration;
  389. }
  390. @Override
  391. public <T> void raise(RepositoryEvent<T> event) {
  392. //
  393. }
  394. }