mirror of https://github.com/apache/archiva.git
[MRM-1843] provide mechanism to obtain the latest version of an artifact
start download api currently redirect
This commit is contained in:
parent
a78b6070bc
commit
85047d3bb6
|
@ -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 )
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
|
|
|
@ -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
|
||||
//-------------------------------------
|
||||
|
|
Loading…
Reference in New Issue