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