]> source.dussan.org Git - archiva.git/blob
92b203c847e0ef1863e7497c7767f2e0aedc7666
[archiva.git] /
1 package org.apache.maven.archiva.web.action;
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.net.MalformedURLException;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
26
27 import com.opensymphony.xwork.ActionContext;
28 import org.apache.commons.collections.CollectionUtils;
29 import org.apache.commons.lang.StringUtils;
30 import org.apache.maven.archiva.database.ArchivaDAO;
31 import org.apache.maven.archiva.database.Constraint;
32 import org.apache.maven.archiva.database.constraints.ArtifactsByChecksumConstraint;
33 import org.apache.maven.archiva.indexer.RepositoryIndexException;
34 import org.apache.maven.archiva.indexer.RepositoryIndexSearchException;
35 import org.apache.maven.archiva.indexer.search.CrossRepositorySearch;
36 import org.apache.maven.archiva.indexer.search.SearchResultLimits;
37 import org.apache.maven.archiva.indexer.search.SearchResults;
38 import org.apache.maven.archiva.security.AccessDeniedException;
39 import org.apache.maven.archiva.security.ArchivaSecurityException;
40 import org.apache.maven.archiva.security.ArchivaXworkUser;
41 import org.apache.maven.archiva.security.PrincipalNotFoundException;
42 import org.apache.maven.archiva.security.UserRepositories;
43 import org.codehaus.plexus.xwork.action.PlexusActionSupport;
44
45 /**
46  * Search all indexed fields by the given criteria.
47  *
48  * @plexus.component role="com.opensymphony.xwork.Action" role-hint="searchAction"
49  */
50 public class SearchAction
51     extends PlexusActionSupport
52 {           
53     /**
54      * Query string.
55      */
56     private String q;
57
58     /**
59      * @plexus.requirement role-hint="jdo"
60      */
61     private ArchivaDAO dao;
62
63     /**
64      * The Search Results.
65      */
66     private SearchResults results;
67
68     /**
69      * @plexus.requirement role-hint="default"
70      */
71     private CrossRepositorySearch crossRepoSearch;
72     
73     /**
74      * @plexus.requirement
75      */
76     private UserRepositories userRepositories;
77     
78     private static final String RESULTS = "results";
79
80     private static final String ARTIFACT = "artifact";
81
82     private List databaseResults;
83     
84     private int currentPage = 0;
85     
86     private int totalPages;
87     
88     private boolean searchResultsOnly; 
89     
90     private String completeQueryString;
91     
92     private static final String COMPLETE_QUERY_STRING_SEPARATOR = ";";
93
94     public String quickSearch()
95         throws MalformedURLException, RepositoryIndexException, RepositoryIndexSearchException
96     {
97         /* TODO: give action message if indexing is in progress.
98          * This should be based off a count of 'unprocessed' artifacts.
99          * This (yet to be written) routine could tell the user that X (unprocessed) artifacts are not yet 
100          * present in the full text search.
101          */
102
103         assert q != null && q.length() != 0;
104         
105         SearchResultLimits limits = new SearchResultLimits( currentPage );
106         
107         List<String> selectedRepos = getObservableRepos();
108         if ( CollectionUtils.isEmpty( selectedRepos ) )
109         {
110             return GlobalResults.ACCESS_TO_NO_REPOS;
111         }
112
113         if( searchResultsOnly && !completeQueryString.equals( "" ) )
114         { 
115             results = crossRepoSearch.searchForTerm( getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString() );
116         }
117         else
118         {
119             completeQueryString = "";
120             results = crossRepoSearch.searchForTerm( getPrincipal(), selectedRepos, q, limits );
121         }
122         
123         if ( results.isEmpty() )
124         {
125             addActionError( "No results found" );
126             return INPUT;
127         }
128         
129         totalPages = results.getTotalHits() / limits.getPageSize();
130         
131         if( (results.getTotalHits() % limits.getPageSize()) != 0 )
132         {
133             totalPages = totalPages + 1;
134         }
135         // TODO: filter / combine the artifacts by version? (is that even possible with non-artifact hits?)
136
137         /* I don't think that we should, as I expect us to utilize the 'score' system in lucene in 
138          * the future to return relevant links better.
139          * I expect the lucene scoring system to take multiple hits on different areas of a single document
140          * to result in a higher score. 
141          *   - Joakim
142          */
143         
144         if( !isEqualToPreviousSearchTerm( q ) )
145         {
146             buildCompleteQueryString( q );
147         }
148         
149         return SUCCESS;
150     }
151
152     public String findArtifact()
153         throws Exception
154     {
155         // TODO: give action message if indexing is in progress
156
157         if ( StringUtils.isBlank( q ) )
158         {
159             addActionError( "Unable to search for a blank checksum" );
160             return INPUT;
161         }
162
163         Constraint constraint = new ArtifactsByChecksumConstraint( q );
164         databaseResults = dao.getArtifactDAO().queryArtifacts( constraint );
165
166         if ( databaseResults.isEmpty() )
167         {
168             addActionError( "No results found" );
169             return INPUT;
170         }
171
172         if ( databaseResults.size() == 1 )
173         {
174             // 1 hit? return it's information directly!            
175             return ARTIFACT;
176         }
177         
178         return RESULTS;
179     }
180
181     @Override
182     public String doInput()
183     {
184         return INPUT;
185     }
186     
187     private String getPrincipal()
188     {
189         return ArchivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
190     }
191     
192     private List<String> getObservableRepos()
193     {
194         try
195         {
196             return userRepositories.getObservableRepositoryIds( getPrincipal() );
197         }
198         catch ( PrincipalNotFoundException e )
199         {
200             getLogger().warn( e.getMessage(), e );
201         }
202         catch ( AccessDeniedException e )
203         {
204             getLogger().warn( e.getMessage(), e );
205             // TODO: pass this onto the screen.
206         }
207         catch ( ArchivaSecurityException e )
208         {
209             getLogger().warn( e.getMessage(), e );
210         }
211         return Collections.emptyList();
212     }
213
214     private void buildCompleteQueryString( String searchTerm )
215     {
216         if( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
217         {
218             searchTerm = StringUtils.remove( searchTerm, COMPLETE_QUERY_STRING_SEPARATOR );
219         }
220         
221         if( completeQueryString == null || "".equals( completeQueryString ) )
222         {
223             completeQueryString = searchTerm;
224         }
225         else
226         {            
227             completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
228         }
229     }
230     
231     private List<String> parseCompleteQueryString()
232     {
233         List<String> parsedCompleteQueryString = new ArrayList<String>();        
234         String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
235         CollectionUtils.addAll( parsedCompleteQueryString, parsed );
236         
237         return parsedCompleteQueryString;
238     }
239     
240     private boolean isEqualToPreviousSearchTerm( String searchTerm )
241     {
242         if( !"".equals( completeQueryString ) )
243         {
244             String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
245             if( StringUtils.equalsIgnoreCase( searchTerm, parsed[ parsed.length - 1 ] ) )
246             {
247                 return true;
248             }
249         }
250         
251         return false;
252     }
253     
254     public String getQ()
255     {
256         return q;
257     }
258
259     public void setQ( String q )
260     {
261         this.q = q;
262     }
263
264     public SearchResults getResults()
265     {
266         return results;
267     }
268
269     public List getDatabaseResults()
270     {
271         return databaseResults;
272     }
273     
274     public void setCurrentPage( int page )
275     {
276         this.currentPage = page;
277     }
278     
279     public int getCurrentPage()
280     {
281         return currentPage;
282     }
283
284     public int getTotalPages()
285     {
286         return totalPages;
287     }
288
289     public void setTotalPages( int totalPages )
290     {
291         this.totalPages = totalPages;
292     }
293
294     public boolean isSearchResultsOnly()
295     {
296         return searchResultsOnly;
297     }
298
299     public void setSearchResultsOnly( boolean searchResultsOnly )
300     {
301         this.searchResultsOnly = searchResultsOnly;
302     }
303
304     public String getCompleteQueryString()
305     {
306         return completeQueryString;
307     }
308
309     public void setCompleteQueryString( String completeQueryString )
310     {
311         this.completeQueryString = completeQueryString;
312     }    
313 }