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

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