[MRM-749]

merged -r 728552:740257 from archiva-nexus-indexer branch


git-svn-id: https://svn.apache.org/repos/asf/archiva/trunk@740552 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Maria Odea B. Ching 2009-02-04 01:09:17 +00:00
parent cedc048694
commit c0e1f8872e
34 changed files with 1822 additions and 128 deletions

View File

@ -86,8 +86,6 @@ public interface RepositoryContentConsumer extends Consumer
* NOTE: If the consumer opted to batch up processing requests in the {@link #processFile(String)} event
* this would be the last opportunity to drain any processing queue's.
* </p>
*
* @todo! this is never called by the RepositoryScannerInstance
*/
public void completeScan();

View File

@ -0,0 +1,214 @@
package org.apache.archiva.consumers.lucene;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexReader;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.maven.archiva.consumers.AbstractMonitoredConsumer;
import org.apache.maven.archiva.consumers.ConsumerException;
import org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer;
import org.apache.maven.archiva.repository.content.ManagedDefaultRepositoryContent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.nexus.index.ArtifactContext;
import org.sonatype.nexus.index.ArtifactContextProducer;
import org.sonatype.nexus.index.ArtifactInfo;
import org.sonatype.nexus.index.DefaultArtifactContextProducer;
import org.sonatype.nexus.index.NexusIndexer;
import org.sonatype.nexus.index.context.IndexingContext;
import org.sonatype.nexus.index.context.UnsupportedExistingLuceneIndexException;
import org.sonatype.nexus.index.creator.AbstractIndexCreator;
import org.sonatype.nexus.index.creator.IndexerEngine;
import org.sonatype.nexus.index.packer.IndexPacker;
/**
* Consumer for indexing the repository to provide search and IDE integration features.
*/
public class NexusIndexerConsumer
extends AbstractMonitoredConsumer
implements KnownRepositoryContentConsumer
{
private static final Logger log = LoggerFactory.getLogger( NexusIndexerConsumer.class );
private final NexusIndexer indexer;
private final ArtifactContextProducer artifactContextProducer;
private final IndexPacker indexPacker;
private ManagedDefaultRepositoryContent repositoryContent;
private IndexingContext context;
private File managedRepository;
private IndexerEngine indexerEngine;
private Set<String> uinfos;
public NexusIndexerConsumer( NexusIndexer indexer, IndexPacker indexPacker, IndexerEngine indexerEngine )
{
this.indexer = indexer;
this.indexPacker = indexPacker;
this.indexerEngine = indexerEngine;
this.artifactContextProducer = new DefaultArtifactContextProducer();
}
public String getDescription()
{
return "Indexes the repository to provide search and IDE integration features";
}
public String getId()
{
return "index-content";
}
public boolean isPermanent()
{
return false;
}
public void beginScan( ManagedRepositoryConfiguration repository, Date whenGathered )
throws ConsumerException
{
managedRepository = new File( repository.getLocation() );
String indexDir = repository.getIndexDir();
File indexDirectory = null;
if( indexDir != null && !"".equals( indexDir ) )
{
//indexDirectory = new File( managedRepository, repository.getIndexDir() );
indexDirectory = new File( repository.getIndexDir() );
}
else
{
indexDirectory = new File( managedRepository, ".indexer" );
}
repositoryContent = new ManagedDefaultRepositoryContent();
repositoryContent.setRepository( repository );
uinfos = new HashSet<String>();
synchronized ( indexer )
{
try
{
context =
indexer.addIndexingContext( repository.getId(), repository.getId(), managedRepository,
indexDirectory, null, null, NexusIndexer.FULL_INDEX );
context.setSearchable( repository.isScanned() );
// read index to get all the artifacts already indexed
IndexReader r = context.getIndexReader();
for ( int i = 0; i < r.numDocs(); i++ )
{
if ( !r.isDeleted( i ) )
{
Document d = r.document( i );
String uinfo = d.get( ArtifactInfo.UINFO );
if ( uinfo != null )
{
uinfos.add( uinfo );
}
}
}
indexerEngine.beginIndexing( context );
}
catch ( UnsupportedExistingLuceneIndexException e )
{
log.error( "Could not create index at " + indexDirectory.getAbsoluteFile(), e );
}
catch ( IOException e )
{
log.error( "Could not create index at " + indexDirectory.getAbsoluteFile(), e );
}
}
}
public void processFile( String path )
throws ConsumerException
{
File artifactFile = new File( managedRepository, path );
ArtifactContext artifactContext = artifactContextProducer.getArtifactContext( context, artifactFile );
if ( artifactContext != null )
{
try
{
ArtifactInfo ai = artifactContext.getArtifactInfo();
String uinfo = AbstractIndexCreator.getGAV(
ai.groupId, ai.artifactId, ai.version, ai.classifier, ai.packaging );
// already indexed so update!
if ( uinfos.contains( uinfo ) )
{
indexerEngine.update( context, artifactContext );
}
else
{
indexerEngine.index( context, artifactContext );
}
}
catch ( IOException e )
{
throw new ConsumerException( e.getMessage(), e );
}
}
}
public void completeScan()
{
final File indexLocation = new File( managedRepository, ".index" );
try
{
indexerEngine.endIndexing( context );
indexPacker.packIndex( context, indexLocation );
indexer.removeIndexingContext( context, false );
uinfos = null;
}
catch ( IOException e )
{
log.error( "Could not pack index" + indexLocation.getAbsolutePath(), e );
}
}
public List<String> getExcludes()
{
return new ArrayList<String>();
}
public List<String> getIncludes()
{
return Arrays.asList( "**/*" );
}
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="indexerConsumer" class="org.apache.archiva.consumers.lucene.NexusIndexerConsumer">
<constructor-arg ref="nexusIndexer#archiva"/>
<constructor-arg ref="indexPacker"/>
<constructor-arg ref="indexerEngine"/>
</bean>
</beans>

View File

@ -0,0 +1,188 @@
package org.apache.archiva.consumers.lucene;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.util.Calendar;
import java.util.Date;
import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.maven.archiva.consumers.KnownRepositoryContentConsumer;
import org.codehaus.plexus.spring.PlexusInSpringTestCase;
import org.sonatype.nexus.index.ArtifactInfo;
import org.sonatype.nexus.index.FlatSearchRequest;
import org.sonatype.nexus.index.FlatSearchResponse;
import org.sonatype.nexus.index.NexusIndexer;
import org.sonatype.nexus.index.context.IndexingContext;
import org.sonatype.nexus.index.creator.IndexerEngine;
import org.sonatype.nexus.index.packer.IndexPacker;
public class NexusIndexerConsumerTest
extends PlexusInSpringTestCase
{
private KnownRepositoryContentConsumer nexusIndexerConsumer;
private ManagedRepositoryConfiguration repositoryConfig;
private NexusIndexer nexusIndexer;
private IndexPacker indexPacker;
private IndexerEngine indexerEngine;
@Override
protected void setUp()
throws Exception
{
super.setUp();
nexusIndexer = ( NexusIndexer ) lookup( NexusIndexer.class );
indexPacker = ( IndexPacker ) lookup( IndexPacker.class );
indexerEngine = ( IndexerEngine ) lookup( IndexerEngine.class );
nexusIndexerConsumer = new NexusIndexerConsumer( nexusIndexer, indexPacker, indexerEngine );
repositoryConfig = new ManagedRepositoryConfiguration();
repositoryConfig.setId( "test-repo" );
repositoryConfig.setLocation( getBasedir() + "/target/test-classes/test-repo" );
repositoryConfig.setLayout( "default" );
repositoryConfig.setName( "Test Repository" );
repositoryConfig.setScanned( true );
repositoryConfig.setSnapshots( false );
repositoryConfig.setReleases( true );
}
@Override
protected void tearDown()
throws Exception
{
// delete created index in the repository
File indexDir = new File( repositoryConfig.getLocation(), ".indexer" );
FileUtils.deleteDirectory( indexDir );
assertFalse( indexDir.exists() );
indexDir = new File( repositoryConfig.getLocation(), ".index" );
FileUtils.deleteDirectory( indexDir );
assertFalse( indexDir.exists() );
super.tearDown();
}
public void testIndexerIndexArtifact()
throws Exception
{
// begin scan
Date now = Calendar.getInstance().getTime();
nexusIndexerConsumer.beginScan( repositoryConfig, now );
nexusIndexerConsumer.processFile( "org/apache/archiva/archiva-index-methods-jar-test/1.0/archiva-index-methods-jar-test-1.0.jar" );
nexusIndexerConsumer.completeScan();
// search!
BooleanQuery q = new BooleanQuery();
q.add( nexusIndexer.constructQuery( ArtifactInfo.GROUP_ID, "org.apache.archiva" ), Occur.SHOULD );
q.add( nexusIndexer.constructQuery( ArtifactInfo.ARTIFACT_ID, "archiva-index-methods-jar-test" ), Occur.SHOULD );
IndexingContext context = nexusIndexer.addIndexingContext( repositoryConfig.getId(), repositoryConfig.getId(), new File( repositoryConfig.getLocation() ),
new File( repositoryConfig.getLocation(), ".indexer" ), null, null, NexusIndexer.FULL_INDEX );
context.setSearchable( true );
FlatSearchRequest request = new FlatSearchRequest( q );
FlatSearchResponse response = nexusIndexer.searchFlat( request );
assertTrue( new File( repositoryConfig.getLocation(), ".indexer" ).exists() );
assertTrue( new File( repositoryConfig.getLocation(), ".index" ).exists() );
assertEquals( 1, response.getTotalHits() );
Set<ArtifactInfo> results = response.getResults();
ArtifactInfo artifactInfo = (ArtifactInfo) results.iterator().next();
assertEquals( "org.apache.archiva", artifactInfo.groupId );
assertEquals( "archiva-index-methods-jar-test", artifactInfo.artifactId );
assertEquals( "test-repo", artifactInfo.repository );
}
public void testIndexerArtifactAlreadyIndexed()
throws Exception
{
// begin scan
Date now = Calendar.getInstance().getTime();
nexusIndexerConsumer.beginScan( repositoryConfig, now );
nexusIndexerConsumer.processFile( "org/apache/archiva/archiva-index-methods-jar-test/1.0/archiva-index-methods-jar-test-1.0.jar" );
nexusIndexerConsumer.completeScan();
// scan and index again
now = Calendar.getInstance().getTime();
nexusIndexerConsumer.beginScan( repositoryConfig, now );
nexusIndexerConsumer.processFile( "org/apache/archiva/archiva-index-methods-jar-test/1.0/archiva-index-methods-jar-test-1.0.jar" );
nexusIndexerConsumer.completeScan();
// search!
BooleanQuery q = new BooleanQuery();
q.add( nexusIndexer.constructQuery( ArtifactInfo.GROUP_ID, "org.apache.archiva" ), Occur.SHOULD );
q.add( nexusIndexer.constructQuery( ArtifactInfo.ARTIFACT_ID, "archiva-index-methods-jar-test" ), Occur.SHOULD );
IndexSearcher searcher = new IndexSearcher( repositoryConfig.getLocation() + "/.indexer" );
TopDocs topDocs = searcher.search( q, null, 10 );
assertTrue( new File( repositoryConfig.getLocation(), ".indexer" ).exists() );
assertTrue( new File( repositoryConfig.getLocation(), ".index" ).exists() );
// should return only 1 hit - artifact should have just been updated and not added as a separate doc
assertEquals( 1, topDocs.totalHits );
}
public void testIndexerIndexArtifactThenPom()
throws Exception
{
// begin scan
Date now = Calendar.getInstance().getTime();
nexusIndexerConsumer.beginScan( repositoryConfig, now );
nexusIndexerConsumer.processFile( "org/apache/archiva/archiva-index-methods-jar-test/1.0/archiva-index-methods-jar-test-1.0.jar" );
nexusIndexerConsumer.completeScan();
// scan and index again
now = Calendar.getInstance().getTime();
nexusIndexerConsumer.beginScan( repositoryConfig, now );
nexusIndexerConsumer.processFile( "org/apache/archiva/archiva-index-methods-jar-test/1.0/pom.xml" );
nexusIndexerConsumer.completeScan();
// search!
BooleanQuery q = new BooleanQuery();
q.add( nexusIndexer.constructQuery( ArtifactInfo.GROUP_ID, "org.apache.archiva" ), Occur.SHOULD );
q.add( nexusIndexer.constructQuery( ArtifactInfo.ARTIFACT_ID, "archiva-index-methods-jar-test" ), Occur.SHOULD );
IndexSearcher searcher = new IndexSearcher( repositoryConfig.getLocation() + "/.indexer" );
TopDocs topDocs = searcher.search( q, null, 10 );
assertTrue( new File( repositoryConfig.getLocation(), ".indexer" ).exists() );
assertTrue( new File( repositoryConfig.getLocation(), ".index" ).exists() );
// should return only 1 hit
assertEquals( 1, topDocs.totalHits );
}
}

View File

@ -65,6 +65,10 @@
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.sonatype.nexus</groupId>
<artifactId>nexus-indexer</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
@ -79,6 +83,24 @@
</check>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-maven-plugin</artifactId>
<executions>
<execution>
<id>merge</id>
<goals>
<goal>merge-descriptors</goal>
</goals>
<configuration>
<descriptors>
<descriptor>${basedir}/src/main/resources/META-INF/plexus/components.xml</descriptor>
<descriptor>${project.build.directory}/generated-resources/plexus/META-INF/plexus/components.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,326 @@
package org.apache.archiva.indexer.search;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.archiva.indexer.util.SearchUtil;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.maven.archiva.configuration.ArchivaConfiguration;
import org.apache.maven.archiva.configuration.Configuration;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.maven.archiva.indexer.search.SearchResultHit;
import org.apache.maven.archiva.indexer.search.SearchResultLimits;
import org.apache.maven.archiva.indexer.search.SearchResults;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.nexus.index.ArtifactInfo;
import org.sonatype.nexus.index.FlatSearchRequest;
import org.sonatype.nexus.index.FlatSearchResponse;
import org.sonatype.nexus.index.NexusIndexer;
import org.sonatype.nexus.index.context.IndexContextInInconsistentStateException;
import org.sonatype.nexus.index.context.IndexingContext;
import org.sonatype.nexus.index.context.UnsupportedExistingLuceneIndexException;
/**
* RepositorySearch implementation which uses the Nexus Indexer for searching.
*/
public class NexusRepositorySearch
implements RepositorySearch
{
private static final Logger log = LoggerFactory.getLogger( NexusRepositorySearch.class );
private NexusIndexer indexer;
private ArchivaConfiguration archivaConfig;
public NexusRepositorySearch( NexusIndexer indexer, ArchivaConfiguration archivaConfig )
{
this.indexer = indexer;
this.archivaConfig = archivaConfig;
}
/**
* @see RepositorySearch#search(String, List, String, SearchResultLimits, List)
*/
public SearchResults search( String principal, List<String> selectedRepos, String term, SearchResultLimits limits,
List<String> previousSearchTerms )
throws RepositorySearchException
{
addIndexingContexts( selectedRepos );
BooleanQuery q = new BooleanQuery();
if( previousSearchTerms == null || previousSearchTerms.isEmpty() )
{
constructQuery( term, q );
}
else
{
for( String previousTerm : previousSearchTerms )
{
BooleanQuery iQuery = new BooleanQuery();
constructQuery( previousTerm, iQuery );
q.add( iQuery, Occur.MUST );
}
BooleanQuery iQuery = new BooleanQuery();
constructQuery( term, iQuery );
q.add( iQuery, Occur.MUST );
}
return search( limits, q );
}
/**
* @see RepositorySearch#search(String, SearchFields, SearchResultLimits)
*/
public SearchResults search( String principal, SearchFields searchFields, SearchResultLimits limits )
throws RepositorySearchException
{
if( searchFields.getRepositories() == null )
{
throw new RepositorySearchException( "Repositories cannot be null." );
}
addIndexingContexts( searchFields.getRepositories() );
BooleanQuery q = new BooleanQuery();
if( searchFields.getGroupId() != null && !"".equals( searchFields.getGroupId() ) )
{
q.add( indexer.constructQuery( ArtifactInfo.GROUP_ID, searchFields.getGroupId() ), Occur.MUST );
}
if( searchFields.getArtifactId() != null && !"".equals( searchFields.getArtifactId() ) )
{
q.add( indexer.constructQuery( ArtifactInfo.ARTIFACT_ID, searchFields.getArtifactId() ), Occur.MUST );
}
if( searchFields.getVersion() != null && !"".equals( searchFields.getVersion() ) )
{
q.add( indexer.constructQuery( ArtifactInfo.VERSION, searchFields.getVersion() ), Occur.MUST );
}
if( searchFields.getPackaging() != null && !"".equals( searchFields.getPackaging() ) )
{
q.add( indexer.constructQuery( ArtifactInfo.PACKAGING, searchFields.getPackaging() ), Occur.MUST );
}
if( searchFields.getClassName() != null && !"".equals( searchFields.getClassName() ) )
{
q.add( indexer.constructQuery( ArtifactInfo.NAMES, searchFields.getClassName() ), Occur.MUST );
}
if( q.getClauses() == null || q.getClauses().length <= 0 )
{
throw new RepositorySearchException( "No search fields set." );
}
return search( limits, q );
}
private SearchResults search( SearchResultLimits limits, BooleanQuery q )
throws RepositorySearchException
{
try
{
FlatSearchRequest request = new FlatSearchRequest( q );
FlatSearchResponse response = indexer.searchFlat( request );
if( response == null || response.getTotalHits() == 0 )
{
return new SearchResults();
}
return convertToSearchResults( response, limits );
}
catch ( IndexContextInInconsistentStateException e )
{
throw new RepositorySearchException( e );
}
catch ( IOException e )
{
throw new RepositorySearchException( e );
}
finally
{
Map<String, IndexingContext> indexingContexts = indexer.getIndexingContexts();
Set<String> keys = indexingContexts.keySet();
for( String key : keys )
{
try
{
indexer.removeIndexingContext( indexingContexts.get( key ), false );
log.debug( "Indexing context '" + key + "' removed from search." );
}
catch ( IOException e )
{
log.warn( "IOException occurred while removing indexing content '" + key + "'." );
continue;
}
}
}
}
private void constructQuery( String term, BooleanQuery q )
{
q.add( indexer.constructQuery( ArtifactInfo.GROUP_ID, term ), Occur.SHOULD );
q.add( indexer.constructQuery( ArtifactInfo.ARTIFACT_ID, term ), Occur.SHOULD );
q.add( indexer.constructQuery( ArtifactInfo.VERSION, term ), Occur.SHOULD );
q.add( indexer.constructQuery( ArtifactInfo.PACKAGING, term ), Occur.SHOULD );
q.add( indexer.constructQuery( ArtifactInfo.NAMES, term ), Occur.SHOULD );
}
private void addIndexingContexts( List<String> selectedRepos )
{
for( String repo : selectedRepos )
{
try
{
Configuration config = archivaConfig.getConfiguration();
ManagedRepositoryConfiguration repoConfig = config.findManagedRepositoryById( repo );
if( repoConfig != null )
{
String indexDir = repoConfig.getIndexDir();
File indexDirectory = null;
if( indexDir != null && !"".equals( indexDir ) )
{
indexDirectory = new File( repoConfig.getIndexDir() );
}
else
{
indexDirectory = new File( repoConfig.getLocation(), ".indexer" );
}
IndexingContext context =
indexer.addIndexingContext( repoConfig.getId(), repoConfig.getId(), new File( repoConfig.getLocation() ),
indexDirectory, null, null, NexusIndexer.FULL_INDEX );
context.setSearchable( repoConfig.isScanned() );
}
else
{
log.warn( "Repository '" + repo + "' not found in configuration." );
}
}
catch ( UnsupportedExistingLuceneIndexException e )
{
log.warn( "Error accessing index of repository '" + repo + "' : " + e.getMessage() );
continue;
}
catch ( IOException e )
{
log.warn( "IO error occured while accessing index of repository '" + repo + "' : " + e.getMessage() );
continue;
}
}
}
private SearchResults convertToSearchResults( FlatSearchResponse response, SearchResultLimits limits )
{
SearchResults results = new SearchResults();
Set<ArtifactInfo> artifactInfos = response.getResults();
for ( ArtifactInfo artifactInfo : artifactInfos )
{
String id = SearchUtil.getHitId( artifactInfo.groupId, artifactInfo.artifactId );
Map<String, SearchResultHit> hitsMap = results.getHitsMap();
SearchResultHit hit = hitsMap.get( id );
if ( hit != null )
{
hit.addVersion( artifactInfo.version );
}
else
{
hit = new SearchResultHit();
hit.setArtifactId( artifactInfo.artifactId );
hit.setGroupId( artifactInfo.groupId );
// do we still need to set the repository id even though we're merging everything?
//hit.setRepositoryId( artifactInfo.repository );
hit.setUrl( artifactInfo.repository + "/" + artifactInfo.fname );
if( !hit.getVersions().contains( artifactInfo.version ) )
{
hit.addVersion( artifactInfo.version );
}
}
results.addHit( id, hit );
}
results.setTotalHits( results.getHitsMap().size() );
if( limits == null || limits.getSelectedPage() == SearchResultLimits.ALL_PAGES )
{
return results;
}
else
{
return paginate( limits, results );
}
}
private SearchResults paginate( SearchResultLimits limits, SearchResults results )
{
SearchResults paginated = new SearchResults();
int fetchCount = limits.getPageSize();
int offset = ( limits.getSelectedPage() * limits.getPageSize() );
if( fetchCount > results.getTotalHits() )
{
fetchCount = results.getTotalHits();
}
// Goto offset.
if ( offset < results.getTotalHits() )
{
// only process if the offset is within the hit count.
for ( int i = 0; i < fetchCount; i++ )
{
// Stop fetching if we are past the total # of available hits.
if ( offset + i >= results.getHits().size() )
{
break;
}
SearchResultHit hit = results.getHits().get( ( offset + i ) );
if( hit != null )
{
String id = SearchUtil.getHitId( hit.getGroupId(), hit.getArtifactId() );
paginated.addHit( id, hit );
}
else
{
break;
}
}
}
paginated.setTotalHits( results.getTotalHits() );
return paginated;
}
}

View File

@ -0,0 +1,53 @@
package org.apache.archiva.indexer.search;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.util.List;
import org.apache.maven.archiva.indexer.search.SearchResultLimits;
import org.apache.maven.archiva.indexer.search.SearchResults;
public interface RepositorySearch
{
/**
* Quick search.
*
* @param principal
* @param selectedRepos
* @param term
* @param limits
* @param previousSearchTerms
* @return
*/
SearchResults search( String principal, List<String> selectedRepos, String term, SearchResultLimits limits,
List<String> previousSearchTerms )
throws RepositorySearchException;
/**
* Advanced search.
*
* @param principal
* @param searchFields
* @param limits
* @return
*/
SearchResults search( String principal, SearchFields searchFields, SearchResultLimits limits )
throws RepositorySearchException;
}

View File

@ -0,0 +1,44 @@
package org.apache.archiva.indexer.search;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
public class RepositorySearchException
extends Exception
{
public RepositorySearchException()
{
super();
}
public RepositorySearchException( String msg )
{
super( msg );
}
public RepositorySearchException( Throwable e )
{
super( e );
}
public RepositorySearchException( String msg, Throwable e )
{
super( msg, e );
}
}

View File

@ -0,0 +1,132 @@
package org.apache.archiva.indexer.search;
import java.util.ArrayList;
import java.util.List;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
public class SearchFields
{
/**
* groupId
*/
private String groupId;
/**
* artifactId
*/
private String artifactId;
/**
* version
*/
private String version;
/**
* packaging (jar, war, pom, etc.)
*/
private String packaging;
/**
* class name or package name
*/
private String className;
/**
* repositories
*/
private List<String> repositories = new ArrayList<String>();
public SearchFields()
{
}
public SearchFields( String groupId, String artifactId, String version, String packaging, String className,
List<String> repositories )
{
this.groupId = groupId;
this.artifactId = artifactId;
this.version = version;
this.packaging = packaging;
this.className = className;
this.repositories = repositories;
}
public String getGroupId()
{
return groupId;
}
public void setGroupId( String groupId )
{
this.groupId = groupId;
}
public String getArtifactId()
{
return artifactId;
}
public void setArtifactId( String artifactId )
{
this.artifactId = artifactId;
}
public String getVersion()
{
return version;
}
public void setVersion( String version )
{
this.version = version;
}
public String getPackaging()
{
return packaging;
}
public void setPackaging( String packaging )
{
this.packaging = packaging;
}
public String getClassName()
{
return className;
}
public void setClassName( String className )
{
this.className = className;
}
public List<String> getRepositories()
{
return repositories;
}
public void setRepositories( List<String> repositories )
{
this.repositories = repositories;
}
}

View File

@ -59,4 +59,9 @@ public class SearchUtil
return qString;
}
public static String getHitId( String groupId, String artifactId )
{
return groupId + ":" + artifactId;
}
}

