/**
* Copyright (c) 2008-2011 Sonatype, Inc.
* All rights reserved. Includes the third-party code listed at http://www.sonatype.com/products/nexus/attributions.
*
* This program is free software: you can redistribute it and/or modify it only under the terms of the GNU Affero General
* Public License Version 3 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License Version 3
* for more details.
*
* You should have received a copy of the GNU Affero General Public License Version 3 along with this program. If not, see
* http://www.gnu.org/licenses.
*
* Sonatype Nexus (TM) Open Source Version is available from Sonatype, Inc. Sonatype and Sonatype Nexus are trademarks of
* Sonatype, Inc. Apache Maven is a trademark of the Apache Foundation. M2Eclipse is a trademark of the Eclipse Foundation.
* All other trademarks are the property of their respective owners.
*/
package org.sonatype.nexus.test.utils;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.maven.index.SearchType;
import org.apache.maven.index.artifact.Gav;
import org.codehaus.plexus.util.StringUtils;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Reference;
import org.restlet.data.Response;
import org.restlet.data.Status;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.nexus.integrationtests.AbstractNexusIntegrationTest;
import org.sonatype.nexus.integrationtests.RequestFacade;
import org.sonatype.nexus.proxy.repository.RepositoryWritePolicy;
import org.sonatype.nexus.rest.indextreeview.IndexBrowserTreeViewResponseDTO;
import org.sonatype.nexus.rest.model.ArtifactInfoResource;
import org.sonatype.nexus.rest.model.ArtifactInfoResourceResponse;
import org.sonatype.nexus.rest.model.NexusArtifact;
import org.sonatype.nexus.rest.model.RepositoryResource;
import org.sonatype.nexus.rest.model.RepositoryResourceResponse;
import org.sonatype.nexus.rest.model.ScheduledServiceBaseResource;
import org.sonatype.nexus.rest.model.ScheduledServicePropertyResource;
import org.sonatype.nexus.rest.model.SearchNGResponse;
import org.sonatype.nexus.rest.model.SearchResponse;
import org.sonatype.nexus.tasks.descriptors.RepairIndexTaskDescriptor;
import org.sonatype.nexus.tasks.descriptors.UpdateIndexTaskDescriptor;
import org.sonatype.plexus.rest.representation.XStreamRepresentation;
import org.testng.Assert;
import com.thoughtworks.xstream.XStream;
public class SearchMessageUtil
extends ITUtil
{
private static Logger log = LoggerFactory.getLogger( SearchMessageUtil.class );
private XStream xstream;
public SearchMessageUtil( AbstractNexusIntegrationTest test )
{
super( test );
this.xstream = XStreamFactory.getXmlXStream();
}
/**
* Main entry point used by other exposed methods. Do NOT expose this method, never ever.
*
* @param queryArgs
* @param repositoryId
* @param asKeywords
* @return
* @throws Exception
*/
private Response doSearchForR( Map<String, String> queryArgs, String repositoryId, SearchType searchType )
throws IOException
{
StringBuffer serviceURI = null;
if ( repositoryId == null )
{
serviceURI = new StringBuffer( "service/local/data_index?" );
}
else
{
serviceURI = new StringBuffer( "service/local/data_index/repositories/" + repositoryId + "?" );
}
for ( Entry<String, String> entry : queryArgs.entrySet() )
{
serviceURI.append( entry.getKey() ).append( "=" ).append( Reference.encode( entry.getValue() ) ).append(
"&" );
}
if ( searchType != null )
{
// we have an override in place
// currently, REST API lacks search type (it is able to only ovveride isKeyword search happening, or not, of
// if
// not specified, rely on server side defaults)
if ( SearchType.EXACT.equals( searchType ) )
{
serviceURI.append( "exact=true&" );
}
else if ( SearchType.SCORED.equals( searchType ) )
{
serviceURI.append( "exact=false&" );
}
}
log.info( "Search serviceURI " + serviceURI );
return RequestFacade.doGetRequest( serviceURI.toString() );
}
/**
* Uses XStream to unmarshall the DTOs.
*
* @param queryArgs
* @param repositoryId
* @param asKeywords
* @return
* @throws IOException
*/
private List<NexusArtifact> doSearchFor( Map<String, String> queryArgs, String repositoryId, SearchType searchType )
throws IOException
{
Response response = doSearchForR( queryArgs, repositoryId, searchType );
String responseText = response.getEntity().getText();
Assert.assertTrue( response.getStatus().isSuccess(), "Search failure:\n" + responseText );
XStreamRepresentation representation =
new XStreamRepresentation( xstream, responseText, MediaType.APPLICATION_XML );
SearchResponse searchResponde = (SearchResponse) representation.getPayload( new SearchResponse() );
return searchResponde.getData();
}
// LOW LEVEL METHODS
public List<NexusArtifact> searchFor( Map<String, String> queryArgs )
throws IOException
{
return searchFor( queryArgs, null, null );
}
public List<NexusArtifact> searchFor( Map<String, String> queryArgs, String repositoryId )
throws IOException
{
return searchFor( queryArgs, repositoryId, null );
}
public List<NexusArtifact> searchFor( Map<String, String> queryArgs, String repositoryId, SearchType searchType )
throws IOException
{
return doSearchFor( queryArgs, repositoryId, searchType );
}
// QUICK ("simple" query)
/**
* Returns "low" Restlet response to access response HTTP Code.
*/
public Response searchFor_response( String query )
throws IOException
{
HashMap<String, String> queryArgs = new HashMap<String, String>();
queryArgs.put( "q", query );
return doSearchForR( queryArgs, null, null );
}
public List<NexusArtifact> searchFor( String query )
throws IOException
{
return searchFor( query, null );
}
public List<NexusArtifact> searchFor( String query, SearchType type )
throws IOException
{
HashMap<String, String> queryArgs = new HashMap<String, String>();
queryArgs.put( "q", query );
return searchFor( queryArgs, null, type );
}
public List<NexusArtifact> searchFor( String query, String repositoryId, SearchType type )
throws IOException
{
HashMap<String, String> queryArgs = new HashMap<String, String>();
queryArgs.put( "q", query );
return searchFor( queryArgs, repositoryId, type );
}
// GAV
public List<NexusArtifact> searchForGav( String groupId, String artifactId, String version )
throws IOException
{
return searchForGav( groupId, artifactId, version, null );
}
public List<NexusArtifact> searchForGav( String groupId, String artifactId, String version, String repositoryId )
throws IOException
{
return searchForGav( groupId, artifactId, version, null, repositoryId );
}
public List<NexusArtifact> searchForGav( String groupId, String artifactId, String version, String packaging,
String repositoryId )
throws IOException
{
return searchForGav( groupId, artifactId, version, packaging, null, repositoryId );
}
public List<NexusArtifact> searchForGav( String groupId, String artifactId, String version, String packaging,
String classifier, String repositoryId )
throws IOException
{
Map<String, String> args = new HashMap<String, String>();
if ( StringUtils.isNotBlank( groupId ) )
{
args.put( "g", groupId );
}
if ( StringUtils.isNotBlank( artifactId ) )
{
args.put( "a", artifactId );
}
if ( StringUtils.isNotBlank( version ) )
{
args.put( "v", version );
}
if ( StringUtils.isNotBlank( packaging ) )
{
args.put( "p", packaging );
}
if ( StringUtils.isNotBlank( classifier ) )
{
args.put( "c", classifier );
}
return doSearchFor( args, repositoryId, null );
}
public List<NexusArtifact> searchForGav( Gav gav, String repositoryId )
throws IOException
{
return searchForGav( gav.getGroupId(), gav.getArtifactId(), gav.getVersion(), gav.getExtension(),
gav.getClassifier(), repositoryId );
}
// CLASSNAME
public List<NexusArtifact> searchForClassname( String classname )
throws IOException
{
Map<String, String> args = new HashMap<String, String>();
args.put( "cn", classname );
return doSearchFor( args, null, null );
}
// IDENTIFY/SHA1
public NexusArtifact identify( String sha1 )
throws IOException
{
// GET /identify/sha1/8b1b85d04eea979c33109ea42808b7d3f6d355ab (is log4j:log4j:1.2.13)
Response response = RequestFacade.doGetRequest( "service/local/identify/sha1/" + sha1 );
if ( response.getStatus().isSuccess() )
{
XStreamRepresentation representation =
new XStreamRepresentation( xstream, response.getEntity().getText(), MediaType.APPLICATION_XML );
return (NexusArtifact) representation.getPayload( new NexusArtifact() );
}
else
{
return null;
}
}
// SWITCHES ALLOW*
public void allowBrowsing( String repositoryName, boolean allowBrowsing )
throws IOException
{
RepositoryResource repository = getRepository( repositoryName );
repository.setBrowseable( allowBrowsing );
saveRepository( repository, repositoryName );
}
public void allowSearch( String repositoryName, boolean allowSearch )
throws IOException
{
RepositoryResource repository = getRepository( repositoryName );
repository.setIndexable( allowSearch );
saveRepository( repository, repositoryName );
}
public void allowDeploying( String repositoryName, boolean allowDeploying )
throws IOException
{
RepositoryResource repository = getRepository( repositoryName );
if ( allowDeploying )
{
repository.setWritePolicy( RepositoryWritePolicy.ALLOW_WRITE.name() );
}
else
{
repository.setWritePolicy( RepositoryWritePolicy.READ_ONLY.name() );
}
saveRepository( repository, repositoryName );
}
// PRIVATE BELOW
private RepositoryResource getRepository( String repositoryName )
throws IOException
{
String serviceURI = "service/local/repositories/" + repositoryName;
final Response response = RequestFacade.doGetRequest( serviceURI );
if ( response.getStatus().isError() )
{
Assert.assertFalse( response.getStatus().isError(), "Unable do retrieve repository: " + repositoryName
+ "\n" + response.getStatus() );
}
String responseText = response.getEntity().getText();
RepositoryResourceResponse repository = (RepositoryResourceResponse) xstream.fromXML( responseText );
return (RepositoryResource) repository.getData();
}
private void saveRepository( RepositoryResource repository, String repositoryName )
throws IOException
{
String serviceURI = "service/local/repositories/" + repositoryName;
RepositoryResourceResponse repositoryResponse = new RepositoryResourceResponse();
XStreamRepresentation representation = new XStreamRepresentation( xstream, "", MediaType.APPLICATION_XML );
repositoryResponse.setData( repository );
representation.setPayload( repositoryResponse );
Status status = RequestFacade.sendMessage( serviceURI, Method.PUT, representation ).getStatus();
Assert.assertEquals( Status.SUCCESS_OK.getCode(), status.getCode() );
}
public void reindexRepository( String taskName, String repoId, boolean force )
throws Exception
{
doReindex( taskName, repoId, force, false );
}
public void reindexGroup( String taskName, String groupId, boolean force )
throws Exception
{
doReindex( taskName, groupId, force, true );
}
private void doReindex( String taskName, String repoId, boolean force, boolean group )
throws Exception
{
ScheduledServiceBaseResource scheduledTask = new ScheduledServiceBaseResource();
scheduledTask.setEnabled( true );
scheduledTask.setId( null );
scheduledTask.setName( taskName );
if ( force )
{
scheduledTask.setTypeId( RepairIndexTaskDescriptor.ID );
}
else
{
scheduledTask.setTypeId( UpdateIndexTaskDescriptor.ID );
}
scheduledTask.setSchedule( "manual" );
if ( repoId != null )
{
ScheduledServicePropertyResource prop = new ScheduledServicePropertyResource();
prop.setKey( UpdateIndexTaskDescriptor.REPO_OR_GROUP_FIELD_ID );
prop.setValue( repoId );
scheduledTask.addProperty( prop );
}
Status status = TaskScheduleUtil.create( scheduledTask );
Assert.assertTrue( status.isSuccess() );
status = TaskScheduleUtil.run( TaskScheduleUtil.getTask( taskName ).getId() );
Assert.assertTrue( status.isSuccess() );
}
public ArtifactInfoResource getInfo( String repositoryId, String itemPath )
throws IOException
{
Response res =
RequestFacade.sendMessage( "content/repositories/" + repositoryId + "/" + itemPath + "?describe=info",
Method.GET, new XStreamRepresentation( xstream, "", MediaType.APPLICATION_XML ) );
String responseText = res.getEntity().getText();
if ( !res.getStatus().isSuccess() )
{
Assert.fail( res.getStatus() + "\n" + responseText );
}
XStreamRepresentation rep =
new XStreamRepresentation( XStreamFactory.getXmlXStream(), responseText, MediaType.APPLICATION_XML );
ArtifactInfoResourceResponse info =
(ArtifactInfoResourceResponse) rep.getPayload( new ArtifactInfoResourceResponse() );
return info.getData();
}
// ================================
// Search NG
/**
* Main entry point used by other exposed methods. Do NOT expose this method, never ever.
*
* @param queryArgs
* @param repositoryId
* @param asKeywords
* @return
* @throws Exception
*/
private Response doNGSearchForR( Map<String, String> queryArgs, String repositoryId, SearchType searchType )
throws IOException
{
StringBuffer serviceURI = new StringBuffer( "service/local/lucene/search?" );
if ( StringUtils.isNotBlank( repositoryId ) )
{
serviceURI.append( "repositoryId=" ).append( repositoryId ).append( "&" );
}
for ( Entry<String, String> entry : queryArgs.entrySet() )
{
serviceURI.append( entry.getKey() ).append( "=" ).append( entry.getValue() ).append( "&" );
}
if ( searchType != null )
{
// we have an override in place
// currently, REST API lacks search type (it is able to only ovveride isKeyword search happening, or not, of
// if
// not specified, rely on server side defaults)
if ( SearchType.EXACT.equals( searchType ) )
{
serviceURI.append( "exact=true&" );
}
else if ( SearchType.SCORED.equals( searchType ) )
{
serviceURI.append( "exact=false&" );
}
}
log.info( "Search serviceURI " + serviceURI );
return RequestFacade.doGetRequest( serviceURI.toString() );
}
/**
* Uses XStream to unmarshall the DTOs.
*
* @param queryArgs
* @param repositoryId
* @param asKeywords
* @return
* @throws IOException
*/
private SearchNGResponse doNGSearchFor( Map<String, String> queryArgs, String repositoryId, SearchType searchType )
throws IOException
{
Response response = doNGSearchForR( queryArgs, repositoryId, searchType );
String responseText = response.getEntity().getText();
Assert.assertTrue( response.getStatus().isSuccess(), "Search failure:\n" + responseText );
XStreamRepresentation representation =
new XStreamRepresentation( xstream, responseText, MediaType.APPLICATION_XML );
SearchNGResponse searchResponse = (SearchNGResponse) representation.getPayload( new SearchNGResponse() );
return searchResponse;
}
// NG Keyword search
public SearchNGResponse searchNGFor( String query )
throws IOException
{
return searchNGFor( query, null, null );
}
public SearchNGResponse searchNGFor( String query, String repositoryId, SearchType type )
throws IOException
{
HashMap<String, String> queryArgs = new HashMap<String, String>();
queryArgs.put( "q", query );
return doNGSearchFor( queryArgs, repositoryId, type );
}
public SearchNGResponse searchNGForGav( String groupId, String artifactId, String version, String classifier,
String packaging )
throws IOException
{
return searchNGForGav( groupId, artifactId, version, classifier, packaging, null, null );
}
public SearchNGResponse searchNGForGav( String groupId, String artifactId, String version, String classifier,
String packaging, String repositoryId, SearchType type )
throws IOException
{
Map<String, String> args = new HashMap<String, String>();
if ( StringUtils.isNotBlank( groupId ) )
{
args.put( "g", groupId );
}
if ( StringUtils.isNotBlank( artifactId ) )
{
args.put( "a", artifactId );
}
if ( StringUtils.isNotBlank( version ) )
{
args.put( "v", version );
}
if ( StringUtils.isNotBlank( classifier ) )
{
args.put( "c", classifier );
}
if ( StringUtils.isNotBlank( packaging ) )
{
args.put( "p", packaging );
}
return doNGSearchFor( args, repositoryId, type );
}
public SearchNGResponse searchNGForGav( Gav gav )
throws IOException
{
return searchNGForGav( gav, null, null );
}
public SearchNGResponse searchNGForGav( Gav gav, String repositoryId, SearchType type )
throws IOException
{
return searchNGForGav( gav.getGroupId(), gav.getArtifactId(), gav.getVersion(), gav.getClassifier(),
gav.getExtension(), repositoryId, type );
}
public SearchNGResponse searchSha1NGFor( String sha1 )
throws IOException
{
return searchSha1NGFor( sha1, null, null );
}
public SearchNGResponse searchSha1NGFor( String sha1, String repositoryId, SearchType type )
throws IOException
{
HashMap<String, String> queryArgs = new HashMap<String, String>();
queryArgs.put( "sha1", sha1 );
return doNGSearchFor( queryArgs, repositoryId, type );
}
// =================
// TreeView
public IndexBrowserTreeViewResponseDTO indexBrowserTreeView( String repoId, String path )
throws IOException
{
return indexBrowserTreeView( repoId, path, null, null, null );
}
public IndexBrowserTreeViewResponseDTO indexBrowserTreeView( String repoId, String groupIdHint,
String artifactIdHint )
throws IOException
{
return indexBrowserTreeView( repoId, null, groupIdHint, artifactIdHint, null );
}
public IndexBrowserTreeViewResponseDTO indexBrowserTreeView( String repoId, String path, String groupIdHint,
String artifactIdHint, String versionIdHint )
throws IOException
{
assert repoId != null : "Repository ID must not be null!";
String serviceURI = "service/local/repositories/" + repoId + "/index_content/";
if ( path != null )
{
// trim off leading "/" if any
while ( path.length() > 0 && path.startsWith( "/" ) )
{
path = path.substring( 1 );
}
serviceURI = serviceURI + path;
if ( !serviceURI.endsWith( "/" ) )
{
serviceURI = serviceURI + "/";
}
}
serviceURI = serviceURI + "?";
if ( StringUtils.isNotBlank( groupIdHint ) )
{
serviceURI = serviceURI + "groupIdHint=" + groupIdHint + "&";
}
if ( StringUtils.isNotBlank( artifactIdHint ) )
{
serviceURI = serviceURI + "artifactIdHint=" + artifactIdHint + "&";
}
if ( StringUtils.isNotBlank( versionIdHint ) )
{
serviceURI = serviceURI + "versionHint=" + versionIdHint + "&";
}
Response response = RequestFacade.doGetRequest( serviceURI );
String responseText = response.getEntity().getText();
Status status = response.getStatus();
Assert.assertTrue( status.isSuccess(), responseText + status );
XStreamRepresentation re =
new XStreamRepresentation( XStreamFactory.getXmlXStream(), responseText, MediaType.APPLICATION_XML );
IndexBrowserTreeViewResponseDTO resourceResponse =
(IndexBrowserTreeViewResponseDTO) re.getPayload( new IndexBrowserTreeViewResponseDTO() );
return resourceResponse;
}
}