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.

DefaultRepositoryProxyHandler.java 35KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. package org.apache.archiva.proxy;
  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.checksum.ChecksumAlgorithm;
  21. import org.apache.archiva.checksum.ChecksumUtil;
  22. import org.apache.archiva.common.filelock.FileLockManager;
  23. import org.apache.archiva.configuration.ArchivaConfiguration;
  24. import org.apache.archiva.configuration.ProxyConnectorConfiguration;
  25. import org.apache.archiva.configuration.ProxyConnectorRuleConfiguration;
  26. import org.apache.archiva.model.ArtifactReference;
  27. import org.apache.archiva.model.Keys;
  28. import org.apache.archiva.policies.DownloadErrorPolicy;
  29. import org.apache.archiva.policies.DownloadPolicy;
  30. import org.apache.archiva.policies.Policy;
  31. import org.apache.archiva.policies.PolicyConfigurationException;
  32. import org.apache.archiva.policies.PolicyOption;
  33. import org.apache.archiva.policies.PolicyViolationException;
  34. import org.apache.archiva.policies.PostDownloadPolicy;
  35. import org.apache.archiva.policies.PreDownloadPolicy;
  36. import org.apache.archiva.policies.ProxyDownloadException;
  37. import org.apache.archiva.policies.urlcache.UrlFailureCache;
  38. import org.apache.archiva.proxy.model.NetworkProxy;
  39. import org.apache.archiva.proxy.model.ProxyConnector;
  40. import org.apache.archiva.proxy.model.ProxyFetchResult;
  41. import org.apache.archiva.proxy.model.RepositoryProxyHandler;
  42. import org.apache.archiva.redback.components.taskqueue.TaskQueueException;
  43. import org.apache.archiva.repository.ManagedRepository;
  44. import org.apache.archiva.repository.RemoteRepository;
  45. import org.apache.archiva.repository.RemoteRepositoryContent;
  46. import org.apache.archiva.repository.RepositoryType;
  47. import org.apache.archiva.repository.metadata.base.MetadataTools;
  48. import org.apache.archiva.repository.metadata.RepositoryMetadataException;
  49. import org.apache.archiva.repository.storage.FilesystemStorage;
  50. import org.apache.archiva.repository.storage.StorageAsset;
  51. import org.apache.archiva.repository.storage.StorageUtil;
  52. import org.apache.archiva.scheduler.ArchivaTaskScheduler;
  53. import org.apache.archiva.scheduler.repository.model.RepositoryTask;
  54. import org.apache.commons.collections4.CollectionUtils;
  55. import org.apache.commons.io.FilenameUtils;
  56. import org.apache.commons.lang3.StringUtils;
  57. import org.apache.commons.lang3.SystemUtils;
  58. import org.apache.tools.ant.types.selectors.SelectorUtils;
  59. import org.slf4j.Logger;
  60. import org.slf4j.LoggerFactory;
  61. import org.slf4j.MarkerFactory;
  62. import javax.annotation.PostConstruct;
  63. import javax.inject.Inject;
  64. import javax.inject.Named;
  65. import java.io.IOException;
  66. import java.net.MalformedURLException;
  67. import java.nio.file.Files;
  68. import java.nio.file.Path;
  69. import java.nio.file.StandardCopyOption;
  70. import java.util.ArrayList;
  71. import java.util.Collections;
  72. import java.util.HashMap;
  73. import java.util.LinkedHashMap;
  74. import java.util.List;
  75. import java.util.Map;
  76. import java.util.Properties;
  77. import java.util.concurrent.ConcurrentHashMap;
  78. import java.util.concurrent.ConcurrentMap;
  79. public abstract class DefaultRepositoryProxyHandler implements RepositoryProxyHandler {
  80. protected Logger log = LoggerFactory.getLogger( DefaultRepositoryProxyHandler.class );
  81. @Inject
  82. protected UrlFailureCache urlFailureCache;
  83. @Inject
  84. @Named(value = "metadataTools#default")
  85. private MetadataTools metadataTools;
  86. private Map<String, PreDownloadPolicy> preDownloadPolicies = new HashMap<>( );
  87. private Map<String, PostDownloadPolicy> postDownloadPolicies = new HashMap<>( );
  88. private Map<String, DownloadErrorPolicy> downloadErrorPolicies = new HashMap<>( );
  89. private ConcurrentMap<String, List<ProxyConnector>> proxyConnectorMap = new ConcurrentHashMap<>();
  90. @Inject
  91. @Named(value = "archivaTaskScheduler#repository")
  92. private ArchivaTaskScheduler<RepositoryTask> scheduler;
  93. @Inject
  94. private ArchivaConfiguration archivaConfiguration;
  95. @Inject
  96. @Named(value = "fileLockManager#default")
  97. private FileLockManager fileLockManager;
  98. private Map<String, NetworkProxy> networkProxyMap = new ConcurrentHashMap<>();
  99. private List<ChecksumAlgorithm> checksumAlgorithms;
  100. @PostConstruct
  101. public void initialize()
  102. {
  103. checksumAlgorithms = ChecksumUtil.getAlgorithms(archivaConfiguration.getConfiguration().getArchivaRuntimeConfiguration().getChecksumTypes());
  104. }
  105. private List<ProxyConnectorRuleConfiguration> findProxyConnectorRules(String sourceRepository,
  106. String targetRepository,
  107. List<ProxyConnectorRuleConfiguration> all )
  108. {
  109. List<ProxyConnectorRuleConfiguration> proxyConnectorRuleConfigurations = new ArrayList<>();
  110. for ( ProxyConnectorRuleConfiguration proxyConnectorRuleConfiguration : all )
  111. {
  112. for ( ProxyConnectorConfiguration proxyConnector : proxyConnectorRuleConfiguration.getProxyConnectors() )
  113. {
  114. if ( StringUtils.equals( sourceRepository, proxyConnector.getSourceRepoId() ) && StringUtils.equals(
  115. targetRepository, proxyConnector.getTargetRepoId() ) )
  116. {
  117. proxyConnectorRuleConfigurations.add( proxyConnectorRuleConfiguration );
  118. }
  119. }
  120. }
  121. return proxyConnectorRuleConfigurations;
  122. }
  123. @Override
  124. public StorageAsset fetchFromProxies( ManagedRepository repository, ArtifactReference artifact )
  125. throws ProxyDownloadException
  126. {
  127. StorageAsset localFile = toLocalFile( repository, artifact );
  128. Properties requestProperties = new Properties();
  129. requestProperties.setProperty( "filetype", "artifact" );
  130. requestProperties.setProperty( "version", artifact.getVersion() );
  131. requestProperties.setProperty( "managedRepositoryId", repository.getId() );
  132. List<ProxyConnector> connectors = getProxyConnectors( repository );
  133. Map<String, Exception> previousExceptions = new LinkedHashMap<>();
  134. for ( ProxyConnector connector : connectors )
  135. {
  136. if ( !connector.isEnabled() )
  137. {
  138. continue;
  139. }
  140. RemoteRepository targetRepository = connector.getTargetRepository();
  141. requestProperties.setProperty( "remoteRepositoryId", targetRepository.getId() );
  142. String targetPath = targetRepository.getContent().toPath( artifact );
  143. if ( SystemUtils.IS_OS_WINDOWS )
  144. {
  145. // toPath use system PATH_SEPARATOR so on windows url are \ which doesn't work very well :-)
  146. targetPath = FilenameUtils.separatorsToUnix( targetPath );
  147. }
  148. try
  149. {
  150. StorageAsset downloadedFile =
  151. transferFile( connector, targetRepository, targetPath, repository, localFile, requestProperties,
  152. true );
  153. if ( fileExists(downloadedFile) )
  154. {
  155. log.debug( "Successfully transferred: {}", downloadedFile.getPath() );
  156. return downloadedFile;
  157. }
  158. }
  159. catch ( NotFoundException e )
  160. {
  161. log.debug( "Artifact {} not found on repository \"{}\".", Keys.toKey( artifact ),
  162. targetRepository.getId() );
  163. }
  164. catch ( NotModifiedException e )
  165. {
  166. log.debug( "Artifact {} not updated on repository \"{}\".", Keys.toKey( artifact ),
  167. targetRepository.getId() );
  168. }
  169. catch ( ProxyException e )
  170. {
  171. validatePolicies( this.downloadErrorPolicies, connector.getPolicies(), requestProperties, artifact,
  172. targetRepository.getContent(), localFile, e, previousExceptions );
  173. }
  174. }
  175. if ( !previousExceptions.isEmpty() )
  176. {
  177. throw new ProxyDownloadException( "Failures occurred downloading from some remote repositories",
  178. previousExceptions );
  179. }
  180. log.debug( "Exhausted all target repositories, artifact {} not found.", Keys.toKey( artifact ) );
  181. return null;
  182. }
  183. @Override
  184. public StorageAsset fetchFromProxies( ManagedRepository repository, String path )
  185. {
  186. StorageAsset localFile = repository.getAsset( path );
  187. // no update policies for these paths
  188. if ( localFile.exists() )
  189. {
  190. return null;
  191. }
  192. Properties requestProperties = new Properties();
  193. requestProperties.setProperty( "filetype", "resource" );
  194. requestProperties.setProperty( "managedRepositoryId", repository.getId() );
  195. List<ProxyConnector> connectors = getProxyConnectors( repository );
  196. for ( ProxyConnector connector : connectors )
  197. {
  198. if ( !connector.isEnabled() )
  199. {
  200. continue;
  201. }
  202. RemoteRepository targetRepository = connector.getTargetRepository();
  203. requestProperties.setProperty( "remoteRepositoryId", targetRepository.getId() );
  204. String targetPath = path;
  205. try
  206. {
  207. StorageAsset downloadedFile =
  208. transferFile( connector, targetRepository, targetPath, repository, localFile, requestProperties,
  209. false );
  210. if ( fileExists( downloadedFile ) )
  211. {
  212. log.debug( "Successfully transferred: {}", downloadedFile.getPath() );
  213. return downloadedFile;
  214. }
  215. }
  216. catch ( NotFoundException e )
  217. {
  218. log.debug( "Resource {} not found on repository \"{}\".", path,
  219. targetRepository.getId() );
  220. }
  221. catch ( NotModifiedException e )
  222. {
  223. log.debug( "Resource {} not updated on repository \"{}\".", path,
  224. targetRepository.getId() );
  225. }
  226. catch ( ProxyException e )
  227. {
  228. log.warn(
  229. "Transfer error from repository {} for resource {}, continuing to next repository. Error message: {}",
  230. targetRepository.getId(), path, e.getMessage() );
  231. log.debug( MarkerFactory.getDetachedMarker( "transfer.error" ),
  232. "Transfer error from repository \"{}"
  233. + "\" for resource {}, continuing to next repository. Error message: {}",
  234. targetRepository.getId(), path, e.getMessage(), e );
  235. }
  236. }
  237. log.debug( "Exhausted all target repositories, resource {} not found.", path );
  238. return null;
  239. }
  240. @Override
  241. public ProxyFetchResult fetchMetadataFromProxies( ManagedRepository repository, String logicalPath )
  242. {
  243. StorageAsset localFile = repository.getAsset( logicalPath );
  244. Properties requestProperties = new Properties();
  245. requestProperties.setProperty( "filetype", "metadata" );
  246. boolean metadataNeedsUpdating = false;
  247. long originalTimestamp = getLastModified( localFile );
  248. List<ProxyConnector> connectors = new ArrayList<>( getProxyConnectors( repository ) );
  249. for ( ProxyConnector connector : connectors )
  250. {
  251. if ( !connector.isEnabled() )
  252. {
  253. continue;
  254. }
  255. RemoteRepository targetRepository = connector.getTargetRepository();
  256. StorageAsset localRepoFile = toLocalRepoFile( repository, targetRepository.getContent(), logicalPath );
  257. long originalMetadataTimestamp = getLastModified( localRepoFile );
  258. try
  259. {
  260. transferFile( connector, targetRepository, logicalPath, repository, localRepoFile, requestProperties,
  261. true );
  262. if ( hasBeenUpdated( localRepoFile, originalMetadataTimestamp ) )
  263. {
  264. metadataNeedsUpdating = true;
  265. }
  266. }
  267. catch ( NotFoundException e )
  268. {
  269. log.debug( "Metadata {} not found on remote repository '{}'.", logicalPath,
  270. targetRepository.getId(), e );
  271. }
  272. catch ( NotModifiedException e )
  273. {
  274. log.debug( "Metadata {} not updated on remote repository '{}'.", logicalPath,
  275. targetRepository.getId(), e );
  276. }
  277. catch ( ProxyException e )
  278. {
  279. log.warn(
  280. "Transfer error from repository {} for versioned Metadata {}, continuing to next repository. Error message: {}",
  281. targetRepository.getId(), logicalPath, e.getMessage() );
  282. log.debug( "Full stack trace", e );
  283. }
  284. }
  285. if ( hasBeenUpdated( localFile, originalTimestamp ) )
  286. {
  287. metadataNeedsUpdating = true;
  288. }
  289. if ( metadataNeedsUpdating || !localFile.exists())
  290. {
  291. try
  292. {
  293. metadataTools.updateMetadata( repository.getContent(), logicalPath );
  294. }
  295. catch ( RepositoryMetadataException e )
  296. {
  297. log.warn( "Unable to update metadata {}:{}", localFile.getPath(), e.getMessage(), e );
  298. }
  299. }
  300. if ( fileExists( localFile ) )
  301. {
  302. return new ProxyFetchResult( localFile, metadataNeedsUpdating );
  303. }
  304. return new ProxyFetchResult( null, false );
  305. }
  306. private long getLastModified(StorageAsset file )
  307. {
  308. if ( !file.exists() || file.isContainer() )
  309. {
  310. return 0;
  311. }
  312. return file.getModificationTime().toEpochMilli();
  313. }
  314. private boolean hasBeenUpdated(StorageAsset file, long originalLastModified )
  315. {
  316. if ( !file.exists() || file.isContainer() )
  317. {
  318. return false;
  319. }
  320. long currentLastModified = getLastModified( file );
  321. return ( currentLastModified > originalLastModified );
  322. }
  323. private StorageAsset toLocalRepoFile( ManagedRepository repository, RemoteRepositoryContent targetRepository,
  324. String targetPath )
  325. {
  326. String repoPath = metadataTools.getRepositorySpecificName( targetRepository, targetPath );
  327. return repository.getAsset( repoPath );
  328. }
  329. /**
  330. * Test if the provided ManagedRepositoryContent has any proxies configured for it.
  331. * @param repository
  332. */
  333. @Override
  334. public boolean hasProxies( ManagedRepository repository )
  335. {
  336. synchronized ( this.proxyConnectorMap )
  337. {
  338. return this.proxyConnectorMap.containsKey( repository.getId() );
  339. }
  340. }
  341. private StorageAsset toLocalFile(ManagedRepository repository, ArtifactReference artifact )
  342. {
  343. return repository.getContent().toFile( artifact );
  344. }
  345. /**
  346. * Simple method to test if the file exists on the local disk.
  347. *
  348. * @param file the file to test. (may be null)
  349. * @return true if file exists. false if the file param is null, doesn't exist, or is not of type File.
  350. */
  351. private boolean fileExists( StorageAsset file )
  352. {
  353. if ( file == null )
  354. {
  355. return false;
  356. }
  357. if ( !file.exists())
  358. {
  359. return false;
  360. }
  361. return !file.isContainer();
  362. }
  363. /**
  364. * Perform the transfer of the file.
  365. *
  366. * @param connector the connector configuration to use.
  367. * @param remoteRepository the remote repository get the resource from.
  368. * @param remotePath the path in the remote repository to the resource to get.
  369. * @param repository the managed repository that will hold the file
  370. * @param resource the path relative to the repository storage where the file should be downloaded to
  371. * @param requestProperties the request properties to utilize for policy handling.
  372. * @param executeConsumers whether to execute the consumers after proxying
  373. * @return the local file that was downloaded, or null if not downloaded.
  374. * @throws NotFoundException if the file was not found on the remote repository.
  375. * @throws NotModifiedException if the localFile was present, and the resource was present on remote repository, but
  376. * the remote resource is not newer than the local File.
  377. * @throws ProxyException if transfer was unsuccessful.
  378. */
  379. protected StorageAsset transferFile( ProxyConnector connector, RemoteRepository remoteRepository, String remotePath,
  380. ManagedRepository repository, StorageAsset resource, Properties requestProperties,
  381. boolean executeConsumers )
  382. throws ProxyException, NotModifiedException
  383. {
  384. String url = null;
  385. try
  386. {
  387. url = remoteRepository.getLocation().toURL().toString();
  388. }
  389. catch ( MalformedURLException e )
  390. {
  391. throw new ProxyException( e.getMessage(), e );
  392. }
  393. if ( !url.endsWith( "/" ) )
  394. {
  395. url = url + "/";
  396. }
  397. url = url + remotePath;
  398. requestProperties.setProperty( "url", url );
  399. // Is a whitelist defined?
  400. if ( CollectionUtils.isNotEmpty( connector.getWhitelist() ) )
  401. {
  402. // Path must belong to whitelist.
  403. if ( !matchesPattern( remotePath, connector.getWhitelist() ) )
  404. {
  405. log.debug( "Path [{}] is not part of defined whitelist (skipping transfer from repository [{}]).",
  406. remotePath, remoteRepository.getId() );
  407. return null;
  408. }
  409. }
  410. // Is target path part of blacklist?
  411. if ( matchesPattern( remotePath, connector.getBlacklist() ) )
  412. {
  413. log.debug( "Path [{}] is part of blacklist (skipping transfer from repository [{}]).", remotePath,
  414. remoteRepository.getId() );
  415. return null;
  416. }
  417. // Handle pre-download policy
  418. try
  419. {
  420. validatePolicies( this.preDownloadPolicies, connector.getPolicies(), requestProperties, resource );
  421. }
  422. catch ( PolicyViolationException e )
  423. {
  424. String emsg = "Transfer not attempted on " + url + " : " + e.getMessage();
  425. if ( resource.exists() )
  426. {
  427. log.debug( "{} : using already present local file.", emsg );
  428. return resource;
  429. }
  430. log.debug( emsg );
  431. return null;
  432. }
  433. Path workingDirectory = createWorkingDirectory( repository );
  434. FilesystemStorage tmpStorage = null;
  435. try
  436. {
  437. tmpStorage = new FilesystemStorage( workingDirectory, fileLockManager );
  438. }
  439. catch ( IOException e )
  440. {
  441. throw new ProxyException( "Could not create tmp storage" );
  442. }
  443. StorageAsset tmpResource = tmpStorage.getAsset( resource.getName( ) );
  444. StorageAsset[] tmpChecksumFiles = new StorageAsset[checksumAlgorithms.size()];
  445. for(int i=0; i<checksumAlgorithms.size(); i++) {
  446. ChecksumAlgorithm alg = checksumAlgorithms.get( i );
  447. tmpChecksumFiles[i] = tmpStorage.getAsset( resource.getName() + "." + alg.getDefaultExtension() );
  448. }
  449. try
  450. {
  451. transferResources( connector, remoteRepository, tmpResource,tmpChecksumFiles , url, remotePath,
  452. resource, workingDirectory, repository );
  453. // Handle post-download policies.
  454. try
  455. {
  456. validatePolicies( this.postDownloadPolicies, connector.getPolicies(), requestProperties, tmpResource );
  457. }
  458. catch ( PolicyViolationException e )
  459. {
  460. log.warn( "Transfer invalidated from {} : {}", url, e.getMessage() );
  461. executeConsumers = false;
  462. if ( !fileExists( tmpResource ) )
  463. {
  464. resource = null;
  465. }
  466. }
  467. if ( resource != null )
  468. {
  469. synchronized ( resource.getPath().intern() )
  470. {
  471. StorageAsset directory = resource.getParent();
  472. for (int i=0; i<tmpChecksumFiles.length; i++) {
  473. moveFileIfExists( tmpChecksumFiles[i], directory );
  474. }
  475. moveFileIfExists( tmpResource, directory );
  476. }
  477. }
  478. }
  479. finally
  480. {
  481. org.apache.archiva.common.utils.FileUtils.deleteQuietly( workingDirectory );
  482. }
  483. if ( executeConsumers )
  484. {
  485. // Just-in-time update of the index and database by executing the consumers for this artifact
  486. //consumers.executeConsumers( connector.getSourceRepository().getRepository(), resource );
  487. queueRepositoryTask( connector.getSourceRepository().getId(), resource );
  488. }
  489. return resource;
  490. }
  491. protected abstract void transferResources( ProxyConnector connector, RemoteRepository remoteRepository,
  492. StorageAsset tmpResource, StorageAsset[] checksumFiles, String url, String remotePath, StorageAsset resource, Path workingDirectory,
  493. ManagedRepository repository ) throws ProxyException;
  494. private void queueRepositoryTask(String repositoryId, StorageAsset localFile )
  495. {
  496. RepositoryTask task = new RepositoryTask();
  497. task.setRepositoryId( repositoryId );
  498. task.setResourceFile( localFile );
  499. task.setUpdateRelatedArtifacts( true );
  500. task.setScanAll( true );
  501. try
  502. {
  503. scheduler.queueTask( task );
  504. }
  505. catch ( TaskQueueException e )
  506. {
  507. log.error( "Unable to queue repository task to execute consumers on resource file ['{}"
  508. + "'].", localFile.getName() );
  509. }
  510. }
  511. /**
  512. * Moves the file into repository location if it exists
  513. *
  514. * @param fileToMove this could be either the main artifact, sha1 or md5 checksum file.
  515. * @param directory directory to write files to
  516. */
  517. private void moveFileIfExists( StorageAsset fileToMove, StorageAsset directory )
  518. throws ProxyException
  519. {
  520. if ( fileToMove != null && fileToMove.exists() )
  521. {
  522. StorageAsset newLocation = directory.getStorage().getAsset( directory.getPath()+ "/" + fileToMove.getName());
  523. moveTempToTarget( fileToMove, newLocation );
  524. }
  525. }
  526. /**
  527. * Apply the policies.
  528. *
  529. * @param policies the map of policies to execute. (Map of String policy keys, to {@link DownloadPolicy} objects)
  530. * @param settings the map of settings for the policies to execute. (Map of String policy keys, to String policy
  531. * setting)
  532. * @param request the request properties (utilized by the {@link DownloadPolicy#applyPolicy(PolicyOption, Properties, StorageAsset)}
  533. * )
  534. * @param localFile the local file (utilized by the {@link DownloadPolicy#applyPolicy(PolicyOption, Properties, StorageAsset)})
  535. * @throws PolicyViolationException
  536. */
  537. private void validatePolicies( Map<String, ? extends DownloadPolicy> policies, Map<Policy, PolicyOption> settings,
  538. Properties request, StorageAsset localFile )
  539. throws PolicyViolationException
  540. {
  541. for ( Map.Entry<String, ? extends DownloadPolicy> entry : policies.entrySet() )
  542. {
  543. // olamy with spring rolehint is now downloadPolicy#hint
  544. // so substring after last # to get the hint as with plexus
  545. String key = entry.getValue( ).getId( );
  546. DownloadPolicy policy = entry.getValue();
  547. PolicyOption option = settings.containsKey(policy ) ? settings.get(policy) : policy.getDefaultOption();
  548. log.debug( "Applying [{}] policy with [{}]", key, option );
  549. try
  550. {
  551. policy.applyPolicy( option, request, localFile );
  552. }
  553. catch ( PolicyConfigurationException e )
  554. {
  555. log.error( e.getMessage(), e );
  556. }
  557. }
  558. }
  559. private void validatePolicies( Map<String, DownloadErrorPolicy> policies, Map<Policy, PolicyOption> settings,
  560. Properties request, ArtifactReference artifact, RemoteRepositoryContent content,
  561. StorageAsset localFile, Exception exception, Map<String, Exception> previousExceptions )
  562. throws ProxyDownloadException
  563. {
  564. boolean process = true;
  565. for ( Map.Entry<String, ? extends DownloadErrorPolicy> entry : policies.entrySet() )
  566. {
  567. // olamy with spring rolehint is now downloadPolicy#hint
  568. // so substring after last # to get the hint as with plexus
  569. String key = entry.getValue( ).getId( );
  570. DownloadErrorPolicy policy = entry.getValue();
  571. PolicyOption option = settings.containsKey( policy ) ? settings.get(policy) : policy.getDefaultOption();
  572. log.debug( "Applying [{}] policy with [{}]", key, option );
  573. try
  574. {
  575. // all policies must approve the exception, any can cancel
  576. process = policy.applyPolicy( option, request, localFile, exception, previousExceptions );
  577. if ( !process )
  578. {
  579. break;
  580. }
  581. }
  582. catch ( PolicyConfigurationException e )
  583. {
  584. log.error( e.getMessage(), e );
  585. }
  586. }
  587. if ( process )
  588. {
  589. // if the exception was queued, don't throw it
  590. if ( !previousExceptions.containsKey( content.getId() ) )
  591. {
  592. throw new ProxyDownloadException(
  593. "An error occurred in downloading from the remote repository, and the policy is to fail immediately",
  594. content.getId(), exception );
  595. }
  596. }
  597. else
  598. {
  599. // if the exception was queued, but cancelled, remove it
  600. previousExceptions.remove( content.getId() );
  601. }
  602. log.warn(
  603. "Transfer error from repository {} for artifact {} , continuing to next repository. Error message: {}",
  604. content.getRepository().getId(), Keys.toKey( artifact ), exception.getMessage() );
  605. log.debug( "Full stack trace", exception );
  606. }
  607. /**
  608. * Creates a working directory
  609. *
  610. * @param repository
  611. * @return file location of working directory
  612. */
  613. private Path createWorkingDirectory( ManagedRepository repository )
  614. {
  615. try
  616. {
  617. return Files.createTempDirectory( "temp" );
  618. }
  619. catch ( IOException e )
  620. {
  621. throw new RuntimeException( e.getMessage(), e );
  622. }
  623. }
  624. /**
  625. * Used to move the temporary file to its real destination. This is patterned from the way WagonManager handles its
  626. * downloaded files.
  627. *
  628. * @param temp The completed download file
  629. * @param target The final location of the downloaded file
  630. * @throws ProxyException when the temp file cannot replace the target file
  631. */
  632. private void moveTempToTarget( StorageAsset temp, StorageAsset target )
  633. throws ProxyException
  634. {
  635. try
  636. {
  637. StorageUtil.moveAsset( temp, target, true , StandardCopyOption.REPLACE_EXISTING);
  638. }
  639. catch ( IOException e )
  640. {
  641. log.error( "Move failed from {} to {}, trying copy.", temp, target );
  642. try
  643. {
  644. StorageUtil.copyAsset( temp, target, true );
  645. if (temp.exists()) {
  646. temp.getStorage( ).removeAsset( temp );
  647. }
  648. }
  649. catch ( IOException ex )
  650. {
  651. log.error("Copy failed from {} to {}: ({}) {}", temp, target, e.getClass(), e.getMessage());
  652. throw new ProxyException("Could not move temp file "+temp.getPath()+" to target "+target.getPath()+": ("+e.getClass()+") "+e.getMessage(), e);
  653. }
  654. }
  655. }
  656. /**
  657. * Tests whitelist and blacklist patterns against path.
  658. *
  659. * @param path the path to test.
  660. * @param patterns the list of patterns to check.
  661. * @return true if the path matches at least 1 pattern in the provided patterns list.
  662. */
  663. private boolean matchesPattern( String path, List<String> patterns )
  664. {
  665. if ( CollectionUtils.isEmpty( patterns ) )
  666. {
  667. return false;
  668. }
  669. if ( !path.startsWith( "/" ) )
  670. {
  671. path = "/" + path;
  672. }
  673. for ( String pattern : patterns )
  674. {
  675. if ( !pattern.startsWith( "/" ) )
  676. {
  677. pattern = "/" + pattern;
  678. }
  679. if ( SelectorUtils.matchPath( pattern, path, false ) )
  680. {
  681. return true;
  682. }
  683. }
  684. return false;
  685. }
  686. /**
  687. * TODO: Ensure that list is correctly ordered based on configuration. See MRM-477
  688. * @param repository
  689. */
  690. @Override
  691. public List<ProxyConnector> getProxyConnectors( ManagedRepository repository )
  692. {
  693. if ( !this.proxyConnectorMap.containsKey( repository.getId() ) )
  694. {
  695. return Collections.emptyList();
  696. }
  697. List<ProxyConnector> ret = new ArrayList<>( this.proxyConnectorMap.get( repository.getId() ) );
  698. Collections.sort( ret, ProxyConnectorOrderComparator.getInstance() );
  699. return ret;
  700. }
  701. protected String addParameters(String path, RemoteRepository remoteRepository )
  702. {
  703. if ( remoteRepository.getExtraParameters().isEmpty() )
  704. {
  705. return path;
  706. }
  707. boolean question = false;
  708. StringBuilder res = new StringBuilder( path == null ? "" : path );
  709. for ( Map.Entry<String, String> entry : remoteRepository.getExtraParameters().entrySet() )
  710. {
  711. if ( !question )
  712. {
  713. res.append( '?' ).append( entry.getKey() ).append( '=' ).append( entry.getValue() );
  714. }
  715. }
  716. return res.toString();
  717. }
  718. public void setArchivaConfiguration(ArchivaConfiguration archivaConfiguration )
  719. {
  720. this.archivaConfiguration = archivaConfiguration;
  721. }
  722. public MetadataTools getMetadataTools()
  723. {
  724. return metadataTools;
  725. }
  726. public void setMetadataTools(MetadataTools metadataTools )
  727. {
  728. this.metadataTools = metadataTools;
  729. }
  730. public UrlFailureCache getUrlFailureCache()
  731. {
  732. return urlFailureCache;
  733. }
  734. public void setUrlFailureCache(UrlFailureCache urlFailureCache )
  735. {
  736. this.urlFailureCache = urlFailureCache;
  737. }
  738. public Map<String, PreDownloadPolicy> getPreDownloadPolicies()
  739. {
  740. return preDownloadPolicies;
  741. }
  742. public void setPreDownloadPolicies(Map<String, PreDownloadPolicy> preDownloadPolicies )
  743. {
  744. this.preDownloadPolicies = preDownloadPolicies;
  745. }
  746. public Map<String, PostDownloadPolicy> getPostDownloadPolicies()
  747. {
  748. return postDownloadPolicies;
  749. }
  750. public void setPostDownloadPolicies(Map<String, PostDownloadPolicy> postDownloadPolicies )
  751. {
  752. this.postDownloadPolicies = postDownloadPolicies;
  753. }
  754. public Map<String, DownloadErrorPolicy> getDownloadErrorPolicies()
  755. {
  756. return downloadErrorPolicies;
  757. }
  758. public void setDownloadErrorPolicies(Map<String, DownloadErrorPolicy> downloadErrorPolicies )
  759. {
  760. this.downloadErrorPolicies = downloadErrorPolicies;
  761. }
  762. @Override
  763. public void setNetworkProxies(Map<String, NetworkProxy> networkProxies ) {
  764. this.networkProxyMap.clear();
  765. this.networkProxyMap.putAll( networkProxies );
  766. }
  767. @Override
  768. public NetworkProxy getNetworkProxy(String id) {
  769. return this.networkProxyMap.get(id);
  770. }
  771. @Override
  772. public Map<String, NetworkProxy> getNetworkProxies() {
  773. return this.networkProxyMap;
  774. }
  775. @Override
  776. public abstract List<RepositoryType> supports();
  777. @Override
  778. public void setPolicies( List<Policy> policyList )
  779. {
  780. preDownloadPolicies.clear();
  781. postDownloadPolicies.clear();
  782. downloadErrorPolicies.clear();
  783. for (Policy policy : policyList) {
  784. addPolicy( policy );
  785. }
  786. }
  787. void addPolicy(PreDownloadPolicy policy) {
  788. preDownloadPolicies.put( policy.getId( ), policy );
  789. }
  790. void addPolicy(PostDownloadPolicy policy) {
  791. postDownloadPolicies.put( policy.getId( ), policy );
  792. }
  793. void addPolicy(DownloadErrorPolicy policy) {
  794. downloadErrorPolicies.put( policy.getId( ), policy );
  795. }
  796. @Override
  797. public void addPolicy( Policy policy )
  798. {
  799. if (policy instanceof PreDownloadPolicy) {
  800. addPolicy( (PreDownloadPolicy)policy );
  801. } else if (policy instanceof PostDownloadPolicy) {
  802. addPolicy( (PostDownloadPolicy) policy );
  803. } else if (policy instanceof DownloadErrorPolicy) {
  804. addPolicy( (DownloadErrorPolicy) policy );
  805. } else {
  806. log.warn( "Policy not known: {}, {}", policy.getId( ), policy.getClass( ).getName( ) );
  807. }
  808. }
  809. @Override
  810. public void removePolicy( Policy policy )
  811. {
  812. final String id = policy.getId();
  813. if (preDownloadPolicies.containsKey( id )) {
  814. preDownloadPolicies.remove( id );
  815. } else if (postDownloadPolicies.containsKey( id )) {
  816. postDownloadPolicies.remove( id );
  817. } else if (downloadErrorPolicies.containsKey( id )) {
  818. downloadErrorPolicies.remove( id );
  819. }
  820. }
  821. @Override
  822. public void addProxyConnector( ProxyConnector connector )
  823. {
  824. final String sourceId = connector.getSourceRepository( ).getId( );
  825. List<ProxyConnector> connectors;
  826. if (proxyConnectorMap.containsKey( sourceId )) {
  827. connectors = proxyConnectorMap.get( sourceId );
  828. } else {
  829. connectors = new ArrayList<>( );
  830. proxyConnectorMap.put( sourceId, connectors );
  831. }
  832. connectors.add( connector );
  833. }
  834. @Override
  835. public void setProxyConnectors( List<ProxyConnector> proxyConnectors )
  836. {
  837. proxyConnectorMap.clear();
  838. for ( ProxyConnector connector : proxyConnectors )
  839. {
  840. addProxyConnector( connector );
  841. }
  842. }
  843. }