Coverage Report - org.apache.archiva.indexer.search.NexusRepositorySearch
 
Classes in this File Line Coverage Branch Coverage Complexity
NexusRepositorySearch
0%
0/120
0%
0/66
0
 
 1  
 package org.apache.archiva.indexer.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 java.io.File;
 23  
 import java.io.IOException;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 import java.util.Set;
 27  
 
 28  
 import org.apache.archiva.indexer.util.SearchUtil;
 29  
 import org.apache.lucene.search.BooleanQuery;
 30  
 import org.apache.lucene.search.BooleanClause.Occur;
 31  
 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
 32  
 import org.apache.maven.archiva.configuration.Configuration;
 33  
 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
 34  
 import org.slf4j.Logger;
 35  
 import org.slf4j.LoggerFactory;
 36  
 import org.sonatype.nexus.index.ArtifactInfo;
 37  
 import org.sonatype.nexus.index.FlatSearchRequest;
 38  
 import org.sonatype.nexus.index.FlatSearchResponse;
 39  
 import org.sonatype.nexus.index.NexusIndexer;
 40  
 import org.sonatype.nexus.index.context.IndexCreator;
 41  
 import org.sonatype.nexus.index.context.IndexingContext;
 42  
 import org.sonatype.nexus.index.context.UnsupportedExistingLuceneIndexException;
 43  
 
 44  
 /**
 45  
  * RepositorySearch implementation which uses the Nexus Indexer for searching.
 46  
  */
 47  
 public class NexusRepositorySearch
 48  
     implements RepositorySearch
 49  
 {
 50  0
     private static final Logger log = LoggerFactory.getLogger( NexusRepositorySearch.class ); 
 51  
                                                               
 52  
     private NexusIndexer indexer;
 53  
     
 54  
     private ArchivaConfiguration archivaConfig;
 55  
     
 56  
     public NexusRepositorySearch( NexusIndexer indexer, ArchivaConfiguration archivaConfig )
 57  0
     {
 58  0
         this.indexer = indexer;
 59  0
         this.archivaConfig = archivaConfig;
 60  0
     }
 61  
 
 62  
     /**
 63  
      * @see RepositorySearch#search(String, List, String, SearchResultLimits, List)
 64  
      */
 65  
     public SearchResults search( String principal, List<String> selectedRepos, String term, SearchResultLimits limits,
 66  
                                  List<String> previousSearchTerms )
 67  
         throws RepositorySearchException
 68  
     {   
 69  0
         addIndexingContexts( selectedRepos );
 70  
         
 71  
         // since upgrade to nexus 2.0.0, query has changed from g:[QUERIED TERM]* to g:*[QUERIED TERM]*
 72  
         //      resulting to more wildcard searches so we need to increase max clause count
 73  0
         BooleanQuery.setMaxClauseCount( Integer.MAX_VALUE );
 74  0
         BooleanQuery q = new BooleanQuery();
 75  
         
 76  0
         if( previousSearchTerms == null || previousSearchTerms.isEmpty() )
 77  
         {            
 78  0
             constructQuery( term, q );
 79  
         }
 80  
         else
 81  
         {   
 82  0
             for( String previousTerm : previousSearchTerms )
 83  
             {
 84  0
                 BooleanQuery iQuery = new BooleanQuery();
 85  0
                 constructQuery( previousTerm, iQuery );
 86  
                 
 87  0
                 q.add( iQuery, Occur.MUST );
 88  0
             }
 89  
             
 90  0
             BooleanQuery iQuery = new BooleanQuery();
 91  0
             constructQuery( term, iQuery );
 92  0
             q.add( iQuery, Occur.MUST );
 93  
         }      
 94  
                     
 95  0
         return search( limits, q );
 96  
     }
 97  
     
 98  
     /**
 99  
      * @see RepositorySearch#search(String, SearchFields, SearchResultLimits)
 100  
      */
 101  
     public SearchResults search( String principal, SearchFields searchFields, SearchResultLimits limits )
 102  
         throws RepositorySearchException
 103  
     {
 104  0
         if( searchFields.getRepositories() == null )
 105  
         {
 106  0
             throw new RepositorySearchException( "Repositories cannot be null." );
 107  
         }
 108  
         
 109  0
         addIndexingContexts( searchFields.getRepositories() );
 110  
         
 111  0
         BooleanQuery q = new BooleanQuery();
 112  0
         if( searchFields.getGroupId() != null && !"".equals( searchFields.getGroupId() ) )
 113  
         {   
 114  0
             q.add( indexer.constructQuery( ArtifactInfo.GROUP_ID, searchFields.getGroupId() ), Occur.MUST );
 115  
         }
 116  
         
 117  0
         if( searchFields.getArtifactId() != null && !"".equals( searchFields.getArtifactId() ) )
 118  
         {
 119  0
             q.add( indexer.constructQuery( ArtifactInfo.ARTIFACT_ID, searchFields.getArtifactId() ), Occur.MUST );
 120  
         }
 121  
         
 122  0
         if( searchFields.getVersion() != null && !"".equals( searchFields.getVersion() ) )
 123  
         {
 124  0
             q.add( indexer.constructQuery( ArtifactInfo.VERSION, searchFields.getVersion() ), Occur.MUST );
 125  
         }
 126  
         
 127  0
         if( searchFields.getPackaging() != null && !"".equals( searchFields.getPackaging() ) )
 128  
         {
 129  0
             q.add( indexer.constructQuery( ArtifactInfo.PACKAGING, searchFields.getPackaging() ), Occur.MUST );
 130  
         }
 131  
         
 132  0
         if( searchFields.getClassName() != null && !"".equals( searchFields.getClassName() ) )
 133  
         {
 134  0
             q.add( indexer.constructQuery( ArtifactInfo.NAMES, searchFields.getClassName() ), Occur.MUST );
 135  
         }
 136  
         
 137  0
         if( q.getClauses() == null || q.getClauses().length <= 0 )
 138  
         {
 139  0
             throw new RepositorySearchException( "No search fields set." );
 140  
         }
 141  
         
 142  0
         return search( limits, q );        
 143  
     }
 144  
 
 145  
     private SearchResults search( SearchResultLimits limits, BooleanQuery q )
 146  
         throws RepositorySearchException
 147  
     {
 148  
         try
 149  
         {
 150  0
             FlatSearchRequest request = new FlatSearchRequest( q );
 151  0
             FlatSearchResponse response = indexer.searchFlat( request );
 152  
             
 153  0
             if( response == null || response.getTotalHits() == 0 )
 154  
             {
 155  0
                 SearchResults results = new SearchResults();
 156  0
                 results.setLimits( limits );
 157  0
                 return results;
 158  
             }
 159  
             
 160  0
             return convertToSearchResults( response, limits );
 161  
         }
 162  0
         catch ( IOException e )
 163  
         {
 164  0
             throw new RepositorySearchException( e );
 165  
         }
 166  
         finally
 167  
         {
 168  0
             Map<String, IndexingContext> indexingContexts = indexer.getIndexingContexts();
 169  0
             Set<String> keys = indexingContexts.keySet();
 170  0
             for( String key : keys )
 171  
             {
 172  
                 try                
 173  
                 {   
 174  0
                     indexer.removeIndexingContext( indexingContexts.get( key ), false );
 175  0
                     log.debug( "Indexing context '" + key + "' removed from search." );
 176  
                 }
 177  0
                 catch ( IOException e )
 178  
                 {
 179  0
                     log.warn( "IOException occurred while removing indexing content '" + key  + "'." );
 180  0
                     continue;
 181  0
                 }
 182  
             }            
 183  0
         }
 184  
     }
 185  
 
 186  
     private void constructQuery( String term, BooleanQuery q )
 187  
     {
 188  0
         q.add( indexer.constructQuery( ArtifactInfo.GROUP_ID, term ), Occur.SHOULD );
 189  0
         q.add( indexer.constructQuery( ArtifactInfo.ARTIFACT_ID, term ), Occur.SHOULD );
 190  0
         q.add( indexer.constructQuery( ArtifactInfo.VERSION, term ), Occur.SHOULD );
 191  0
         q.add( indexer.constructQuery( ArtifactInfo.PACKAGING, term ), Occur.SHOULD );
 192  0
         q.add( indexer.constructQuery( ArtifactInfo.NAMES, term ), Occur.SHOULD );        
 193  0
     }
 194  
        
 195  
     
 196  
     private void addIndexingContexts( List<String> selectedRepos )
 197  
     {
 198  0
         for( String repo : selectedRepos )
 199  
         {
 200  
             try
 201  
             {
 202  0
                 Configuration config = archivaConfig.getConfiguration();
 203  0
                 ManagedRepositoryConfiguration repoConfig = config.findManagedRepositoryById( repo );
 204  
                 
 205  0
                 if( repoConfig != null )
 206  
                 {
 207  0
                     String indexDir = repoConfig.getIndexDir();
 208  0
                     File indexDirectory = null;
 209  0
                     if( indexDir != null && !"".equals( indexDir ) )
 210  
                     {
 211  0
                         indexDirectory = new File( repoConfig.getIndexDir() );
 212  
                     }
 213  
                     else
 214  
                     {
 215  0
                         indexDirectory = new File( repoConfig.getLocation(), ".indexer" );
 216  
                     }
 217  
                     
 218  0
                     IndexingContext context =
 219  
                         indexer.addIndexingContext( repoConfig.getId(), repoConfig.getId(), new File( repoConfig.getLocation() ),
 220  
                                                     indexDirectory, null, null, NexusIndexer.FULL_INDEX );
 221  0
                     context.setSearchable( repoConfig.isScanned() );
 222  0
                 }
 223  
                 else
 224  
                 {
 225  0
                     log.warn( "Repository '" + repo + "' not found in configuration." );
 226  
                 }
 227  
             }
 228  0
             catch ( UnsupportedExistingLuceneIndexException e )
 229  
             {                
 230  0
                 log.warn( "Error accessing index of repository '" + repo + "' : " + e.getMessage() );
 231  0
                 continue;
 232  
             }
 233  0
             catch ( IOException e )
 234  
             {                
 235  0
                 log.warn( "IO error occured while accessing index of repository '" + repo + "' : " + e.getMessage() );
 236  0
                 continue;
 237  0
             }
 238  
         }
 239  0
     }
 240  
 
 241  
     private SearchResults convertToSearchResults( FlatSearchResponse response, SearchResultLimits limits )
 242  
     {   
 243  0
         SearchResults results = new SearchResults();
 244  0
         Set<ArtifactInfo> artifactInfos = response.getResults();
 245  
         
 246  0
         for ( ArtifactInfo artifactInfo : artifactInfos )
 247  
         {
 248  0
             String id = SearchUtil.getHitId( artifactInfo.groupId, artifactInfo.artifactId );
 249  0
             Map<String, SearchResultHit> hitsMap = results.getHitsMap();
 250  
 
 251  0
             SearchResultHit hit = hitsMap.get( id );
 252  0
             if ( hit != null )
 253  
             {
 254  0
                 hit.addVersion( artifactInfo.version );
 255  
             }
 256  
             else
 257  
             {
 258  0
                 hit = new SearchResultHit();
 259  0
                 hit.setArtifactId( artifactInfo.artifactId );
 260  0
                 hit.setGroupId( artifactInfo.groupId );
 261  
                 // do we still need to set the repository id even though we're merging everything?
 262  
                 //hit.setRepositoryId( artifactInfo.repository );
 263  0
                 hit.setUrl( artifactInfo.repository + "/" + artifactInfo.fname );
 264  0
                 if( !hit.getVersions().contains( artifactInfo.version ) )
 265  
                 {
 266  0
                     hit.addVersion( artifactInfo.version );
 267  
                 }
 268  
             }
 269  
 
 270  0
             results.addHit( id, hit );
 271  0
         }
 272  
         
 273  0
         results.setTotalHits( results.getHitsMap().size() );
 274  0
         results.setLimits( limits );
 275  
         
 276  0
         if( limits == null || limits.getSelectedPage() == SearchResultLimits.ALL_PAGES )
 277  
         {   
 278  0
             return results;
 279  
         }
 280  
         else
 281  
         {
 282  0
             return paginate( results );            
 283  
         }        
 284  
     }
 285  
 
 286  
     private SearchResults paginate( SearchResults results )
 287  
     {
 288  0
         SearchResultLimits limits = results.getLimits();
 289  0
         SearchResults paginated = new SearchResults();  
 290  
         
 291  0
         int fetchCount = limits.getPageSize();
 292  0
         int offset = ( limits.getSelectedPage() * limits.getPageSize() );
 293  
         
 294  0
         if( fetchCount > results.getTotalHits() )
 295  
         {
 296  0
             fetchCount = results.getTotalHits();
 297  
         }
 298  
         
 299  
         // Goto offset.
 300  0
         if ( offset < results.getTotalHits() )
 301  
         {
 302  
             // only process if the offset is within the hit count.
 303  0
             for ( int i = 0; i < fetchCount; i++ )
 304  
             {
 305  
                 // Stop fetching if we are past the total # of available hits.
 306  0
                 if ( offset + i >= results.getHits().size() )
 307  
                 {
 308  0
                     break;
 309  
                 }
 310  
                 
 311  0
                 SearchResultHit hit = results.getHits().get( ( offset + i ) );
 312  0
                 if( hit != null )
 313  
                 {
 314  0
                     String id = SearchUtil.getHitId( hit.getGroupId(), hit.getArtifactId() );
 315  0
                     paginated.addHit( id, hit );
 316  
                 }
 317  
                 else
 318  
                 {
 319  
                     break;
 320  
                 }
 321  
             }
 322  
         }            
 323  0
         paginated.setTotalHits( results.getTotalHits() );
 324  0
         paginated.setLimits( limits );
 325  
         
 326  0
         return paginated;
 327  
     }
 328  
 }