You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by br...@apache.org on 2010/11/03 23:51:35 UTC
svn commit: r1030748 [6/21] - in /maven/indexer: branches/ tags/ trunk/
trunk/indexer-artifact/ trunk/indexer-artifact/src/
trunk/indexer-artifact/src/main/ trunk/indexer-artifact/src/main/java/
trunk/indexer-artifact/src/main/java/org/ trunk/indexer-a...
Added: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/NexusIndexerCli.java
URL: http://svn.apache.org/viewvc/maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/NexusIndexerCli.java?rev=1030748&view=auto
==============================================================================
--- maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/NexusIndexerCli.java (added)
+++ maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/NexusIndexerCli.java Wed Nov 3 22:51:12 2010
@@ -0,0 +1,615 @@
+/**
+ * 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.
+ */
+package org.apache.maven.index.cli;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.BufferedInputStream;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.lang.reflect.Proxy;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.maven.index.ArtifactContext;
+import org.apache.maven.index.ArtifactInfo;
+import org.apache.maven.index.ArtifactScanningListener;
+import org.apache.maven.index.NexusIndexer;
+import org.apache.maven.index.ScanningResult;
+import org.apache.maven.index.context.IndexCreator;
+import org.apache.maven.index.context.IndexingContext;
+import org.apache.maven.index.context.UnsupportedExistingLuceneIndexException;
+import org.apache.maven.index.creator.JarFileContentsIndexCreator;
+import org.apache.maven.index.creator.MinimalArtifactInfoIndexCreator;
+import org.apache.maven.index.packer.IndexPacker;
+import org.apache.maven.index.packer.IndexPackingRequest;
+import org.apache.maven.index.packer.IndexPackingRequest.IndexFormat;
+import org.apache.maven.index.updater.DefaultIndexUpdater;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.classworlds.ClassWorld;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.logging.Logger;
+import org.codehaus.plexus.logging.LoggerManager;
+import org.codehaus.plexus.tools.cli.AbstractCli;
+
+/**
+ * A command line tool that can be used to index local Maven repository.
+ * <p>
+ * The following command line options are supported:
+ * <ul>
+ * <li>-repository <path> : required path to repository to be indexed</li>
+ * <li>-index <path> : required index folder used to store created index or where previously created index is stored</li>
+ * <li>-name <path> : required repository name/id</li>
+ * <li>-target <path> : optional folder name where to save produced index files</li>
+ * <li>-type <path> : optional indexer types</li>
+ * <li>-format <path> : optional indexer formats</li>
+ * </ul>
+ * When index folder contains previously created index, the tool will use it as a base line and will generate chunks for
+ * the incremental updates.
+ * <p>
+ * The indexer types could be one of default, min or full. You can also specify list of coma-separated custom index
+ * creators. An index creator should be a regular Plexus component, see {@link MinimalArtifactInfoIndexCreator} and
+ * {@link JarFileContentsIndexCreator}.
+ */
+public class NexusIndexerCli
+ extends AbstractCli
+{
+ // Command line options
+
+ public static final char REPO = 'r';
+
+ public static final char INDEX = 'i';
+
+ public static final char NAME = 'n';
+
+ public static final char TYPE = 't';
+
+ public static final char TARGET_DIR = 'd';
+
+ public static final char CREATE_INCREMENTAL_CHUNKS = 'c';
+
+ public static final char CREATE_FILE_CHECKSUMS = 's';
+
+ public static final char INCREMENTAL_CHUNK_KEEP_COUNT = 'k';
+
+ public static final char LEGACY = 'l';
+
+ public static final char UNPACK = 'u';
+
+ private static final long MB = 1024 * 1024;
+
+ private Options options;
+
+ private int status = 0;
+
+ public static void main( String[] args )
+ throws Exception
+ {
+ NexusIndexerCli cli = new NexusIndexerCli();
+
+ cli.execute( args );
+
+ System.exit( cli.status );
+ }
+
+ @Override
+ public int execute( String[] arg0, ClassWorld arg1 )
+ {
+ int value = super.execute( arg0, arg1 );
+
+ if ( status == 0 )
+ {
+ status = value;
+ }
+
+ return status;
+ }
+
+ @Override
+ public int execute( String[] args )
+ {
+ int value = super.execute( args );
+
+ if ( status == 0 )
+ {
+ status = value;
+ }
+
+ return status;
+ }
+
+ @Override
+ protected void showError( String message, Exception e, boolean show )
+ {
+ status = 1;
+ super.showError( message, e, show );
+ }
+
+ @Override
+ protected int showFatalError( String message, Exception e, boolean show )
+ {
+ status = 1;
+ return super.showFatalError( message, e, show );
+ }
+
+ @Override
+ public CommandLine parse( String[] args )
+ throws ParseException
+ {
+ try
+ {
+ return super.parse( args );
+ }
+ catch ( ParseException e )
+ {
+ status = 1;
+ throw e;
+ }
+ }
+
+ @Override
+ public String getPomPropertiesPath()
+ {
+ return "META-INF/maven/org.sonatype.nexus/nexus-indexer/pom.properties";
+ }
+
+ @Override
+ @SuppressWarnings( "static-access" )
+ public Options buildCliOptions( Options options )
+ {
+ this.options = options;
+
+ options.addOption( OptionBuilder.withLongOpt( "index" ).hasArg() //
+ .withDescription( "Path to the index folder." ).create( INDEX ) );
+
+ options.addOption( OptionBuilder.withLongOpt( "destination" ).hasArg() //
+ .withDescription( "Target folder." ).create( TARGET_DIR ) );
+
+ options.addOption( OptionBuilder.withLongOpt( "repository" ).hasArg() //
+ .withDescription( "Path to the Maven repository." ).create( REPO ) );
+
+ options.addOption( OptionBuilder.withLongOpt( "name" ).hasArg() //
+ .withDescription( "Repository name." ).create( NAME ) );
+
+ options.addOption( OptionBuilder.withLongOpt( "chunks" ) //
+ .withDescription( "Create incremental chunks." ).create( CREATE_INCREMENTAL_CHUNKS ) );
+
+ options.addOption( OptionBuilder.withLongOpt( "keep" ).hasArg().withDescription(
+ "Number of incremental chunks to keep." ).create( INCREMENTAL_CHUNK_KEEP_COUNT ) );
+
+ options.addOption( OptionBuilder.withLongOpt( "checksums" ) //
+ .withDescription( "Create checksums for all files (sha1, md5)." ).create( CREATE_FILE_CHECKSUMS ) );
+
+ options.addOption( OptionBuilder.withLongOpt( "type" ).hasArg() //
+ .withDescription( "Indexer type (default, min, full or coma separated list of custom types)." ).create( TYPE ) );
+
+ options.addOption( OptionBuilder.withLongOpt( "legacy" ) //
+ .withDescription( "Build legacy .zip index file" ).create( LEGACY ) );
+
+ options.addOption( OptionBuilder.withLongOpt( "unpack" ) //
+ .withDescription( "Unpack an index file" ).create( UNPACK ) );
+
+ return options;
+ }
+
+ @Override
+ public void displayHelp()
+ {
+ System.out.println();
+
+ HelpFormatter formatter = new HelpFormatter();
+
+ formatter.printHelp( "nexus-indexer [options]", "\nOptions:", options, "\n" );
+ }
+
+ public void displayHelp( String message )
+ {
+ System.out.println();
+
+ System.out.println( message );
+
+ System.out.println();
+
+ displayHelp();
+ }
+
+ @Override
+ public void invokePlexusComponent( final CommandLine cli, PlexusContainer plexus )
+ throws Exception
+ {
+ if ( cli.hasOption( QUIET ) )
+ {
+ setLogLevel( plexus, Logger.LEVEL_DISABLED );
+ }
+ else if ( cli.hasOption( DEBUG ) )
+ {
+ setLogLevel( plexus, Logger.LEVEL_DEBUG );
+ }
+ else if ( cli.hasOption( ERRORS ) )
+ {
+ setLogLevel( plexus, Logger.LEVEL_ERROR );
+ }
+
+ if ( cli.hasOption( UNPACK ) )
+ {
+ unpack( cli, plexus );
+ }
+ else if ( cli.hasOption( INDEX ) && cli.hasOption( REPO ) )
+ {
+ index( cli, plexus );
+ }
+ else
+ {
+ status = 1;
+
+ displayHelp( "Use either unpack (\"" + UNPACK + "\") or index (\"" + INDEX + "\" and \"" + REPO
+ + "\") options, but none has been found!" );
+ }
+ }
+
+ private void setLogLevel( PlexusContainer plexus, int logLevel )
+ throws ComponentLookupException
+ {
+ plexus.lookup( LoggerManager.class ).setThresholds( logLevel );
+ }
+
+ private void index( final CommandLine cli, PlexusContainer plexus )
+ throws ComponentLookupException, IOException, UnsupportedExistingLuceneIndexException
+ {
+ String indexDirectoryName = cli.getOptionValue( INDEX );
+
+ File indexFolder = new File( indexDirectoryName );
+
+ String outputDirectoryName = cli.getOptionValue( TARGET_DIR, "." );
+
+ File outputFolder = new File( outputDirectoryName );
+
+ File repositoryFolder = new File( cli.getOptionValue( REPO ) );
+
+ String repositoryName = cli.getOptionValue( NAME, indexFolder.getName() );
+
+ List<IndexCreator> indexers = getIndexers( cli, plexus );
+
+ boolean createChecksums = cli.hasOption( CREATE_FILE_CHECKSUMS );
+
+ boolean createIncrementalChunks = cli.hasOption( CREATE_INCREMENTAL_CHUNKS );
+
+ boolean createLegacyIndex = cli.hasOption( LEGACY );
+
+ boolean debug = cli.hasOption( DEBUG );
+
+ boolean quiet = cli.hasOption( QUIET );
+
+ Integer chunkCount =
+ cli.hasOption( INCREMENTAL_CHUNK_KEEP_COUNT ) ? Integer.parseInt( cli.getOptionValue( INCREMENTAL_CHUNK_KEEP_COUNT ) )
+ : null;
+
+ if ( !quiet )
+ {
+ System.err.printf( "Repository Folder: %s\n", repositoryFolder.getAbsolutePath() );
+ System.err.printf( "Index Folder: %s\n", indexFolder.getAbsolutePath() );
+ System.err.printf( "Output Folder: %s\n", outputFolder.getAbsolutePath() );
+ System.err.printf( "Repository name: %s\n", repositoryName );
+ System.err.printf( "Indexers: %s\n", indexers.toString() );
+
+ if ( createChecksums )
+ {
+ System.err.printf( "Will create checksum files for all published files (sha1, md5).\n" );
+ }
+ else
+ {
+ System.err.printf( "Will not create checksum files.\n" );
+ }
+
+ if ( createIncrementalChunks )
+ {
+ System.err.printf( "Will create incremental chunks for changes, along with baseline file.\n" );
+ }
+ else
+ {
+ System.err.printf( "Will create baseline file.\n" );
+ }
+
+ if ( createLegacyIndex )
+ {
+ System.err.printf( "Will also create legacy .zip index file.\n" );
+ }
+ }
+
+ NexusIndexer indexer = plexus.lookup( NexusIndexer.class );
+ IndexingContext context = null;
+
+ try
+ {
+ long tstart = System.currentTimeMillis();
+
+ context = indexer.addIndexingContext( //
+ repositoryName, // context id
+ repositoryName, // repository id
+ repositoryFolder, // repository folder
+ indexFolder, // index folder
+ null, // repositoryUrl
+ null, // index update url
+ indexers );
+
+ IndexPacker packer = plexus.lookup( IndexPacker.class );
+
+ ArtifactScanningListener listener = new IndexerListener( context, debug, quiet );
+
+ indexer.scan( context, listener, true );
+
+ IndexPackingRequest request = new IndexPackingRequest( context, outputFolder );
+
+ request.setCreateChecksumFiles( createChecksums );
+
+ request.setCreateIncrementalChunks( createIncrementalChunks );
+
+ if ( createLegacyIndex )
+ {
+ request.setFormats( Arrays.asList( IndexFormat.FORMAT_LEGACY, IndexFormat.FORMAT_V1 ) );
+ }
+ else
+ {
+ request.setFormats( Arrays.asList( IndexFormat.FORMAT_V1 ) );
+ }
+
+ if ( chunkCount != null )
+ {
+ request.setMaxIndexChunks( chunkCount.intValue() );
+ }
+
+ packIndex( packer, request, debug, quiet );
+
+ if ( !quiet )
+ {
+ printStats( tstart );
+ }
+ }
+ finally
+ {
+ indexer.removeIndexingContext( context, false );
+ }
+ }
+
+ private void unpack( CommandLine cli, PlexusContainer plexus )
+ throws ComponentLookupException, IOException
+ {
+ final String indexDirectoryName = cli.getOptionValue( INDEX, "." );
+ final File indexFolder = new File( indexDirectoryName ).getCanonicalFile();
+ final File indexArchive = new File( indexFolder, IndexingContext.INDEX_FILE + ".gz" );
+
+ final String outputDirectoryName = cli.getOptionValue( TARGET_DIR, "." );
+ final File outputFolder = new File( outputDirectoryName ).getCanonicalFile();
+
+ final boolean quiet = cli.hasOption( QUIET );
+ if ( !quiet )
+ {
+ System.err.printf( "Index Folder: %s\n", indexFolder.getAbsolutePath() );
+ System.err.printf( "Output Folder: %s\n", outputFolder.getAbsolutePath() );
+ }
+
+ long tstart = System.currentTimeMillis();
+
+ final FSDirectory directory = FSDirectory.getDirectory( outputFolder );
+
+ final List<IndexCreator> indexers = getIndexers( cli, plexus );
+
+ BufferedInputStream is = null;
+ try
+ {
+ is = new BufferedInputStream( new FileInputStream( indexArchive ) );
+ DefaultIndexUpdater.unpackIndexData( is, directory, (IndexingContext) Proxy.newProxyInstance(
+ getClass().getClassLoader(), new Class[] { IndexingContext.class }, new PartialImplementation()
+ {
+ public List<IndexCreator> getIndexCreators()
+ {
+ return indexers;
+ }
+ } )
+
+ );
+ }
+ finally
+ {
+ IOUtil.close( is );
+ if ( directory != null )
+ {
+ directory.close();
+ }
+ }
+
+ if ( !quiet )
+ {
+ printStats( tstart );
+ }
+ }
+
+ private List<IndexCreator> getIndexers( final CommandLine cli, PlexusContainer plexus )
+ throws ComponentLookupException
+ {
+ String type = "default";
+
+ if ( cli.hasOption( TYPE ) )
+ {
+ type = cli.getOptionValue( TYPE );
+ }
+
+ List<IndexCreator> indexers = new ArrayList<IndexCreator>(); // NexusIndexer.DEFAULT_INDEX;
+
+ if ( "default".equals( type ) )
+ {
+ indexers.add( plexus.lookup( IndexCreator.class, "min" ) );
+ indexers.add( plexus.lookup( IndexCreator.class, "jarContent" ) );
+ }
+ else if ( "full".equals( type ) )
+ {
+ for ( Object component : plexus.lookupList( IndexCreator.class ) )
+ {
+ indexers.add( (IndexCreator) component );
+ }
+ }
+ else
+ {
+ for ( String hint : type.split( "," ) )
+ {
+ indexers.add( plexus.lookup( IndexCreator.class, hint ) );
+ }
+ }
+ return indexers;
+ }
+
+ private void packIndex( IndexPacker packer, IndexPackingRequest request, boolean debug, boolean quiet )
+ {
+ try
+ {
+ packer.packIndex( request );
+ }
+ catch ( IOException e )
+ {
+ if ( !quiet )
+ {
+ System.err.printf( "Cannot zip index; \n", e.getMessage() );
+
+ if ( debug )
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ private void printStats( final long startTimeInMillis )
+ {
+ long t = System.currentTimeMillis() - startTimeInMillis;
+
+ long s = t / 1000L;
+ if ( t > 60 * 1000 )
+ {
+ long m = t / 1000L / 60L;
+
+ System.err.printf( "Total time: %d min %d sec\n", m, s - ( m * 60 ) );
+ }
+ else
+ {
+ System.err.printf( "Total time: %d sec\n", s );
+ }
+
+ Runtime r = Runtime.getRuntime();
+
+ System.err.printf( "Final memory: %dM/%dM\n", //
+ ( r.totalMemory() - r.freeMemory() ) / MB, r.totalMemory() / MB );
+ }
+
+ /**
+ * Scanner listener
+ */
+ private static final class IndexerListener
+ implements ArtifactScanningListener
+ {
+ private final IndexingContext context;
+
+ private final boolean debug;
+
+ private boolean quiet;
+
+ private long ts = System.currentTimeMillis();
+
+ private int count;
+
+ IndexerListener( IndexingContext context, boolean debug, boolean quiet )
+ {
+ this.context = context;
+ this.debug = debug;
+ this.quiet = quiet;
+ }
+
+ public void scanningStarted( IndexingContext context )
+ {
+ if ( !quiet )
+ {
+ System.err.println( "Scanning started" );
+ }
+ }
+
+ public void artifactDiscovered( ArtifactContext ac )
+ {
+ count++;
+
+ long t = System.currentTimeMillis();
+
+ ArtifactInfo ai = ac.getArtifactInfo();
+
+ if ( !quiet && debug && "maven-plugin".equals( ai.packaging ) )
+ {
+ System.err.printf( "Plugin: %s:%s:%s - %s %s\n", //
+ ai.groupId, ai.artifactId, ai.version, ai.prefix, "" + ai.goals );
+ }
+
+ if ( !quiet && ( debug || ( t - ts ) > 2000L ) )
+ {
+ System.err.printf( " %6d %s\n", count, formatFile( ac.getPom() ) );
+ ts = t;
+ }
+ }
+
+ public void artifactError( ArtifactContext ac, Exception e )
+ {
+ if ( !quiet )
+ {
+ System.err.printf( "! %6d %s - %s\n", count, formatFile( ac.getPom() ), e.getMessage() );
+
+ System.err.printf( " %s\n", formatFile( ac.getArtifact() ) );
+
+ if ( debug )
+ {
+ e.printStackTrace();
+ }
+ }
+
+ ts = System.currentTimeMillis();
+ }
+
+ private String formatFile( File file )
+ {
+ return file.getAbsolutePath().substring( context.getRepository().getAbsolutePath().length() + 1 );
+ }
+
+ public void scanningFinished( IndexingContext context, ScanningResult result )
+ {
+ if ( !quiet )
+ {
+ if ( result.hasExceptions() )
+ {
+ System.err.printf( "Scanning errors: %s\n", result.getExceptions().size() );
+ }
+
+ System.err.printf( "Artifacts added: %s\n", result.getTotalFiles() );
+ System.err.printf( "Artifacts deleted: %s\n", result.getDeletedFiles() );
+ }
+ }
+ }
+
+}
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/NexusIndexerCli.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/NexusIndexerCli.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/PartialImplementation.java
URL: http://svn.apache.org/viewvc/maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/PartialImplementation.java?rev=1030748&view=auto
==============================================================================
--- maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/PartialImplementation.java (added)
+++ maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/PartialImplementation.java Wed Nov 3 22:51:12 2010
@@ -0,0 +1,59 @@
+/**
+ * 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.
+ */
+package org.apache.maven.index.cli;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * An {@link java.lang.reflect.InvocationHandler} that can be extended with methods from the proxied interface.
+ * While invocation it will look for a method within itself that matches the signature of the invoked peoxy method.
+ * If found the method will be invoked and result returned, otherwise an {@link UnsupportedOperationException} will be
+ * thrown.
+ *
+ * @author Alin Dreghiciu
+ */
+public class PartialImplementation
+ implements InvocationHandler
+{
+
+ public Object invoke( final Object proxy, final Method method, final Object[] args )
+ throws Throwable
+ {
+ try
+ {
+ final Method localMethod = getClass().getMethod( method.getName(), method.getParameterTypes() );
+ return localMethod.invoke( this, args );
+ }
+ catch( NoSuchMethodException e )
+ {
+ throw new UnsupportedOperationException( "Method " + method.getName() + "() is not supported" );
+ }
+ catch( IllegalAccessException e )
+ {
+ throw new UnsupportedOperationException( "Method " + method.getName() + "() is not supported" );
+ }
+ catch( InvocationTargetException e )
+ {
+ throw e.getCause();
+ }
+ }
+
+}
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/PartialImplementation.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/cli/PartialImplementation.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DefaultIndexingContext.java
URL: http://svn.apache.org/viewvc/maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DefaultIndexingContext.java?rev=1030748&view=auto
==============================================================================
--- maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DefaultIndexingContext.java (added)
+++ maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DefaultIndexingContext.java Wed Nov 3 22:51:12 2010
@@ -0,0 +1,800 @@
+/**
+ * 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.
+ */
+package org.apache.maven.index.context;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.SerialMergeScheduler;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.maven.index.ArtifactInfo;
+import org.apache.maven.index.artifact.GavCalculator;
+import org.apache.maven.index.artifact.M2GavCalculator;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * The default {@link IndexingContext} implementation.
+ *
+ * @author Jason van Zyl
+ * @author Tamas Cservenak
+ */
+public class DefaultIndexingContext
+ implements IndexingContext
+{
+ /**
+ * A standard location for indices served up by a webserver.
+ */
+ private static final String INDEX_DIRECTORY = ".index";
+
+ private static final String FLD_DESCRIPTOR = "DESCRIPTOR";
+
+ private static final String FLD_DESCRIPTOR_CONTENTS = "NexusIndex";
+
+ private static final String FLD_IDXINFO = "IDXINFO";
+
+ private static final String VERSION = "1.0";
+
+ private static final Term DESCRIPTOR_TERM = new Term( FLD_DESCRIPTOR, FLD_DESCRIPTOR_CONTENTS );
+
+ private Object indexLock = new Object();
+
+ private Directory indexDirectory;
+
+ private File indexDirectoryFile;
+
+ private String id;
+
+ private boolean searchable;
+
+ private String repositoryId;
+
+ private File repository;
+
+ private String repositoryUrl;
+
+ private String indexUpdateUrl;
+
+ private IndexReader indexReader;
+
+ private NexusIndexSearcher indexSearcher;
+
+ // disabled for now, see getReadOnlyIndexSearcher() method for explanation
+ // private NexusIndexSearcher readOnlyIndexSearcher;
+
+ private NexusIndexWriter indexWriter;
+
+ private Date timestamp;
+
+ private List<? extends IndexCreator> indexCreators;
+
+ /**
+ * Currently nexus-indexer knows only M2 reposes
+ * <p>
+ * XXX move this into a concrete Scanner implementation
+ */
+ private GavCalculator gavCalculator;
+
+ private DefaultIndexingContext( String id, String repositoryId,
+ File repository, //
+ String repositoryUrl, String indexUpdateUrl,
+ List<? extends IndexCreator> indexCreators )
+ {
+ this.id = id;
+
+ this.searchable = true;
+
+ this.repositoryId = repositoryId;
+
+ this.repository = repository;
+
+ this.repositoryUrl = repositoryUrl;
+
+ this.indexUpdateUrl = indexUpdateUrl;
+
+ this.indexReader = null;
+
+ this.indexWriter = null;
+
+ this.indexCreators = indexCreators;
+
+ // eh?
+ // Guice does NOT initialize these, and we have to do manually?
+ // While in Plexus, all is well, but when in guice-shim,
+ // these objects are still LazyHintedBeans or what not and IndexerFields are NOT registered!
+ for ( IndexCreator indexCreator : indexCreators )
+ {
+ indexCreator.getIndexerFields();
+ }
+
+ this.gavCalculator = new M2GavCalculator();
+ }
+
+ public DefaultIndexingContext( String id, String repositoryId, File repository, File indexDirectoryFile,
+ String repositoryUrl, String indexUpdateUrl,
+ List<? extends IndexCreator> indexCreators, boolean reclaimIndex )
+ throws IOException, UnsupportedExistingLuceneIndexException
+ {
+ this( id, repositoryId, repository, repositoryUrl, indexUpdateUrl, indexCreators );
+
+ this.indexDirectoryFile = indexDirectoryFile;
+
+ this.indexDirectory = FSDirectory.getDirectory( indexDirectoryFile );
+
+ prepareIndex( reclaimIndex );
+ }
+
+ public DefaultIndexingContext( String id, String repositoryId, File repository, Directory indexDirectory,
+ String repositoryUrl, String indexUpdateUrl,
+ List<? extends IndexCreator> indexCreators, boolean reclaimIndex )
+ throws IOException, UnsupportedExistingLuceneIndexException
+ {
+ this( id, repositoryId, repository, repositoryUrl, indexUpdateUrl, indexCreators );
+
+ this.indexDirectory = indexDirectory;
+
+ if ( indexDirectory instanceof FSDirectory )
+ {
+ this.indexDirectoryFile = ( (FSDirectory) indexDirectory ).getFile();
+ }
+
+ prepareIndex( reclaimIndex );
+ }
+
+ public Directory getIndexDirectory()
+ {
+ return indexDirectory;
+ }
+
+ public File getIndexDirectoryFile()
+ {
+ return indexDirectoryFile;
+ }
+
+ private void prepareIndex( boolean reclaimIndex )
+ throws IOException, UnsupportedExistingLuceneIndexException
+ {
+ if ( IndexReader.indexExists( indexDirectory ) )
+ {
+ try
+ {
+ // unlock the dir forcibly
+ if ( IndexReader.isLocked( indexDirectory ) )
+ {
+ IndexReader.unlock( indexDirectory );
+ }
+
+ checkAndUpdateIndexDescriptor( reclaimIndex );
+ }
+ catch ( IOException e )
+ {
+ if ( reclaimIndex )
+ {
+ prepareCleanIndex( true );
+ }
+ else
+ {
+ throw e;
+ }
+ }
+ }
+ else
+ {
+ prepareCleanIndex( false );
+ }
+
+ timestamp = IndexUtils.getTimestamp( indexDirectory );
+ }
+
+ private void prepareCleanIndex( boolean deleteExisting )
+ throws IOException
+ {
+ if ( deleteExisting )
+ {
+ if ( indexReader != null )
+ {
+ indexReader.close();
+ }
+
+ indexReader = null;
+
+ if ( indexWriter != null && !indexWriter.isClosed() )
+ {
+ indexWriter.close();
+ }
+
+ indexWriter = null;
+
+ // unlock the dir forcibly
+ if ( IndexReader.isLocked( indexDirectory ) )
+ {
+ IndexReader.unlock( indexDirectory );
+ }
+
+ indexDirectory.close();
+ FileUtils.deleteDirectory( indexDirectoryFile );
+ indexDirectoryFile.mkdirs();
+
+ indexDirectory = FSDirectory.getDirectory( indexDirectoryFile );
+ }
+
+ if ( StringUtils.isEmpty( getRepositoryId() ) )
+ {
+ throw new IllegalArgumentException( "The repositoryId cannot be null when creating new repository!" );
+ }
+
+ // create empty idx and store descriptor
+ new NexusIndexWriter( getIndexDirectory(), new NexusAnalyzer(), true ).close();
+
+ storeDescriptor();
+ }
+
+ private void checkAndUpdateIndexDescriptor( boolean reclaimIndex )
+ throws IOException, UnsupportedExistingLuceneIndexException
+ {
+ if ( reclaimIndex )
+ {
+ // forcefully "reclaiming" the ownership of the index as ours
+ storeDescriptor();
+ return;
+ }
+
+ Hits hits = getIndexSearcher().search( new TermQuery( DESCRIPTOR_TERM ) );
+
+ if ( hits == null || hits.length() == 0 )
+ {
+ throw new UnsupportedExistingLuceneIndexException( "The existing index has no NexusIndexer descriptor" );
+ }
+
+ Document descriptor = hits.doc( 0 );
+
+ if ( hits.length() != 1 )
+ {
+ storeDescriptor();
+ return;
+ }
+
+ String[] h = StringUtils.split( descriptor.get( FLD_IDXINFO ), ArtifactInfo.FS );
+ // String version = h[0];
+ String repoId = h[1];
+
+ // // compare version
+ // if ( !VERSION.equals( version ) )
+ // {
+ // throw new UnsupportedExistingLuceneIndexException(
+ // "The existing index has version [" + version + "] and not [" + VERSION + "] version!" );
+ // }
+
+ if ( getRepositoryId() == null )
+ {
+ repositoryId = repoId;
+ }
+ else if ( !getRepositoryId().equals( repoId ) )
+ {
+ throw new UnsupportedExistingLuceneIndexException( "The existing index is for repository " //
+ + "[" + repoId + "] and not for repository [" + getRepositoryId() + "]" );
+ }
+ }
+
+ private void storeDescriptor()
+ throws IOException
+ {
+ Document hdr = new Document();
+
+ hdr.add( new Field( FLD_DESCRIPTOR, FLD_DESCRIPTOR_CONTENTS, Field.Store.YES, Field.Index.UN_TOKENIZED ) );
+
+ hdr.add( new Field( FLD_IDXINFO, VERSION + ArtifactInfo.FS + getRepositoryId(), Field.Store.YES, Field.Index.NO ) );
+
+ IndexWriter w = getIndexWriter();
+
+ w.updateDocument( DESCRIPTOR_TERM, hdr );
+
+ w.commit();
+ }
+
+ private void deleteIndexFiles()
+ throws IOException
+ {
+ String[] names = indexDirectory.list();
+
+ if ( names != null )
+ {
+ for ( int i = 0; i < names.length; i++ )
+ {
+ indexDirectory.deleteFile( names[i] );
+ }
+ }
+
+ IndexUtils.deleteTimestamp( indexDirectory );
+ }
+
+ public boolean isSearchable()
+ {
+ return searchable;
+ }
+
+ public void setSearchable( boolean searchable )
+ {
+ this.searchable = searchable;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public void updateTimestamp()
+ throws IOException
+ {
+ updateTimestamp( false );
+ }
+
+ public void updateTimestamp( boolean save )
+ throws IOException
+ {
+ updateTimestamp( save, new Date() );
+ }
+
+ public void updateTimestamp( boolean save, Date timestamp )
+ throws IOException
+ {
+ this.timestamp = timestamp;
+
+ if ( save )
+ {
+ IndexUtils.updateTimestamp( indexDirectory, getTimestamp() );
+ }
+ }
+
+ public Date getTimestamp()
+ {
+ return timestamp;
+ }
+
+ public String getRepositoryId()
+ {
+ return repositoryId;
+ }
+
+ public File getRepository()
+ {
+ return repository;
+ }
+
+ public String getRepositoryUrl()
+ {
+ return repositoryUrl;
+ }
+
+ public String getIndexUpdateUrl()
+ {
+ if ( repositoryUrl != null )
+ {
+ if ( indexUpdateUrl == null || indexUpdateUrl.trim().length() == 0 )
+ {
+ return repositoryUrl + ( repositoryUrl.endsWith( "/" ) ? "" : "/" ) + INDEX_DIRECTORY;
+ }
+ }
+ return indexUpdateUrl;
+ }
+
+ public Analyzer getAnalyzer()
+ {
+ return new NexusAnalyzer();
+ }
+
+ public IndexWriter getIndexWriter()
+ throws IOException
+ {
+ synchronized ( indexLock )
+ {
+ if ( indexWriter == null || indexWriter.isClosed() )
+ {
+ indexWriter = new NexusIndexWriter( getIndexDirectory(), new NexusAnalyzer(), false );
+
+ indexWriter.setRAMBufferSizeMB( 2 );
+
+ indexWriter.setMergeScheduler( new SerialMergeScheduler() );
+ }
+
+ return indexWriter;
+ }
+ }
+
+ protected boolean isIndexWriterDirty()
+ {
+ synchronized ( indexLock )
+ {
+ if ( indexWriter == null || indexWriter.isClosed() )
+ {
+ return false;
+ }
+ else
+ {
+ return indexWriter.hasUncommittedChanges();
+ }
+ }
+ }
+
+ public IndexReader getIndexReader()
+ throws IOException
+ {
+ synchronized ( indexLock )
+ {
+ if ( indexReader == null || ( !indexReader.isCurrent() && !isIndexWriterDirty() ) )
+ {
+ if ( indexReader != null )
+ {
+ indexReader.close();
+ }
+
+ indexReader = IndexReader.open( indexDirectory );
+ }
+
+ return indexReader;
+ }
+ }
+
+ public IndexSearcher getIndexSearcher()
+ throws IOException
+ {
+ synchronized ( indexLock )
+ {
+ if ( indexSearcher == null || getIndexReader() != indexSearcher.getIndexReader() )
+ {
+ if ( indexSearcher != null )
+ {
+ indexSearcher.close();
+
+ // the reader was supplied explicitly
+ indexSearcher.getIndexReader().close();
+ }
+
+ indexSearcher = new NexusIndexSearcher( this );
+ }
+
+ return indexSearcher;
+ }
+ }
+
+ @Deprecated
+ public IndexSearcher getReadOnlyIndexSearcher()
+ throws IOException
+ {
+ return getIndexSearcher();
+
+ // using RO IndexReader in this way just causes to _double_ the file handles Nexus
+ // uses to read/maintain the Lucene Indexes (once for UPDATE, once for Searches).
+ // The performance gain (no lock contention) is currently too small for the price of
+ // doubled file handles. We will have to resolve this later.
+
+ // disabled for now, see getReadOnlyIndexSearcher() method for explanation
+ // synchronized ( indexLock )
+ // {
+ // if ( readOnlyIndexSearcher == null || !readOnlyIndexSearcher.getIndexReader().isCurrent() )
+ // {
+ // if ( readOnlyIndexSearcher != null )
+ // {
+ // readOnlyIndexSearcher.close();
+ //
+ // // the reader was supplied explicitly
+ // readOnlyIndexSearcher.getIndexReader().close();
+ // }
+ //
+ // readOnlyIndexSearcher = new NexusIndexSearcher( this, IndexReader.open( indexDirectory, true ) );
+ // }
+ //
+ // return readOnlyIndexSearcher;
+ // }
+ }
+
+ public void optimize()
+ throws CorruptIndexException, IOException
+ {
+ IndexWriter w = getIndexWriter();
+
+ try
+ {
+ w.optimize();
+
+ w.commit();
+ }
+ catch ( CorruptIndexException e )
+ {
+ w.close();
+
+ throw e;
+ }
+ catch ( IOException e )
+ {
+ w.close();
+
+ throw e;
+ }
+ }
+
+ public void close( boolean deleteFiles )
+ throws IOException
+ {
+ if ( indexDirectory != null )
+ {
+ synchronized ( indexLock )
+ {
+ IndexUtils.updateTimestamp( indexDirectory, getTimestamp() );
+
+ closeReaders();
+
+ if ( deleteFiles )
+ {
+ deleteIndexFiles();
+ }
+
+ indexDirectory.close();
+ }
+ }
+
+ // TODO: this will prevent from reopening them, but needs better solution
+ indexDirectory = null;
+ }
+
+ public void purge()
+ throws IOException
+ {
+ synchronized ( indexLock )
+ {
+ closeReaders();
+
+ deleteIndexFiles();
+
+ try
+ {
+ prepareIndex( true );
+ }
+ catch ( UnsupportedExistingLuceneIndexException e )
+ {
+ // just deleted it
+ }
+
+ rebuildGroups();
+
+ updateTimestamp( true, null );
+ }
+ }
+
+ // XXX need some locking for reader/writer
+ public void replace( Directory directory )
+ throws IOException
+ {
+ synchronized ( indexLock )
+ {
+ closeReaders();
+
+ deleteIndexFiles();
+
+ Directory.copy( directory, indexDirectory, false );
+
+ // reclaim the index as mine
+ storeDescriptor();
+
+ timestamp = IndexUtils.getTimestamp( directory );
+
+ IndexUtils.updateTimestamp( indexDirectory, getTimestamp() );
+
+ optimize();
+ }
+ }
+
+ public void merge( Directory directory )
+ throws IOException
+ {
+ merge( directory, null );
+ }
+
+ public void merge( Directory directory, DocumentFilter filter )
+ throws IOException
+ {
+ synchronized ( indexLock )
+ {
+ IndexWriter w = getIndexWriter();
+
+ IndexSearcher s = getIndexSearcher();
+
+ IndexReader r = IndexReader.open( directory );
+
+ try
+ {
+ int numDocs = r.maxDoc();
+
+ for ( int i = 0; i < numDocs; i++ )
+ {
+ if ( r.isDeleted( i ) )
+ {
+ continue;
+ }
+
+ Document d = r.document( i );
+
+ if ( filter != null && !filter.accept( d ) )
+ {
+ continue;
+ }
+
+ String uinfo = d.get( ArtifactInfo.UINFO );
+
+ if ( uinfo != null )
+ {
+ Hits hits = s.search( new TermQuery( new Term( ArtifactInfo.UINFO, uinfo ) ) );
+
+ if ( hits.length() == 0 )
+ {
+ w.addDocument( IndexUtils.updateDocument( d, this, false ) );
+ }
+ }
+ else
+ {
+ String deleted = d.get( ArtifactInfo.DELETED );
+
+ if ( deleted != null )
+ {
+ // Deleting the document loses history that it was delete,
+ // so incrementals wont work. Therefore, put the delete
+ // document in as well
+ w.deleteDocuments( new Term( ArtifactInfo.UINFO, deleted ) );
+ w.addDocument( d );
+ }
+ }
+ }
+
+ }
+ finally
+ {
+ r.close();
+
+ w.commit();
+ }
+
+ rebuildGroups();
+
+ Date mergedTimestamp = IndexUtils.getTimestamp( directory );
+
+ if ( getTimestamp() != null && mergedTimestamp != null && mergedTimestamp.after( getTimestamp() ) )
+ {
+ // we have both, keep the newest
+ updateTimestamp( true, mergedTimestamp );
+ }
+ else
+ {
+ updateTimestamp( true );
+ }
+
+ optimize();
+ }
+ }
+
+ private void closeReaders()
+ throws CorruptIndexException, IOException
+ {
+ if ( indexWriter != null )
+ {
+ if ( !indexWriter.isClosed() )
+ {
+ indexWriter.close();
+ }
+
+ indexWriter = null;
+ }
+ if ( indexSearcher != null )
+ {
+ indexSearcher.close();
+
+ // the reader was supplied explicitly
+ indexSearcher.getIndexReader().close();
+
+ indexSearcher = null;
+ }
+ if ( indexReader != null )
+ {
+ indexReader.close();
+
+ indexReader = null;
+ }
+
+ // if ( readOnlyIndexSearcher != null )
+ // {
+ // readOnlyIndexSearcher.close();
+ //
+ // // the reader was supplied explicitly
+ // readOnlyIndexSearcher.getIndexReader().close();
+ //
+ // readOnlyIndexSearcher = null;
+ // }
+ }
+
+ public GavCalculator getGavCalculator()
+ {
+ return gavCalculator;
+ }
+
+ public List<IndexCreator> getIndexCreators()
+ {
+ return Collections.unmodifiableList( indexCreators );
+ }
+
+ // groups
+
+ public void rebuildGroups()
+ throws IOException
+ {
+ synchronized ( indexLock )
+ {
+ IndexUtils.rebuildGroups( this );
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.apache.maven.index.context.IndexingContext#getAllGroups()
+ */
+ public Set<String> getAllGroups()
+ throws IOException
+ {
+ return IndexUtils.getAllGroups( this );
+ }
+
+ public void setAllGroups( Collection<String> groups )
+ throws IOException
+ {
+ IndexUtils.setAllGroups( this, groups );
+ }
+
+ public Set<String> getRootGroups()
+ throws IOException
+ {
+ return IndexUtils.getRootGroups( this );
+ }
+
+ public void setRootGroups( Collection<String> groups )
+ throws IOException
+ {
+ IndexUtils.setRootGroups( this, groups );
+ }
+
+ @Override
+ public String toString()
+ {
+ return id + " : " + timestamp;
+ }
+
+}
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DefaultIndexingContext.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DefaultIndexingContext.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DocumentFilter.java
URL: http://svn.apache.org/viewvc/maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DocumentFilter.java?rev=1030748&view=auto
==============================================================================
--- maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DocumentFilter.java (added)
+++ maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DocumentFilter.java Wed Nov 3 22:51:12 2010
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+package org.apache.maven.index.context;
+
+import org.apache.lucene.document.Document;
+
+public interface DocumentFilter
+{
+ boolean accept( Document doc );
+}
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DocumentFilter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/DocumentFilter.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexCreator.java
URL: http://svn.apache.org/viewvc/maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexCreator.java?rev=1030748&view=auto
==============================================================================
--- maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexCreator.java (added)
+++ maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexCreator.java Wed Nov 3 22:51:12 2010
@@ -0,0 +1,65 @@
+/**
+ * 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.
+ */
+package org.apache.maven.index.context;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import org.apache.lucene.document.Document;
+import org.apache.maven.index.ArtifactContext;
+import org.apache.maven.index.ArtifactInfo;
+import org.apache.maven.index.IndexerField;
+import org.apache.maven.index.creator.JarFileContentsIndexCreator;
+import org.apache.maven.index.creator.MinimalArtifactInfoIndexCreator;
+
+/**
+ * An index creator is responsible for storing and reading data to and from Lucene index.
+ *
+ * @author Jason van Zyl
+ * @see MinimalArtifactInfoIndexCreator
+ * @see JarFileContentsIndexCreator
+ */
+public interface IndexCreator
+{
+ /**
+ * Returns the indexer fields that this IndexCreator introduces to index.
+ *
+ * @return
+ */
+ public Collection<IndexerField> getIndexerFields();
+
+ /**
+ * Populate an <code>ArtifactContext</code> with information about corresponding artifact.
+ */
+ void populateArtifactInfo( ArtifactContext artifactContext )
+ throws IOException;
+
+ /**
+ * Update Lucene <code>Document</code> from a given <code>ArtifactInfo</code>.
+ */
+ void updateDocument( ArtifactInfo artifactInfo, Document document );
+
+ /**
+ * Update an <code>ArtifactInfo</code> from given Lucene <code>Document</code>.
+ *
+ * @return true is artifact info has been updated
+ */
+ boolean updateArtifactInfo( Document document, ArtifactInfo artifactInfo );
+
+}
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexCreator.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexCreator.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexUtils.java
URL: http://svn.apache.org/viewvc/maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexUtils.java?rev=1030748&view=auto
==============================================================================
--- maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexUtils.java (added)
+++ maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexUtils.java Wed Nov 3 22:51:12 2010
@@ -0,0 +1,418 @@
+/**
+ * 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.
+ */
+package org.apache.maven.index.context;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.IndexInput;
+import org.apache.lucene.store.IndexOutput;
+import org.apache.maven.index.ArtifactInfo;
+import org.codehaus.plexus.util.FileUtils;
+
+public class IndexUtils
+{
+ public static final String TIMESTAMP_FILE = "timestamp";
+
+ // timestamp
+
+ public static ArtifactInfo constructArtifactInfo( Document doc, IndexingContext context )
+ {
+ // if no UINFO can't create, must be a different type of record
+ if ( doc.get( ArtifactInfo.UINFO ) == null )
+ {
+ return null;
+ }
+
+ boolean res = false;
+
+ ArtifactInfo artifactInfo = new ArtifactInfo();
+
+ for ( IndexCreator ic : context.getIndexCreators() )
+ {
+ res |= ic.updateArtifactInfo( doc, artifactInfo );
+ }
+
+ return res ? artifactInfo : null;
+ }
+
+ public static Document updateDocument( Document doc, IndexingContext context )
+ {
+ return updateDocument( doc, context, true );
+ }
+
+ public static Document updateDocument( Document doc, IndexingContext context, boolean updateLastModified )
+ {
+ ArtifactInfo ai = constructArtifactInfo( doc, context );
+ if ( ai == null )
+ {
+ return doc;
+ }
+
+ Document document = new Document();
+
+ // unique key
+ document.add( new Field( ArtifactInfo.UINFO, ai.getUinfo(), Field.Store.YES, Field.Index.UN_TOKENIZED ) );
+
+ if ( updateLastModified
+ || doc.getField( ArtifactInfo.LAST_MODIFIED ) == null )
+ {
+ document.add( new Field( ArtifactInfo.LAST_MODIFIED, //
+ Long.toString( System.currentTimeMillis() ), Field.Store.YES, Field.Index.NO ) );
+ }
+ else
+ {
+ document.add( doc.getField( ArtifactInfo.LAST_MODIFIED ) );
+ }
+
+ for ( IndexCreator ic : context.getIndexCreators() )
+ {
+ ic.updateDocument( ai, document );
+ }
+
+ return document;
+ }
+
+ public static void deleteTimestamp( Directory directory )
+ throws IOException
+ {
+ if ( directory.fileExists( TIMESTAMP_FILE ) )
+ {
+ directory.deleteFile( TIMESTAMP_FILE );
+ }
+ }
+
+ public static void updateTimestamp( Directory directory, Date timestamp )
+ throws IOException
+ {
+ synchronized ( directory )
+ {
+ Date currentTimestamp = getTimestamp( directory );
+
+ if ( timestamp != null && ( currentTimestamp == null || !currentTimestamp.equals( timestamp ) ) )
+ {
+ deleteTimestamp( directory );
+
+ IndexOutput io = directory.createOutput( TIMESTAMP_FILE );
+
+ try
+ {
+ io.writeLong( timestamp.getTime() );
+
+ io.flush();
+ }
+ finally
+ {
+ close( io );
+ }
+ }
+ }
+ }
+
+ public static Date getTimestamp( Directory directory )
+ {
+ synchronized ( directory )
+ {
+ Date result = null;
+ try
+ {
+ if ( directory.fileExists( TIMESTAMP_FILE ) )
+ {
+ IndexInput ii = null;
+
+ try
+ {
+ ii = directory.openInput( TIMESTAMP_FILE );
+
+ result = new Date( ii.readLong() );
+ }
+ finally
+ {
+ close( ii );
+ }
+ }
+ }
+ catch ( IOException ex )
+ {
+ }
+
+ return result;
+ }
+ }
+
+ /**
+ * Used to rebuild group information, for example on context which were merged, since merge() of contexts
+ * only merges the Documents with UINFO record (Artifacts).
+ */
+ public static void rebuildGroups( IndexingContext context ) throws IOException
+ {
+ IndexReader r = context.getIndexReader();
+
+ Set<String> rootGroups = new LinkedHashSet<String>();
+ Set<String> allGroups = new LinkedHashSet<String>();
+
+ int numDocs = r.maxDoc();
+
+ for ( int i = 0; i < numDocs; i++ )
+ {
+ if ( r.isDeleted( i ) )
+ {
+ continue;
+ }
+
+ Document d = r.document( i );
+
+ String uinfo = d.get( ArtifactInfo.UINFO );
+
+ if ( uinfo != null )
+ {
+ ArtifactInfo info = IndexUtils.constructArtifactInfo( d, context );
+ rootGroups.add( info.getRootGroup() );
+ allGroups.add( info.groupId );
+ }
+ }
+
+ setRootGroups( context, rootGroups );
+ setAllGroups( context, allGroups );
+
+ context.optimize();
+ }
+
+ // ----------------------------------------------------------------------------
+ // Root groups
+ // ----------------------------------------------------------------------------
+
+ public static Set<String> getRootGroups( IndexingContext context )
+ throws IOException
+ {
+ return getGroups( context, ArtifactInfo.ROOT_GROUPS, ArtifactInfo.ROOT_GROUPS_VALUE, ArtifactInfo.ROOT_GROUPS_LIST );
+ }
+
+ public static void setRootGroups( IndexingContext context, Collection<String> groups )
+ throws IOException
+ {
+ setGroups( context, groups, ArtifactInfo.ROOT_GROUPS, ArtifactInfo.ROOT_GROUPS_VALUE, ArtifactInfo.ROOT_GROUPS_LIST );
+ }
+
+ // ----------------------------------------------------------------------------
+ // All groups
+ // ----------------------------------------------------------------------------
+
+ public static Set<String> getAllGroups( IndexingContext context )
+ throws IOException
+ {
+ return getGroups( context, ArtifactInfo.ALL_GROUPS, ArtifactInfo.ALL_GROUPS_VALUE, ArtifactInfo.ALL_GROUPS_LIST );
+ }
+
+ public static void setAllGroups( IndexingContext context, Collection<String> groups )
+ throws IOException
+ {
+ setGroups( context, groups, ArtifactInfo.ALL_GROUPS, ArtifactInfo.ALL_GROUPS_VALUE, ArtifactInfo.ALL_GROUPS_LIST );
+ }
+
+ private static Set<String> getGroups( IndexingContext context, String field, String filedValue, String listField )
+ throws IOException,
+ CorruptIndexException
+ {
+ Hits hits = context.getIndexSearcher().search( new TermQuery( new Term( field, filedValue ) ) );
+ Set<String> groups = new LinkedHashSet<String>( Math.max( 10, hits.length() ) );
+ if ( hits.length() > 0 )
+ {
+ Document doc = hits.doc( 0 );
+
+ String groupList = doc.get( listField );
+
+ if ( groupList != null )
+ {
+ groups.addAll( Arrays.asList( groupList.split( "\\|" ) ) );
+ }
+ }
+
+ return groups;
+ }
+
+ static void setGroups( IndexingContext context, Collection<String> groups, String groupField, String groupFieldValue, String groupListField )
+ throws IOException,
+ CorruptIndexException
+ {
+ IndexWriter w = context.getIndexWriter();
+
+ w.updateDocument( new Term( groupField, groupFieldValue ), createGroupsDocument(
+ groups,
+ groupField,
+ groupFieldValue,
+ groupListField ) );
+
+ w.commit();
+ }
+
+ static Document createGroupsDocument( Collection<String> groups, String field, String fieldValue, String listField )
+ {
+ Document groupDoc = new Document();
+
+ groupDoc.add( new Field( field, //
+ fieldValue,
+ Field.Store.YES,
+ Field.Index.UN_TOKENIZED ) );
+
+ groupDoc.add( new Field( listField, //
+ ArtifactInfo.lst2str( groups ),
+ Field.Store.YES,
+ Field.Index.NO ) );
+
+ return groupDoc;
+ }
+
+
+ // close helpers
+
+ public static void close( OutputStream os )
+ {
+ if ( os != null )
+ {
+ try
+ {
+ os.close();
+ }
+ catch ( IOException e )
+ {
+ // ignore
+ }
+ }
+ }
+
+ public static void close( InputStream is )
+ {
+ if ( is != null )
+ {
+ try
+ {
+ is.close();
+ }
+ catch ( IOException e )
+ {
+ // ignore
+ }
+ }
+ }
+
+ public static void close( IndexOutput io )
+ {
+ if ( io != null )
+ {
+ try
+ {
+ io.close();
+ }
+ catch ( IOException e )
+ {
+ // ignore
+ }
+ }
+ }
+
+ public static void close( IndexInput in )
+ {
+ if ( in != null )
+ {
+ try
+ {
+ in.close();
+ }
+ catch ( IOException e )
+ {
+ // ignore
+ }
+ }
+ }
+
+ public static void close( IndexReader r )
+ {
+ if ( r != null )
+ {
+ try
+ {
+ r.close();
+ }
+ catch ( IOException e )
+ {
+ // ignore
+ }
+ }
+ }
+
+ public static void close( IndexWriter w )
+ {
+ if ( w != null )
+ {
+ try
+ {
+ w.close();
+ }
+ catch ( IOException e )
+ {
+ // ignore
+ }
+ }
+ }
+
+ public static void close( Directory d )
+ {
+ if ( d != null )
+ {
+ try
+ {
+ d.close();
+ }
+ catch ( IOException e )
+ {
+ // ignore
+ }
+ }
+ }
+
+ public static void delete( File indexDir )
+ {
+ try
+ {
+ FileUtils.deleteDirectory( indexDir );
+ }
+ catch ( IOException ex )
+ {
+ // ignore
+ }
+ }
+
+}
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexUtils.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexUtils.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexingContext.java
URL: http://svn.apache.org/viewvc/maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexingContext.java?rev=1030748&view=auto
==============================================================================
--- maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexingContext.java (added)
+++ maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexingContext.java Wed Nov 3 22:51:12 2010
@@ -0,0 +1,289 @@
+/**
+ * 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.
+ */
+package org.apache.maven.index.context;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.store.Directory;
+import org.apache.maven.index.artifact.GavCalculator;
+
+/**
+ * An indexing context is representing artifact repository for indexing and searching. Indexing context is a statefull
+ * component, it keeps state of index readers and writers.
+ *
+ * @author Jason van Zyl
+ * @author Tamas Cservenak
+ * @author Eugene Kuleshov
+ */
+public interface IndexingContext
+{
+ /**
+ * Standard name of the full repository index that is used when clients requesting index information have nothing to
+ * start with.
+ */
+ public static final String INDEX_FILE = "nexus-maven-repository-index";
+
+ /**
+ * A prefix used for all index property names
+ */
+ public static final String INDEX_PROPERTY_PREFIX = "nexus.index.";
+
+ /**
+ * A property name used to specify index id
+ */
+ public static final String INDEX_ID = INDEX_PROPERTY_PREFIX + "id";
+
+ /**
+ * A property name used to specify legacy index timestam (the last update time)
+ */
+ public static final String INDEX_LEGACY_TIMESTAMP = INDEX_PROPERTY_PREFIX + "time";
+
+ /**
+ * A property name used to specify index timtestamp
+ */
+ public static final String INDEX_TIMESTAMP = INDEX_PROPERTY_PREFIX + "timestamp";
+
+ /**
+ * A prefix used to specify an incremental update chunk name
+ */
+ public static final String INDEX_CHUNK_PREFIX = INDEX_PROPERTY_PREFIX + "incremental-";
+
+ /**
+ * A date format used for index timestamp
+ */
+ public static final String INDEX_TIME_FORMAT = "yyyyMMddHHmmss.SSS Z";
+
+ /**
+ * A date format used for incremental update chunk names
+ */
+ public static final String INDEX_TIME_DAY_FORMAT = "yyyyMMdd";
+
+ /**
+ * A counter used to id the chunks
+ */
+ public static final String INDEX_CHUNK_COUNTER = INDEX_PROPERTY_PREFIX + "last-incremental";
+
+ /**
+ * An id that defines the current incremental chain. If when checking remote repo, the index chain doesnt match
+ * you'll know that you need to download the full index
+ */
+ public static final String INDEX_CHAIN_ID = INDEX_PROPERTY_PREFIX + "chain-id";
+
+ /**
+ * Returns this indexing context id.
+ */
+ String getId();
+
+ /**
+ * Returns repository id.
+ */
+ String getRepositoryId();
+
+ /**
+ * Returns location for the local repository.
+ */
+ File getRepository();
+
+ /**
+ * Returns public repository url.
+ */
+ String getRepositoryUrl();
+
+ /**
+ * Returns url for the index update
+ */
+ String getIndexUpdateUrl();
+
+ /**
+ * Is the context searchable when doing "non-targeted" searches? Ie. Should it take a part when searching without
+ * specifying context?
+ *
+ * @return
+ */
+ boolean isSearchable();
+
+ /**
+ * Sets is the context searchable when doing "non-targeted" searches.
+ *
+ * @param searchable
+ */
+ void setSearchable( boolean searchable );
+
+ /**
+ * Returns index update time
+ */
+ Date getTimestamp();
+
+ void updateTimestamp()
+ throws IOException;
+
+ void updateTimestamp( boolean save )
+ throws IOException;
+
+ void updateTimestamp( boolean save, Date date )
+ throws IOException;
+
+ /**
+ * Returns the Lucene IndexReader of this context.
+ *
+ * @return reader
+ * @throws IOException
+ */
+ IndexReader getIndexReader()
+ throws IOException;
+
+ /**
+ * Returns the Lucene IndexSearcher of this context.
+ *
+ * @return searcher
+ * @throws IOException
+ */
+ IndexSearcher getIndexSearcher()
+ throws IOException;
+
+ /**
+ * Returns the ReadOnly IndexSearcher of this context. IndexingContext will manage this searcher in similar way as
+ * the RW readers. -- THIS IS NOT YET FULLY DONE, DO NOT USE IT!
+ *
+ * @return
+ * @throws IOException
+ * @deprecated Do not use it yet! Not done!
+ */
+ IndexSearcher getReadOnlyIndexSearcher()
+ throws IOException;
+
+ /**
+ * Returns the Lucene IndexWriter of this context.
+ *
+ * @return indexWriter
+ * @throws IOException
+ */
+ IndexWriter getIndexWriter()
+ throws IOException;
+
+ /**
+ * List of IndexCreators used in this context.
+ *
+ * @return list of index creators.
+ */
+ List<IndexCreator> getIndexCreators();
+
+ /**
+ * Returns the Lucene Analyzer of this context used for by IndexWriter and IndexSearcher. Note: this method always
+ * creates a new instance of analyzer!
+ *
+ * @return
+ */
+ Analyzer getAnalyzer();
+
+ /**
+ * Optimizes index
+ */
+ void optimize()
+ throws CorruptIndexException, IOException;
+
+ /**
+ * Shuts down this context.
+ */
+ void close( boolean deleteFiles )
+ throws IOException;
+
+ /**
+ * Purge (cleans) the context, deletes/empties the index and restores the context to new/empty state.
+ *
+ * @throws IOException
+ */
+ void purge()
+ throws IOException;
+
+ /**
+ * Merges content of given Lucene directory with this context.
+ *
+ * @param directory - the directory to merge
+ */
+ void merge( Directory directory )
+ throws IOException;
+
+ /**
+ * Merges content of given Lucene directory with this context, but filters out the unwanted ones.
+ *
+ * @param directory - the directory to merge
+ */
+ void merge( Directory directory, DocumentFilter filter )
+ throws IOException;
+
+ /**
+ * Replaces the Lucene index with the one from supplied directory.
+ *
+ * @param directory
+ * @throws IOException
+ */
+ void replace( Directory directory )
+ throws IOException;
+
+ Directory getIndexDirectory();
+
+ File getIndexDirectoryFile();
+
+ /**
+ * Returns the GavCalculator for this Context. Implies repository layout.
+ */
+ GavCalculator getGavCalculator();
+
+ /**
+ * Sets all group names stored in the current indexing context
+ */
+ void setAllGroups( Collection<String> groups )
+ throws IOException;
+
+ /**
+ * Gets all group names stored in the current indexing context
+ */
+ Set<String> getAllGroups()
+ throws IOException;
+
+ /**
+ * Sets root group names stored in the current indexing context
+ */
+ void setRootGroups( Collection<String> groups )
+ throws IOException;
+
+ /**
+ * Gets root group names stored in the current indexing context
+ */
+ Set<String> getRootGroups()
+ throws IOException;
+
+ /**
+ * Rebuilds stored group names from the index
+ */
+ void rebuildGroups()
+ throws IOException;
+
+}
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexingContext.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/IndexingContext.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusAnalyzer.java
URL: http://svn.apache.org/viewvc/maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusAnalyzer.java?rev=1030748&view=auto
==============================================================================
--- maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusAnalyzer.java (added)
+++ maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusAnalyzer.java Wed Nov 3 22:51:12 2010
@@ -0,0 +1,118 @@
+/**
+ * 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.
+ */
+package org.apache.maven.index.context;
+
+import java.io.Reader;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.CharTokenizer;
+import org.apache.lucene.analysis.TokenStream;
+import org.apache.lucene.analysis.Tokenizer;
+import org.apache.maven.index.creator.JarFileContentsIndexCreator;
+
+/**
+ * A Nexus specific analyzer. Only difference from Lucene's SimpleAnalyzer is that we use LetterOrDigitTokenizer instead
+ * of LowerCaseTokenizer. LetterOrDigitTokenizer does pretty much the same as LowerCaseTokenizer, it normalizes to lower
+ * case letter, but it takes letters and numbers too (as opposed to LowerCaseTokenizer) as token chars.
+ *
+ * @author Eugene Kuleshov
+ * @author cstamas
+ */
+public class NexusAnalyzer
+ extends Analyzer
+{
+ public TokenStream tokenStream( String fieldName, Reader reader )
+ {
+ return getTokenizer( fieldName, reader );
+ }
+
+ protected Tokenizer getTokenizer( String fieldName, Reader reader )
+ {
+ if ( JarFileContentsIndexCreator.FLD_CLASSNAMES_KW.getKey().equals( fieldName ) )
+ {
+ // To keep "backward" compatibility, we have to use old flawed tokenizer.
+ return new DeprecatedClassnamesTokenizer( reader );
+ }
+ else
+ {
+ return new LetterOrDigitTokenizer( reader );
+ }
+ }
+
+ // ==
+
+ public static class NoopTokenizer
+ extends CharTokenizer
+ {
+ public NoopTokenizer( Reader in )
+ {
+ super( in );
+ }
+
+ @Override
+ protected boolean isTokenChar( char c )
+ {
+ return true;
+ }
+ }
+
+ @Deprecated
+ public static class DeprecatedClassnamesTokenizer
+ extends CharTokenizer
+ {
+ public DeprecatedClassnamesTokenizer( Reader in )
+ {
+ super( in );
+ }
+
+ @Override
+ protected boolean isTokenChar( char c )
+ {
+ return c != '\n';
+ }
+
+ @Override
+ protected char normalize( char c )
+ {
+ return Character.toLowerCase( c );
+ }
+ }
+
+ public static class LetterOrDigitTokenizer
+ extends CharTokenizer
+ {
+ public LetterOrDigitTokenizer( Reader in )
+ {
+ super( in );
+ }
+
+ @Override
+ protected boolean isTokenChar( char c )
+ {
+ return Character.isLetterOrDigit( c );
+ }
+
+ @Override
+ protected char normalize( char c )
+ {
+ return Character.toLowerCase( c );
+ }
+ }
+
+}
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusAnalyzer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusAnalyzer.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexSearcher.java
URL: http://svn.apache.org/viewvc/maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexSearcher.java?rev=1030748&view=auto
==============================================================================
--- maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexSearcher.java (added)
+++ maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexSearcher.java Wed Nov 3 22:51:12 2010
@@ -0,0 +1,55 @@
+/**
+ * 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.
+ */
+package org.apache.maven.index.context;
+
+import java.io.IOException;
+
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.search.IndexSearcher;
+
+/**
+ * An extended Searcher, that holds reference to the IndexingContext that is a searcher for. Needed to provide "extra"
+ * data for search hits, that are not on index, and suppot ArtifactInfoPostprocessor's.
+ *
+ * @author cstamas
+ */
+public class NexusIndexSearcher
+ extends IndexSearcher
+{
+ private final IndexingContext indexingContext;
+
+ public NexusIndexSearcher( final IndexingContext indexingContext )
+ throws IOException
+ {
+ this( indexingContext, indexingContext.getIndexReader() );
+ }
+
+ public NexusIndexSearcher( final IndexingContext indexingContext, final IndexReader reader )
+ throws IOException
+ {
+ super( reader );
+
+ this.indexingContext = indexingContext;
+ }
+
+ public IndexingContext getIndexingContext()
+ {
+ return indexingContext;
+ }
+}
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexSearcher.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexSearcher.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Added: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexWriter.java
URL: http://svn.apache.org/viewvc/maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexWriter.java?rev=1030748&view=auto
==============================================================================
--- maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexWriter.java (added)
+++ maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexWriter.java Wed Nov 3 22:51:12 2010
@@ -0,0 +1,90 @@
+/**
+ * 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.
+ */
+package org.apache.maven.index.context;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.index.CorruptIndexException;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.LockObtainFailedException;
+
+/**
+ * An extension of <a
+ * href="http://lucene.apache.org/java/2_4_0/api/core/org/apache/lucene/index/IndexWriter.html">Lucene IndexWriter</a>
+ * to allow to track if writer is closed
+ */
+public class NexusIndexWriter
+ extends IndexWriter
+{
+ private boolean closed;
+
+ public NexusIndexWriter( final Directory directory, final Analyzer analyzer, boolean create )
+ throws CorruptIndexException, LockObtainFailedException, IOException
+ {
+ this( directory, analyzer, create, false /* autoCommit */);
+ }
+
+ public NexusIndexWriter( final Directory directory, final Analyzer analyzer, boolean create, boolean autoCommit )
+ throws CorruptIndexException, LockObtainFailedException, IOException
+ {
+ super( directory, autoCommit, analyzer, create );
+
+ this.closed = false;
+ }
+
+ @Override
+ public void close()
+ throws CorruptIndexException, IOException
+ {
+ super.close();
+
+ this.closed = true;
+ }
+
+ public boolean isClosed()
+ {
+ return closed;
+ }
+
+ public boolean hasUncommittedChanges()
+ {
+ try
+ {
+ Field pendingCommit = IndexWriter.class.getDeclaredField( "pendingCommit" );
+
+ pendingCommit.setAccessible( true );
+
+ return pendingCommit.get( this ) != null;
+ }
+ catch ( Exception x )
+ {
+ if ( x instanceof RuntimeException )
+ {
+ throw (RuntimeException) x;
+ }
+ else
+ {
+ throw new RuntimeException( "Could not access the \"IndexWriter.pendingCommit\" field!", x );
+ }
+ }
+ }
+}
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexWriter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: maven/indexer/trunk/indexer-core/src/main/java/org/apache/maven/index/context/NexusIndexWriter.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision