Author: epbernard Date: 2006-07-01 11:11:45 -0400 (Sat, 01 Jul 2006) New Revision: 10076 Added: trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/ trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProvider.java trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProviderFactory.java trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/FSDirectoryProvider.java trunk/HibernateExt/metadata/src/test/org/hibernate/lucene/test/ Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/DocumentBuilder.java trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/event/LuceneEventListener.java Log: ANN-385 abstract lucene directory. Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/DocumentBuilder.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/DocumentBuilder.java 2006-07-01 12:50:34 UTC (rev 10075) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/DocumentBuilder.java 2006-07-01 15:11:45 UTC (rev 10076) @@ -4,10 +4,10 @@ import java.beans.Introspector; import java.io.Serializable; import java.lang.reflect.AccessibleObject; +import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.lang.reflect.AnnotatedElement; import java.util.ArrayList; import java.util.List; @@ -15,10 +15,10 @@ import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.Term; -import org.apache.lucene.store.Directory; import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; import org.hibernate.cfg.annotations.Version; +import org.hibernate.lucene.store.DirectoryProvider; //TODO handle attribute (only getters are handled currently) public class DocumentBuilder<T> { @@ -35,15 +35,15 @@ private final List<String> textNames = new ArrayList<String>(); //private final Class<T> beanClass; - private final Directory directory; + private final DirectoryProvider directoryProvider; private String idKeywordName; private final Analyzer analyzer; private Float idBoost; - public DocumentBuilder(Class<?> clazz, Analyzer analyzer, Directory directory) { + public DocumentBuilder(Class<?> clazz, Analyzer analyzer, DirectoryProvider directory) { //this.beanClass = clazz; this.analyzer = analyzer; - this.directory = directory; + this.directoryProvider = directory; for ( Class currClass = clazz; currClass != null ; currClass = currClass.getSuperclass() ) { Method[] methods = currClass.getDeclaredMethods(); @@ -174,8 +174,8 @@ return Introspector.decapitalize( methodName.substring( startIndex ) ); } - public Directory getDirectory() { - return directory; + public DirectoryProvider getDirectoryProvider() { + return directoryProvider; } public Analyzer getAnalyzer() { Modified: trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/event/LuceneEventListener.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/event/LuceneEventListener.java 2006-07-01 12:50:34 UTC (rev 10075) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/event/LuceneEventListener.java 2006-07-01 15:11:45 UTC (rev 10076) @@ -1,7 +1,6 @@ //$Id$ package org.hibernate.lucene.event; -import java.io.File; import java.io.IOException; import java.io.Serializable; import java.util.HashMap; @@ -18,8 +17,6 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.Term; -import org.apache.lucene.store.Directory; -import org.apache.lucene.store.FSDirectory; import org.hibernate.HibernateException; import org.hibernate.cfg.Configuration; import org.hibernate.event.Initializable; @@ -32,6 +29,8 @@ import org.hibernate.lucene.DocumentBuilder; import org.hibernate.lucene.Environment; import org.hibernate.lucene.Indexed; +import org.hibernate.lucene.store.DirectoryProvider; +import org.hibernate.lucene.store.DirectoryProviderFactory; import org.hibernate.mapping.PersistentClass; /** @@ -48,7 +47,7 @@ private Map<Class, DocumentBuilder<Object>> documentBuilders = new HashMap<Class, DocumentBuilder<Object>>(); //** keep track of the index modifiers per file since 1 index modifier can be present at a time */ - private Map<Directory, Lock> indexLock = new HashMap<Directory, Lock>(); + private Map<DirectoryProvider, Lock> indexLock = new HashMap<DirectoryProvider, Lock>(); private boolean initialized; private static final Log log = LogFactory.getLog( LuceneEventListener.class ); @@ -81,63 +80,27 @@ throw new HibernateException( "Failed to instantiate lucene analyzer with type " + analyzerClassName ); } - // Initialize index parent dir - String indexDirName = cfg.getProperty( Environment.INDEX_BASE_DIR ); - File indexDir = indexDirName != null ? new File( indexDirName ) : new File( "." ); - - if ( !( indexDir.exists() && indexDir.isDirectory() ) ) { - //TODO create the directory - throw new HibernateException( "Index directory does not exists: " + Environment.INDEX_BASE_DIR ); - } - if ( !indexDir.canWrite() ) { - throw new HibernateException( "Cannot write into index directory: " + Environment.INDEX_BASE_DIR ); - } - log.info( "Setting index dir to " + indexDir ); - Iterator iter = cfg.getClassMappings(); + DirectoryProviderFactory factory = new DirectoryProviderFactory(); while ( iter.hasNext() ) { PersistentClass clazz = (PersistentClass) iter.next(); Class<?> mappedClass = clazz.getMappedClass(); if ( mappedClass != null ) { if ( mappedClass.isAnnotationPresent( Indexed.class ) ) { - Indexed indexed = mappedClass.getAnnotation( Indexed.class ); - String fileName = getTypeName( mappedClass, indexed.index() ); - File file = new File( indexDir, fileName ); - Directory directory; - try { - boolean create = !file.exists(); - directory = FSDirectory.getDirectory( file.getCanonicalPath(), create ); - if (create) { - IndexWriter iw = new IndexWriter(directory, new StandardAnalyzer(), create ); - iw.close(); - } + DirectoryProvider provider = factory.createDirectoryProvider( mappedClass, cfg ); + final DocumentBuilder<Object> documentBuilder = new DocumentBuilder<Object>( + mappedClass, analyzer, provider + ); + if ( ! indexLock.containsKey( provider ) ) { + indexLock.put( provider, new ReentrantLock() ); } - catch (IOException ie) { - throw new HibernateException("Unable to initialize index: " + indexed.index(), ie ); - } - final DocumentBuilder<Object> documentBuilder = new DocumentBuilder<Object>( mappedClass, analyzer, directory ); - if ( ! indexLock.containsKey( directory ) ) { - indexLock.put( directory, new ReentrantLock() ); - } documentBuilders.put( mappedClass, documentBuilder ); -// try { -// IndexWriter iw = new IndexWriter( documentBuilder.getFile(), new StopAnalyzer(), true ); -// iw.close(); -// } -// catch (IOException ioe) { -// throw new HibernateException(ioe); -// } - log.info( "index file: " + file.getAbsolutePath() ); } } } initialized = true; } - private static String getTypeName(Class clazz, String name) { - return "".equals( name ) ? clazz.getName() : name; - } - public void onPostDelete(PostDeleteEvent event) { DocumentBuilder builder = documentBuilders.get( event.getEntity().getClass() ); if ( builder != null ) { @@ -166,12 +129,12 @@ private void remove(DocumentBuilder<?> builder, Serializable id) { Term term = builder.getTerm( id ); log.debug( "removing: " + term ); - Directory directory = builder.getDirectory(); - Lock lock = indexLock.get( directory ); + DirectoryProvider directoryProvider = builder.getDirectoryProvider(); + Lock lock = indexLock.get( directoryProvider ); lock.lock(); try { - IndexReader reader = IndexReader.open( directory ); + IndexReader reader = IndexReader.open( directoryProvider.getDirectory() ); reader.deleteDocuments( term ); reader.close(); } @@ -185,14 +148,16 @@ private void add(final Object entity, final DocumentBuilder<Object> builder, final Serializable id) { Document doc = builder.getDocument( entity, id ); - if( log.isDebugEnabled() ) { + if ( log.isDebugEnabled() ) { log.debug( "adding: " + doc ); } - Directory directory = builder.getDirectory(); - Lock lock = indexLock.get( directory ); + DirectoryProvider directoryProvider = builder.getDirectoryProvider(); + Lock lock = indexLock.get( directoryProvider ); lock.lock(); try { - IndexWriter writer = new IndexWriter( directory, builder.getAnalyzer(), false); //have been created at init time + IndexWriter writer = new IndexWriter( + directoryProvider.getDirectory(), builder.getAnalyzer(), false + ); //have been created at init time writer.addDocument( doc ); writer.close(); } Added: trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProvider.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProvider.java 2006-07-01 12:50:34 UTC (rev 10075) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProvider.java 2006-07-01 15:11:45 UTC (rev 10076) @@ -0,0 +1,23 @@ +//$Id: $ +package org.hibernate.lucene.store; + +import java.util.Properties; + +import org.hibernate.cfg.Configuration; +import org.apache.lucene.store.Directory; + + +/** + * Set up and provide a Lucene <code>Directory</code> + * <code>equals()</code> and <code>hashCode()</code> must guaranty to + * return true for a provider pointing to the same underlying Lucene Store + * This class must be thread safe regarding <code>getDirectory()</code> + * @author Emmanuel Bernard + */ +public interface DirectoryProvider<TDirectory extends Directory> { + /** get the information toi initialize the directory and build its hashCode */ + void initialize(Class<?> entity, Configuration cfg, Properties properties); + + TDirectory getDirectory(); +} + Added: trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProviderFactory.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProviderFactory.java 2006-07-01 12:50:34 UTC (rev 10075) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/DirectoryProviderFactory.java 2006-07-01 15:11:45 UTC (rev 10076) @@ -0,0 +1,86 @@ +//$Id: $ +package org.hibernate.lucene.store; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.hibernate.HibernateException; +import org.hibernate.cfg.Configuration; +import org.hibernate.lucene.Indexed; +import org.hibernate.util.ReflectHelper; +import org.hibernate.util.StringHelper; + +/** + * Create a Lucene directory provider + * <p/> + * Lucene directory providers are configured through... + * hibernate.lucene.default.impl=FSDirectory + * hibernate.lucene.toto.impl=FSDirectory + * hibernate.lucene.toto.*= + * + * @author Emmanuel Bernard + */ +public class DirectoryProviderFactory { + public List<DirectoryProvider> providers = new ArrayList<DirectoryProvider>(); + private static String LUCENE_PREFIX = "hibernate.lucene."; + private static String LUCENE_DEFAULT = LUCENE_PREFIX + "default."; + private static String DEFAULT_DIRECTORY_PROVIDER = FSDirectoryProvider.class.getName(); + + + + public DirectoryProvider createDirectoryProvider(Class<?> entity, Configuration cfg) { + //get properties + Properties indexProps = getDirectoryProperties( cfg, entity ); + + //set up the directory + String className = indexProps.getProperty( "impl" ); + if ( StringHelper.isEmpty( className ) ) { + className = DEFAULT_DIRECTORY_PROVIDER; + } + DirectoryProvider provider = null; + try { + Class<DirectoryProvider> directoryClass = ReflectHelper.classForName( + className, DirectoryProviderFactory.class + ); + provider = directoryClass.newInstance(); + } + catch (Exception e) { + throw new HibernateException( "Unable to instanciate directory provider: " + className ); + } + provider.initialize( entity, cfg, indexProps ); + int index = providers.indexOf( provider ); + if ( index != -1 ) { + //share the same Directory provider for the same underlying store + return providers.get( index ); + } + else { + providers.add( provider ); + return provider; + } + } + + private static Properties getDirectoryProperties(Configuration cfg, Class<?> entity) { + Properties props = cfg.getProperties(); + String indexName = LUCENE_PREFIX + getTypeName( entity ); + Properties indexProps = new Properties(); + Properties indexSpecificProps = new Properties(); + for ( Map.Entry<String, ?> entry : ( (Map<String, ?>) props ).entrySet() ) { + String key = entry.getKey(); + if ( key.startsWith( LUCENE_DEFAULT ) ) { + indexProps.setProperty( key.substring( LUCENE_DEFAULT.length() ), (String) entry.getValue() ); + } + else if ( key.startsWith( indexName ) ) { + indexSpecificProps.setProperty( key.substring( indexName.length() ), (String) entry.getValue() ); + } + } + indexProps.putAll( indexSpecificProps ); + return indexProps; + } + + public static String getTypeName(Class<?> clazz) { + String name = clazz.getAnnotation(Indexed.class).index(); + return "".equals( name ) ? clazz.getName() : name; + } +} Added: trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/FSDirectoryProvider.java =================================================================== --- trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/FSDirectoryProvider.java 2006-07-01 12:50:34 UTC (rev 10075) +++ trunk/HibernateExt/metadata/src/java/org/hibernate/lucene/store/FSDirectoryProvider.java 2006-07-01 15:11:45 UTC (rev 10076) @@ -0,0 +1,61 @@ +//$Id: $ +package org.hibernate.lucene.store; + +import java.io.File; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.lucene.store.Directory; +import org.apache.lucene.store.FSDirectory; +import org.apache.lucene.index.IndexWriter; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.hibernate.HibernateException; +import org.hibernate.cfg.Configuration; + +/** + * Use a Lucene FSDirectory + * The base directory is represented by hibernate.lucene.<index>.indexBase + * The index is created in <base directory>/<index name> + * @author Emmanuel Bernard + */ +public class FSDirectoryProvider implements DirectoryProvider { + private FSDirectory directory; + private static Log log = LogFactory.getLog( FSDirectoryProvider.class ); + + public void initialize(Class entity, Configuration cfg, Properties properties) { + String indexBase = properties.getProperty( "indexBase", "." ); + File indexDir = new File( indexBase ); + + if ( !( indexDir.exists() && indexDir.isDirectory() ) ) { + //TODO create the directory? + throw new HibernateException( MessageFormat.format( "Index directory does not exists: {0}", indexBase ) ); + } + if ( !indexDir.canWrite() ) { + throw new HibernateException( "Cannot write into index directory: " + indexBase ); + } + log.info( "Setting index dir to " + indexDir ); + + String fileName = DirectoryProviderFactory.getTypeName( entity ); + File file = new File( indexDir, fileName ); + + try { + boolean create = !file.exists(); + directory = FSDirectory.getDirectory( file.getCanonicalPath(), create ); + if (create) { + IndexWriter iw = new IndexWriter(directory, new StandardAnalyzer(), create ); + iw.close(); + } + } + catch (IOException e) { + throw new HibernateException( "Unable to initialize index: " + fileName, e ); + } + + } + + public Directory getDirectory() { + return directory; + } +} |