Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

DefaultMetadataResolver.java 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. package org.apache.archiva.metadata.repository;
  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.metadata.model.ArtifactMetadata;
  21. import org.apache.archiva.metadata.model.ProjectMetadata;
  22. import org.apache.archiva.metadata.model.ProjectVersionMetadata;
  23. import org.apache.archiva.metadata.model.ProjectVersionReference;
  24. import org.apache.archiva.filter.ExcludesFilter;
  25. import org.apache.archiva.metadata.repository.storage.ReadMetadataRequest;
  26. import org.apache.archiva.metadata.repository.storage.RepositoryStorage;
  27. import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataInvalidException;
  28. import org.apache.archiva.metadata.repository.storage.RepositoryStorageMetadataNotFoundException;
  29. import org.apache.archiva.metadata.repository.storage.RepositoryStorageRuntimeException;
  30. import org.apache.archiva.redback.components.cache.Cache;
  31. import org.apache.archiva.repository.events.RepositoryListener;
  32. import org.slf4j.Logger;
  33. import org.slf4j.LoggerFactory;
  34. import org.springframework.beans.factory.annotation.Autowired;
  35. import org.springframework.stereotype.Service;
  36. import javax.inject.Inject;
  37. import javax.inject.Named;
  38. import java.util.ArrayList;
  39. import java.util.Collection;
  40. import java.util.List;
  41. /**
  42. * <p>
  43. * Default implementation of the metadata resolver API. At present it will handle updating the content repository
  44. * from new or changed information in the model and artifacts from the repository storage.
  45. * </p>
  46. * <p>
  47. * This is a singleton component to allow an alternate implementation to be provided. It is intended to be the same
  48. * system-wide for the whole content repository instead of on a per-managed-repository basis. Therefore, the session is
  49. * passed in as an argument to obtain any necessary resources, rather than the class being instantiated within the
  50. * session in the context of a single managed repository's resolution needs.
  51. * </p>
  52. * <p>
  53. * Note that the caller is responsible for the session, such as closing and saving (which is implied by the resolver
  54. * being obtained from within the session). The {@link RepositorySession#markDirty()} method is used as a hint to ensure
  55. * that the session knows we've made changes at close. We cannot ensure the changes will be persisted if the caller
  56. * chooses to revert first. This is preferable to storing the metadata immediately - a separate session would require
  57. * having a bi-directional link with the session factory, and saving the existing session might save other changes
  58. * unknowingly by the caller.
  59. * </p>
  60. */
  61. @Service("metadataResolver#default")
  62. public class DefaultMetadataResolver
  63. implements MetadataResolver
  64. {
  65. private Logger log = LoggerFactory.getLogger( DefaultMetadataResolver.class );
  66. /**
  67. * <p>
  68. * FIXME: this needs to be configurable based on storage type - and could also be instantiated per repo. Change to a
  69. * factory, and perhaps retrieve from the session. We should avoid creating one per request, however.
  70. * </p>
  71. * <p>
  72. * TODO: Also need to accommodate availability of proxy module
  73. * ... could be a different type since we need methods to modify the storage metadata, which would also allow more
  74. * appropriate methods to pass in the already determined repository configuration, for example, instead of the ID
  75. * </p>
  76. */
  77. @Inject
  78. @Named(value = "repositoryStorage#maven2")
  79. private RepositoryStorage repositoryStorage;
  80. @Inject
  81. @Autowired(required = false)
  82. private List<RepositoryListener> listeners = new ArrayList<>();
  83. /**
  84. * Cache used for namespaces
  85. */
  86. @Inject
  87. @Named( value = "cache#namespaces" )
  88. private Cache<String, Collection<String>> namespacesCache;
  89. @Override
  90. public ProjectVersionMetadata resolveProjectVersion( RepositorySession session, String repoId, String namespace,
  91. String projectId, String projectVersion )
  92. throws MetadataResolutionException
  93. {
  94. MetadataRepository metadataRepository = session.getRepository();
  95. ProjectVersionMetadata metadata =
  96. metadataRepository.getProjectVersion( repoId, namespace, projectId, projectVersion );
  97. // TODO: do we want to detect changes as well by comparing timestamps? isProjectVersionNewerThan(updated)
  98. // in such cases we might also remove/update stale metadata, including adjusting plugin-based facets
  99. // This would also be better than checking for completeness - we can then refresh only when fixed (though
  100. // sometimes this has an additional dependency - such as a parent - requesting the user to force an update
  101. // may then work here and be more efficient than always trying again)
  102. if ( metadata == null || metadata.isIncomplete() )
  103. {
  104. try
  105. {
  106. ReadMetadataRequest readMetadataRequest =
  107. new ReadMetadataRequest().repositoryId( repoId ).namespace( namespace ).projectId(
  108. projectId ).projectVersion( projectVersion ).browsingRequest( true );
  109. metadata = repositoryStorage.readProjectVersionMetadata( readMetadataRequest );
  110. log.debug( "Resolved project version metadata from storage: {}", metadata );
  111. // FIXME: make this a more generic post-processing that plugins can take advantage of
  112. // eg. maven projects should be able to process parent here
  113. if ( !metadata.getDependencies().isEmpty() )
  114. {
  115. ProjectVersionReference ref = new ProjectVersionReference();
  116. ref.setNamespace( namespace );
  117. ref.setProjectId( projectId );
  118. ref.setProjectVersion( projectVersion );
  119. ref.setReferenceType( ProjectVersionReference.ReferenceType.DEPENDENCY );
  120. }
  121. try
  122. {
  123. for ( RepositoryListener listener : listeners )
  124. {
  125. listener.addArtifact( session, repoId, namespace, projectId, metadata );
  126. }
  127. metadataRepository.updateProjectVersion( repoId, namespace, projectId, metadata );
  128. }
  129. catch ( MetadataRepositoryException e )
  130. {
  131. log.warn( "Unable to persist resolved information: {}", e.getMessage(), e );
  132. }
  133. session.markDirty();
  134. }
  135. catch ( RepositoryStorageMetadataInvalidException e )
  136. {
  137. for ( RepositoryListener listener : listeners )
  138. {
  139. listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
  140. }
  141. throw new MetadataResolutionException( e.getMessage(), e );
  142. }
  143. catch ( RepositoryStorageMetadataNotFoundException e )
  144. {
  145. for ( RepositoryListener listener : listeners )
  146. {
  147. listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
  148. }
  149. // no need to rethrow - return null
  150. }
  151. catch ( RepositoryStorageRuntimeException e )
  152. {
  153. for ( RepositoryListener listener : listeners )
  154. {
  155. listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
  156. }
  157. throw new MetadataResolutionException( e.getMessage(), e );
  158. }
  159. }
  160. return metadata;
  161. }
  162. @Override
  163. public Collection<ProjectVersionReference> resolveProjectReferences( RepositorySession session, String repoId,
  164. String namespace, String projectId,
  165. String projectVersion )
  166. throws MetadataResolutionException
  167. {
  168. // TODO: is this assumption correct? could a storage mech. actually know all references in a non-Maven scenario?
  169. // not passed to the storage mechanism as resolving references would require iterating all artifacts
  170. MetadataRepository metadataRepository = session.getRepository();
  171. return metadataRepository.getProjectReferences( repoId, namespace, projectId, projectVersion );
  172. }
  173. @Override
  174. public Collection<String> resolveRootNamespaces( RepositorySession session, String repoId )
  175. throws MetadataResolutionException
  176. {
  177. try
  178. {
  179. Collection<String> namespaces = namespacesCache.get( repoId );
  180. if ( namespaces != null )
  181. {
  182. return namespaces;
  183. }
  184. MetadataRepository metadataRepository = session.getRepository();
  185. namespaces = metadataRepository.getRootNamespaces( repoId );
  186. Collection<String> storageNamespaces =
  187. repositoryStorage.listRootNamespaces( repoId, new ExcludesFilter<String>( namespaces ) );
  188. if ( storageNamespaces != null && !storageNamespaces.isEmpty() )
  189. {
  190. log.debug( "Resolved root namespaces from storage: {}", storageNamespaces );
  191. for ( String n : storageNamespaces )
  192. {
  193. try
  194. {
  195. metadataRepository.updateNamespace( repoId, n );
  196. // just invalidate cache entry
  197. String cacheKey = repoId + "-" + n;
  198. namespacesCache.remove( cacheKey );
  199. }
  200. catch ( MetadataRepositoryException e )
  201. {
  202. log.warn( "Unable to persist resolved information: {}", e.getMessage(), e );
  203. }
  204. }
  205. session.markDirty();
  206. namespaces = new ArrayList<>( namespaces );
  207. namespaces.addAll( storageNamespaces );
  208. }
  209. namespacesCache.put( repoId, namespaces );
  210. return namespaces;
  211. }
  212. catch ( RepositoryStorageRuntimeException e )
  213. {
  214. throw new MetadataResolutionException( e.getMessage(), e );
  215. }
  216. }
  217. @Override
  218. public Collection<String> resolveNamespaces( RepositorySession session, String repoId, String namespace )
  219. throws MetadataResolutionException
  220. {
  221. try
  222. {
  223. MetadataRepository metadataRepository = session.getRepository();
  224. String cacheKey = repoId + "-" + namespace;
  225. Collection<String> namespaces = namespacesCache.get( cacheKey );
  226. if ( namespaces == null )
  227. {
  228. namespaces = metadataRepository.getNamespaces( repoId, namespace );
  229. namespacesCache.put( cacheKey, namespaces );
  230. }
  231. Collection<String> exclusions = new ArrayList<>( namespaces );
  232. exclusions.addAll( metadataRepository.getProjects( repoId, namespace ) );
  233. Collection<String> storageNamespaces =
  234. repositoryStorage.listNamespaces( repoId, namespace, new ExcludesFilter<String>( exclusions ) );
  235. if ( storageNamespaces != null && !storageNamespaces.isEmpty() )
  236. {
  237. log.debug( "Resolved namespaces from storage: {}", storageNamespaces );
  238. for ( String n : storageNamespaces )
  239. {
  240. try
  241. {
  242. metadataRepository.updateNamespace( repoId, namespace + "." + n );
  243. // just invalidate cache entry
  244. cacheKey = repoId + "-" + namespace + "." + n;
  245. namespacesCache.remove( cacheKey );
  246. }
  247. catch ( MetadataRepositoryException e )
  248. {
  249. log.warn( "Unable to persist resolved information: {}", e.getMessage(), e );
  250. }
  251. }
  252. session.markDirty();
  253. namespaces = new ArrayList<>( namespaces );
  254. namespaces.addAll( storageNamespaces );
  255. }
  256. return namespaces;
  257. }
  258. catch ( RepositoryStorageRuntimeException e )
  259. {
  260. throw new MetadataResolutionException( e.getMessage(), e );
  261. }
  262. }
  263. @Override
  264. public Collection<String> resolveProjects( RepositorySession session, String repoId, String namespace )
  265. throws MetadataResolutionException
  266. {
  267. try
  268. {
  269. MetadataRepository metadataRepository = session.getRepository();
  270. Collection<String> projects = metadataRepository.getProjects( repoId, namespace );
  271. Collection<String> exclusions = new ArrayList<>( projects );
  272. String cacheKey = repoId + "-" + namespace;
  273. Collection<String> namespaces = namespacesCache.get( cacheKey );
  274. if ( namespaces == null )
  275. {
  276. namespaces = metadataRepository.getNamespaces( repoId, namespace );
  277. namespacesCache.put( cacheKey, namespaces );
  278. }
  279. exclusions.addAll( namespaces );
  280. Collection<String> storageProjects =
  281. repositoryStorage.listProjects( repoId, namespace, new ExcludesFilter<>( exclusions ) );
  282. if ( storageProjects != null && !storageProjects.isEmpty() )
  283. {
  284. log.debug( "Resolved projects from storage: {}", storageProjects );
  285. for ( String projectId : storageProjects )
  286. {
  287. ProjectMetadata projectMetadata =
  288. repositoryStorage.readProjectMetadata( repoId, namespace, projectId );
  289. if ( projectMetadata != null )
  290. {
  291. try
  292. {
  293. metadataRepository.updateProject( repoId, projectMetadata );
  294. }
  295. catch ( MetadataRepositoryException e )
  296. {
  297. log.warn( "Unable to persist resolved information: {}", e.getMessage(), e );
  298. }
  299. }
  300. }
  301. session.markDirty();
  302. projects = new ArrayList<>( projects );
  303. projects.addAll( storageProjects );
  304. }
  305. return projects;
  306. }
  307. catch ( RepositoryStorageRuntimeException e )
  308. {
  309. throw new MetadataResolutionException( e.getMessage(), e );
  310. }
  311. }
  312. @Override
  313. public Collection<String> resolveProjectVersions( RepositorySession session, String repoId, String namespace,
  314. String projectId )
  315. throws MetadataResolutionException
  316. {
  317. try
  318. {
  319. MetadataRepository metadataRepository = session.getRepository();
  320. Collection<String> projectVersions = metadataRepository.getProjectVersions( repoId, namespace, projectId );
  321. Collection<String> storageProjectVersions =
  322. repositoryStorage.listProjectVersions( repoId, namespace, projectId,
  323. new ExcludesFilter<String>( projectVersions ) );
  324. if ( storageProjectVersions != null && !storageProjectVersions.isEmpty() )
  325. {
  326. log.debug( "Resolved project versions from storage: {}", storageProjectVersions );
  327. for ( String projectVersion : storageProjectVersions )
  328. {
  329. try
  330. {
  331. ReadMetadataRequest readMetadataRequest =
  332. new ReadMetadataRequest().repositoryId( repoId ).namespace( namespace ).projectId(
  333. projectId ).projectVersion( projectVersion );
  334. ProjectVersionMetadata versionMetadata =
  335. repositoryStorage.readProjectVersionMetadata( readMetadataRequest );
  336. for ( RepositoryListener listener : listeners )
  337. {
  338. listener.addArtifact( session, repoId, namespace, projectId, versionMetadata );
  339. }
  340. metadataRepository.updateProjectVersion( repoId, namespace, projectId, versionMetadata );
  341. }
  342. catch ( MetadataRepositoryException e )
  343. {
  344. log.warn( "Unable to persist resolved information: {}", e.getMessage(), e );
  345. }
  346. catch ( RepositoryStorageMetadataInvalidException e )
  347. {
  348. log.warn(
  349. "Not update project in metadata repository due to an error resolving it from storage: {}",
  350. e.getMessage() );
  351. for ( RepositoryListener listener : listeners )
  352. {
  353. listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
  354. }
  355. }
  356. catch ( RepositoryStorageMetadataNotFoundException e )
  357. {
  358. for ( RepositoryListener listener : listeners )
  359. {
  360. listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
  361. }
  362. }
  363. }
  364. session.markDirty();
  365. projectVersions = new ArrayList<>( projectVersions );
  366. projectVersions.addAll( storageProjectVersions );
  367. }
  368. return projectVersions;
  369. }
  370. catch ( RepositoryStorageRuntimeException e )
  371. {
  372. throw new MetadataResolutionException( e.getMessage(), e );
  373. }
  374. }
  375. @Override
  376. public Collection<ArtifactMetadata> resolveArtifacts( RepositorySession session, String repoId, String namespace,
  377. String projectId, String projectVersion )
  378. throws MetadataResolutionException
  379. {
  380. try
  381. {
  382. MetadataRepository metadataRepository = session.getRepository();
  383. Collection<ArtifactMetadata> artifacts =
  384. metadataRepository.getArtifacts( repoId, namespace, projectId, projectVersion );
  385. ExcludesFilter<String> filter = new ExcludesFilter<String>( createArtifactIdList( artifacts ) );
  386. ReadMetadataRequest readMetadataRequest =
  387. new ReadMetadataRequest().repositoryId( repoId ).namespace( namespace ).projectId(
  388. projectId ).projectVersion( projectVersion ).filter( filter );
  389. Collection<ArtifactMetadata> storageArtifacts =
  390. repositoryStorage.readArtifactsMetadata( readMetadataRequest );
  391. if ( storageArtifacts != null && !storageArtifacts.isEmpty() )
  392. {
  393. log.debug( "Resolved artifacts from storage: {}", storageArtifacts );
  394. for ( ArtifactMetadata artifact : storageArtifacts )
  395. {
  396. try
  397. {
  398. metadataRepository.updateArtifact( repoId, namespace, projectId, projectVersion, artifact );
  399. }
  400. catch ( MetadataRepositoryException e )
  401. {
  402. log.warn( "Unable to persist resolved information: {}", e.getMessage(), e );
  403. }
  404. }
  405. session.markDirty();
  406. artifacts = new ArrayList<>( artifacts );
  407. artifacts.addAll( storageArtifacts );
  408. }
  409. return artifacts;
  410. }
  411. catch ( RepositoryStorageRuntimeException e )
  412. {
  413. for ( RepositoryListener listener : listeners )
  414. {
  415. listener.addArtifactProblem( session, repoId, namespace, projectId, projectVersion, e );
  416. }
  417. throw new MetadataResolutionException( e.getMessage(), e );
  418. }
  419. }
  420. private Collection<String> createArtifactIdList( Collection<ArtifactMetadata> artifacts )
  421. {
  422. Collection<String> artifactIds = new ArrayList<>();
  423. for ( ArtifactMetadata artifact : artifacts )
  424. {
  425. artifactIds.add( artifact.getId() );
  426. }
  427. return artifactIds;
  428. }
  429. }