1 package org.apache.archiva.web.action;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
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;
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;
51 * Search all indexed fields by the given criteria.
53 @Controller( "searchAction" )
55 public class SearchAction
56 extends AbstractRepositoryBasedAction
61 protected ManagedRepositoryAdmin managedRepositoryAdmin;
71 private SearchResults results;
73 private static final String RESULTS = "results";
75 private static final String ARTIFACT = "artifact";
77 private List<ArtifactMetadata> databaseResults;
79 private int currentPage = 0;
81 private int totalPages;
83 private boolean searchResultsOnly;
85 private String completeQueryString;
87 private static final String COMPLETE_QUERY_STRING_SEPARATOR = ";";
89 private List<String> managedRepositoryList = new ArrayList<String>();
91 private String groupId;
93 private String artifactId;
95 private String version;
97 private String className;
100 * contains osgi metadata Bundle-Version if available
104 private String bundleVersion;
107 * contains osgi metadata Bundle-SymbolicName if available
111 private String bundleSymbolicName;
114 * contains osgi metadata Export-Package if available
118 private String bundleExportPackage;
121 * contains osgi metadata import package if available
125 private String bundleImportPackage;
128 * contains osgi metadata name if available
132 private String bundleName;
135 * contains osgi metadata Export-Service if available
139 private String bundleExportService;
141 private int rowCount = 30;
143 private String repositoryId;
145 private boolean fromFilterSearch;
147 private boolean filterSearch = false;
149 private boolean fromResultsPage;
152 private RepositorySearch nexusSearch;
154 private Map<String, String> searchFields;
156 private String infoMessage;
158 public boolean isFromResultsPage()
160 return fromResultsPage;
163 public void setFromResultsPage(boolean fromResultsPage)
165 this.fromResultsPage = fromResultsPage;
168 public boolean isFromFilterSearch()
170 return fromFilterSearch;
173 public void setFromFilterSearch(boolean fromFilterSearch)
175 this.fromFilterSearch = fromFilterSearch;
178 public void prepare()
180 managedRepositoryList = getObservableRepos();
182 if ( managedRepositoryList.size() > 0 )
184 managedRepositoryList.add("all");
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");
200 super.clearErrorsAndMessages();
204 private void clearSearchFields()
215 // advanced search MRM-90 -- filtered search
216 public String filteredSearch()
217 throws MalformedURLException
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) )
224 addActionError("Advanced Search - At least one search criteria must be provided.");
228 fromFilterSearch = true;
230 if ( CollectionUtils.isEmpty(managedRepositoryList) )
232 return GlobalResults.ACCESS_TO_NO_REPOS;
235 SearchResultLimits limits = new SearchResultLimits(currentPage);
236 limits.setPageSize(rowCount);
237 List<String> selectedRepos = new ArrayList<String>();
239 if ( repositoryId == null || StringUtils.isBlank(repositoryId) || "all".equals(
240 StringUtils.stripToEmpty(repositoryId)) )
242 selectedRepos = getObservableRepos();
246 selectedRepos.add(repositoryId);
249 if ( CollectionUtils.isEmpty(selectedRepos) )
251 return GlobalResults.ACCESS_TO_NO_REPOS;
254 SearchFields searchFields = new SearchFields(groupId, artifactId, version, null, className, selectedRepos);
256 if ( StringUtils.isNotBlank(this.bundleExportPackage) )
258 searchFields.setBundleExportPackage(this.bundleExportPackage);
261 if ( StringUtils.isNotBlank(this.bundleExportService) )
263 searchFields.setBundleExportService(this.bundleExportService);
266 if ( StringUtils.isNotBlank(this.bundleImportPackage) )
268 searchFields.setBundleImportPackage(this.bundleImportPackage);
271 if ( StringUtils.isNotBlank(this.bundleSymbolicName) )
273 searchFields.setBundleSymbolicName(this.bundleSymbolicName);
276 if ( StringUtils.isNotBlank(this.bundleName) )
278 searchFields.setBundleName(this.bundleName);
281 if ( StringUtils.isNotBlank(this.bundleVersion) )
283 searchFields.setBundleVersion(this.bundleVersion);
286 log.debug("filteredSearch with searchFields {}", searchFields);
288 // TODO: add packaging in the list of fields for advanced search (UI)?
291 results = getNexusSearch().search(getPrincipal(), searchFields, limits);
293 catch ( RepositorySearchException e )
295 addActionError(e.getMessage());
299 if ( results.isEmpty() )
301 addActionError("No results found");
305 totalPages = results.getTotalHits() / limits.getPageSize();
307 if ( ( results.getTotalHits() % limits.getPageSize() ) != 0 )
309 totalPages = totalPages + 1;
312 for ( SearchResultHit hit : results.getHits() )
315 //hit.setVersion( VersionUtil.getBaseVersion( version ) );
322 @SuppressWarnings( "unchecked" )
323 public String quickSearch()
324 throws MalformedURLException
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.
332 assert q != null && q.length() != 0;
334 fromFilterSearch = false;
336 SearchResultLimits limits = new SearchResultLimits(currentPage);
338 List<String> selectedRepos = getObservableRepos();
339 if ( CollectionUtils.isEmpty(selectedRepos) )
341 return GlobalResults.ACCESS_TO_NO_REPOS;
344 log.debug("quickSearch with selectedRepos {} query {}", selectedRepos, q);
348 if ( searchResultsOnly && !completeQueryString.equals("") )
350 results = getNexusSearch().search(getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString());
354 completeQueryString = "";
355 results = getNexusSearch().search(getPrincipal(), selectedRepos, q, limits, null);
358 catch ( RepositorySearchException e )
360 addActionError(e.getMessage());
364 if ( results.isEmpty() )
366 addActionError("No results found");
370 totalPages = results.getTotalHitsMapSize() / limits.getPageSize();
372 if ( ( results.getTotalHitsMapSize() % limits.getPageSize() ) != 0 )
374 totalPages = totalPages + 1;
377 if ( !isEqualToPreviousSearchTerm(q) )
379 buildCompleteQueryString(q);
385 public String findArtifact()
388 // TODO: give action message if indexing is in progress
390 if ( StringUtils.isBlank(q) )
392 addActionError("Unable to search for a blank checksum");
396 databaseResults = new ArrayList<ArtifactMetadata>();
397 RepositorySession repositorySession = repositorySessionFactory.createSession();
400 MetadataRepository metadataRepository = repositorySession.getRepository();
401 for ( String repoId : getObservableRepos() )
403 databaseResults.addAll(metadataRepository.getArtifactsByChecksum(repoId, q));
408 repositorySession.close();
411 if ( databaseResults.isEmpty() )
413 addActionError("No results found");
417 if ( databaseResults.size() == 1 )
419 // 1 hit? return it's information directly!
426 public String doInput()
431 private void buildCompleteQueryString(String searchTerm)
433 if ( searchTerm.indexOf(COMPLETE_QUERY_STRING_SEPARATOR) != -1 )
435 searchTerm = StringUtils.remove(searchTerm, COMPLETE_QUERY_STRING_SEPARATOR);
438 if ( completeQueryString == null || "".equals(completeQueryString) )
440 completeQueryString = searchTerm;
444 completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
448 private List<String> parseCompleteQueryString()
450 List<String> parsedCompleteQueryString = new ArrayList<String>();
451 String[] parsed = StringUtils.split(completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR);
452 CollectionUtils.addAll(parsedCompleteQueryString, parsed);
454 return parsedCompleteQueryString;
457 private boolean isEqualToPreviousSearchTerm(String searchTerm)
459 if ( !"".equals(completeQueryString) )
461 String[] parsed = StringUtils.split(completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR);
462 if ( StringUtils.equalsIgnoreCase(searchTerm, parsed[parsed.length - 1]) )
476 public void setQ(String q)
481 public SearchResults getResults()
486 public List<ArtifactMetadata> getDatabaseResults()
488 return databaseResults;
491 public void setCurrentPage(int page)
493 this.currentPage = page;
496 public int getCurrentPage()
501 public int getTotalPages()
506 public void setTotalPages(int totalPages)
508 this.totalPages = totalPages;
511 public boolean isSearchResultsOnly()
513 return searchResultsOnly;
516 public void setSearchResultsOnly(boolean searchResultsOnly)
518 this.searchResultsOnly = searchResultsOnly;
521 public String getCompleteQueryString()
523 return completeQueryString;
526 public void setCompleteQueryString(String completeQueryString)
528 this.completeQueryString = completeQueryString;
531 public Map<String, ManagedRepository> getManagedRepositories()
532 throws RepositoryAdminException
534 return managedRepositoryAdmin.getManagedRepositoriesAsMap();
537 // wtf : does nothing ??
538 public void setManagedRepositories(Map<String, ManagedRepository> managedRepositories)
542 public String getGroupId()
547 public void setGroupId(String groupId)
549 this.groupId = groupId;
552 public String getArtifactId()
557 public void setArtifactId(String artifactId)
559 this.artifactId = artifactId;
562 public String getVersion()
567 public void setVersion(String version)
569 this.version = version;
572 public int getRowCount()
577 public void setRowCount(int rowCount)
579 this.rowCount = rowCount;
582 public boolean isFilterSearch()
587 public void setFilterSearch(boolean filterSearch)
589 this.filterSearch = filterSearch;
592 public String getRepositoryId()
597 public void setRepositoryId(String repositoryId)
599 this.repositoryId = repositoryId;
602 public List<String> getManagedRepositoryList()
604 return managedRepositoryList;
607 public void setManagedRepositoryList(List<String> managedRepositoryList)
609 this.managedRepositoryList = managedRepositoryList;
612 public String getClassName()
617 public void setClassName(String className)
619 this.className = className;
622 public RepositorySearch getNexusSearch()
624 if ( nexusSearch == null )
626 WebApplicationContext wac =
627 WebApplicationContextUtils.getRequiredWebApplicationContext(ServletActionContext.getServletContext());
628 nexusSearch = wac.getBean("nexusSearch", RepositorySearch.class);
633 public void setNexusSearch(RepositorySearch nexusSearch)
635 this.nexusSearch = nexusSearch;
638 public Map<String, String> getSearchFields()
643 public void setSearchFields(Map<String, String> searchFields)
645 this.searchFields = searchFields;
648 public String getInfoMessage()
653 public void setInfoMessage(String infoMessage)
655 this.infoMessage = infoMessage;
658 public ManagedRepositoryAdmin getManagedRepositoryAdmin()
660 return managedRepositoryAdmin;
663 public void setManagedRepositoryAdmin(ManagedRepositoryAdmin managedRepositoryAdmin)
665 this.managedRepositoryAdmin = managedRepositoryAdmin;
668 public String getBundleVersion()
670 return bundleVersion;
673 public void setBundleVersion(String bundleVersion)
675 this.bundleVersion = bundleVersion;
678 public String getBundleSymbolicName()
680 return bundleSymbolicName;
683 public void setBundleSymbolicName(String bundleSymbolicName)
685 this.bundleSymbolicName = bundleSymbolicName;
688 public String getBundleExportPackage()
690 return bundleExportPackage;
693 public void setBundleExportPackage(String bundleExportPackage)
695 this.bundleExportPackage = bundleExportPackage;
698 public String getBundleImportPackage()
700 return bundleImportPackage;
703 public void setBundleImportPackage(String bundleImportPackage)
705 this.bundleImportPackage = bundleImportPackage;
708 public String getBundleName()
713 public void setBundleName(String bundleName)
715 this.bundleName = bundleName;
718 public String getBundleExportService()
720 return bundleExportService;
723 public void setBundleExportService(String bundleExportService)
725 this.bundleExportService = bundleExportService;