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 java.net.MalformedURLException;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.List;
28 import org.apache.archiva.indexer.util.SearchUtil;
29 import org.apache.commons.collections.CollectionUtils;
30 import org.apache.commons.lang.StringUtils;
31 import org.apache.maven.archiva.configuration.ArchivaConfiguration;
32 import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
33 import org.apache.maven.archiva.database.ArchivaDAO;
34 import org.apache.maven.archiva.database.Constraint;
35 import org.apache.maven.archiva.database.constraints.ArtifactsByChecksumConstraint;
36 import org.apache.maven.archiva.indexer.RepositoryIndexException;
37 import org.apache.maven.archiva.indexer.RepositoryIndexSearchException;
38 import org.apache.maven.archiva.indexer.search.CrossRepositorySearch;
39 import org.apache.maven.archiva.indexer.search.SearchResultLimits;
40 import org.apache.maven.archiva.indexer.search.SearchResults;
41 import org.apache.maven.archiva.security.AccessDeniedException;
42 import org.apache.maven.archiva.security.ArchivaSecurityException;
43 import org.apache.maven.archiva.security.ArchivaXworkUser;
44 import org.apache.maven.archiva.security.PrincipalNotFoundException;
45 import org.apache.maven.archiva.security.UserRepositories;
47 import com.opensymphony.xwork2.ActionContext;
48 import com.opensymphony.xwork2.Preparable;
51 * Search all indexed fields by the given criteria.
53 * @plexus.component role="com.opensymphony.xwork2.Action" role-hint="searchAction"
55 public class SearchAction
56 extends PlexusActionSupport
63 private ArchivaConfiguration archivaConfiguration;
65 private Map<String, ManagedRepositoryConfiguration> managedRepositories;
70 * @plexus.requirement role-hint="jdo"
72 private ArchivaDAO dao;
77 private SearchResults results;
80 * @plexus.requirement role-hint="default"
82 private CrossRepositorySearch crossRepoSearch;
87 private UserRepositories userRepositories;
92 private ArchivaXworkUser archivaXworkUser;
94 private static final String RESULTS = "results";
96 private static final String ARTIFACT = "artifact";
98 private List databaseResults;
100 private int currentPage = 0;
102 private int totalPages;
104 private boolean searchResultsOnly;
106 private String completeQueryString;
108 private static final String COMPLETE_QUERY_STRING_SEPARATOR = ";";
110 private List<String> managedRepositoryList;
112 private String groupId;
114 private String artifactId;
116 private String version;
118 private String className;
120 private int rowCount = 30;
122 private String repositoryId;
124 private boolean fromFilterSearch;
126 private boolean filterSearch = false;
128 private boolean fromResultsPage;
132 public boolean isFromResultsPage()
134 return fromResultsPage;
137 public void setFromResultsPage( boolean fromResultsPage )
139 this.fromResultsPage = fromResultsPage;
142 public boolean isFromFilterSearch()
144 return fromFilterSearch;
147 public void setFromFilterSearch( boolean fromFilterSearch )
149 this.fromFilterSearch = fromFilterSearch;
152 public void prepare()
154 managedRepositoryList = new ArrayList<String>();
155 managedRepositoryList = getObservableRepos();
157 if ( managedRepositoryList.size() > 0 )
159 managedRepositoryList.add( "all" );
163 // advanced search MRM-90 -- filtered search
164 public String filteredSearch()
165 throws MalformedURLException, RepositoryIndexException, RepositoryIndexSearchException
167 fromFilterSearch = true;
169 if ( CollectionUtils.isEmpty( managedRepositoryList ) )
171 return GlobalResults.ACCESS_TO_NO_REPOS;
174 SearchResultLimits limits = new SearchResultLimits( currentPage );
176 limits.setPageSize( rowCount );
177 List<String> selectedRepos = new ArrayList<String>();
179 if ( repositoryId.equals( "all" ) )
181 selectedRepos = getObservableRepos();
185 selectedRepos.add( repositoryId );
188 if ( CollectionUtils.isEmpty( selectedRepos ) )
190 return GlobalResults.ACCESS_TO_NO_REPOS;
194 crossRepoSearch.executeFilteredSearch( getPrincipal(), selectedRepos, groupId, artifactId, version,
197 if ( results.isEmpty() )
199 addActionError( "No results found" );
203 totalPages = results.getTotalHits() / limits.getPageSize();
205 if ( ( results.getTotalHits() % limits.getPageSize() ) != 0 )
207 totalPages = totalPages + 1;
213 public String quickSearch()
214 throws MalformedURLException, RepositoryIndexException, RepositoryIndexSearchException
216 /* TODO: give action message if indexing is in progress.
217 * This should be based off a count of 'unprocessed' artifacts.
218 * This (yet to be written) routine could tell the user that X (unprocessed) artifacts are not yet
219 * present in the full text search.
222 assert q != null && q.length() != 0;
224 fromFilterSearch = false;
226 SearchResultLimits limits = new SearchResultLimits( currentPage );
228 List<String> selectedRepos = getObservableRepos();
229 if ( CollectionUtils.isEmpty( selectedRepos ) )
231 return GlobalResults.ACCESS_TO_NO_REPOS;
234 if( SearchUtil.isBytecodeSearch( q ) )
236 results = crossRepoSearch.searchForBytecode( getPrincipal(), selectedRepos, SearchUtil.removeBytecodeKeyword( q ), limits );
240 if( searchResultsOnly && !completeQueryString.equals( "" ) )
242 results = crossRepoSearch.searchForTerm( getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString() );
246 completeQueryString = "";
247 results = crossRepoSearch.searchForTerm( getPrincipal(), selectedRepos, q, limits );
251 if ( results.isEmpty() )
253 addActionError( "No results found" );
257 totalPages = results.getTotalHits() / limits.getPageSize();
259 if( (results.getTotalHits() % limits.getPageSize()) != 0 )
261 totalPages = totalPages + 1;
263 // TODO: filter / combine the artifacts by version? (is that even possible with non-artifact hits?)
265 /* I don't think that we should, as I expect us to utilize the 'score' system in lucene in
266 * the future to return relevant links better.
267 * I expect the lucene scoring system to take multiple hits on different areas of a single document
268 * to result in a higher score.
272 if( !isEqualToPreviousSearchTerm( q ) )
274 buildCompleteQueryString( q );
280 public String findArtifact()
283 // TODO: give action message if indexing is in progress
285 if ( StringUtils.isBlank( q ) )
287 addActionError( "Unable to search for a blank checksum" );
291 Constraint constraint = new ArtifactsByChecksumConstraint( q );
292 databaseResults = dao.getArtifactDAO().queryArtifacts( constraint );
294 if ( databaseResults.isEmpty() )
296 addActionError( "No results found" );
300 if ( databaseResults.size() == 1 )
302 // 1 hit? return it's information directly!
309 public String doInput()
314 private String getPrincipal()
316 return archivaXworkUser.getActivePrincipal( ActionContext.getContext().getSession() );
319 private List<String> getObservableRepos()
323 return userRepositories.getObservableRepositoryIds( getPrincipal() );
325 catch ( PrincipalNotFoundException e )
327 getLogger().warn( e.getMessage(), e );
329 catch ( AccessDeniedException e )
331 getLogger().warn( e.getMessage(), e );
332 // TODO: pass this onto the screen.
334 catch ( ArchivaSecurityException e )
336 getLogger().warn( e.getMessage(), e );
338 return Collections.emptyList();
341 private void buildCompleteQueryString( String searchTerm )
343 if ( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
345 searchTerm = StringUtils.remove( searchTerm, COMPLETE_QUERY_STRING_SEPARATOR );
348 if ( completeQueryString == null || "".equals( completeQueryString ) )
350 completeQueryString = searchTerm;
354 completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
358 private List<String> parseCompleteQueryString()
360 List<String> parsedCompleteQueryString = new ArrayList<String>();
361 String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
362 CollectionUtils.addAll( parsedCompleteQueryString, parsed );
364 return parsedCompleteQueryString;
367 private boolean isEqualToPreviousSearchTerm( String searchTerm )
369 if ( !"".equals( completeQueryString ) )
371 String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
372 if ( StringUtils.equalsIgnoreCase( searchTerm, parsed[parsed.length - 1] ) )
386 public void setQ( String q )
391 public SearchResults getResults()
396 public List getDatabaseResults()
398 return databaseResults;
401 public void setCurrentPage( int page )
403 this.currentPage = page;
406 public int getCurrentPage()
411 public int getTotalPages()
416 public void setTotalPages( int totalPages )
418 this.totalPages = totalPages;
421 public boolean isSearchResultsOnly()
423 return searchResultsOnly;
426 public void setSearchResultsOnly( boolean searchResultsOnly )
428 this.searchResultsOnly = searchResultsOnly;
431 public String getCompleteQueryString()
433 return completeQueryString;
436 public void setCompleteQueryString( String completeQueryString )
438 this.completeQueryString = completeQueryString;
441 public ArchivaConfiguration getArchivaConfiguration()
443 return archivaConfiguration;
446 public void setArchivaConfiguration( ArchivaConfiguration archivaConfiguration )
448 this.archivaConfiguration = archivaConfiguration;
451 public Map<String, ManagedRepositoryConfiguration> getManagedRepositories()
453 return getArchivaConfiguration().getConfiguration().getManagedRepositoriesAsMap();
456 public void setManagedRepositories( Map<String, ManagedRepositoryConfiguration> managedRepositories )
458 this.managedRepositories = managedRepositories;
461 public String getGroupId()
466 public void setGroupId( String groupId )
468 this.groupId = groupId;
471 public String getArtifactId()
476 public void setArtifactId( String artifactId )
478 this.artifactId = artifactId;
481 public String getVersion()
486 public void setVersion( String version )
488 this.version = version;
491 public int getRowCount()
496 public void setRowCount( int rowCount )
498 this.rowCount = rowCount;
501 public boolean isFilterSearch()
506 public void setFilterSearch( boolean filterSearch )
508 this.filterSearch = filterSearch;
511 public String getRepositoryId()
516 public void setRepositoryId( String repositoryId )
518 this.repositoryId = repositoryId;
521 public List<String> getManagedRepositoryList()
523 return managedRepositoryList;
526 public void setManagedRepositoryList( List<String> managedRepositoryList )
528 this.managedRepositoryList = managedRepositoryList;
531 public String getClassName()
536 public void setClassName( String className )
538 this.className = className;