]> source.dussan.org Git - archiva.git/blob
75ddecc1115952d4fe3772b020fc54206aff201a
[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         BooleanQuery q = new BooleanQuery();
75         if( previousSearchTerms == null || previousSearchTerms.isEmpty() )
76         {            
77             constructQuery( term, q );
78         }
79         else
80         {   
81             for( String previousTerm : previousSearchTerms )
82             {
83                 BooleanQuery iQuery = new BooleanQuery();
84                 constructQuery( previousTerm, iQuery );
85                 
86                 q.add( iQuery, Occur.MUST );
87             }
88             
89             BooleanQuery iQuery = new BooleanQuery();
90             constructQuery( term, iQuery );
91             q.add( iQuery, Occur.MUST );
92         }        
93                     
94         return search( limits, q );
95     }
96     
97     /**
98      * @see RepositorySearch#search(String, SearchFields, SearchResultLimits)
99      */
100     public SearchResults search( String principal, SearchFields searchFields, SearchResultLimits limits )
101         throws RepositorySearchException
102     {
103         if( searchFields.getRepositories() == null )
104         {
105             throw new RepositorySearchException( "Repositories cannot be null." );
106         }
107         
108         addIndexingContexts( searchFields.getRepositories() );
109         
110         BooleanQuery q = new BooleanQuery();
111         if( searchFields.getGroupId() != null && !"".equals( searchFields.getGroupId() ) )
112         {   
113             q.add( indexer.constructQuery( ArtifactInfo.GROUP_ID, searchFields.getGroupId() ), Occur.MUST );
114         }
115         
116         if( searchFields.getArtifactId() != null && !"".equals( searchFields.getArtifactId() ) )
117         {
118             q.add( indexer.constructQuery( ArtifactInfo.ARTIFACT_ID, searchFields.getArtifactId() ), Occur.MUST );
119         }
120         
121         if( searchFields.getVersion() != null && !"".equals( searchFields.getVersion() ) )
122         {
123             q.add( indexer.constructQuery( ArtifactInfo.VERSION, searchFields.getVersion() ), Occur.MUST );
124         }
125         
126         if( searchFields.getPackaging() != null && !"".equals( searchFields.getPackaging() ) )
127         {
128             q.add( indexer.constructQuery( ArtifactInfo.PACKAGING, searchFields.getPackaging() ), Occur.MUST );
129         }
130         
131         if( searchFields.getClassName() != null && !"".equals( searchFields.getClassName() ) )
132         {
133             q.add( indexer.constructQuery( ArtifactInfo.NAMES, searchFields.getClassName() ), Occur.MUST );
134         }
135         
136         if( q.getClauses() == null || q.getClauses().length <= 0 )
137         {
138             throw new RepositorySearchException( "No search fields set." );
139         }
140         
141         return search( limits, q );        
142     }
143
144     private SearchResults search( SearchResultLimits limits, BooleanQuery q )
145         throws RepositorySearchException
146     {
147         try
148         {
149             FlatSearchRequest request = new FlatSearchRequest( q );
150             FlatSearchResponse response = indexer.searchFlat( request );
151             
152             if( response == null || response.getTotalHits() == 0 )
153             {
154                 return new SearchResults();
155             }
156             
157             return convertToSearchResults( response, limits );
158         }
159         catch ( IndexContextInInconsistentStateException e )
160         {
161             throw new RepositorySearchException( e );
162         }
163         catch ( IOException e )
164         {
165             throw new RepositorySearchException( e );
166         }
167         finally
168         {
169             Map<String, IndexingContext> indexingContexts = indexer.getIndexingContexts();
170             Set<String> keys = indexingContexts.keySet();
171             for( String key : keys )
172             {
173                 try                
174                 {   
175                     indexer.removeIndexingContext( indexingContexts.get( key ), false );
176                     log.debug( "Indexing context '" + key + "' removed from search." );
177                 }
178                 catch ( IOException e )
179                 {
180                     log.warn( "IOException occurred while removing indexing content '" + key  + "'." );
181                     continue;
182                 }
183             }            
184         }
185     }
186
187     private void constructQuery( String term, BooleanQuery q )
188     {
189         q.add( indexer.constructQuery( ArtifactInfo.GROUP_ID, term ), Occur.SHOULD );
190         q.add( indexer.constructQuery( ArtifactInfo.ARTIFACT_ID, term ), Occur.SHOULD );
191         q.add( indexer.constructQuery( ArtifactInfo.VERSION, term ), Occur.SHOULD );
192         q.add( indexer.constructQuery( ArtifactInfo.PACKAGING, term ), Occur.SHOULD );
193         q.add( indexer.constructQuery( ArtifactInfo.NAMES, term ), Occur.SHOULD );        
194     }
195        
196     
197     private void addIndexingContexts( List<String> selectedRepos )
198     {
199         for( String repo : selectedRepos )
200         {
201             try
202             {
203                 Configuration config = archivaConfig.getConfiguration();
204                 ManagedRepositoryConfiguration repoConfig = config.findManagedRepositoryById( repo );
205                 
206                 if( repoConfig != null )
207                 {
208                     String indexDir = repoConfig.getIndexDir();
209                     File indexDirectory = null;
210                     if( indexDir != null && !"".equals( indexDir ) )
211                     {
212                         indexDirectory = new File( repoConfig.getIndexDir() );
213                     }
214                     else
215                     {
216                         indexDirectory = new File( repoConfig.getLocation(), ".indexer" );
217                     }
218                     
219                     IndexingContext context =
220                         indexer.addIndexingContext( repoConfig.getId(), repoConfig.getId(), new File( repoConfig.getLocation() ),
221                                                     indexDirectory, null, null, NexusIndexer.FULL_INDEX );
222                     context.setSearchable( repoConfig.isScanned() );
223                 }
224                 else
225                 {
226                     log.warn( "Repository '" + repo + "' not found in configuration." );
227                 }
228             }
229             catch ( UnsupportedExistingLuceneIndexException e )
230             {                
231                 log.warn( "Error accessing index of repository '" + repo + "' : " + e.getMessage() );
232                 continue;
233             }
234             catch ( IOException e )
235             {                
236                 log.warn( "IO error occured while accessing index of repository '" + repo + "' : " + e.getMessage() );
237                 continue;
238             }
239         }
240     }
241
242     private SearchResults convertToSearchResults( FlatSearchResponse response, SearchResultLimits limits )
243     {   
244         SearchResults results = new SearchResults();
245         Set<ArtifactInfo> artifactInfos = response.getResults();
246         
247         for ( ArtifactInfo artifactInfo : artifactInfos )
248         {
249             String id = SearchUtil.getHitId( artifactInfo.groupId, artifactInfo.artifactId );            
250             Map<String, SearchResultHit> hitsMap = results.getHitsMap();
251
252             SearchResultHit hit = hitsMap.get( id );
253             if ( hit != null )
254             {
255                 hit.addVersion( artifactInfo.version );
256             }
257             else
258             {
259                 hit = new SearchResultHit();
260                 hit.setArtifactId( artifactInfo.artifactId );
261                 hit.setGroupId( artifactInfo.groupId );
262                 // do we still need to set the repository id even though we're merging everything?
263                 //hit.setRepositoryId( artifactInfo.repository );
264                 hit.setUrl( artifactInfo.repository + "/" + artifactInfo.fname );
265                 if( !hit.getVersions().contains( artifactInfo.version ) )
266                 {
267                     hit.addVersion( artifactInfo.version );
268                 }
269             }
270
271             results.addHit( id, hit );
272         }
273         
274         results.setTotalHits( results.getHitsMap().size() );
275         
276         if( limits == null || limits.getSelectedPage() == SearchResultLimits.ALL_PAGES )
277         {   
278             return results;
279         }
280         else
281         {
282             return paginate( limits, results );            
283         }        
284     }
285
286     private SearchResults paginate( SearchResultLimits limits, SearchResults results )
287     {
288         SearchResults paginated = new SearchResults();        
289         int fetchCount = limits.getPageSize();
290         int offset = ( limits.getSelectedPage() * limits.getPageSize() );
291         
292         if( fetchCount > results.getTotalHits() )
293         {
294             fetchCount = results.getTotalHits();
295         }
296         
297         // Goto offset.
298         if ( offset < results.getTotalHits() )
299         {
300             // only process if the offset is within the hit count.
301             for ( int i = 0; i < fetchCount; i++ )
302             {
303                 // Stop fetching if we are past the total # of available hits.
304                 if ( offset + i >= results.getHits().size() )
305                 {
306                     break;
307                 }
308                 
309                 SearchResultHit hit = results.getHits().get( ( offset + i ) );
310                 if( hit != null )
311                 {
312                     String id = SearchUtil.getHitId( hit.getGroupId(), hit.getArtifactId() );
313                     paginated.addHit( id, hit );
314                 }
315                 else
316                 {
317                     break;
318                 }
319             }
320         }            
321         paginated.setTotalHits( results.getTotalHits() );
322         
323         return paginated;
324     }
325
326 }