]> source.dussan.org Git - archiva.git/blob
b8da4fa536034d0f83434e27f9b4ed0eabb2abbb
[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.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27
28 import com.opensymphony.xwork2.Preparable;
29 import org.apache.archiva.indexer.search.RepositorySearch;
30 import org.apache.archiva.indexer.search.RepositorySearchException;
31 import org.apache.archiva.indexer.search.SearchFields;
32 import org.apache.archiva.indexer.search.SearchResultHit;
33 import org.apache.archiva.indexer.search.SearchResultLimits;
34 import org.apache.archiva.indexer.search.SearchResults;
35 import org.apache.archiva.metadata.model.ArtifactMetadata;
36 import org.apache.archiva.metadata.repository.MetadataRepository;
37 import org.apache.commons.collections.CollectionUtils;
38 import org.apache.commons.lang.StringUtils;
39 import org.apache.maven.archiva.common.utils.VersionUtil;
40 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
41 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
42 import org.apache.struts2.ServletActionContext;
43 import org.springframework.web.context.WebApplicationContext;
44 import org.springframework.web.context.support.WebApplicationContextUtils;
45
46 /**
47  * Search all indexed fields by the given criteria.
48  *
49  * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="searchAction" instantiation-strategy="per-lookup"
50  */
51 public class SearchAction 
52     extends AbstractRepositoryBasedAction
53     implements Preparable
54 {
55     /**
56      * Query string.
57      */
58
59     private ArchivaConfiguration archivaConfiguration;
60
61     private String q;
62
63     /**
64      * The Search Results.
65      */
66     private SearchResults results;
67
68     private static final String RESULTS = "results";
69
70     private static final String ARTIFACT = "artifact";
71
72     private List<ArtifactMetadata> databaseResults;
73     
74     private int currentPage = 0;
75     
76     private int totalPages;
77     
78     private boolean searchResultsOnly;
79     
80     private String completeQueryString;
81     
82     private static final String COMPLETE_QUERY_STRING_SEPARATOR = ";";
83
84     private List<String> managedRepositoryList;
85
86     private String groupId;
87
88     private String artifactId;
89
90     private String version;
91
92     private String className;
93
94     private int rowCount = 30;
95
96     private String repositoryId;
97
98     private boolean fromFilterSearch;
99
100     private boolean filterSearch = false;
101
102     private boolean fromResultsPage;
103
104     private RepositorySearch nexusSearch;
105     
106     private Map<String, String> searchFields;
107
108     private String infoMessage;
109
110     /**
111      * @plexus.requirement
112      */
113     private MetadataRepository metadataRepository;
114
115     public boolean isFromResultsPage()
116     {
117         return fromResultsPage;
118     }
119
120     public void setFromResultsPage( boolean fromResultsPage )
121     {
122         this.fromResultsPage = fromResultsPage;
123     }
124
125     public boolean isFromFilterSearch()
126     {
127         return fromFilterSearch;
128     }
129
130     public void setFromFilterSearch( boolean fromFilterSearch )
131     {
132         this.fromFilterSearch = fromFilterSearch;
133     }
134
135     public void prepare()
136     {
137         managedRepositoryList = new ArrayList<String>();
138         managedRepositoryList = getObservableRepos();
139
140         if ( managedRepositoryList.size() > 0 )
141         {
142             managedRepositoryList.add( "all" );
143         }
144         
145         searchFields = new LinkedHashMap<String, String>();
146         searchFields.put( "groupId", "Group ID" );
147         searchFields.put( "artifactId", "Artifact ID" );
148         searchFields.put( "version", "Version" );
149         searchFields.put( "className", "Class/Package Name" ); 
150         searchFields.put( "rowCount", "Row Count" );
151         
152         super.clearErrorsAndMessages();       
153         clearSearchFields();
154     }
155     
156     private void clearSearchFields()
157     {
158         repositoryId = "";
159         artifactId = "";
160         groupId = "";
161         version = "";
162         className = "";     
163         rowCount = 30;
164         currentPage = 0;
165     }
166
167     // advanced search MRM-90 -- filtered search
168     public String filteredSearch()
169         throws MalformedURLException
170     {           
171         if ( ( groupId == null || "".equals( groupId ) ) &&
172             ( artifactId == null || "".equals( artifactId ) ) && ( className == null || "".equals( className ) ) &&
173             ( version == null || "".equals( version ) ) )
174         {   
175             addActionError( "Advanced Search - At least one search criteria must be provided." );
176             return INPUT;
177         }
178         
179         fromFilterSearch = true;
180         
181         if ( CollectionUtils.isEmpty( managedRepositoryList ) )
182         {            
183             return GlobalResults.ACCESS_TO_NO_REPOS;
184         }
185
186         SearchResultLimits limits = new SearchResultLimits( currentPage );
187         limits.setPageSize( rowCount );
188         List<String> selectedRepos = new ArrayList<String>();
189         
190         if ( repositoryId == null || StringUtils.isBlank( repositoryId ) ||
191             "all".equals( StringUtils.stripToEmpty( repositoryId ) ) )
192         {
193             selectedRepos = getObservableRepos();
194         }
195         else
196         {
197             selectedRepos.add( repositoryId );
198         }        
199
200         if ( CollectionUtils.isEmpty( selectedRepos ) )
201         {         
202             return GlobalResults.ACCESS_TO_NO_REPOS;
203         }
204
205         SearchFields searchFields =
206             new SearchFields( groupId, artifactId, version, null, className, selectedRepos );
207                 
208         // TODO: add packaging in the list of fields for advanced search (UI)?
209         try
210         {
211             results = getNexusSearch().search( getPrincipal(), searchFields, limits );
212         }
213         catch ( RepositorySearchException e )
214         {
215             addActionError( e.getMessage() );
216             return ERROR;
217         }
218         
219         if ( results.isEmpty() )
220         {
221             addActionError( "No results found" );
222             return INPUT;
223         }
224
225         totalPages = results.getTotalHits() / limits.getPageSize();
226
227         if ( ( results.getTotalHits() % limits.getPageSize() ) != 0 )
228         {
229             totalPages = totalPages + 1;
230         }
231
232         for (SearchResultHit hit : results.getHits())
233         {
234             final String version = hit.getVersion();
235             if (version != null)
236             {
237                 hit.setVersion(VersionUtil.getBaseVersion(version));
238             }
239         }
240
241         return SUCCESS;
242     }
243
244     @SuppressWarnings("unchecked")
245     public String quickSearch()
246         throws MalformedURLException
247     {
248         /* TODO: give action message if indexing is in progress.
249          * This should be based off a count of 'unprocessed' artifacts.
250          * This (yet to be written) routine could tell the user that X (unprocessed) artifacts are not yet
251          * present in the full text search.
252          */
253
254         assert q != null && q.length() != 0;
255
256         fromFilterSearch = false;
257
258         SearchResultLimits limits = new SearchResultLimits( currentPage );
259
260         List<String> selectedRepos = getObservableRepos();
261         if ( CollectionUtils.isEmpty( selectedRepos ) )
262         {
263             return GlobalResults.ACCESS_TO_NO_REPOS;
264         }
265
266         try
267         {
268             if( searchResultsOnly && !completeQueryString.equals( "" ) )
269             {                       
270                 results = getNexusSearch().search( getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString() );                   
271             }
272             else
273             {
274                 completeQueryString = "";                    
275                 results = getNexusSearch().search( getPrincipal(), selectedRepos, q, limits, null );                    
276             }
277         }
278         catch ( RepositorySearchException e )
279         {
280             addActionError( e.getMessage() );
281             return ERROR;
282         }
283
284         if ( results.isEmpty() )
285         {
286             addActionError( "No results found" );
287             return INPUT;
288         }
289
290         totalPages = results.getTotalHits() / limits.getPageSize();
291
292         if( (results.getTotalHits() % limits.getPageSize()) != 0 )
293         {
294             totalPages = totalPages + 1;
295         }
296
297         if( !isEqualToPreviousSearchTerm( q ) )
298         {
299             buildCompleteQueryString( q );
300         }
301        
302         return SUCCESS;
303     }
304
305     public String findArtifact()
306         throws Exception
307     {
308         // TODO: give action message if indexing is in progress
309
310         if ( StringUtils.isBlank( q ) )
311         {
312             addActionError( "Unable to search for a blank checksum" );
313             return INPUT;
314         }
315
316         databaseResults = new ArrayList<ArtifactMetadata>();
317         for ( String repoId : getObservableRepos() )
318         {
319             databaseResults.addAll( metadataRepository.getArtifactsByChecksum( repoId, q ) );
320         }
321
322         if ( databaseResults.isEmpty() )
323         {
324             addActionError( "No results found" );
325             return INPUT;
326         }
327
328         if ( databaseResults.size() == 1 )
329         {
330             // 1 hit? return it's information directly!
331             return ARTIFACT;
332         }
333
334         return RESULTS;
335     }
336     
337     public String doInput()
338     {
339         return INPUT;
340     }
341
342     private void buildCompleteQueryString( String searchTerm )
343     {
344         if ( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
345         {
346             searchTerm = StringUtils.remove( searchTerm, COMPLETE_QUERY_STRING_SEPARATOR );
347         }
348
349         if ( completeQueryString == null || "".equals( completeQueryString ) )
350         {
351             completeQueryString = searchTerm;
352         }
353         else
354         {
355             completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
356         }
357     }
358
359     private List<String> parseCompleteQueryString()
360     {
361         List<String> parsedCompleteQueryString = new ArrayList<String>();
362         String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
363         CollectionUtils.addAll( parsedCompleteQueryString, parsed );
364
365         return parsedCompleteQueryString;
366     }
367
368     private boolean isEqualToPreviousSearchTerm( String searchTerm )
369     {
370         if ( !"".equals( completeQueryString ) )
371         {
372             String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
373             if ( StringUtils.equalsIgnoreCase( searchTerm, parsed[parsed.length - 1] ) )
374             {
375                 return true;
376             }
377         }
378
379         return false;
380     }
381
382     public String getQ()
383     {
384         return q;
385     }
386
387     public void setQ( String q )
388     {
389         this.q = q;
390     }
391
392     public SearchResults getResults()
393     {
394         return results;
395     }
396
397     public List<ArtifactMetadata> getDatabaseResults()
398     {
399         return databaseResults;
400     }
401
402     public void setCurrentPage( int page )
403     {
404         this.currentPage = page;
405     }
406
407     public int getCurrentPage()
408     {
409         return currentPage;
410     }
411
412     public int getTotalPages()
413     {
414         return totalPages;
415     }
416
417     public void setTotalPages( int totalPages )
418     {
419         this.totalPages = totalPages;
420     }
421
422     public boolean isSearchResultsOnly()
423     {
424         return searchResultsOnly;
425     }
426
427     public void setSearchResultsOnly( boolean searchResultsOnly )
428     {
429         this.searchResultsOnly = searchResultsOnly;
430     }
431
432     public String getCompleteQueryString()
433     {
434         return completeQueryString;
435     }
436
437     public void setCompleteQueryString( String completeQueryString )
438     {
439         this.completeQueryString = completeQueryString;
440     }
441
442     public ArchivaConfiguration getArchivaConfiguration()
443     {
444         return archivaConfiguration;
445     }
446
447     public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
448     {
449         this.archivaConfiguration = archivaConfiguration;
450     }
451
452     public Map<String, ManagedRepositoryConfiguration> getManagedRepositories()
453     {
454         return getArchivaConfiguration().getConfiguration().getManagedRepositoriesAsMap();
455     }
456
457     public void setManagedRepositories( Map<String, ManagedRepositoryConfiguration> managedRepositories )
458     {
459     }
460
461     public String getGroupId()
462     {
463         return groupId;
464     }
465
466     public void setGroupId( String groupId )
467     {
468         this.groupId = groupId;
469     }
470
471     public String getArtifactId()
472     {
473         return artifactId;
474     }
475
476     public void setArtifactId( String artifactId )
477     {
478         this.artifactId = artifactId;
479     }
480
481     public String getVersion()
482     {
483         return version;
484     }
485
486     public void setVersion( String version )
487     {
488         this.version = version;
489     }
490
491     public int getRowCount()
492     {
493         return rowCount;
494     }
495
496     public void setRowCount( int rowCount )
497     {
498         this.rowCount = rowCount;
499     }
500
501     public boolean isFilterSearch()
502     {
503         return filterSearch;
504     }
505
506     public void setFilterSearch( boolean filterSearch )
507     {
508         this.filterSearch = filterSearch;
509     }
510
511     public String getRepositoryId()
512     {
513         return repositoryId;
514     }
515
516     public void setRepositoryId( String repositoryId )
517     {
518         this.repositoryId = repositoryId;
519     }
520
521     public List<String> getManagedRepositoryList()
522     {
523         return managedRepositoryList;
524     }
525
526     public void setManagedRepositoryList( List<String> managedRepositoryList )
527     {
528         this.managedRepositoryList = managedRepositoryList;
529     }
530
531     public String getClassName()
532     {
533         return className;
534     }
535
536     public void setClassName( String className )
537     {
538         this.className = className;
539     }
540
541     public RepositorySearch getNexusSearch()
542     {
543         // no need to do this when wiring is already in spring
544         if( nexusSearch == null )
545         {
546             WebApplicationContext wac =
547                 WebApplicationContextUtils.getRequiredWebApplicationContext( ServletActionContext.getServletContext() );
548             nexusSearch = ( RepositorySearch ) wac.getBean( "nexusSearch" );
549         }
550         return nexusSearch;
551     }
552
553     public void setNexusSearch( RepositorySearch nexusSearch )
554     {
555         this.nexusSearch = nexusSearch;
556     }
557
558     public Map<String, String> getSearchFields()
559     {
560         return searchFields;
561     }
562
563     public void setSearchFields( Map<String, String> searchFields )
564     {
565         this.searchFields = searchFields;
566     }
567     
568     public String getInfoMessage()
569     {
570         return infoMessage;
571     }
572
573     public void setInfoMessage( String infoMessage )
574     {
575         this.infoMessage = infoMessage;
576     }
577
578     public void setMetadataRepository( MetadataRepository metadataRepository )
579     {
580         this.metadataRepository = metadataRepository;
581     }
582 }