View File

@ -44,6 +44,7 @@ public class SearchResultHit
// Advanced hit, reference to artifactId.
private String artifactId;
// TODO: remove/deprecate this field!
private String version = "";
private String repositoryId = "";
@ -157,4 +158,14 @@ public class SearchResultHit
{
this.repositoryId = repositoryId;
}
public void addVersion( String version )
{
if( versions == null )
{
versions = new ArrayList<String>();
}
versions.add( version );
}
}

View File

@ -51,6 +51,12 @@ public class SearchResults
/* do nothing */
}
// for new RepositorySearch
public void addHit( String id, SearchResultHit hit )
{
hits.put( id, hit );
}
public void addHit( LuceneRepositoryContentRecord record )
{
if ( record instanceof FileContentRecord )
@ -149,6 +155,11 @@ public class SearchResults
{
return new ArrayList( hits.values() );
}
public Map<String, SearchResultHit> getHitsMap()
{
return hits;
}
public List getRepositories()
{

View File

@ -0,0 +1,55 @@
<?xml version="1.0" ?>
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<component-set>
<components>
<component>
<role>org.sonatype.nexus.index.NexusIndexer</role>
<role-hint>archiva</role-hint>
<implementation>org.sonatype.nexus.index.DefaultNexusIndexer</implementation>
<description>The default nexus indexer implementation.</description>
<instantiation-strategy>per-lookup</instantiation-strategy>
<isolated-realm>false</isolated-realm>
<requirements>
<requirement>
<role>org.sonatype.nexus.index.scan.Scanner</role>
<role-hint>default</role-hint>
<field-name>scanner</field-name>
</requirement>
<requirement>
<role>org.sonatype.nexus.index.search.SearchEngine</role>
<role-hint>default</role-hint>
<field-name>searcher</field-name>
</requirement>
<requirement>
<role>org.sonatype.nexus.index.creator.IndexerEngine</role>
<role-hint>default</role-hint>
<field-name>indexerEngine</field-name>
</requirement>
<requirement>
<role>org.sonatype.nexus.index.QueryCreator</role>
<role-hint>default</role-hint>
<field-name>queryCreator</field-name>
</requirement>
</requirements>
</component>
</components>
</component-set>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="nexusSearch" class="org.apache.archiva.indexer.search.NexusRepositorySearch">
<constructor-arg ref="nexusIndexer#archiva"/>
<constructor-arg ref="archivaConfiguration"/>
</bean>
</beans>

View File

@ -0,0 +1,426 @@
package org.apache.archiva.indexer.search;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.maven.archiva.configuration.ArchivaConfiguration;
import org.apache.maven.archiva.configuration.Configuration;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.maven.archiva.indexer.search.SearchResultHit;
import org.apache.maven.archiva.indexer.search.SearchResultLimits;
import org.apache.maven.archiva.indexer.search.SearchResults;
import org.codehaus.plexus.spring.PlexusInSpringTestCase;
import org.easymock.MockControl;
import org.sonatype.nexus.index.ArtifactContext;
import org.sonatype.nexus.index.ArtifactContextProducer;
import org.sonatype.nexus.index.NexusIndexer;
import org.sonatype.nexus.index.context.IndexingContext;
import org.sonatype.nexus.index.context.UnsupportedExistingLuceneIndexException;
import org.sonatype.nexus.index.creator.IndexerEngine;
public class NexusRepositorySearchTest
extends PlexusInSpringTestCase
{
private RepositorySearch search;
private ArchivaConfiguration archivaConfig;
private NexusIndexer indexer;
private IndexingContext context;
private IndexerEngine indexerEngine;
private ArtifactContextProducer artifactContextProducer;
private MockControl archivaConfigControl;
private Configuration config;
private final static String TEST_REPO_1 = "nexus-search-test-repo";
private final static String TEST_REPO_2 = "nexus-search-test-repo-2";
@Override
protected void setUp()
throws Exception
{
super.setUp();
indexer = (NexusIndexer) lookup( NexusIndexer.class );
archivaConfigControl = MockControl.createControl( ArchivaConfiguration.class );
archivaConfig = (ArchivaConfiguration) archivaConfigControl.getMock();
search = new NexusRepositorySearch( indexer, archivaConfig );
indexerEngine = (IndexerEngine) lookup( IndexerEngine.class );
artifactContextProducer = (ArtifactContextProducer) lookup( ArtifactContextProducer.class );
config = new Configuration();
config.addManagedRepository( createRepositoryConfig( TEST_REPO_1 ) );
List<File> files = new ArrayList<File>();
files.add( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_1 +
"/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.jar" ) );
files.add( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_1 +
"/org/apache/archiva/archiva-test/1.0/archiva-test-1.0.jar" ) );
files.add( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_1 +
"/org/apache/archiva/archiva-test/2.0/archiva-test-2.0.jar" ) );
createIndex( TEST_REPO_1, files );
}
private ManagedRepositoryConfiguration createRepositoryConfig( String repository )
{
ManagedRepositoryConfiguration repositoryConfig = new ManagedRepositoryConfiguration();
repositoryConfig.setId( repository );
repositoryConfig.setLocation( getBasedir() + "/target/test-classes/" + repository );
repositoryConfig.setLayout( "default" );
repositoryConfig.setName( repository );
repositoryConfig.setScanned( true );
repositoryConfig.setSnapshots( false );
repositoryConfig.setReleases( true );
return repositoryConfig;
}
@Override
protected void tearDown()
throws Exception
{
FileUtils.deleteDirectory( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_1 + "/.indexer" ) );
assertFalse( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_1 + "/.indexer" ).exists() );
super.tearDown();
}
private void createIndex( String repository, List<File> filesToBeIndexed )
throws IOException, UnsupportedExistingLuceneIndexException
{
context =
indexer.addIndexingContext( repository, repository, new File( getBasedir(), "/target/test-classes/" +
repository ), new File( getBasedir(), "/target/test-classes/" + repository + "/.indexer" ), null, null,
NexusIndexer.FULL_INDEX );
context.setSearchable( true );
indexerEngine.beginIndexing( context );
for ( File artifactFile : filesToBeIndexed )
{
ArtifactContext ac = artifactContextProducer.getArtifactContext( context, artifactFile );
indexerEngine.index( context, ac );
}
indexerEngine.endIndexing( context );
indexer.removeIndexingContext( context, false );
assertTrue( new File( getBasedir(), "/target/test-classes/" + repository + "/.indexer" ).exists() );
}
public void testQuickSearch()
throws Exception
{
List<String> selectedRepos = new ArrayList<String>();
selectedRepos.add( TEST_REPO_1 );
// search artifactId
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config );
archivaConfigControl.replay();
SearchResults results = search.search( "user", selectedRepos, "archiva-search", null, null );
archivaConfigControl.verify();
assertNotNull( results );
assertEquals( 1, results.getTotalHits() );
SearchResultHit hit = results.getHits().get( 0 );
assertEquals( "org.apache.archiva", hit.getGroupId() );
assertEquals( "archiva-search", hit.getArtifactId() );
assertEquals( "1.0", hit.getVersions().get( 0 ) );
archivaConfigControl.reset();
// search groupId
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config );
archivaConfigControl.replay();
results = search.search( "user", selectedRepos, "org.apache.archiva", null, null );
archivaConfigControl.verify();
assertNotNull( results );
assertEquals( 2, results.getTotalHits() );
//TODO: search for class & package names
}
public void testQuickSearchWithPagination()
throws Exception
{
List<String> selectedRepos = new ArrayList<String>();
selectedRepos.add( TEST_REPO_1 );
// page 1
SearchResultLimits limits = new SearchResultLimits( 0 );
limits.setPageSize( 1 );
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config );
archivaConfigControl.replay();
SearchResults results = search.search( "user", selectedRepos, "org", limits, null );
archivaConfigControl.verify();
assertNotNull( results );
assertEquals( 1, results.getHits().size() );
assertEquals( 2, results.getTotalHits() );
archivaConfigControl.reset();
// page 2
limits = new SearchResultLimits( 1 );
limits.setPageSize( 1 );
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config );
archivaConfigControl.replay();
results = search.search( "user", selectedRepos, "org", limits, null );
archivaConfigControl.verify();
assertNotNull( results );
assertEquals( 1, results.getHits().size() );
assertEquals( 2, results.getTotalHits() );
}
public void testArtifactFoundInMultipleRepositories()
throws Exception
{
List<File> files = new ArrayList<File>();
files.add( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 +
"/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.jar" ) );
files.add( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 +
"/org/apache/archiva/archiva-search/1.1/archiva-search-1.1.jar" ) );
createIndex( TEST_REPO_2, files );
List<String> selectedRepos = new ArrayList<String>();
selectedRepos.add( TEST_REPO_1 );
selectedRepos.add( TEST_REPO_2 );
config.addManagedRepository( createRepositoryConfig( TEST_REPO_2 ) );
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config, 2 );
archivaConfigControl.replay();
SearchResults results = search.search( "user", selectedRepos, "archiva-search", null, null );
archivaConfigControl.verify();
assertNotNull( results );
assertEquals( 1, results.getTotalHits() );
SearchResultHit hit = results.getHits().get( 0 );
assertEquals( "org.apache.archiva", hit.getGroupId() );
assertEquals( "archiva-search", hit.getArtifactId() );
assertEquals( 2, hit.getVersions().size() );
assertTrue( hit.getVersions().contains( "1.0" ) );
assertTrue( hit.getVersions().contains( "1.1" ) );
archivaConfigControl.reset();
FileUtils.deleteDirectory( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 + "/.indexer" ) );
assertFalse( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 + "/.indexer" ).exists() );
// TODO: [BROWSE] in artifact info from browse, display all the repositories where the artifact is found
}
public void testNoMatchFound()
throws Exception
{
List<String> selectedRepos = new ArrayList<String>();
selectedRepos.add( TEST_REPO_1 );
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config );
archivaConfigControl.replay();
SearchResults results = search.search( "user", selectedRepos, "dfghdfkweriuasndsaie", null, null );
archivaConfigControl.verify();
assertNotNull( results );
assertEquals( 0, results.getTotalHits() );
}
public void testNoIndexFound()
throws Exception
{
List<String> selectedRepos = new ArrayList<String>();
selectedRepos.add( "non-existing-repo" );
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config );
archivaConfigControl.replay();
SearchResults results = search.search( "user", selectedRepos, "org.apache.archiva", null, null );
assertNotNull( results );
assertEquals( 0, results.getTotalHits() );
archivaConfigControl.verify();
}
public void testSearchWithinSearchResults()
throws Exception
{
List<String> selectedRepos = new ArrayList<String>();
selectedRepos.add( TEST_REPO_1 );
List<String> previousSearchTerms = new ArrayList<String>();
previousSearchTerms.add( "archiva-test" );
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config );
archivaConfigControl.replay();
SearchResults results = search.search( "user", selectedRepos, "1.0", null, previousSearchTerms );
archivaConfigControl.verify();
assertNotNull( results );
assertEquals( 1, results.getTotalHits() );
SearchResultHit hit = results.getHits().get( 0 );
assertEquals( "org.apache.archiva", hit.getGroupId() );
assertEquals( "archiva-test", hit.getArtifactId() );
assertEquals( 1, hit.getVersions().size() );
assertEquals( "1.0", hit.getVersions().get( 0 ) );
}
public void testAdvancedSearch()
throws Exception
{
List<File> files = new ArrayList<File>();
files.add( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 +
"/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.jar" ) );
files.add( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 +
"/org/apache/archiva/archiva-search/1.1/archiva-search-1.1.jar" ) );
createIndex( TEST_REPO_2, files );
List<String> selectedRepos = new ArrayList<String>();
selectedRepos.add( TEST_REPO_1 );
selectedRepos.add( TEST_REPO_2 );
config.addManagedRepository( createRepositoryConfig( TEST_REPO_2 ) );
SearchFields searchFields = new SearchFields();
searchFields.setGroupId( "org.apache.archiva" );
searchFields.setVersion( "1.0" );
searchFields.setRepositories( selectedRepos );
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config, 2 );
archivaConfigControl.replay();
SearchResults results = search.search( "user", searchFields, null );
archivaConfigControl.verify();
assertNotNull( results );
assertEquals( 2, results.getTotalHits() );
FileUtils.deleteDirectory( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 + "/.indexer" ) );
assertFalse( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 + "/.indexer" ).exists() );
}
public void testAdvancedSearchWithPagination()
throws Exception
{
List<File> files = new ArrayList<File>();
files.add( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 +
"/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.jar" ) );
files.add( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 +
"/org/apache/archiva/archiva-search/1.1/archiva-search-1.1.jar" ) );
createIndex( TEST_REPO_2, files );
List<String> selectedRepos = new ArrayList<String>();
selectedRepos.add( TEST_REPO_1 );
selectedRepos.add( TEST_REPO_2 );
config.addManagedRepository( createRepositoryConfig( TEST_REPO_2 ) );
SearchFields searchFields = new SearchFields();
searchFields.setGroupId( "org.apache.archiva" );
searchFields.setVersion( "1.0" );
searchFields.setRepositories( selectedRepos );
// page 1
SearchResultLimits limits = new SearchResultLimits( 0 );
limits.setPageSize( 1 );
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config, 2 );
archivaConfigControl.replay();
SearchResults results = search.search( "user", searchFields, limits );
archivaConfigControl.verify();
assertNotNull( results );
assertEquals( 2, results.getTotalHits() );
assertEquals( 1, results.getHits().size() );
// page 2
archivaConfigControl.reset();
limits = new SearchResultLimits( 1 );
limits.setPageSize( 1 );
archivaConfigControl.expectAndReturn( archivaConfig.getConfiguration(), config, 2 );
archivaConfigControl.replay();
results = search.search( "user", searchFields, limits );
archivaConfigControl.verify();
assertNotNull( results );
assertEquals( 2, results.getTotalHits() );
assertEquals( 1, results.getHits().size() );
FileUtils.deleteDirectory( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 + "/.indexer" ) );
assertFalse( new File( getBasedir(), "/target/test-classes/" + TEST_REPO_2 + "/.indexer" ).exists() );
}
}

