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