]> source.dussan.org Git - archiva.git/blob
fd9dfc8b56d740a688fbce99719379502cc13191
[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     private String q;
63
64     // FIXME olamy WTF here??
65     private ArchivaConfiguration archivaConfiguration;
66
67     /**
68      * The Search Results.
69      */
70     private SearchResults results;
71
72     private static final String RESULTS = "results";
73
74     private static final String ARTIFACT = "artifact";
75
76     private List<ArtifactMetadata> databaseResults;
77
78     private int currentPage = 0;
79
80     private int totalPages;
81
82     private boolean searchResultsOnly;
83
84     private String completeQueryString;
85
86     private static final String COMPLETE_QUERY_STRING_SEPARATOR = ";";
87
88     private List<String> managedRepositoryList = new ArrayList<String>();
89
90     private String groupId;
91
92     private String artifactId;
93
94     private String version;
95
96     private String className;
97
98     private int rowCount = 30;
99
100     private String repositoryId;
101
102     private boolean fromFilterSearch;
103
104     private boolean filterSearch = false;
105
106     private boolean fromResultsPage;
107
108     @Inject
109     private RepositorySearch nexusSearch;
110
111     private Map<String, String> searchFields;
112
113     private String infoMessage;
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 = getObservableRepos();
138
139         if ( managedRepositoryList.size() > 0 )
140         {
141             managedRepositoryList.add( "all" );
142         }
143
144         searchFields = new LinkedHashMap<String, String>();
145         searchFields.put( "groupId", "Group ID" );
146         searchFields.put( "artifactId", "Artifact ID" );
147         searchFields.put( "version", "Version" );
148         searchFields.put( "className", "Class/Package Name" );
149         searchFields.put( "rowCount", "Row Count" );
150
151         super.clearErrorsAndMessages();
152         clearSearchFields();
153     }
154
155     private void clearSearchFields()
156     {
157         repositoryId = "";
158         artifactId = "";
159         groupId = "";
160         version = "";
161         className = "";
162         rowCount = 30;
163         currentPage = 0;
164     }
165
166     // advanced search MRM-90 -- filtered search
167     public String filteredSearch()
168         throws MalformedURLException
169     {
170         if ( ( groupId == null || "".equals( groupId ) ) && ( artifactId == null || "".equals( artifactId ) )
171             && ( className == null || "".equals( className ) ) && ( version == null || "".equals( version ) ) )
172         {
173             addActionError( "Advanced Search - At least one search criteria must be provided." );
174             return INPUT;
175         }
176
177         fromFilterSearch = true;
178
179         if ( CollectionUtils.isEmpty( managedRepositoryList ) )
180         {
181             return GlobalResults.ACCESS_TO_NO_REPOS;
182         }
183
184         SearchResultLimits limits = new SearchResultLimits( currentPage );
185         limits.setPageSize( rowCount );
186         List<String> selectedRepos = new ArrayList<String>();
187
188         if ( repositoryId == null || StringUtils.isBlank( repositoryId ) || "all".equals(
189             StringUtils.stripToEmpty( repositoryId ) ) )
190         {
191             selectedRepos = getObservableRepos();
192         }
193         else
194         {
195             selectedRepos.add( repositoryId );
196         }
197
198         if ( CollectionUtils.isEmpty( selectedRepos ) )
199         {
200             return GlobalResults.ACCESS_TO_NO_REPOS;
201         }
202
203         SearchFields searchFields = new SearchFields( groupId, artifactId, version, null, className, selectedRepos );
204
205         log.debug( "filteredSearch with searchFields {}", searchFields );
206
207         // TODO: add packaging in the list of fields for advanced search (UI)?
208         try
209         {
210             results = getNexusSearch().search( getPrincipal(), searchFields, limits );
211         }
212         catch ( RepositorySearchException e )
213         {
214             addActionError( e.getMessage() );
215             return ERROR;
216         }
217
218         if ( results.isEmpty() )
219         {
220             addActionError( "No results found" );
221             return INPUT;
222         }
223
224         totalPages = results.getTotalHits() / limits.getPageSize();
225
226         if ( ( results.getTotalHits() % limits.getPageSize() ) != 0 )
227         {
228             totalPages = totalPages + 1;
229         }
230
231         for ( SearchResultHit hit : results.getHits() )
232         {
233             // fix version ?
234             //hit.setVersion( VersionUtil.getBaseVersion( version ) );
235
236         }
237
238         return SUCCESS;
239     }
240
241     @SuppressWarnings( "unchecked" )
242     public String quickSearch()
243         throws MalformedURLException
244     {
245         /* TODO: give action message if indexing is in progress.
246          * This should be based off a count of 'unprocessed' artifacts.
247          * This (yet to be written) routine could tell the user that X (unprocessed) artifacts are not yet
248          * present in the full text search.
249          */
250
251         assert q != null && q.length() != 0;
252
253         fromFilterSearch = false;
254
255         SearchResultLimits limits = new SearchResultLimits( currentPage );
256
257         List<String> selectedRepos = getObservableRepos();
258         if ( CollectionUtils.isEmpty( selectedRepos ) )
259         {
260             return GlobalResults.ACCESS_TO_NO_REPOS;
261         }
262
263         log.debug( "quickSearch with selectedRepos {} query {}", selectedRepos, q );
264
265         try
266         {
267             if ( searchResultsOnly && !completeQueryString.equals( "" ) )
268             {
269                 results =
270                     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         RepositorySession repositorySession = repositorySessionFactory.createSession();
318         try
319         {
320             MetadataRepository metadataRepository = repositorySession.getRepository();
321             for ( String repoId : getObservableRepos() )
322             {
323                 databaseResults.addAll( metadataRepository.getArtifactsByChecksum( repoId, q ) );
324             }
325         }
326         finally
327         {
328             repositorySession.close();
329         }
330
331         if ( databaseResults.isEmpty() )
332         {
333             addActionError( "No results found" );
334             return INPUT;
335         }
336
337         if ( databaseResults.size() == 1 )
338         {
339             // 1 hit? return it's information directly!
340             return ARTIFACT;
341         }
342
343         return RESULTS;
344     }
345
346     public String doInput()
347     {
348         return INPUT;
349     }
350
351     private void buildCompleteQueryString( String searchTerm )
352     {
353         if ( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
354         {
355             searchTerm = StringUtils.remove( searchTerm, COMPLETE_QUERY_STRING_SEPARATOR );
356         }
357
358         if ( completeQueryString == null || "".equals( completeQueryString ) )
359         {
360             completeQueryString = searchTerm;
361         }
362         else
363         {
364             completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
365         }
366     }
367
368     private List<String> parseCompleteQueryString()
369     {
370         List<String> parsedCompleteQueryString = new ArrayList<String>();
371         String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
372         CollectionUtils.addAll( parsedCompleteQueryString, parsed );
373
374         return parsedCompleteQueryString;
375     }
376
377     private boolean isEqualToPreviousSearchTerm( String searchTerm )
378     {
379         if ( !"".equals( completeQueryString ) )
380         {
381             String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
382             if ( StringUtils.equalsIgnoreCase( searchTerm, parsed[parsed.length - 1] ) )
383             {
384                 return true;
385             }
386         }
387
388         return false;
389     }
390
391     public String getQ()
392     {
393         return q;
394     }
395
396     public void setQ( String q )
397     {
398         this.q = q;
399     }
400
401     public SearchResults getResults()
402     {
403         return results;
404     }
405
406     public List<ArtifactMetadata> getDatabaseResults()
407     {
408         return databaseResults;
409     }
410
411     public void setCurrentPage( int page )
412     {
413         this.currentPage = page;
414     }
415
416     public int getCurrentPage()
417     {
418         return currentPage;
419     }
420
421     public int getTotalPages()
422     {
423         return totalPages;
424     }
425
426     public void setTotalPages( int totalPages )
427     {
428         this.totalPages = totalPages;
429     }
430
431     public boolean isSearchResultsOnly()
432     {
433         return searchResultsOnly;
434     }
435
436     public void setSearchResultsOnly( boolean searchResultsOnly )
437     {
438         this.searchResultsOnly = searchResultsOnly;
439     }
440
441     public String getCompleteQueryString()
442     {
443         return completeQueryString;
444     }
445
446     public void setCompleteQueryString( String completeQueryString )
447     {
448         this.completeQueryString = completeQueryString;
449     }
450
451     public ArchivaConfiguration getArchivaConfiguration()
452     {
453         return archivaConfiguration;
454     }
455
456     public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
457     {
458         this.archivaConfiguration = archivaConfiguration;
459     }
460
461     public Map<String, ManagedRepositoryConfiguration> getManagedRepositories()
462     {
463         return getArchivaConfiguration().getConfiguration().getManagedRepositoriesAsMap();
464     }
465
466     public void setManagedRepositories( Map<String, ManagedRepositoryConfiguration> managedRepositories )
467     {
468     }
469
470     public String getGroupId()
471     {
472         return groupId;
473     }
474
475     public void setGroupId( String groupId )
476     {
477         this.groupId = groupId;
478     }
479
480     public String getArtifactId()
481     {
482         return artifactId;
483     }
484
485     public void setArtifactId( String artifactId )
486     {
487         this.artifactId = artifactId;
488     }
489
490     public String getVersion()
491     {
492         return version;
493     }
494
495     public void setVersion( String version )
496     {
497         this.version = version;
498     }
499
500     public int getRowCount()
501     {
502         return rowCount;
503     }
504
505     public void setRowCount( int rowCount )
506     {
507         this.rowCount = rowCount;
508     }
509
510     public boolean isFilterSearch()
511     {
512         return filterSearch;
513     }
514
515     public void setFilterSearch( boolean filterSearch )
516     {
517         this.filterSearch = filterSearch;
518     }
519
520     public String getRepositoryId()
521     {
522         return repositoryId;
523     }
524
525     public void setRepositoryId( String repositoryId )
526     {
527         this.repositoryId = repositoryId;
528     }
529
530     public List<String> getManagedRepositoryList()
531     {
532         return managedRepositoryList;
533     }
534
535     public void setManagedRepositoryList( List<String> managedRepositoryList )
536     {
537         this.managedRepositoryList = managedRepositoryList;
538     }
539
540     public String getClassName()
541     {
542         return className;
543     }
544
545     public void setClassName( String className )
546     {
547         this.className = className;
548     }
549
550     public RepositorySearch getNexusSearch()
551     {
552         if ( nexusSearch == null )
553         {
554             WebApplicationContext wac =
555                 WebApplicationContextUtils.getRequiredWebApplicationContext( ServletActionContext.getServletContext() );
556             nexusSearch = wac.getBean( "nexusSearch", RepositorySearch.class );
557         }
558         return nexusSearch;
559     }
560
561     public void setNexusSearch( RepositorySearch nexusSearch )
562     {
563         this.nexusSearch = nexusSearch;
564     }
565
566     public Map<String, String> getSearchFields()
567     {
568         return searchFields;
569     }
570
571     public void setSearchFields( Map<String, String> searchFields )
572     {
573         this.searchFields = searchFields;
574     }
575
576     public String getInfoMessage()
577     {
578         return infoMessage;
579     }
580
581     public void setInfoMessage( String infoMessage )
582     {
583         this.infoMessage = infoMessage;
584     }
585 }