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.

MavenRepositorySearch.java 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  1. package org.apache.archiva.indexer.maven.search;
  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.ProxyConnector;
  22. import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin;
  23. import org.apache.archiva.indexer.UnsupportedBaseContextException;
  24. import org.apache.archiva.indexer.search.ArtifactInfoFilter;
  25. import org.apache.archiva.indexer.search.NoClassifierArtifactInfoFilter;
  26. import org.apache.archiva.indexer.search.RepositorySearch;
  27. import org.apache.archiva.indexer.search.RepositorySearchException;
  28. import org.apache.archiva.indexer.search.SearchFields;
  29. import org.apache.archiva.indexer.search.SearchResultHit;
  30. import org.apache.archiva.indexer.search.SearchResultLimits;
  31. import org.apache.archiva.indexer.search.SearchResults;
  32. import org.apache.archiva.indexer.util.SearchUtil;
  33. import org.apache.archiva.model.ArchivaArtifactModel;
  34. import org.apache.archiva.repository.RemoteRepository;
  35. import org.apache.archiva.repository.Repository;
  36. import org.apache.archiva.repository.RepositoryRegistry;
  37. import org.apache.archiva.repository.RepositoryType;
  38. import org.apache.commons.lang.StringUtils;
  39. import org.apache.maven.index.ArtifactInfo;
  40. import org.apache.maven.index.FlatSearchRequest;
  41. import org.apache.maven.index.FlatSearchResponse;
  42. import org.apache.maven.index.Indexer;
  43. import org.apache.maven.index.MAVEN;
  44. import org.apache.maven.index.OSGI;
  45. import org.apache.maven.index.QueryCreator;
  46. import org.apache.maven.index.SearchType;
  47. import org.apache.maven.index.context.IndexingContext;
  48. import org.apache.maven.index.expr.SearchExpression;
  49. import org.apache.maven.index.expr.SearchTyped;
  50. import org.apache.maven.index.expr.SourcedSearchExpression;
  51. import org.apache.maven.index.expr.UserInputSearchExpression;
  52. import org.apache.maven.index_shaded.lucene.search.BooleanClause;
  53. import org.apache.maven.index_shaded.lucene.search.BooleanClause.Occur;
  54. import org.apache.maven.index_shaded.lucene.search.BooleanQuery;
  55. import org.slf4j.Logger;
  56. import org.slf4j.LoggerFactory;
  57. import org.springframework.stereotype.Service;
  58. import javax.inject.Inject;
  59. import java.io.IOException;
  60. import java.util.ArrayList;
  61. import java.util.Collection;
  62. import java.util.Collections;
  63. import java.util.HashSet;
  64. import java.util.List;
  65. import java.util.Map;
  66. import java.util.Set;
  67. /**
  68. * RepositorySearch implementation which uses the Maven Indexer for searching.
  69. */
  70. @Service( "repositorySearch#maven" )
  71. public class MavenRepositorySearch
  72. implements RepositorySearch
  73. {
  74. private Logger log = LoggerFactory.getLogger( getClass() );
  75. private Indexer indexer;
  76. private QueryCreator queryCreator;
  77. RepositoryRegistry repositoryRegistry;
  78. private ProxyConnectorAdmin proxyConnectorAdmin;
  79. protected MavenRepositorySearch()
  80. {
  81. // for test purpose
  82. }
  83. @Inject
  84. public MavenRepositorySearch( Indexer nexusIndexer, RepositoryRegistry repositoryRegistry,
  85. ProxyConnectorAdmin proxyConnectorAdmin, QueryCreator queryCreator )
  86. {
  87. this.indexer = nexusIndexer;
  88. this.queryCreator = queryCreator;
  89. this.repositoryRegistry = repositoryRegistry;
  90. this.proxyConnectorAdmin = proxyConnectorAdmin;
  91. }
  92. /**
  93. * @see RepositorySearch#search(String, List, String, SearchResultLimits, List)
  94. */
  95. @Override
  96. public SearchResults search(String principal, List<String> selectedRepos, String term, SearchResultLimits limits,
  97. List<String> previousSearchTerms )
  98. throws RepositorySearchException
  99. {
  100. List<String> indexingContextIds = addIndexingContexts( selectedRepos );
  101. // since upgrade to nexus 2.0.0, query has changed from g:[QUERIED TERM]* to g:*[QUERIED TERM]*
  102. // resulting to more wildcard searches so we need to increase max clause count
  103. BooleanQuery.setMaxClauseCount( Integer.MAX_VALUE );
  104. BooleanQuery.Builder qb = new BooleanQuery.Builder();
  105. if ( previousSearchTerms == null || previousSearchTerms.isEmpty() )
  106. {
  107. constructQuery( term, qb );
  108. }
  109. else
  110. {
  111. for ( String previousTerm : previousSearchTerms )
  112. {
  113. BooleanQuery.Builder iQuery = new BooleanQuery.Builder();
  114. constructQuery( previousTerm, iQuery );
  115. qb.add( iQuery.build(), BooleanClause.Occur.MUST );
  116. }
  117. BooleanQuery.Builder iQuery = new BooleanQuery.Builder();
  118. constructQuery( term, iQuery );
  119. qb.add( iQuery.build(), BooleanClause.Occur.MUST );
  120. }
  121. // we retun only artifacts without classifier in quick search, olamy cannot find a way to say with this field empty
  122. // FIXME cannot find a way currently to setup this in constructQuery !!!
  123. return search( limits, qb.build(), indexingContextIds, NoClassifierArtifactInfoFilter.LIST, selectedRepos, true );
  124. }
  125. /**
  126. * @see RepositorySearch#search(String, SearchFields, SearchResultLimits)
  127. */
  128. @SuppressWarnings( "deprecation" )
  129. @Override
  130. public SearchResults search( String principal, SearchFields searchFields, SearchResultLimits limits )
  131. throws RepositorySearchException
  132. {
  133. if ( searchFields.getRepositories() == null )
  134. {
  135. throw new RepositorySearchException( "Repositories cannot be null." );
  136. }
  137. List<String> indexingContextIds = addIndexingContexts( searchFields.getRepositories() );
  138. // if no index found in the specified ones return an empty search result instead of doing a search on all index
  139. // olamy: IMHO doesn't make sense
  140. if ( !searchFields.getRepositories().isEmpty() && ( indexingContextIds == null
  141. || indexingContextIds.isEmpty() ) )
  142. {
  143. return new SearchResults();
  144. }
  145. BooleanQuery.Builder qb = new BooleanQuery.Builder();
  146. if ( StringUtils.isNotBlank( searchFields.getGroupId() ) )
  147. {
  148. qb.add( indexer.constructQuery( MAVEN.GROUP_ID, searchFields.isExactSearch() ? new SourcedSearchExpression(
  149. searchFields.getGroupId() ) : new UserInputSearchExpression( searchFields.getGroupId() ) ),
  150. BooleanClause.Occur.MUST );
  151. }
  152. if ( StringUtils.isNotBlank( searchFields.getArtifactId() ) )
  153. {
  154. qb.add( indexer.constructQuery( MAVEN.ARTIFACT_ID,
  155. searchFields.isExactSearch()
  156. ? new SourcedSearchExpression( searchFields.getArtifactId() )
  157. : new UserInputSearchExpression( searchFields.getArtifactId() ) ),
  158. BooleanClause.Occur.MUST );
  159. }
  160. if ( StringUtils.isNotBlank( searchFields.getVersion() ) )
  161. {
  162. qb.add( indexer.constructQuery( MAVEN.VERSION, searchFields.isExactSearch() ? new SourcedSearchExpression(
  163. searchFields.getVersion() ) : new SourcedSearchExpression( searchFields.getVersion() ) ),
  164. BooleanClause.Occur.MUST );
  165. }
  166. if ( StringUtils.isNotBlank( searchFields.getPackaging() ) )
  167. {
  168. qb.add( indexer.constructQuery( MAVEN.PACKAGING, searchFields.isExactSearch() ? new SourcedSearchExpression(
  169. searchFields.getPackaging() ) : new UserInputSearchExpression( searchFields.getPackaging() ) ),
  170. BooleanClause.Occur.MUST );
  171. }
  172. if ( StringUtils.isNotBlank( searchFields.getClassName() ) )
  173. {
  174. qb.add( indexer.constructQuery( MAVEN.CLASSNAMES,
  175. new UserInputSearchExpression( searchFields.getClassName() ) ),
  176. BooleanClause.Occur.MUST );
  177. }
  178. if ( StringUtils.isNotBlank( searchFields.getBundleSymbolicName() ) )
  179. {
  180. qb.add( indexer.constructQuery( OSGI.SYMBOLIC_NAME,
  181. new UserInputSearchExpression( searchFields.getBundleSymbolicName() ) ),
  182. BooleanClause.Occur.MUST );
  183. }
  184. if ( StringUtils.isNotBlank( searchFields.getBundleVersion() ) )
  185. {
  186. qb.add( indexer.constructQuery( OSGI.VERSION,
  187. new UserInputSearchExpression( searchFields.getBundleVersion() ) ),
  188. BooleanClause.Occur.MUST );
  189. }
  190. if ( StringUtils.isNotBlank( searchFields.getBundleExportPackage() ) )
  191. {
  192. qb.add( indexer.constructQuery( OSGI.EXPORT_PACKAGE,
  193. new UserInputSearchExpression( searchFields.getBundleExportPackage() ) ),
  194. Occur.MUST );
  195. }
  196. if ( StringUtils.isNotBlank( searchFields.getBundleExportService() ) )
  197. {
  198. qb.add( indexer.constructQuery( OSGI.EXPORT_SERVICE,
  199. new UserInputSearchExpression( searchFields.getBundleExportService() ) ),
  200. Occur.MUST );
  201. }
  202. if ( StringUtils.isNotBlank( searchFields.getBundleImportPackage() ) )
  203. {
  204. qb.add( indexer.constructQuery( OSGI.IMPORT_PACKAGE,
  205. new UserInputSearchExpression( searchFields.getBundleImportPackage() ) ),
  206. Occur.MUST );
  207. }
  208. if ( StringUtils.isNotBlank( searchFields.getBundleName() ) )
  209. {
  210. qb.add( indexer.constructQuery( OSGI.NAME, new UserInputSearchExpression( searchFields.getBundleName() ) ),
  211. Occur.MUST );
  212. }
  213. if ( StringUtils.isNotBlank( searchFields.getBundleImportPackage() ) )
  214. {
  215. qb.add( indexer.constructQuery( OSGI.IMPORT_PACKAGE,
  216. new UserInputSearchExpression( searchFields.getBundleImportPackage() ) ),
  217. Occur.MUST );
  218. }
  219. if ( StringUtils.isNotBlank( searchFields.getBundleRequireBundle() ) )
  220. {
  221. qb.add( indexer.constructQuery( OSGI.REQUIRE_BUNDLE,
  222. new UserInputSearchExpression( searchFields.getBundleRequireBundle() ) ),
  223. Occur.MUST );
  224. }
  225. if ( StringUtils.isNotBlank( searchFields.getClassifier() ) )
  226. {
  227. qb.add( indexer.constructQuery( MAVEN.CLASSIFIER, searchFields.isExactSearch() ? new SourcedSearchExpression(
  228. searchFields.getClassifier() ) : new UserInputSearchExpression( searchFields.getClassifier() ) ),
  229. Occur.MUST );
  230. }
  231. else if ( searchFields.isExactSearch() )
  232. {
  233. //TODO improvement in case of exact search and no classifier we must query for classifier with null value
  234. // currently it's done in DefaultSearchService with some filtering
  235. }
  236. BooleanQuery qu = qb.build();
  237. if ( qu.clauses() == null || qu.clauses().size() <= 0 )
  238. {
  239. throw new RepositorySearchException( "No search fields set." );
  240. }
  241. if (qu.clauses()!=null) {
  242. log.debug("CLAUSES ", qu.clauses());
  243. for (BooleanClause cl : qu.clauses()) {
  244. log.debug("Clause ",cl);
  245. }
  246. }
  247. return search( limits, qu, indexingContextIds, Collections.<ArtifactInfoFilter>emptyList(),
  248. searchFields.getRepositories(), searchFields.isIncludePomArtifacts() );
  249. }
  250. private static class NullSearch
  251. implements SearchTyped, SearchExpression
  252. {
  253. private static final NullSearch INSTANCE = new NullSearch();
  254. @Override
  255. public String getStringValue()
  256. {
  257. return "[[NULL_VALUE]]";
  258. }
  259. @Override
  260. public SearchType getSearchType()
  261. {
  262. return SearchType.EXACT;
  263. }
  264. }
  265. private SearchResults search( SearchResultLimits limits, BooleanQuery q, List<String> indexingContextIds,
  266. List<? extends ArtifactInfoFilter> filters, List<String> selectedRepos,
  267. boolean includePoms )
  268. throws RepositorySearchException
  269. {
  270. try
  271. {
  272. FlatSearchRequest request = new FlatSearchRequest( q );
  273. request.setContexts( getIndexingContexts( indexingContextIds ) );
  274. if ( limits != null )
  275. {
  276. // we apply limits only when first page asked
  277. if ( limits.getSelectedPage() == 0 )
  278. {
  279. request.setCount( limits.getPageSize() * ( Math.max( 1, limits.getSelectedPage() ) ) );
  280. }
  281. }
  282. FlatSearchResponse response = indexer.searchFlat( request );
  283. if ( response == null || response.getTotalHitsCount() == 0 )
  284. {
  285. SearchResults results = new SearchResults();
  286. results.setLimits( limits );
  287. return results;
  288. }
  289. return convertToSearchResults( response, limits, filters, selectedRepos, includePoms );
  290. }
  291. catch ( IOException e )
  292. {
  293. throw new RepositorySearchException( e.getMessage(), e );
  294. }
  295. catch ( RepositoryAdminException e )
  296. {
  297. throw new RepositorySearchException( e.getMessage(), e );
  298. }
  299. }
  300. private IndexingContext getIndexingContext(String id) {
  301. String repoId;
  302. if (StringUtils.startsWith(id, "remote-")) {
  303. repoId = StringUtils.substringAfter(id, "remote-");
  304. } else {
  305. repoId = id;
  306. }
  307. Repository repo = repositoryRegistry.getRepository(repoId);
  308. if (repo==null) {
  309. return null;
  310. } else {
  311. if (repo.getIndexingContext()!=null) {
  312. try {
  313. return repo.getIndexingContext().getBaseContext(IndexingContext.class);
  314. } catch (UnsupportedBaseContextException e) {
  315. return null;
  316. }
  317. } else {
  318. return null;
  319. }
  320. }
  321. }
  322. private List<IndexingContext> getIndexingContexts( List<String> ids )
  323. {
  324. List<IndexingContext> contexts = new ArrayList<>( ids.size() );
  325. for ( String id : ids )
  326. {
  327. IndexingContext context = getIndexingContext(id);
  328. if ( context != null )
  329. {
  330. contexts.add( context );
  331. }
  332. else
  333. {
  334. log.warn( "context with id {} not exists", id );
  335. }
  336. }
  337. return contexts;
  338. }
  339. private void constructQuery( String term, BooleanQuery.Builder q )
  340. {
  341. q.add( indexer.constructQuery( MAVEN.GROUP_ID, new UserInputSearchExpression( term ) ), Occur.SHOULD );
  342. q.add( indexer.constructQuery( MAVEN.ARTIFACT_ID, new UserInputSearchExpression( term ) ), Occur.SHOULD );
  343. q.add( indexer.constructQuery( MAVEN.VERSION, new UserInputSearchExpression( term ) ), Occur.SHOULD );
  344. q.add( indexer.constructQuery( MAVEN.PACKAGING, new UserInputSearchExpression( term ) ), Occur.SHOULD );
  345. q.add( indexer.constructQuery( MAVEN.CLASSNAMES, new UserInputSearchExpression( term ) ), Occur.SHOULD );
  346. //Query query =
  347. // new WildcardQuery( new Term( MAVEN.CLASSNAMES.getFieldName(), "*" ) );
  348. //q.add( query, Occur.MUST_NOT );
  349. // olamy IMHO we could set this option as at least one must match
  350. //q.setMinimumNumberShouldMatch( 1 );
  351. }
  352. /**
  353. * @param selectedRepos
  354. * @return indexing contextId used
  355. */
  356. private List<String> addIndexingContexts( List<String> selectedRepos )
  357. {
  358. Set<String> indexingContextIds = new HashSet<>();
  359. for ( String repo : selectedRepos )
  360. {
  361. try
  362. {
  363. Repository rRepo = repositoryRegistry.getRepository(repo);
  364. if ( rRepo != null )
  365. {
  366. if (rRepo.getType().equals(RepositoryType.MAVEN)) {
  367. assert rRepo.getIndexingContext() != null;
  368. IndexingContext context = rRepo.getIndexingContext().getBaseContext(IndexingContext.class);
  369. if (context.isSearchable()) {
  370. indexingContextIds.addAll(getRemoteIndexingContextIds(repo));
  371. indexingContextIds.add(context.getId());
  372. } else {
  373. log.warn("indexingContext with id {} not searchable", rRepo.getId());
  374. }
  375. }
  376. }
  377. else
  378. {
  379. log.warn( "Repository '{}' not found in configuration.", repo );
  380. }
  381. }
  382. catch ( RepositorySearchException e )
  383. {
  384. log.warn( "RepositorySearchException occured while accessing index of repository '{}' : {}", repo,
  385. e.getMessage() );
  386. continue;
  387. } catch (UnsupportedBaseContextException e) {
  388. log.error("Fatal situation: Maven repository without IndexingContext found.");
  389. continue;
  390. }
  391. }
  392. return new ArrayList<>( indexingContextIds );
  393. }
  394. @Override
  395. public Set<String> getRemoteIndexingContextIds( String managedRepoId )
  396. throws RepositorySearchException
  397. {
  398. Set<String> ids = new HashSet<>();
  399. List<ProxyConnector> proxyConnectors = null;
  400. try
  401. {
  402. proxyConnectors = proxyConnectorAdmin.getProxyConnectorAsMap().get( managedRepoId );
  403. }
  404. catch ( RepositoryAdminException e )
  405. {
  406. throw new RepositorySearchException( e.getMessage(), e );
  407. }
  408. if ( proxyConnectors == null || proxyConnectors.isEmpty() )
  409. {
  410. return ids;
  411. }
  412. for ( ProxyConnector proxyConnector : proxyConnectors )
  413. {
  414. String remoteId = "remote-" + proxyConnector.getTargetRepoId();
  415. RemoteRepository repo = repositoryRegistry.getRemoteRepository(proxyConnector.getTargetRepoId());
  416. if (repo.getType()==RepositoryType.MAVEN) {
  417. try {
  418. IndexingContext context = repo.getIndexingContext() != null ? repo.getIndexingContext().getBaseContext(IndexingContext.class) : null;
  419. if (context!=null && context.isSearchable()) {
  420. ids.add(remoteId);
  421. }
  422. } catch (UnsupportedBaseContextException e) {
  423. // Ignore this one
  424. }
  425. }
  426. }
  427. return ids;
  428. }
  429. @Override
  430. public Collection<String> getAllGroupIds( String principal, List<String> selectedRepos )
  431. throws RepositorySearchException
  432. {
  433. List<IndexingContext> indexContexts = getIndexingContexts( selectedRepos );
  434. if ( indexContexts == null || indexContexts.isEmpty() )
  435. {
  436. return Collections.emptyList();
  437. }
  438. try
  439. {
  440. Set<String> allGroupIds = new HashSet<>();
  441. for ( IndexingContext indexingContext : indexContexts )
  442. {
  443. allGroupIds.addAll( indexingContext.getAllGroups() );
  444. }
  445. return allGroupIds;
  446. }
  447. catch ( IOException e )
  448. {
  449. throw new RepositorySearchException( e.getMessage(), e );
  450. }
  451. }
  452. private SearchResults convertToSearchResults( FlatSearchResponse response, SearchResultLimits limits,
  453. List<? extends ArtifactInfoFilter> artifactInfoFilters,
  454. List<String> selectedRepos, boolean includePoms )
  455. throws RepositoryAdminException
  456. {
  457. SearchResults results = new SearchResults();
  458. Set<ArtifactInfo> artifactInfos = response.getResults();
  459. for ( ArtifactInfo artifactInfo : artifactInfos )
  460. {
  461. if ( StringUtils.equalsIgnoreCase( "pom", artifactInfo.getFileExtension() ) && !includePoms )
  462. {
  463. continue;
  464. }
  465. String id = SearchUtil.getHitId( artifactInfo.getGroupId(), //
  466. artifactInfo.getArtifactId(), //
  467. artifactInfo.getClassifier(), //
  468. artifactInfo.getPackaging() );
  469. Map<String, SearchResultHit> hitsMap = results.getHitsMap();
  470. if ( !applyArtifactInfoFilters( artifactInfo, artifactInfoFilters, hitsMap ) )
  471. {
  472. continue;
  473. }
  474. SearchResultHit hit = hitsMap.get( id );
  475. if ( hit != null )
  476. {
  477. if ( !hit.getVersions().contains( artifactInfo.getVersion() ) )
  478. {
  479. hit.addVersion( artifactInfo.getVersion() );
  480. }
  481. }
  482. else
  483. {
  484. hit = new SearchResultHit();
  485. hit.setArtifactId( artifactInfo.getArtifactId() );
  486. hit.setGroupId( artifactInfo.getGroupId() );
  487. hit.setRepositoryId( artifactInfo.getRepository() );
  488. hit.addVersion( artifactInfo.getVersion() );
  489. hit.setBundleExportPackage( artifactInfo.getBundleExportPackage() );
  490. hit.setBundleExportService( artifactInfo.getBundleExportService() );
  491. hit.setBundleSymbolicName( artifactInfo.getBundleSymbolicName() );
  492. hit.setBundleVersion( artifactInfo.getBundleVersion() );
  493. hit.setBundleDescription( artifactInfo.getBundleDescription() );
  494. hit.setBundleDocUrl( artifactInfo.getBundleDocUrl() );
  495. hit.setBundleRequireBundle( artifactInfo.getBundleRequireBundle() );
  496. hit.setBundleImportPackage( artifactInfo.getBundleImportPackage() );
  497. hit.setBundleLicense( artifactInfo.getBundleLicense() );
  498. hit.setBundleName( artifactInfo.getBundleName() );
  499. hit.setContext( artifactInfo.getContext() );
  500. hit.setGoals( artifactInfo.getGoals() );
  501. hit.setPrefix( artifactInfo.getPrefix() );
  502. hit.setPackaging( artifactInfo.getPackaging() );
  503. hit.setClassifier( artifactInfo.getClassifier() );
  504. hit.setFileExtension( artifactInfo.getFileExtension() );
  505. hit.setUrl( getBaseUrl( artifactInfo, selectedRepos ) );
  506. }
  507. results.addHit( id, hit );
  508. }
  509. results.setTotalHits( response.getTotalHitsCount() );
  510. results.setTotalHitsMapSize( results.getHitsMap().values().size() );
  511. results.setReturnedHitsCount( response.getReturnedHitsCount() );
  512. results.setLimits( limits );
  513. if ( limits == null || limits.getSelectedPage() == SearchResultLimits.ALL_PAGES )
  514. {
  515. return results;
  516. }
  517. else
  518. {
  519. return paginate( results );
  520. }
  521. }
  522. /**
  523. * calculate baseUrl without the context and base Archiva Url
  524. *
  525. * @param artifactInfo
  526. * @return
  527. */
  528. protected String getBaseUrl( ArtifactInfo artifactInfo, List<String> selectedRepos )
  529. throws RepositoryAdminException
  530. {
  531. StringBuilder sb = new StringBuilder();
  532. if ( StringUtils.startsWith( artifactInfo.getContext(), "remote-" ) )
  533. {
  534. // it's a remote index result we search a managed which proxying this remote and on which
  535. // current user has read karma
  536. String managedRepoId =
  537. getManagedRepoId( StringUtils.substringAfter( artifactInfo.getContext(), "remote-" ), selectedRepos );
  538. if ( managedRepoId != null )
  539. {
  540. sb.append( '/' ).append( managedRepoId );
  541. artifactInfo.setContext( managedRepoId );
  542. }
  543. }
  544. else
  545. {
  546. sb.append( '/' ).append( artifactInfo.getContext() );
  547. }
  548. sb.append( '/' ).append( StringUtils.replaceChars( artifactInfo.getGroupId(), '.', '/' ) );
  549. sb.append( '/' ).append( artifactInfo.getArtifactId() );
  550. sb.append( '/' ).append( artifactInfo.getVersion() );
  551. sb.append( '/' ).append( artifactInfo.getArtifactId() );
  552. sb.append( '-' ).append( artifactInfo.getVersion() );
  553. if ( StringUtils.isNotBlank( artifactInfo.getClassifier() ) )
  554. {
  555. sb.append( '-' ).append( artifactInfo.getClassifier() );
  556. }
  557. // maven-plugin packaging is a jar
  558. if ( StringUtils.equals( "maven-plugin", artifactInfo.getPackaging() ) )
  559. {
  560. sb.append( "jar" );
  561. }
  562. else
  563. {
  564. sb.append( '.' ).append( artifactInfo.getPackaging() );
  565. }
  566. return sb.toString();
  567. }
  568. /**
  569. * return a managed repo for a remote result
  570. *
  571. * @param remoteRepo
  572. * @param selectedRepos
  573. * @return
  574. * @throws RepositoryAdminException
  575. */
  576. private String getManagedRepoId( String remoteRepo, List<String> selectedRepos )
  577. throws RepositoryAdminException
  578. {
  579. Map<String, List<ProxyConnector>> proxyConnectorMap = proxyConnectorAdmin.getProxyConnectorAsMap();
  580. if ( proxyConnectorMap == null || proxyConnectorMap.isEmpty() )
  581. {
  582. return null;
  583. }
  584. if ( selectedRepos != null && !selectedRepos.isEmpty() )
  585. {
  586. for ( Map.Entry<String, List<ProxyConnector>> entry : proxyConnectorMap.entrySet() )
  587. {
  588. if ( selectedRepos.contains( entry.getKey() ) )
  589. {
  590. for ( ProxyConnector proxyConnector : entry.getValue() )
  591. {
  592. if ( StringUtils.equals( remoteRepo, proxyConnector.getTargetRepoId() ) )
  593. {
  594. return proxyConnector.getSourceRepoId();
  595. }
  596. }
  597. }
  598. }
  599. }
  600. // we don't find in search selected repos so return the first one
  601. for ( Map.Entry<String, List<ProxyConnector>> entry : proxyConnectorMap.entrySet() )
  602. {
  603. for ( ProxyConnector proxyConnector : entry.getValue() )
  604. {
  605. if ( StringUtils.equals( remoteRepo, proxyConnector.getTargetRepoId() ) )
  606. {
  607. return proxyConnector.getSourceRepoId();
  608. }
  609. }
  610. }
  611. return null;
  612. }
  613. private boolean applyArtifactInfoFilters( ArtifactInfo artifactInfo,
  614. List<? extends ArtifactInfoFilter> artifactInfoFilters,
  615. Map<String, SearchResultHit> currentResult )
  616. {
  617. if ( artifactInfoFilters == null || artifactInfoFilters.isEmpty() )
  618. {
  619. return true;
  620. }
  621. ArchivaArtifactModel artifact = new ArchivaArtifactModel();
  622. artifact.setArtifactId( artifactInfo.getArtifactId() );
  623. artifact.setClassifier( artifactInfo.getClassifier() );
  624. artifact.setGroupId( artifactInfo.getGroupId() );
  625. artifact.setRepositoryId( artifactInfo.getRepository() );
  626. artifact.setVersion( artifactInfo.getVersion() );
  627. artifact.setChecksumMD5( artifactInfo.getMd5() );
  628. artifact.setChecksumSHA1( artifactInfo.getSha1() );
  629. for ( ArtifactInfoFilter filter : artifactInfoFilters )
  630. {
  631. if ( !filter.addArtifactInResult( artifact, currentResult ) )
  632. {
  633. return false;
  634. }
  635. }
  636. return true;
  637. }
  638. protected SearchResults paginate( SearchResults results )
  639. {
  640. SearchResultLimits limits = results.getLimits();
  641. SearchResults paginated = new SearchResults();
  642. // ( limits.getPageSize() * ( Math.max( 1, limits.getSelectedPage() ) ) );
  643. int fetchCount = limits.getPageSize();
  644. int offset = ( limits.getSelectedPage() * limits.getPageSize() );
  645. if ( fetchCount > results.getTotalHits() )
  646. {
  647. fetchCount = results.getTotalHits();
  648. }
  649. // Goto offset.
  650. if ( offset < results.getTotalHits() )
  651. {
  652. // only process if the offset is within the hit count.
  653. for ( int i = 0; i < fetchCount; i++ )
  654. {
  655. // Stop fetching if we are past the total # of available hits.
  656. if ( offset + i >= results.getHits().size() )
  657. {
  658. break;
  659. }
  660. SearchResultHit hit = results.getHits().get( ( offset + i ) );
  661. if ( hit != null )
  662. {
  663. String id = SearchUtil.getHitId( hit.getGroupId(), hit.getArtifactId(), hit.getClassifier(),
  664. hit.getPackaging() );
  665. paginated.addHit( id, hit );
  666. }
  667. else
  668. {
  669. break;
  670. }
  671. }
  672. }
  673. paginated.setTotalHits( results.getTotalHits() );
  674. paginated.setReturnedHitsCount( paginated.getHits().size() );
  675. paginated.setTotalHitsMapSize( results.getTotalHitsMapSize() );
  676. paginated.setLimits( limits );
  677. return paginated;
  678. }
  679. }