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.

DefaultRepositoriesService.java 47KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  1. package org.apache.archiva.rest.services;
  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.admin.model.RepositoryAdminException;
  21. import org.apache.archiva.admin.model.admin.ArchivaAdministration;
  22. import org.apache.archiva.checksum.ChecksumAlgorithm;
  23. import org.apache.archiva.checksum.ChecksummedFile;
  24. import org.apache.archiva.common.utils.VersionComparator;
  25. import org.apache.archiva.common.utils.VersionUtil;
  26. import org.apache.archiva.maven2.metadata.MavenMetadataReader;
  27. import org.apache.archiva.maven2.model.Artifact;
  28. import org.apache.archiva.metadata.model.ArtifactMetadata;
  29. import org.apache.archiva.metadata.model.facets.AuditEvent;
  30. import org.apache.archiva.metadata.model.maven2.MavenArtifactFacet;
  31. import org.apache.archiva.metadata.repository.MetadataRepository;
  32. import org.apache.archiva.metadata.repository.MetadataRepositoryException;
  33. import org.apache.archiva.metadata.repository.MetadataResolutionException;
  34. import org.apache.archiva.metadata.repository.RepositorySession;
  35. import org.apache.archiva.metadata.repository.RepositorySessionFactory;
  36. import org.apache.archiva.model.ArchivaRepositoryMetadata;
  37. import org.apache.archiva.model.ArtifactReference;
  38. import org.apache.archiva.model.VersionedReference;
  39. import org.apache.archiva.redback.authentication.AuthenticationResult;
  40. import org.apache.archiva.redback.authorization.AuthorizationException;
  41. import org.apache.archiva.redback.components.cache.Cache;
  42. import org.apache.archiva.redback.components.taskqueue.TaskQueueException;
  43. import org.apache.archiva.redback.system.DefaultSecuritySession;
  44. import org.apache.archiva.redback.system.SecuritySession;
  45. import org.apache.archiva.redback.system.SecuritySystem;
  46. import org.apache.archiva.redback.users.User;
  47. import org.apache.archiva.redback.users.UserManagerException;
  48. import org.apache.archiva.redback.users.UserNotFoundException;
  49. import org.apache.archiva.repository.ContentNotFoundException;
  50. import org.apache.archiva.repository.ManagedRepository;
  51. import org.apache.archiva.repository.ManagedRepositoryContent;
  52. import org.apache.archiva.repository.RepositoryException;
  53. import org.apache.archiva.repository.RepositoryNotFoundException;
  54. import org.apache.archiva.repository.RepositoryRegistry;
  55. import org.apache.archiva.repository.storage.RepositoryStorage;
  56. import org.apache.archiva.repository.storage.StorageAsset;
  57. import org.apache.archiva.repository.storage.StorageUtil;
  58. import org.apache.archiva.repository.events.RepositoryListener;
  59. import org.apache.archiva.repository.metadata.MetadataTools;
  60. import org.apache.archiva.repository.metadata.RepositoryMetadataException;
  61. import org.apache.archiva.repository.metadata.RepositoryMetadataWriter;
  62. import org.apache.archiva.repository.scanner.RepositoryScanStatistics;
  63. import org.apache.archiva.repository.scanner.RepositoryScanner;
  64. import org.apache.archiva.repository.scanner.RepositoryScannerException;
  65. import org.apache.archiva.repository.scanner.RepositoryScannerInstance;
  66. import org.apache.archiva.rest.api.model.ArtifactTransferRequest;
  67. import org.apache.archiva.rest.api.model.StringList;
  68. import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
  69. import org.apache.archiva.rest.api.services.RepositoriesService;
  70. import org.apache.archiva.scheduler.ArchivaTaskScheduler;
  71. import org.apache.archiva.scheduler.indexing.maven.ArchivaIndexingTaskExecutor;
  72. import org.apache.archiva.scheduler.indexing.ArtifactIndexingTask;
  73. import org.apache.archiva.scheduler.indexing.DownloadRemoteIndexException;
  74. import org.apache.archiva.scheduler.indexing.DownloadRemoteIndexScheduler;
  75. import org.apache.archiva.scheduler.repository.model.RepositoryTask;
  76. import org.apache.archiva.security.ArchivaSecurityException;
  77. import org.apache.archiva.security.common.ArchivaRoleConstants;
  78. import org.apache.archiva.xml.XMLException;
  79. import org.apache.commons.io.FilenameUtils;
  80. import org.apache.commons.lang.StringUtils;
  81. import org.slf4j.Logger;
  82. import org.slf4j.LoggerFactory;
  83. import org.springframework.beans.factory.annotation.Autowired;
  84. import org.springframework.stereotype.Service;
  85. import javax.inject.Inject;
  86. import javax.inject.Named;
  87. import javax.ws.rs.core.Response;
  88. import java.io.IOException;
  89. import java.io.OutputStream;
  90. import java.io.OutputStreamWriter;
  91. import java.nio.file.Files;
  92. import java.nio.file.Path;
  93. import java.text.DateFormat;
  94. import java.text.SimpleDateFormat;
  95. import java.util.ArrayList;
  96. import java.util.Arrays;
  97. import java.util.Calendar;
  98. import java.util.Collection;
  99. import java.util.Collections;
  100. import java.util.Date;
  101. import java.util.List;
  102. import java.util.Set;
  103. import java.util.TimeZone;
  104. /**
  105. * @author Olivier Lamy
  106. * @since 1.4-M1
  107. */
  108. @Service("repositoriesService#rest")
  109. public class DefaultRepositoriesService
  110. extends AbstractRestService
  111. implements RepositoriesService
  112. {
  113. private Logger log = LoggerFactory.getLogger( getClass() );
  114. @Inject
  115. @Named(value = "taskExecutor#indexing")
  116. private ArchivaIndexingTaskExecutor archivaIndexingTaskExecutor;
  117. @Inject
  118. private RepositoryRegistry repositoryRegistry;
  119. @Inject
  120. private SecuritySystem securitySystem;
  121. @Inject
  122. @Named(value = "archivaTaskScheduler#repository")
  123. private ArchivaTaskScheduler<RepositoryTask> scheduler;
  124. @Inject
  125. private DownloadRemoteIndexScheduler downloadRemoteIndexScheduler;
  126. @Inject
  127. @Named(value = "repositorySessionFactory")
  128. protected RepositorySessionFactory repositorySessionFactory;
  129. @Inject
  130. @Autowired(required = false)
  131. protected List<RepositoryListener> listeners = new ArrayList<RepositoryListener>();
  132. @Inject
  133. private RepositoryScanner repoScanner;
  134. /**
  135. * Cache used for namespaces
  136. */
  137. @Inject
  138. @Named(value = "cache#namespaces")
  139. private Cache<String, Collection<String>> namespacesCache;
  140. private List<ChecksumAlgorithm> algorithms = Arrays.asList(ChecksumAlgorithm.SHA256, ChecksumAlgorithm.SHA1, ChecksumAlgorithm.MD5 );
  141. @Override
  142. public Boolean scanRepository( String repositoryId, boolean fullScan )
  143. {
  144. return doScanRepository( repositoryId, fullScan );
  145. }
  146. @Override
  147. public Boolean alreadyScanning( String repositoryId )
  148. {
  149. // check queue first to make sure it doesn't get dequeued between calls
  150. if ( repositoryTaskScheduler.isProcessingRepositoryTask( repositoryId ) )
  151. {
  152. return true;
  153. }
  154. for ( RepositoryScannerInstance scan : repoScanner.getInProgressScans() )
  155. {
  156. if ( scan.getRepository().getId().equals( repositoryId ) )
  157. {
  158. return true;
  159. }
  160. }
  161. return false;
  162. }
  163. @Override
  164. public Boolean removeScanningTaskFromQueue( String repositoryId )
  165. {
  166. RepositoryTask task = new RepositoryTask();
  167. task.setRepositoryId( repositoryId );
  168. try
  169. {
  170. return repositoryTaskScheduler.unQueueTask( task );
  171. }
  172. catch ( TaskQueueException e )
  173. {
  174. log.error( "failed to unschedule scanning of repo with id {}", repositoryId, e );
  175. return false;
  176. }
  177. }
  178. private ManagedRepositoryContent getManagedRepositoryContent(String id) throws RepositoryException
  179. {
  180. org.apache.archiva.repository.ManagedRepository repo = repositoryRegistry.getManagedRepository( id );
  181. if (repo==null) {
  182. throw new RepositoryException( "Repository not found "+id );
  183. }
  184. return repo.getContent();
  185. }
  186. @Override
  187. public Boolean scanRepositoryNow( String repositoryId, boolean fullScan )
  188. throws ArchivaRestServiceException
  189. {
  190. try
  191. {
  192. org.apache.archiva.repository.ManagedRepository repository = repositoryRegistry.getManagedRepository( repositoryId );
  193. ArtifactIndexingTask task =
  194. new ArtifactIndexingTask( repository, null, ArtifactIndexingTask.Action.FINISH, repository.getIndexingContext() );
  195. task.setExecuteOnEntireRepo( true );
  196. task.setOnlyUpdate( !fullScan );
  197. archivaIndexingTaskExecutor.executeTask( task );
  198. scheduler.queueTask( new RepositoryTask( repositoryId, fullScan ) );
  199. return Boolean.TRUE;
  200. }
  201. catch ( Exception e )
  202. {
  203. log.error( e.getMessage(), e );
  204. throw new ArchivaRestServiceException( e.getMessage(), e );
  205. }
  206. }
  207. @Override
  208. public Boolean scheduleDownloadRemoteIndex( String repositoryId, boolean now, boolean fullDownload )
  209. throws ArchivaRestServiceException
  210. {
  211. try
  212. {
  213. downloadRemoteIndexScheduler.scheduleDownloadRemote( repositoryId, now, fullDownload );
  214. }
  215. catch ( DownloadRemoteIndexException e )
  216. {
  217. log.error( e.getMessage(), e );
  218. throw new ArchivaRestServiceException( e.getMessage(), e );
  219. }
  220. return Boolean.TRUE;
  221. }
  222. @Override
  223. public Boolean copyArtifact( ArtifactTransferRequest artifactTransferRequest )
  224. throws ArchivaRestServiceException
  225. {
  226. // check parameters
  227. String userName = getAuditInformation().getUser().getUsername();
  228. if ( StringUtils.isBlank( userName ) )
  229. {
  230. throw new ArchivaRestServiceException( "copyArtifact call: userName not found", null );
  231. }
  232. if ( StringUtils.isBlank( artifactTransferRequest.getRepositoryId() ) )
  233. {
  234. throw new ArchivaRestServiceException( "copyArtifact call: sourceRepositoryId cannot be null", null );
  235. }
  236. if ( StringUtils.isBlank( artifactTransferRequest.getTargetRepositoryId() ) )
  237. {
  238. throw new ArchivaRestServiceException( "copyArtifact call: targetRepositoryId cannot be null", null );
  239. }
  240. ManagedRepository source = null;
  241. source = repositoryRegistry.getManagedRepository( artifactTransferRequest.getRepositoryId() );
  242. if ( source == null )
  243. {
  244. throw new ArchivaRestServiceException(
  245. "cannot find repository with id " + artifactTransferRequest.getRepositoryId(), null );
  246. }
  247. ManagedRepository target = null;
  248. target = repositoryRegistry.getManagedRepository( artifactTransferRequest.getTargetRepositoryId() );
  249. if ( target == null )
  250. {
  251. throw new ArchivaRestServiceException(
  252. "cannot find repository with id " + artifactTransferRequest.getTargetRepositoryId(), null );
  253. }
  254. if ( StringUtils.isBlank( artifactTransferRequest.getGroupId() ) )
  255. {
  256. throw new ArchivaRestServiceException( "groupId is mandatory", null );
  257. }
  258. if ( StringUtils.isBlank( artifactTransferRequest.getArtifactId() ) )
  259. {
  260. throw new ArchivaRestServiceException( "artifactId is mandatory", null );
  261. }
  262. if ( StringUtils.isBlank( artifactTransferRequest.getVersion() ) )
  263. {
  264. throw new ArchivaRestServiceException( "version is mandatory", null );
  265. }
  266. if ( VersionUtil.isSnapshot( artifactTransferRequest.getVersion() ) )
  267. {
  268. throw new ArchivaRestServiceException( "copy of SNAPSHOT not supported", null );
  269. }
  270. // end check parameters
  271. User user = null;
  272. try
  273. {
  274. user = securitySystem.getUserManager().findUser( userName );
  275. }
  276. catch ( UserNotFoundException e )
  277. {
  278. throw new ArchivaRestServiceException( "user " + userName + " not found", e );
  279. }
  280. catch ( UserManagerException e )
  281. {
  282. throw new ArchivaRestServiceException( "ArchivaRestServiceException:" + e.getMessage(), e );
  283. }
  284. // check karma on source : read
  285. AuthenticationResult authn = new AuthenticationResult( true, userName, null );
  286. SecuritySession securitySession = new DefaultSecuritySession( authn, user );
  287. try
  288. {
  289. boolean authz =
  290. securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS,
  291. artifactTransferRequest.getRepositoryId() );
  292. if ( !authz )
  293. {
  294. throw new ArchivaRestServiceException(
  295. "not authorized to access repo:" + artifactTransferRequest.getRepositoryId(), null );
  296. }
  297. }
  298. catch ( AuthorizationException e )
  299. {
  300. log.error( "error reading permission: {}", e.getMessage(), e );
  301. throw new ArchivaRestServiceException( e.getMessage(), e );
  302. }
  303. // check karma on target: write
  304. try
  305. {
  306. boolean authz =
  307. securitySystem.isAuthorized( securitySession, ArchivaRoleConstants.OPERATION_REPOSITORY_UPLOAD,
  308. artifactTransferRequest.getTargetRepositoryId() );
  309. if ( !authz )
  310. {
  311. throw new ArchivaRestServiceException(
  312. "not authorized to write to repo:" + artifactTransferRequest.getTargetRepositoryId(), null );
  313. }
  314. }
  315. catch ( AuthorizationException e )
  316. {
  317. log.error( "error reading permission: {}", e.getMessage(), e );
  318. throw new ArchivaRestServiceException( e.getMessage(), e );
  319. }
  320. // sounds good we can continue !
  321. ArtifactReference artifactReference = new ArtifactReference();
  322. artifactReference.setArtifactId( artifactTransferRequest.getArtifactId() );
  323. artifactReference.setGroupId( artifactTransferRequest.getGroupId() );
  324. artifactReference.setVersion( artifactTransferRequest.getVersion() );
  325. artifactReference.setClassifier( artifactTransferRequest.getClassifier() );
  326. String packaging = StringUtils.trim( artifactTransferRequest.getPackaging() );
  327. artifactReference.setType( StringUtils.isEmpty( packaging ) ? "jar" : packaging );
  328. try
  329. {
  330. ManagedRepositoryContent sourceRepository =
  331. getManagedRepositoryContent( artifactTransferRequest.getRepositoryId() );
  332. String artifactSourcePath = sourceRepository.toPath( artifactReference );
  333. if ( StringUtils.isEmpty( artifactSourcePath ) )
  334. {
  335. log.error( "cannot find artifact {}", artifactTransferRequest );
  336. throw new ArchivaRestServiceException( "cannot find artifact " + artifactTransferRequest.toString(),
  337. null );
  338. }
  339. StorageAsset artifactFile = source.getAsset( artifactSourcePath );
  340. if ( !artifactFile.exists() )
  341. {
  342. log.error( "cannot find artifact {}", artifactTransferRequest );
  343. throw new ArchivaRestServiceException( "cannot find artifact " + artifactTransferRequest.toString(),
  344. null );
  345. }
  346. ManagedRepositoryContent targetRepository =
  347. getManagedRepositoryContent( artifactTransferRequest.getTargetRepositoryId() );
  348. String artifactPath = targetRepository.toPath( artifactReference );
  349. int lastIndex = artifactPath.lastIndexOf( '/' );
  350. String path = artifactPath.substring( 0, lastIndex );
  351. StorageAsset targetPath = target.getAsset( path );
  352. Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
  353. int newBuildNumber = 1;
  354. String timestamp = null;
  355. StorageAsset versionMetadataFile = target.getAsset(path + "/" + MetadataTools.MAVEN_METADATA );
  356. /* unused */ getMetadata( versionMetadataFile );
  357. if ( !targetPath.exists() )
  358. {
  359. targetPath = target.addAsset(targetPath.getPath(), true);
  360. targetPath.create();
  361. }
  362. String filename = artifactPath.substring( lastIndex + 1 );
  363. boolean fixChecksums =
  364. !( archivaAdministration.getKnownContentConsumers().contains( "create-missing-checksums" ) );
  365. StorageAsset targetFile = target.getAsset(targetPath + "/" + filename );
  366. if ( targetFile.exists() && target.blocksRedeployments())
  367. {
  368. throw new ArchivaRestServiceException(
  369. "artifact already exists in target repo: " + artifactTransferRequest.getTargetRepositoryId()
  370. + " and redeployment blocked", null
  371. );
  372. }
  373. else
  374. {
  375. copyFile( source, artifactFile, target, targetFile, fixChecksums );
  376. queueRepositoryTask( target.getId(), targetFile );
  377. }
  378. // copy source pom to target repo
  379. String pomFilename = filename;
  380. if ( StringUtils.isNotBlank( artifactTransferRequest.getClassifier() ) )
  381. {
  382. pomFilename = StringUtils.remove( pomFilename, "-" + artifactTransferRequest.getClassifier() );
  383. }
  384. pomFilename = FilenameUtils.removeExtension( pomFilename ) + ".pom";
  385. StorageAsset pomFile = source.getAsset(
  386. artifactSourcePath.substring( 0, artifactPath.lastIndexOf( '/' ) )+"/"+ pomFilename );
  387. if ( pomFile != null && pomFile.exists() )
  388. {
  389. StorageAsset targetPomFile = target.getAsset( targetPath.getPath() + "/" + pomFilename );
  390. copyFile( source, pomFile, target, targetPomFile, fixChecksums );
  391. queueRepositoryTask( target.getId(), targetPomFile );
  392. }
  393. // explicitly update only if metadata-updater consumer is not enabled!
  394. if ( !archivaAdministration.getKnownContentConsumers().contains( "metadata-updater" ) )
  395. {
  396. updateProjectMetadata( target, targetPath, lastUpdatedTimestamp, timestamp, newBuildNumber,
  397. fixChecksums, artifactTransferRequest );
  398. }
  399. String msg =
  400. "Artifact \'" + artifactTransferRequest.getGroupId() + ":" + artifactTransferRequest.getArtifactId()
  401. + ":" + artifactTransferRequest.getVersion() + "\' was successfully deployed to repository \'"
  402. + artifactTransferRequest.getTargetRepositoryId() + "\'";
  403. log.debug("copyArtifact {}", msg);
  404. }
  405. catch ( RepositoryException e )
  406. {
  407. log.error( "RepositoryException: {}", e.getMessage(), e );
  408. throw new ArchivaRestServiceException( e.getMessage(), e );
  409. }
  410. catch ( RepositoryAdminException e )
  411. {
  412. log.error( "RepositoryAdminException: {}", e.getMessage(), e );
  413. throw new ArchivaRestServiceException( e.getMessage(), e );
  414. }
  415. catch ( IOException e )
  416. {
  417. log.error( "IOException: {}", e.getMessage(), e );
  418. throw new ArchivaRestServiceException( e.getMessage(), e );
  419. }
  420. return true;
  421. }
  422. private void queueRepositoryTask( String repositoryId, StorageAsset localFile )
  423. {
  424. RepositoryTask task = new RepositoryTask();
  425. task.setRepositoryId( repositoryId );
  426. task.setResourceFile( localFile );
  427. task.setUpdateRelatedArtifacts( true );
  428. //task.setScanAll( true );
  429. try
  430. {
  431. scheduler.queueTask( task );
  432. }
  433. catch ( TaskQueueException e )
  434. {
  435. log.error( "Unable to queue repository task to execute consumers on resource file ['{}"
  436. + "'].", localFile.getName());
  437. }
  438. }
  439. private ArchivaRepositoryMetadata getMetadata( StorageAsset metadataFile )
  440. throws RepositoryMetadataException
  441. {
  442. ArchivaRepositoryMetadata metadata = new ArchivaRepositoryMetadata();
  443. if ( metadataFile.exists() )
  444. {
  445. try
  446. {
  447. metadata = MavenMetadataReader.read( metadataFile.getFilePath() );
  448. }
  449. catch (XMLException | IOException e )
  450. {
  451. throw new RepositoryMetadataException( e.getMessage(), e );
  452. }
  453. }
  454. return metadata;
  455. }
  456. private StorageAsset getMetadata( RepositoryStorage storage, String targetPath )
  457. {
  458. return storage.getAsset( targetPath + "/" + MetadataTools.MAVEN_METADATA );
  459. }
  460. /*
  461. * Copies the asset to the new target.
  462. */
  463. private void copyFile( RepositoryStorage sourceStorage, StorageAsset sourceFile, RepositoryStorage targetStorage, StorageAsset targetPath, boolean fixChecksums )
  464. throws IOException
  465. {
  466. StorageUtil.copyAsset( sourceFile, targetPath, true );
  467. if ( fixChecksums )
  468. {
  469. fixChecksums( targetPath );
  470. }
  471. }
  472. private void fixChecksums( StorageAsset file )
  473. {
  474. Path destinationFile = file.getFilePath();
  475. if (destinationFile!=null)
  476. {
  477. ChecksummedFile checksum = new ChecksummedFile( destinationFile );
  478. checksum.fixChecksums( algorithms );
  479. }
  480. }
  481. private void updateProjectMetadata( RepositoryStorage storage, StorageAsset targetPath, Date lastUpdatedTimestamp, String timestamp, int buildNumber,
  482. boolean fixChecksums, ArtifactTransferRequest artifactTransferRequest )
  483. throws RepositoryMetadataException
  484. {
  485. List<String> availableVersions = new ArrayList<>();
  486. String latestVersion = artifactTransferRequest.getVersion();
  487. StorageAsset projectDir = targetPath.getParent();
  488. StorageAsset projectMetadataFile = storage.getAsset( projectDir.getPath()+"/"+MetadataTools.MAVEN_METADATA );
  489. ArchivaRepositoryMetadata projectMetadata = getMetadata( projectMetadataFile );
  490. if ( projectMetadataFile.exists() )
  491. {
  492. availableVersions = projectMetadata.getAvailableVersions();
  493. Collections.sort( availableVersions, VersionComparator.getInstance() );
  494. if ( !availableVersions.contains( artifactTransferRequest.getVersion() ) )
  495. {
  496. availableVersions.add( artifactTransferRequest.getVersion() );
  497. }
  498. latestVersion = availableVersions.get( availableVersions.size() - 1 );
  499. }
  500. else
  501. {
  502. availableVersions.add( artifactTransferRequest.getVersion() );
  503. projectMetadata.setGroupId( artifactTransferRequest.getGroupId() );
  504. projectMetadata.setArtifactId( artifactTransferRequest.getArtifactId() );
  505. }
  506. if ( projectMetadata.getGroupId() == null )
  507. {
  508. projectMetadata.setGroupId( artifactTransferRequest.getGroupId() );
  509. }
  510. if ( projectMetadata.getArtifactId() == null )
  511. {
  512. projectMetadata.setArtifactId( artifactTransferRequest.getArtifactId() );
  513. }
  514. projectMetadata.setLatestVersion( latestVersion );
  515. projectMetadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
  516. projectMetadata.setAvailableVersions( availableVersions );
  517. if ( !VersionUtil.isSnapshot( artifactTransferRequest.getVersion() ) )
  518. {
  519. projectMetadata.setReleasedVersion( latestVersion );
  520. }
  521. try(OutputStreamWriter writer = new OutputStreamWriter(projectMetadataFile.getWriteStream(true))) {
  522. RepositoryMetadataWriter.write(projectMetadata, writer);
  523. } catch (IOException e) {
  524. throw new RepositoryMetadataException(e);
  525. }
  526. if ( fixChecksums )
  527. {
  528. fixChecksums( projectMetadataFile );
  529. }
  530. }
  531. @Override
  532. public Boolean removeProjectVersion( String repositoryId, String namespace, String projectId, String version )
  533. throws ArchivaRestServiceException
  534. {
  535. // if not a generic we can use the standard way to delete artifact
  536. if ( !VersionUtil.isGenericSnapshot( version ) )
  537. {
  538. Artifact artifact = new Artifact( namespace, projectId, version );
  539. artifact.setRepositoryId( repositoryId );
  540. artifact.setContext( repositoryId );
  541. return deleteArtifact( artifact );
  542. }
  543. if ( StringUtils.isEmpty( repositoryId ) )
  544. {
  545. throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
  546. }
  547. if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
  548. {
  549. throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
  550. }
  551. if ( StringUtils.isEmpty( namespace ) )
  552. {
  553. throw new ArchivaRestServiceException( "groupId cannot be null", 400, null );
  554. }
  555. if ( StringUtils.isEmpty( projectId ) )
  556. {
  557. throw new ArchivaRestServiceException( "artifactId cannot be null", 400, null );
  558. }
  559. if ( StringUtils.isEmpty( version ) )
  560. {
  561. throw new ArchivaRestServiceException( "version cannot be null", 400, null );
  562. }
  563. RepositorySession repositorySession = repositorySessionFactory.createSession();
  564. try
  565. {
  566. ManagedRepositoryContent repository = getManagedRepositoryContent( repositoryId );
  567. VersionedReference ref = new VersionedReference();
  568. ref.setArtifactId( projectId );
  569. ref.setGroupId( namespace );
  570. ref.setVersion( version );
  571. repository.deleteVersion( ref );
  572. /*
  573. ProjectReference projectReference = new ProjectReference();
  574. projectReference.setGroupId( namespace );
  575. projectReference.setArtifactId( projectId );
  576. repository.getVersions( )
  577. */
  578. ArtifactReference artifactReference = new ArtifactReference();
  579. artifactReference.setGroupId( namespace );
  580. artifactReference.setArtifactId( projectId );
  581. artifactReference.setVersion( version );
  582. MetadataRepository metadataRepository = repositorySession.getRepository();
  583. Set<ArtifactReference> related = repository.getRelatedArtifacts( artifactReference );
  584. log.debug( "related: {}", related );
  585. for ( ArtifactReference artifactRef : related )
  586. {
  587. repository.deleteArtifact( artifactRef );
  588. }
  589. Collection<ArtifactMetadata> artifacts =
  590. metadataRepository.getArtifacts( repositoryId, namespace, projectId, version );
  591. for ( ArtifactMetadata artifactMetadata : artifacts )
  592. {
  593. metadataRepository.removeArtifact( artifactMetadata, version );
  594. }
  595. metadataRepository.removeProjectVersion( repositoryId, namespace, projectId, version );
  596. }
  597. catch ( MetadataRepositoryException e )
  598. {
  599. throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
  600. }
  601. catch ( MetadataResolutionException e )
  602. {
  603. throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
  604. }
  605. catch ( RepositoryException e )
  606. {
  607. throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
  608. }
  609. finally
  610. {
  611. repositorySession.save();
  612. repositorySession.close();
  613. }
  614. return Boolean.TRUE;
  615. }
  616. @Override
  617. public Boolean deleteArtifact( Artifact artifact )
  618. throws ArchivaRestServiceException
  619. {
  620. String repositoryId = artifact.getContext();
  621. // some rest call can use context or repositoryId
  622. // so try both!!
  623. if ( StringUtils.isEmpty( repositoryId ) )
  624. {
  625. repositoryId = artifact.getRepositoryId();
  626. }
  627. if ( StringUtils.isEmpty( repositoryId ) )
  628. {
  629. throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
  630. }
  631. if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
  632. {
  633. throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
  634. }
  635. if ( artifact == null )
  636. {
  637. throw new ArchivaRestServiceException( "artifact cannot be null", 400, null );
  638. }
  639. if ( StringUtils.isEmpty( artifact.getGroupId() ) )
  640. {
  641. throw new ArchivaRestServiceException( "artifact.groupId cannot be null", 400, null );
  642. }
  643. if ( StringUtils.isEmpty( artifact.getArtifactId() ) )
  644. {
  645. throw new ArchivaRestServiceException( "artifact.artifactId cannot be null", 400, null );
  646. }
  647. // TODO more control on artifact fields
  648. boolean snapshotVersion =
  649. VersionUtil.isSnapshot( artifact.getVersion() ) | VersionUtil.isGenericSnapshot( artifact.getVersion() );
  650. RepositorySession repositorySession = repositorySessionFactory.createSession();
  651. try
  652. {
  653. Date lastUpdatedTimestamp = Calendar.getInstance().getTime();
  654. TimeZone timezone = TimeZone.getTimeZone( "UTC" );
  655. DateFormat fmt = new SimpleDateFormat( "yyyyMMdd.HHmmss" );
  656. fmt.setTimeZone( timezone );
  657. ManagedRepository repo = repositoryRegistry.getManagedRepository( repositoryId );
  658. VersionedReference ref = new VersionedReference();
  659. ref.setArtifactId( artifact.getArtifactId() );
  660. ref.setGroupId( artifact.getGroupId() );
  661. ref.setVersion( artifact.getVersion() );
  662. ManagedRepositoryContent repository = getManagedRepositoryContent( repositoryId );
  663. ArtifactReference artifactReference = new ArtifactReference();
  664. artifactReference.setArtifactId( artifact.getArtifactId() );
  665. artifactReference.setGroupId( artifact.getGroupId() );
  666. artifactReference.setVersion( artifact.getVersion() );
  667. artifactReference.setClassifier( artifact.getClassifier() );
  668. artifactReference.setType( artifact.getPackaging() );
  669. MetadataRepository metadataRepository = repositorySession.getRepository();
  670. String path = repository.toMetadataPath( ref );
  671. if ( StringUtils.isNotBlank( artifact.getClassifier() ) )
  672. {
  673. if ( StringUtils.isBlank( artifact.getPackaging() ) )
  674. {
  675. throw new ArchivaRestServiceException( "You must configure a type/packaging when using classifier",
  676. 400, null );
  677. }
  678. repository.deleteArtifact( artifactReference );
  679. }
  680. else
  681. {
  682. int index = path.lastIndexOf( '/' );
  683. path = path.substring( 0, index );
  684. StorageAsset targetPath = repo.getAsset( path );
  685. if ( targetPath.exists() )
  686. {
  687. //throw new ContentNotFoundException(
  688. // artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion() );
  689. log.warn( "targetPath {} not found skip file deletion", targetPath );
  690. }
  691. // TODO: this should be in the storage mechanism so that it is all tied together
  692. // delete from file system
  693. if ( !snapshotVersion )
  694. {
  695. repository.deleteVersion( ref );
  696. }
  697. else
  698. {
  699. Set<ArtifactReference> related = repository.getRelatedArtifacts( artifactReference );
  700. log.debug( "related: {}", related );
  701. for ( ArtifactReference artifactRef : related )
  702. {
  703. repository.deleteArtifact( artifactRef );
  704. }
  705. }
  706. StorageAsset metadataFile = getMetadata( repo, targetPath.getPath() );
  707. ArchivaRepositoryMetadata metadata = getMetadata( metadataFile );
  708. updateMetadata( metadata, metadataFile, lastUpdatedTimestamp, artifact );
  709. }
  710. Collection<ArtifactMetadata> artifacts = Collections.emptyList();
  711. if ( snapshotVersion )
  712. {
  713. String baseVersion = VersionUtil.getBaseVersion( artifact.getVersion() );
  714. artifacts =
  715. metadataRepository.getArtifacts( repositoryId, artifact.getGroupId(), artifact.getArtifactId(),
  716. baseVersion );
  717. }
  718. else
  719. {
  720. artifacts =
  721. metadataRepository.getArtifacts( repositoryId, artifact.getGroupId(), artifact.getArtifactId(),
  722. artifact.getVersion() );
  723. }
  724. log.debug( "artifacts: {}", artifacts );
  725. if ( artifacts.isEmpty() )
  726. {
  727. if ( !snapshotVersion )
  728. {
  729. // verify metata repository doesn't contains anymore the version
  730. Collection<String> projectVersions =
  731. metadataRepository.getProjectVersions( repositoryId, artifact.getGroupId(),
  732. artifact.getArtifactId() );
  733. if ( projectVersions.contains( artifact.getVersion() ) )
  734. {
  735. log.warn( "artifact not found when deleted but version still here ! so force cleanup" );
  736. metadataRepository.removeProjectVersion( repositoryId, artifact.getGroupId(),
  737. artifact.getArtifactId(), artifact.getVersion() );
  738. }
  739. }
  740. }
  741. for ( ArtifactMetadata artifactMetadata : artifacts )
  742. {
  743. // TODO: mismatch between artifact (snapshot) version and project (base) version here
  744. if ( artifactMetadata.getVersion().equals( artifact.getVersion() ) )
  745. {
  746. if ( StringUtils.isNotBlank( artifact.getClassifier() ) )
  747. {
  748. if ( StringUtils.isBlank( artifact.getPackaging() ) )
  749. {
  750. throw new ArchivaRestServiceException(
  751. "You must configure a type/packaging when using classifier", 400, null );
  752. }
  753. // cleanup facet which contains classifier information
  754. MavenArtifactFacet mavenArtifactFacet =
  755. (MavenArtifactFacet) artifactMetadata.getFacet( MavenArtifactFacet.FACET_ID );
  756. if ( StringUtils.equals( artifact.getClassifier(), mavenArtifactFacet.getClassifier() ) )
  757. {
  758. artifactMetadata.removeFacet( MavenArtifactFacet.FACET_ID );
  759. String groupId = artifact.getGroupId(), artifactId = artifact.getArtifactId(), version =
  760. artifact.getVersion();
  761. MavenArtifactFacet mavenArtifactFacetToCompare = new MavenArtifactFacet();
  762. mavenArtifactFacetToCompare.setClassifier( artifact.getClassifier() );
  763. metadataRepository.removeArtifact( repositoryId, groupId, artifactId, version,
  764. mavenArtifactFacetToCompare );
  765. metadataRepository.save();
  766. }
  767. }
  768. else
  769. {
  770. if ( snapshotVersion )
  771. {
  772. metadataRepository.removeArtifact( artifactMetadata,
  773. VersionUtil.getBaseVersion( artifact.getVersion() ) );
  774. }
  775. else
  776. {
  777. metadataRepository.removeArtifact( artifactMetadata.getRepositoryId(),
  778. artifactMetadata.getNamespace(),
  779. artifactMetadata.getProject(), artifact.getVersion(),
  780. artifactMetadata.getId() );
  781. }
  782. }
  783. // TODO: move into the metadata repository proper - need to differentiate attachment of
  784. // repository metadata to an artifact
  785. for ( RepositoryListener listener : listeners )
  786. {
  787. listener.deleteArtifact( metadataRepository, repository.getId(),
  788. artifactMetadata.getNamespace(), artifactMetadata.getProject(),
  789. artifactMetadata.getVersion(), artifactMetadata.getId() );
  790. }
  791. triggerAuditEvent( repositoryId, path, AuditEvent.REMOVE_FILE );
  792. }
  793. }
  794. }
  795. catch ( ContentNotFoundException e )
  796. {
  797. throw new ArchivaRestServiceException( "Artifact does not exist: " + e.getMessage(), 400, e );
  798. }
  799. catch ( RepositoryNotFoundException e )
  800. {
  801. throw new ArchivaRestServiceException( "Target repository cannot be found: " + e.getMessage(), 400, e );
  802. }
  803. catch ( RepositoryException e )
  804. {
  805. throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
  806. }
  807. catch ( MetadataResolutionException e )
  808. {
  809. throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
  810. }
  811. catch ( MetadataRepositoryException e )
  812. {
  813. throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
  814. }
  815. finally
  816. {
  817. repositorySession.save();
  818. repositorySession.close();
  819. }
  820. return Boolean.TRUE;
  821. }
  822. @Override
  823. public Boolean deleteGroupId( String groupId, String repositoryId )
  824. throws ArchivaRestServiceException
  825. {
  826. if ( StringUtils.isEmpty( repositoryId ) )
  827. {
  828. throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
  829. }
  830. if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
  831. {
  832. throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
  833. }
  834. if ( StringUtils.isEmpty( groupId ) )
  835. {
  836. throw new ArchivaRestServiceException( "groupId cannot be null", 400, null );
  837. }
  838. RepositorySession repositorySession = repositorySessionFactory.createSession();
  839. try
  840. {
  841. ManagedRepositoryContent repository = getManagedRepositoryContent( repositoryId );
  842. repository.deleteGroupId( groupId );
  843. MetadataRepository metadataRepository = repositorySession.getRepository();
  844. metadataRepository.removeNamespace( repositoryId, groupId );
  845. // just invalidate cache entry
  846. String cacheKey = repositoryId + "-" + groupId;
  847. namespacesCache.remove( cacheKey );
  848. namespacesCache.remove( repositoryId );
  849. metadataRepository.save();
  850. }
  851. catch ( MetadataRepositoryException e )
  852. {
  853. log.error( e.getMessage(), e );
  854. throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
  855. }
  856. catch ( RepositoryException e )
  857. {
  858. log.error( e.getMessage(), e );
  859. throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
  860. }
  861. finally
  862. {
  863. repositorySession.close();
  864. }
  865. return true;
  866. }
  867. @Override
  868. public Boolean deleteProject( String groupId, String projectId, String repositoryId )
  869. throws ArchivaRestServiceException
  870. {
  871. if ( StringUtils.isEmpty( repositoryId ) )
  872. {
  873. throw new ArchivaRestServiceException( "repositoryId cannot be null", 400, null );
  874. }
  875. if ( !isAuthorizedToDeleteArtifacts( repositoryId ) )
  876. {
  877. throw new ArchivaRestServiceException( "not authorized to delete artifacts", 403, null );
  878. }
  879. if ( StringUtils.isEmpty( groupId ) )
  880. {
  881. throw new ArchivaRestServiceException( "groupId cannot be null", 400, null );
  882. }
  883. if ( StringUtils.isEmpty( projectId ) )
  884. {
  885. throw new ArchivaRestServiceException( "artifactId cannot be null", 400, null );
  886. }
  887. RepositorySession repositorySession = repositorySessionFactory.createSession();
  888. try
  889. {
  890. ManagedRepositoryContent repository = getManagedRepositoryContent( repositoryId );
  891. repository.deleteProject( groupId, projectId );
  892. }
  893. catch ( ContentNotFoundException e )
  894. {
  895. log.warn( "skip ContentNotFoundException: {}", e.getMessage() );
  896. }
  897. catch ( RepositoryException e )
  898. {
  899. log.error( e.getMessage(), e );
  900. throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
  901. }
  902. try
  903. {
  904. MetadataRepository metadataRepository = repositorySession.getRepository();
  905. metadataRepository.removeProject( repositoryId, groupId, projectId );
  906. metadataRepository.save();
  907. }
  908. catch ( MetadataRepositoryException e )
  909. {
  910. log.error( e.getMessage(), e );
  911. throw new ArchivaRestServiceException( "Repository exception: " + e.getMessage(), 500, e );
  912. }
  913. finally
  914. {
  915. repositorySession.close();
  916. }
  917. return true;
  918. }
  919. @Override
  920. public Boolean isAuthorizedToDeleteArtifacts( String repoId )
  921. throws ArchivaRestServiceException
  922. {
  923. String userName =
  924. getAuditInformation().getUser() == null ? "guest" : getAuditInformation().getUser().getUsername();
  925. try
  926. {
  927. return userRepositories.isAuthorizedToDeleteArtifacts( userName, repoId );
  928. }
  929. catch ( ArchivaSecurityException e )
  930. {
  931. throw new ArchivaRestServiceException( e.getMessage(),
  932. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  933. }
  934. }
  935. @Override
  936. public RepositoryScanStatistics scanRepositoryDirectoriesNow( String repositoryId )
  937. throws ArchivaRestServiceException
  938. {
  939. long sinceWhen = RepositoryScanner.FRESH_SCAN;
  940. try
  941. {
  942. return repoScanner.scan( repositoryRegistry.getManagedRepository( repositoryId ), sinceWhen );
  943. }
  944. catch ( RepositoryScannerException e )
  945. {
  946. log.error( e.getMessage(), e );
  947. throw new ArchivaRestServiceException( "RepositoryScannerException exception: " + e.getMessage(), 500, e );
  948. }
  949. }
  950. /**
  951. * Update artifact level metadata. Creates one if metadata does not exist after artifact deletion.
  952. *
  953. * @param metadata
  954. */
  955. private void updateMetadata( ArchivaRepositoryMetadata metadata, StorageAsset metadataFile, Date lastUpdatedTimestamp,
  956. Artifact artifact )
  957. throws RepositoryMetadataException
  958. {
  959. List<String> availableVersions = new ArrayList<>();
  960. String latestVersion = "";
  961. if ( metadataFile.exists() )
  962. {
  963. if ( metadata.getAvailableVersions() != null )
  964. {
  965. availableVersions = metadata.getAvailableVersions();
  966. if ( availableVersions.size() > 0 )
  967. {
  968. Collections.sort( availableVersions, VersionComparator.getInstance() );
  969. if ( availableVersions.contains( artifact.getVersion() ) )
  970. {
  971. availableVersions.remove( availableVersions.indexOf( artifact.getVersion() ) );
  972. }
  973. if ( availableVersions.size() > 0 )
  974. {
  975. latestVersion = availableVersions.get( availableVersions.size() - 1 );
  976. }
  977. }
  978. }
  979. }
  980. if ( metadata.getGroupId() == null )
  981. {
  982. metadata.setGroupId( artifact.getGroupId() );
  983. }
  984. if ( metadata.getArtifactId() == null )
  985. {
  986. metadata.setArtifactId( artifact.getArtifactId() );
  987. }
  988. if ( !VersionUtil.isSnapshot( artifact.getVersion() ) )
  989. {
  990. if ( metadata.getReleasedVersion() != null && metadata.getReleasedVersion().equals(
  991. artifact.getVersion() ) )
  992. {
  993. metadata.setReleasedVersion( latestVersion );
  994. }
  995. }
  996. metadata.setLatestVersion( latestVersion );
  997. metadata.setLastUpdatedTimestamp( lastUpdatedTimestamp );
  998. metadata.setAvailableVersions( availableVersions );
  999. try (OutputStreamWriter writer = new OutputStreamWriter(metadataFile.getWriteStream(true))) {
  1000. RepositoryMetadataWriter.write(metadata, writer);
  1001. } catch (IOException e) {
  1002. throw new RepositoryMetadataException(e);
  1003. }
  1004. ChecksummedFile checksum = new ChecksummedFile( metadataFile.getFilePath() );
  1005. checksum.fixChecksums( algorithms );
  1006. }
  1007. @Override
  1008. public StringList getRunningRemoteDownloadIds()
  1009. {
  1010. return new StringList( downloadRemoteIndexScheduler.getRunningRemoteDownloadIds() );
  1011. }
  1012. public RepositorySessionFactory getRepositorySessionFactory()
  1013. {
  1014. return repositorySessionFactory;
  1015. }
  1016. public void setRepositorySessionFactory( RepositorySessionFactory repositorySessionFactory )
  1017. {
  1018. this.repositorySessionFactory = repositorySessionFactory;
  1019. }
  1020. public List<RepositoryListener> getListeners()
  1021. {
  1022. return listeners;
  1023. }
  1024. public void setListeners( List<RepositoryListener> listeners )
  1025. {
  1026. this.listeners = listeners;
  1027. }
  1028. public ArchivaAdministration getArchivaAdministration()
  1029. {
  1030. return archivaAdministration;
  1031. }
  1032. public void setArchivaAdministration( ArchivaAdministration archivaAdministration )
  1033. {
  1034. this.archivaAdministration = archivaAdministration;
  1035. }
  1036. }