001package org.apache.archiva.indexer.search; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.archiva.admin.model.RepositoryAdminException; 023import org.apache.archiva.admin.model.beans.ManagedRepository; 024import org.apache.archiva.admin.model.beans.ProxyConnector; 025import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin; 026import org.apache.archiva.admin.model.proxyconnector.ProxyConnectorAdmin; 027import org.apache.archiva.common.plexusbridge.MavenIndexerUtils; 028import org.apache.archiva.common.plexusbridge.PlexusSisuBridge; 029import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException; 030import org.apache.archiva.indexer.util.SearchUtil; 031import org.apache.commons.lang.StringUtils; 032import org.apache.lucene.queryParser.ParseException; 033import org.apache.lucene.search.BooleanClause; 034import org.apache.lucene.search.BooleanClause.Occur; 035import org.apache.lucene.search.BooleanQuery; 036import org.apache.lucene.search.Query; 037import org.apache.maven.index.ArtifactInfo; 038import org.apache.maven.index.FlatSearchRequest; 039import org.apache.maven.index.FlatSearchResponse; 040import org.apache.maven.index.MAVEN; 041import org.apache.maven.index.NexusIndexer; 042import org.apache.maven.index.OSGI; 043import org.apache.maven.index.QueryCreator; 044import org.apache.maven.index.SearchType; 045import org.apache.maven.index.context.IndexCreator; 046import org.apache.maven.index.context.IndexingContext; 047import org.apache.maven.index.expr.SearchExpression; 048import org.apache.maven.index.expr.SearchTyped; 049import org.apache.maven.index.expr.SourcedSearchExpression; 050import org.apache.maven.index.expr.UserInputSearchExpression; 051import org.slf4j.Logger; 052import org.slf4j.LoggerFactory; 053import org.springframework.stereotype.Service; 054 055import javax.inject.Inject; 056import java.io.IOException; 057import java.util.ArrayList; 058import java.util.Collection; 059import java.util.Collections; 060import java.util.HashSet; 061import java.util.List; 062import java.util.Map; 063import java.util.Set; 064 065/** 066 * RepositorySearch implementation which uses the Maven Indexer for searching. 067 */ 068@Service( "repositorySearch#maven" ) 069public class MavenRepositorySearch 070 implements RepositorySearch 071{ 072 private Logger log = LoggerFactory.getLogger( getClass() ); 073 074 private NexusIndexer indexer; 075 076 private QueryCreator queryCreator; 077 078 private ManagedRepositoryAdmin managedRepositoryAdmin; 079 080 private ProxyConnectorAdmin proxyConnectorAdmin; 081 082 private MavenIndexerUtils mavenIndexerUtils; 083 084 protected MavenRepositorySearch() 085 { 086 // for test purpose 087 } 088 089 @Inject 090 public MavenRepositorySearch( PlexusSisuBridge plexusSisuBridge, ManagedRepositoryAdmin managedRepositoryAdmin, 091 MavenIndexerUtils mavenIndexerUtils, ProxyConnectorAdmin proxyConnectorAdmin ) 092 throws PlexusSisuBridgeException 093 { 094 this.indexer = plexusSisuBridge.lookup( NexusIndexer.class ); 095 this.queryCreator = plexusSisuBridge.lookup( QueryCreator.class ); 096 this.managedRepositoryAdmin = managedRepositoryAdmin; 097 this.mavenIndexerUtils = mavenIndexerUtils; 098 this.proxyConnectorAdmin = proxyConnectorAdmin; 099 } 100 101 /** 102 * @see RepositorySearch#search(String, List, String, SearchResultLimits, List) 103 */ 104 @Override 105 public SearchResults search( String principal, List<String> selectedRepos, String term, SearchResultLimits limits, 106 List<String> previousSearchTerms ) 107 throws RepositorySearchException 108 { 109 List<String> indexingContextIds = addIndexingContexts( selectedRepos ); 110 111 // since upgrade to nexus 2.0.0, query has changed from g:[QUERIED TERM]* to g:*[QUERIED TERM]* 112 // resulting to more wildcard searches so we need to increase max clause count 113 BooleanQuery.setMaxClauseCount( Integer.MAX_VALUE ); 114 BooleanQuery q = new BooleanQuery(); 115 116 if ( previousSearchTerms == null || previousSearchTerms.isEmpty() ) 117 { 118 constructQuery( term, q ); 119 } 120 else 121 { 122 for ( String previousTerm : previousSearchTerms ) 123 { 124 BooleanQuery iQuery = new BooleanQuery(); 125 constructQuery( previousTerm, iQuery ); 126 127 q.add( iQuery, Occur.MUST ); 128 } 129 130 BooleanQuery iQuery = new BooleanQuery(); 131 constructQuery( term, iQuery ); 132 q.add( iQuery, Occur.MUST ); 133 } 134 135 // we retun only artifacts without classifier in quick search, olamy cannot find a way to say with this field empty 136 // FIXME cannot find a way currently to setup this in constructQuery !!! 137 return search( limits, q, indexingContextIds, NoClassifierArtifactInfoFilter.LIST, selectedRepos, true ); 138 139 } 140 141 /** 142 * @see RepositorySearch#search(String, SearchFields, SearchResultLimits) 143 */ 144 @Override 145 public SearchResults search( String principal, SearchFields searchFields, SearchResultLimits limits ) 146 throws RepositorySearchException 147 { 148 if ( searchFields.getRepositories() == null ) 149 { 150 throw new RepositorySearchException( "Repositories cannot be null." ); 151 } 152 153 List<String> indexingContextIds = addIndexingContexts( searchFields.getRepositories() ); 154 155 // if no index found in the specified ones return an empty search result instead of doing a search on all index 156 // olamy: IMHO doesn't make sense 157 if ( !searchFields.getRepositories().isEmpty() && ( indexingContextIds == null 158 || indexingContextIds.isEmpty() ) ) 159 { 160 return new SearchResults(); 161 } 162 163 BooleanQuery q = new BooleanQuery(); 164 if ( StringUtils.isNotBlank( searchFields.getGroupId() ) ) 165 { 166 q.add( indexer.constructQuery( MAVEN.GROUP_ID, searchFields.isExactSearch() 167 ? new SourcedSearchExpression( searchFields.getGroupId() ) 168 : new UserInputSearchExpression( searchFields.getGroupId() ) 169 ), Occur.MUST 170 ); 171 } 172 173 if ( StringUtils.isNotBlank( searchFields.getArtifactId() ) ) 174 { 175 q.add( indexer.constructQuery( MAVEN.ARTIFACT_ID, 176 searchFields.isExactSearch() 177 ? new SourcedSearchExpression( searchFields.getArtifactId() ) 178 : new UserInputSearchExpression( searchFields.getArtifactId() ) 179 ), Occur.MUST 180 ); 181 } 182 183 if ( StringUtils.isNotBlank( searchFields.getVersion() ) ) 184 { 185 q.add( indexer.constructQuery( MAVEN.VERSION, new SourcedSearchExpression( 186 searchFields.getVersion( ) ) ), Occur.MUST ); 187 } 188 189 if ( StringUtils.isNotBlank( searchFields.getPackaging() ) ) 190 { 191 q.add( indexer.constructQuery( MAVEN.PACKAGING, searchFields.isExactSearch() ? new SourcedSearchExpression( 192 searchFields.getPackaging() ) : new UserInputSearchExpression( searchFields.getPackaging() ) ), 193 Occur.MUST 194 ); 195 } 196 197 if ( StringUtils.isNotBlank( searchFields.getClassName() ) ) 198 { 199 q.add( indexer.constructQuery( MAVEN.CLASSNAMES, 200 new UserInputSearchExpression( searchFields.getClassName() ) ), Occur.MUST ); 201 } 202 203 if ( StringUtils.isNotBlank( searchFields.getBundleSymbolicName() ) ) 204 { 205 q.add( indexer.constructQuery( OSGI.SYMBOLIC_NAME, 206 new UserInputSearchExpression( searchFields.getBundleSymbolicName() ) ), 207 Occur.MUST 208 ); 209 } 210 211 if ( StringUtils.isNotBlank( searchFields.getBundleVersion() ) ) 212 { 213 q.add( indexer.constructQuery( OSGI.VERSION, 214 new UserInputSearchExpression( searchFields.getBundleVersion() ) ), 215 Occur.MUST 216 ); 217 } 218 219 if ( StringUtils.isNotBlank( searchFields.getBundleExportPackage() ) ) 220 { 221 q.add( indexer.constructQuery( OSGI.EXPORT_PACKAGE, 222 new UserInputSearchExpression( searchFields.getBundleExportPackage() ) ), 223 Occur.MUST 224 ); 225 } 226 227 if ( StringUtils.isNotBlank( searchFields.getBundleExportService() ) ) 228 { 229 q.add( indexer.constructQuery( OSGI.EXPORT_SERVICE, 230 new UserInputSearchExpression( searchFields.getBundleExportService() ) ), 231 Occur.MUST 232 ); 233 } 234 235 if ( StringUtils.isNotBlank( searchFields.getBundleImportPackage() ) ) 236 { 237 q.add( indexer.constructQuery( OSGI.IMPORT_PACKAGE, 238 new UserInputSearchExpression( searchFields.getBundleImportPackage() ) ), 239 Occur.MUST 240 ); 241 } 242 243 if ( StringUtils.isNotBlank( searchFields.getBundleName() ) ) 244 { 245 q.add( indexer.constructQuery( OSGI.NAME, new UserInputSearchExpression( searchFields.getBundleName() ) ), 246 Occur.MUST ); 247 } 248 249 if ( StringUtils.isNotBlank( searchFields.getBundleImportPackage() ) ) 250 { 251 q.add( indexer.constructQuery( OSGI.IMPORT_PACKAGE, 252 new UserInputSearchExpression( searchFields.getBundleImportPackage() ) ), 253 Occur.MUST 254 ); 255 } 256 257 if ( StringUtils.isNotBlank( searchFields.getBundleRequireBundle() ) ) 258 { 259 q.add( indexer.constructQuery( OSGI.REQUIRE_BUNDLE, 260 new UserInputSearchExpression( searchFields.getBundleRequireBundle() ) ), 261 Occur.MUST 262 ); 263 } 264 265 if ( StringUtils.isNotBlank( searchFields.getClassifier() ) ) 266 { 267 q.add( indexer.constructQuery( MAVEN.CLASSIFIER, searchFields.isExactSearch() ? new SourcedSearchExpression( 268 searchFields.getClassifier() ) : new UserInputSearchExpression( searchFields.getClassifier() ) ), 269 Occur.MUST 270 ); 271 } 272 else if ( searchFields.isExactSearch() ) 273 { 274 //TODO improvement in case of exact search and no classifier we must query for classifier with null value 275 // currently it's done in DefaultSearchService with some filtering 276 } 277 278 if ( q.getClauses() == null || q.getClauses().length <= 0 ) 279 { 280 throw new RepositorySearchException( "No search fields set." ); 281 } 282 283 return search( limits, q, indexingContextIds, Collections.<ArtifactInfoFilter>emptyList(), 284 searchFields.getRepositories(), searchFields.isIncludePomArtifacts() ); 285 } 286 287 private static class NullSearch implements SearchTyped, SearchExpression 288 { 289 private static final NullSearch INSTANCE = new NullSearch(); 290 291 @Override 292 public String getStringValue() 293 { 294 return "[[NULL_VALUE]]"; 295 } 296 297 @Override 298 public SearchType getSearchType() 299 { 300 return SearchType.EXACT; 301 } 302 } 303 304 private SearchResults search( SearchResultLimits limits, BooleanQuery q, List<String> indexingContextIds, 305 List<? extends ArtifactInfoFilter> filters, List<String> selectedRepos, 306 boolean includePoms ) 307 throws RepositorySearchException 308 { 309 310 try 311 { 312 FlatSearchRequest request = new FlatSearchRequest( q ); 313 314 request.setContexts( getIndexingContexts( indexingContextIds ) ); 315 if ( limits != null ) 316 { 317 // we apply limits only when first page asked 318 if ( limits.getSelectedPage() == 0 ) 319 { 320 request.setCount( limits.getPageSize() * ( Math.max( 1, limits.getSelectedPage() ) ) ); 321 } 322 } 323 324 FlatSearchResponse response = indexer.searchFlat( request ); 325 326 if ( response == null || response.getTotalHits() == 0 ) 327 { 328 SearchResults results = new SearchResults(); 329 results.setLimits( limits ); 330 return results; 331 } 332 333 return convertToSearchResults( response, limits, filters, selectedRepos, includePoms ); 334 } 335 catch ( IOException e ) 336 { 337 throw new RepositorySearchException( e.getMessage(), e ); 338 } 339 catch ( RepositoryAdminException e ) 340 { 341 throw new RepositorySearchException( e.getMessage(), e ); 342 } 343 344 } 345 346 private List<IndexingContext> getIndexingContexts( List<String> ids ) 347 { 348 List<IndexingContext> contexts = new ArrayList<>( ids.size() ); 349 350 for ( String id : ids ) 351 { 352 IndexingContext context = indexer.getIndexingContexts().get( id ); 353 if ( context != null ) 354 { 355 contexts.add( context ); 356 } 357 else 358 { 359 log.warn( "context with id {} not exists", id ); 360 } 361 } 362 363 return contexts; 364 } 365 366 private void constructQuery( String term, BooleanQuery q ) 367 { 368 q.add( indexer.constructQuery( MAVEN.GROUP_ID, new UserInputSearchExpression( term ) ), Occur.SHOULD ); 369 q.add( indexer.constructQuery( MAVEN.ARTIFACT_ID, new UserInputSearchExpression( term ) ), Occur.SHOULD ); 370 q.add( indexer.constructQuery( MAVEN.VERSION, new UserInputSearchExpression( term ) ), Occur.SHOULD ); 371 q.add( indexer.constructQuery( MAVEN.PACKAGING, new UserInputSearchExpression( term ) ), Occur.SHOULD ); 372 q.add( indexer.constructQuery( MAVEN.CLASSNAMES, new UserInputSearchExpression( term ) ), Occur.SHOULD ); 373 374 //Query query = 375 // new WildcardQuery( new Term( MAVEN.CLASSNAMES.getFieldName(), "*" ) ); 376 //q.add( query, Occur.MUST_NOT ); 377 // olamy IMHO we could set this option as at least one must match 378 //q.setMinimumNumberShouldMatch( 1 ); 379 } 380 381 382 /** 383 * @param selectedRepos 384 * @return indexing contextId used 385 */ 386 private List<String> addIndexingContexts( List<String> selectedRepos ) 387 { 388 Set<String> indexingContextIds = new HashSet<>(); 389 for ( String repo : selectedRepos ) 390 { 391 try 392 { 393 ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repo ); 394 395 if ( repoConfig != null ) 396 { 397 398 IndexingContext context = managedRepositoryAdmin.createIndexContext( repoConfig ); 399 if ( context.isSearchable() ) 400 { 401 indexingContextIds.addAll( getRemoteIndexingContextIds( repo ) ); 402 indexingContextIds.add( context.getId() ); 403 } 404 else 405 { 406 log.warn( "indexingContext with id {} not searchable", repoConfig.getId() ); 407 } 408 409 } 410 else 411 { 412 log.warn( "Repository '{}' not found in configuration.", repo ); 413 } 414 } 415 catch ( RepositoryAdminException e ) 416 { 417 log.warn( "RepositoryAdminException occured while accessing index of repository '{}' : {}", repo, 418 e.getMessage() ); 419 continue; 420 } 421 } 422 423 return new ArrayList<>( indexingContextIds ); 424 } 425 426 427 @Override 428 public Set<String> getRemoteIndexingContextIds( String managedRepoId ) 429 throws RepositoryAdminException 430 { 431 Set<String> ids = new HashSet<>(); 432 433 List<ProxyConnector> proxyConnectors = proxyConnectorAdmin.getProxyConnectorAsMap().get( managedRepoId ); 434 435 if ( proxyConnectors == null || proxyConnectors.isEmpty() ) 436 { 437 return ids; 438 } 439 440 for ( ProxyConnector proxyConnector : proxyConnectors ) 441 { 442 String remoteId = "remote-" + proxyConnector.getTargetRepoId(); 443 IndexingContext context = indexer.getIndexingContexts().get( remoteId ); 444 if ( context != null && context.isSearchable() ) 445 { 446 ids.add( remoteId ); 447 } 448 } 449 450 return ids; 451 } 452 453 @Override 454 public Collection<String> getAllGroupIds( String principal, List<String> selectedRepos ) 455 throws RepositorySearchException 456 { 457 List<IndexingContext> indexContexts = getIndexingContexts( selectedRepos ); 458 459 if ( indexContexts == null || indexContexts.isEmpty() ) 460 { 461 return Collections.emptyList(); 462 } 463 464 try 465 { 466 Set<String> allGroupIds = new HashSet<>(); 467 for ( IndexingContext indexingContext : indexContexts ) 468 { 469 allGroupIds.addAll( indexingContext.getAllGroups() ); 470 } 471 return allGroupIds; 472 } 473 catch ( IOException e ) 474 { 475 throw new RepositorySearchException( e.getMessage(), e ); 476 } 477 478 } 479 480 481 protected List<? extends IndexCreator> getAllIndexCreators() 482 { 483 return mavenIndexerUtils.getAllIndexCreators(); 484 } 485 486 487 private SearchResults convertToSearchResults( FlatSearchResponse response, SearchResultLimits limits, 488 List<? extends ArtifactInfoFilter> artifactInfoFilters, 489 List<String> selectedRepos, boolean includePoms ) 490 throws RepositoryAdminException 491 { 492 SearchResults results = new SearchResults(); 493 Set<ArtifactInfo> artifactInfos = response.getResults(); 494 495 for ( ArtifactInfo artifactInfo : artifactInfos ) 496 { 497 if ( StringUtils.equalsIgnoreCase( "pom", artifactInfo.fextension ) && !includePoms ) 498 { 499 continue; 500 } 501 String id = SearchUtil.getHitId( artifactInfo.groupId, artifactInfo.artifactId, artifactInfo.classifier, 502 artifactInfo.packaging ); 503 Map<String, SearchResultHit> hitsMap = results.getHitsMap(); 504 505 if ( !applyArtifactInfoFilters( artifactInfo, artifactInfoFilters, hitsMap ) ) 506 { 507 continue; 508 } 509 510 SearchResultHit hit = hitsMap.get( id ); 511 if ( hit != null ) 512 { 513 if ( !hit.getVersions().contains( artifactInfo.version ) ) 514 { 515 hit.addVersion( artifactInfo.version ); 516 } 517 } 518 else 519 { 520 hit = new SearchResultHit(); 521 hit.setArtifactId( artifactInfo.artifactId ); 522 hit.setGroupId( artifactInfo.groupId ); 523 hit.setRepositoryId( artifactInfo.repository ); 524 hit.addVersion( artifactInfo.version ); 525 hit.setBundleExportPackage( artifactInfo.bundleExportPackage ); 526 hit.setBundleExportService( artifactInfo.bundleExportService ); 527 hit.setBundleSymbolicName( artifactInfo.bundleSymbolicName ); 528 hit.setBundleVersion( artifactInfo.bundleVersion ); 529 hit.setBundleDescription( artifactInfo.bundleDescription ); 530 hit.setBundleDocUrl( artifactInfo.bundleDocUrl ); 531 hit.setBundleRequireBundle( artifactInfo.bundleRequireBundle ); 532 hit.setBundleImportPackage( artifactInfo.bundleImportPackage ); 533 hit.setBundleLicense( artifactInfo.bundleLicense ); 534 hit.setBundleName( artifactInfo.bundleName ); 535 hit.setContext( artifactInfo.context ); 536 hit.setGoals( artifactInfo.goals ); 537 hit.setPrefix( artifactInfo.prefix ); 538 hit.setPackaging( artifactInfo.packaging ); 539 hit.setClassifier( artifactInfo.classifier ); 540 hit.setFileExtension( artifactInfo.fextension ); 541 hit.setUrl( getBaseUrl( artifactInfo, selectedRepos ) ); 542 } 543 544 results.addHit( id, hit ); 545 } 546 547 results.setTotalHits( response.getTotalHitsCount() ); 548 results.setTotalHitsMapSize( results.getHitsMap().values().size() ); 549 results.setReturnedHitsCount( response.getReturnedHitsCount() ); 550 results.setLimits( limits ); 551 552 if ( limits == null || limits.getSelectedPage() == SearchResultLimits.ALL_PAGES ) 553 { 554 return results; 555 } 556 else 557 { 558 return paginate( results ); 559 } 560 } 561 562 /** 563 * calculate baseUrl without the context and base Archiva Url 564 * 565 * @param artifactInfo 566 * @return 567 */ 568 protected String getBaseUrl( ArtifactInfo artifactInfo, List<String> selectedRepos ) 569 throws RepositoryAdminException 570 { 571 StringBuilder sb = new StringBuilder(); 572 if ( StringUtils.startsWith( artifactInfo.context, "remote-" ) ) 573 { 574 // it's a remote index result we search a managed which proxying this remote and on which 575 // current user has read karma 576 String managedRepoId = 577 getManagedRepoId( StringUtils.substringAfter( artifactInfo.context, "remote-" ), selectedRepos ); 578 if ( managedRepoId != null ) 579 { 580 sb.append( '/' ).append( managedRepoId ); 581 artifactInfo.context = managedRepoId; 582 } 583 } 584 else 585 { 586 sb.append( '/' ).append( artifactInfo.context ); 587 } 588 589 sb.append( '/' ).append( StringUtils.replaceChars( artifactInfo.groupId, '.', '/' ) ); 590 sb.append( '/' ).append( artifactInfo.artifactId ); 591 sb.append( '/' ).append( artifactInfo.version ); 592 sb.append( '/' ).append( artifactInfo.artifactId ); 593 sb.append( '-' ).append( artifactInfo.version ); 594 if ( StringUtils.isNotBlank( artifactInfo.classifier ) ) 595 { 596 sb.append( '-' ).append( artifactInfo.classifier ); 597 } 598 // maven-plugin packaging is a jar 599 if ( StringUtils.equals( "maven-plugin", artifactInfo.packaging ) ) 600 { 601 sb.append( "jar" ); 602 } 603 else 604 { 605 sb.append( '.' ).append( artifactInfo.packaging ); 606 } 607 608 return sb.toString(); 609 } 610 611 /** 612 * return a managed repo for a remote result 613 * 614 * @param remoteRepo 615 * @param selectedRepos 616 * @return 617 * @throws RepositoryAdminException 618 */ 619 private String getManagedRepoId( String remoteRepo, List<String> selectedRepos ) 620 throws RepositoryAdminException 621 { 622 Map<String, List<ProxyConnector>> proxyConnectorMap = proxyConnectorAdmin.getProxyConnectorAsMap(); 623 if ( proxyConnectorMap == null || proxyConnectorMap.isEmpty() ) 624 { 625 return null; 626 } 627 if ( selectedRepos != null && !selectedRepos.isEmpty() ) 628 { 629 for ( Map.Entry<String, List<ProxyConnector>> entry : proxyConnectorMap.entrySet() ) 630 { 631 if ( selectedRepos.contains( entry.getKey() ) ) 632 { 633 for ( ProxyConnector proxyConnector : entry.getValue() ) 634 { 635 if ( StringUtils.equals( remoteRepo, proxyConnector.getTargetRepoId() ) ) 636 { 637 return proxyConnector.getSourceRepoId(); 638 } 639 } 640 } 641 } 642 } 643 644 // we don't find in search selected repos so return the first one 645 for ( Map.Entry<String, List<ProxyConnector>> entry : proxyConnectorMap.entrySet() ) 646 { 647 648 for ( ProxyConnector proxyConnector : entry.getValue() ) 649 { 650 if ( StringUtils.equals( remoteRepo, proxyConnector.getTargetRepoId() ) ) 651 { 652 return proxyConnector.getSourceRepoId(); 653 } 654 } 655 656 } 657 return null; 658 } 659 660 private boolean applyArtifactInfoFilters( ArtifactInfo artifactInfo, 661 List<? extends ArtifactInfoFilter> artifactInfoFilters, 662 Map<String, SearchResultHit> currentResult ) 663 { 664 if ( artifactInfoFilters == null || artifactInfoFilters.isEmpty() ) 665 { 666 return true; 667 } 668 669 for ( ArtifactInfoFilter filter : artifactInfoFilters ) 670 { 671 if ( !filter.addArtifactInResult( artifactInfo, currentResult ) ) 672 { 673 return false; 674 } 675 } 676 return true; 677 } 678 679 protected SearchResults paginate( SearchResults results ) 680 { 681 SearchResultLimits limits = results.getLimits(); 682 SearchResults paginated = new SearchResults(); 683 684 // ( limits.getPageSize() * ( Math.max( 1, limits.getSelectedPage() ) ) ); 685 686 int fetchCount = limits.getPageSize(); 687 int offset = ( limits.getSelectedPage() * limits.getPageSize() ); 688 689 if ( fetchCount > results.getTotalHits() ) 690 { 691 fetchCount = results.getTotalHits(); 692 } 693 694 // Goto offset. 695 if ( offset < results.getTotalHits() ) 696 { 697 // only process if the offset is within the hit count. 698 for ( int i = 0; i < fetchCount; i++ ) 699 { 700 // Stop fetching if we are past the total # of available hits. 701 if ( offset + i >= results.getHits().size() ) 702 { 703 break; 704 } 705 706 SearchResultHit hit = results.getHits().get( ( offset + i ) ); 707 if ( hit != null ) 708 { 709 String id = SearchUtil.getHitId( hit.getGroupId(), hit.getArtifactId(), hit.getClassifier(), 710 hit.getPackaging() ); 711 paginated.addHit( id, hit ); 712 } 713 else 714 { 715 break; 716 } 717 } 718 } 719 paginated.setTotalHits( results.getTotalHits() ); 720 paginated.setReturnedHitsCount( paginated.getHits().size() ); 721 paginated.setTotalHitsMapSize( results.getTotalHitsMapSize() ); 722 paginated.setLimits( limits ); 723 724 return paginated; 725 } 726 727 728}