View File

@ -0,0 +1,28 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-search</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>Archiva Search</name>
<url>http://archiva.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,28 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-search</artifactId>
<packaging>jar</packaging>
<version>1.1</version>
<name>Archiva Search</name>
<url>http://archiva.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,28 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-search</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>Archiva Search</name>
<url>http://archiva.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.8</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,23 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-test</artifactId>
<packaging>jar</packaging>
<version>1.0</version>
<name>archiva-test</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,28 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.archiva</groupId>
<artifactId>archiva-test</artifactId>
<packaging>jar</packaging>
<version>2.0</version>
<name>Archiva Test</name>
<url>http://archiva.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.4</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,52 @@
package org.apache.archiva.repository.scanner.functors;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import org.apache.commons.collections.Closure;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.maven.archiva.consumers.RepositoryContentConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* TriggerScanCompletedClosure
*/
public class TriggerScanCompletedClosure
implements Closure
{
private Logger log = LoggerFactory.getLogger( TriggerScanCompletedClosure.class );
private final ManagedRepositoryConfiguration repository;
public TriggerScanCompletedClosure( ManagedRepositoryConfiguration repository )
{
this.repository = repository;
}
public void execute( Object input )
{
if ( input instanceof RepositoryContentConsumer )
{
RepositoryContentConsumer consumer = (RepositoryContentConsumer) input;
consumer.completeScan();
log.info( "Consumer [" + consumer.getId() + "] completed for repository [" + repository.getId() + "]" );
}
}
}

