]> source.dussan.org Git - archiva.git/blob
f9a65f572378cf6bdb1ab4211a933f73175f4c0d
[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 com.opensymphony.xwork2.Preparable;
23 import org.apache.archiva.indexer.search.RepositorySearch;
24 import org.apache.archiva.indexer.search.RepositorySearchException;
25 import org.apache.archiva.indexer.search.SearchFields;
26 import org.apache.archiva.indexer.search.SearchResultHit;
27 import org.apache.archiva.indexer.search.SearchResultLimits;
28 import org.apache.archiva.indexer.search.SearchResults;
29 import org.apache.archiva.metadata.model.ArtifactMetadata;
30 import org.apache.archiva.metadata.repository.MetadataRepository;
31 import org.apache.archiva.metadata.repository.RepositorySession;
32 import org.apache.commons.collections.CollectionUtils;
33 import org.apache.commons.lang.StringUtils;
34 import org.apache.maven.archiva.common.utils.VersionUtil;
35 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
36 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
37 import org.apache.struts2.ServletActionContext;
38 import org.springframework.context.annotation.Scope;
39 import org.springframework.stereotype.Controller;
40 import org.springframework.web.context.WebApplicationContext;
41 import org.springframework.web.context.support.WebApplicationContextUtils;
42
43 import javax.inject.Inject;
44 import java.net.MalformedURLException;
45 import java.util.ArrayList;
46 import java.util.LinkedHashMap;
47 import java.util.List;
48 import java.util.Map;
49
50 /**
51  * Search all indexed fields by the given criteria.
52  */
53 @Controller( "searchAction" )
54 @Scope( "prototype" )
55 public class SearchAction
56     extends AbstractRepositoryBasedAction
57     implements Preparable
58 {
59     /**
60      * Query string.
61      */
62
63     // FIXME olamy WTF here??
64     private ArchivaConfiguration archivaConfiguration;
65
66     private String q;
67
68     /**
69      * The Search Results.
70      */
71     private SearchResults results;
72
73     private static final String RESULTS = "results";
74
75     private static final String ARTIFACT = "artifact";
76
77     private List<ArtifactMetadata> databaseResults;
78
79     private int currentPage = 0;
80
81     private int totalPages;
82
83     private boolean searchResultsOnly;
84
85     private String completeQueryString;
86
87     private static final String COMPLETE_QUERY_STRING_SEPARATOR = ";";
88
89     private List<String> managedRepositoryList = new ArrayList<String>();
90
91     private String groupId;
92
93     private String artifactId;
94
95     private String version;
96
97     private String className;
98
99     private int rowCount = 30;
100
101     private String repositoryId;
102
103     private boolean fromFilterSearch;
104
105     private boolean filterSearch = false;
106
107     private boolean fromResultsPage;
108
109     @Inject
110     private RepositorySearch nexusSearch;
111
112     private Map<String, String> searchFields;
113
114     private String infoMessage;
115
116     public boolean isFromResultsPage()
117     {
118         return fromResultsPage;
119     }
120
121     public void setFromResultsPage( boolean fromResultsPage )
122     {
123         this.fromResultsPage = fromResultsPage;
124     }
125
126     public boolean isFromFilterSearch()
127     {
128         return fromFilterSearch;
129     }
130
131     public void setFromFilterSearch( boolean fromFilterSearch )
132     {
133         this.fromFilterSearch = fromFilterSearch;
134     }
135
136     public void prepare()
137     {
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 ) ) && ( artifactId == null || "".equals( artifactId ) )
172             && ( className == null || "".equals( className ) ) && ( version == null || "".equals( version ) ) )
173         {
174             addActionError( "Advanced Search - At least one search criteria must be provided." );
175             return INPUT;
176         }
177
178         fromFilterSearch = true;
179
180         if ( CollectionUtils.isEmpty( managedRepositoryList ) )
181         {
182             return GlobalResults.ACCESS_TO_NO_REPOS;
183         }
184
185         SearchResultLimits limits = new SearchResultLimits( currentPage );
186         limits.setPageSize( rowCount );
187         List<String> selectedRepos = new ArrayList<String>();
188
189         if ( repositoryId == null || StringUtils.isBlank( repositoryId ) || "all".equals(
190             StringUtils.stripToEmpty( repositoryId ) ) )
191         {
192             selectedRepos = getObservableRepos();
193         }
194         else
195         {
196             selectedRepos.add( repositoryId );
197         }
198
199         if ( CollectionUtils.isEmpty( selectedRepos ) )
200         {
201             return GlobalResults.ACCESS_TO_NO_REPOS;
202         }
203
204         SearchFields searchFields = new SearchFields( groupId, artifactId, version, null, className, selectedRepos );
205
206         log.debug( "filteredSearch with searchFields {}", searchFields );
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         log.debug( "quickSearch with selectedRepos {} query {}", selectedRepos, q );
267
268         try
269         {
270             if ( searchResultsOnly && !completeQueryString.equals( "" ) )
271             {
272                 results =
273                     getNexusSearch().search( getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString() );
274             }
275             else
276             {
277                 completeQueryString = "";
278                 results = getNexusSearch().search( getPrincipal(), selectedRepos, q, limits, null );
279             }
280         }
281         catch ( RepositorySearchException e )
282         {
283             addActionError( e.getMessage() );
284             return ERROR;
285         }
286
287         if ( results.isEmpty() )
288         {
289             addActionError( "No results found" );
290             return INPUT;
291         }
292
293         totalPages = results.getTotalHits() / limits.getPageSize();
294
295         if ( ( results.getTotalHits() % limits.getPageSize() ) != 0 )
296         {
297             totalPages = totalPages + 1;
298         }
299
300         if ( !isEqualToPreviousSearchTerm( q ) )
301         {
302             buildCompleteQueryString( q );
303         }
304
305         return SUCCESS;
306     }
307
308     public String findArtifact()
309         throws Exception
310     {
311         // TODO: give action message if indexing is in progress
312
313         if ( StringUtils.isBlank( q ) )
314         {
315             addActionError( "Unable to search for a blank checksum" );
316             return INPUT;
317         }
318
319         databaseResults = new ArrayList<ArtifactMetadata>();
320         RepositorySession repositorySession = repositorySessionFactory.createSession();
321         try
322         {
323             MetadataRepository metadataRepository = repositorySession.getRepository();
324             for ( String repoId : getObservableRepos() )
325             {
326                 databaseResults.addAll( metadataRepository.getArtifactsByChecksum( repoId, q ) );
327             }
328         }
329         finally
330         {
331             repositorySession.close();
332         }
333
334         if ( databaseResults.isEmpty() )
335         {
336             addActionError( "No results found" );
337             return INPUT;
338         }
339
340         if ( databaseResults.size() == 1 )
341         {
342             // 1 hit? return it's information directly!
343             return ARTIFACT;
344         }
345
346         return RESULTS;
347     }
348
349     public String doInput()
350     {
351         return INPUT;
352     }
353
354     private void buildCompleteQueryString( String searchTerm )
355     {
356         if ( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
357         {
358             searchTerm = StringUtils.remove( searchTerm, COMPLETE_QUERY_STRING_SEPARATOR );
359         }
360
361         if ( completeQueryString == null || "".equals( completeQueryString ) )
362         {
363             completeQueryString = searchTerm;
364         }
365         else
366         {
367             completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
368         }
369     }
370
371     private List<String> parseCompleteQueryString()
372     {
373         List<String> parsedCompleteQueryString = new ArrayList<String>();
374         String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
375         CollectionUtils.addAll( parsedCompleteQueryString, parsed );
376
377         return parsedCompleteQueryString;
378     }
379
380     private boolean isEqualToPreviousSearchTerm( String searchTerm )
381     {
382         if ( !"".equals( completeQueryString ) )
383         {
384             String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
385             if ( StringUtils.equalsIgnoreCase( searchTerm, parsed[parsed.length - 1] ) )
386             {
387                 return true;
388             }
389         }
390
391         return false;
392     }
393
394     public String getQ()
395     {
396         return q;
397     }
398
399     public void setQ( String q )
400     {
401         this.q = q;
402     }
403
404     public SearchResults getResults()
405     {
406         return results;
407     }
408
409     public List<ArtifactMetadata> getDatabaseResults()
410     {
411         return databaseResults;
412     }
413
414     public void setCurrentPage( int page )
415     {
416         this.currentPage = page;
417     }
418
419     public int getCurrentPage()
420     {
421         return currentPage;
422     }
423
424     public int getTotalPages()
425     {
426         return totalPages;
427     }
428
429     public void setTotalPages( int totalPages )
430     {
431         this.totalPages = totalPages;
432     }
433
434     public boolean isSearchResultsOnly()
435     {
436         return searchResultsOnly;
437     }
438
439     public void setSearchResultsOnly( boolean searchResultsOnly )
440     {
441         this.searchResultsOnly = searchResultsOnly;
442     }
443
444     public String getCompleteQueryString()
445     {
446         return completeQueryString;
447     }
448
449     public void setCompleteQueryString( String completeQueryString )
450     {
451         this.completeQueryString = completeQueryString;
452     }
453
454     public ArchivaConfiguration getArchivaConfiguration()
455     {
456         return archivaConfiguration;
457     }
458
459     public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
460     {
461         this.archivaConfiguration = archivaConfiguration;
462     }
463
464     public Map<String, ManagedRepositoryConfiguration> getManagedRepositories()
465     {
466         return getArchivaConfiguration().getConfiguration().getManagedRepositoriesAsMap();
467     }
468
469     public void setManagedRepositories( Map<String, ManagedRepositoryConfiguration> managedRepositories )
470     {
471     }
472
473     public String getGroupId()
474     {
475         return groupId;
476     }
477
478     public void setGroupId( String groupId )
479     {
480         this.groupId = groupId;
481     }
482
483     public String getArtifactId()
484     {
485         return artifactId;
486     }
487
488     public void setArtifactId( String artifactId )
489     {
490         this.artifactId = artifactId;
491     }
492
493     public String getVersion()
494     {
495         return version;
496     }
497
498     public void setVersion( String version )
499     {
500         this.version = version;
501     }
502
503     public int getRowCount()
504     {
505         return rowCount;
506     }
507
508     public void setRowCount( int rowCount )
509     {
510         this.rowCount = rowCount;
511     }
512
513     public boolean isFilterSearch()
514     {
515         return filterSearch;
516     }
517
518     public void setFilterSearch( boolean filterSearch )
519     {
520         this.filterSearch = filterSearch;
521     }
522
523     public String getRepositoryId()
524     {
525         return repositoryId;
526     }
527
528     public void setRepositoryId( String repositoryId )
529     {
530         this.repositoryId = repositoryId;
531     }
532
533     public List<String> getManagedRepositoryList()
534     {
535         return managedRepositoryList;
536     }
537
538     public void setManagedRepositoryList( List<String> managedRepositoryList )
539     {
540         this.managedRepositoryList = managedRepositoryList;
541     }
542
543     public String getClassName()
544     {
545         return className;
546     }
547
548     public void setClassName( String className )
549     {
550         this.className = className;
551     }
552
553     public RepositorySearch getNexusSearch()
554     {
555         if ( nexusSearch == null )
556         {
557             WebApplicationContext wac =
558                 WebApplicationContextUtils.getRequiredWebApplicationContext( ServletActionContext.getServletContext() );
559             nexusSearch = wac.getBean( "nexusSearch", RepositorySearch.class );
560         }
561         return nexusSearch;
562     }
563
564     public void setNexusSearch( RepositorySearch nexusSearch )
565     {
566         this.nexusSearch = nexusSearch;
567     }
568
569     public Map<String, String> getSearchFields()
570     {
571         return searchFields;
572     }
573
574     public void setSearchFields( Map<String, String> searchFields )
575     {
576         this.searchFields = searchFields;
577     }
578
579     public String getInfoMessage()
580     {
581         return infoMessage;
582     }
583
584     public void setInfoMessage( String infoMessage )
585     {
586         this.infoMessage = infoMessage;
587     }
588 }