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.

DefaultBrowseService.java 51KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280
  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.beans.ManagedRepository;
  22. import org.apache.archiva.common.utils.VersionComparator;
  23. import org.apache.archiva.common.utils.VersionUtil;
  24. import org.apache.archiva.dependency.tree.maven2.DependencyTreeBuilder;
  25. import org.apache.archiva.maven2.metadata.MavenMetadataReader;
  26. import org.apache.archiva.maven2.model.Artifact;
  27. import org.apache.archiva.maven2.model.TreeEntry;
  28. import org.apache.archiva.metadata.generic.GenericMetadataFacet;
  29. import org.apache.archiva.metadata.model.ArtifactMetadata;
  30. import org.apache.archiva.metadata.model.MetadataFacet;
  31. import org.apache.archiva.metadata.model.ProjectVersionMetadata;
  32. import org.apache.archiva.metadata.model.ProjectVersionReference;
  33. import org.apache.archiva.metadata.repository.MetadataRepository;
  34. import org.apache.archiva.metadata.repository.MetadataRepositoryException;
  35. import org.apache.archiva.metadata.repository.MetadataResolutionException;
  36. import org.apache.archiva.metadata.repository.MetadataResolver;
  37. import org.apache.archiva.metadata.repository.RepositorySession;
  38. import org.apache.archiva.metadata.repository.storage.maven2.ArtifactMetadataVersionComparator;
  39. import org.apache.archiva.metadata.repository.storage.maven2.MavenProjectFacet;
  40. import org.apache.archiva.model.ArchivaArtifact;
  41. import org.apache.archiva.model.ArchivaRepositoryMetadata;
  42. import org.apache.archiva.proxy.model.RepositoryProxyConnectors;
  43. import org.apache.archiva.redback.components.cache.Cache;
  44. import org.apache.archiva.repository.ManagedRepositoryContent;
  45. import org.apache.archiva.repository.RepositoryContentFactory;
  46. import org.apache.archiva.repository.RepositoryException;
  47. import org.apache.archiva.repository.RepositoryNotFoundException;
  48. import org.apache.archiva.repository.metadata.MetadataTools;
  49. import org.apache.archiva.rest.api.model.ArtifactContent;
  50. import org.apache.archiva.rest.api.model.ArtifactContentEntry;
  51. import org.apache.archiva.rest.api.model.BrowseResult;
  52. import org.apache.archiva.rest.api.model.BrowseResultEntry;
  53. import org.apache.archiva.rest.api.model.Entry;
  54. import org.apache.archiva.rest.api.model.MetadataAddRequest;
  55. import org.apache.archiva.rest.api.model.VersionsList;
  56. import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
  57. import org.apache.archiva.rest.api.services.BrowseService;
  58. import org.apache.archiva.rest.services.utils.ArtifactContentEntryComparator;
  59. import org.apache.archiva.security.ArchivaSecurityException;
  60. import org.apache.archiva.xml.XMLException;
  61. import org.apache.commons.collections.CollectionUtils;
  62. import org.apache.commons.io.IOUtils;
  63. import org.apache.commons.lang.StringUtils;
  64. import org.springframework.stereotype.Service;
  65. import javax.inject.Inject;
  66. import javax.inject.Named;
  67. import javax.ws.rs.core.Response;
  68. import java.io.IOException;
  69. import java.io.InputStream;
  70. import java.nio.charset.Charset;
  71. import java.nio.file.Files;
  72. import java.nio.file.Path;
  73. import java.util.ArrayList;
  74. import java.util.Collection;
  75. import java.util.Collections;
  76. import java.util.Enumeration;
  77. import java.util.HashMap;
  78. import java.util.LinkedHashSet;
  79. import java.util.List;
  80. import java.util.Map;
  81. import java.util.Set;
  82. import java.util.jar.JarEntry;
  83. import java.util.jar.JarFile;
  84. import java.util.zip.ZipEntry;
  85. /**
  86. * @author Olivier Lamy
  87. * @since 1.4-M3
  88. */
  89. @Service( "browseService#rest" )
  90. public class DefaultBrowseService
  91. extends AbstractRestService
  92. implements BrowseService
  93. {
  94. private Charset ARTIFACT_CONTENT_ENCODING=Charset.forName( "UTF-8" );
  95. @Inject
  96. private DependencyTreeBuilder dependencyTreeBuilder;
  97. @Inject
  98. private RepositoryContentFactory repositoryContentFactory;
  99. @Inject
  100. @Named( value = "repositoryProxyConnectors#default" )
  101. private RepositoryProxyConnectors connectors;
  102. @Inject
  103. @Named( value = "browse#versionMetadata" )
  104. private Cache<String, ProjectVersionMetadata> versionMetadataCache;
  105. @Override
  106. public BrowseResult getRootGroups( String repositoryId )
  107. throws ArchivaRestServiceException
  108. {
  109. List<String> selectedRepos = getSelectedRepos( repositoryId );
  110. Set<String> namespaces = new LinkedHashSet<String>();
  111. // TODO: this logic should be optional, particularly remembering we want to keep this code simple
  112. // it is located here to avoid the content repository implementation needing to do too much for what
  113. // is essentially presentation code
  114. Set<String> namespacesToCollapse = new LinkedHashSet<String>();
  115. RepositorySession repositorySession = repositorySessionFactory.createSession();
  116. try
  117. {
  118. MetadataResolver metadataResolver = repositorySession.getResolver();
  119. for ( String repoId : selectedRepos )
  120. {
  121. namespacesToCollapse.addAll( metadataResolver.resolveRootNamespaces( repositorySession, repoId ) );
  122. }
  123. for ( String n : namespacesToCollapse )
  124. {
  125. // TODO: check performance of this
  126. namespaces.add( collapseNamespaces( repositorySession, metadataResolver, selectedRepos, n ) );
  127. }
  128. }
  129. catch ( MetadataResolutionException e )
  130. {
  131. throw new ArchivaRestServiceException( e.getMessage(),
  132. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  133. }
  134. finally
  135. {
  136. repositorySession.close();
  137. }
  138. List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() );
  139. for ( String namespace : namespaces )
  140. {
  141. browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ) );
  142. }
  143. Collections.sort( browseGroupResultEntries );
  144. return new BrowseResult( browseGroupResultEntries );
  145. }
  146. @Override
  147. public BrowseResult browseGroupId( String groupId, String repositoryId )
  148. throws ArchivaRestServiceException
  149. {
  150. List<String> selectedRepos = getSelectedRepos( repositoryId );
  151. Set<String> projects = new LinkedHashSet<>();
  152. RepositorySession repositorySession = repositorySessionFactory.createSession();
  153. Set<String> namespaces;
  154. try
  155. {
  156. MetadataResolver metadataResolver = repositorySession.getResolver();
  157. Set<String> namespacesToCollapse = new LinkedHashSet<>();
  158. for ( String repoId : selectedRepos )
  159. {
  160. namespacesToCollapse.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, groupId ) );
  161. projects.addAll( metadataResolver.resolveProjects( repositorySession, repoId, groupId ) );
  162. }
  163. // TODO: this logic should be optional, particularly remembering we want to keep this code simple
  164. // it is located here to avoid the content repository implementation needing to do too much for what
  165. // is essentially presentation code
  166. namespaces = new LinkedHashSet<>();
  167. for ( String n : namespacesToCollapse )
  168. {
  169. // TODO: check performance of this
  170. namespaces.add(
  171. collapseNamespaces( repositorySession, metadataResolver, selectedRepos, groupId + "." + n ) );
  172. }
  173. }
  174. catch ( MetadataResolutionException e )
  175. {
  176. throw new ArchivaRestServiceException( e.getMessage(),
  177. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  178. }
  179. finally
  180. {
  181. repositorySession.close();
  182. }
  183. List<BrowseResultEntry> browseGroupResultEntries = new ArrayList<>( namespaces.size() + projects.size() );
  184. for ( String namespace : namespaces )
  185. {
  186. browseGroupResultEntries.add( new BrowseResultEntry( namespace, false ).groupId( namespace ) );
  187. }
  188. for ( String project : projects )
  189. {
  190. browseGroupResultEntries.add(
  191. new BrowseResultEntry( groupId + '.' + project, true ).groupId( groupId ).artifactId( project ) );
  192. }
  193. Collections.sort( browseGroupResultEntries );
  194. return new BrowseResult( browseGroupResultEntries );
  195. }
  196. @Override
  197. public VersionsList getVersionsList( String groupId, String artifactId, String repositoryId )
  198. throws ArchivaRestServiceException
  199. {
  200. List<String> selectedRepos = getSelectedRepos( repositoryId );
  201. try
  202. {
  203. Collection<String> versions = getVersions( selectedRepos, groupId, artifactId );
  204. return new VersionsList( new ArrayList<>( versions ) );
  205. }
  206. catch ( MetadataResolutionException e )
  207. {
  208. throw new ArchivaRestServiceException( e.getMessage(),
  209. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  210. }
  211. }
  212. private Collection<String> getVersions( List<String> selectedRepos, String groupId, String artifactId )
  213. throws MetadataResolutionException
  214. {
  215. RepositorySession repositorySession = repositorySessionFactory.createSession();
  216. try
  217. {
  218. MetadataResolver metadataResolver = repositorySession.getResolver();
  219. Set<String> versions = new LinkedHashSet<String>();
  220. for ( String repoId : selectedRepos )
  221. {
  222. Collection<String> projectVersions =
  223. metadataResolver.resolveProjectVersions( repositorySession, repoId, groupId, artifactId );
  224. versions.addAll( projectVersions );
  225. }
  226. List<String> sortedVersions = new ArrayList<>( versions );
  227. Collections.sort( sortedVersions, VersionComparator.getInstance() );
  228. return sortedVersions;
  229. }
  230. finally
  231. {
  232. repositorySession.close();
  233. }
  234. }
  235. @Override
  236. public ProjectVersionMetadata getProjectMetadata( String groupId, String artifactId, String version,
  237. String repositoryId )
  238. throws ArchivaRestServiceException
  239. {
  240. List<String> selectedRepos = getSelectedRepos( repositoryId );
  241. RepositorySession repositorySession = null;
  242. try
  243. {
  244. repositorySession = repositorySessionFactory.createSession();
  245. MetadataResolver metadataResolver = repositorySession.getResolver();
  246. ProjectVersionMetadata versionMetadata = null;
  247. for ( String repoId : selectedRepos )
  248. {
  249. if ( versionMetadata == null || versionMetadata.isIncomplete() )
  250. {
  251. try
  252. {
  253. ProjectVersionMetadata versionMetadataTmp =
  254. metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId, artifactId,
  255. version );
  256. if ( versionMetadata == null && versionMetadataTmp != null )
  257. {
  258. versionMetadata = versionMetadataTmp;
  259. }
  260. }
  261. catch ( MetadataResolutionException e )
  262. {
  263. log.warn( "Skipping invalid metadata while compiling shared model for {}:{} in repo {}: {}",
  264. groupId, artifactId, repoId, e.getMessage() );
  265. }
  266. }
  267. }
  268. return versionMetadata;
  269. }
  270. finally
  271. {
  272. if ( repositorySession != null )
  273. {
  274. repositorySession.close();
  275. }
  276. }
  277. }
  278. @Override
  279. public ProjectVersionMetadata getProjectVersionMetadata( String groupId, String artifactId, String repositoryId )
  280. throws ArchivaRestServiceException
  281. {
  282. List<String> selectedRepos = getSelectedRepos( repositoryId );
  283. RepositorySession repositorySession = null;
  284. try
  285. {
  286. Collection<String> projectVersions = getVersions( selectedRepos, groupId, artifactId );
  287. repositorySession = repositorySessionFactory.createSession();
  288. MetadataResolver metadataResolver = repositorySession.getResolver();
  289. ProjectVersionMetadata sharedModel = new ProjectVersionMetadata();
  290. MavenProjectFacet mavenFacet = new MavenProjectFacet();
  291. mavenFacet.setGroupId( groupId );
  292. mavenFacet.setArtifactId( artifactId );
  293. sharedModel.addFacet( mavenFacet );
  294. boolean isFirstVersion = true;
  295. for ( String version : projectVersions )
  296. {
  297. ProjectVersionMetadata versionMetadata = null;
  298. for ( String repoId : selectedRepos )
  299. {
  300. if ( versionMetadata == null || versionMetadata.isIncomplete() )
  301. {
  302. try
  303. {
  304. ProjectVersionMetadata projectVersionMetadataResolved = null;
  305. boolean useCache = !StringUtils.endsWith( version, VersionUtil.SNAPSHOT );
  306. String cacheKey = null;
  307. boolean cacheToUpdate = false;
  308. // FIXME a bit maven centric!!!
  309. // not a snapshot so get it from cache
  310. if ( useCache )
  311. {
  312. cacheKey = repoId + groupId + artifactId + version;
  313. projectVersionMetadataResolved = versionMetadataCache.get( cacheKey );
  314. }
  315. if ( useCache && projectVersionMetadataResolved != null )
  316. {
  317. versionMetadata = projectVersionMetadataResolved;
  318. }
  319. else
  320. {
  321. projectVersionMetadataResolved =
  322. metadataResolver.resolveProjectVersion( repositorySession, repoId, groupId,
  323. artifactId, version );
  324. versionMetadata = projectVersionMetadataResolved;
  325. cacheToUpdate = true;
  326. }
  327. if ( useCache && cacheToUpdate )
  328. {
  329. versionMetadataCache.put( cacheKey, projectVersionMetadataResolved );
  330. }
  331. }
  332. catch ( MetadataResolutionException e )
  333. {
  334. log.error( "Skipping invalid metadata while compiling shared model for " + groupId + ":"
  335. + artifactId + " in repo " + repoId + ": " + e.getMessage() );
  336. }
  337. }
  338. }
  339. if ( versionMetadata == null )
  340. {
  341. continue;
  342. }
  343. if ( isFirstVersion )
  344. {
  345. sharedModel = versionMetadata;
  346. sharedModel.setId( null );
  347. }
  348. else
  349. {
  350. MavenProjectFacet versionMetadataMavenFacet =
  351. (MavenProjectFacet) versionMetadata.getFacet( MavenProjectFacet.FACET_ID );
  352. if ( versionMetadataMavenFacet != null )
  353. {
  354. if ( mavenFacet.getPackaging() != null //
  355. && !StringUtils.equalsIgnoreCase( mavenFacet.getPackaging(),
  356. versionMetadataMavenFacet.getPackaging() ) )
  357. {
  358. mavenFacet.setPackaging( null );
  359. }
  360. }
  361. if ( StringUtils.isEmpty( sharedModel.getName() ) //
  362. && !StringUtils.isEmpty( versionMetadata.getName() ) )
  363. {
  364. sharedModel.setName( versionMetadata.getName() );
  365. }
  366. if ( sharedModel.getDescription() != null //
  367. && !StringUtils.equalsIgnoreCase( sharedModel.getDescription(),
  368. versionMetadata.getDescription() ) )
  369. {
  370. sharedModel.setDescription( StringUtils.isNotEmpty( versionMetadata.getDescription() )
  371. ? versionMetadata.getDescription()
  372. : "" );
  373. }
  374. if ( sharedModel.getIssueManagement() != null //
  375. && versionMetadata.getIssueManagement() != null //
  376. && !StringUtils.equalsIgnoreCase( sharedModel.getIssueManagement().getUrl(),
  377. versionMetadata.getIssueManagement().getUrl() ) )
  378. {
  379. sharedModel.setIssueManagement( versionMetadata.getIssueManagement() );
  380. }
  381. if ( sharedModel.getCiManagement() != null //
  382. && versionMetadata.getCiManagement() != null //
  383. && !StringUtils.equalsIgnoreCase( sharedModel.getCiManagement().getUrl(),
  384. versionMetadata.getCiManagement().getUrl() ) )
  385. {
  386. sharedModel.setCiManagement( versionMetadata.getCiManagement() );
  387. }
  388. if ( sharedModel.getOrganization() != null //
  389. && versionMetadata.getOrganization() != null //
  390. && !StringUtils.equalsIgnoreCase( sharedModel.getOrganization().getName(),
  391. versionMetadata.getOrganization().getName() ) )
  392. {
  393. sharedModel.setOrganization( versionMetadata.getOrganization() );
  394. }
  395. if ( sharedModel.getUrl() != null //
  396. && !StringUtils.equalsIgnoreCase( sharedModel.getUrl(), versionMetadata.getUrl() ) )
  397. {
  398. sharedModel.setUrl( versionMetadata.getUrl() );
  399. }
  400. }
  401. isFirstVersion = false;
  402. }
  403. return sharedModel;
  404. }
  405. catch ( MetadataResolutionException e )
  406. {
  407. throw new ArchivaRestServiceException( e.getMessage(),
  408. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  409. }
  410. finally
  411. {
  412. if ( repositorySession != null )
  413. {
  414. repositorySession.close();
  415. }
  416. }
  417. }
  418. @Override
  419. public List<TreeEntry> getTreeEntries( String groupId, String artifactId, String version, String repositoryId )
  420. throws ArchivaRestServiceException
  421. {
  422. List<String> selectedRepos = getSelectedRepos( repositoryId );
  423. try
  424. {
  425. return dependencyTreeBuilder.buildDependencyTree( selectedRepos, groupId, artifactId, version );
  426. }
  427. catch ( Exception e )
  428. {
  429. log.error( e.getMessage(), e );
  430. }
  431. return Collections.emptyList();
  432. }
  433. @Override
  434. public List<ManagedRepository> getUserRepositories()
  435. throws ArchivaRestServiceException
  436. {
  437. try
  438. {
  439. return userRepositories.getAccessibleRepositories( getPrincipal() );
  440. }
  441. catch ( ArchivaSecurityException e )
  442. {
  443. throw new ArchivaRestServiceException( "repositories.read.observable.error",
  444. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  445. }
  446. }
  447. @Override
  448. public List<ManagedRepository> getUserManagableRepositories() throws ArchivaRestServiceException {
  449. try
  450. {
  451. return userRepositories.getManagableRepositories( getPrincipal() );
  452. }
  453. catch ( ArchivaSecurityException e )
  454. {
  455. throw new ArchivaRestServiceException( "repositories.read.managable.error",
  456. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  457. }
  458. }
  459. @Override
  460. public List<Artifact> getDependees( String groupId, String artifactId, String version, String repositoryId )
  461. throws ArchivaRestServiceException
  462. {
  463. List<ProjectVersionReference> references = new ArrayList<>();
  464. // TODO: what if we get duplicates across repositories?
  465. RepositorySession repositorySession = repositorySessionFactory.createSession();
  466. try
  467. {
  468. MetadataResolver metadataResolver = repositorySession.getResolver();
  469. for ( String repoId : getObservableRepos() )
  470. {
  471. // TODO: what about if we want to see this irrespective of version?
  472. references.addAll(
  473. metadataResolver.resolveProjectReferences( repositorySession, repoId, groupId, artifactId,
  474. version ) );
  475. }
  476. }
  477. catch ( MetadataResolutionException e )
  478. {
  479. throw new ArchivaRestServiceException( e.getMessage(),
  480. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  481. }
  482. finally
  483. {
  484. repositorySession.close();
  485. }
  486. List<Artifact> artifacts = new ArrayList<>( references.size() );
  487. for ( ProjectVersionReference projectVersionReference : references )
  488. {
  489. artifacts.add( new Artifact( projectVersionReference.getNamespace(), projectVersionReference.getProjectId(),
  490. projectVersionReference.getProjectVersion() ) );
  491. }
  492. return artifacts;
  493. }
  494. @Override
  495. public List<Entry> getMetadatas( String groupId, String artifactId, String version, String repositoryId )
  496. throws ArchivaRestServiceException
  497. {
  498. ProjectVersionMetadata projectVersionMetadata =
  499. getProjectMetadata( groupId, artifactId, version, repositoryId );
  500. if ( projectVersionMetadata == null )
  501. {
  502. return Collections.emptyList();
  503. }
  504. MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
  505. if ( metadataFacet == null )
  506. {
  507. return Collections.emptyList();
  508. }
  509. Map<String, String> map = metadataFacet.toProperties();
  510. List<Entry> entries = new ArrayList<>( map.size() );
  511. for ( Map.Entry<String, String> entry : map.entrySet() )
  512. {
  513. entries.add( new Entry( entry.getKey(), entry.getValue() ) );
  514. }
  515. return entries;
  516. }
  517. @Override
  518. public Boolean addMetadata( String groupId, String artifactId, String version, String key, String value,
  519. String repositoryId )
  520. throws ArchivaRestServiceException
  521. {
  522. ProjectVersionMetadata projectVersionMetadata =
  523. getProjectMetadata( groupId, artifactId, version, repositoryId );
  524. if ( projectVersionMetadata == null )
  525. {
  526. return Boolean.FALSE;
  527. }
  528. Map<String, String> properties = new HashMap<>();
  529. MetadataFacet metadataFacet = projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
  530. if ( metadataFacet != null && metadataFacet.toProperties() != null )
  531. {
  532. properties.putAll( metadataFacet.toProperties() );
  533. }
  534. else
  535. {
  536. metadataFacet = new GenericMetadataFacet();
  537. }
  538. properties.put( key, value );
  539. metadataFacet.fromProperties( properties );
  540. projectVersionMetadata.addFacet( metadataFacet );
  541. RepositorySession repositorySession = repositorySessionFactory.createSession();
  542. try
  543. {
  544. MetadataRepository metadataRepository = repositorySession.getRepository();
  545. metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
  546. repositorySession.save();
  547. }
  548. catch ( MetadataRepositoryException e )
  549. {
  550. log.error( e.getMessage(), e );
  551. throw new ArchivaRestServiceException( e.getMessage(),
  552. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  553. }
  554. finally
  555. {
  556. repositorySession.close();
  557. }
  558. return Boolean.TRUE;
  559. }
  560. @Override
  561. public Boolean deleteMetadata( String groupId, String artifactId, String version, String key, String repositoryId )
  562. throws ArchivaRestServiceException
  563. {
  564. ProjectVersionMetadata projectVersionMetadata =
  565. getProjectMetadata( groupId, artifactId, version, repositoryId );
  566. if ( projectVersionMetadata == null )
  567. {
  568. return Boolean.FALSE;
  569. }
  570. GenericMetadataFacet metadataFacet =
  571. (GenericMetadataFacet) projectVersionMetadata.getFacet( GenericMetadataFacet.FACET_ID );
  572. if ( metadataFacet != null && metadataFacet.toProperties() != null )
  573. {
  574. Map<String, String> properties = metadataFacet.toProperties();
  575. properties.remove( key );
  576. metadataFacet.setAdditionalProperties( properties );
  577. }
  578. else
  579. {
  580. return Boolean.TRUE;
  581. }
  582. RepositorySession repositorySession = repositorySessionFactory.createSession();
  583. try
  584. {
  585. MetadataRepository metadataRepository = repositorySession.getRepository();
  586. metadataRepository.updateProjectVersion( repositoryId, groupId, artifactId, projectVersionMetadata );
  587. repositorySession.save();
  588. }
  589. catch ( MetadataRepositoryException e )
  590. {
  591. log.error( e.getMessage(), e );
  592. throw new ArchivaRestServiceException( e.getMessage(),
  593. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  594. }
  595. finally
  596. {
  597. repositorySession.close();
  598. }
  599. return Boolean.TRUE;
  600. }
  601. @Override
  602. public List<ArtifactContentEntry> getArtifactContentEntries( String groupId, String artifactId, String version,
  603. String classifier, String type, String path,
  604. String repositoryId )
  605. throws ArchivaRestServiceException
  606. {
  607. List<String> selectedRepos = getSelectedRepos( repositoryId );
  608. try
  609. {
  610. for ( String repoId : selectedRepos )
  611. {
  612. ManagedRepositoryContent managedRepositoryContent =
  613. repositoryContentFactory.getManagedRepositoryContent( repoId );
  614. ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
  615. StringUtils.isEmpty( type ) ? "jar" : type,
  616. repoId );
  617. Path file = managedRepositoryContent.toFile( archivaArtifact );
  618. if ( Files.exists(file) )
  619. {
  620. return readFileEntries( file, path, repoId );
  621. }
  622. }
  623. }
  624. catch ( IOException e )
  625. {
  626. log.error( e.getMessage(), e );
  627. throw new ArchivaRestServiceException( e.getMessage(),
  628. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  629. }
  630. catch ( RepositoryNotFoundException e )
  631. {
  632. log.error( e.getMessage(), e );
  633. throw new ArchivaRestServiceException( e.getMessage(),
  634. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  635. }
  636. catch ( RepositoryException e )
  637. {
  638. log.error( e.getMessage(), e );
  639. throw new ArchivaRestServiceException( e.getMessage(),
  640. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  641. }
  642. return Collections.emptyList();
  643. }
  644. @Override
  645. public List<Artifact> getArtifactDownloadInfos( String groupId, String artifactId, String version,
  646. String repositoryId )
  647. throws ArchivaRestServiceException
  648. {
  649. List<String> selectedRepos = getSelectedRepos( repositoryId );
  650. List<Artifact> artifactDownloadInfos = new ArrayList<>();
  651. try (RepositorySession session = repositorySessionFactory.createSession())
  652. {
  653. MetadataResolver metadataResolver = session.getResolver();
  654. for ( String repoId : selectedRepos )
  655. {
  656. List<ArtifactMetadata> artifacts = new ArrayList<>(
  657. metadataResolver.resolveArtifacts( session, repoId, groupId, artifactId, version ) );
  658. Collections.sort( artifacts, ArtifactMetadataVersionComparator.INSTANCE );
  659. if ( artifacts != null && !artifacts.isEmpty() )
  660. {
  661. return buildArtifacts( artifacts, repoId );
  662. }
  663. }
  664. }
  665. catch ( MetadataResolutionException e )
  666. {
  667. log.error( e.getMessage(), e );
  668. throw new ArchivaRestServiceException( e.getMessage(),
  669. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  670. }
  671. return artifactDownloadInfos;
  672. }
  673. @Override
  674. public ArtifactContent getArtifactContentText( String groupId, String artifactId, String version, String classifier,
  675. String type, String path, String repositoryId )
  676. throws ArchivaRestServiceException
  677. {
  678. List<String> selectedRepos = getSelectedRepos( repositoryId );
  679. try
  680. {
  681. for ( String repoId : selectedRepos )
  682. {
  683. ManagedRepositoryContent managedRepositoryContent =
  684. repositoryContentFactory.getManagedRepositoryContent( repoId );
  685. ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version, classifier,
  686. StringUtils.isEmpty( type ) ? "jar" : type,
  687. repoId );
  688. Path file = managedRepositoryContent.toFile( archivaArtifact );
  689. if ( !Files.exists(file) )
  690. {
  691. log.debug( "file: {} not exists for repository: {} try next repository", file, repoId );
  692. continue;
  693. }
  694. if ( StringUtils.isNotBlank( path ) )
  695. {
  696. // zip entry of the path -> path must a real file entry of the archive
  697. JarFile jarFile = new JarFile( file.toFile() );
  698. ZipEntry zipEntry = jarFile.getEntry( path );
  699. try (InputStream inputStream = jarFile.getInputStream( zipEntry ))
  700. {
  701. return new ArtifactContent( IOUtils.toString( inputStream, ARTIFACT_CONTENT_ENCODING ), repoId );
  702. }
  703. finally
  704. {
  705. closeQuietly( jarFile );
  706. }
  707. }
  708. return new ArtifactContent( new String(Files.readAllBytes( file ), ARTIFACT_CONTENT_ENCODING), repoId );
  709. }
  710. }
  711. catch ( IOException e )
  712. {
  713. log.error( e.getMessage(), e );
  714. throw new ArchivaRestServiceException( e.getMessage(),
  715. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  716. }
  717. catch ( RepositoryNotFoundException e )
  718. {
  719. log.error( e.getMessage(), e );
  720. throw new ArchivaRestServiceException( e.getMessage(),
  721. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  722. }
  723. catch ( RepositoryException e )
  724. {
  725. log.error( e.getMessage(), e );
  726. throw new ArchivaRestServiceException( e.getMessage(),
  727. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  728. }
  729. log.debug( "artifact: {}:{}:{}:{}:{} not found", groupId, artifactId, version, classifier, type );
  730. // 404 ?
  731. return new ArtifactContent();
  732. }
  733. @Override
  734. public Boolean artifactAvailable( String groupId, String artifactId, String version, String classifier,
  735. String repositoryId )
  736. throws ArchivaRestServiceException
  737. {
  738. List<String> selectedRepos = getSelectedRepos( repositoryId );
  739. boolean snapshot = VersionUtil.isSnapshot( version );
  740. try
  741. {
  742. for ( String repoId : selectedRepos )
  743. {
  744. ManagedRepository managedRepository = managedRepositoryAdmin.getManagedRepository( repoId );
  745. if ( ( snapshot && !managedRepository.isSnapshots() ) || ( !snapshot
  746. && managedRepository.isSnapshots() ) )
  747. {
  748. continue;
  749. }
  750. ManagedRepositoryContent managedRepositoryContent =
  751. repositoryContentFactory.getManagedRepositoryContent( repoId );
  752. // FIXME default to jar which can be wrong for war zip etc....
  753. ArchivaArtifact archivaArtifact = new ArchivaArtifact( groupId, artifactId, version,
  754. StringUtils.isEmpty( classifier )
  755. ? ""
  756. : classifier, "jar", repoId );
  757. Path file = managedRepositoryContent.toFile( archivaArtifact );
  758. if ( file != null && Files.exists(file) )
  759. {
  760. return true;
  761. }
  762. // in case of SNAPSHOT we can have timestamped version locally !
  763. if ( StringUtils.endsWith( version, VersionUtil.SNAPSHOT ) )
  764. {
  765. Path metadataFile = file.getParent().resolve(MetadataTools.MAVEN_METADATA );
  766. if ( Files.exists(metadataFile) )
  767. {
  768. try
  769. {
  770. ArchivaRepositoryMetadata archivaRepositoryMetadata =
  771. MavenMetadataReader.read( metadataFile );
  772. int buildNumber = archivaRepositoryMetadata.getSnapshotVersion().getBuildNumber();
  773. String timeStamp = archivaRepositoryMetadata.getSnapshotVersion().getTimestamp();
  774. // rebuild file name with timestamped version and build number
  775. String timeStampFileName = new StringBuilder( artifactId ).append( '-' ) //
  776. .append( StringUtils.remove( version, "-" + VersionUtil.SNAPSHOT ) ) //
  777. .append( '-' ).append( timeStamp ) //
  778. .append( '-' ).append( Integer.toString( buildNumber ) ) //
  779. .append( ( StringUtils.isEmpty( classifier ) ? "" : "-" + classifier ) ) //
  780. .append( ".jar" ).toString();
  781. Path timeStampFile = file.getParent().resolve( timeStampFileName );
  782. log.debug( "try to find timestamped snapshot version file: {}", timeStampFile.toAbsolutePath() );
  783. if ( Files.exists(timeStampFile) )
  784. {
  785. return true;
  786. }
  787. }
  788. catch ( XMLException e )
  789. {
  790. log.warn( "skip fail to find timestamped snapshot file: {}", e.getMessage() );
  791. }
  792. }
  793. }
  794. String path = managedRepositoryContent.toPath( archivaArtifact );
  795. file = connectors.fetchFromProxies( managedRepositoryContent, path );
  796. if ( file != null && Files.exists(file) )
  797. {
  798. // download pom now
  799. String pomPath = StringUtils.substringBeforeLast( path, ".jar" ) + ".pom";
  800. connectors.fetchFromProxies( managedRepositoryContent, pomPath );
  801. return true;
  802. }
  803. }
  804. }
  805. catch ( RepositoryAdminException e )
  806. {
  807. log.error( e.getMessage(), e );
  808. throw new ArchivaRestServiceException( e.getMessage(),
  809. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  810. }
  811. catch ( RepositoryException e )
  812. {
  813. log.error( e.getMessage(), e );
  814. throw new ArchivaRestServiceException( e.getMessage(),
  815. Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), e );
  816. }
  817. return false;
  818. }
  819. @Override
  820. public Boolean artifactAvailable( String groupId, String artifactId, String version, String repositoryId )
  821. throws ArchivaRestServiceException
  822. {
  823. return artifactAvailable( groupId, artifactId, version, null, repositoryId );
  824. }
  825. @Override
  826. public List<Artifact> getArtifacts( String repositoryId )
  827. throws ArchivaRestServiceException
  828. {
  829. RepositorySession repositorySession = repositorySessionFactory.createSession();
  830. try
  831. {
  832. List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifacts( repositoryId );
  833. return buildArtifacts( artifactMetadatas, repositoryId );
  834. }
  835. catch ( MetadataRepositoryException e )
  836. {
  837. throw new ArchivaRestServiceException( e.getMessage(), e );
  838. }
  839. finally
  840. {
  841. repositorySession.close();
  842. }
  843. }
  844. @Override
  845. public List<Artifact> getArtifactsByProjectVersionMetadata( String key, String value, String repositoryId )
  846. throws ArchivaRestServiceException
  847. {
  848. RepositorySession repositorySession = repositorySessionFactory.createSession();
  849. try
  850. {
  851. List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProjectVersionMetadata( key, value, repositoryId );
  852. return buildArtifacts( artifactMetadatas, repositoryId );
  853. }
  854. catch ( MetadataRepositoryException e )
  855. {
  856. throw new ArchivaRestServiceException( e.getMessage(), e );
  857. }
  858. finally
  859. {
  860. repositorySession.close();
  861. }
  862. }
  863. @Override
  864. public List<Artifact> getArtifactsByMetadata( String key, String value, String repositoryId )
  865. throws ArchivaRestServiceException
  866. {
  867. RepositorySession repositorySession = repositorySessionFactory.createSession();
  868. try
  869. {
  870. List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByMetadata( key, value, repositoryId );
  871. return buildArtifacts( artifactMetadatas, repositoryId );
  872. }
  873. catch ( MetadataRepositoryException e )
  874. {
  875. throw new ArchivaRestServiceException( e.getMessage(), e );
  876. }
  877. finally
  878. {
  879. repositorySession.close();
  880. }
  881. }
  882. @Override
  883. public List<Artifact> getArtifactsByProperty( String key, String value, String repositoryId )
  884. throws ArchivaRestServiceException
  885. {
  886. RepositorySession repositorySession = repositorySessionFactory.createSession();
  887. try
  888. {
  889. List<ArtifactMetadata> artifactMetadatas = repositorySession.getRepository().getArtifactsByProperty( key, value, repositoryId );
  890. return buildArtifacts( artifactMetadatas, repositoryId );
  891. }
  892. catch ( MetadataRepositoryException e )
  893. {
  894. throw new ArchivaRestServiceException( e.getMessage(), e );
  895. }
  896. finally
  897. {
  898. repositorySession.close();
  899. }
  900. }
  901. @Override
  902. public Boolean importMetadata( MetadataAddRequest metadataAddRequest, String repositoryId )
  903. throws ArchivaRestServiceException
  904. {
  905. boolean result = true;
  906. for ( Map.Entry<String, String> metadata : metadataAddRequest.getMetadatas().entrySet() )
  907. {
  908. result = addMetadata( metadataAddRequest.getGroupId(), metadataAddRequest.getArtifactId(),
  909. metadataAddRequest.getVersion(), metadata.getKey(), metadata.getValue(),
  910. repositoryId );
  911. if ( !result )
  912. {
  913. break;
  914. }
  915. }
  916. return result;
  917. }
  918. @Override
  919. public List<Artifact> searchArtifacts( String text, String repositoryId, Boolean exact )
  920. throws ArchivaRestServiceException
  921. {
  922. RepositorySession repositorySession = repositorySessionFactory.createSession();
  923. try
  924. {
  925. List<ArtifactMetadata> artifactMetadatas =
  926. repositorySession.getRepository().searchArtifacts( text, repositoryId, exact == null ? false : exact );
  927. return buildArtifacts( artifactMetadatas, repositoryId );
  928. }
  929. catch ( MetadataRepositoryException e )
  930. {
  931. throw new ArchivaRestServiceException( e.getMessage(), e );
  932. }
  933. finally
  934. {
  935. repositorySession.close();
  936. }
  937. }
  938. @Override
  939. public List<Artifact> searchArtifacts( String key, String text, String repositoryId, Boolean exact )
  940. throws ArchivaRestServiceException
  941. {
  942. RepositorySession repositorySession = repositorySessionFactory.createSession();
  943. try
  944. {
  945. List<ArtifactMetadata> artifactMetadatas =
  946. repositorySession.getRepository().searchArtifacts( key, text, repositoryId, exact == null ? false : exact );
  947. return buildArtifacts( artifactMetadatas, repositoryId );
  948. }
  949. catch ( MetadataRepositoryException e )
  950. {
  951. throw new ArchivaRestServiceException( e.getMessage(), e );
  952. }
  953. finally
  954. {
  955. repositorySession.close();
  956. }
  957. }
  958. //---------------------------
  959. // internals
  960. //---------------------------
  961. private void closeQuietly( JarFile jarFile )
  962. {
  963. if ( jarFile != null )
  964. {
  965. try
  966. {
  967. jarFile.close();
  968. }
  969. catch ( IOException e )
  970. {
  971. log.warn( "ignore error closing jarFile {}", jarFile.getName() );
  972. }
  973. }
  974. }
  975. protected List<ArtifactContentEntry> readFileEntries(final Path file, final String filterPath, final String repoId )
  976. throws IOException
  977. {
  978. String cleanedfilterPath = filterPath==null ? "" : (StringUtils.startsWith(filterPath, "/") ?
  979. StringUtils.substringAfter(filterPath, "/") : filterPath);
  980. Map<String, ArtifactContentEntry> artifactContentEntryMap = new HashMap<>();
  981. int filterDepth = StringUtils.countMatches( cleanedfilterPath, "/" );
  982. if (!StringUtils.endsWith(cleanedfilterPath,"/") && !StringUtils.isEmpty(cleanedfilterPath)) {
  983. filterDepth++;
  984. }
  985. JarFile jarFile = new JarFile( file.toFile() );
  986. try
  987. {
  988. Enumeration<JarEntry> jarEntryEnumeration = jarFile.entries();
  989. while ( jarEntryEnumeration.hasMoreElements() )
  990. {
  991. JarEntry currentEntry = jarEntryEnumeration.nextElement();
  992. String cleanedEntryName = StringUtils.endsWith( currentEntry.getName(), "/" ) ? //
  993. StringUtils.substringBeforeLast( currentEntry.getName(), "/" ) : currentEntry.getName();
  994. String entryRootPath = getRootPath( cleanedEntryName );
  995. int depth = StringUtils.countMatches( cleanedEntryName, "/" );
  996. if ( StringUtils.isEmpty( cleanedfilterPath ) //
  997. && !artifactContentEntryMap.containsKey( entryRootPath ) //
  998. && depth == filterDepth )
  999. {
  1000. artifactContentEntryMap.put( entryRootPath,
  1001. new ArtifactContentEntry( entryRootPath, !currentEntry.isDirectory(),
  1002. depth, repoId ) );
  1003. }
  1004. else
  1005. {
  1006. if ( StringUtils.startsWith( cleanedEntryName, cleanedfilterPath ) //
  1007. && ( depth == filterDepth || ( !currentEntry.isDirectory() && depth == filterDepth ) ) )
  1008. {
  1009. artifactContentEntryMap.put( cleanedEntryName, new ArtifactContentEntry( cleanedEntryName,
  1010. !currentEntry.isDirectory(),
  1011. depth, repoId ) );
  1012. }
  1013. }
  1014. }
  1015. if ( StringUtils.isNotEmpty( cleanedfilterPath ) )
  1016. {
  1017. Map<String, ArtifactContentEntry> filteredArtifactContentEntryMap = new HashMap<>();
  1018. for ( Map.Entry<String, ArtifactContentEntry> entry : artifactContentEntryMap.entrySet() )
  1019. {
  1020. filteredArtifactContentEntryMap.put( entry.getKey(), entry.getValue() );
  1021. }
  1022. List<ArtifactContentEntry> sorted = getSmallerDepthEntries( filteredArtifactContentEntryMap );
  1023. if ( sorted == null )
  1024. {
  1025. return Collections.emptyList();
  1026. }
  1027. Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
  1028. return sorted;
  1029. }
  1030. }
  1031. finally
  1032. {
  1033. if ( jarFile != null )
  1034. {
  1035. jarFile.close();
  1036. }
  1037. }
  1038. List<ArtifactContentEntry> sorted = new ArrayList<>( artifactContentEntryMap.values() );
  1039. Collections.sort( sorted, ArtifactContentEntryComparator.INSTANCE );
  1040. return sorted;
  1041. }
  1042. private List<ArtifactContentEntry> getSmallerDepthEntries( Map<String, ArtifactContentEntry> entries )
  1043. {
  1044. int smallestDepth = Integer.MAX_VALUE;
  1045. Map<Integer, List<ArtifactContentEntry>> perDepthList = new HashMap<>();
  1046. for ( Map.Entry<String, ArtifactContentEntry> entry : entries.entrySet() )
  1047. {
  1048. ArtifactContentEntry current = entry.getValue();
  1049. if ( current.getDepth() < smallestDepth )
  1050. {
  1051. smallestDepth = current.getDepth();
  1052. }
  1053. List<ArtifactContentEntry> currentList = perDepthList.get( current.getDepth() );
  1054. if ( currentList == null )
  1055. {
  1056. currentList = new ArrayList<>();
  1057. currentList.add( current );
  1058. perDepthList.put( current.getDepth(), currentList );
  1059. }
  1060. else
  1061. {
  1062. currentList.add( current );
  1063. }
  1064. }
  1065. return perDepthList.get( smallestDepth );
  1066. }
  1067. /**
  1068. * @param path
  1069. * @return org/apache -&gt; org , org -&gt; org
  1070. */
  1071. private String getRootPath( String path )
  1072. {
  1073. if ( StringUtils.contains( path, '/' ) )
  1074. {
  1075. return StringUtils.substringBefore( path, "/" );
  1076. }
  1077. return path;
  1078. }
  1079. private List<String> getSelectedRepos( String repositoryId )
  1080. throws ArchivaRestServiceException
  1081. {
  1082. List<String> selectedRepos = getObservableRepos();
  1083. if ( CollectionUtils.isEmpty( selectedRepos ) )
  1084. {
  1085. return Collections.emptyList();
  1086. }
  1087. if ( StringUtils.isNotEmpty( repositoryId ) )
  1088. {
  1089. // check user has karma on the repository
  1090. if ( !selectedRepos.contains( repositoryId ) )
  1091. {
  1092. throw new ArchivaRestServiceException( "browse.root.groups.repositoy.denied",
  1093. Response.Status.FORBIDDEN.getStatusCode(), null );
  1094. }
  1095. selectedRepos = Collections.singletonList( repositoryId );
  1096. }
  1097. return selectedRepos;
  1098. }
  1099. private String collapseNamespaces( RepositorySession repositorySession, MetadataResolver metadataResolver,
  1100. Collection<String> repoIds, String n )
  1101. throws MetadataResolutionException
  1102. {
  1103. Set<String> subNamespaces = new LinkedHashSet<String>();
  1104. for ( String repoId : repoIds )
  1105. {
  1106. subNamespaces.addAll( metadataResolver.resolveNamespaces( repositorySession, repoId, n ) );
  1107. }
  1108. if ( subNamespaces.size() != 1 )
  1109. {
  1110. log.debug( "{} is not collapsible as it has sub-namespaces: {}", n, subNamespaces );
  1111. return n;
  1112. }
  1113. else
  1114. {
  1115. for ( String repoId : repoIds )
  1116. {
  1117. Collection<String> projects = metadataResolver.resolveProjects( repositorySession, repoId, n );
  1118. if ( projects != null && !projects.isEmpty() )
  1119. {
  1120. log.debug( "{} is not collapsible as it has projects", n );
  1121. return n;
  1122. }
  1123. }
  1124. return collapseNamespaces( repositorySession, metadataResolver, repoIds,
  1125. n + "." + subNamespaces.iterator().next() );
  1126. }
  1127. }
  1128. public Cache getVersionMetadataCache()
  1129. {
  1130. return versionMetadataCache;
  1131. }
  1132. public void setVersionMetadataCache( Cache versionMetadataCache )
  1133. {
  1134. this.versionMetadataCache = versionMetadataCache;
  1135. }
  1136. }