View File

@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.archiva.repository.scanner.functors.TriggerScanCompletedClosure;
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.functors.IfClosure;
@ -256,6 +257,11 @@ public class RepositoryContentConsumers implements ApplicationContextAware
// Nothing known processed this file. It is invalid!
CollectionUtils.forAllDo( selectedInvalidConsumers, closure );
}
TriggerScanCompletedClosure scanCompletedClosure = new TriggerScanCompletedClosure(repository);
CollectionUtils.forAllDo(selectedKnownConsumers, scanCompletedClosure);
CollectionUtils.forAllDo(selectedKnownConsumers, scanCompletedClosure);
}
finally
{

View File

@ -23,6 +23,7 @@ import java.io.File;
import java.util.Date;
import java.util.List;
import org.apache.archiva.repository.scanner.functors.TriggerScanCompletedClosure;
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.functors.IfClosure;
@ -144,6 +145,11 @@ public class RepositoryScannerInstance
public void directoryWalkFinished()
{
TriggerScanCompletedClosure scanCompletedClosure = new TriggerScanCompletedClosure(repository);
CollectionUtils.forAllDo( knownConsumers, scanCompletedClosure );
CollectionUtils.forAllDo( invalidConsumers, scanCompletedClosure );
log.info( "Walk Finished: [" + this.repository.getId() + "] " + this.repository.getLocation() );
stats.triggerFinished();
}

View File

@ -25,7 +25,9 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.apache.archiva.indexer.util.SearchUtil;
import org.apache.archiva.indexer.search.RepositorySearch;
import org.apache.archiva.indexer.search.RepositorySearchException;
import org.apache.archiva.indexer.search.SearchFields;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.archiva.configuration.ArchivaConfiguration;
@ -35,7 +37,6 @@ import org.apache.maven.archiva.database.Constraint;
import org.apache.maven.archiva.database.constraints.ArtifactsByChecksumConstraint;
import org.apache.maven.archiva.indexer.RepositoryIndexException;
import org.apache.maven.archiva.indexer.RepositoryIndexSearchException;
import org.apache.maven.archiva.indexer.search.CrossRepositorySearch;
import org.apache.maven.archiva.indexer.search.SearchResultLimits;
import org.apache.maven.archiva.indexer.search.SearchResults;
import org.apache.maven.archiva.security.AccessDeniedException;
@ -49,6 +50,9 @@ import com.opensymphony.xwork2.Preparable;
import org.apache.maven.archiva.common.utils.VersionUtil;
import org.apache.maven.archiva.database.constraints.UniqueVersionConstraint;
import org.apache.maven.archiva.indexer.search.SearchResultHit;
import org.apache.struts2.ServletActionContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
/**
* Search all indexed fields by the given criteria.
@ -78,11 +82,6 @@ public class SearchAction
* The Search Results.
*/
private SearchResults results;
/**
* @plexus.requirement role-hint="default"
*/
private CrossRepositorySearch crossRepoSearch;
/**
* @plexus.requirement
@ -130,6 +129,8 @@ public class SearchAction
private boolean fromResultsPage;
private RepositorySearch nexusSearch;
public boolean isFromResultsPage()
{
return fromResultsPage;
@ -191,10 +192,20 @@ public class SearchAction
return GlobalResults.ACCESS_TO_NO_REPOS;
}
results =
crossRepoSearch.executeFilteredSearch( getPrincipal(), selectedRepos, groupId, artifactId, version,
className, limits );
SearchFields searchFields = new SearchFields( groupId, artifactId, version, null, className, selectedRepos );
// TODO: add packaging in the list of fields for advanced search (UI)
try
{
results = getNexusSearch().search( getPrincipal(), searchFields, limits );
}
catch ( RepositorySearchException e )
{
addActionError( e.getMessage() );
return ERROR;
}
if ( results.isEmpty() )
{
addActionError( "No results found" );
@ -241,23 +252,23 @@ public class SearchAction
return GlobalResults.ACCESS_TO_NO_REPOS;
}
final boolean isbytecodeSearch = SearchUtil.isBytecodeSearch( q );
if( isbytecodeSearch )
{
results = crossRepoSearch.searchForBytecode( getPrincipal(), selectedRepos, SearchUtil.removeBytecodeKeyword( q ), limits );
}
else
try
{
if( searchResultsOnly && !completeQueryString.equals( "" ) )
{
results = crossRepoSearch.searchForTerm( getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString() );
{
results = getNexusSearch().search( getPrincipal(), selectedRepos, q, limits, parseCompleteQueryString() );
}
else
{
completeQueryString = "";
results = crossRepoSearch.searchForTerm( getPrincipal(), selectedRepos, q, limits );
completeQueryString = "";
results = getNexusSearch().search( getPrincipal(), selectedRepos, q, limits, null );
}
}
catch ( RepositorySearchException e )
{
addActionError( e.getMessage() );
return ERROR;
}
if ( results.isEmpty() )
{
@ -284,22 +295,19 @@ public class SearchAction
{
buildCompleteQueryString( q );
}
if (!isbytecodeSearch)
//Lets get the versions for the artifact we just found and display them
//Yes, this is in the lucene index but its more challenging to get them out when we are searching by project
for (SearchResultHit resultHit : results.getHits())
{
//Lets get the versions for the artifact we just found and display them
//Yes, this is in the lucene index but its more challenging to get them out when we are searching by project
for (SearchResultHit resultHit : results.getHits())
final List<String> versions = dao.query(new UniqueVersionConstraint(getObservableRepos(), resultHit.getGroupId(), resultHit.getArtifactId()));
if (versions != null && !versions.isEmpty())
{
final List<String> versions = dao.query(new UniqueVersionConstraint(getObservableRepos(), resultHit.getGroupId(), resultHit.getArtifactId()));
if (versions != null && !versions.isEmpty())
{
resultHit.setVersion(null);
resultHit.setVersions(filterTimestampedSnapshots(versions));
}
resultHit.setVersion(null);
resultHit.setVersions(filterTimestampedSnapshots(versions));
}
}
return SUCCESS;
}
@ -579,4 +587,20 @@ public class SearchAction
{
this.className = className;
}
public RepositorySearch getNexusSearch()
{
if( nexusSearch == null )
{
WebApplicationContext wac =
WebApplicationContextUtils.getRequiredWebApplicationContext( ServletActionContext.getServletContext() );
nexusSearch = ( RepositorySearch ) wac.getBean( "nexusSearch" );
}
return nexusSearch;
}
public void setNexusSearch( RepositorySearch nexusSearch )
{
this.nexusSearch = nexusSearch;
}
}

View File

@ -39,15 +39,11 @@
</bean>
<!-- Web Services : Search Service -->
<bean name="searchService" lazy-init="true" scope="singleton" class="org.apache.archiva.web.xmlrpc.services.SearchServiceImpl">
<!--
<constructor-arg ref="archivaConfiguration"/>
<constructor-arg ref="repositoryContentFactory"/>
-->
<constructor-arg ref="xmlRpcUserRepositories"/>
<constructor-arg ref="crossRepositorySearch"/>
<bean name="searchService" lazy-init="true" scope="singleton" class="org.apache.archiva.web.xmlrpc.services.SearchServiceImpl">
<constructor-arg ref="xmlRpcUserRepositories"/>
<constructor-arg ref="archivaDAO#jdo"/>
<constructor-arg ref="repositoryBrowsing"/>
<constructor-arg ref="nexusSearch"/>
</bean>
<!-- Web Services : Administration Service -->

View File

@ -23,7 +23,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.archiva.indexer.util.SearchUtil;
import org.apache.archiva.indexer.search.RepositorySearch;
import org.apache.archiva.web.xmlrpc.api.SearchService;
import org.apache.archiva.web.xmlrpc.api.beans.Artifact;
import org.apache.archiva.web.xmlrpc.api.beans.Dependency;
@ -35,7 +35,6 @@ import org.apache.maven.archiva.database.ObjectNotFoundException;
import org.apache.maven.archiva.database.browsing.BrowsingResults;
import org.apache.maven.archiva.database.browsing.RepositoryBrowsing;
import org.apache.maven.archiva.database.constraints.ArtifactsByChecksumConstraint;
import org.apache.maven.archiva.indexer.search.CrossRepositorySearch;
import org.apache.maven.archiva.indexer.search.SearchResultHit;
import org.apache.maven.archiva.indexer.search.SearchResultLimits;
import org.apache.maven.archiva.indexer.search.SearchResults;
@ -50,8 +49,7 @@ import org.apache.maven.archiva.model.ArchivaProjectModel;
public class SearchServiceImpl
implements SearchService
{
private CrossRepositorySearch crossRepoSearch;
private RepositorySearch search;
private XmlRpcUserRepositories xmlRpcUserRepositories;
@ -59,13 +57,13 @@ public class SearchServiceImpl
private RepositoryBrowsing repoBrowsing;
public SearchServiceImpl( XmlRpcUserRepositories xmlRpcUserRepositories, CrossRepositorySearch crossRepoSearch,
ArchivaDAO archivaDAO, RepositoryBrowsing repoBrowsing )
public SearchServiceImpl( XmlRpcUserRepositories xmlRpcUserRepositories, ArchivaDAO archivaDAO,
RepositoryBrowsing repoBrowsing, RepositorySearch search )
{
this.xmlRpcUserRepositories = xmlRpcUserRepositories;
this.crossRepoSearch = crossRepoSearch;
this.archivaDAO = archivaDAO;
this.repoBrowsing = repoBrowsing;
this.search = search;
}
/*
@ -90,15 +88,8 @@ public class SearchServiceImpl
SearchResultLimits limits = new SearchResultLimits( SearchResultLimits.ALL_PAGES );
SearchResults results = null;
if( SearchUtil.isBytecodeSearch( queryString ) )
{
results = crossRepoSearch.searchForBytecode( "", observableRepos, SearchUtil.removeBytecodeKeyword( queryString ), limits );
}
else
{
results = crossRepoSearch.searchForTerm( "", observableRepos, queryString, limits );
}
results = search.search( "", observableRepos, queryString, limits, null );
List<SearchResultHit> hits = results.getHits();
for( SearchResultHit hit : hits )
{

View File

@ -20,20 +20,15 @@ package org.apache.archiva.web.xmlrpc.services;
*/
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.archiva.indexer.search.RepositorySearch;
import org.apache.archiva.web.xmlrpc.api.SearchService;
import org.apache.archiva.web.xmlrpc.api.beans.Artifact;
import org.apache.archiva.web.xmlrpc.api.beans.Dependency;
import org.apache.archiva.web.xmlrpc.security.XmlRpcAuthenticator;
import org.apache.archiva.web.xmlrpc.security.XmlRpcUserRepositories;
import org.apache.maven.archiva.configuration.ArchivaConfiguration;
import org.apache.maven.archiva.configuration.Configuration;
import org.apache.maven.archiva.configuration.FileTypes;
import org.apache.maven.archiva.configuration.ManagedRepositoryConfiguration;
import org.apache.maven.archiva.database.ArchivaDAO;
import org.apache.maven.archiva.database.ArtifactDAO;
import org.apache.maven.archiva.database.ObjectNotFoundException;
@ -41,33 +36,14 @@ import org.apache.maven.archiva.database.browsing.BrowsingResults;
import org.apache.maven.archiva.database.browsing.RepositoryBrowsing;
import org.apache.maven.archiva.database.constraints.ArtifactsByChecksumConstraint;
import org.apache.maven.archiva.indexer.filecontent.FileContentRecord;
import org.apache.maven.archiva.indexer.lucene.LuceneRepositoryContentRecord;
import org.apache.maven.archiva.indexer.search.CrossRepositorySearch;
import org.apache.maven.archiva.indexer.search.SearchResultLimits;
import org.apache.maven.archiva.indexer.search.SearchResults;
import org.apache.maven.archiva.model.ArchivaArtifact;
import org.apache.maven.archiva.model.ArchivaArtifactModel;
import org.apache.maven.archiva.model.ArchivaProjectModel;
import org.apache.maven.archiva.model.ArtifactReference;
import org.apache.maven.archiva.repository.ManagedRepositoryContent;
import org.apache.maven.archiva.repository.RepositoryContentFactory;
import org.apache.maven.archiva.repository.content.ManagedDefaultRepositoryContent;
import org.apache.maven.archiva.repository.content.PathParser;
import org.apache.maven.archiva.security.ArchivaRoleConstants;
import org.apache.xmlrpc.XmlRpcRequest;
import org.apache.xmlrpc.common.XmlRpcHttpRequestConfigImpl;
import org.codehaus.plexus.redback.role.RoleManager;
import org.codehaus.plexus.redback.system.SecuritySystem;
import org.codehaus.plexus.redback.users.User;
import org.codehaus.plexus.redback.users.UserManager;
import org.codehaus.plexus.redback.users.UserNotFoundException;
import org.codehaus.plexus.spring.PlexusInSpringTestCase;
import org.easymock.ArgumentsMatcher;
import org.easymock.MockControl;
import org.easymock.classextension.MockClassControl;
import sun.security.action.GetLongAction;
/**
* SearchServiceImplTest
*
@ -82,10 +58,10 @@ public class SearchServiceImplTest
private XmlRpcUserRepositories userRepos;
private MockControl crossRepoSearchControl;
private CrossRepositorySearch crossRepoSearch;
private MockControl searchControl;
private RepositorySearch search;
private MockControl archivaDAOControl;
private ArchivaDAO archivaDAO;
@ -103,17 +79,17 @@ public class SearchServiceImplTest
{
userReposControl = MockClassControl.createControl( XmlRpcUserRepositories.class );
userRepos = ( XmlRpcUserRepositories ) userReposControl.getMock();
crossRepoSearchControl = MockControl.createControl( CrossRepositorySearch.class );
crossRepoSearch = ( CrossRepositorySearch ) crossRepoSearchControl.getMock();
archivaDAOControl = MockControl.createControl( ArchivaDAO.class );
archivaDAO = ( ArchivaDAO ) archivaDAOControl.getMock();
repoBrowsingControl = MockControl.createControl( RepositoryBrowsing.class );
repoBrowsing = ( RepositoryBrowsing ) repoBrowsingControl.getMock();
searchService = new SearchServiceImpl( userRepos, crossRepoSearch, archivaDAO, repoBrowsing );
searchControl = MockControl.createControl( RepositorySearch.class );
search = ( RepositorySearch ) searchControl.getMock();
searchService = new SearchServiceImpl( userRepos, archivaDAO, repoBrowsing, search );
artifactDAOControl = MockControl.createControl( ArtifactDAO.class );
artifactDAO = ( ArtifactDAO ) artifactDAOControl.getMock();
@ -158,21 +134,20 @@ public class SearchServiceImplTest
SearchResultLimits limits = new SearchResultLimits( SearchResultLimits.ALL_PAGES );
crossRepoSearchControl.expectAndDefaultReturn(
crossRepoSearch.searchForBytecode( "", observableRepoIds, "MyClassName", limits ), results );
searchControl.expectAndDefaultReturn( search.search( "", observableRepoIds, "MyClassName", limits, null ), results );
archivaDAOControl.expectAndReturn( archivaDAO.getArtifactDAO(), artifactDAO );
artifactDAOControl.expectAndReturn( artifactDAO.getArtifact( "org.apache.archiva", "archiva-test", "1.0", "", "pom" ), artifact );
userReposControl.replay();
crossRepoSearchControl.replay();
searchControl.replay();
archivaDAOControl.replay();
artifactDAOControl.replay();
List<Artifact> artifacts = searchService.quickSearch( "bytecode:MyClassName" );
userReposControl.verify();
crossRepoSearchControl.verify();
searchControl.verify();
archivaDAOControl.verify();
artifactDAOControl.verify();
@ -203,21 +178,20 @@ public class SearchServiceImplTest
SearchResultLimits limits = new SearchResultLimits( SearchResultLimits.ALL_PAGES );
crossRepoSearchControl.expectAndDefaultReturn(
crossRepoSearch.searchForTerm( "", observableRepoIds, "archiva", limits ), results );
searchControl.expectAndDefaultReturn( search.search( "", observableRepoIds, "archiva", limits, null ), results );
archivaDAOControl.expectAndReturn( archivaDAO.getArtifactDAO(), artifactDAO );
artifactDAOControl.expectAndReturn( artifactDAO.getArtifact( "org.apache.archiva", "archiva-test", "1.0", "", "pom" ), artifact );
userReposControl.replay();
crossRepoSearchControl.replay();
searchControl.replay();
archivaDAOControl.replay();
artifactDAOControl.replay();
List<Artifact> artifacts = searchService.quickSearch( "archiva" );
userReposControl.verify();
crossRepoSearchControl.verify();
searchControl.verify();
archivaDAOControl.verify();
artifactDAOControl.verify();

View File

@ -1,27 +0,0 @@
<component-set>
<components>
<component>
<role>org.apache.maven.archiva.configuration.ArchivaConfiguration</role>
<implementation>org.apache.maven.archiva.configuration.DefaultArchivaConfiguration</implementation>
<requirements>
<requirement>
<role>org.codehaus.plexus.registry.Registry</role>
<role-hint>configured</role-hint>
</requirement>
</requirements>
</component>
<component>
<role>org.codehaus.plexus.registry.Registry</role>
<role-hint>configured</role-hint>
<implementation>org.codehaus.plexus.registry.commons.CommonsConfigurationRegistry</implementation>
<configuration>
<properties>
<system/>
<xml fileName="${basedir}/target/test-conf/archiva.xml"
config-name="org.apache.maven.archiva.base" config-at="org.apache.maven.archiva"/>
</properties>
</configuration>
</component>
</components>
</component-set>

31
pom.xml
View File

@ -245,6 +245,37 @@
<artifactId>xercesImpl</artifactId>
<version>2.8.1</version>
</dependency>
<dependency>
<groupId>org.sonatype.nexus</groupId>
<artifactId>nexus-indexer</artifactId>
<version>1.1.1</version>
<exclusions>
<exclusion>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-container-default</artifactId>
</exclusion>
<exclusion>
<groupId>classworlds</groupId>
<artifactId>classworlds</artifactId>
</exclusion>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<exclusion>
<groupId>velocity</groupId>
<artifactId>velocity-dep</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-registry</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.maven</groupId>
<artifactId>maven-settings</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>