This project has retired. For details please refer to its Attic page.
Source code
001package org.apache.archiva.rest.services;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import org.apache.archiva.common.utils.VersionComparator;
023import org.apache.archiva.indexer.search.RepositorySearch;
024import org.apache.archiva.indexer.search.RepositorySearchException;
025import org.apache.archiva.indexer.search.SearchFields;
026import org.apache.archiva.indexer.search.SearchResultHit;
027import org.apache.archiva.indexer.search.SearchResultLimits;
028import org.apache.archiva.indexer.search.SearchResults;
029import org.apache.archiva.maven2.model.Artifact;
030import org.apache.archiva.metadata.model.ArtifactMetadata;
031import org.apache.archiva.metadata.repository.MetadataRepository;
032import org.apache.archiva.metadata.repository.MetadataRepositoryException;
033import org.apache.archiva.metadata.repository.RepositorySession;
034import org.apache.archiva.metadata.repository.RepositorySessionFactory;
035import org.apache.archiva.rest.api.model.ChecksumSearch;
036import org.apache.archiva.rest.api.model.GroupIdList;
037import org.apache.archiva.rest.api.model.SearchRequest;
038import org.apache.archiva.rest.api.model.StringList;
039import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
040import org.apache.archiva.rest.api.services.SearchService;
041import org.apache.commons.collections4.ListUtils;
042import org.apache.commons.lang3.StringUtils;
043import org.springframework.stereotype.Service;
044
045import javax.inject.Inject;
046import javax.ws.rs.core.Response;
047import java.net.URI;
048import java.util.ArrayList;
049import java.util.Arrays;
050import java.util.Collection;
051import java.util.Collections;
052import java.util.HashSet;
053import java.util.List;
054import java.util.Set;
055import java.util.TreeMap;
056
057/**
058 * @author Olivier Lamy
059 */
060@Service( "searchService#rest" )
061public class DefaultSearchService
062    extends AbstractRestService
063    implements SearchService
064{
065
066    private static final String LATEST_KEYWORD = "LATEST";
067
068    @Inject
069    private RepositorySearch repositorySearch;
070
071    @Inject
072    private RepositorySessionFactory repositorySessionFactory;
073
074    @Override
075    public List<Artifact> quickSearch( String queryString )
076        throws ArchivaRestServiceException
077    {
078        if ( StringUtils.isBlank( queryString ) )
079        {
080            return Collections.emptyList();
081        }
082
083        SearchResultLimits limits = new SearchResultLimits( 0 );
084        try
085        {
086            SearchResults searchResults =
087                repositorySearch.search( getPrincipal(), getObservableRepos(), queryString, limits,
088                                         Collections.<String>emptyList() );
089            return getArtifacts( searchResults );
090
091        }
092        catch ( RepositorySearchException e )
093        {
094            log.error( e.getMessage(), e );
095            throw new ArchivaRestServiceException( e.getMessage(), e );
096        }
097    }
098
099    @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}