[hibernate-commits] Hibernate SVN: r14612 - in search/trunk/src: java/org/hibernate/search/event and 4 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Apr 29 20:27:12 EDT 2008


Author: epbernard
Date: 2008-04-29 20:27:12 -0400 (Tue, 29 Apr 2008)
New Revision: 14612

Added:
   search/trunk/src/java/org/hibernate/search/store/DirectoryProviderHelper.java
Removed:
   search/trunk/src/java/org/hibernate/search/util/DirectoryProviderHelper.java
Modified:
   search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java
   search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java
   search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
   search/trunk/src/java/org/hibernate/search/store/FSDirectoryProvider.java
   search/trunk/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java
   search/trunk/src/java/org/hibernate/search/store/FSSlaveDirectoryProvider.java
   search/trunk/src/test/org/hibernate/search/test/FSDirectoryTest.java
Log:
HSEARCH-181 Fix a few directory related issues around DirectoryProvider (Sanne Grinovero)

Modified: search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java	2008-04-29 23:46:43 UTC (rev 14611)
+++ search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java	2008-04-30 00:27:12 UTC (rev 14612)
@@ -40,4 +40,6 @@
 	public LuceneIndexingParameters getIndexingParameters(DirectoryProvider<?> provider);
 
 	void addIndexingParmeters(DirectoryProvider<?> provider, LuceneIndexingParameters indexingParams);
+
+	public String getIndexingStrategy();
 }

