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 38KB

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