Repository: archiva
Updated Branches:
  refs/heads/master a78b6070b -> d485a9963


[MRM-1843] provide mechanism to obtain the latest version of an artifact
start download api currently redirect


Project: http://git-wip-us.apache.org/repos/asf/archiva/repo
Commit: http://git-wip-us.apache.org/repos/asf/archiva/commit/85047d3b
Tree: http://git-wip-us.apache.org/repos/asf/archiva/tree/85047d3b
Diff: http://git-wip-us.apache.org/repos/asf/archiva/diff/85047d3b

Branch: refs/heads/master
Commit: 85047d3bb6163b3223ec9a4b90dae2a968d6bcb6
Parents: a78b607
Author: Olivier Lamy <[email protected]>
Authored: Tue May 20 15:04:47 2014 +1000
Committer: Olivier Lamy <[email protected]>
Committed: Tue May 20 15:04:47 2014 +1000

----------------------------------------------------------------------
 .../indexer/search/MavenRepositorySearch.java   | 62 ++++++++++++++++----
 .../archiva/indexer/search/SearchFields.java    | 17 ++++++
 .../rest/api/services/SearchService.java        | 15 ++++-
 .../rest/services/AbstractRestService.java      | 29 +++++++--
 .../rest/services/DefaultSearchService.java     | 50 +++++++++++++++-
 5 files changed, 152 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/archiva/blob/85047d3b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/MavenRepositorySearch.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/MavenRepositorySearch.java
 
b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/MavenRepositorySearch.java
index 2a41526..848ca78 100644
--- 
a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/MavenRepositorySearch.java
+++ 
b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/MavenRepositorySearch.java
@@ -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 )

http://git-wip-us.apache.org/repos/asf/archiva/blob/85047d3b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/SearchFields.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/SearchFields.java
 
b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/SearchFields.java
index fd23534..e5844a7 100644
--- 
a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/SearchFields.java
+++ 
b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/SearchFields.java
@@ -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()
     {

http://git-wip-us.apache.org/repos/asf/archiva/blob/85047d3b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/SearchService.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/SearchService.java
 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/SearchService.java
index de88454..319abdf 100644
--- 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/SearchService.java
+++ 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-api/src/main/java/org/apache/archiva/rest/api/services/SearchService.java
@@ -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;
+
 }

http://git-wip-us.apache.org/repos/asf/archiva/blob/85047d3b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/AbstractRestService.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/AbstractRestService.java
 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/AbstractRestService.java
index 6fb7d0b..3443625 100644
--- 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/AbstractRestService.java
+++ 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/AbstractRestService.java
@@ -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();
@@ -213,6 +217,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() );

http://git-wip-us.apache.org/repos/asf/archiva/blob/85047d3b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultSearchService.java
----------------------------------------------------------------------
diff --git 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultSearchService.java
 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultSearchService.java
index d944893..9dae949 100644
--- 
a/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultSearchService.java
+++ 
b/archiva-modules/archiva-web/archiva-rest/archiva-rest-services/src/main/java/org/apache/archiva/rest/services/DefaultSearchService.java
@@ -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
     //-------------------------------------

Reply via email to