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( );
201 clearSearchFields( );
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( "" ) )
351 getNexusSearch( ).search( getPrincipal( ), selectedRepos, q, limits, parseCompleteQueryString( ) );
355 completeQueryString = "";
356 results = getNexusSearch( ).search( getPrincipal( ), selectedRepos, q, limits, null );
359 catch ( RepositorySearchException e )
361 addActionError( e.getMessage( ) );
365 if ( results.isEmpty( ) )
367 addActionError( "No results found" );
371 totalPages = results.getTotalHits( ) / limits.getPageSize( );
373 if ( ( results.getTotalHits( ) % limits.getPageSize( ) ) != 0 )
375 totalPages = totalPages + 1;
378 if ( !isEqualToPreviousSearchTerm( q ) )
380 buildCompleteQueryString( q );
386 public String findArtifact( )
389 // TODO: give action message if indexing is in progress
391 if ( StringUtils.isBlank( q ) )
393 addActionError( "Unable to search for a blank checksum" );
397 databaseResults = new ArrayList<ArtifactMetadata>( );
398 RepositorySession repositorySession = repositorySessionFactory.createSession( );
401 MetadataRepository metadataRepository = repositorySession.getRepository( );
402 for ( String repoId : getObservableRepos( ) )
404 databaseResults.addAll( metadataRepository.getArtifactsByChecksum( repoId, q ) );
409 repositorySession.close( );
412 if ( databaseResults.isEmpty( ) )
414 addActionError( "No results found" );
418 if ( databaseResults.size( ) == 1 )
420 // 1 hit? return it's information directly!
427 public String doInput( )
432 private void buildCompleteQueryString( String searchTerm )
434 if ( searchTerm.indexOf( COMPLETE_QUERY_STRING_SEPARATOR ) != -1 )
436 searchTerm = StringUtils.remove( searchTerm, COMPLETE_QUERY_STRING_SEPARATOR );
439 if ( completeQueryString == null || "".equals( completeQueryString ) )
441 completeQueryString = searchTerm;
445 completeQueryString = completeQueryString + COMPLETE_QUERY_STRING_SEPARATOR + searchTerm;
449 private List<String> parseCompleteQueryString( )
451 List<String> parsedCompleteQueryString = new ArrayList<String>( );
452 String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
453 CollectionUtils.addAll( parsedCompleteQueryString, parsed );
455 return parsedCompleteQueryString;
458 private boolean isEqualToPreviousSearchTerm( String searchTerm )
460 if ( !"".equals( completeQueryString ) )
462 String[] parsed = StringUtils.split( completeQueryString, COMPLETE_QUERY_STRING_SEPARATOR );
463 if ( StringUtils.equalsIgnoreCase( searchTerm, parsed[parsed.length - 1] ) )
472 public String getQ( )
477 public void setQ( String q )
482 public SearchResults getResults( )
487 public List<ArtifactMetadata> getDatabaseResults( )
489 return databaseResults;
492 public void setCurrentPage( int page )
494 this.currentPage = page;
497 public int getCurrentPage( )
502 public int getTotalPages( )
507 public void setTotalPages( int totalPages )
509 this.totalPages = totalPages;
512 public boolean isSearchResultsOnly( )
514 return searchResultsOnly;
517 public void setSearchResultsOnly( boolean searchResultsOnly )
519 this.searchResultsOnly = searchResultsOnly;
522 public String getCompleteQueryString( )
524 return completeQueryString;
527 public void setCompleteQueryString( String completeQueryString )
529 this.completeQueryString = completeQueryString;
532 public Map<String, ManagedRepository> getManagedRepositories( )
533 throws RepositoryAdminException
535 return managedRepositoryAdmin.getManagedRepositoriesAsMap( );
538 // wtf : does nothing ??
539 public void setManagedRepositories( Map<String, ManagedRepository> managedRepositories )
543 public String getGroupId( )
548 public void setGroupId( String groupId )
550 this.groupId = groupId;
553 public String getArtifactId( )
558 public void setArtifactId( String artifactId )
560 this.artifactId = artifactId;
563 public String getVersion( )
568 public void setVersion( String version )
570 this.version = version;
573 public int getRowCount( )
578 public void setRowCount( int rowCount )
580 this.rowCount = rowCount;
583 public boolean isFilterSearch( )
588 public void setFilterSearch( boolean filterSearch )
590 this.filterSearch = filterSearch;
593 public String getRepositoryId( )
598 public void setRepositoryId( String repositoryId )
600 this.repositoryId = repositoryId;
603 public List<String> getManagedRepositoryList( )
605 return managedRepositoryList;
608 public void setManagedRepositoryList( List<String> managedRepositoryList )
610 this.managedRepositoryList = managedRepositoryList;
613 public String getClassName( )
618 public void setClassName( String className )
620 this.className = className;
623 public RepositorySearch getNexusSearch( )
625 if ( nexusSearch == null )
627 WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(
628 ServletActionContext.getServletContext( ) );
629 nexusSearch = wac.getBean( "nexusSearch", RepositorySearch.class );
634 public void setNexusSearch( RepositorySearch nexusSearch )
636 this.nexusSearch = nexusSearch;
639 public Map<String, String> getSearchFields( )
644 public void setSearchFields( Map<String, String> searchFields )
646 this.searchFields = searchFields;
649 public String getInfoMessage( )
654 public void setInfoMessage( String infoMessage )
656 this.infoMessage = infoMessage;
659 public ManagedRepositoryAdmin getManagedRepositoryAdmin( )
661 return managedRepositoryAdmin;
664 public void setManagedRepositoryAdmin( ManagedRepositoryAdmin managedRepositoryAdmin )
666 this.managedRepositoryAdmin = managedRepositoryAdmin;
669 public String getBundleVersion( )
671 return bundleVersion;
674 public void setBundleVersion( String bundleVersion )
676 this.bundleVersion = bundleVersion;
679 public String getBundleSymbolicName( )
681 return bundleSymbolicName;
684 public void setBundleSymbolicName( String bundleSymbolicName )
686 this.bundleSymbolicName = bundleSymbolicName;
689 public String getBundleExportPackage( )
691 return bundleExportPackage;
694 public void setBundleExportPackage( String bundleExportPackage )
696 this.bundleExportPackage = bundleExportPackage;
699 public String getBundleImportPackage( )
701 return bundleImportPackage;
704 public void setBundleImportPackage( String bundleImportPackage )
706 this.bundleImportPackage = bundleImportPackage;
709 public String getBundleName( )
714 public void setBundleName( String bundleName )
716 this.bundleName = bundleName;
719 public String getBundleExportService( )
721 return bundleExportService;
724 public void setBundleExportService( String bundleExportService )
726 this.bundleExportService = bundleExportService;