]> source.dussan.org Git - archiva.git/blob
68631041ea9bcd1d1bc4f87c68df207ec508721f
[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.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 )
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 ( !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             searchField.setExactSearch( true );
350             SearchResults searchResults = repositorySearch.search( getPrincipal(), searchField, null );
351             List<Artifact> artifacts = getArtifacts( searchResults );
352
353             if ( artifacts.isEmpty() )
354             {
355                 return Response.status( new Response.StatusType()
356                 {
357                     @Override
358                     public int getStatusCode()
359                     {
360                         return Response.Status.NO_CONTENT.getStatusCode();
361                     }
362
363                     @Override
364                     public Response.Status.Family getFamily()
365                     {
366                         return Response.Status.NO_CONTENT.getFamily();
367                     }
368
369                     @Override
370                     public String getReasonPhrase()
371                     {
372                         return "your query doesn't return any artifact";
373                     }
374                 } ).build();
375             }
376
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 )
380             {
381                 List<Artifact> filteredArtifacts = new ArrayList<>( artifacts.size() );
382                 for ( Artifact artifact : artifacts )
383                 {
384                     if ( artifact.getClassifier() == null )
385                     {
386                         filteredArtifacts.add( artifact );
387                     }
388                 }
389
390                 artifacts = filteredArtifacts;
391             }
392
393             // TODO return json result of the query ?
394             if ( artifacts.size() > 1 && !StringUtils.equals( version, LATEST_KEYWORD ) )
395             {
396                 return Response.status( new Response.StatusType()
397                 {
398                     @Override
399                     public int getStatusCode()
400                     {
401                         return Response.Status.BAD_REQUEST.getStatusCode();
402                     }
403
404                     @Override
405                     public Response.Status.Family getFamily()
406                     {
407                         return Response.Status.BAD_REQUEST.getFamily();
408                     }
409
410                     @Override
411                     public String getReasonPhrase()
412                     {
413                         return "your query return more than one artifact";
414                     }
415                 } ).build();
416             }
417
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 ) )
420             {
421                 TreeMap<String, Artifact> artifactPerVersion = new TreeMap<>( VersionComparator.getInstance() );
422
423                 for ( Artifact artifact : artifacts )
424                 {
425                     artifactPerVersion.put( artifact.getVersion(), artifact );
426                 }
427
428                 return Response.temporaryRedirect(
429                     new URI( artifactPerVersion.lastEntry().getValue().getUrl() ) ).build();
430
431             }
432
433             Artifact artifact = artifacts.get( 0 );
434
435             return Response.temporaryRedirect( new URI( artifact.getUrl() ) ).build();
436         }
437         catch ( Exception e )
438         {
439             throw new ArchivaRestServiceException( e.getMessage(), e );
440         }
441     }
442
443
444     //-------------------------------------
445     // internal
446     //-------------------------------------
447     protected List<Artifact> getArtifacts( SearchResults searchResults )
448         throws ArchivaRestServiceException
449     {
450
451         if ( searchResults == null || searchResults.isEmpty() )
452         {
453             return Collections.emptyList();
454         }
455         List<Artifact> artifacts = new ArrayList<>( searchResults.getReturnedHitsCount() );
456         for ( SearchResultHit hit : searchResults.getHits() )
457         {
458             // duplicate Artifact one per available version
459             if ( hit.getVersions().size() > 0 )
460             {
461                 for ( String version : hit.getVersions() )
462                 {
463
464                     Artifact versionned = getModelMapper().map( hit, Artifact.class );
465
466                     if ( StringUtils.isNotBlank( version ) )
467                     {
468                         versionned.setVersion( version );
469                         versionned.setUrl( getArtifactUrl( versionned ) );
470
471                         artifacts.add( versionned );
472
473                     }
474                 }
475             }
476         }
477         return artifacts;
478     }
479
480
481 }