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