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