]> source.dussan.org Git - archiva.git/blob
b58ef3436efa262dcd201be32fe84709e37fbed4
[archiva.git] /
1 package org.apache.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.admin.model.RepositoryAdminException;
24 import org.apache.archiva.admin.model.beans.ManagedRepository;
25 import org.apache.archiva.admin.model.managed.ManagedRepositoryAdmin;
26 import org.apache.archiva.indexer.search.RepositorySearch;
27 import org.apache.archiva.indexer.search.RepositorySearchException;
28 import org.apache.archiva.indexer.search.SearchFields;
29 import org.apache.archiva.indexer.search.SearchResultHit;
30 import org.apache.archiva.indexer.search.SearchResultLimits;
31 import org.apache.archiva.indexer.search.SearchResults;
32 import org.apache.archiva.metadata.model.ArtifactMetadata;
33 import org.apache.archiva.metadata.repository.MetadataRepository;
34 import org.apache.archiva.metadata.repository.RepositorySession;
35 import org.apache.commons.collections.CollectionUtils;
36 import org.apache.commons.lang.StringUtils;
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     @Inject
61     protected ManagedRepositoryAdmin managedRepositoryAdmin;
62
63     /**
64      * Query string.
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     /**
100      * contains osgi metadata Bundle-Version if available
101      *
102      * @since 1.4-M1
103      */
104     private String bundleVersion;
105
106     /**
107      * contains osgi metadata Bundle-SymbolicName if available
108      *
109      * @since 1.4-M1
110      */
111     private String bundleSymbolicName;
112
113     /**
114      * contains osgi metadata Export-Package if available
115      *
116      * @since 1.4-M1
117      */
118     private String bundleExportPackage;
119
120     /**
121      * contains osgi metadata import package if available
122      *
123      * @since 1.4-M1
124      */
125     private String bundleImportPackage;
126
127     /**
128      * contains osgi metadata name if available
129      *
130      * @since 1.4-M1
131      */
132     private String bundleName;
133
134     /**
135      * contains osgi metadata Export-Service if available
136      *
137      * @since 1.4-M1
138      */
139     private String bundleExportService;
140
141     private int rowCount = 30;
142
143     private String repositoryId;
144
145     private boolean fromFilterSearch;
146
147     private boolean filterSearch = false;
148
149     private boolean fromResultsPage;
150
151     @Inject
152     private RepositorySearch nexusSearch;
153
154     private Map<String, String> searchFields;
155
156     private String infoMessage;
157
158     public boolean isFromResultsPage( )
159     {
160         return fromResultsPage;
161     }
162
163     public void setFromResultsPage( boolean fromResultsPage )
164     {
165         this.fromResultsPage = fromResultsPage;
166     }
167
168     public boolean isFromFilterSearch( )
169     {
170         return fromFilterSearch;
171     }
172
173     public void setFromFilterSearch( boolean fromFilterSearch )
174     {
175         this.fromFilterSearch = fromFilterSearch;
176     }
177
178     public void prepare( )
179     {
180         managedRepositoryList = getObservableRepos( );
181
182         if ( managedRepositoryList.size( ) > 0 )
183         {
184             managedRepositoryList.add( "all" );
185         }
186
187         searchFields = new LinkedHashMap<String, String>( );
188         searchFields.put( "groupId", "Group ID" );
189         searchFields.put( "artifactId", "Artifact ID" );
190         searchFields.put( "version", "Version" );
191         searchFields.put( "className", "Class/Package Name" );
192         searchFields.put( "rowCount", "Row Count" );
193         searchFields.put( "bundleVersion", "OSGI Bundle Version" );
194         searchFields.put( "bundleSymbolicName", "OSGI Bundle-SymbolicName" );
195         searchFields.put( "bundleExportPackage", "OSGI Export-Package" );
196         searchFields.put( "bundleImportPackage", "OSGI import package" );
197         searchFields.put( "bundleName", "OSGI name" );
198         searchFields.put( "bundleExportService", "OSGI Export-Service" );
199
200         super.clearErrorsAndMessages( );
201         clearSearchFields( );
202     }
203
204     private void clearSearchFields( )
205     {
206         repositoryId = "";
207         artifactId = "";
208         groupId = "";
209         version = "";
210         className = "";
211         rowCount = 30;
212         currentPage = 0;
213     }
214
215     // advanced search MRM-90 -- filtered search
216     public String filteredSearch( )
217         throws MalformedURLException
218     {
219         if ( StringUtils.isBlank( groupId ) && StringUtils.isBlank( artifactId ) && StringUtils.isBlank( className )
220             && StringUtils.isBlank( version ) && StringUtils.isBlank( bundleExportPackage ) && StringUtils.isBlank(
221             bundleExportService ) && StringUtils.isBlank( bundleImportPackage ) && StringUtils.isBlank( bundleName )
222             && StringUtils.isBlank( bundleSymbolicName ) && StringUtils.isBlank( bundleVersion ) )
223         {
224             addActionError( "Advanced Search - At least one search criteria must be provided." );
225             return INPUT;
226         }
227
228         fromFilterSearch = true;
229
230         if ( CollectionUtils.isEmpty( managedRepositoryList ) )
231         {
232             return GlobalResults.ACCESS_TO_NO_REPOS;
233         }
234
235         SearchResultLimits limits = new SearchResultLimits( currentPage );
236         limits.setPageSize( rowCount );
237         List<String> selectedRepos = new ArrayList<String>( );
238
239         if ( repositoryId == null || StringUtils.isBlank( repositoryId ) || "all".equals(
240             StringUtils.stripToEmpty( repositoryId ) ) )
241         {
242             selectedRepos = getObservableRepos( );
243         }
244         else
245         {
246             selectedRepos.add( repositoryId );
247         }
248
249         if ( CollectionUtils.isEmpty( selectedRepos ) )
250         {
251             return GlobalResults.ACCESS_TO_NO_REPOS;
252         }
253
254         SearchFields searchFields = new SearchFields( groupId, artifactId, version, null, className, selectedRepos );
255
256         if ( StringUtils.isNotBlank( this.bundleExportPackage ) )
257         {
258             searchFields.setBundleExportPackage( this.bundleExportPackage );
259         }
260
261         if ( StringUtils.isNotBlank( this.bundleExportService ) )
262         {
263             searchFields.setBundleExportService( this.bundleExportService );
264         }
265
266         if ( StringUtils.isNotBlank( this.bundleImportPackage ) )
267         {
268             searchFields.setBundleImportPackage( this.bundleImportPackage );
269         }
270
271         if ( StringUtils.isNotBlank( this.bundleSymbolicName ) )
272         {
273             searchFields.setBundleSymbolicName( this.bundleSymbolicName );
274         }
275
276         if ( StringUtils.isNotBlank( this.bundleName ) )
277         {
278             searchFields.setBundleName( this.bundleName );
279         }
280
281         if ( StringUtils.isNotBlank( this.bundleVersion ) )
282         {
283             searchFields.setBundleVersion( this.bundleVersion );
284         }
285
286         log.debug( "filteredSearch with searchFields {}", searchFields );
287
288         // TODO: add packaging in the list of fields for advanced search (UI)?
289         try
290         {
291             results = getNexusSearch( ).search( getPrincipal( ), searchFields, limits );
292         }
293         catch ( RepositorySearchException e )
294         {
295             addActionError( e.getMessage( ) );
296             return ERROR;
297         }
298
299         if ( results.isEmpty( ) )
300         {
301             addActionError( "No results found" );
302             return INPUT;
303         }
304
305         totalPages = results.getTotalHits( ) / limits.getPageSize( );
306
307         if ( ( results.getTotalHits( ) % limits.getPageSize( ) ) != 0 )
308         {
309             totalPages = totalPages + 1;
310         }
311
312         for ( SearchResultHit hit : results.getHits( ) )
313         {
314             // fix version ?
315             //hit.setVersion( VersionUtil.getBaseVersion( version ) );
316
317         }
318
319         return SUCCESS;
320     }
321
322     @SuppressWarnings( "unchecked" )
323     public String quickSearch( )
324         throws MalformedURLException
325     {
326         /* TODO: give action message if indexing is in progress.
327          * This should be based off a count of 'unprocessed' artifacts.
328          * This (yet to be written) routine could tell the user that X (unprocessed) artifacts are not yet
329          * present in the full text search.
330          */
331
332         assert q != null && q.length( ) != 0;
333
334         fromFilterSearch = false;
335
336         SearchResultLimits limits = new SearchResultLimits( currentPage );
337
338         List<String> selectedRepos = getObservableRepos( );
339         if ( CollectionUtils.isEmpty( selectedRepos ) )
340         {
341             return GlobalResults.ACCESS_TO_NO_REPOS;
342         }
343
344         log.debug( "quickSearch with selectedRepos {} query {}", selectedRepos, q );
345
346         try
347         {
348             if ( searchResultsOnly && !completeQueryString.equals( "" ) )
349             {
350                 results =
351                     getNexusSearch( ).search( getPrincipal( ), selectedRepos, q, limits, parseCompleteQueryString( ) );
352             }
353             else
354             {
355                 completeQueryString = "";
356                 results = getNexusSearch( ).search( getPrincipal( ), selectedRepos, q, limits, null );
357             }
358         }
359         catch ( RepositorySearchException e )
360         {
361             addActionError( e.getMessage( ) );
362             return ERROR;
363         }
364
365         if ( results.isEmpty( ) )
366         {
367             addActionError( "No results found" );
368             return INPUT;
369         }
370
371         totalPages = results.getTotalHits( ) / limits.getPageSize( );
372
373         if ( ( results.getTotalHits( ) % limits.getPageSize( ) ) != 0 )
374         {
375             totalPages = totalPages + 1;
376         }
377
378         if ( !isEqualToPreviousSearchTerm( q ) )
379         {
380             buildCompleteQueryString( q );
381         }
382
383         return SUCCESS;
384     }
385
386     public String findArtifact( )
387         throws Exception
388     {
389         // TODO: give action message if indexing is in progress
390
391         if ( StringUtils.isBlank( q ) )
392         {
393             addActionError( "Unable to search for a blank checksum" );
394             return INPUT;
395         }
396
397         databaseResults = new ArrayList<ArtifactMetadata>( );
398         RepositorySession repositorySession = repositorySessionFactory.createSession( );
399         try
400         {
401             MetadataRepository metadataRepository = repositorySession.getRepository( );
402             for ( String repoId : getObservableRepos( ) )
403             {
404                 databaseResults.addAll( metadataRepository.getArtifactsByChecksum( repoId, q ) );
405             }
406         }
407         finally
408         {
409             repositorySession.close( );
410         }
411
412         if ( databaseResults.isEmpty( ) )
413         {
414             addActionError( "No results found" );
415             return INPUT;
416         }
417
418         if ( databaseResults.size( ) == 1 )
419         {
420             // 1 hit? return it's information directly!
421             return ARTIFACT;
422         }
423
424         return RESULTS;
425     }
426
427     public String doInput( )
428     {
429         return INPUT;
430     }
431
432     private void buildCompleteQueryString( String searchTerm )
433     {
434         if ( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
435         {
436             searchTerm = StringUtils.remove( searchTerm, COMPLETE_QUERY_STRING_SEPARATOR );
437         }
438
439         if ( completeQueryString == null || "".equals( completeQueryString ) )
440         {
441             completeQueryString = searchTerm;
442         }
443         else
444         {
445             completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
446         }
447     }
448
449     private List<String> parseCompleteQueryString( )
450     {
451         List<String> parsedCompleteQueryString = new ArrayList<String>( );
452         String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
453         CollectionUtils.addAll( parsedCompleteQueryString, parsed );
454
455         return parsedCompleteQueryString;
456     }
457
458     private boolean isEqualToPreviousSearchTerm( String searchTerm )
459     {
460         if ( !"".equals( completeQueryString ) )
461         {
462             String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
463             if ( StringUtils.equalsIgnoreCase( searchTerm, parsed[parsed.length - 1] ) )
464             {
465                 return true;
466             }
467         }
468
469         return false;
470     }
471
472     public String getQ( )
473     {
474         return q;
475     }
476
477     public void setQ( String q )
478     {
479         this.q = q;
480     }
481
482     public SearchResults getResults( )
483     {
484         return results;
485     }
486
487     public List<ArtifactMetadata> getDatabaseResults( )
488     {
489         return databaseResults;
490     }
491
492     public void setCurrentPage( int page )
493     {
494         this.currentPage = page;
495     }
496
497     public int getCurrentPage( )
498     {
499         return currentPage;
500     }
501
502     public int getTotalPages( )
503     {
504         return totalPages;
505     }
506
507     public void setTotalPages( int totalPages )
508     {
509         this.totalPages = totalPages;
510     }
511
512     public boolean isSearchResultsOnly( )
513     {
514         return searchResultsOnly;
515     }
516
517     public void setSearchResultsOnly( boolean searchResultsOnly )
518     {
519         this.searchResultsOnly = searchResultsOnly;
520     }
521
522     public String getCompleteQueryString( )
523     {
524         return completeQueryString;
525     }
526
527     public void setCompleteQueryString( String completeQueryString )
528     {
529         this.completeQueryString = completeQueryString;
530     }
531
532     public Map<String, ManagedRepository> getManagedRepositories( )
533         throws RepositoryAdminException
534     {
535         return managedRepositoryAdmin.getManagedRepositoriesAsMap( );
536     }
537
538     // wtf : does nothing ??
539     public void setManagedRepositories( Map<String, ManagedRepository> managedRepositories )
540     {
541     }
542
543     public String getGroupId( )
544     {
545         return groupId;
546     }
547
548     public void setGroupId( String groupId )
549     {
550         this.groupId = groupId;
551     }
552
553     public String getArtifactId( )
554     {
555         return artifactId;
556     }
557
558     public void setArtifactId( String artifactId )
559     {
560         this.artifactId = artifactId;
561     }
562
563     public String getVersion( )
564     {
565         return version;
566     }
567
568     public void setVersion( String version )
569     {
570         this.version = version;
571     }
572
573     public int getRowCount( )
574     {
575         return rowCount;
576     }
577
578     public void setRowCount( int rowCount )
579     {
580         this.rowCount = rowCount;
581     }
582
583     public boolean isFilterSearch( )
584     {
585         return filterSearch;
586     }
587
588     public void setFilterSearch( boolean filterSearch )
589     {
590         this.filterSearch = filterSearch;
591     }
592
593     public String getRepositoryId( )
594     {
595         return repositoryId;
596     }
597
598     public void setRepositoryId( String repositoryId )
599     {
600         this.repositoryId = repositoryId;
601     }
602
603     public List<String> getManagedRepositoryList( )
604     {
605         return managedRepositoryList;
606     }
607
608     public void setManagedRepositoryList( List<String> managedRepositoryList )
609     {
610         this.managedRepositoryList = managedRepositoryList;
611     }
612
613     public String getClassName( )
614     {
615         return className;
616     }
617
618     public void setClassName( String className )
619     {
620         this.className = className;
621     }
622
623     public RepositorySearch getNexusSearch( )
624     {
625         if ( nexusSearch == null )
626         {
627             WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(
628                 ServletActionContext.getServletContext( ) );
629             nexusSearch = wac.getBean( "nexusSearch", RepositorySearch.class );
630         }
631         return nexusSearch;
632     }
633
634     public void setNexusSearch( RepositorySearch nexusSearch )
635     {
636         this.nexusSearch = nexusSearch;
637     }
638
639     public Map<String, String> getSearchFields( )
640     {
641         return searchFields;
642     }
643
644     public void setSearchFields( Map<String, String> searchFields )
645     {
646         this.searchFields = searchFields;
647     }
648
649     public String getInfoMessage( )
650     {
651         return infoMessage;
652     }
653
654     public void setInfoMessage( String infoMessage )
655     {
656         this.infoMessage = infoMessage;
657     }
658
659     public ManagedRepositoryAdmin getManagedRepositoryAdmin( )
660     {
661         return managedRepositoryAdmin;
662     }
663
664     public void setManagedRepositoryAdmin( ManagedRepositoryAdmin managedRepositoryAdmin )
665     {
666         this.managedRepositoryAdmin = managedRepositoryAdmin;
667     }
668
669     public String getBundleVersion( )
670     {
671         return bundleVersion;
672     }
673
674     public void setBundleVersion( String bundleVersion )
675     {
676         this.bundleVersion = bundleVersion;
677     }
678
679     public String getBundleSymbolicName( )
680     {
681         return bundleSymbolicName;
682     }
683
684     public void setBundleSymbolicName( String bundleSymbolicName )
685     {
686         this.bundleSymbolicName = bundleSymbolicName;
687     }
688
689     public String getBundleExportPackage( )
690     {
691         return bundleExportPackage;
692     }
693
694     public void setBundleExportPackage( String bundleExportPackage )
695     {
696         this.bundleExportPackage = bundleExportPackage;
697     }
698
699     public String getBundleImportPackage( )
700     {
701         return bundleImportPackage;
702     }
703
704     public void setBundleImportPackage( String bundleImportPackage )
705     {
706         this.bundleImportPackage = bundleImportPackage;
707     }
708
709     public String getBundleName( )
710     {
711         return bundleName;
712     }
713
714     public void setBundleName( String bundleName )
715     {
716         this.bundleName = bundleName;
717     }
718
719     public String getBundleExportService( )
720     {
721         return bundleExportService;
722     }
723
724     public void setBundleExportService( String bundleExportService )
725     {
726         this.bundleExportService = bundleExportService;
727     }
728 }