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

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Oct 22 22:15:50 EDT 2008


Author: epbernard
Date: 2008-10-22 22:15:50 -0400 (Wed, 22 Oct 2008)
New Revision: 15376

Added:
   search/trunk/src/java/org/hibernate/search/engine/EntityState.java
   search/trunk/src/test/org/hibernate/search/test/embedded/NonIndexedEntity.java
Modified:
   search/trunk/src/java/org/hibernate/search/backend/WorkType.java
   search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
   search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java
   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/FullTextSessionImpl.java
   search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
   search/trunk/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java
   search/trunk/src/test/org/hibernate/search/test/embedded/State.java
Log:
HSEARCH-142 Entity not marked as @Indexed but using @ContainedIn are now properly indexed on update

Modified: search/trunk/src/java/org/hibernate/search/backend/WorkType.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/WorkType.java	2008-10-23 00:04:14 UTC (rev 15375)
+++ search/trunk/src/java/org/hibernate/search/backend/WorkType.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -10,23 +10,38 @@
  * @author John Griffin
  */
 public enum WorkType {
-	ADD,
-	UPDATE,
-	DELETE,
-	COLLECTION,
+	ADD(true),
+	UPDATE(true),
+	DELETE(false),
+	COLLECTION(true),
 	/**
 	 * Used to remove a specific instance
 	 * of a class from an index.
 	 */
-	PURGE,
+	PURGE(false),
 	/**
 	 * Used to remove all instances of a
 	 * class from an index.
 	 */
-	PURGE_ALL,
+	PURGE_ALL(false),
 	
 	/**
 	 * This type is used for batch indexing.
 	 */
-	INDEX 
+	INDEX(true);
+
+	private final boolean searchForContainers;
+
+	private WorkType(boolean searchForContainers) {
+		this.searchForContainers = searchForContainers;
+	}
+
+	/**
+	 * When references are changed, either null or another one, we expect dirty checking to be triggered (both sides
+	 * have to be updated)
+	 * When the internal object is changed, we apply the {Add|Update}Work on containedIns
+	 */
+	public boolean searchForContainers() {
+		return this.searchForContainers;
+	}
 }

Modified: search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java	2008-10-23 00:04:14 UTC (rev 15375)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -146,6 +146,10 @@
 					work.getEntityClass() :
 					Hibernate.getClass( work.getEntity() );
 		DocumentBuilder<T> builder = searchFactoryImplementor.getDocumentBuilder( entityClass );
+		if ( builder == null ) {
+			//might be a entity contained in
+			builder = searchFactoryImplementor.getContainedInOnlyBuilder( entityClass );
+		}
 		if ( builder == null ) return;
 		//TODO remove casting when Work is Work<T>
 		builder.addWorkToQueue(entityClass, (T) work.getEntity(), work.getId(), work.getType(), luceneQueue, searchFactoryImplementor );

Modified: search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java	2008-10-23 00:04:14 UTC (rev 15375)
+++ search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -67,7 +67,6 @@
  * @author Richard Hallier
  * @author Hardy Ferentschik
  */
