]> source.dussan.org Git - archiva.git/commitdiff
[MRM-1843] provide mechanism to obtain the latest version of an artifact
authorOlivier Lamy <olamy@apache.org>
Tue, 20 May 2014 05:04:47 +0000 (15:04 +1000)
committerOlivier Lamy <olamy@apache.org>
Tue, 20 May 2014 05:04:47 +0000 (15:04 +1000)
start download api currently redirect

archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/MavenRepositorySearch.java
archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/SearchFields.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/SearchService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/AbstractRestService.java
archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultSearchService.java

index 2a41526e23113ecba79bca17542ce56ba21e77e1..848ca78c1ae501ec3d42e47a8c4d6d42aa70ec25 100644 (file)
@@ -29,16 +29,23 @@ import org.apache.archiva.common.plexusbridge.PlexusSisuBridge;
 import org.apache.archiva.common.plexusbridge.PlexusSisuBridgeException;
 import org.apache.archiva.indexer.util.SearchUtil;
 import org.apache.commons.lang.StringUtils;
+import org.apache.lucene.queryParser.ParseException;
+import org.apache.lucene.search.BooleanClause;
 import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
 import org.apache.maven.index.ArtifactInfo;
 import org.apache.maven.index.FlatSearchRequest;
 import org.apache.maven.index.FlatSearchResponse;
 import org.apache.maven.index.MAVEN;
 import org.apache.maven.index.NexusIndexer;
 import org.apache.maven.index.OSGI;
+import org.apache.maven.index.QueryCreator;
+import org.apache.maven.index.SearchType;
 import org.apache.maven.index.context.IndexCreator;
 import org.apache.maven.index.context.IndexingContext;
+import org.apache.maven.index.expr.SearchExpression;
+import org.apache.maven.index.expr.SearchTyped;
 import org.apache.maven.index.expr.SourcedSearchExpression;
 import org.apache.maven.index.expr.UserInputSearchExpression;
 import org.slf4j.Logger;
@@ -58,7 +65,7 @@ import java.util.Set;
 /**
  * RepositorySearch implementation which uses the Maven Indexer for searching.
  */
