This project has retired. For details please refer to its Attic page.
DefaultSearchService xref
View Javadoc
1   package org.apache.archiva.rest.services;
2   
3   /*
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
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
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
19   * under the License.
20   */
21  
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;
44  
45  import javax.inject.Inject;
46  import javax.ws.rs.core.Response;
47  import java.net.URI;
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;
54  import java.util.Set;
55  import java.util.TreeMap;
56  
57  /**
58   * @author Olivier Lamy
59   */
60  @Service( "searchService#rest" )
61  public class DefaultSearchService
62      extends AbstractRestService
63      implements SearchService
64  {
65  
66      private static final String LATEST_KEYWORD = "LATEST";
67  
68      @Inject
69      private RepositorySearch repositorySearch;
70  
71      @Inject
72      private RepositorySessionFactory repositorySessionFactory;
73  
74      @Override
75      public List<Artifact> quickSearch( String queryString )
76          throws ArchivaRestServiceException
77      {
78          if ( StringUtils.isBlank( queryString ) )
79          {
80              return Collections.emptyList( );
81          }
82  
83          SearchResultLimits limits = new SearchResultLimits( 0 );
84          try
85          {
86              SearchResults searchResults =
87                  repositorySearch.search( getPrincipal( ), getObservableRepos( ), queryString, limits,
88                      Collections.<String>emptyList( ) );
89              return getArtifacts( searchResults );
90  
91          }
92          catch ( RepositorySearchException e )
93          {
94              log.error( e.getMessage( ), e );
95              throw new ArchivaRestServiceException( e.getMessage( ), e );
96          }
97      }
98  
99      @Override
100     public List<Artifact> quickSearchWithRepositories( SearchRequest searchRequest )
101         throws ArchivaRestServiceException
102     {
103         String queryString = searchRequest.getQueryTerms( );
104         if ( StringUtils.isBlank( queryString ) )
105         {
106             return Collections.emptyList( );
107         }
108         List<String> repositories = searchRequest.getRepositories( );
109         if ( repositories == null || repositories.isEmpty( ) )
110         {
111             repositories = getObservableRepos( );
112         }
113         SearchResultLimits limits =
114             new SearchResultLimits( searchRequest.getPageSize( ), searchRequest.getSelectedPage( ) );
115         try
116         {
117             SearchResults searchResults = repositorySearch.search( getPrincipal( ), repositories, queryString, limits,
118                 Collections.<String>emptyList( ) );
119             return getArtifacts( searchResults );
120 
121         }
122         catch ( RepositorySearchException e )
123         {
124             log.error( e.getMessage( ), e );
125             throw new ArchivaRestServiceException( e.getMessage( ), e );
126         }
127     }
128 
129     @Override
130     public List<Artifact> getArtifactVersions( String groupId, String artifactId, String packaging )
131         throws ArchivaRestServiceException
132     {
133         if ( StringUtils.isBlank( groupId ) || StringUtils.isBlank( artifactId ) )
134         {
135             return Collections.emptyList( );
136         }
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( ) );
142 
143         try
144         {
145             SearchResults searchResults = repositorySearch.search( getPrincipal( ), searchField, null );
146             return getArtifacts( searchResults );
147         }
148         catch ( RepositorySearchException e )
149         {
150             log.error( e.getMessage( ), e );
151             throw new ArchivaRestServiceException( e.getMessage( ), e );
152         }
153     }
154 
155     @Override
156     public List<Artifact> searchArtifacts( SearchRequest searchRequest )
157         throws ArchivaRestServiceException
158     {
159         if ( searchRequest == null )
160         {
161             return Collections.emptyList( );
162         }
163         SearchFields searchField = getModelMapper( ).map( searchRequest, SearchFields.class );
164         SearchResultLimits limits = new SearchResultLimits( 0 );
165         limits.setPageSize( searchRequest.getPageSize( ) );
166 
167         // if no repos set we use ones available for the user
168         if ( searchField.getRepositories( ) == null || searchField.getRepositories( ).isEmpty( ) )
169         {
170             searchField.setRepositories( getObservableRepos( ) );
171         }
172 
173         try
174         {
175             SearchResults searchResults = repositorySearch.search( getPrincipal( ), searchField, limits );
176             return getArtifacts( searchResults );
177         }
178         catch ( RepositorySearchException e )
179         {
180             log.error( e.getMessage( ), e );
181             throw new ArchivaRestServiceException( e.getMessage( ), e );
182         }
183     }
184 
185     @Override
186     public GroupIdList getAllGroupIds( List<String> selectedRepos )
187         throws ArchivaRestServiceException
188     {
189         List<String> observableRepos = getObservableRepos( );
190         List<String> repos = ListUtils.intersection( observableRepos, selectedRepos );
191         if ( repos == null || repos.isEmpty( ) )
192         {
193             return new GroupIdList( Collections.<String>emptyList( ) );
194         }
195         try
196         {
197             return new GroupIdList( new ArrayList<>( repositorySearch.getAllGroupIds( getPrincipal( ), repos ) ) );
198         }
199         catch ( RepositorySearchException e )
200         {
201             log.error( e.getMessage( ), e );
202             throw new ArchivaRestServiceException( e.getMessage( ), e );
203         }
204 
205     }
206 
207 
208     public List<Artifact> getArtifactByChecksum( ChecksumSearch checksumSearch )
209         throws ArchivaRestServiceException
210     {
211 
212         // if no repos set we use ones available for the user
213         if ( checksumSearch.getRepositories( ) == null || checksumSearch.getRepositories( ).isEmpty( ) )
214         {
215             checksumSearch.setRepositories( getObservableRepos( ) );
216         }
217 
218         RepositorySession repositorySession = repositorySessionFactory.createSession( );
219 
220         MetadataRepository metadataRepository = repositorySession.getRepository( );
221 
222         Set<Artifact> artifactSet = new HashSet<>( );
223 
224         try
225         {
226             for ( String repoId : checksumSearch.getRepositories( ) )
227             {
228                 Collection<ArtifactMetadata> artifactMetadatas =
229                     metadataRepository.getArtifactsByChecksum( repoId, checksumSearch.getChecksum( ) );
230                 artifactSet.addAll( buildArtifacts( artifactMetadatas, repoId ) );
231             }
232 
233             return new ArrayList<>( artifactSet );
234 
235         }
236         catch ( MetadataRepositoryException e )
237         {
238             log.error( e.getMessage( ), e );
239             throw new ArchivaRestServiceException( e.getMessage( ), e );
240         }
241         finally
242         {
243             repositorySession.closeQuietly( );
244         }
245 
246 
247     }
248 
249     @Override
250     public StringList getObservablesRepoIds( )
251         throws ArchivaRestServiceException
252     {
253         return new StringList( getObservableRepos( ) );
254     }
255 
256     @Override
257     public Response redirectToArtifactFile( String repositoryId, String groupId, String artifactId, String version,
258                                             String packaging, String classifier, Boolean literalVersion )
259         throws ArchivaRestServiceException
260     {
261         try
262         {
263             // validate query
264 
265             if ( StringUtils.isEmpty( groupId ) )
266             {
267                 return Response.status( new Response.StatusType( )
268                 {
269                     @Override
270                     public int getStatusCode( )
271                     {
272                         return Response.Status.BAD_REQUEST.getStatusCode( );
273                     }
274 
275                     @Override
276                     public Response.Status.Family getFamily( )
277                     {
278                         return Response.Status.BAD_REQUEST.getFamily( );
279                     }
280 
281                     @Override
282                     public String getReasonPhrase( )
283                     {
284                         return "groupId mandatory";
285                     }
286                 } ).build( );
287             }
288 
289             if ( StringUtils.isEmpty( version ) )
290             {
291                 return Response.status( new Response.StatusType( )
292                 {
293                     @Override
294                     public int getStatusCode( )
295                     {
296                         return Response.Status.BAD_REQUEST.getStatusCode( );
297                     }
298 
299                     @Override
300                     public Response.Status.Family getFamily( )
301                     {
302                         return Response.Status.BAD_REQUEST.getFamily( );
303                     }
304 
305                     @Override
306                     public String getReasonPhrase( )
307                     {
308                         return "version mandatory";
309                     }
310                 } ).build( );
311             }
312 
313             if ( StringUtils.isEmpty( artifactId ) )
314             {
315                 return Response.status( new Response.StatusType( )
316                 {
317                     @Override
318                     public int getStatusCode( )
319                     {
320                         return Response.Status.BAD_REQUEST.getStatusCode( );
321                     }
322 
323                     @Override
324                     public Response.Status.Family getFamily( )
325                     {
326                         return Response.Status.BAD_REQUEST.getFamily( );
327                     }
328 
329                     @Override
330                     public String getReasonPhrase( )
331                     {
332                         return "artifactId mandatory";
333                     }
334                 } ).build( );
335             }
336 
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 ) )
342             {
343                 searchField.setVersion( version );
344             }
345             searchField.setClassifier( classifier );
346             List<String> userRepos = getObservablesRepoIds( ).getStrings( );
347             searchField.setRepositories(
348                 StringUtils.isEmpty( repositoryId ) ? userRepos : Arrays.asList( repositoryId ) );
349             log.debug( "Searching repository {}", repositoryId );
350             searchField.setExactSearch( true );
351             SearchResults searchResults = repositorySearch.search( getPrincipal( ), searchField, null );
352             List<Artifact> artifacts = getArtifacts( searchResults, repositoryId );
353 
354             if ( artifacts.isEmpty( ) )
355             {
356                 return Response.status( new Response.StatusType( )
357                 {
358                     @Override
359                     public int getStatusCode( )
360                     {
361                         return Response.Status.NO_CONTENT.getStatusCode( );
362                     }
363 
364                     @Override
365                     public Response.Status.Family getFamily( )
366                     {
367                         return Response.Status.NO_CONTENT.getFamily( );
368                     }
369 
370                     @Override
371                     public String getReasonPhrase( )
372                     {
373                         return "your query doesn't return any artifact";
374                     }
375                 } ).build( );
376             }
377 
378             // TODO improve that with querying lucene with null value for classifier
379             // so simple loop and retain only artifact with null classifier
380             if ( classifier == null )
381             {
382                 List<Artifact> filteredArtifacts = new ArrayList<>( artifacts.size( ) );
383                 for ( Artifact artifact : artifacts )
384                 {
385                     if ( artifact.getClassifier( ) == null )
386                     {
387                         filteredArtifacts.add( artifact );
388                     }
389                 }
390 
391                 artifacts = filteredArtifacts;
392             }
393 
394             // TODO return json result of the query ?
395             if ( artifacts.size( ) > 1 && ( literalVersion || !StringUtils.equals( version, LATEST_KEYWORD ) ) )
396             {
397                 return Response.status( new Response.StatusType( )
398                 {
399                     @Override
400                     public int getStatusCode( )
401                     {
402                         return Response.Status.BAD_REQUEST.getStatusCode( );
403                     }
404 
405                     @Override
406                     public Response.Status.Family getFamily( )
407                     {
408                         return Response.Status.BAD_REQUEST.getFamily( );
409                     }
410 
411                     @Override
412                     public String getReasonPhrase( )
413                     {
414                         return "your query return more than one artifact";
415                     }
416                 } ).build( );
417             }
418 
419             // version is LATEST so we have to find the latest one from the result
420             if ( !literalVersion && ( artifacts.size( ) > 1 && StringUtils.equals( version, LATEST_KEYWORD ) ) )
421             {
422                 TreeMap<String, Artifact> artifactPerVersion = new TreeMap<>( VersionComparator.getInstance( ) );
423 
424                 for ( Artifact artifact : artifacts )
425                 {
426                     artifactPerVersion.put( artifact.getVersion( ), artifact );
427                 }
428 
429                 return Response.temporaryRedirect(
430                     new URI( artifactPerVersion.lastEntry( ).getValue( ).getUrl( ) ) ).build( );
431 
432             }
433 
434             Artifact artifact = artifacts.get( 0 );
435             log.debug( "Returning artifact {}, {}", artifact.getUrl( ), artifact.getRepositoryId( ) );
436             return Response.temporaryRedirect( new URI( artifact.getUrl( ) ) ).build( );
437         }
438         catch ( Exception e )
439         {
440             throw new ArchivaRestServiceException( e.getMessage( ), e );
441         }
442     }
443 
444     protected List<Artifact> getArtifacts( SearchResults searchResults )
445            throws ArchivaRestServiceException
446     {
447         return getArtifacts( searchResults, null );
448     }
449 
450     //-------------------------------------
451     // internal
452     //-------------------------------------
453     protected List<Artifact> getArtifacts( SearchResults searchResults, String repositoryId )
454         throws ArchivaRestServiceException
455     {
456 
457         if ( searchResults == null || searchResults.isEmpty() )
458         {
459             return Collections.emptyList();
460         }
461         List<Artifact> artifacts = new ArrayList<>( searchResults.getReturnedHitsCount() );
462         for ( SearchResultHit hit : searchResults.getHits() )
463         {
464             // duplicate Artifact one per available version
465             if ( hit.getVersions().size() > 0 )
466             {
467                 for ( String version : hit.getVersions() )
468                 {
469 
470                     Artifact versionned = getModelMapper().map( hit, Artifact.class );
471 
472                     if ( StringUtils.isNotBlank( version ) )
473                     {
474                         versionned.setVersion( version );
475                         versionned.setUrl( getArtifactUrl( versionned, repositoryId ) );
476 
477                         artifacts.add( versionned );
478 
479                     }
480                 }
481             }
482         }
483         return artifacts;
484     }
485 
486 
487 }