MINDEXER-91: Add a Spring based example
- Corrected the README.md of the basic module as it was showing the wrong profile.
- Added a minimalistic Spring implementation with a simple service.
- Added two Spring contexts -- one for the actual maven-indexer specific classes and one for the the tests.
- Setup logging via SLF4J + Logback.
- Added README.md.
- Added a simple generator for valid artifact files (useful for testing without needing to have the resources under version control; this could probably be used in the indexer-core as well).
- Added a repository booter which creates test repositories with indexes.
diff --git a/indexer-examples/indexer-examples-basic/README.md b/indexer-examples/indexer-examples-basic/README.md
index de4dc7a..395c662 100644
--- a/indexer-examples/indexer-examples-basic/README.md
+++ b/indexer-examples/indexer-examples-basic/README.md
@@ -7,9 +7,9 @@
```
$ cd indexer-examples
-$ mvn clean test -Ptests
+$ mvn clean test -Pexamples
... first run will take few minutes to download the index, and then will run showing some output
-$ mvn test -Ptests
+$ mvn test -Pexamples
... (no clean goal!) second run will finish quickly, as target folder will already contain an up-to-date index
```
diff --git a/indexer-examples/indexer-examples-spring/README.md b/indexer-examples/indexer-examples-spring/README.md
new file mode 100644
index 0000000..eb25e72
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/README.md
@@ -0,0 +1,12 @@
+Maven Indexer Examples
+======
+
+This example covers simple use cases and is runnable as Java Junit via the "test" goal.
+
+Execute the following in order to run the example/test:
+
+```
+$ mvn clean test -Pexamples
+```
+
+Please, note that the tests in this module will only compile by default; the will not be executed, unless you activate the profile (-Ptests).
diff --git a/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/IndexerConfiguration.java b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/IndexerConfiguration.java
new file mode 100644
index 0000000..10229be
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/IndexerConfiguration.java
@@ -0,0 +1,102 @@
+package org.apache.maven.indexer.examples.indexing;
+
+/*
+ * 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 javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.index.Indexer;
+import org.apache.maven.index.Scanner;
+import org.apache.maven.index.context.IndexCreator;
+
+/**
+ * A simple configuration holder class.
+ * This class contains the mapped indexers.
+ *
+ * @author mtodorov
+ */
+@Named
+@Singleton
+public class IndexerConfiguration
+{
+
+ private Indexer indexer;
+
+ private Scanner scanner;
+
+ private Map<String, IndexCreator> indexers;
+
+
+ @Inject
+ public IndexerConfiguration( Indexer indexer,
+ Scanner scanner,
+ Map<String, IndexCreator> indexers )
+ {
+ this.indexer = indexer;
+ this.scanner = scanner;
+ this.indexers = indexers;
+ }
+
+ public List<IndexCreator> getIndexersAsList()
+ {
+ List<IndexCreator> indexersAsList = new ArrayList<>();
+ for ( Map.Entry entry : indexers.entrySet() )
+ {
+ indexersAsList.add( ( IndexCreator ) entry.getValue() );
+ }
+
+ return indexersAsList;
+ }
+
+ public Indexer getIndexer()
+ {
+ return indexer;
+ }
+
+ public void setIndexer( Indexer indexer )
+ {
+ this.indexer = indexer;
+ }
+
+ public Scanner getScanner()
+ {
+ return scanner;
+ }
+
+ public void setScanner( Scanner scanner )
+ {
+ this.scanner = scanner;
+ }
+
+ public Map<String, IndexCreator> getIndexers()
+ {
+ return indexers;
+ }
+
+ public void setIndexers( Map<String, IndexCreator> indexers )
+ {
+ this.indexers = indexers;
+ }
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/RepositoryIndexManager.java b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/RepositoryIndexManager.java
new file mode 100644
index 0000000..536b859
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/RepositoryIndexManager.java
@@ -0,0 +1,109 @@
+package org.apache.maven.indexer.examples.indexing;
+
+/*
+ * 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 javax.annotation.PreDestroy;
+import javax.inject.Singleton;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class represents a mapping between repositoryId-s and their respective indexes.
+ *
+ * @author mtodorov
+ */
+@Singleton
+@Component
+public class RepositoryIndexManager
+{
+
+ private static final Logger logger = LoggerFactory.getLogger( RepositoryIndexManager.class );
+
+ /**
+ * K: repositoryId
+ * V: index
+ */
+ private Map<String, RepositoryIndexer> indexes = new LinkedHashMap<>();
+
+
+ public RepositoryIndexManager()
+ {
+ }
+
+ /**
+ * A convenience method for closing the indexes. This method will be called
+ * by the Spring container and it shouldn't be invoked directly.
+ * <p/>
+ * This method is of particular importance, as you should close the indexes properly.
+ */
+ @PreDestroy
+ private void close()
+ {
+ for ( String repositoryId : indexes.keySet() )
+ {
+ try
+ {
+ final RepositoryIndexer repositoryIndexer = indexes.get( repositoryId );
+
+ logger.debug( "Closing indexer for " + repositoryIndexer.getRepositoryId() + "..." );
+
+ repositoryIndexer.close();
+
+ logger.debug( "Closed indexer for " + repositoryIndexer.getRepositoryId() + "." );
+ }
+ catch ( IOException e )
+ {
+ logger.error( e.getMessage(), e );
+ }
+ }
+ }
+
+ public Map<String, RepositoryIndexer> getIndexes()
+ {
+ return indexes;
+ }
+
+ public void setIndexes( Map<String, RepositoryIndexer> indexes )
+ {
+ this.indexes = indexes;
+ }
+
+ public RepositoryIndexer getRepositoryIndex( String repositoryId )
+ {
+ return indexes.get( repositoryId );
+ }
+
+ public RepositoryIndexer addRepositoryIndex( String repositoryId,
+ RepositoryIndexer value )
+ {
+ return indexes.put( repositoryId, value );
+ }
+
+ public RepositoryIndexer removeRepositoryIndex( String repositoryId )
+ {
+ return indexes.remove( repositoryId );
+ }
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/RepositoryIndexer.java b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/RepositoryIndexer.java
new file mode 100644
index 0000000..11a4eb4
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/RepositoryIndexer.java
@@ -0,0 +1,391 @@
+package org.apache.maven.indexer.examples.indexing;
+
+/*
+ * 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.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
+import org.apache.lucene.queryparser.classic.MultiFieldQueryParser;
+import org.apache.lucene.queryparser.classic.ParseException;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.util.Version;
+import org.apache.maven.index.*;
+import org.apache.maven.index.context.IndexCreator;
+import org.apache.maven.index.context.IndexingContext;
+import org.apache.maven.index.expr.SourcedSearchExpression;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import static java.util.Arrays.asList;
+import static org.apache.lucene.search.BooleanClause.Occur.MUST;
+
+/**
+ * This class provides means to index and search for artifacts in a repository on the file system.
+ *
+ * @author mtodorov
+ */
+public class RepositoryIndexer
+{
+
+ private static final Logger logger = LoggerFactory.getLogger( RepositoryIndexer.class );
+
+ private static final Version luceneVersion = Version.LUCENE_48;
+
+ private static final String[] luceneFields = new String[]{ "g", "a", "v", "p", "c" };
+
+ private static final WhitespaceAnalyzer luceneAnalyzer = new WhitespaceAnalyzer( luceneVersion );
+
+ private Indexer indexer;
+
+ private Scanner scanner;
+
+ private List<IndexCreator> indexers;
+
+ private IndexingContext indexingContext;
+
+ private String repositoryId;
+
+ private File repositoryBasedir;
+
+ private File indexDir;
+
+
+ public RepositoryIndexer()
+ {
+ }
+
+ public void close()
+ throws IOException
+ {
+ indexer.closeIndexingContext( indexingContext, false );
+ }
+
+ public void close( boolean deleteFiles )
+ throws IOException
+ {
+ indexingContext.close( deleteFiles );
+ }
+
+ public void delete( final Collection<ArtifactInfo> artifacts )
+ throws IOException
+ {
+ final List<ArtifactContext> delete = new ArrayList<ArtifactContext>();
+ for ( final ArtifactInfo artifact : artifacts )
+ {
+ logger.debug( "Deleting artifact: {}; ctx id: {}; idx dir: {}",
+ new String[]{ artifact.toString(),
+ indexingContext.getId(),
+ indexingContext.getIndexDirectory().toString() } );
+
+ delete.add( new ArtifactContext( null, null, null, artifact, null ) );
+ }
+
+ getIndexer().deleteArtifactsFromIndex( delete, indexingContext );
+ }
+
+ public Set<ArtifactInfo> search( final String groupId,
+ final String artifactId,
+ final String version,
+ final String packaging,
+ final String classifier )
+ throws IOException
+ {
+ final BooleanQuery query = new BooleanQuery();
+
+ if ( groupId != null )
+ {
+ query.add( getIndexer().constructQuery( MAVEN.GROUP_ID, new SourcedSearchExpression( groupId ) ), MUST );
+ }
+
+ if ( artifactId != null )
+ {
+ query.add( getIndexer().constructQuery( MAVEN.ARTIFACT_ID, new SourcedSearchExpression( artifactId ) ),
+ MUST );
+ }
+
+ if ( version != null )
+ {
+ query.add( getIndexer().constructQuery( MAVEN.VERSION, new SourcedSearchExpression( version ) ), MUST );
+ }
+
+ if ( packaging != null )
+ {
+ query.add( getIndexer().constructQuery( MAVEN.PACKAGING, new SourcedSearchExpression( packaging ) ), MUST );
+ }
+ else
+ {
+ // Fallback to jar
+ query.add( getIndexer().constructQuery( MAVEN.PACKAGING, new SourcedSearchExpression( "jar" ) ), MUST );
+ }
+
+ if ( classifier != null )
+ {
+ query.add( getIndexer().constructQuery( MAVEN.CLASSIFIER, new SourcedSearchExpression( classifier ) ), MUST );
+ }
+
+ logger.debug( "Executing search query: {}; ctx id: {}; idx dir: {}",
+ new String[]{ query.toString(),
+ indexingContext.getId(),
+ indexingContext.getIndexDirectory().toString() } );
+
+ final FlatSearchResponse response = getIndexer().searchFlat( new FlatSearchRequest( query, indexingContext ) );
+
+ logger.info( "Hit count: {}", response.getReturnedHitsCount() );
+
+ final Set<ArtifactInfo> results = response.getResults();
+ if ( logger.isDebugEnabled() )
+ {
+ for ( final ArtifactInfo result : results )
+ {
+ logger.debug( "Found artifact: {}", result.toString() );
+ }
+ }
+
+ return results;
+ }
+
+ public Set<ArtifactInfo> search( final String queryText )
+ throws ParseException, IOException
+ {
+ final Query query = new MultiFieldQueryParser( luceneVersion, luceneFields, luceneAnalyzer ).parse( queryText );
+
+ logger.debug( "Executing search query: {}; ctx id: {}; idx dir: {}",
+ new String[]{ query.toString(),
+ indexingContext.getId(),
+ indexingContext.getIndexDirectory().toString() } );
+
+ final FlatSearchResponse response = getIndexer().searchFlat( new FlatSearchRequest( query, indexingContext ) );
+
+ final Set<ArtifactInfo> results = response.getResults();
+ if ( logger.isDebugEnabled() )
+ {
+ logger.debug( "Hit count: {}", response.getReturnedHitsCount() );
+
+ for ( final ArtifactInfo result : results )
+ {
+ logger.debug( "Found artifact: {}; uinfo: {}", result.toString(), result.getUinfo() );
+ }
+ }
+
+ return results;
+ }
+
+ public Set<ArtifactInfo> searchBySHA1( final String checksum )
+ throws IOException
+ {
+ final BooleanQuery query = new BooleanQuery();
+ query.add( getIndexer().constructQuery( MAVEN.SHA1, new SourcedSearchExpression( checksum ) ), MUST );
+
+ logger.debug( "Executing search query: {}; ctx id: {}; idx dir: {}",
+ new String[]{ query.toString(),
+ indexingContext.getId(),
+ indexingContext.getIndexDirectory().toString() } );
+
+ final FlatSearchResponse response = getIndexer().searchFlat( new FlatSearchRequest( query, indexingContext ) );
+
+ logger.info( "Hit count: {}", response.getReturnedHitsCount() );
+
+ final Set<ArtifactInfo> results = response.getResults();
+ if ( logger.isDebugEnabled() )
+ {
+ for ( final ArtifactInfo result : results )
+ {
+ logger.debug( "Found artifact: {}", result.toString() );
+ }
+ }
+
+ return results;
+ }
+
+ public int index( final File startingPath )
+ {
+ final ScanningResult scan = getScanner().scan( new ScanningRequest( indexingContext,
+ new ReindexArtifactScanningListener(),
+ startingPath == null ? "." :
+ startingPath.getPath() ) );
+ return scan.getTotalFiles();
+ }
+
+ public void addArtifactToIndex( final File artifactFile,
+ final ArtifactInfo artifactInfo )
+ throws IOException
+ {
+ getIndexer().addArtifactsToIndex( asList( new ArtifactContext( null, artifactFile, null, artifactInfo, null ) ),
+ indexingContext );
+ }
+
+ public void addArtifactToIndex( String repository,
+ File artifactFile,
+ String groupId,
+ String artifactId,
+ String version,
+ String extension,
+ String classifier )
+ throws IOException
+ {
+ ArtifactInfo artifactInfo = new ArtifactInfo( repository,
+ groupId,
+ artifactId,
+ version,
+ classifier,
+ extension );
+ if ( extension != null )
+ {
+ artifactInfo.setFieldValue( MAVEN.EXTENSION, extension );
+ }
+
+ logger.debug( "Adding artifact: {}; repo: {}; type: {}", new String[]{ artifactInfo.getUinfo(),
+ repository,
+ extension } );
+
+ getIndexer().addArtifactsToIndex( asList( new ArtifactContext( null,
+ artifactFile,
+ null,
+ artifactInfo,
+ artifactInfo.calculateGav() ) ),
+ indexingContext );
+ }
+
+ private class ReindexArtifactScanningListener
+ implements ArtifactScanningListener
+ {
+
+ int totalFiles = 0;
+ private IndexingContext context;
+
+ @Override
+ public void scanningStarted( final IndexingContext context )
+ {
+ this.context = context;
+ }
+
+ @Override
+ public void scanningFinished( final IndexingContext context,
+ final ScanningResult result )
+ {
+ result.setTotalFiles( totalFiles );
+ logger.debug( "Scanning finished; total files: {}; has exception: {}",
+ result.getTotalFiles(),
+ result.hasExceptions() );
+ }
+
+ @Override
+ public void artifactError( final ArtifactContext ac,
+ final Exception ex )
+ {
+ logger.error( "Artifact error!", ex );
+ }
+
+ @Override
+ public void artifactDiscovered( final ArtifactContext ac )
+ {
+ try
+ {
+ logger.debug( "Adding artifact gav: {}; ctx id: {}; idx dir: {}",
+ new String[]{ ac.getGav().toString(),
+ context.getId(),
+ context.getIndexDirectory().toString() } );
+
+ getIndexer().addArtifactsToIndex( asList( ac ), context );
+ totalFiles++;
+ }
+ catch ( IOException ex )
+ {
+ logger.error( "Artifact index error", ex );
+ }
+ }
+ }
+
+ public Indexer getIndexer()
+ {
+ return indexer;
+ }
+
+ public void setIndexer( Indexer indexer )
+ {
+ this.indexer = indexer;
+ }
+
+ public Scanner getScanner()
+ {
+ return scanner;
+ }
+
+ public void setScanner( Scanner scanner )
+ {
+ this.scanner = scanner;
+ }
+
+ public List<IndexCreator> getIndexers()
+ {
+ return indexers;
+ }
+
+ public void setIndexers( List<IndexCreator> indexers )
+ {
+ this.indexers = indexers;
+ }
+
+ public IndexingContext getIndexingContext()
+ {
+ return indexingContext;
+ }
+
+ public void setIndexingContext( IndexingContext indexingContext )
+ {
+ this.indexingContext = indexingContext;
+ }
+
+ public String getRepositoryId()
+ {
+ return repositoryId;
+ }
+
+ public void setRepositoryId( String repositoryId )
+ {
+ this.repositoryId = repositoryId;
+ }
+
+ public File getRepositoryBasedir()
+ {
+ return repositoryBasedir;
+ }
+
+ public void setRepositoryBasedir( File repositoryBasedir )
+ {
+ this.repositoryBasedir = repositoryBasedir;
+ }
+
+ public File getIndexDir()
+ {
+ return indexDir;
+ }
+
+ public void setIndexDir( File indexDir )
+ {
+ this.indexDir = indexDir;
+ }
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/RepositoryIndexerFactory.java b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/RepositoryIndexerFactory.java
new file mode 100644
index 0000000..b935372
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/RepositoryIndexerFactory.java
@@ -0,0 +1,115 @@
+package org.apache.maven.indexer.examples.indexing;
+
+/*
+ * 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 javax.inject.Inject;
+import javax.inject.Singleton;
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.maven.index.Indexer;
+import org.apache.maven.index.Scanner;
+import org.apache.maven.index.context.IndexCreator;
+import org.apache.maven.index.context.IndexingContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A factory for pre-configured RepositoryIndexers.
+ *
+ * @author mtodorov
+ */
+@Singleton
+public class RepositoryIndexerFactory
+{
+
+ private static final Logger logger = LoggerFactory.getLogger( RepositoryIndexerFactory.class );
+
+ private IndexerConfiguration indexerConfiguration;
+
+
+ @Inject
+ public RepositoryIndexerFactory( IndexerConfiguration indexerConfiguration )
+ {
+ this.indexerConfiguration = indexerConfiguration;
+ }
+
+ public RepositoryIndexer createRepositoryIndexer( String repositoryId,
+ File repositoryBasedir,
+ File indexDir )
+ throws IOException
+ {
+ RepositoryIndexer repositoryIndexer = new RepositoryIndexer();
+ repositoryIndexer.setRepositoryId( repositoryId );
+ repositoryIndexer.setRepositoryBasedir( repositoryBasedir );
+ repositoryIndexer.setIndexDir( indexDir );
+ repositoryIndexer.setIndexingContext( createIndexingContext( repositoryId, repositoryBasedir, indexDir ) );
+ repositoryIndexer.setIndexer( indexerConfiguration.getIndexer() );
+ repositoryIndexer.setScanner( indexerConfiguration.getScanner() );
+
+ return repositoryIndexer;
+ }
+
+ private IndexingContext createIndexingContext( String repositoryId,
+ File repositoryBasedir,
+ File indexDir )
+ throws IOException
+ {
+ return getIndexer().createIndexingContext( repositoryId + "/ctx",
+ repositoryId,
+ repositoryBasedir,
+ indexDir,
+ null,
+ null,
+ true, // if context should be searched in non-targeted mode.
+ true, // if indexDirectory is known to contain (or should contain)
+ // valid Maven Indexer lucene index, and no checks needed to be
+ // performed, or, if we want to "stomp" over existing index
+ // (unsafe to do!).
+ indexerConfiguration.getIndexersAsList() );
+ }
+
+ public IndexerConfiguration getIndexerConfiguration()
+ {
+ return indexerConfiguration;
+ }
+
+ public void setIndexerConfiguration( IndexerConfiguration indexerConfiguration )
+ {
+ this.indexerConfiguration = indexerConfiguration;
+ }
+
+ public Indexer getIndexer()
+ {
+ return indexerConfiguration.getIndexer();
+ }
+
+ public Scanner getScanner()
+ {
+ return indexerConfiguration.getScanner();
+ }
+
+ public Map<String, IndexCreator> getIndexers()
+ {
+ return indexerConfiguration.getIndexers();
+ }
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/SearchRequest.java b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/SearchRequest.java
new file mode 100644
index 0000000..131eb3c
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/SearchRequest.java
@@ -0,0 +1,66 @@
+package org.apache.maven.indexer.examples.indexing;
+
+/*
+ * 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.
+ */
+
+/**
+ * This class holds the details of the search request.
+ *
+ * @author mtodorov
+ */
+public class SearchRequest
+{
+
+ private String repository;
+
+ private String query;
+
+
+ public SearchRequest()
+ {
+ }
+
+ public SearchRequest( String repository,
+ String query )
+ {
+ this.repository = repository;
+ this.query = query;
+ }
+
+ public String getRepository()
+ {
+ return repository;
+ }
+
+ public void setRepository( String repository )
+ {
+ this.repository = repository;
+ }
+
+ public String getQuery()
+ {
+ return query;
+ }
+
+ public void setQuery( String query )
+ {
+ this.query = query;
+ }
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/SearchResults.java b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/SearchResults.java
new file mode 100644
index 0000000..073e737
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/indexing/SearchResults.java
@@ -0,0 +1,57 @@
+package org.apache.maven.indexer.examples.indexing;
+
+/*
+ * 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.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.maven.index.ArtifactInfo;
+
+/**
+ * This is a convenience class for holding search results mapped by repository.
+ *
+ * @author mtodorov
+ */
+public class SearchResults
+{
+
+ /**
+ * K: repositoryId
+ * V: artifactInfos
+ */
+ private Map<String, Collection<ArtifactInfo>> results = new LinkedHashMap<>();
+
+
+ public SearchResults()
+ {
+ }
+
+ public Map<String, Collection<ArtifactInfo>> getResults()
+ {
+ return results;
+ }
+
+ public void setResults( Map<String, Collection<ArtifactInfo>> results )
+ {
+ this.results = results;
+ }
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/services/ArtifactIndexingService.java b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/services/ArtifactIndexingService.java
new file mode 100644
index 0000000..0a720b4
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/services/ArtifactIndexingService.java
@@ -0,0 +1,60 @@
+package org.apache.maven.indexer.examples.services;
+
+/*
+ * 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 org.apache.lucene.queryparser.classic.ParseException;
+import org.apache.maven.indexer.examples.indexing.SearchRequest;
+import org.apache.maven.indexer.examples.indexing.SearchResults;
+
+/**
+ * A simple indexing and search service.
+ *
+ * @author mtodorov
+ */
+public interface ArtifactIndexingService
+{
+
+ void addToIndex( String repositoryId,
+ File artifactFile,
+ String groupId,
+ String artifactId,
+ String version,
+ String extension,
+ String classifier )
+ throws IOException;
+
+ void deleteFromIndex( String repositoryId,
+ String groupId,
+ String artifactId,
+ String version,
+ String extension,
+ String classifier )
+ throws IOException;
+
+ SearchResults search( SearchRequest searchRequest )
+ throws IOException, ParseException;
+
+ boolean contains( SearchRequest searchRequest )
+ throws IOException, ParseException;
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/services/impl/ArtifactIndexingServiceImpl.java b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/services/impl/ArtifactIndexingServiceImpl.java
new file mode 100644
index 0000000..8f74cf5
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/main/java/org/apache/maven/indexer/examples/services/impl/ArtifactIndexingServiceImpl.java
@@ -0,0 +1,176 @@
+package org.apache.maven.indexer.examples.services.impl;
+
+/*
+ * 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.*;
+
+import org.apache.lucene.queryparser.classic.ParseException;
+import org.apache.maven.index.ArtifactInfo;
+import org.apache.maven.indexer.examples.indexing.RepositoryIndexManager;
+import org.apache.maven.indexer.examples.indexing.RepositoryIndexer;
+import org.apache.maven.indexer.examples.indexing.SearchRequest;
+import org.apache.maven.indexer.examples.indexing.SearchResults;
+import org.apache.maven.indexer.examples.services.ArtifactIndexingService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author mtodorov
+ */
+@Component
+public class ArtifactIndexingServiceImpl
+ implements ArtifactIndexingService
+{
+
+ private static final Logger logger = LoggerFactory.getLogger( ArtifactIndexingServiceImpl.class );
+
+ @Autowired
+ private RepositoryIndexManager repositoryIndexManager;
+
+
+ @Override
+ public void addToIndex( String repositoryId,
+ File artifactFile,
+ String groupId,
+ String artifactId,
+ String version,
+ String extension,
+ String classifier )
+ throws IOException
+ {
+ final RepositoryIndexer indexer = repositoryIndexManager.getRepositoryIndex( repositoryId );
+
+ indexer.addArtifactToIndex( repositoryId, artifactFile, groupId, artifactId, version, extension, classifier );
+ }
+
+ @Override
+ public void deleteFromIndex( String repositoryId,
+ String groupId,
+ String artifactId,
+ String version,
+ String extension,
+ String classifier )
+ throws IOException
+ {
+ final RepositoryIndexer indexer = repositoryIndexManager.getRepositoryIndex( repositoryId );
+ if ( indexer != null )
+ {
+ indexer.delete( Arrays.asList( new ArtifactInfo( repositoryId,
+ groupId,
+ artifactId,
+ version,
+ classifier,
+ extension ) ) );
+ }
+ }
+
+ @Override
+ public SearchResults search( SearchRequest searchRequest )
+ throws IOException, ParseException
+ {
+ SearchResults searchResults = new SearchResults();
+
+ final String repositoryId = searchRequest.getRepository();
+
+ if ( repositoryId != null && !repositoryId.isEmpty() )
+ {
+ logger.debug( "Repository: {}", repositoryId );
+
+ final Map<String, Collection<ArtifactInfo>> resultsMap = getResultsMap( repositoryId,
+ searchRequest.getQuery() );
+
+ if ( !resultsMap.isEmpty() )
+ {
+ searchResults.setResults( resultsMap );
+ }
+
+ if ( logger.isDebugEnabled() )
+ {
+ int results = resultsMap.entrySet().iterator().next().getValue().size();
+
+ logger.debug( "Results: {}", results );
+ }
+ }
+ else
+ {
+ Map<String, Collection<ArtifactInfo>> resultsMap = new LinkedHashMap<>();
+ for ( String repoId : repositoryIndexManager.getIndexes().keySet() )
+ {
+ logger.debug( "Repository: {}", repoId );
+
+ final RepositoryIndexer repositoryIndex = repositoryIndexManager.getRepositoryIndex( repoId );
+ if ( repositoryIndex != null )
+ {
+ final Set<ArtifactInfo> artifactInfoResults = repositoryIndexManager.getRepositoryIndex( repoId )
+ .search( searchRequest.getQuery() );
+
+ if ( !artifactInfoResults.isEmpty() )
+ {
+ resultsMap.put( repoId, artifactInfoResults );
+ }
+
+ logger.debug( "Results: {}", artifactInfoResults.size() );
+ }
+ }
+
+ searchResults.setResults( resultsMap );
+ }
+
+ return searchResults;
+ }
+
+ @Override
+ public boolean contains( SearchRequest searchRequest )
+ throws IOException, ParseException
+ {
+ return !getResultsMap( searchRequest.getRepository(), searchRequest.getQuery() ).isEmpty();
+ }
+
+ public Map<String, Collection<ArtifactInfo>> getResultsMap( String repositoryId,
+ String query )
+ throws IOException, ParseException
+ {
+ Map<String, Collection<ArtifactInfo>> resultsMap = new LinkedHashMap<>();
+ final Set<ArtifactInfo> artifactInfoResults = repositoryIndexManager.getRepositoryIndex( repositoryId )
+ .search( query );
+
+ if ( !artifactInfoResults.isEmpty() )
+ {
+ resultsMap.put( repositoryId, artifactInfoResults );
+ }
+
+ return resultsMap;
+ }
+
+ public RepositoryIndexManager getRepositoryIndexManager()
+ {
+ return repositoryIndexManager;
+ }
+
+ public void setRepositoryIndexManager( RepositoryIndexManager repositoryIndexManager )
+ {
+ this.repositoryIndexManager = repositoryIndexManager;
+ }
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/main/resources/META-INF/spring/maven-indexer-context.xml b/indexer-examples/indexer-examples-spring/src/main/resources/META-INF/spring/maven-indexer-context.xml
new file mode 100644
index 0000000..2cd5841
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/main/resources/META-INF/spring/maven-indexer-context.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:util="http://www.springframework.org/schema/util"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
+
+ <context:component-scan base-package="org.apache.maven.indexer.examples"/>
+
+ <!-- This context contains the maven-indexer beans and the configuration of the indexing. -->
+
+ <bean id="indexer" class="org.apache.maven.index.DefaultIndexer"/>
+
+ <bean id="scanner" class="org.apache.maven.index.DefaultScanner"/>
+
+ <bean id="indexerEngine" class="org.apache.maven.index.DefaultIndexerEngine"/>
+
+ <bean id="searchEngine" class="org.apache.maven.index.DefaultSearchEngine"/>
+
+ <bean id="queryCreator" class="org.apache.maven.index.DefaultQueryCreator"/>
+
+ <bean id="artifactContextProducer" class="org.apache.maven.index.DefaultArtifactContextProducer"/>
+
+ <bean id="artifactPackagingMapper" class="org.apache.maven.index.artifact.DefaultArtifactPackagingMapper"/>
+
+ <!-- Index creators: -->
+ <bean id="minimalArtifactInfoIndexCreator" class="org.apache.maven.index.creator.MinimalArtifactInfoIndexCreator"/>
+ <bean id="jarFileContentsIndexCreator" class="org.apache.maven.index.creator.JarFileContentsIndexCreator"/>
+ <bean id="mavenPluginArtifactInfoIndexCreator" class="org.apache.maven.index.creator.MavenPluginArtifactInfoIndexCreator"/>
+ <!-- Index creators. -->
+
+ <util:map id="indexers"
+ key-type="java.lang.String"
+ value-type="org.apache.maven.index.creator.AbstractIndexCreator"
+ map-class="java.util.LinkedHashMap">
+ <entry key="min" value-ref="minimalArtifactInfoIndexCreator"/>
+ <entry key="jarContent" value-ref="jarFileContentsIndexCreator"/>
+ <entry key="maven-plugin" value-ref="mavenPluginArtifactInfoIndexCreator"/>
+ </util:map>
+
+</beans>
diff --git a/indexer-examples/indexer-examples-spring/src/site/site.xml b/indexer-examples/indexer-examples-spring/src/site/site.xml
new file mode 100644
index 0000000..5ab71c2
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/site/site.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+/*
+ * 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.
+ */
+ -->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/DECORATION/1.1.0 http://maven.apache.org/xsd/decoration-1.1.0.xsd">
+
+ <body>
+
+ <menu ref="parent"/>
+
+ <menu name="Overview">
+ <item name="Introduction" href="index.html"/>
+ <item name="JavaDocs" href="apidocs/index.html"/>
+ <item name="Source Xref" href="xref/index.html"/>
+ <!--item name="FAQ" href="faq.html"/-->
+ </menu>
+
+ <menu ref="reports"/>
+
+ </body>
+
+</project>
\ No newline at end of file
diff --git a/indexer-examples/indexer-examples-spring/src/test/java/org/apache/maven/indexer/examples/SimpleArtifactGenerator.java b/indexer-examples/indexer-examples-spring/src/test/java/org/apache/maven/indexer/examples/SimpleArtifactGenerator.java
new file mode 100644
index 0000000..2ed1c56
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/test/java/org/apache/maven/indexer/examples/SimpleArtifactGenerator.java
@@ -0,0 +1,175 @@
+package org.apache.maven.indexer.examples;
+
+/*
+ * 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.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.io.DefaultModelWriter;
+import org.apache.maven.model.io.ModelWriter;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * @author mtodorov
+ */
+public class SimpleArtifactGenerator
+{
+
+
+ public SimpleArtifactGenerator()
+ {
+ }
+
+ public File generateArtifact( String repositoryBasedir,
+ String groupId,
+ String artifactId,
+ String version,
+ String classifier,
+ String extension )
+ throws IOException, NoSuchAlgorithmException, XmlPullParserException
+ {
+ File repositoryDir = new File( repositoryBasedir );
+ File artifactFile = new File( repositoryDir,
+ groupId.replaceAll( "\\.", File.separator ) + File.separatorChar +
+ artifactId + File.separatorChar + version + File.separatorChar +
+ artifactId + "-" + version +
+ ( classifier != null ? "-" + classifier + File.separatorChar : "" ) + "." +
+ extension );
+
+ if ( !artifactFile.getParentFile().exists() )
+ {
+ //noinspection ResultOfMethodCallIgnored
+ artifactFile.getParentFile().mkdirs();
+ }
+
+ createArchive( artifactFile, groupId, artifactId, version, extension );
+
+ return artifactFile;
+ }
+
+ private void createArchive( File artifactFile,
+ String groupId,
+ String artifactId,
+ String version,
+ String extension )
+ throws NoSuchAlgorithmException,
+ IOException, XmlPullParserException
+ {
+ ZipOutputStream zos = null;
+
+ try
+ {
+ // Make sure the artifact's parent directory exists before writing the model.
+ //noinspection ResultOfMethodCallIgnored
+ artifactFile.getParentFile().mkdirs();
+
+ File pomFile = new File( artifactFile.getParent(),
+ artifactFile.getName().substring( 0, artifactFile.getName().lastIndexOf( "." ) ) +
+ ".pom" );
+
+ zos = new ZipOutputStream( new FileOutputStream( artifactFile ) );
+
+ generatePom( pomFile, groupId, artifactId, version, extension );
+
+ addMavenPomFile( zos, pomFile, groupId, artifactId );
+ }
+ finally
+ {
+ if ( zos != null )
+ {
+ zos.close();
+ }
+ }
+ }
+
+ protected void generatePom( File pomFile,
+ String groupId,
+ String artifactId,
+ String version,
+ String type )
+ throws IOException,
+ XmlPullParserException,
+ NoSuchAlgorithmException
+ {
+
+ // Make sure the artifact's parent directory exists before writing the model.
+ //noinspection ResultOfMethodCallIgnored
+ pomFile.getParentFile().mkdirs();
+
+ Model model = new Model();
+ model.setGroupId( groupId );
+ model.setArtifactId( artifactId );
+ model.setVersion( version );
+ model.setPackaging( type ); // This is not exactly correct.
+
+ ModelWriter writer = new DefaultModelWriter();
+ writer.write( pomFile, null, model );
+
+ }
+
+
+ private void addMavenPomFile( ZipOutputStream zos,
+ File pomFile,
+ String groupId,
+ String artifactId )
+ throws IOException
+ {
+ ZipEntry ze = new ZipEntry( "META-INF/maven/" + groupId + "/" + artifactId + "/" + "pom.xml" );
+ zos.putNextEntry( ze );
+
+ FileInputStream fis = new FileInputStream( pomFile );
+
+ byte[] buffer = new byte[ 1024 ];
+ int len;
+ while ( ( len = fis.read( buffer ) ) > 0 )
+ {
+ zos.write( buffer, 0, len );
+ }
+
+ fis.close();
+ zos.closeEntry();
+ }
+
+ public static String convertGAVToPath( String groupId,
+ String artifactId,
+ String version,
+ String classifier,
+ String extension )
+ {
+ String path = "";
+
+ path += groupId.replaceAll( "\\.", "/" ) + "/";
+ path += artifactId + "/";
+ path += version + "/";
+ path += artifactId + "-";
+ path += version;
+ path += classifier != null ? "-" + classifier : "";
+ path += "." + extension;
+
+ return path;
+ }
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/test/java/org/apache/maven/indexer/examples/SpringUsageExampleTest.java b/indexer-examples/indexer-examples-spring/src/test/java/org/apache/maven/indexer/examples/SpringUsageExampleTest.java
new file mode 100644
index 0000000..8c055a7
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/test/java/org/apache/maven/indexer/examples/SpringUsageExampleTest.java
@@ -0,0 +1,211 @@
+package org.apache.maven.indexer.examples;
+
+/*
+ * 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.security.NoSuchAlgorithmException;
+import java.util.Collection;
+
+import org.apache.lucene.queryparser.classic.ParseException;
+import org.apache.maven.index.ArtifactInfo;
+import org.apache.maven.indexer.examples.indexing.SearchRequest;
+import org.apache.maven.indexer.examples.indexing.SearchResults;
+import org.apache.maven.indexer.examples.services.ArtifactIndexingService;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import static junit.framework.TestCase.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author mtodorov
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = { "/META-INF/spring/*-context.xml",
+ "classpath*:/META-INF/spring/*-context.xml" })
+public class SpringUsageExampleTest
+{
+
+ public static final File REPOSITORIES_BASEDIR = new File( "target/repositories" );
+
+ @Autowired
+ private ArtifactIndexingService artifactIndexingService;
+
+ private SimpleArtifactGenerator generator = new SimpleArtifactGenerator();
+
+
+ @Before
+ public void setUp()
+ throws Exception
+ {
+ if ( !new File( REPOSITORIES_BASEDIR,
+ "releases/org/apache/maven/indexer/examples/indexer-examples-spring" ).exists() )
+ {
+ //noinspection ResultOfMethodCallIgnored
+ REPOSITORIES_BASEDIR.mkdirs();
+
+ // Generate some valid test artifacts:
+ generateArtifactAndAddToIndex( new File( REPOSITORIES_BASEDIR, "releases" ).getAbsolutePath(),
+ "releases",
+ "org.apache.maven.indexer.examples",
+ "indexer-examples-spring",
+ "1.0",
+ "jar",
+ null );
+ generateArtifactAndAddToIndex( new File( REPOSITORIES_BASEDIR, "releases" ).getAbsolutePath(),
+ "releases",
+ "org.apache.maven.indexer.examples",
+ "indexer-examples-spring",
+ "1.1",
+ "jar",
+ null );
+ generateArtifactAndAddToIndex( new File( REPOSITORIES_BASEDIR, "releases" ).getAbsolutePath(),
+ "releases",
+ "org.apache.maven.indexer.examples",
+ "indexer-examples-spring",
+ "1.2",
+ "jar",
+ null );
+ generateArtifactAndAddToIndex( new File( REPOSITORIES_BASEDIR, "releases" ).getAbsolutePath(),
+ "releases",
+ "org.apache.maven.indexer.examples",
+ "indexer-examples-spring",
+ "1.3",
+ "jar",
+ null );
+ generateArtifactAndAddToIndex( new File( REPOSITORIES_BASEDIR, "releases" ).getAbsolutePath(),
+ "releases",
+ "org.apache.maven.indexer.examples",
+ "indexer-examples-spring",
+ "1.3.1",
+ "jar",
+ null );
+ generateArtifactAndAddToIndex( new File( REPOSITORIES_BASEDIR, "releases" ).getAbsolutePath(),
+ "releases",
+ "org.apache.maven.indexer.examples",
+ "indexer-examples-spring",
+ "1.4",
+ "jar",
+ null );
+ }
+ }
+
+ @Test
+ public void testAddAndDelete()
+ throws IOException, ParseException, NoSuchAlgorithmException, XmlPullParserException
+ {
+ // Create a search request matching GAV "org.apache.maven.indexer.examples:indexer-examples-spring:1.4"
+ SearchRequest request = new SearchRequest( "releases",
+ "+g:org.apache.maven.indexer.examples +a:indexer-examples-spring +v:1.4" );
+
+ assertTrue( "Couldn't find existing artifact!", artifactIndexingService.contains( request ) );
+
+ // Delete the artifact from the index:
+ artifactIndexingService.deleteFromIndex( "releases",
+ "org.apache.maven.indexer.examples",
+ "indexer-examples-spring",
+ "1.4",
+ "jar",
+ null );
+
+ assertFalse( "Failed to remove artifact from index!", artifactIndexingService.contains( request ) );
+ }
+
+ @Test
+ public void testSearch()
+ throws IOException, ParseException
+ {
+ // Create a search request matching GAV "org.apache.maven.indexer.examples:indexer-examples-spring:1.3"
+ SearchRequest request = new SearchRequest( "releases",
+ "+g:org.apache.maven.indexer.examples +a:indexer-examples-spring +v:1.3*" );
+
+ assertTrue( "Couldn't find existing artifact!", artifactIndexingService.contains( request ) );
+
+ final SearchResults searchResults = artifactIndexingService.search( request );
+
+ assertFalse( searchResults.getResults().isEmpty() );
+
+ for ( String repositoryId : searchResults.getResults().keySet() )
+ {
+ System.out.println( "Matches in repository " + repositoryId + ":" );
+
+ final Collection<ArtifactInfo> artifactInfos = searchResults.getResults().get( repositoryId );
+ for ( ArtifactInfo artifactInfo : artifactInfos )
+ {
+ System.out.println( " " +
+ artifactInfo.getGroupId() + ":" +
+ artifactInfo.getArtifactId() + ":" +
+ artifactInfo.getVersion() + ":" +
+ artifactInfo.getPackaging() + ":" +
+ artifactInfo.getClassifier() );
+ }
+ }
+
+ }
+
+ /**
+ * This method creates some valid dummy artifacts in order to be able to add them to index.
+ *
+ * @param repositoryBasedir
+ * @param repositoryId
+ * @param groupId
+ * @param artifactId
+ * @param version
+ * @param extension
+ * @param classifier
+ * @return
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ * @throws XmlPullParserException
+ */
+ private File generateArtifactAndAddToIndex( String repositoryBasedir,
+ String repositoryId,
+ String groupId,
+ String artifactId,
+ String version,
+ String extension,
+ String classifier )
+ throws IOException, NoSuchAlgorithmException, XmlPullParserException
+ {
+ final File artifactFile = generator.generateArtifact( repositoryBasedir,
+ groupId,
+ artifactId,
+ version,
+ classifier,
+ extension );
+
+ // Add the artifact to the index:
+ artifactIndexingService.addToIndex( repositoryId,
+ artifactFile,
+ groupId,
+ artifactId,
+ version,
+ extension,
+ classifier );
+
+ return artifactFile;
+ }
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/test/java/org/apache/maven/indexer/examples/boot/RepositoryBooter.java b/indexer-examples/indexer-examples-spring/src/test/java/org/apache/maven/indexer/examples/boot/RepositoryBooter.java
new file mode 100644
index 0000000..19ad7c6
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/test/java/org/apache/maven/indexer/examples/boot/RepositoryBooter.java
@@ -0,0 +1,156 @@
+package org.apache.maven.indexer.examples.boot;
+
+/*
+ * 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 javax.annotation.PostConstruct;
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.maven.indexer.examples.indexing.RepositoryIndexManager;
+import org.apache.maven.indexer.examples.indexing.RepositoryIndexer;
+import org.apache.maven.indexer.examples.indexing.RepositoryIndexerFactory;
+import org.codehaus.plexus.PlexusContainerException;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * This is a dummy artifact repository creator.
+ *
+ * @author mtodorov
+ */
+@Component
+public class RepositoryBooter
+{
+
+ private static final Logger logger = LoggerFactory.getLogger( RepositoryBooter.class );
+
+ @Autowired
+ private RepositoryIndexManager repositoryIndexManager;
+
+ @Autowired
+ private RepositoryIndexerFactory repositoryIndexerFactory;
+
+
+ public RepositoryBooter()
+ {
+ }
+
+ @PostConstruct
+ public void initialize()
+ throws IOException,
+ PlexusContainerException,
+ ComponentLookupException
+ {
+ File repositoriesBaseDir = new File( "target/repositories" );
+
+ if ( !lockExists( repositoriesBaseDir ) )
+ {
+ createLockFile( repositoriesBaseDir );
+ initializeRepositories( repositoriesBaseDir );
+ }
+ else
+ {
+ logger.error( "Failed to initialize the repositories. Another JVM may have already done this." );
+ }
+
+ logger.debug( "Initialized repositories." );
+ }
+
+ private void createLockFile( File repositoriesRootDir )
+ throws IOException
+ {
+ final File lockFile = new File( repositoriesRootDir, "repositories.lock" );
+ //noinspection ResultOfMethodCallIgnored
+ lockFile.getParentFile().mkdirs();
+ //noinspection ResultOfMethodCallIgnored
+ lockFile.createNewFile();
+ }
+
+ private boolean lockExists( File repositoriesRootDir )
+ throws IOException
+ {
+ File lockFile = new File( repositoriesRootDir, "repositories.lock" );
+
+ return lockFile.exists();
+ }
+
+ private void initializeRepositories( File repositoriesBaseDir )
+ throws IOException,
+ PlexusContainerException,
+ ComponentLookupException
+ {
+ initializeRepository( repositoriesBaseDir, "releases" );
+ initializeRepository( repositoriesBaseDir, "snapshots" );
+ }
+
+ private void initializeRepository( File repositoriesBaseDir,
+ String repositoryName )
+ throws IOException,
+ PlexusContainerException,
+ ComponentLookupException
+ {
+ createRepositoryStructure( repositoriesBaseDir.getAbsolutePath(), repositoryName );
+
+ initializeRepositoryIndex( new File( repositoriesBaseDir.getAbsoluteFile(), repositoryName ), repositoryName );
+ }
+
+ public void createRepositoryStructure( String repositoriesBaseDir,
+ String repositoryName )
+ throws IOException
+ {
+ final File repositoriesBasedir = new File( repositoriesBaseDir );
+ //noinspection ResultOfMethodCallIgnored
+ new File( repositoriesBasedir, repositoryName ).mkdirs();
+ //noinspection ResultOfMethodCallIgnored
+ new File( repositoriesBasedir, repositoryName + File.separatorChar + ".index" ).mkdirs();
+
+ logger.debug( "Created directory structure for repository '" +
+ repositoriesBasedir.getAbsolutePath() + File.separatorChar + repositoryName + "'." );
+ }
+
+ private void initializeRepositoryIndex( File repositoryBasedir,
+ String repositoryId )
+ throws PlexusContainerException,
+ ComponentLookupException,
+ IOException
+ {
+ final File indexDir = new File( repositoryBasedir, ".index" );
+
+ RepositoryIndexer repositoryIndexer = repositoryIndexerFactory.createRepositoryIndexer( repositoryId,
+ repositoryBasedir,
+ indexDir );
+
+ repositoryIndexManager.addRepositoryIndex( repositoryId, repositoryIndexer );
+ }
+
+ public RepositoryIndexManager getRepositoryIndexManager()
+ {
+ return repositoryIndexManager;
+ }
+
+ public void setRepositoryIndexManager( RepositoryIndexManager repositoryIndexManager )
+ {
+ this.repositoryIndexManager = repositoryIndexManager;
+ }
+
+}
diff --git a/indexer-examples/indexer-examples-spring/src/test/resources/META-INF/spring/indexer-examples-context.xml b/indexer-examples/indexer-examples-spring/src/test/resources/META-INF/spring/indexer-examples-context.xml
new file mode 100644
index 0000000..e0a2cf7
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/test/resources/META-INF/spring/indexer-examples-context.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
+
+ <context:component-scan base-package="org.apache.maven.indexer.examples"/>
+
+ <bean id="indexerConfiguration" class="org.apache.maven.indexer.examples.indexing.IndexerConfiguration">
+ <constructor-arg name="indexer" ref="indexer"/>
+ <constructor-arg name="indexers" ref="indexers"/>
+ <constructor-arg name="scanner" ref="scanner"/>
+ </bean>
+
+ <bean id="repositoryIndexerFactory" class="org.apache.maven.indexer.examples.indexing.RepositoryIndexerFactory"/>
+
+ <bean id="repositoryIndexManager" class="org.apache.maven.indexer.examples.indexing.RepositoryIndexManager"/>
+
+ <bean id="artifactIndexingService" class="org.apache.maven.indexer.examples.services.impl.ArtifactIndexingServiceImpl"/>
+
+ <bean id="repositoryBooter" class="org.apache.maven.indexer.examples.boot.RepositoryBooter"/>
+
+</beans>
diff --git a/indexer-examples/indexer-examples-spring/src/test/resources/logback.xml b/indexer-examples/indexer-examples-spring/src/test/resources/logback.xml
new file mode 100644
index 0000000..a27f7b5
--- /dev/null
+++ b/indexer-examples/indexer-examples-spring/src/test/resources/logback.xml
@@ -0,0 +1,35 @@
+<!--
+ 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.
+-->
+
+<configuration>
+
+ <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>[%p] %c - %m%n</pattern>
+ </encoder>
+ </appender>
+
+ <logger name="org.springframework" level="ERROR" />
+ <logger name="org.apache.maven.indexer.examples.indexing" level="DEBUG" />
+ <logger name="org.apache.maven.indexer.examples.boot" level="ERROR" />
+
+ <root level="ERROR">
+ <appender-ref ref="stdout" />
+ </root>
+
+</configuration>
\ No newline at end of file