This project has retired. For details please refer to its Attic page.
Source code
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}