]> source.dussan.org Git - archiva.git/blob
9c616b238c1ce47bd1d4dcf1b4caa327ea7503c9
[archiva.git] /
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         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 = 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             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 }