- at SuppressWarnings( "unchecked" )
 public class DocumentBuilder<T> {
 	private static final Logger log = LoggerFactory.make();
 
@@ -90,14 +89,19 @@
 	//if composite id, use of (a, b) in ((1,2), (3,4)) fails on most database
 	private boolean safeFromTupleId;
 	private boolean idProvided = false;
+	private EntityState entityState;
 
 
 	public boolean isRoot() {
 		return isRoot;
 	}
 
+	/**
+	 * used on an @Indexed entity
+	 */
 	public DocumentBuilder(XClass clazz, InitContext context, DirectoryProvider[] directoryProviders,
 						   IndexShardingStrategy shardingStrategy, ReflectionManager reflectionManager) {
+		this.entityState = EntityState.INDEXED;
 		this.beanClass = clazz;
 		this.directoryProviders = directoryProviders;
 		this.shardingStrategy = shardingStrategy;
@@ -105,6 +109,10 @@
 		this.reflectionManager = reflectionManager;
 		this.similarity = context.getDefaultSimilarity();
 
+		init( clazz, context, reflectionManager );
+	}
+
+	private void init(XClass clazz, InitContext context, ReflectionManager reflectionManager) {
 		if ( clazz == null ) throw new AssertionFailure( "Unable to build a DocumentBuilder with a null class" );
 		rootPropertiesMetadata.boost = getBoost( clazz );
 		rootPropertiesMetadata.analyzer = context.getDefaultAnalyzer();
@@ -113,7 +121,7 @@
 		initializeMembers( clazz, rootPropertiesMetadata, true, "", processedClasses, context );
 		//processedClasses.remove( clazz ); for the sake of completness
 		this.analyzer.setGlobalAnalyzer( rootPropertiesMetadata.analyzer );
-		if ( idKeywordName == null ) {
+		if ( entityState == EntityState.INDEXED && idKeywordName == null ) {
 			// if no DocumentId then check if we have a ProvidedId instead
 			ProvidedId provided = findProvidedId( clazz, reflectionManager );
 			if ( provided == null ) throw new SearchException( "No document id in: " + clazz.getName() );
@@ -123,9 +131,28 @@
 		}
 		//if composite id, use of (a, b) in ((1,2)TwoWayString2FieldBridgeAdaptor, (3,4)) fails on most database
 		//a TwoWayString2FieldBridgeAdaptor is never a composite id
-		safeFromTupleId = TwoWayString2FieldBridgeAdaptor.class.isAssignableFrom( idBridge.getClass() );
+		safeFromTupleId = entityState != EntityState.INDEXED || TwoWayString2FieldBridgeAdaptor.class.isAssignableFrom( idBridge.getClass() );
 	}
 
+	/**
+	 * used on a non @Indexed entity
+	 */
+	public DocumentBuilder(XClass clazz, InitContext context, ReflectionManager reflectionManager) {
+		this.entityState = EntityState.CONTAINED_IN_ONLY;
+		this.beanClass = clazz;
+		this.directoryProviders = null;
+		this.shardingStrategy = null;
+
+		//FIXME get rid of it when boost is stored?
+		this.reflectionManager = reflectionManager;
+		this.similarity = context.getDefaultSimilarity();
+
+		init( clazz, context, reflectionManager );
+		if (rootPropertiesMetadata.containedInGetters.size() == 0) {
+			this.entityState = EntityState.NON_INDEXABLE;
+		}
+	}
+
 	private ProvidedId findProvidedId(XClass clazz, ReflectionManager reflectionManager) {
 		ProvidedId id = null;
 		XClass currentClass = clazz;
@@ -502,83 +529,81 @@
 	}
 
 	//TODO could we use T instead of EntityClass?
-	public void addWorkToQueue(Class entityClass, T entity, Serializable id, WorkType workType, List<LuceneWork> queue, SearchFactoryImplementor searchFactoryImplementor) {
+	public void addWorkToQueue(Class<T> entityClass, T entity, Serializable id, WorkType workType, List<LuceneWork> queue, SearchFactoryImplementor searchFactoryImplementor) {
 		//TODO with the caller loop we are in a n^2: optimize it using a HashMap for work recognition
-		List<LuceneWork> toDelete = new ArrayList<LuceneWork>();
-		boolean duplicateDelete = false;
-		for (LuceneWork luceneWork : queue) {
-   			//avoid unecessary duplicated work
-			if ( luceneWork.getEntityClass() == entityClass
-					) {
-				Serializable currentId = luceneWork.getId();
-				//currentId != null => either ADD or Delete work
-				if ( currentId != null && currentId.equals( id ) ) { //find a way to use Type.equals(x,y)
-					if (workType == WorkType.DELETE) { //TODO add PURGE?
-						//DELETE should have precedence over any update before (HSEARCH-257)
-						//if an Add work is here, remove it
-						//if an other delete is here remember but still search for Add
-						if (luceneWork instanceof AddLuceneWork) {
-							toDelete.add( luceneWork );
+		if ( entityState == EntityState.INDEXED ) {
+			List<LuceneWork> toDelete = new ArrayList<LuceneWork>();
+			boolean duplicateDelete = false;
+			for (LuceneWork luceneWork : queue) {
+				//avoid unecessary duplicated work
+				if ( luceneWork.getEntityClass() == entityClass
+						) {
+					Serializable currentId = luceneWork.getId();
+					//currentId != null => either ADD or Delete work
+					if ( currentId != null && currentId.equals( id ) ) { //find a way to use Type.equals(x,y)
+						if (workType == WorkType.DELETE) { //TODO add PURGE?
+							//DELETE should have precedence over any update before (HSEARCH-257)
+							//if an Add work is here, remove it
+							//if an other delete is here remember but still search for Add
+							if (luceneWork instanceof AddLuceneWork) {
+								toDelete.add( luceneWork );
+							}
+							else if (luceneWork instanceof DeleteLuceneWork) {
+								duplicateDelete = true;
+							}
 						}
-						else if (luceneWork instanceof DeleteLuceneWork) {
-							duplicateDelete = true;
+						else {
+							//we can safely say we are out, the other work is an ADD
+							return;
 						}
 					}
-					else {
-						//we can safely say we are out, the other work is an ADD
-						return;
-					}
+					//TODO do something to avoid multiple PURGE ALL and OPTIMIZE
 				}
-				//TODO do something to avoid multiple PURGE ALL and OPTIMIZE
 			}
-		}
-		for ( LuceneWork luceneWork : toDelete ) {
-			toDelete.remove( luceneWork );
-		}
-		if (duplicateDelete) return;
+			for ( LuceneWork luceneWork : toDelete ) {
+				toDelete.remove( luceneWork );
+			}
+			if (duplicateDelete) return;
 
-		boolean searchForContainers = false;
-		String idInString = idBridge.objectToString( id );
-		if ( workType == WorkType.ADD ) {
-			Document doc = getDocument( entity, id );
-			queue.add( new AddLuceneWork( id, idInString, entityClass, doc ) );
-			searchForContainers = true;
+			String idInString = idBridge.objectToString( id );
+			if ( workType == WorkType.ADD ) {
+				Document doc = getDocument( entity, id );
+				queue.add( new AddLuceneWork( id, idInString, entityClass, doc ) );
+			}
+			else if ( workType == WorkType.DELETE || workType == WorkType.PURGE ) {
+				queue.add( new DeleteLuceneWork( id, idInString, entityClass ) );
+			}
+			else if ( workType == WorkType.PURGE_ALL ) {
+				queue.add( new PurgeAllLuceneWork( entityClass ) );
+			}
+			else if ( workType == WorkType.UPDATE || workType == WorkType.COLLECTION ) {
+				Document doc = getDocument( entity, id );
+				/**
+				 * even with Lucene 2.1, use of indexWriter to update is not an option
+				 * We can only delete by term, and the index doesn't have a term that
+				 * uniquely identify the entry.
+				 * But essentially the optimization we are doing is the same Lucene is doing, the only extra cost is the
+				 * double file opening.
+				 */
+				queue.add( new DeleteLuceneWork( id, idInString, entityClass ) );
+				queue.add( new AddLuceneWork( id, idInString, entityClass, doc ) );
+			}
+			else if ( workType == WorkType.INDEX ) {
+				Document doc = getDocument( entity, id );
+				queue.add( new DeleteLuceneWork( id, idInString, entityClass ) );
+				queue.add( new AddLuceneWork( id, idInString, entityClass, doc, true ) );
+			}
+			else {
+				throw new AssertionFailure( "Unknown WorkType: " + workType );
+			}
 		}
-		else if ( workType == WorkType.DELETE || workType == WorkType.PURGE ) {
-			queue.add( new DeleteLuceneWork( id, idInString, entityClass ) );
-		}
-		else if ( workType == WorkType.PURGE_ALL ) {
-			queue.add( new PurgeAllLuceneWork( entityClass ) );
-		}
-		else if ( workType == WorkType.UPDATE || workType == WorkType.COLLECTION ) {
-			Document doc = getDocument( entity, id );
-			/**
-			 * even with Lucene 2.1, use of indexWriter to update is not an option
-			 * We can only delete by term, and the index doesn't have a term that
-			 * uniquely identify the entry.
-			 * But essentially the optimization we are doing is the same Lucene is doing, the only extra cost is the
-			 * double file opening.
-			 */
-			queue.add( new DeleteLuceneWork( id, idInString, entityClass ) );
-			queue.add( new AddLuceneWork( id, idInString, entityClass, doc ) );
-			searchForContainers = true;
-		}
-		else if ( workType == WorkType.INDEX ) {
-			Document doc = getDocument( entity, id );
-			queue.add( new DeleteLuceneWork( id, idInString, entityClass ) );
-			queue.add( new AddLuceneWork( id, idInString, entityClass, doc, true ) );
-			searchForContainers = true;
-		}
-		else {
-			throw new AssertionFailure( "Unknown WorkType: " + workType );
-		}
 
 		/**
 		 * When references are changed, either null or another one, we expect dirty checking to be triggered (both sides
 		 * have to be updated)
 		 * When the internal object is changed, we apply the {Add|Update}Work on containedIns
 		 */
-		if ( searchForContainers ) {
+		if ( workType.searchForContainers() ) {
 			processContainedIn( entity, queue, rootPropertiesMetadata, searchFactoryImplementor );
 		}
 	}
@@ -626,7 +651,7 @@
 		//do not walk through them
 	}
 
-	private void processContainedInValue(Object value, List<LuceneWork> queue, Class valueClass,
+	private void processContainedInValue(Object value, List<LuceneWork> queue, Class<?> valueClass,
 										 DocumentBuilder builder, SearchFactoryImplementor searchFactoryImplementor) {
 		Serializable id = (Serializable) builder.getMemberValue( value, builder.idGetter );
 		builder.addWorkToQueue( valueClass, value, id, WorkType.UPDATE, queue, searchFactoryImplementor );
@@ -634,7 +659,8 @@
 
 	public Document getDocument(T instance, Serializable id) {
 		Document doc = new Document();
-		XClass instanceClass = reflectionManager.toXClass( Hibernate.getClass( instance ) );
+		final Class<?> entityType = Hibernate.getClass( instance );
+		XClass instanceClass = reflectionManager.toXClass( entityType );
 		if ( rootPropertiesMetadata.boost != null ) {
 			doc.setBoost( rootPropertiesMetadata.boost );
 		}
@@ -718,10 +744,16 @@
 	}
 
 	public DirectoryProvider[] getDirectoryProviders() {
+		if( entityState != EntityState.INDEXED ) {
+			throw new AssertionFailure("Contained in only entity: getDirectoryProvider should not have been called.");
+		}
 		return directoryProviders;
 	}
 
 	public IndexShardingStrategy getDirectoryProviderSelectionStrategy() {
+		if( entityState != EntityState.INDEXED ) {
+			throw new AssertionFailure("Contained in only entity: getDirectoryProviderSelectionStrategy should not have been called.");
+		}
 		return shardingStrategy;
 	}
 
@@ -825,6 +857,7 @@
 	}
 
 	public void postInitialize(Set<Class<?>> indexedClasses) {
+		if (entityState == EntityState.NON_INDEXABLE) throw new AssertionFailure("A non indexed entity is post processed");
 		//this method does not requires synchronization
 		Class plainClass = reflectionManager.toClass( beanClass );
 		Set<Class<?>> tempMappedSubclasses = new HashSet<Class<?>>();
@@ -844,6 +877,9 @@
 		}
 	}
 
+	public EntityState getEntityState() {
+		return entityState;
+	}
 
 	public Set<Class<?>> getMappedSubclasses() {
 		return mappedSubclasses;

Added: search/trunk/src/java/org/hibernate/search/engine/EntityState.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/EntityState.java	                        (rev 0)
+++ search/trunk/src/java/org/hibernate/search/engine/EntityState.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -0,0 +1,12 @@
+package org.hibernate.search.engine;
+
+/**
+ * Entity state with regard to indexing possibilities
+ *
+ * @author Emmanuel Bernard
+ */
+public enum EntityState {
+	INDEXED,
+	CONTAINED_IN_ONLY,
+	NON_INDEXABLE
+}

Modified: search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java	2008-10-23 00:04:14 UTC (rev 15375)
+++ search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -19,7 +19,6 @@
  * @author Emmanuel Bernard
  * @author Hardy Ferentschik
  */
- at SuppressWarnings("unchecked")
 public interface SearchFactoryImplementor extends SearchFactory {
 	BackendQueueProcessorFactory getBackendQueueProcessorFactory();
 
@@ -29,6 +28,8 @@
 
 	<T> DocumentBuilder<T> getDocumentBuilder(Class<T> entityType);
 
+	<T> DocumentBuilder<T> getContainedInOnlyBuilder(Class<T> entityType);
+
 	Worker getWorker();
 
 	void addOptimizerStrategy(DirectoryProvider<?> provider, OptimizerStrategy optimizerStrategy);

Modified: search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java	2008-10-23 00:04:14 UTC (rev 15375)
+++ search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -72,17 +72,20 @@
 	}
 
 	public void onPostDelete(PostDeleteEvent event) {
-		if ( used && searchFactoryImplementor.getDocumentBuilders().containsKey( event.getEntity().getClass() ) ) {
-			processWork( event.getEntity(), event.getId(), WorkType.DELETE, event );
+		if ( used ) {
+			final Class<?> entityType = event.getEntity().getClass();
+			if ( searchFactoryImplementor.getDocumentBuilders().containsKey( entityType )
+					|| searchFactoryImplementor.getContainedInOnlyBuilder( entityType ) != null ) {
+				processWork( event.getEntity(), event.getId(), WorkType.DELETE, event );
+			}
 		}
 	}
 
 	public void onPostInsert(PostInsertEvent event) {
 		if ( used ) {
 			final Object entity = event.getEntity();
-			DocumentBuilder<?> builder = searchFactoryImplementor.getDocumentBuilder( entity.getClass() );
-			//not strictly necessary but a small optimization
-			if ( builder != null ) {
+			if ( searchFactoryImplementor.getDocumentBuilder( entity.getClass() ) != null
+					|| searchFactoryImplementor.getContainedInOnlyBuilder( entity.getClass() ) != null ) {
 				Serializable id = event.getId();
 				processWork( entity, id, WorkType.ADD, event );
 			}
@@ -92,9 +95,8 @@
 	public void onPostUpdate(PostUpdateEvent event) {
 		if ( used ) {
 			final Object entity = event.getEntity();
-			//not strictly necessary but a small optimization
-			DocumentBuilder<?> builder = searchFactoryImplementor.getDocumentBuilder( entity.getClass() );
-			if ( builder != null ) {
+			if ( searchFactoryImplementor.getDocumentBuilder( entity.getClass() ) != null
+					|| searchFactoryImplementor.getContainedInOnlyBuilder( entity.getClass() ) != null ) {
 				Serializable id = event.getId();
 				processWork( entity, id, WorkType.UPDATE, event );
 			}
@@ -131,16 +133,19 @@
 			//Should log really but we don't know if we're interested in this collection for indexing
 			return;
 		}
-		if ( used && searchFactoryImplementor.getDocumentBuilders().containsKey( entity.getClass() ) ) {
-			Serializable id = getId( entity, event );
-			if ( id == null ) {
-				log.warn(
-						"Unable to reindex entity on collection change, id cannot be extracted: {}",
-						event.getAffectedOwnerEntityName()
-				);
-				return;
+		if ( used ) {
+			if ( searchFactoryImplementor.getDocumentBuilder( entity.getClass() ) != null
+					|| searchFactoryImplementor.getContainedInOnlyBuilder( entity.getClass() ) != null ) {
+				Serializable id = getId( entity, event );
+				if ( id == null ) {
+					log.warn(
+							"Unable to reindex entity on collection change, id cannot be extracted: {}",
+							event.getAffectedOwnerEntityName()
+					);
+					return;
+				}
+				processWork( entity, id, WorkType.COLLECTION, event );
 			}
-			processWork( entity, id, WorkType.COLLECTION, event );
 		}
 	}
 

Modified: search/trunk/src/java/org/hibernate/search/impl/FullTextSessionImpl.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/impl/FullTextSessionImpl.java	2008-10-23 00:04:14 UTC (rev 15375)
+++ search/trunk/src/java/org/hibernate/search/impl/FullTextSessionImpl.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -112,9 +112,10 @@
 		// not strictly necessary but a small optimization plus let's make sure the
 		// client didn't mess something up.
 
-		DocumentBuilder<?> builder = searchFactoryImplementor.getDocumentBuilder( entityType );
-		if ( builder == null ) {
-			throw new IllegalArgumentException( entityType.getName() + " is not a mapped entity (don't forget to add @Indexed)" );
+		if ( searchFactoryImplementor.getDocumentBuilder( entityType ) == null
+				&& searchFactoryImplementor.getContainedInOnlyBuilder( entityType ) == null ) {
+			throw new IllegalArgumentException( "Entity to index is not an @Indexed entity nor @ContainedIn another entity: "
+					+ entityType.getName() );
 		}
 		WorkType type;
 		if ( id == null ) {
@@ -142,9 +143,10 @@
 		//TODO cache that at the FTSession level
 		SearchFactoryImplementor searchFactoryImplementor = getSearchFactoryImplementor();
 		//not strictly necessary but a small optimization
-		DocumentBuilder<?> builder = searchFactoryImplementor.getDocumentBuilder( clazz );
-		if ( builder == null ) {
-			throw new IllegalArgumentException( "Entity to index not an @Indexed entity: " + entity.getClass().getName() );
+		if ( searchFactoryImplementor.getDocumentBuilder( clazz ) == null
+				&& searchFactoryImplementor.getContainedInOnlyBuilder( clazz ) == null ) {
+			throw new IllegalArgumentException( "Entity to index is not an @Indexed entity nor @ContainedIn another entity: "
+					+ entity.getClass().getName() );
 		}
 		Serializable id = session.getIdentifier( entity );
 		Work work = new Work( entity, id, WorkType.INDEX );

Modified: search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java	2008-10-23 00:04:14 UTC (rev 15375)
+++ search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -42,6 +42,7 @@
 import org.hibernate.search.engine.DocumentBuilder;
 import org.hibernate.search.engine.FilterDef;
 import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.engine.EntityState;
 import org.hibernate.search.filter.CachingWrapperFilter;
 import org.hibernate.search.filter.FilterCachingStrategy;
 import org.hibernate.search.filter.MRUFilterCachingStrategy;
@@ -66,6 +67,7 @@
 	private static final Logger log = LoggerFactory.make();
 
 	private final Map<Class<?>, DocumentBuilder<?>> documentBuilders = new HashMap<Class<?>, DocumentBuilder<?>>();
+	private final Map<Class<?>, DocumentBuilder<?>> containedInOnlyBuilders = new HashMap<Class<?>, DocumentBuilder<?>>();
 	//keep track of the index modifiers per DirectoryProvider since multiple entity can use the same directory provider
 	private final Map<DirectoryProvider<?>, DirectoryProviderData> dirProviderData = new HashMap<DirectoryProvider<?>, DirectoryProviderData>();
 	private final Worker worker;
@@ -117,6 +119,10 @@
 		for (DocumentBuilder builder : documentBuilders.values()) {
 			builder.postInitialize( indexedClasses );
 		}
+		//not really necessary today
+		for (DocumentBuilder builder : containedInOnlyBuilders.values()) {
+			builder.postInitialize( indexedClasses );
+		}
 		this.worker = WorkerFactory.createWorker( cfg, this );
 		this.readerProvider = ReaderProviderFactory.createReaderProvider( cfg, this );
 		this.filterCachingStrategy = buildFilterCachingStrategy( cfg.getProperties() );
@@ -244,9 +250,16 @@
 
 	@SuppressWarnings( "unckecked" )
 	public <T> DocumentBuilder<T> getDocumentBuilder(Class<T> entityType) {
+		if (barrier != 0) { } //read barrier
 		return ( DocumentBuilder<T> ) documentBuilders.get( entityType );
 	}
 
+	@SuppressWarnings( "unckecked" )
+	public <T> DocumentBuilder<T> getContainedInOnlyBuilder(Class<T> entityType) {
+		if (barrier != 0) { } //read barrier
+		return ( DocumentBuilder<T> ) containedInOnlyBuilders.get( entityType );
+	}
+
 	public Set<DirectoryProvider<?>> getDirectoryProviders() {
 		if (barrier != 0) { } //read barrier
 		return this.dirProviderData.keySet();
@@ -343,14 +356,26 @@
 				if ( mappedXClass != null) {
 					if ( mappedXClass.isAnnotationPresent( Indexed.class ) ) {
 						DirectoryProviderFactory.DirectoryProviders providers = factory.createDirectoryProviders( mappedXClass, cfg, this, reflectionManager );
-
-						final DocumentBuilder<Object> documentBuilder = new DocumentBuilder<Object>(
+						//FIXME DocumentBuilder needs to be built by a helper method receiving Class<T> to infer T properly
+						//XClass unfortunately is not (yet) genericized: TODO?
+						final DocumentBuilder<?> documentBuilder = new DocumentBuilder(
 								mappedXClass, context, providers.getProviders(), providers.getSelectionStrategy(),
 								reflectionManager
 						);
 
 						documentBuilders.put( mappedClass, documentBuilder );
 					}
+					else {
+						//FIXME DocumentBuilder needs to be built by a helper method receiving Class<T> to infer T properly
+						//XClass unfortunately is not (yet) genericized: TODO?
+						final DocumentBuilder<?> documentBuilder = new DocumentBuilder(
+								mappedXClass, context, reflectionManager
+						);
+						//TODO enhance that, I don't like to expose EntityState
+						if ( documentBuilder.getEntityState() != EntityState.NON_INDEXABLE ) {
+							containedInOnlyBuilders.put( mappedClass, documentBuilder );
+						}
+					}
 					bindFilterDefs(mappedXClass);
 					//TODO should analyzer def for classes at tyher sqme level???
 				}

Modified: search/trunk/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java	2008-10-23 00:04:14 UTC (rev 15375)
+++ search/trunk/src/test/org/hibernate/search/test/embedded/EmbeddedTest.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -264,7 +264,6 @@
 	 * Tests that updating an indexed embedded object updates the Lucene index as well.
 	 * 
 	 * @throws Exception in case the test fails
-	 * @see HSEARCH-142
 	 */
 	public void testEmbeddedObjectUpdate() throws Exception {
 
@@ -316,6 +315,7 @@
 
 	protected Class<?>[] getMappings() {
 		return new Class[] { Tower.class, Address.class, Product.class, Order.class, Author.class, Country.class,
-				State.class, StateCandidate.class };
+				State.class, StateCandidate.class, NonIndexedEntity.class
+		};
 	}
 }

Added: search/trunk/src/test/org/hibernate/search/test/embedded/NonIndexedEntity.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/embedded/NonIndexedEntity.java	                        (rev 0)
+++ search/trunk/src/test/org/hibernate/search/test/embedded/NonIndexedEntity.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -0,0 +1,23 @@
+package org.hibernate.search.test.embedded;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.GeneratedValue;
+
+/**
+ * @author Emmanuel Bernard
+ */
+ at Entity
+public class NonIndexedEntity {
+	@Id
+	@GeneratedValue
+	private int id;
+
+	public int getId() {
+		return id;
+	}
+
+	public void setId(int id) {
+		this.id = id;
+	}
+}

Modified: search/trunk/src/test/org/hibernate/search/test/embedded/State.java
===================================================================
--- search/trunk/src/test/org/hibernate/search/test/embedded/State.java	2008-10-23 00:04:14 UTC (rev 15375)
+++ search/trunk/src/test/org/hibernate/search/test/embedded/State.java	2008-10-23 02:15:50 UTC (rev 15376)
@@ -15,7 +15,6 @@
  * @author Hardy Ferentschik
  */
 @Entity
- at Indexed // @indexed should not be needed, see HSEARCH-142 and testEmbeddedObjectUpdate()
 public class State {
 	@Id
 	@DocumentId




More information about the hibernate-commits mailing list