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