-@Service("repositorySearch#maven")
+@Service( "repositorySearch#maven" )
 public class MavenRepositorySearch
     implements RepositorySearch
 {
@@ -66,6 +73,8 @@ public class MavenRepositorySearch
 
     private NexusIndexer indexer;
 
+    private QueryCreator queryCreator;
+
     private ManagedRepositoryAdmin managedRepositoryAdmin;
 
     private ProxyConnectorAdmin proxyConnectorAdmin;
@@ -83,6 +92,7 @@ public class MavenRepositorySearch
         throws PlexusSisuBridgeException
     {
         this.indexer = plexusSisuBridge.lookup( NexusIndexer.class );
+        this.queryCreator = plexusSisuBridge.lookup( QueryCreator.class );
         this.managedRepositoryAdmin = managedRepositoryAdmin;
         this.mavenIndexerUtils = mavenIndexerUtils;
         this.proxyConnectorAdmin = proxyConnectorAdmin;
@@ -153,28 +163,35 @@ public class MavenRepositorySearch
         BooleanQuery q = new BooleanQuery();
         if ( StringUtils.isNotBlank( searchFields.getGroupId() ) )
         {
-            q.add( indexer.constructQuery( MAVEN.GROUP_ID, new UserInputSearchExpression( searchFields.getGroupId() ) ),
-                   Occur.MUST );
+            q.add( indexer.constructQuery( MAVEN.GROUP_ID, searchFields.isExactSearch()
+                                               ? new SourcedSearchExpression( searchFields.getGroupId() )
+                                               : new UserInputSearchExpression( searchFields.getGroupId() )
+                   ), Occur.MUST
+            );
         }
 
         if ( StringUtils.isNotBlank( searchFields.getArtifactId() ) )
         {
             q.add( indexer.constructQuery( MAVEN.ARTIFACT_ID,
-                                           new UserInputSearchExpression( searchFields.getArtifactId() ) ), Occur.MUST
+                                           searchFields.isExactSearch()
+                                               ? new SourcedSearchExpression( searchFields.getArtifactId() )
+                                               : new UserInputSearchExpression( searchFields.getArtifactId() )
+                   ), Occur.MUST
             );
         }
 
         if ( StringUtils.isNotBlank( searchFields.getVersion() ) )
         {
-            q.add( indexer.constructQuery( MAVEN.VERSION, new SourcedSearchExpression( searchFields.getVersion() ) ),
-                   Occur.MUST );
+            q.add( indexer.constructQuery( MAVEN.VERSION, searchFields.isExactSearch() ? new SourcedSearchExpression(
+                searchFields.getVersion() ) : new SourcedSearchExpression( searchFields.getVersion() ) ), Occur.MUST );
         }
 
         if ( StringUtils.isNotBlank( searchFields.getPackaging() ) )
         {
-            q.add(
-                indexer.constructQuery( MAVEN.PACKAGING, new UserInputSearchExpression( searchFields.getPackaging() ) ),
-                Occur.MUST );
+            q.add( indexer.constructQuery( MAVEN.PACKAGING, searchFields.isExactSearch() ? new SourcedSearchExpression(
+                       searchFields.getPackaging() ) : new UserInputSearchExpression( searchFields.getPackaging() ) ),
+                   Occur.MUST
+            );
         }
 
         if ( StringUtils.isNotBlank( searchFields.getClassName() ) )
@@ -247,10 +264,16 @@ public class MavenRepositorySearch
 
         if ( StringUtils.isNotBlank( searchFields.getClassifier() ) )
         {
-            q.add( indexer.constructQuery( MAVEN.CLASSIFIER,
-                                           new UserInputSearchExpression( searchFields.getClassifier() ) ), Occur.MUST
+            q.add( indexer.constructQuery( MAVEN.CLASSIFIER, searchFields.isExactSearch() ? new SourcedSearchExpression(
+                       searchFields.getClassifier() ) : new UserInputSearchExpression( searchFields.getClassifier() ) ),
+                   Occur.MUST
             );
         }
+        else if ( searchFields.isExactSearch() )
+        {
+            //TODO improvement in case of exact search and no classifier we must query for classifier with null value
+            // currently it's done in DefaultSearchService with some filtering
+        }
 
         if ( q.getClauses() == null || q.getClauses().length <= 0 )
         {
@@ -261,6 +284,23 @@ public class MavenRepositorySearch
                        searchFields.getRepositories(), searchFields.isIncludePomArtifacts() );
     }
 
+    private static class NullSearch implements SearchTyped, SearchExpression
+    {
+        private static final NullSearch INSTANCE = new NullSearch();
+
+        @Override
+        public String getStringValue()
+        {
+            return "[[NULL_VALUE]]";
+        }
+
+        @Override
+        public SearchType getSearchType()
+        {
+            return SearchType.EXACT;
+        }
+    }
+
     private SearchResults search( SearchResultLimits limits, BooleanQuery q, List<String> indexingContextIds,
                                   List<? extends ArtifactInfoFilter> filters, List<String> selectedRepos,
                                   boolean includePoms )
index fd2353423846ccd5b03e345117d5a0a0b432b56c..e5844a765025f63c386ec57f423d3f100b29966b 100644 (file)
@@ -114,6 +114,13 @@ public class SearchFields
 
     private String classifier;
 
+    /**
+     * we use exact String matching search
+     *
+     * @since 2.1.0
+     */
+    private boolean exactSearch = false;
+
     public SearchFields()
     {
         // no op
@@ -281,6 +288,16 @@ public class SearchFields
         this.bundleRequireBundle = bundleRequireBundle;
     }
 
+    public boolean isExactSearch()
+    {
+        return exactSearch;
+    }
+
+    public void setExactSearch( boolean exactSearch )
+    {
+        this.exactSearch = exactSearch;
+    }
+
     @Override
     public String toString()
     {
index de884541cc46094fa4fd43bfad620e196baa1340..319abdfeb514faa9a96af5769728f0c668fbaef9 100644 (file)
@@ -21,10 +21,10 @@ package org.apache.archiva.rest.api.services;
 
 
 import org.apache.archiva.maven2.model.Artifact;
+import org.apache.archiva.redback.authorization.RedbackAuthorization;
 import org.apache.archiva.rest.api.model.GroupIdList;
 import org.apache.archiva.rest.api.model.SearchRequest;
 import org.apache.archiva.rest.api.model.StringList;
-import org.apache.archiva.redback.authorization.RedbackAuthorization;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -32,6 +32,7 @@ import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
 import java.util.List;
 
 @Path( "/searchService/" )
@@ -60,8 +61,7 @@ public interface SearchService
     @POST
     @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML } )
     @RedbackAuthorization( noPermission = true, noRestriction = true )
-
-   List<Artifact> quickSearchWithRepositories( SearchRequest searchRequest )
+    List<Artifact> quickSearchWithRepositories( SearchRequest searchRequest )
         throws ArchivaRestServiceException;
 
     /**
@@ -127,4 +127,13 @@ public interface SearchService
         throws ArchivaRestServiceException;
     */
 
+    @GET
+    @Path( "/artifact" )
+    @Produces( "text/html" )
+    @RedbackAuthorization( noPermission = true, noRestriction = true )
+    Response redirectToArtifactFile( @QueryParam( "r" ) String repositoryId, @QueryParam( "g" ) String groupId,
+                                     @QueryParam( "a" ) String artifactId, @QueryParam( "v" ) String version,
+                                     @QueryParam( "p" ) String packaging, @QueryParam( "c" ) String classifier )
+        throws ArchivaRestServiceException;
+
 }
