1 package org.apache.archiva.rest.services;
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 org.apache.archiva.common.utils.VersionComparator;
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.maven2.model.Artifact;
30 import org.apache.archiva.metadata.model.ArtifactMetadata;
31 import org.apache.archiva.metadata.repository.MetadataRepository;
32 import org.apache.archiva.metadata.repository.MetadataRepositoryException;
33 import org.apache.archiva.metadata.repository.RepositorySession;
34 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
35 import org.apache.archiva.rest.api.model.ChecksumSearch;
36 import org.apache.archiva.rest.api.model.GroupIdList;
37 import org.apache.archiva.rest.api.model.SearchRequest;
38 import org.apache.archiva.rest.api.model.StringList;
39 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
40 import org.apache.archiva.rest.api.services.SearchService;
41 import org.apache.commons.collections.ListUtils;
42 import org.apache.commons.lang.StringUtils;
43 import org.springframework.stereotype.Service;
45 import javax.inject.Inject;
46 import javax.ws.rs.core.Response;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.Collection;
51 import java.util.Collections;
52 import java.util.HashSet;
53 import java.util.List;
55 import java.util.TreeMap;
58 * @author Olivier Lamy
60 @Service( "searchService#rest" )
61 public class DefaultSearchService
62 extends AbstractRestService
63 implements SearchService
66 private static final String LATEST_KEYWORD = "LATEST";
69 private RepositorySearch repositorySearch;
72 private RepositorySessionFactory repositorySessionFactory;
75 public List<Artifact> quickSearch( String queryString )
76 throws ArchivaRestServiceException
78 if ( StringUtils.isBlank( queryString ) )
80 return Collections.emptyList();
83 SearchResultLimits limits = new SearchResultLimits( 0 );
86 SearchResults searchResults =
87 repositorySearch.search( getPrincipal(), getObservableRepos(), queryString, limits,
88 Collections.<String>emptyList() );
89 return getArtifacts( searchResults );
92 catch ( RepositorySearchException e )
94 log.error( e.getMessage(), e );
95 throw new ArchivaRestServiceException( e.getMessage(), e );
100 public List<Artifact> quickSearchWithRepositories( SearchRequest searchRequest )
101 throws ArchivaRestServiceException
103 String queryString = searchRequest.getQueryTerms();
104 if ( StringUtils.isBlank( queryString ) )
106 return Collections.emptyList();
108 List<String> repositories = searchRequest.getRepositories();
109 if ( repositories == null || repositories.isEmpty() )
111 repositories = getObservableRepos();
113 SearchResultLimits limits =
114 new SearchResultLimits( searchRequest.getPageSize(), searchRequest.getSelectedPage() );
117 SearchResults searchResults = repositorySearch.search( getPrincipal(), repositories, queryString, limits,
118 Collections.<String>emptyList() );
119 return getArtifacts( searchResults );
122 catch ( RepositorySearchException e )
124 log.error( e.getMessage(), e );
125 throw new ArchivaRestServiceException( e.getMessage(), e );
130 public List<Artifact> getArtifactVersions( String groupId, String artifactId, String packaging )
131 throws ArchivaRestServiceException
133 if ( StringUtils.isBlank( groupId ) || StringUtils.isBlank( artifactId ) )
135 return Collections.emptyList();
137 SearchFields searchField = new SearchFields();
138 searchField.setGroupId( groupId );
139 searchField.setArtifactId( artifactId );
140 searchField.setPackaging( StringUtils.isBlank( packaging ) ? "jar" : packaging );
141 searchField.setRepositories( getObservableRepos() );
145 SearchResults searchResults = repositorySearch.search( getPrincipal(), searchField, null );
146 return getArtifacts( searchResults );
148 catch ( RepositorySearchException e )
150 log.error( e.getMessage(), e );
151 throw new ArchivaRestServiceException( e.getMessage(), e );
156 public List<Artifact> searchArtifacts( SearchRequest searchRequest )
157 throws ArchivaRestServiceException
159 if ( searchRequest == null )
161 return Collections.emptyList();
163 SearchFields searchField = getModelMapper().map( searchRequest, SearchFields.class );
164 SearchResultLimits limits = new SearchResultLimits( 0 );
165 limits.setPageSize( searchRequest.getPageSize() );
167 // if no repos set we use ones available for the user
168 if ( searchField.getRepositories() == null || searchField.getRepositories().isEmpty() )
170 searchField.setRepositories( getObservableRepos() );
175 SearchResults searchResults = repositorySearch.search( getPrincipal(), searchField, limits );
176 return getArtifacts( searchResults );
178 catch ( RepositorySearchException e )
180 log.error( e.getMessage(), e );
181 throw new ArchivaRestServiceException( e.getMessage(), e );
186 public GroupIdList getAllGroupIds( List<String> selectedRepos )
187 throws ArchivaRestServiceException
189 List<String> observableRepos = getObservableRepos();
190 List<String> repos = ListUtils.intersection( observableRepos, selectedRepos );
191 if ( repos == null || repos.isEmpty() )
193 return new GroupIdList( Collections.<String>emptyList() );
197 return new GroupIdList( new ArrayList<>( repositorySearch.getAllGroupIds( getPrincipal(), repos ) ) );
199 catch ( RepositorySearchException e )
201 log.error( e.getMessage(), e );
202 throw new ArchivaRestServiceException( e.getMessage(), e );
208 public List<Artifact> getArtifactByChecksum( ChecksumSearch checksumSearch )
209 throws ArchivaRestServiceException
212 // if no repos set we use ones available for the user
213 if ( checksumSearch.getRepositories() == null || checksumSearch.getRepositories().isEmpty() )
215 checksumSearch.setRepositories( getObservableRepos() );
218 RepositorySession repositorySession = repositorySessionFactory.createSession();
220 MetadataRepository metadataRepository = repositorySession.getRepository();
222 Set<Artifact> artifactSet = new HashSet<>();
226 for ( String repoId : checksumSearch.getRepositories() )
228 Collection<ArtifactMetadata> artifactMetadatas =
229 metadataRepository.getArtifactsByChecksum( repoId, checksumSearch.getChecksum() );
230 artifactSet.addAll( buildArtifacts( artifactMetadatas, repoId ) );
233 return new ArrayList<>( artifactSet );
236 catch ( MetadataRepositoryException e )
238 log.error( e.getMessage(), e );
239 throw new ArchivaRestServiceException( e.getMessage(), e );
243 repositorySession.closeQuietly();
250 public StringList getObservablesRepoIds()
251 throws ArchivaRestServiceException
253 return new StringList( getObservableRepos() );
257 public Response redirectToArtifactFile( String repositoryId, String groupId, String artifactId, String version,
258 String packaging, String classifier, Boolean literalVersion )
259 throws ArchivaRestServiceException
265 if ( StringUtils.isEmpty( groupId ) )
267 return Response.status( new Response.StatusType()
270 public int getStatusCode()
272 return Response.Status.BAD_REQUEST.getStatusCode();
276 public Response.Status.Family getFamily()
278 return Response.Status.BAD_REQUEST.getFamily();
282 public String getReasonPhrase()
284 return "groupId mandatory";
289 if ( StringUtils.isEmpty( version ) )
291 return Response.status( new Response.StatusType()
294 public int getStatusCode()
296 return Response.Status.BAD_REQUEST.getStatusCode();
300 public Response.Status.Family getFamily()
302 return Response.Status.BAD_REQUEST.getFamily();
306 public String getReasonPhrase()
308 return "version mandatory";
313 if ( StringUtils.isEmpty( artifactId ) )
315 return Response.status( new Response.StatusType()
318 public int getStatusCode()
320 return Response.Status.BAD_REQUEST.getStatusCode();
324 public Response.Status.Family getFamily()
326 return Response.Status.BAD_REQUEST.getFamily();
330 public String getReasonPhrase()
332 return "artifactId mandatory";
337 SearchFields searchField = new SearchFields();
338 searchField.setGroupId( groupId );
339 searchField.setArtifactId( artifactId );
340 searchField.setPackaging( StringUtils.isBlank( packaging ) ? "jar" : packaging );
341 if ( literalVersion.booleanValue() || !StringUtils.equals( version, LATEST_KEYWORD ) )
343 searchField.setVersion( version );
345 searchField.setClassifier( classifier );
346 List<String> userRepos = getObservablesRepoIds().getStrings();
347 searchField.setRepositories(
348 StringUtils.isEmpty( repositoryId ) ? userRepos : Arrays.asList( repositoryId ) );
349 searchField.setExactSearch( true );
350 SearchResults searchResults = repositorySearch.search( getPrincipal(), searchField, null );
351 List<Artifact> artifacts = getArtifacts( searchResults );
353 if ( artifacts.isEmpty() )
355 return Response.status( new Response.StatusType()
358 public int getStatusCode()
360 return Response.Status.NO_CONTENT.getStatusCode();
364 public Response.Status.Family getFamily()
366 return Response.Status.NO_CONTENT.getFamily();
370 public String getReasonPhrase()
372 return "your query doesn't return any artifact";
377 // TODO improve that with querying lucene with null value for classifier
378 // so simple loop and retain only artifact with null classifier
379 if ( classifier == null )
381 List<Artifact> filteredArtifacts = new ArrayList<>( artifacts.size() );
382 for ( Artifact artifact : artifacts )
384 if ( artifact.getClassifier() == null )
386 filteredArtifacts.add( artifact );
390 artifacts = filteredArtifacts;
393 // TODO return json result of the query ?
394 if ( artifacts.size() > 1 && !StringUtils.equals( version, LATEST_KEYWORD ) )
396 return Response.status( new Response.StatusType()
399 public int getStatusCode()
401 return Response.Status.BAD_REQUEST.getStatusCode();
405 public Response.Status.Family getFamily()
407 return Response.Status.BAD_REQUEST.getFamily();
411 public String getReasonPhrase()
413 return "your query return more than one artifact";
418 // version is LATEST so we have to find the latest one from the result
419 if ( artifacts.size() > 1 && StringUtils.equals( version, LATEST_KEYWORD ) )
421 TreeMap<String, Artifact> artifactPerVersion = new TreeMap<>( VersionComparator.getInstance() );
423 for ( Artifact artifact : artifacts )
425 artifactPerVersion.put( artifact.getVersion(), artifact );
428 return Response.temporaryRedirect(
429 new URI( artifactPerVersion.lastEntry().getValue().getUrl() ) ).build();
433 Artifact artifact = artifacts.get( 0 );
435 return Response.temporaryRedirect( new URI( artifact.getUrl() ) ).build();
437 catch ( Exception e )
439 throw new ArchivaRestServiceException( e.getMessage(), e );
444 //-------------------------------------
446 //-------------------------------------
447 protected List<Artifact> getArtifacts( SearchResults searchResults )
448 throws ArchivaRestServiceException
451 if ( searchResults == null || searchResults.isEmpty() )
453 return Collections.emptyList();
455 List<Artifact> artifacts = new ArrayList<>( searchResults.getReturnedHitsCount() );
456 for ( SearchResultHit hit : searchResults.getHits() )
458 // duplicate Artifact one per available version
459 if ( hit.getVersions().size() > 0 )
461 for ( String version : hit.getVersions() )
464 Artifact versionned = getModelMapper().map( hit, Artifact.class );
466 if ( StringUtils.isNotBlank( version ) )
468 versionned.setVersion( version );
469 versionned.setUrl( getArtifactUrl( versionned ) );
471 artifacts.add( versionned );