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.collections4.ListUtils;
42  import org.apache.commons.lang3.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          SearchResultLimitsrchResultLimits.html#SearchResultLimits">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         SearchFieldsarchFields.html#SearchFields">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         SearchResultLimitsrchResultLimits.html#SearchResultLimits">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 = null;
219         try
220         {
221             repositorySession = repositorySessionFactory.createSession();
222         }
223         catch ( MetadataRepositoryException e )
224         {
225             e.printStackTrace( );
226         }
227 
228         MetadataRepository metadataRepository = repositorySession.getRepository();
229 
230         Set<Artifact> artifactSet = new HashSet<>();
231 
232         try
233         {
234             for ( String repoId : checksumSearch.getRepositories() )
235             {
236                 Collection<ArtifactMetadata> artifactMetadatas =
237                     metadataRepository.getArtifactsByChecksum( repositorySession, repoId, checksumSearch.getChecksum() );
238                 artifactSet.addAll( buildArtifacts( artifactMetadatas, repoId ) );
239             }
240 
241             return new ArrayList<>( artifactSet );
242 
243         }
244         catch ( MetadataRepositoryException e )
245         {
246             log.error( e.getMessage(), e );
247             throw new ArchivaRestServiceException( e.getMessage(), e );
248         }
249         finally
250         {
251             repositorySession.closeQuietly();
252         }
253 
254 
255     }
256 
257     @Override
258     public StringList getObservablesRepoIds()
259         throws ArchivaRestServiceException
260     {
261         return new StringList( getObservableRepos() );
262     }
263 
264     @Override
265     public Response redirectToArtifactFile( String repositoryId, String groupId, String artifactId, String version,
266                                             String packaging, String classifier )
267         throws ArchivaRestServiceException
268     {
269         try
270         {
271             // validate query
272 
273             if ( StringUtils.isEmpty( groupId ) )
274             {
275                 return Response.status( new Response.StatusType()
276                 {
277                     @Override
278                     public int getStatusCode()
279                     {
280                         return Response.Status.BAD_REQUEST.getStatusCode();
281                     }
282 
283                     @Override
284                     public Response.Status.Family getFamily()
285                     {
286                         return Response.Status.BAD_REQUEST.getFamily();
287                     }
288 
289                     @Override
290                     public String getReasonPhrase()
291                     {
292                         return "groupId mandatory";
293                     }
294                 } ).build();
295             }
296 
297             if ( StringUtils.isEmpty( version ) )
298             {
299                 return Response.status( new Response.StatusType()
300                 {
301                     @Override
302                     public int getStatusCode()
303                     {
304                         return Response.Status.BAD_REQUEST.getStatusCode();
305                     }
306 
307                     @Override
308                     public Response.Status.Family getFamily()
309                     {
310                         return Response.Status.BAD_REQUEST.getFamily();
311                     }
312 
313                     @Override
314                     public String getReasonPhrase()
315                     {
316                         return "version mandatory";
317                     }
318                 } ).build();
319             }
320 
321             if ( StringUtils.isEmpty( artifactId ) )
322             {
323                 return Response.status( new Response.StatusType()
324                 {
325                     @Override
326                     public int getStatusCode()
327                     {
328                         return Response.Status.BAD_REQUEST.getStatusCode();
329                     }
330 
331                     @Override
332                     public Response.Status.Family getFamily()
333                     {
334                         return Response.Status.BAD_REQUEST.getFamily();
335                     }
336 
337                     @Override
338                     public String getReasonPhrase()
339                     {
340                         return "artifactId mandatory";
341                     }
342                 } ).build();
343             }
344 
345             SearchFieldsarchFields.html#SearchFields">SearchFields searchField = new SearchFields();
346             searchField.setGroupId( groupId );
347             searchField.setArtifactId( artifactId );
348             searchField.setPackaging( StringUtils.isBlank( packaging ) ? "jar" : packaging );
349             if ( !StringUtils.equals( version, LATEST_KEYWORD ) )
350             {
351                 searchField.setVersion( version );
352             }
353             searchField.setClassifier( classifier );
354             List<String> userRepos = getObservablesRepoIds().getStrings();
355             searchField.setRepositories(
356                 StringUtils.isEmpty( repositoryId ) ? userRepos : Arrays.asList( repositoryId ) );
357             searchField.setExactSearch( true );
358             SearchResults searchResults = repositorySearch.search( getPrincipal(), searchField, null );
359             List<Artifact> artifacts = getArtifacts( searchResults );
360 
361             if ( artifacts.isEmpty() )
362             {
363                 return Response.status( new Response.StatusType()
364                 {
365                     @Override
366                     public int getStatusCode()
367                     {
368                         return Response.Status.NO_CONTENT.getStatusCode();
369                     }
370 
371                     @Override
372                     public Response.Status.Family getFamily()
373                     {
374                         return Response.Status.NO_CONTENT.getFamily();
375                     }
376 
377                     @Override
378                     public String getReasonPhrase()
379                     {
380                         return "your query doesn't return any artifact";
381                     }
382                 } ).build();
383             }
384 
385             // TODO improve that with querying lucene with null value for classifier
386             // so simple loop and retain only artifact with null classifier
387             if ( classifier == null )
388             {
389                 List<Artifact> filteredArtifacts = new ArrayList<>( artifacts.size() );
390                 for ( Artifact artifact : artifacts )
391                 {
392                     if ( artifact.getClassifier() == null )
393                     {
394                         filteredArtifacts.add( artifact );
395                     }
396                 }
397 
398                 artifacts = filteredArtifacts;
399             }
400 
401             // TODO return json result of the query ?
402             if ( artifacts.size() > 1 && !StringUtils.equals( version, LATEST_KEYWORD ) )
403             {
404                 return Response.status( new Response.StatusType()
405                 {
406                     @Override
407                     public int getStatusCode()
408                     {
409                         return Response.Status.BAD_REQUEST.getStatusCode();
410                     }
411 
412                     @Override
413                     public Response.Status.Family getFamily()
414                     {
415                         return Response.Status.BAD_REQUEST.getFamily();
416                     }
417 
418                     @Override
419                     public String getReasonPhrase()
420                     {
421                         return "your query return more than one artifact";
422                     }
423                 } ).build();
424             }
425 
426             // version is LATEST so we have to find the latest one from the result
427             if ( artifacts.size() > 1 && StringUtils.equals( version, LATEST_KEYWORD ) )
428             {
429                 TreeMap<String, Artifact> artifactPerVersion = new TreeMap<>( VersionComparator.getInstance() );
430 
431                 for ( Artifact artifact : artifacts )
432                 {
433                     artifactPerVersion.put( artifact.getVersion(), artifact );
434                 }
435 
436                 return Response.temporaryRedirect(
437                     new URI( artifactPerVersion.lastEntry().getValue().getUrl() ) ).build();
438 
439             }
440 
441             Artifact artifact = artifacts.get( 0 );
442 
443             return Response.temporaryRedirect( new URI( artifact.getUrl() ) ).build();
444         }
445         catch ( Exception e )
446         {
447             throw new ArchivaRestServiceException( e.getMessage(), e );
448         }
449     }
450 
451 
452     //-------------------------------------
453     // internal
454     //-------------------------------------
455     protected List<Artifact> getArtifacts( SearchResults searchResults )
456         throws ArchivaRestServiceException
457     {
458 
459         if ( searchResults == null || searchResults.isEmpty() )
460         {
461             return Collections.emptyList();
462         }
463         List<Artifact> artifacts = new ArrayList<>( searchResults.getReturnedHitsCount() );
464         for ( SearchResultHit hit : searchResults.getHits() )
465         {
466             // duplicate Artifact one per available version
467             if ( hit.getVersions().size() > 0 )
468             {
469                 for ( String version : hit.getVersions() )
470                 {
471 
472                     Artifact versionned = getModelMapper().map( hit, Artifact.class );
473 
474                     if ( StringUtils.isNotBlank( version ) )
475                     {
476                         versionned.setVersion( version );
477                         versionned.setUrl( getArtifactUrl( versionned ) );
478 
479                         artifacts.add( versionned );
480 
481                     }
482                 }
483             }
484         }
485         return artifacts;
486     }
487 
488 
489 }