diff --git a/archiva-modules/archiva-base/archiva-consumers/archiva-consumer-api/src/main/java/org/apache/maven/archiva/consumers/RepositoryContentConsumer.java b/archiva-modules/archiva-base/archiva-consumers/archiva-consumer-api/src/main/java/org/apache/maven/archiva/consumers/RepositoryContentConsumer.java
index 595da491e..203e5bd76 100644
--- a/archiva-modules/archiva-base/archiva-consumers/archiva-consumer-api/src/main/java/org/apache/maven/archiva/consumers/RepositoryContentConsumer.java
+++ b/archiva-modules/archiva-base/archiva-consumers/archiva-consumer-api/src/main/java/org/apache/maven/archiva/consumers/RepositoryContentConsumer.java
@@ -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.
*
- *
- * @todo! this is never called by the RepositoryScannerInstance
*/
public void completeScan();
diff --git a/archiva-modules/archiva-base/archiva-consumers/archiva-lucene-consumers/src/main/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumer.java b/archiva-modules/archiva-base/archiva-consumers/archiva-lucene-consumers/src/main/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumer.java
new file mode 100644
index 000000000..8a34836de
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-consumers/archiva-lucene-consumers/src/main/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumer.java
@@ -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 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();
+
+ 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 getExcludes()
+ {
+ return new ArrayList();
+ }
+
+ public List getIncludes()
+ {
+ return Arrays.asList( "**/*" );
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-consumers/archiva-lucene-consumers/src/main/resources/META-INF/spring-context.xml b/archiva-modules/archiva-base/archiva-consumers/archiva-lucene-consumers/src/main/resources/META-INF/spring-context.xml
new file mode 100644
index 000000000..815236176
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-consumers/archiva-lucene-consumers/src/main/resources/META-INF/spring-context.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/archiva-modules/archiva-base/archiva-consumers/archiva-lucene-consumers/src/test/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumerTest.java b/archiva-modules/archiva-base/archiva-consumers/archiva-lucene-consumers/src/test/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumerTest.java
new file mode 100644
index 000000000..7b3ec1441
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-consumers/archiva-lucene-consumers/src/test/java/org/apache/archiva/consumers/lucene/NexusIndexerConsumerTest.java
@@ -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 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 );
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-indexer/pom.xml b/archiva-modules/archiva-base/archiva-indexer/pom.xml
index 13b1b2b92..54d8a7a2a 100644
--- a/archiva-modules/archiva-base/archiva-indexer/pom.xml
+++ b/archiva-modules/archiva-base/archiva-indexer/pom.xml
@@ -65,6 +65,10 @@
commons-io
commons-io
+
+ org.sonatype.nexus
+ nexus-indexer
+
@@ -79,6 +83,24 @@
+
+ org.codehaus.plexus
+ plexus-maven-plugin
+
+
+ merge
+
+ merge-descriptors
+
+
+
+ ${basedir}/src/main/resources/META-INF/plexus/components.xml
+ ${project.build.directory}/generated-resources/plexus/META-INF/plexus/components.xml
+
+
+
+
+
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/NexusRepositorySearch.java b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/NexusRepositorySearch.java
new file mode 100644
index 000000000..75ddecc11
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/NexusRepositorySearch.java
@@ -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 selectedRepos, String term, SearchResultLimits limits,
+ List 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 indexingContexts = indexer.getIndexingContexts();
+ Set 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 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 artifactInfos = response.getResults();
+
+ for ( ArtifactInfo artifactInfo : artifactInfos )
+ {
+ String id = SearchUtil.getHitId( artifactInfo.groupId, artifactInfo.artifactId );
+ Map 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;
+ }
+
+}
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/RepositorySearch.java b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/RepositorySearch.java
new file mode 100644
index 000000000..7e20f0892
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/RepositorySearch.java
@@ -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 selectedRepos, String term, SearchResultLimits limits,
+ List previousSearchTerms )
+ throws RepositorySearchException;
+
+ /**
+ * Advanced search.
+ *
+ * @param principal
+ * @param searchFields
+ * @param limits
+ * @return
+ */
+ SearchResults search( String principal, SearchFields searchFields, SearchResultLimits limits )
+ throws RepositorySearchException;
+}
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/RepositorySearchException.java b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/RepositorySearchException.java
new file mode 100644
index 000000000..364cce2c2
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/RepositorySearchException.java
@@ -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 );
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/SearchFields.java b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/SearchFields.java
new file mode 100644
index 000000000..af8813213
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/search/SearchFields.java
@@ -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 repositories = new ArrayList();
+
+ public SearchFields()
+ {
+
+ }
+
+ public SearchFields( String groupId, String artifactId, String version, String packaging, String className,
+ List 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 getRepositories()
+ {
+ return repositories;
+ }
+
+ public void setRepositories( List repositories )
+ {
+ this.repositories = repositories;
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/util/SearchUtil.java b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/util/SearchUtil.java
index 3a57ec8c8..3e1e7627e 100644
--- a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/util/SearchUtil.java
+++ b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/archiva/indexer/util/SearchUtil.java
@@ -59,4 +59,9 @@ public static String removeBytecodeKeyword( String queryString )
return qString;
}
+
+ public static String getHitId( String groupId, String artifactId )
+ {
+ return groupId + ":" + artifactId;
+ }
}
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/SearchResultHit.java b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/SearchResultHit.java
index ba3bca500..590280b2d 100644
--- a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/SearchResultHit.java
+++ b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/SearchResultHit.java
@@ -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 void setRepositoryId( String repositoryId )
{
this.repositoryId = repositoryId;
}
+
+ public void addVersion( String version )
+ {
+ if( versions == null )
+ {
+ versions = new ArrayList();
+ }
+
+ versions.add( version );
+ }
}
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/SearchResults.java b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/SearchResults.java
index ecb01fbcf..2c961d0d8 100644
--- a/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/SearchResults.java
+++ b/archiva-modules/archiva-base/archiva-indexer/src/main/java/org/apache/maven/archiva/indexer/search/SearchResults.java
@@ -51,6 +51,12 @@ public 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 List getHits()
{
return new ArrayList( hits.values() );
}
+
+ public Map getHitsMap()
+ {
+ return hits;
+ }
public List getRepositories()
{
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/resources/META-INF/plexus/components.xml b/archiva-modules/archiva-base/archiva-indexer/src/main/resources/META-INF/plexus/components.xml
new file mode 100644
index 000000000..8e03700cc
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/main/resources/META-INF/plexus/components.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+ org.sonatype.nexus.index.NexusIndexer
+ archiva
+ org.sonatype.nexus.index.DefaultNexusIndexer
+ The default nexus indexer implementation.
+ per-lookup
+ false
+
+
+ org.sonatype.nexus.index.scan.Scanner
+ default
+ scanner
+
+
+ org.sonatype.nexus.index.search.SearchEngine
+ default
+ searcher
+
+
+ org.sonatype.nexus.index.creator.IndexerEngine
+ default
+ indexerEngine
+
+
+ org.sonatype.nexus.index.QueryCreator
+ default
+ queryCreator
+
+
+
+
+
+
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/main/resources/META-INF/spring-context.xml b/archiva-modules/archiva-base/archiva-indexer/src/main/resources/META-INF/spring-context.xml
new file mode 100644
index 000000000..bc69c7e36
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/main/resources/META-INF/spring-context.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/archiva/indexer/search/NexusRepositorySearchTest.java b/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/archiva/indexer/search/NexusRepositorySearchTest.java
new file mode 100644
index 000000000..94967ed81
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/test/java/org/apache/archiva/indexer/search/NexusRepositorySearchTest.java
@@ -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 files = new ArrayList();
+ 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 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 selectedRepos = new ArrayList();
+ 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 selectedRepos = new ArrayList();
+ 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 files = new ArrayList();
+ 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 selectedRepos = new ArrayList();
+ 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 selectedRepos = new ArrayList();
+ 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 selectedRepos = new ArrayList();
+ 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 selectedRepos = new ArrayList();
+ selectedRepos.add( TEST_REPO_1 );
+
+ List previousSearchTerms = new ArrayList();
+ 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 files = new ArrayList();
+ 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 selectedRepos = new ArrayList();
+ 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 files = new ArrayList();
+ 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 selectedRepos = new ArrayList();
+ 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() );
+ }
+
+}
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.jar b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.jar
new file mode 100644
index 000000000..9c16c3ced
Binary files /dev/null and b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.jar differ
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.pom b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.pom
new file mode 100644
index 000000000..b0d983fde
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.pom
@@ -0,0 +1,28 @@
+
+ 4.0.0
+ org.apache.archiva
+ archiva-search
+ jar
+ 1.0
+ Archiva Search
+ http://archiva.apache.org
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+ commons-lang
+ commons-lang
+ 2.3
+
+
+ log4j
+ log4j
+ 1.2.8
+
+
+
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.1/archiva-search-1.1.jar b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.1/archiva-search-1.1.jar
new file mode 100644
index 000000000..97eaf869b
Binary files /dev/null and b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.1/archiva-search-1.1.jar differ
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.1/archiva-search-1.1.pom b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.1/archiva-search-1.1.pom
new file mode 100644
index 000000000..be02c7c4d
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo-2/org/apache/archiva/archiva-search/1.1/archiva-search-1.1.pom
@@ -0,0 +1,28 @@
+
+ 4.0.0
+ org.apache.archiva
+ archiva-search
+ jar
+ 1.1
+ Archiva Search
+ http://archiva.apache.org
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+ commons-lang
+ commons-lang
+ 2.3
+
+
+ log4j
+ log4j
+ 1.2.8
+
+
+
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.jar b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.jar
new file mode 100644
index 000000000..9c16c3ced
Binary files /dev/null and b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.jar differ
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.pom b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.pom
new file mode 100644
index 000000000..b0d983fde
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-search/1.0/archiva-search-1.0.pom
@@ -0,0 +1,28 @@
+
+ 4.0.0
+ org.apache.archiva
+ archiva-search
+ jar
+ 1.0
+ Archiva Search
+ http://archiva.apache.org
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+ commons-lang
+ commons-lang
+ 2.3
+
+
+ log4j
+ log4j
+ 1.2.8
+
+
+
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/1.0/archiva-test-1.0.jar b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/1.0/archiva-test-1.0.jar
new file mode 100644
index 000000000..843ee45bc
Binary files /dev/null and b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/1.0/archiva-test-1.0.jar differ
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/1.0/archiva-test-1.0.pom b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/1.0/archiva-test-1.0.pom
new file mode 100644
index 000000000..0b037a3a5
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/1.0/archiva-test-1.0.pom
@@ -0,0 +1,23 @@
+
+ 4.0.0
+ org.apache.archiva
+ archiva-test
+ jar
+ 1.0
+ archiva-test
+ http://maven.apache.org
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+ commons-lang
+ commons-lang
+ 2.3
+
+
+
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/2.0/archiva-test-2.0.jar b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/2.0/archiva-test-2.0.jar
new file mode 100644
index 000000000..e904a17c4
Binary files /dev/null and b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/2.0/archiva-test-2.0.jar differ
diff --git a/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/2.0/archiva-test-2.0.pom b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/2.0/archiva-test-2.0.pom
new file mode 100644
index 000000000..04fdb4859
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-indexer/src/test/resources/nexus-search-test-repo/org/apache/archiva/archiva-test/2.0/archiva-test-2.0.pom
@@ -0,0 +1,28 @@
+
+ 4.0.0
+ org.apache.archiva
+ archiva-test
+ jar
+ 2.0
+ Archiva Test
+ http://archiva.apache.org
+
+
+ junit
+ junit
+ 3.8.1
+ test
+
+
+ commons-lang
+ commons-lang
+ 2.3
+
+
+ commons-io
+ commons-io
+ 1.4
+
+
+
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/scanner/functors/TriggerScanCompletedClosure.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/scanner/functors/TriggerScanCompletedClosure.java
new file mode 100644
index 000000000..52a9ca18a
--- /dev/null
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/archiva/repository/scanner/functors/TriggerScanCompletedClosure.java
@@ -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() + "]" );
+ }
+ }
+}
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/scanner/RepositoryContentConsumers.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/scanner/RepositoryContentConsumers.java
index 83042e287..6f35e81f3 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/scanner/RepositoryContentConsumers.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/scanner/RepositoryContentConsumers.java
@@ -26,6 +26,7 @@
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 void executeConsumers( ManagedRepositoryConfiguration repository, File lo
// 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
{
diff --git a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/scanner/RepositoryScannerInstance.java b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/scanner/RepositoryScannerInstance.java
index d0fd38ad1..e8d86d90c 100644
--- a/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/scanner/RepositoryScannerInstance.java
+++ b/archiva-modules/archiva-base/archiva-repository-layer/src/main/java/org/apache/maven/archiva/repository/scanner/RepositoryScannerInstance.java
@@ -23,6 +23,7 @@
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 void directoryWalkStep( int percentage, File file )
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();
}
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java
index 7db42d166..8d5911915 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/java/org/apache/maven/archiva/web/action/SearchAction.java
@@ -25,7 +25,9 @@
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.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 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 String filteredSearch()
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 String quickSearch()
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 String quickSearch()
{
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 versions = dao.query(new UniqueVersionConstraint(getObservableRepos(), resultHit.getGroupId(), resultHit.getArtifactId()));
+ if (versions != null && !versions.isEmpty())
{
- final List 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 void setClassName( String className )
{
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;
+ }
}
diff --git a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml
index 58c3b69b7..f640639d8 100644
--- a/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml
+++ b/archiva-modules/archiva-web/archiva-webapp/src/main/webapp/WEB-INF/applicationContext.xml
@@ -39,15 +39,11 @@
-
-
-
-
+
+
+
diff --git a/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/main/java/org/apache/archiva/web/xmlrpc/services/SearchServiceImpl.java b/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/main/java/org/apache/archiva/web/xmlrpc/services/SearchServiceImpl.java
index 72276d449..d08f50bb9 100644
--- a/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/main/java/org/apache/archiva/web/xmlrpc/services/SearchServiceImpl.java
+++ b/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/main/java/org/apache/archiva/web/xmlrpc/services/SearchServiceImpl.java
@@ -23,7 +23,7 @@
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.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 @@
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 List quickSearch( String queryString )
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 hits = results.getHits();
for( SearchResultHit hit : hits )
{
diff --git a/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/test/java/org/apache/archiva/web/xmlrpc/services/SearchServiceImplTest.java b/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/test/java/org/apache/archiva/web/xmlrpc/services/SearchServiceImplTest.java
index 2db1b931c..5f1d937b3 100644
--- a/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/test/java/org/apache/archiva/web/xmlrpc/services/SearchServiceImplTest.java
+++ b/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/test/java/org/apache/archiva/web/xmlrpc/services/SearchServiceImplTest.java
@@ -20,20 +20,15 @@
*/
-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.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 void setUp()
{
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 void testQuickSearchArtifactBytecodeSearch()
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 artifacts = searchService.quickSearch( "bytecode:MyClassName" );
userReposControl.verify();
- crossRepoSearchControl.verify();
+ searchControl.verify();
archivaDAOControl.verify();
artifactDAOControl.verify();
@@ -203,21 +178,20 @@ public void testQuickSearchArtifactRegularSearch()
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 artifacts = searchService.quickSearch( "archiva" );
userReposControl.verify();
- crossRepoSearchControl.verify();
+ searchControl.verify();
archivaDAOControl.verify();
artifactDAOControl.verify();
diff --git a/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/test/resources/org/apache/archiva/web/xmlrpc/services/AdministrationServiceImplTest.xml b/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/test/resources/org/apache/archiva/web/xmlrpc/services/AdministrationServiceImplTest.xml
deleted file mode 100644
index fc0308c69..000000000
--- a/archiva-modules/archiva-web/archiva-xmlrpc/archiva-xmlrpc-services/src/test/resources/org/apache/archiva/web/xmlrpc/services/AdministrationServiceImplTest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
- org.apache.maven.archiva.configuration.ArchivaConfiguration
- org.apache.maven.archiva.configuration.DefaultArchivaConfiguration
-
-
- org.codehaus.plexus.registry.Registry
- configured
-
-
-
-
- org.codehaus.plexus.registry.Registry
- configured
- org.codehaus.plexus.registry.commons.CommonsConfigurationRegistry
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 4f483b398..d2a342c4e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -245,6 +245,37 @@
xercesImpl
2.8.1
+
+ org.sonatype.nexus
+ nexus-indexer
+ 1.1.1
+
+
+ org.codehaus.plexus
+ plexus-container-default
+
+
+ classworlds
+ classworlds
+
+
+ commons-logging
+ commons-logging
+
+
+ velocity
+ velocity-dep
+
+
+ org.apache.maven
+ maven-plugin-registry
+
+
+ org.apache.maven
+ maven-settings
+
+
+
javax.activation
activation