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