Modified: search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java	2008-04-29 23:46:43 UTC (rev 14611)
+++ search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java	2008-04-30 00:27:12 UTC (rev 14612)
@@ -40,16 +40,13 @@
 
 	public void initialize(Configuration cfg) {
 		searchFactoryImplementor = SearchFactoryImpl.getSearchFactory( cfg );
-		String indexingStrategy = cfg.getProperties().getProperty( Environment.INDEXING_STRATEGY, "event" );
+		String indexingStrategy = searchFactoryImplementor.getIndexingStrategy();
 		if ( "event".equals( indexingStrategy ) ) {
 			used = searchFactoryImplementor.getDocumentBuilders().size() != 0;
 		}
 		else if ( "manual".equals( indexingStrategy ) ) {
 			used = false;
 		}
-		else {
-			throw new SearchException(Environment.INDEXING_STRATEGY + " unknown: " + indexingStrategy);
-		}
 	}
 
 	public SearchFactoryImplementor getSearchFactoryImplementor() {

Modified: search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java	2008-04-29 23:46:43 UTC (rev 14611)
+++ search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java	2008-04-30 00:27:12 UTC (rev 14612)
@@ -66,6 +66,7 @@
 	private BackendQueueProcessorFactory backendQueueProcessorFactory;
 	private Map<String, FilterDef> filterDefinitions = new HashMap<String, FilterDef>();
 	private FilterCachingStrategy filterCachingStrategy;
+	private String indexingStrategy;
 
 	/**
 	 * Each directory provider (index) can have its own performance settings.
@@ -86,6 +87,7 @@
 	public SearchFactoryImpl(Configuration cfg) {
 		//yuk
 		ReflectionManager reflectionManager = getReflectionManager( cfg );
+		setIndexingStrategy(cfg); //need to be done before the document builds
 		InitContext context = new InitContext(cfg);
 		initDocumentBuilders(cfg, reflectionManager, context );
 
@@ -98,6 +100,17 @@
 		buildFilterCachingStrategy( cfg.getProperties() );
 	}
 
+	private void setIndexingStrategy(Configuration cfg) {
+		indexingStrategy = cfg.getProperties().getProperty( Environment.INDEXING_STRATEGY, "event" );
+		if ( ! ("event".equals( indexingStrategy ) || "manual".equals( indexingStrategy ) ) ) {
+			throw new SearchException(Environment.INDEXING_STRATEGY + " unknown: " + indexingStrategy);
+		}
+	}
+
+	public String getIndexingStrategy() {
+		return indexingStrategy;
+	}
+
 	private void bindFilterDefs(XClass mappedXClass) {
 		FullTextFilterDef defAnn = mappedXClass.getAnnotation( FullTextFilterDef.class );
 		if ( defAnn != null ) {

Added: search/trunk/src/java/org/hibernate/search/store/DirectoryProviderHelper.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/store/DirectoryProviderHelper.java	                        (rev 0)
+++ search/trunk/src/java/org/hibernate/search/store/DirectoryProviderHelper.java	2008-04-30 00:27:12 UTC (rev 14612)
@@ -0,0 +1,143 @@
+//$Id$
+package org.hibernate.search.store;
+
+import java.util.Properties;
+import java.io.File;
+import java.io.IOException;
+
+import org.hibernate.search.SearchException;
+import org.hibernate.annotations.common.util.StringHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.store.FSDirectory;
+
+/**
+ * @author Emmanuel Bernard
+ * @author Sanne Grinovero
+ */
+public class DirectoryProviderHelper {
+	
+	private static final Log log = LogFactory.getLog( DirectoryProviderHelper.class );
+	private static final String ROOTINDEX_PROP_NAME = "sourceBase";
+	private static final String RELATIVEINDEX_PROP_NAME = "source";
+
+	/**
+	 * Build a directory name out of a root and relative path, guessing the significant part
+	 * and checking for the file availability
+	 * @param directoryProviderName
+	 * @param properties
+	 * @param needWritePermissions when true the directory will be tested for read-write permissions. 
+	 * @return
+	 */
+	public static File getSourceDirectory( String directoryProviderName, Properties properties, boolean needWritePermissions ) {
+		String root = properties.getProperty( ROOTINDEX_PROP_NAME );
+		String relative = properties.getProperty( RELATIVEINDEX_PROP_NAME );
+		File sourceDirectory;
+		if ( log.isTraceEnabled() ) {
+			log.trace(
+					"Guess source directory from " + ROOTINDEX_PROP_NAME + " " + root != null ? root : "<null>"
+							+ " and " + RELATIVEINDEX_PROP_NAME + " " + relative != null ? relative : "<null>"
+			);
+		}
+		if ( relative == null ) relative = directoryProviderName;
+		if ( StringHelper.isEmpty( root ) ) {
+			log.debug( "No root directory, go with relative " + relative );
+			sourceDirectory = new File( relative );
+			if ( ! sourceDirectory.isDirectory() ) { // this also tests for existence
+				throw new SearchException( "Unable to read source directory: " + relative );
+			}
+			//else keep source as it
+		}
+		else {
+			File rootDir = new File( root );
+			makeSanityCheckedDirectory( rootDir, directoryProviderName, needWritePermissions );
+			sourceDirectory = new File( root, relative );
+			makeSanityCheckedDirectory( sourceDirectory, directoryProviderName, needWritePermissions );
+			log.debug( "Get directory from root + relative" );
+		}
+		return sourceDirectory;
+	}
+	
+	/**
+	 * Creates an FSDirectory in provided directory if not already existing.
+	 * @param indexDir The directory where to write a new index
+	 * @return the created FSDirectory
+	 * @throws IOException
+	 */
+	public static FSDirectory createFSIndex(File indexDir) throws IOException {
+		FSDirectory fsDirectory = FSDirectory.getDirectory( indexDir );
+		if ( ! IndexReader.indexExists( fsDirectory ) ) {
+			log.debug( "Initialize index: '" + indexDir.getAbsolutePath() + "'" );
+			IndexWriter iw = new IndexWriter( fsDirectory, new StandardAnalyzer(), true );
+			iw.close();
+		}
+		return fsDirectory;
+	}
+
+	/**
+	 * Verify the index directory exists and is writable,
+	 * or creates it if not existing.
+	 * @param annotatedIndexName The index name declared on the @Indexed annotation
+	 * @param properties The properties may override the indexname.
+	 * @param verifyIsWritable Verify the directory is writable
+	 * @return the File representing the Index Directory
+	 * @throws SearchException
+	 */
+	public static File getVerifiedIndexDir(String annotatedIndexName, Properties properties, boolean verifyIsWritable) {
+		String indexBase = properties.getProperty( "indexBase", "." );
+		String indexName = properties.getProperty( "indexName", annotatedIndexName );
+		File baseIndexDir = new File( indexBase );
+		makeSanityCheckedDirectory( baseIndexDir, indexName, verifyIsWritable );
+		File indexDir = new File( baseIndexDir, indexName );
+		makeSanityCheckedDirectory( indexDir, indexName, verifyIsWritable );
+		return indexDir;
+	}
+	
+	/**
+	 * @param directory The directory to create or verify
+	 * @param indexName To label exceptions
+	 * @param verifyIsWritable Verify the directory is writable
+	 * @throws SearchException
+	 */
+	private static void makeSanityCheckedDirectory(File directory, String indexName, boolean verifyIsWritable) {
+		if ( ! directory.exists() ) {
+			log.warn( "Index directory not found, creating: '" + directory.getAbsolutePath() + "'" );
+			//if not existing, create the full path
+			if ( ! directory.mkdirs() ) {
+				throw new SearchException( "Unable to create index directory: "
+						+ directory.getAbsolutePath() + " for index "
+						+ indexName );
+			}
+		}
+		else {
+			// else check it is not a file
+			if ( ! directory.isDirectory() ) {
+				throw new SearchException( "Unable to initialize index: "
+						+ indexName + ": "
+						+ directory.getAbsolutePath() + " is a file." );
+			}
+		}
+		// and ensure it's writable
+		if ( verifyIsWritable && ( ! directory.canWrite() ) ) {
+			throw new SearchException( "Cannot write into index directory: "
+					+ directory.getAbsolutePath() + " for index "
+					+ indexName );
+		}
+	}
+
+	static long getRefreshPeriod(Properties properties, String directoryProviderName) {
+		String refreshPeriod = properties.getProperty( "refresh", "3600" );
+		long period;
+		try {
+			period = Long.parseLong( refreshPeriod );
+		} catch (NumberFormatException nfe) {
+			throw new SearchException( "Unable to initialize index: " + directoryProviderName +"; refresh period is not numeric.", nfe );
+		}
+		log.debug( "Refresh period " + period + " seconds" );
+		return period * 1000; //per second
+	}
+	
+}

Modified: search/trunk/src/java/org/hibernate/search/store/FSDirectoryProvider.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/store/FSDirectoryProvider.java	2008-04-29 23:46:43 UTC (rev 14611)
+++ search/trunk/src/java/org/hibernate/search/store/FSDirectoryProvider.java	2008-04-30 00:27:12 UTC (rev 14612)
@@ -5,13 +5,9 @@
 import java.io.IOException;
 import java.util.Properties;
 
-import org.apache.lucene.analysis.standard.StandardAnalyzer;
-import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.store.FSDirectory;
-import org.apache.commons.logging.LogFactory;
-import org.apache.commons.logging.Log;
-import org.hibernate.HibernateException;
-import org.hibernate.search.util.DirectoryProviderHelper;
+import org.hibernate.search.Environment;
+import org.hibernate.search.SearchException;
 import org.hibernate.search.engine.SearchFactoryImplementor;
 
 /**
@@ -21,31 +17,24 @@
  *
  * @author Emmanuel Bernard
  * @author Sylvain Vieujot
+ * @author Sanne Grinovero
  */
 public class FSDirectoryProvider implements DirectoryProvider<FSDirectory> {
-	private static Log log = LogFactory.getLog( FSDirectoryProvider.class );
+	
 	private FSDirectory directory;
 	private String indexName;
 
 	public void initialize(String directoryProviderName, Properties properties, SearchFactoryImplementor searchFactoryImplementor) {
-		File indexDir = DirectoryProviderHelper.determineIndexDir( directoryProviderName, properties );
+		// on "manual" indexing skip read-write check on index directory
+		boolean manual = searchFactoryImplementor.getIndexingStrategy().equals( "manual" );
+		File indexDir = DirectoryProviderHelper.getVerifiedIndexDir( directoryProviderName, properties, ! manual );
 		try {
-			boolean create = !indexDir.exists();
-			if (create) {
-				log.debug( "index directory not found, creating: '" + indexDir.getAbsolutePath() + "'" );
-				indexDir.mkdirs();
-			}
 			indexName = indexDir.getCanonicalPath();
-			directory = FSDirectory.getDirectory( indexName );
 			//this is cheap so it's not done in start()
-			if ( create ) {
-				log.debug( "Initialize index: '" + indexName + "'" );
-				IndexWriter iw = new IndexWriter( directory, new StandardAnalyzer(), create );
-				iw.close();
-			}
+			directory = DirectoryProviderHelper.createFSIndex( indexDir );
 		}
 		catch (IOException e) {
-			throw new HibernateException( "Unable to initialize index: " + directoryProviderName, e );
+			throw new SearchException( "Unable to initialize index: " + directoryProviderName, e );
 		}
 	}
 

Modified: search/trunk/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java	2008-04-29 23:46:43 UTC (rev 14611)
+++ search/trunk/src/java/org/hibernate/search/store/FSMasterDirectoryProvider.java	2008-04-30 00:27:12 UTC (rev 14612)
@@ -11,14 +11,11 @@
 import java.io.IOException;
 
 import org.apache.lucene.store.FSDirectory;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.analysis.standard.StandardAnalyzer;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.hibernate.search.util.DirectoryProviderHelper;
+import org.hibernate.search.SearchException;
 import org.hibernate.search.util.FileHelper;
 import org.hibernate.search.engine.SearchFactoryImplementor;
-import org.hibernate.HibernateException;
 
 /**
  * File based DirectoryProvider that takes care of index copy
@@ -29,10 +26,13 @@
  * A copy is triggered every refresh seconds
  *
  * @author Emmanuel Bernard
+ * @author Sanne Grinovero
  */
 //TODO rename copy?
 public class FSMasterDirectoryProvider implements DirectoryProvider<FSDirectory> {
+	
 	private static Log log = LogFactory.getLog( FSMasterDirectoryProvider.class );
+	
 	private FSDirectory directory;
 	private int current;
 	private String indexName;
@@ -40,54 +40,37 @@
 	private SearchFactoryImplementor searchFactory;
 
 	//variables needed between initialize and start
-	private String source;
+	private File sourceDir;
 	private File indexDir;
 	private String directoryProviderName;
 	private Properties properties;
 
-
 	public void initialize(String directoryProviderName, Properties properties, SearchFactoryImplementor searchFactoryImplementor) {
 		this.properties = properties;
 		this.directoryProviderName = directoryProviderName;
 		//source guessing
-		source = DirectoryProviderHelper.getSourceDirectory( "sourceBase", "source", directoryProviderName, properties );
-		if ( source == null)
-			throw new IllegalStateException("FSMasterDirectoryProvider requires a viable source directory");
-		log.debug( "Source directory: " + source );
-		indexDir = DirectoryProviderHelper.determineIndexDir( directoryProviderName, properties );
-		log.debug( "Index directory: " + indexDir );
+		sourceDir = DirectoryProviderHelper.getSourceDirectory( directoryProviderName, properties, true );
+		log.debug( "Source directory: " + sourceDir.getPath() );
+		indexDir = DirectoryProviderHelper.getVerifiedIndexDir( directoryProviderName, properties, true );
+		log.debug( "Index directory: " + indexDir.getPath() );
 		try {
-			boolean create = !indexDir.exists();
-			if (create) {
-				log.debug( "index directory not found, creating: '" + indexDir.getAbsolutePath() + "'" );
-				indexDir.mkdirs();
-			}
 			indexName = indexDir.getCanonicalPath();
-			directory = FSDirectory.getDirectory( indexName);
-			if ( create ) {
-				log.debug( "Initialize index: '" + indexName + "'" );
-				IndexWriter iw = new IndexWriter( directory, new StandardAnalyzer(), create );
-				iw.close();
-			}
+			directory = DirectoryProviderHelper.createFSIndex( indexDir );
 		}
 		catch (IOException e) {
-			throw new HibernateException( "Unable to initialize index: " + directoryProviderName, e );
+			throw new SearchException( "Unable to initialize index: " + directoryProviderName, e );
 		}
 		this.searchFactory = searchFactoryImplementor;
 	}
 
 	public void start() {
-		//source guessing
-		String refreshPeriod = properties.getProperty( "refresh", "3600" );
-		long period = Long.parseLong( refreshPeriod );
-		log.debug("Refresh period " + period + " seconds");
-		period *= 1000; //per second
+		long period = DirectoryProviderHelper.getRefreshPeriod( properties, directoryProviderName );
 		try {
 			//copy to source
-			if ( new File( source, "current1").exists() ) {
+			if ( new File( sourceDir, "current1").exists() ) {
 				current = 2;
 			}
-			else if ( new File( source, "current2").exists() ) {
+			else if ( new File( sourceDir, "current2").exists() ) {
 				current = 1;
 			}
 			else {
@@ -95,19 +78,19 @@
 				current = 1;
 			}
 			String currentString = Integer.valueOf( current ).toString();
-			File subDir = new File( source, currentString );
+			File subDir = new File( sourceDir, currentString );
 			FileHelper.synchronize( indexDir, subDir, true );
-			new File( source, "current1").delete();
-			new File( source, "current2").delete();
+			new File( sourceDir, "current1 ").delete();
+			new File( sourceDir, "current2" ).delete();
 			//TODO small hole, no file can be found here
-			new File( source, "current" + currentString).createNewFile();
-			log.debug( "Current directory: " + current);
+			new File( sourceDir, "current" + currentString ).createNewFile();
+			log.debug( "Current directory: " + current );
 		}
 		catch (IOException e) {
-			throw new HibernateException( "Unable to initialize index: " + directoryProviderName, e );
+			throw new SearchException( "Unable to initialize index: " + directoryProviderName, e );
 		}
-		timer = new Timer(true); //daemon thread, the copy algorithm is robust
-		TimerTask task = new FSMasterDirectoryProvider.TriggerTask(indexName, source, this );
+		timer = new Timer( true ); //daemon thread, the copy algorithm is robust
+		TimerTask task = new FSMasterDirectoryProvider.TriggerTask( indexDir, sourceDir, this );
 		timer.scheduleAtFixedRate( task, period, period );
 	}
 
@@ -136,10 +119,10 @@
 
 	class TriggerTask extends TimerTask {
 
-		private ExecutorService executor;
-		private FSMasterDirectoryProvider.CopyDirectory copyTask;
+		private final ExecutorService executor;
+		private final FSMasterDirectoryProvider.CopyDirectory copyTask;
 
-		public TriggerTask(String source, String destination, DirectoryProvider directoryProvider) {
+		public TriggerTask(File source, File destination, DirectoryProvider directoryProvider) {
 			executor = Executors.newSingleThreadExecutor();
 			copyTask = new FSMasterDirectoryProvider.CopyDirectory( source, destination, directoryProvider );
 		}
@@ -149,19 +132,19 @@
 				executor.execute( copyTask );
 			}
 			else {
-				log.info( "Skipping directory synchronization, previous work still in progress: " + indexName);
+				log.info( "Skipping directory synchronization, previous work still in progress: " + indexName );
 			}
 		}
 	}
 
 	class CopyDirectory implements Runnable {
-		private String source;
-		private String destination;
+		private final File source;
+		private final File destination;
 		private volatile boolean inProgress;
 		private Lock directoryProviderLock;
 		private DirectoryProvider directoryProvider;
 
-		public CopyDirectory(String source, String destination, DirectoryProvider directoryProvider) {
+		public CopyDirectory(File source, File destination, DirectoryProvider directoryProvider) {
 			this.source = source;
 			this.destination = destination;
 			this.directoryProvider = directoryProvider;
@@ -171,7 +154,7 @@
 			//TODO get rid of current and use the marker file instead?
 			long start = System.currentTimeMillis();
 			inProgress = true;
-			if (directoryProviderLock == null) {
+			if ( directoryProviderLock == null ) {
 				directoryProviderLock = searchFactory.getLockableDirectoryProviders().get( directoryProvider );
 				directoryProvider = null;
 				searchFactory = null; //get rid of any useless link (help hot redeployment?)
@@ -180,26 +163,25 @@
 				directoryProviderLock.lock();
 				int oldIndex = current;
 				int index = current == 1 ? 2 : 1;
-				File sourceFile = new File(source);
 
 				File destinationFile = new File(destination, Integer.valueOf(index).toString() );
 				//TODO make smart a parameter
 				try {
-					log.trace("Copying " + sourceFile + " into " + destinationFile);
-					FileHelper.synchronize( sourceFile, destinationFile, true);
+					log.trace( "Copying " + source + " into " + destinationFile );
+					FileHelper.synchronize( source, destinationFile, true );
 					current = index;
 				}
 				catch (IOException e) {
 					//don't change current
-					log.error( "Unable to synchronize source of " + indexName, e);
+					log.error( "Unable to synchronize source of " + indexName, e );
 					inProgress = false;
 					return;
 				}
-				if ( ! new File(destination, "current" + oldIndex).delete() ) {
+				if ( ! new File( destination, "current" + oldIndex ).delete() ) {
 					log.warn( "Unable to remove previous marker file from source of " + indexName );
 				}
 				try {
-					new File(destination, "current" + index).createNewFile();
+					new File( destination, "current" + index ).createNewFile();
 				}
 				catch( IOException e ) {
 					log.warn( "Unable to create current marker in source of " + indexName, e );
@@ -209,7 +191,7 @@
 				directoryProviderLock.unlock();
 				inProgress = false;
 			}
-			log.trace( "Copy for " + indexName + " took " + (System.currentTimeMillis() - start) + " ms");
+			log.trace( "Copy for " + indexName + " took " + (System.currentTimeMillis() - start) + " ms" );
 		}
 	}
 

Modified: search/trunk/src/java/org/hibernate/search/store/FSSlaveDirectoryProvider.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/store/FSSlaveDirectoryProvider.java	2008-04-29 23:46:43 UTC (rev 14611)
+++ search/trunk/src/java/org/hibernate/search/store/FSSlaveDirectoryProvider.java	2008-04-30 00:27:12 UTC (rev 14612)
@@ -10,14 +10,11 @@
 import java.io.IOException;
 
 import org.apache.lucene.store.FSDirectory;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.analysis.standard.StandardAnalyzer;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.hibernate.HibernateException;
 import org.hibernate.AssertionFailure;
+import org.hibernate.search.SearchException;
 import org.hibernate.search.util.FileHelper;
-import org.hibernate.search.util.DirectoryProviderHelper;
 import org.hibernate.search.engine.SearchFactoryImplementor;
 
 /**
@@ -30,9 +27,12 @@
  * A copy is triggered every refresh seconds
  *
  * @author Emmanuel Bernard
+ * @author Sanne Grinovero
  */
 public class FSSlaveDirectoryProvider implements DirectoryProvider<FSDirectory> {
+	
 	private static Log log = LogFactory.getLog( FSSlaveDirectoryProvider.class );
+	
 	private FSDirectory directory1;
 	private FSDirectory directory2;
 	private int current;
@@ -40,7 +40,7 @@
 	private Timer timer;
 
 	//variables needed between initialize and start
-	private String source;
+	private File sourceIndexDir;
 	private File indexDir;
 	private String directoryProviderName;
 	private Properties properties;
@@ -49,58 +49,33 @@
 		this.properties = properties;
 		this.directoryProviderName = directoryProviderName;
 		//source guessing
-		source = DirectoryProviderHelper.getSourceDirectory( "sourceBase", "source", directoryProviderName, properties );
-		if (source == null)
-			throw new IllegalStateException("FSSlaveDirectoryProvider requires a viable source directory");
-		if ( ! new File(source, "current1").exists() && ! new File(source, "current2").exists() ) {
-			throw new IllegalStateException("No current marker in source directory");
+		sourceIndexDir = DirectoryProviderHelper.getSourceDirectory( directoryProviderName, properties, false );
+		if ( ! new File( sourceIndexDir, "current1" ).exists() && ! new File( sourceIndexDir, "current2" ).exists() ) {
+			throw new IllegalStateException( "No current marker in source directory" );
 		}
-		log.debug( "Source directory: " + source );
-		indexDir = DirectoryProviderHelper.determineIndexDir( directoryProviderName, properties );
+		log.debug( "Source directory: " + sourceIndexDir.getPath() );
+		indexDir = DirectoryProviderHelper.getVerifiedIndexDir( directoryProviderName, properties, true );
 		log.debug( "Index directory: " + indexDir.getPath() );
 		try {
-			boolean create = !indexDir.exists();
-			if (create) {
-				log.debug( "index directory not found, creating: '" + indexDir.getAbsolutePath() + "'" );
-				indexDir.mkdirs();
-			}
 			indexName = indexDir.getCanonicalPath();
 		}
 		catch (IOException e) {
-			throw new HibernateException( "Unable to initialize index: " + directoryProviderName, e );
+			throw new SearchException( "Unable to initialize index: " + directoryProviderName, e );
 		}
 	}
 
 	public void start() {
-		//source guessing
-		String refreshPeriod = properties.getProperty( "refresh", "3600" );
-		long period = Long.parseLong( refreshPeriod );
-		log.debug("Refresh period " + period + " seconds");
-		period *= 1000; //per second
+		long period = DirectoryProviderHelper.getRefreshPeriod( properties, directoryProviderName );
 		try {
-			boolean create;
-
-			File subDir = new File( indexName, "1" );
-			create = ! subDir.exists();
-			directory1 = FSDirectory.getDirectory( subDir.getCanonicalPath());
-			if ( create ) {
-				log.debug( "Initialize index: '" + subDir.getAbsolutePath() + "'" );
-				IndexWriter iw = new IndexWriter( directory1, new StandardAnalyzer(), create );
-				iw.close();
-			}
-
-			subDir = new File( indexName, "2" );
-			create = ! subDir.exists();
-			directory2 = FSDirectory.getDirectory( subDir.getCanonicalPath());
-			if ( create ) {
-				log.debug( "Initialize index: '" + subDir.getAbsolutePath() + "'" );
-				IndexWriter iw = new IndexWriter( directory2, new StandardAnalyzer(), create );
-				iw.close();
-			}
-			File currentMarker = new File(indexName, "current1");
-			File current2Marker = new File(indexName, "current2");
+			directory1 = DirectoryProviderHelper.createFSIndex( new File(indexDir, "1") );
+			directory2 = DirectoryProviderHelper.createFSIndex( new File(indexDir, "2") );
+			File currentMarker = new File( indexDir, "current1" );
+			File current2Marker = new File( indexDir, "current2" );
 			if ( currentMarker.exists() ) {
 				current = 1;
+				if ( current2Marker.exists() ) {
+					current2Marker.delete(); //TODO or throw an exception?
+				}
 			}
 			else if ( current2Marker.exists() ) {
 				current = 2;
@@ -109,38 +84,38 @@
 				//no default
 				log.debug( "Setting directory 1 as current");
 				current = 1;
-				File sourceFile = new File(source);
-				File destinationFile = new File(indexName, Integer.valueOf(current).toString() );
+				File destinationFile = new File( indexDir, Integer.valueOf( current ).toString() );
 				int sourceCurrent;
-				if ( new File(sourceFile, "current1").exists() ) {
+				if ( new File( sourceIndexDir, "current1").exists() ) {
 					sourceCurrent = 1;
 				}
-				else if ( new File(sourceFile, "current2").exists() ) {
+				else if ( new File( sourceIndexDir, "current2").exists() ) {
 					sourceCurrent = 2;
 				}
 				else {
-					throw new AssertionFailure("No current file marker found in source directory: " + source);
+					throw new AssertionFailure( "No current file marker found in source directory: " + sourceIndexDir.getPath() );
 				}
 				try {
-					FileHelper.synchronize( new File(sourceFile, String.valueOf(sourceCurrent) ), destinationFile, true);
+					FileHelper.synchronize( new File( sourceIndexDir, String.valueOf(sourceCurrent) ), destinationFile, true);
 				}
 				catch (IOException e) {
-					throw new HibernateException("Umable to synchonize directory: " + indexName, e);
+					throw new SearchException( "Unable to synchronize directory: " + indexName, e );
 				}
 				if (! currentMarker.createNewFile() ) {
-					throw new HibernateException("Unable to create the directory marker file: " + indexName);
+					throw new SearchException( "Unable to create the directory marker file: " + indexName );
 				}
 			}
 			log.debug( "Current directory: " + current);
 		}
 		catch (IOException e) {
-			throw new HibernateException( "Unable to initialize index: " + directoryProviderName, e );
+			throw new SearchException( "Unable to initialize index: " + directoryProviderName, e );
 		}
 		timer = new Timer(true); //daemon thread, the copy algorithm is robust
-		TimerTask task = new TriggerTask(source, indexName);
+		TimerTask task = new TriggerTask( sourceIndexDir, indexDir );
 		timer.scheduleAtFixedRate( task, period, period );
 	}
 
+	//FIXME this is Thread-Unsafe! A memory barrier is missing.
 	public FSDirectory getDirectory() {
 		if (current == 1) {
 			return directory1;
@@ -149,7 +124,7 @@
 			return directory2;
 		}
 		else {
-			throw new AssertionFailure("Illegal current directory: " + current);
+			throw new AssertionFailure( "Illegal current directory: " + current );
 		}
 	}
 
@@ -174,12 +149,12 @@
 
 	class TriggerTask extends TimerTask {
 
-		private ExecutorService executor;
-		private CopyDirectory copyTask;
+		private final ExecutorService executor;
+		private final CopyDirectory copyTask;
 
-		public TriggerTask(String source, String destination) {
+		public TriggerTask(File sourceIndexDir, File destination) {
 			executor = Executors.newSingleThreadExecutor();
-			copyTask = new CopyDirectory( source, destination  );
+			copyTask = new CopyDirectory( sourceIndexDir, destination  );
 		}
 
 		public void run() {
@@ -193,12 +168,12 @@
 	}
 
 	class CopyDirectory implements Runnable {
-		private String source;
-		private String destination;
+		private final File source;
+		private final File destination;
 		private volatile boolean inProgress;
 
-		public CopyDirectory(String source, String destination) {
-			this.source = source;
+		public CopyDirectory(File sourceIndexDir, File destination) {
+			this.source = sourceIndexDir;
 			this.destination = destination;
 		}
 
@@ -216,16 +191,16 @@
 					sourceFile = new File(source, "2");
 				}
 				else {
-					log.error("Unable to determine current in source directory");
+					log.error( "Unable to determine current in source directory" );
 					inProgress = false;
 					return;
 				}
 
-				File destinationFile = new File(destination, Integer.valueOf(index).toString() );
+				File destinationFile = new File( destination, Integer.valueOf( index ).toString() );
 				//TODO make smart a parameter
 				try {
-					log.trace("Copying " + sourceFile + " into " + destinationFile);
-					FileHelper.synchronize( sourceFile, destinationFile, true);
+					log.trace( "Copying " + sourceFile + " into " + destinationFile );
+					FileHelper.synchronize( sourceFile, destinationFile, true );
 					current = index;
 				}
 				catch (IOException e) {
@@ -234,11 +209,11 @@
 					inProgress = false;
 					return;
 				}
-				if ( ! new File(indexName, "current" + oldIndex).delete() ) {
+				if ( ! new File( indexName, "current" + oldIndex ).delete() ) {
 					log.warn( "Unable to remove previous marker file in " + indexName );
 				}
 				try {
-					new File(indexName, "current" + index).createNewFile();
+					new File( indexName, "current" + index ).createNewFile();
 				}
 				catch( IOException e ) {
 					log.warn( "Unable to create current marker file in " + indexName, e );
@@ -247,7 +222,7 @@
 			finally {
 				inProgress = false;
 			}
-			log.trace( "Copy for " + indexName + " took " + (System.currentTimeMillis() - start) + " ms");
+			log.trace( "Copy for " + indexName + " took " + (System.currentTimeMillis() - start) + " ms" );
 		}
 	}
 

Deleted: search/trunk/src/java/org/hibernate/search/util/DirectoryProviderHelper.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/util/DirectoryProviderHelper.java	2008-04-29 23:46:43 UTC (rev 14611)
+++ search/trunk/src/java/org/hibernate/search/util/DirectoryProviderHelper.java	2008-04-30 00:27:12 UTC (rev 14612)
@@ -1,93 +0,0 @@
-//$Id$
-package org.hibernate.search.util;
-
-import java.util.Properties;
-import java.io.File;
-import java.io.IOException;
-import java.text.MessageFormat;
-
-import org.hibernate.HibernateException;
-import org.hibernate.AssertionFailure;
-import org.hibernate.search.SearchException;
-import org.hibernate.annotations.common.util.StringHelper;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * @author Emmanuel Bernard
- */
-public class DirectoryProviderHelper {
-	private static Log log = LogFactory.getLog( DirectoryProviderHelper.class );
-	/**
-	 * Build a directory name out of a root and relative path, guessing the significant part
-	 * and checking for the file availability
-	 * 
-	 */
-	public static String getSourceDirectory(String rootPropertyName, String relativePropertyName,
-											String directoryProviderName, Properties properties) {
-		//TODO check that it's a directory
-		String root = properties.getProperty( rootPropertyName );
-		String relative = properties.getProperty( relativePropertyName );
-		if ( log.isTraceEnabled() ) {
-			log.trace(
-					"Guess source directory from " + rootPropertyName + " " + root != null ? root : "<null>"
-							+ " and " + relativePropertyName + " " + relative != null ? relative : "<null>"
-			);
-		}
-		if (relative == null) relative = directoryProviderName;
-		if ( StringHelper.isEmpty( root ) ) {
-			log.debug( "No root directory, go with relative " + relative );
-			File sourceFile = new File(relative);
-			if ( ! sourceFile.exists() ) {
-				throw new SearchException("Unable to read source directory: " + relative);
-			}
-			//else keep source as it
-		}
-		else {
-			File rootDir = new File(root);
-			if ( ! rootDir.exists() ) {
-				rootDir.mkdirs();
-			}
-			else if ( ! rootDir.isDirectory() ) {
-				throw new SearchException(rootPropertyName + " is not a directory");
-			}
-			//test it again in case mkdir failed for wrong reasons
-			if ( rootDir.exists() ) {
-				File sourceFile = new File(root, relative);
-				if (! sourceFile.exists() ) sourceFile.mkdirs();
-				log.debug( "Get directory from root + relative");
-				try {
-					relative = sourceFile.getCanonicalPath();
-				}
-				catch (IOException e) {
-					throw new AssertionFailure("Unable to get canonical path: " + root + " + " + relative);
-				}
-			}
-			else {
-				throw new SearchException(rootPropertyName + " does not exist and cannot be created");
-			}
-		}
-		return relative;
-	}
-
-	public static File determineIndexDir(String directoryProviderName, Properties properties) {
-		String indexBase = properties.getProperty( "indexBase", "." );
-		String indexName = properties.getProperty( "indexName", directoryProviderName );
-		File indexDir = new File( indexBase );
-		if ( ! indexDir.exists() ) {
-			//if the base directory does not exist, create it
-			//we do not fear concurrent creation since mkdir does not raise exceptions
-			indexDir.mkdirs();
-		}
-		else if ( ! indexDir.isDirectory() ) {
-			throw new SearchException( MessageFormat.format( "Index directory is not a directory: {0}", indexBase ) );
-		}
-		if ( !indexDir.canWrite() ) {
-			throw new SearchException( "Cannot write into index directory: "
-					+ ( indexDir.isAbsolute() ? indexBase : indexDir.getAbsolutePath() ) );
-		}
-
-		indexDir = new File( indexDir, indexName );
-		return indexDir;
-	}
-}

Modified: search/trunk/src/test/org/hibernate/search/test/FSDirectoryTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/FSDirectoryTest.java	2008-04-29 23:46:43 UTC (rev 14611)
+++ search/trunk/src/test/org/hibernate/search/test/FSDirectoryTest.java	2008-04-30 00:27:12 UTC (rev 14612)
@@ -14,28 +14,29 @@
 import org.apache.lucene.search.Hits;
 import org.apache.lucene.search.IndexSearcher;
 import org.apache.lucene.search.Query;
+import org.apache.lucene.search.TermQuery;
 import org.hibernate.Session;
 import org.hibernate.event.PostDeleteEventListener;
 import org.hibernate.event.PostInsertEventListener;
 import org.hibernate.event.PostUpdateEventListener;
 import org.hibernate.search.Environment;
 import org.hibernate.search.event.FullTextIndexEventListener;
+import org.hibernate.search.store.DirectoryProviderHelper;
 import org.hibernate.search.store.FSDirectoryProvider;
-import org.hibernate.search.util.DirectoryProviderHelper;
+import org.hibernate.search.util.FileHelper;
 
 /**
  * @author Gavin King
  */
 public class FSDirectoryTest extends SearchTestCase {
 
-
 	protected void setUp() throws Exception {
 		File sub = getBaseIndexDir();
 		sub.mkdir();
 		File[] files = sub.listFiles();
 		for (File file : files) {
 			if ( file.isDirectory() ) {
-				delete( file );
+				FileHelper.delete( file );
 			}
 		}
 		//super.setUp(); //we need a fresh session factory each time for index set up
@@ -51,44 +52,22 @@
 	protected void tearDown() throws Exception {
 		super.tearDown();
 		File sub = getBaseIndexDir();
-		delete( sub );
+		FileHelper.delete( sub );
 	}
 
-	private void delete(File sub) {
-		if ( sub.isDirectory() ) {
-			for (File file : sub.listFiles()) {
-				delete( file );
-			}
-			sub.delete();
-		}
-		else {
-			sub.delete();
-		}
-	}
-
-	private void recursiveDelete(File f) {
-		for (File file : f.listFiles()) {
-			if ( file.isDirectory() ) {
-				recursiveDelete( file );
-			}
-		}
-		f.delete();
-	}
-
 	public void testDirectoryProviderHelperMkdirsGetSource() throws Exception {
 		String root = "./testDir";
 		String relative = "dir1/dir2/dir3";
 
 		Properties properties = new Properties();
-		properties.put( "root", root );
-		properties.put( "relative", relative );
+		properties.put( "sourceBase", root );
+		properties.put( "source", relative );
 
-		String rel = DirectoryProviderHelper.getSourceDirectory( "root", "relative", "name", properties );
+		File rel = DirectoryProviderHelper.getSourceDirectory( "name", properties, true );
 
-		File f = new File( rel );
-		assertTrue( f.exists() );
+		assertTrue( rel.exists() );
 
-		recursiveDelete( new File( root ) );
+		FileHelper.delete( new File( root ) );
 	}
 
 	public void testDirectoryProviderHelperMkdirsDetermineIndex() throws Exception {
@@ -99,16 +78,15 @@
 		properties.put( "indexBase", root );
 		properties.put( "indexName", relative );
 
-		File f = DirectoryProviderHelper.determineIndexDir( "name", properties );
+		File f = DirectoryProviderHelper.getVerifiedIndexDir( "name", properties, true );
 
 		assertTrue( new File( root ).exists() );
 
-		recursiveDelete( new File( "./testDir" ) );
+		FileHelper.delete( new File( "./testDir" ) );
 	}
 
 	public void testEventIntegration() throws Exception {
 
-
 		Session s = getSessions().openSession();
 		s.getTransaction().begin();
 		s.persist(
@@ -205,7 +183,6 @@
 			searcher.close();
 		}
 
-
 		s = getSessions().openSession();
 		s.getTransaction().begin();
 		List list = s.createQuery( "from Document" ).list();
@@ -216,6 +193,24 @@
 		s.close();
 	}
 
+	public void testSearchOnDeletedIndex() throws Exception {
+		Session s = getSessions().openSession();
+		s.getTransaction().begin();
+		s.persist( new Document( "Hibernate Search in Action", "", "") );
+		s.getTransaction().commit();
+		s.close();
+		
+		IndexSearcher searcher = new IndexSearcher( new File( getBaseIndexDir(), "Documents" ).getCanonicalPath() );
+		// deleting before search, but after IndexSearcher creation:
+		// ( fails when deleting -concurrently- to IndexSearcher initialization! )
+		FileHelper.delete(getBaseIndexDir());
+		TermQuery query = new TermQuery( new Term("title","action") );
+		Hits hits = searcher.search( query );
+		assertEquals( 1, hits.length() );
+		assertEquals( "Hibernate Search in Action", hits.doc( 0 ).get( "title" ) );
+		searcher.close();
+	}
+
 	protected Class[] getMappings() {
 		return new Class[] {
 				Document.class




More information about the hibernate-commits mailing list