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
63 // FIXME olamy WTF here??
64 private ArchivaConfiguration archivaConfiguration;
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;
99 private int rowCount = 30;
101 private String repositoryId;
103 private boolean fromFilterSearch;
105 private boolean filterSearch = false;
107 private boolean fromResultsPage;
110 private RepositorySearch nexusSearch;
112 private Map<String, String> searchFields;
114 private String infoMessage;
116 public boolean isFromResultsPage()
118 return fromResultsPage;
121 public void setFromResultsPage( boolean fromResultsPage )
123 this.fromResultsPage = fromResultsPage;
126 public boolean isFromFilterSearch()
128 return fromFilterSearch;
131 public void setFromFilterSearch( boolean fromFilterSearch )
133 this.fromFilterSearch = fromFilterSearch;
136 public void prepare()
138 managedRepositoryList = getObservableRepos();
140 if ( managedRepositoryList.size() > 0 )
142 managedRepositoryList.add( "all" );
145 searchFields = new LinkedHashMap<String, String>();
146 searchFields.put( "groupId", "Group ID" );
147 searchFields.put( "artifactId", "Artifact ID" );
148 searchFields.put( "version", "Version" );
149 searchFields.put( "className", "Class/Package Name" );
150 searchFields.put( "rowCount", "Row Count" );
152 super.clearErrorsAndMessages();
156 private void clearSearchFields()
167 // advanced search MRM-90 -- filtered search
168 public String filteredSearch()
169 throws MalformedURLException
171 if ( ( groupId == null || "".equals( groupId ) ) && ( artifactId == null || "".equals( artifactId ) )
172 && ( className == null || "".equals( className ) ) && ( version == null || "".equals( version ) ) )
174 addActionError( "Advanced Search - At least one search criteria must be provided." );
178 fromFilterSearch = true;
180 if ( CollectionUtils.isEmpty( managedRepositoryList ) )
182 return GlobalResults.ACCESS_TO_NO_REPOS;
185 SearchResultLimits limits = new SearchResultLimits( currentPage );
186 limits.setPageSize( rowCount );
187 List<String> selectedRepos = new ArrayList<String>();
189 if ( repositoryId == null || StringUtils.isBlank( repositoryId ) || "all".equals(
190 StringUtils.stripToEmpty( repositoryId ) ) )
192 selectedRepos = getObservableRepos();
196 selectedRepos.add( repositoryId );
199 if ( CollectionUtils.isEmpty( selectedRepos ) )
201 return GlobalResults.ACCESS_TO_NO_REPOS;
204 SearchFields searchFields = new SearchFields( groupId, artifactId, version, null, className, selectedRepos );
206 log.debug( "filteredSearch with searchFields {}", searchFields );
208 // TODO: add packaging in the list of fields for advanced search (UI)?
211 results = getNexusSearch().search( getPrincipal(), searchFields, limits );
213 catch ( RepositorySearchException e )
215 addActionError( e.getMessage() );
219 if ( results.isEmpty() )
221 addActionError( "No results found" );
225 totalPages = results.getTotalHits() / limits.getPageSize();
227 if ( ( results.getTotalHits() % limits.getPageSize() ) != 0 )
229 totalPages = totalPages + 1;
232 for ( SearchResultHit hit : results.getHits() )
234 final String version = hit.getVersion();
235 if ( version != null )
237 hit.setVersion( VersionUtil.getBaseVersion( version ) );
244 @SuppressWarnings( "unchecked" )
245 public String quickSearch()
246 throws MalformedURLException
248 /* TODO: give action message if indexing is in progress.
249 * This should be based off a count of 'unprocessed' artifacts.
250 * This (yet to be written) routine could tell the user that X (unprocessed) artifacts are not yet
251 * present in the full text search.
254 assert q != null && q.length() != 0;
256 fromFilterSearch = false;
258 SearchResultLimits limits = new SearchResultLimits( currentPage );
260 List<String> selectedRepos = getObservableRepos();
261 if ( CollectionUtils.isEmpty( selectedRepos ) )
263 return GlobalResults.ACCESS_TO_NO_REPOS;
266 log.debug( "quickSearch with selectedRepos {} query {}", selectedRepos, q );
270 if ( searchResultsOnly && !completeQueryString.equals( "" ) )
273 getNexusSearch().search( getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString() );
277 completeQueryString = "";
278 results = getNexusSearch().search( getPrincipal(), selectedRepos, q, limits, null );
281 catch ( RepositorySearchException e )
283 addActionError( e.getMessage() );
287 if ( results.isEmpty() )
289 addActionError( "No results found" );
293 totalPages = results.getTotalHits() / limits.getPageSize();
295 if ( ( results.getTotalHits() % limits.getPageSize() ) != 0 )
297 totalPages = totalPages + 1;
300 if ( !isEqualToPreviousSearchTerm( q ) )
302 buildCompleteQueryString( q );
308 public String findArtifact()
311 // TODO: give action message if indexing is in progress
313 if ( StringUtils.isBlank( q ) )
315 addActionError( "Unable to search for a blank checksum" );
319 databaseResults = new ArrayList<ArtifactMetadata>();
320 RepositorySession repositorySession = repositorySessionFactory.createSession();
323 MetadataRepository metadataRepository = repositorySession.getRepository();
324 for ( String repoId : getObservableRepos() )
326 databaseResults.addAll( metadataRepository.getArtifactsByChecksum( repoId, q ) );
331 repositorySession.close();
334 if ( databaseResults.isEmpty() )
336 addActionError( "No results found" );
340 if ( databaseResults.size() == 1 )
342 // 1 hit? return it's information directly!
349 public String doInput()
354 private void buildCompleteQueryString( String searchTerm )
356 if ( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
358 searchTerm = StringUtils.remove( searchTerm, COMPLETE_QUERY_STRING_SEPARATOR );
361 if ( completeQueryString == null || "".equals( completeQueryString ) )
363 completeQueryString = searchTerm;
367 completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
371 private List<String> parseCompleteQueryString()
373 List<String> parsedCompleteQueryString = new ArrayList<String>();
374 String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
375 CollectionUtils.addAll( parsedCompleteQueryString, parsed );
377 return parsedCompleteQueryString;
380 private boolean isEqualToPreviousSearchTerm( String searchTerm )
382 if ( !"".equals( completeQueryString ) )
384 String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
385 if ( StringUtils.equalsIgnoreCase( searchTerm, parsed[parsed.length - 1] ) )
399 public void setQ( String q )
404 public SearchResults getResults()
409 public List<ArtifactMetadata> getDatabaseResults()
411 return databaseResults;
414 public void setCurrentPage( int page )
416 this.currentPage = page;
419 public int getCurrentPage()
424 public int getTotalPages()
429 public void setTotalPages( int totalPages )
431 this.totalPages = totalPages;
434 public boolean isSearchResultsOnly()
436 return searchResultsOnly;
439 public void setSearchResultsOnly( boolean searchResultsOnly )
441 this.searchResultsOnly = searchResultsOnly;
444 public String getCompleteQueryString()
446 return completeQueryString;
449 public void setCompleteQueryString( String completeQueryString )
451 this.completeQueryString = completeQueryString;
454 public ArchivaConfiguration getArchivaConfiguration()
456 return archivaConfiguration;
459 public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
461 this.archivaConfiguration = archivaConfiguration;
464 public Map<String, ManagedRepositoryConfiguration> getManagedRepositories()
466 return getArchivaConfiguration().getConfiguration().getManagedRepositoriesAsMap();
469 public void setManagedRepositories( Map<String, ManagedRepositoryConfiguration> managedRepositories )
473 public String getGroupId()
478 public void setGroupId( String groupId )
480 this.groupId = groupId;
483 public String getArtifactId()
488 public void setArtifactId( String artifactId )
490 this.artifactId = artifactId;
493 public String getVersion()
498 public void setVersion( String version )
500 this.version = version;
503 public int getRowCount()
508 public void setRowCount( int rowCount )
510 this.rowCount = rowCount;
513 public boolean isFilterSearch()
518 public void setFilterSearch( boolean filterSearch )
520 this.filterSearch = filterSearch;
523 public String getRepositoryId()
528 public void setRepositoryId( String repositoryId )
530 this.repositoryId = repositoryId;
533 public List<String> getManagedRepositoryList()
535 return managedRepositoryList;
538 public void setManagedRepositoryList( List<String> managedRepositoryList )
540 this.managedRepositoryList = managedRepositoryList;
543 public String getClassName()
548 public void setClassName( String className )
550 this.className = className;
553 public RepositorySearch getNexusSearch()
555 if ( nexusSearch == null )
557 WebApplicationContext wac =
558 WebApplicationContextUtils.getRequiredWebApplicationContext( ServletActionContext.getServletContext() );
559 nexusSearch = wac.getBean( "nexusSearch", RepositorySearch.class );
564 public void setNexusSearch( RepositorySearch nexusSearch )
566 this.nexusSearch = nexusSearch;
569 public Map<String, String> getSearchFields()
574 public void setSearchFields( Map<String, String> searchFields )
576 this.searchFields = searchFields;
579 public String getInfoMessage()
584 public void setInfoMessage( String infoMessage )
586 this.infoMessage = infoMessage;