]> source.dussan.org Git - archiva.git/blob
3c8f5a577cbc51b7390ef86dae653c6515970c86
[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.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.IndexingContext;
41 import org.sonatype.nexus.index.context.UnsupportedExistingLuceneIndexException;
42
43 /**
44  * RepositorySearch implementation which uses the Nexus Indexer for searching.
45  */
46 public class NexusRepositorySearch
47     implements RepositorySearch
48 {
49     private static final Logger log = LoggerFactory.getLogger( NexusRepositorySearch.class ); 
50                                                               
51     private NexusIndexer indexer;
52     
53     private ArchivaConfiguration archivaConfig;
54     
55     public NexusRepositorySearch( NexusIndexer indexer, ArchivaConfiguration archivaConfig )
56     {
57         this.indexer = indexer;
58         this.archivaConfig = archivaConfig;
59     }
60
61     /**
62      * @see RepositorySearch#search(String, List, String, SearchResultLimits, List)
63      */
64     public SearchResults search( String principal, List<String> selectedRepos, String term, SearchResultLimits limits,
65                                  List<String> previousSearchTerms )
66         throws RepositorySearchException
67     {   
68         addIndexingContexts( selectedRepos );
69         
70         // since upgrade to nexus 2.0.0, query has changed from g:[QUERIED TERM]* to g:*[QUERIED TERM]*
71         //      resulting to more wildcard searches so we need to increase max clause count
72         BooleanQuery.setMaxClauseCount( Integer.MAX_VALUE );
73         BooleanQuery q = new BooleanQuery();
74         
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                 SearchResults results = new SearchResults();
155                 results.setLimits( limits );
156                 return results;
157             }
158             
159             return convertToSearchResults( response, limits );
160         }
161         catch ( IOException e )
162         {
163             throw new RepositorySearchException( e );
164         }
165         finally
166         {
167             Map<String, IndexingContext> indexingContexts = indexer.getIndexingContexts();
168             Set<String> keys = indexingContexts.keySet();
169             for( String key : keys )
170             {
171                 try                
172                 {   
173                     indexer.removeIndexingContext( indexingContexts.get( key ), false );
174                     log.debug( "Indexing context '" + key + "' removed from search." );
175                 }
176                 catch ( IOException e )
177                 {
178                     log.warn( "IOException occurred while removing indexing content '" + key  + "'." );
179                     continue;
180                 }
181             }            
182         }
183     }
184
185     private void constructQuery( String term, BooleanQuery q )
186     {
187         q.add( indexer.constructQuery( ArtifactInfo.GROUP_ID, term ), Occur.SHOULD );
188         q.add( indexer.constructQuery( ArtifactInfo.ARTIFACT_ID, term ), Occur.SHOULD );
189         q.add( indexer.constructQuery( ArtifactInfo.VERSION, term ), Occur.SHOULD );
190         q.add( indexer.constructQuery( ArtifactInfo.PACKAGING, term ), Occur.SHOULD );
191         q.add( indexer.constructQuery( ArtifactInfo.NAMES, term ), Occur.SHOULD );        
192     }
193        
194     
195     private void addIndexingContexts( List<String> selectedRepos )
196     {
197         for( String repo : selectedRepos )
198         {
199             try
200             {
201                 Configuration config = archivaConfig.getConfiguration();
202                 ManagedRepositoryConfiguration repoConfig = config.findManagedRepositoryById( repo );
203                 
204                 if( repoConfig != null )
205                 {
206                     String indexDir = repoConfig.getIndexDir();
207                     File indexDirectory = null;
208                     if( indexDir != null && !"".equals( indexDir ) )
209                     {
210                         indexDirectory = new File( repoConfig.getIndexDir() );
211                     }
212                     else
213                     {
214                         indexDirectory = new File( repoConfig.getLocation(), ".indexer" );
215                     }
216                     
217                     IndexingContext context =
218                         indexer.addIndexingContext( repoConfig.getId(), repoConfig.getId(), new File( repoConfig.getLocation() ),
219                                                     indexDirectory, null, null, NexusIndexer.FULL_INDEX );
220                     context.setSearchable( repoConfig.isScanned() );
221                 }
222                 else
223                 {
224                     log.warn( "Repository '" + repo + "' not found in configuration." );
225                 }
226             }
227             catch ( UnsupportedExistingLuceneIndexException e )
228             {                
229                 log.warn( "Error accessing index of repository '" + repo + "' : " + e.getMessage() );
230                 continue;
231             }
232             catch ( IOException e )
233             {                
234                 log.warn( "IO error occured while accessing index of repository '" + repo + "' : " + e.getMessage() );
235                 continue;
236             }
237         }
238     }
239
240     private SearchResults convertToSearchResults( FlatSearchResponse response, SearchResultLimits limits )
241     {   
242         SearchResults results = new SearchResults();
243         Set<ArtifactInfo> artifactInfos = response.getResults();
244         
245         for ( ArtifactInfo artifactInfo : artifactInfos )
246         {
247             String id = SearchUtil.getHitId( artifactInfo.groupId, artifactInfo.artifactId );
248             Map<String, SearchResultHit> hitsMap = results.getHitsMap();
249
250             SearchResultHit hit = hitsMap.get( id );
251             if ( hit != null )
252             {
253                 hit.addVersion( artifactInfo.version );
254             }
255             else
256             {
257                 hit = new SearchResultHit();
258                 hit.setArtifactId( artifactInfo.artifactId );
259                 hit.setGroupId( artifactInfo.groupId );
260                 // do we still need to set the repository id even though we're merging everything?
261                 //hit.setRepositoryId( artifactInfo.repository );
262                 hit.setUrl( artifactInfo.repository + "/" + artifactInfo.fname );
263                 if( !hit.getVersions().contains( artifactInfo.version ) )
264                 {
265                     hit.addVersion( artifactInfo.version );
266                 }
267             }
268
269             results.addHit( id, hit );
270         }
271         
272         results.setTotalHits( results.getHitsMap().size() );
273         results.setLimits( limits );
274         
275         if( limits == null || limits.getSelectedPage() == SearchResultLimits.ALL_PAGES )
276         {   
277             return results;
278         }
279         else
280         {
281             return paginate( results );            
282         }        
283     }
284
285     private SearchResults paginate( SearchResults results )
286     {
287         SearchResultLimits limits = results.getLimits();
288         SearchResults paginated = new SearchResults();  
289         
290         int fetchCount = limits.getPageSize();
291         int offset = ( limits.getSelectedPage() * limits.getPageSize() );
292         
293         if( fetchCount > results.getTotalHits() )
294         {
295             fetchCount = results.getTotalHits();
296         }
297         
298         // Goto offset.
299         if ( offset < results.getTotalHits() )
300         {
301             // only process if the offset is within the hit count.
302             for ( int i = 0; i < fetchCount; i++ )
303             {
304                 // Stop fetching if we are past the total # of available hits.
305                 if ( offset + i >= results.getHits().size() )
306                 {
307                     break;
308                 }
309                 
310                 SearchResultHit hit = results.getHits().get( ( offset + i ) );
311                 if( hit != null )
312                 {
313                     String id = SearchUtil.getHitId( hit.getGroupId(), hit.getArtifactId() );
314                     paginated.addHit( id, hit );
315                 }
316                 else
317                 {
318                     break;
319                 }
320             }
321         }            
322         paginated.setTotalHits( results.getTotalHits() );
323         paginated.setLimits( limits );
324         
325         return paginated;
326     }
327 }