1 package org.apache.maven.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.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;
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
64 // FIXME olamy WTF here??
65 private ArchivaConfiguration archivaConfiguration;
70 private SearchResults results;
72 private static final String RESULTS = "results";
74 private static final String ARTIFACT = "artifact";
76 private List<ArtifactMetadata> databaseResults;
78 private int currentPage = 0;
80 private int totalPages;
82 private boolean searchResultsOnly;
84 private String completeQueryString;
86 private static final String COMPLETE_QUERY_STRING_SEPARATOR = ";";
88 private List<String> managedRepositoryList = new ArrayList<String>();
90 private String groupId;
92 private String artifactId;
94 private String version;
96 private String className;
98 private int rowCount = 30;
100 private String repositoryId;
102 private boolean fromFilterSearch;
104 private boolean filterSearch = false;
106 private boolean fromResultsPage;
109 private RepositorySearch nexusSearch;
111 private Map<String, String> searchFields;
113 private String infoMessage;
115 public boolean isFromResultsPage()
117 return fromResultsPage;
120 public void setFromResultsPage( boolean fromResultsPage )
122 this.fromResultsPage = fromResultsPage;
125 public boolean isFromFilterSearch()
127 return fromFilterSearch;
130 public void setFromFilterSearch( boolean fromFilterSearch )
132 this.fromFilterSearch = fromFilterSearch;
135 public void prepare()
137 managedRepositoryList = getObservableRepos();
139 if ( managedRepositoryList.size() > 0 )
141 managedRepositoryList.add( "all" );
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" );
151 super.clearErrorsAndMessages();
155 private void clearSearchFields()
166 // advanced search MRM-90 -- filtered search
167 public String filteredSearch()
168 throws MalformedURLException
170 if ( ( groupId == null || "".equals( groupId ) ) && ( artifactId == null || "".equals( artifactId ) )
171 && ( className == null || "".equals( className ) ) && ( version == null || "".equals( version ) ) )
173 addActionError( "Advanced Search - At least one search criteria must be provided." );
177 fromFilterSearch = true;
179 if ( CollectionUtils.isEmpty( managedRepositoryList ) )
181 return GlobalResults.ACCESS_TO_NO_REPOS;
184 SearchResultLimits limits = new SearchResultLimits( currentPage );
185 limits.setPageSize( rowCount );
186 List<String> selectedRepos = new ArrayList<String>();
188 if ( repositoryId == null || StringUtils.isBlank( repositoryId ) || "all".equals(
189 StringUtils.stripToEmpty( repositoryId ) ) )
191 selectedRepos = getObservableRepos();
195 selectedRepos.add( repositoryId );
198 if ( CollectionUtils.isEmpty( selectedRepos ) )
200 return GlobalResults.ACCESS_TO_NO_REPOS;
203 SearchFields searchFields = new SearchFields( groupId, artifactId, version, null, className, selectedRepos );
205 log.debug( "filteredSearch with searchFields {}", searchFields );
207 // TODO: add packaging in the list of fields for advanced search (UI)?
210 results = getNexusSearch().search( getPrincipal(), searchFields, limits );
212 catch ( RepositorySearchException e )
214 addActionError( e.getMessage() );
218 if ( results.isEmpty() )
220 addActionError( "No results found" );
224 totalPages = results.getTotalHits() / limits.getPageSize();
226 if ( ( results.getTotalHits() % limits.getPageSize() ) != 0 )
228 totalPages = totalPages + 1;
231 for ( SearchResultHit hit : results.getHits() )
234 //hit.setVersion( VersionUtil.getBaseVersion( version ) );
241 @SuppressWarnings( "unchecked" )
242 public String quickSearch()
243 throws MalformedURLException
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.
251 assert q != null && q.length() != 0;
253 fromFilterSearch = false;
255 SearchResultLimits limits = new SearchResultLimits( currentPage );
257 List<String> selectedRepos = getObservableRepos();
258 if ( CollectionUtils.isEmpty( selectedRepos ) )
260 return GlobalResults.ACCESS_TO_NO_REPOS;
263 log.debug( "quickSearch with selectedRepos {} query {}", selectedRepos, q );
267 if ( searchResultsOnly && !completeQueryString.equals( "" ) )
270 getNexusSearch().search( getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString() );
274 completeQueryString = "";
275 results = getNexusSearch().search( getPrincipal(), selectedRepos, q, limits, null );
278 catch ( RepositorySearchException e )
280 addActionError( e.getMessage() );
284 if ( results.isEmpty() )
286 addActionError( "No results found" );
290 totalPages = results.getTotalHits() / limits.getPageSize();
292 if ( ( results.getTotalHits() % limits.getPageSize() ) != 0 )
294 totalPages = totalPages + 1;
297 if ( !isEqualToPreviousSearchTerm( q ) )
299 buildCompleteQueryString( q );
305 public String findArtifact()
308 // TODO: give action message if indexing is in progress
310 if ( StringUtils.isBlank( q ) )
312 addActionError( "Unable to search for a blank checksum" );
316 databaseResults = new ArrayList<ArtifactMetadata>();
317 RepositorySession repositorySession = repositorySessionFactory.createSession();
320 MetadataRepository metadataRepository = repositorySession.getRepository();
321 for ( String repoId : getObservableRepos() )
323 databaseResults.addAll( metadataRepository.getArtifactsByChecksum( repoId, q ) );
328 repositorySession.close();
331 if ( databaseResults.isEmpty() )
333 addActionError( "No results found" );
337 if ( databaseResults.size() == 1 )
339 // 1 hit? return it's information directly!
346 public String doInput()
351 private void buildCompleteQueryString( String searchTerm )
353 if ( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
355 searchTerm = StringUtils.remove( searchTerm, COMPLETE_QUERY_STRING_SEPARATOR );
358 if ( completeQueryString == null || "".equals( completeQueryString ) )
360 completeQueryString = searchTerm;
364 completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
368 private List<String> parseCompleteQueryString()
370 List<String> parsedCompleteQueryString = new ArrayList<String>();
371 String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
372 CollectionUtils.addAll( parsedCompleteQueryString, parsed );
374 return parsedCompleteQueryString;
377 private boolean isEqualToPreviousSearchTerm( String searchTerm )
379 if ( !"".equals( completeQueryString ) )
381 String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
382 if ( StringUtils.equalsIgnoreCase( searchTerm, parsed[parsed.length - 1] ) )
396 public void setQ( String q )
401 public SearchResults getResults()
406 public List<ArtifactMetadata> getDatabaseResults()
408 return databaseResults;
411 public void setCurrentPage( int page )
413 this.currentPage = page;
416 public int getCurrentPage()
421 public int getTotalPages()
426 public void setTotalPages( int totalPages )
428 this.totalPages = totalPages;
431 public boolean isSearchResultsOnly()
433 return searchResultsOnly;
436 public void setSearchResultsOnly( boolean searchResultsOnly )
438 this.searchResultsOnly = searchResultsOnly;
441 public String getCompleteQueryString()
443 return completeQueryString;
446 public void setCompleteQueryString( String completeQueryString )
448 this.completeQueryString = completeQueryString;
451 public ArchivaConfiguration getArchivaConfiguration()
453 return archivaConfiguration;
456 public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
458 this.archivaConfiguration = archivaConfiguration;
461 public Map<String, ManagedRepositoryConfiguration> getManagedRepositories()
463 return getArchivaConfiguration().getConfiguration().getManagedRepositoriesAsMap();
466 public void setManagedRepositories( Map<String, ManagedRepositoryConfiguration> managedRepositories )
470 public String getGroupId()
475 public void setGroupId( String groupId )
477 this.groupId = groupId;
480 public String getArtifactId()
485 public void setArtifactId( String artifactId )
487 this.artifactId = artifactId;
490 public String getVersion()
495 public void setVersion( String version )
497 this.version = version;
500 public int getRowCount()
505 public void setRowCount( int rowCount )
507 this.rowCount = rowCount;
510 public boolean isFilterSearch()
515 public void setFilterSearch( boolean filterSearch )
517 this.filterSearch = filterSearch;
520 public String getRepositoryId()
525 public void setRepositoryId( String repositoryId )
527 this.repositoryId = repositoryId;
530 public List<String> getManagedRepositoryList()
532 return managedRepositoryList;
535 public void setManagedRepositoryList( List<String> managedRepositoryList )
537 this.managedRepositoryList = managedRepositoryList;
540 public String getClassName()
545 public void setClassName( String className )
547 this.className = className;
550 public RepositorySearch getNexusSearch()
552 if ( nexusSearch == null )
554 WebApplicationContext wac =
555 WebApplicationContextUtils.getRequiredWebApplicationContext( ServletActionContext.getServletContext() );
556 nexusSearch = wac.getBean( "nexusSearch", RepositorySearch.class );
561 public void setNexusSearch( RepositorySearch nexusSearch )
563 this.nexusSearch = nexusSearch;
566 public Map<String, String> getSearchFields()
571 public void setSearchFields( Map<String, String> searchFields )
573 this.searchFields = searchFields;
576 public String getInfoMessage()
581 public void setInfoMessage( String infoMessage )
583 this.infoMessage = infoMessage;