index 6fb7d0bd0dc756ebf917aa4bada36a03efdb265f..3443625e581701bb9ea00994a129011b562bad0f 100644 (file)
@@ -57,6 +57,7 @@ import org.springframework.context.ApplicationContext;
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.Response;
 import java.util.ArrayList;
@@ -87,7 +88,7 @@ public abstract class AbstractRestService
      * FIXME: this could be multiple implementations and needs to be configured.
      */
     @Inject
-    @Named( value = "repositorySessionFactory" )
+    @Named(value = "repositorySessionFactory")
     protected RepositorySessionFactory repositorySessionFactory;
 
     @Inject
@@ -100,17 +101,20 @@ public abstract class AbstractRestService
     protected RepositoryContentFactory repositoryContentFactory;
 
     @Inject
-    @Named( value = "archivaTaskScheduler#repository" )
+    @Named(value = "archivaTaskScheduler#repository")
     protected DefaultRepositoryArchivaTaskScheduler repositoryTaskScheduler;
 
 
     @Inject
-    @Named( value = "userConfiguration#default" )
+    @Named(value = "userConfiguration#default")
     protected UserConfiguration config;
 
     @Context
     protected HttpServletRequest httpServletRequest;
 
+    @Context
+    protected HttpServletResponse httpServletResponse;
+
     protected AuditInformation getAuditInformation()
     {
         RedbackRequestInformation redbackRequestInformation = RedbackAuthenticationThreadLocal.get();
@@ -212,6 +216,13 @@ public abstract class AbstractRestService
      */
     protected String getArtifactUrl( Artifact artifact )
         throws ArchivaRestServiceException
+    {
+        return getArtifactUrl( artifact, null );
+    }
+
+
+    protected String getArtifactUrl( Artifact artifact, String repositoryId )
+        throws ArchivaRestServiceException
     {
         try
         {
@@ -225,10 +236,16 @@ public abstract class AbstractRestService
 
             sb.append( "/repository" );
 
-            // FIXME when artifact come from a remote repository when have here the remote repo id
+            // when artifact come from a remote repository when have here the remote repo id
             // we must replace it with a valid managed one available for the user.
-
-            sb.append( '/' ).append( artifact.getContext() );
+            if ( StringUtils.isEmpty( repositoryId ) )
+            {
+                sb.append( '/' ).append( artifact.getContext() );
+            }
+            else
+            {
+                sb.append( '/' ).append( repositoryId );
+            }
 
             sb.append( '/' ).append( StringUtils.replaceChars( artifact.getGroupId(), '.', '/' ) );
             sb.append( '/' ).append( artifact.getArtifactId() );
index d944893aaad4fde847c4c21f72243b6a09fe2e67..9dae9491d99f5472733cd135d4b7f61d49bb0df6 100644 (file)
@@ -37,14 +37,17 @@ import org.apache.commons.lang.StringUtils;
 import org.springframework.stereotype.Service;
 
 import javax.inject.Inject;
+import javax.ws.rs.core.Response;
+import java.net.URI;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
 /**
  * @author Olivier Lamy
  */
-@Service( "searchService#rest" )
+@Service("searchService#rest")
 public class DefaultSearchService
     extends AbstractRestService
     implements SearchService
@@ -205,6 +208,51 @@ public class DefaultSearchService
         return new StringList( getObservableRepos() );
     }
 
+    @Override
+    public Response redirectToArtifactFile( String repositoryId, String groupId, String artifactId, String version,
+                                            String packaging, String classifier )
+        throws ArchivaRestServiceException
+    {
+        try
+        {
+
+            SearchFields searchField = new SearchFields();
+            searchField.setGroupId( groupId );
+            searchField.setArtifactId( artifactId );
+            searchField.setPackaging( StringUtils.isBlank( packaging ) ? "jar" : packaging );
+            searchField.setVersion( version );
+            searchField.setClassifier( classifier );
+            searchField.setRepositories( Arrays.asList( repositoryId ) );
+            searchField.setExactSearch( true );
+            SearchResults searchResults = repositorySearch.search( getPrincipal(), searchField, null );
+            List<Artifact> artifacts = getArtifacts( searchResults );
+
+            // TODO improve that with querying lucene with null value for classifier
+            // so simple loop and retain only artifact with null classifier
+            if ( classifier == null )
+            {
+                List<Artifact> filteredArtifacts = new ArrayList<>( artifacts.size() );
+                for ( Artifact artifact : artifacts )
+                {
+                    if ( artifact.getClassifier() == null )
+                    {
+                        filteredArtifacts.add( artifact );
+                    }
+                }
+
+                artifacts = filteredArtifacts;
+            }
+
+            String artifactUrl = getArtifactUrl( artifacts.get( 0 ), repositoryId );
+
+            return Response.temporaryRedirect( new URI( artifactUrl ) ).build();
+        }
+        catch ( Exception e )
+        {
+            throw new ArchivaRestServiceException( e.getMessage(), e );
+        }
+    }
+
     //-------------------------------------
     // internal
     //-------------------------------------