]> source.dussan.org Git - archiva.git/blob
24bf761796485c371db094de2bc01da241ddb34a
[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 = getNexusSearch().search(getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString());
351             }
352             else
353             {
354                 completeQueryString = "";
355                 results = getNexusSearch().search(getPrincipal(), selectedRepos, q, limits, null);
356             }
357         }
358         catch ( RepositorySearchException e )
359         {
360             addActionError(e.getMessage());
361             return ERROR;
362         }
363
364         if ( results.isEmpty() )
365         {
366             addActionError("No results found");
367             return INPUT;
368         }
369
370         totalPages = results.getTotalHitsMapSize() / limits.getPageSize();
371
372         if ( ( results.getTotalHitsMapSize() % limits.getPageSize() ) != 0 )
373         {
374             totalPages = totalPages + 1;
375         }
376
377         if ( !isEqualToPreviousSearchTerm(q) )
378         {
379             buildCompleteQueryString(q);
380         }
381
382         return SUCCESS;
383     }
384
385     public String findArtifact()
386         throws Exception
387     {
388         // TODO: give action message if indexing is in progress
389
390         if ( StringUtils.isBlank(q) )
391         {
392             addActionError("Unable to search for a blank checksum");
393             return INPUT;
394         }
395
396         databaseResults = new ArrayList<ArtifactMetadata>();
397         RepositorySession repositorySession = repositorySessionFactory.createSession();
398         try
399         {
400             MetadataRepository metadataRepository = repositorySession.getRepository();
401             for ( String repoId : getObservableRepos() )
402             {
403                 databaseResults.addAll(metadataRepository.getArtifactsByChecksum(repoId, q));
404             }
405         }
406         finally
407         {
408             repositorySession.close();
409         }
410
411         if ( databaseResults.isEmpty() )
412         {
413             addActionError("No results found");
414             return INPUT;
415         }
416
417         if ( databaseResults.size() == 1 )
418         {
419             // 1 hit? return it's information directly!
420             return ARTIFACT;
421         }
422
423         return RESULTS;
424     }
425
426     public String doInput()
427     {
428         return INPUT;
429     }
430
431     private void buildCompleteQueryString(String searchTerm)
432     {
433         if ( searchTerm.indexOf(COMPLETE_QUERY_STRING_SEPARATOR) != -1 )
434         {
435             searchTerm = StringUtils.remove(searchTerm, COMPLETE_QUERY_STRING_SEPARATOR);
436         }
437
438         if ( completeQueryString == null || "".equals(completeQueryString) )
439         {
440             completeQueryString = searchTerm;
441         }
442         else
443         {
444             completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
445         }
446     }
447
448     private List<String> parseCompleteQueryString()
449     {
450         List<String> parsedCompleteQueryString = new ArrayList<String>();
451         String[] parsed = StringUtils.split(completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR);
452         CollectionUtils.addAll(parsedCompleteQueryString, parsed);
453
454         return parsedCompleteQueryString;
455     }
456
457     private boolean isEqualToPreviousSearchTerm(String searchTerm)
458     {
459         if ( !"".equals(completeQueryString) )
460         {
461             String[] parsed = StringUtils.split(completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR);
462             if ( StringUtils.equalsIgnoreCase(searchTerm, parsed[parsed.length - 1]) )
463             {
464                 return true;
465             }
466         }
467
468         return false;
469     }
470
471     public String getQ()
472     {
473         return q;
474     }
475
476     public void setQ(String q)
477     {
478         this.q = q;
479     }
480
481     public SearchResults getResults()
482     {
483         return results;
484     }
485
486     public List<ArtifactMetadata> getDatabaseResults()
487     {
488         return databaseResults;
489     }
490
491     public void setCurrentPage(int page)
492     {
493         this.currentPage = page;
494     }
495
496     public int getCurrentPage()
497     {
498         return currentPage;
499     }
500
501     public int getTotalPages()
502     {
503         return totalPages;
504     }
505
506     public void setTotalPages(int totalPages)
507     {
508         this.totalPages = totalPages;
509     }
510
511     public boolean isSearchResultsOnly()
512     {
513         return searchResultsOnly;
514     }
515
516     public void setSearchResultsOnly(boolean searchResultsOnly)
517     {
518         this.searchResultsOnly = searchResultsOnly;
519     }
520
521     public String getCompleteQueryString()
522     {
523         return completeQueryString;
524     }
525
526     public void setCompleteQueryString(String completeQueryString)
527     {
528         this.completeQueryString = completeQueryString;
529     }
530
531     public Map<String, ManagedRepository> getManagedRepositories()
532         throws RepositoryAdminException
533     {
534         return managedRepositoryAdmin.getManagedRepositoriesAsMap();
535     }
536
537     // wtf : does nothing ??
538     public void setManagedRepositories(Map<String, ManagedRepository> managedRepositories)
539     {
540     }
541
542     public String getGroupId()
543     {
544         return groupId;
545     }
546
547     public void setGroupId(String groupId)
548     {
549         this.groupId = groupId;
550     }
551
552     public String getArtifactId()
553     {
554         return artifactId;
555     }
556
557     public void setArtifactId(String artifactId)
558     {
559         this.artifactId = artifactId;
560     }
561
562     public String getVersion()
563     {
564         return version;
565     }
566
567     public void setVersion(String version)
568     {
569         this.version = version;
570     }
571
572     public int getRowCount()
573     {
574         return rowCount;
575     }
576
577     public void setRowCount(int rowCount)
578     {
579         this.rowCount = rowCount;
580     }
581
582     public boolean isFilterSearch()
583     {
584         return filterSearch;
585     }
586
587     public void setFilterSearch(boolean filterSearch)
588     {
589         this.filterSearch = filterSearch;
590     }
591
592     public String getRepositoryId()
593     {
594         return repositoryId;
595     }
596
597     public void setRepositoryId(String repositoryId)
598     {
599         this.repositoryId = repositoryId;
600     }
601
602     public List<String> getManagedRepositoryList()
603     {
604         return managedRepositoryList;
605     }
606
607     public void setManagedRepositoryList(List<String> managedRepositoryList)
608     {
609         this.managedRepositoryList = managedRepositoryList;
610     }
611
612     public String getClassName()
613     {
614         return className;
615     }
616
617     public void setClassName(String className)
618     {
619         this.className = className;
620     }
621
622     public RepositorySearch getNexusSearch()
623     {
624         if ( nexusSearch == null )
625         {
626             WebApplicationContext wac =
627                 WebApplicationContextUtils.getRequiredWebApplicationContext(ServletActionContext.getServletContext());
628             nexusSearch = wac.getBean("nexusSearch", RepositorySearch.class);
629         }
630         return nexusSearch;
631     }
632
633     public void setNexusSearch(RepositorySearch nexusSearch)
634     {
635         this.nexusSearch = nexusSearch;
636     }
637
638     public Map<String, String> getSearchFields()
639     {
640         return searchFields;
641     }
642
643     public void setSearchFields(Map<String, String> searchFields)
644     {
645         this.searchFields = searchFields;
646     }
647
648     public String getInfoMessage()
649     {
650         return infoMessage;
651     }
652
653     public void setInfoMessage(String infoMessage)
654     {
655         this.infoMessage = infoMessage;
656     }
657
658     public ManagedRepositoryAdmin getManagedRepositoryAdmin()
659     {
660         return managedRepositoryAdmin;
661     }
662
663     public void setManagedRepositoryAdmin(ManagedRepositoryAdmin managedRepositoryAdmin)
664     {
665         this.managedRepositoryAdmin = managedRepositoryAdmin;
666     }
667
668     public String getBundleVersion()
669     {
670         return bundleVersion;
671     }
672
673     public void setBundleVersion(String bundleVersion)
674     {
675         this.bundleVersion = bundleVersion;
676     }
677
678     public String getBundleSymbolicName()
679     {
680         return bundleSymbolicName;
681     }
682
683     public void setBundleSymbolicName(String bundleSymbolicName)
684     {
685         this.bundleSymbolicName = bundleSymbolicName;
686     }
687
688     public String getBundleExportPackage()
689     {
690         return bundleExportPackage;
691     }
692
693     public void setBundleExportPackage(String bundleExportPackage)
694     {
695         this.bundleExportPackage = bundleExportPackage;
696     }
697
698     public String getBundleImportPackage()
699     {
700         return bundleImportPackage;
701     }
702
703     public void setBundleImportPackage(String bundleImportPackage)
704     {
705         this.bundleImportPackage = bundleImportPackage;
706     }
707
708     public String getBundleName()
709     {
710         return bundleName;
711     }
712
713     public void setBundleName(String bundleName)
714     {
715         this.bundleName = bundleName;
716     }
717
718     public String getBundleExportService()
719     {
720         return bundleExportService;
721     }
722
723     public void setBundleExportService(String bundleExportService)
724     {
725         this.bundleExportService = bundleExportService;
726     }
727 }