Hibernate SVN: r15618 - in search/trunk/src/java/org/hibernate/search/backend/impl: lucene and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: sannegrinovero
Date: 2008-11-25 13:38:50 -0500 (Tue, 25 Nov 2008)
New Revision: 15618
Added:
search/trunk/src/java/org/hibernate/search/backend/impl/lucene/PerDPResources.java
Modified:
search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessor.java
search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessorFactory.java
search/trunk/src/java/org/hibernate/search/backend/impl/lucene/PerDPQueueProcessor.java
search/trunk/src/java/org/hibernate/search/backend/impl/lucene/QueueProcessors.java
search/trunk/src/java/org/hibernate/search/backend/impl/lucene/works/LuceneWorkVisitor.java
Log:
HSEARCH-268 Apply changes to different indexes in parallel
Modified: search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java 2008-11-25 18:25:17 UTC (rev 15617)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java 2008-11-25 18:38:50 UTC (rev 15618)
@@ -48,8 +48,7 @@
public BatchedQueueingProcessor(SearchFactoryImplementor searchFactoryImplementor, Properties properties) {
this.searchFactoryImplementor = searchFactoryImplementor;
- //default to sync if none defined
- this.sync = !"async".equalsIgnoreCase( properties.getProperty( Environment.WORKER_EXECUTION ) );
+ this.sync = isConfiguredAsSync( properties );
//default to a simple asynchronous operation
int min = ConfigurationParseHelper.getIntValue( properties, Environment.WORKER_THREADPOOL_SIZE, 1 );
@@ -207,5 +206,14 @@
return this == SECOND && type == WorkType.COLLECTION;
}
}
+
+ /**
+ * @param properties the configuration to parse
+ * @return true if the configuration uses sync indexing
+ */
+ public static boolean isConfiguredAsSync(Properties properties){
+ //default to sync if none defined
+ return !"async".equalsIgnoreCase( properties.getProperty( Environment.WORKER_EXECUTION ) );
+ }
}
Modified: search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessor.java 2008-11-25 18:25:17 UTC (rev 15617)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessor.java 2008-11-25 18:38:50 UTC (rev 15618)
@@ -5,11 +5,12 @@
import java.util.Map;
import org.hibernate.search.backend.LuceneWork;
-import org.hibernate.search.backend.impl.lucene.works.LuceneWorkVisitor;
import org.hibernate.search.engine.DocumentBuilderIndexedEntity;
import org.hibernate.search.engine.SearchFactoryImplementor;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.store.IndexShardingStrategy;
+import org.hibernate.search.util.LoggerFactory;
+import org.slf4j.Logger;
/**
* Apply the operations to Lucene directories.
@@ -23,31 +24,37 @@
private final List<LuceneWork> queue;
private final SearchFactoryImplementor searchFactoryImplementor;
- private final Map<DirectoryProvider,LuceneWorkVisitor> visitorsMap;
- private static final DpSelectionVisitor providerSelectionVisitor = new DpSelectionVisitor();
+ private final Map<DirectoryProvider,PerDPResources> resourcesMap;
+ private final boolean sync;
+
+ private static final DpSelectionVisitor providerSelectionVisitor = new DpSelectionVisitor();
+ private static final Logger log = LoggerFactory.make();
LuceneBackendQueueProcessor(List<LuceneWork> queue,
SearchFactoryImplementor searchFactoryImplementor,
- Map<DirectoryProvider,LuceneWorkVisitor> visitorsMap) {
+ Map<DirectoryProvider,PerDPResources> resourcesMap,
+ boolean syncMode) {
+ this.sync = syncMode;
this.queue = queue;
this.searchFactoryImplementor = searchFactoryImplementor;
- this.visitorsMap = visitorsMap;
+ this.resourcesMap = resourcesMap;
}
public void run() {
- QueueProcessors processors = new QueueProcessors( visitorsMap );
- // divide tasks in parts, adding to QueueProcessors by affected Directory.
+ QueueProcessors processors = new QueueProcessors( resourcesMap );
+ // divide the queue in tasks, adding to QueueProcessors by affected Directory.
for ( LuceneWork work : queue ) {
final Class<?> entityType = work.getEntityClass();
DocumentBuilderIndexedEntity<?> documentBuilder = searchFactoryImplementor.getDocumentBuilderIndexedEntity( entityType );
IndexShardingStrategy shardingStrategy = documentBuilder.getDirectoryProviderSelectionStrategy();
work.getWorkDelegate( providerSelectionVisitor ).addAsPayLoadsToQueue( work, shardingStrategy, processors );
}
- // TODO next cycle could be performed in parallel
- for ( PerDPQueueProcessor processor : processors.getQueueProcessors() ) {
- // perform the work on indexes
- processor.performWorks();
+ try {
+ //this Runnable splits tasks in more runnables and then runs them:
+ processors.runAll( sync );
+ } catch (InterruptedException e) {
+ log.error( "Index update task has been interrupted", e );
}
}
-
+
}
Modified: search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessorFactory.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessorFactory.java 2008-11-25 18:25:17 UTC (rev 15617)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessorFactory.java 2008-11-25 18:38:50 UTC (rev 15618)
@@ -5,11 +5,11 @@
import java.util.Map;
import java.util.Properties;
import java.util.List;
+import java.util.concurrent.ExecutorService;
import org.hibernate.search.backend.BackendQueueProcessorFactory;
import org.hibernate.search.backend.LuceneWork;
-import org.hibernate.search.backend.Workspace;
-import org.hibernate.search.backend.impl.lucene.works.LuceneWorkVisitor;
+import org.hibernate.search.backend.impl.BatchedQueueingProcessor;
import org.hibernate.search.engine.SearchFactoryImplementor;
import org.hibernate.search.store.DirectoryProvider;
@@ -34,23 +34,32 @@
* lifecycle (reused and shared by all transactions);
* the LuceneWorkVisitor(s) are stateless, the Workspace(s) are threadsafe.
*/
- private final Map<DirectoryProvider,LuceneWorkVisitor> visitorsMap = new HashMap<DirectoryProvider,LuceneWorkVisitor>();
+ private final Map<DirectoryProvider,PerDPResources> resourcesMap = new HashMap<DirectoryProvider,PerDPResources>();
+ /**
+ * copy of BatchedQueueingProcessor.sync
+ */
+ private boolean sync;
+
public void initialize(Properties props, SearchFactoryImplementor searchFactoryImplementor) {
this.searchFactoryImp = searchFactoryImplementor;
+ this.sync = BatchedQueueingProcessor.isConfiguredAsSync( props );
for (DirectoryProvider dp : searchFactoryImplementor.getDirectoryProviders() ) {
- Workspace w = new Workspace( searchFactoryImplementor, dp );
- LuceneWorkVisitor visitor = new LuceneWorkVisitor( w );
- visitorsMap.put( dp, visitor );
+ PerDPResources resources = new PerDPResources( searchFactoryImplementor, dp );
+ resourcesMap.put( dp, resources );
}
}
public Runnable getProcessor(List<LuceneWork> queue) {
- return new LuceneBackendQueueProcessor( queue, searchFactoryImp, visitorsMap );
+ return new LuceneBackendQueueProcessor( queue, searchFactoryImp, resourcesMap, sync );
}
public void close() {
- // no need to release anything
+ // needs to stop all used ThreadPools
+ for (PerDPResources res : resourcesMap.values() ) {
+ ExecutorService executor = res.getExecutor();
+ executor.shutdown();
+ }
}
}
Modified: search/trunk/src/java/org/hibernate/search/backend/impl/lucene/PerDPQueueProcessor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/lucene/PerDPQueueProcessor.java 2008-11-25 18:25:17 UTC (rev 15617)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/lucene/PerDPQueueProcessor.java 2008-11-25 18:38:50 UTC (rev 15618)
@@ -2,6 +2,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.ExecutorService;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
@@ -16,11 +17,12 @@
/**
* @author Sanne Grinovero
*/
-class PerDPQueueProcessor {
+class PerDPQueueProcessor implements Runnable {
private static final Logger log = LoggerFactory.make();
private final Workspace workspace;
private final LuceneWorkVisitor worker;
+ private final ExecutorService executor;
private final List<LuceneWork> workOnWriter = new ArrayList<LuceneWork>();
private final List<LuceneWork> workOnReader= new ArrayList<LuceneWork>();
@@ -29,9 +31,10 @@
private boolean needsWriter = false;
private boolean preferReader = false;
- public PerDPQueueProcessor(LuceneWorkVisitor worker) {
- this.worker = worker;
- this.workspace = worker.getWorkspace();
+ public PerDPQueueProcessor(PerDPResources resources) {
+ this.worker = resources.getVisitor();
+ this.workspace = resources.getWorkspace();
+ this.executor = resources.getExecutor();
}
public void addWork(LuceneWork work) {
@@ -56,7 +59,7 @@
}
}
- public void performWorks() {
+ public void run() {
// skip "resource optimization mode" when in batch to have all tasks use preferred (optimal) mode.
if ( ! batchmode ) {
// see if we can skip using some resource
@@ -153,5 +156,9 @@
workOnWriter.addAll( 0, workOnReader );
workOnReader.clear();
}
-
+
+ public ExecutorService getOwningExecutor() {
+ return executor;
+ }
+
}
Added: search/trunk/src/java/org/hibernate/search/backend/impl/lucene/PerDPResources.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/lucene/PerDPResources.java (rev 0)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/lucene/PerDPResources.java 2008-11-25 18:38:50 UTC (rev 15618)
@@ -0,0 +1,35 @@
+package org.hibernate.search.backend.impl.lucene;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.hibernate.search.backend.Workspace;
+import org.hibernate.search.backend.impl.lucene.works.LuceneWorkVisitor;
+import org.hibernate.search.engine.SearchFactoryImplementor;
+import org.hibernate.search.store.DirectoryProvider;
+
+class PerDPResources {
+
+ private final ExecutorService executor;
+ private final LuceneWorkVisitor visitor;
+ private final Workspace workspace;
+
+ PerDPResources(SearchFactoryImplementor searchFactoryImp, DirectoryProvider dp) {
+ workspace = new Workspace( searchFactoryImp, dp );
+ visitor = new LuceneWorkVisitor( workspace );
+ executor = Executors.newFixedThreadPool( 1 );
+ }
+
+ public ExecutorService getExecutor() {
+ return executor;
+ }
+
+ public LuceneWorkVisitor getVisitor() {
+ return visitor;
+ }
+
+ public Workspace getWorkspace() {
+ return workspace;
+ }
+
+}
Property changes on: search/trunk/src/java/org/hibernate/search/backend/impl/lucene/PerDPResources.java
___________________________________________________________________
Name: svn:executable
+ *
Modified: search/trunk/src/java/org/hibernate/search/backend/impl/lucene/QueueProcessors.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/lucene/QueueProcessors.java 2008-11-25 18:25:17 UTC (rev 15617)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/lucene/QueueProcessors.java 2008-11-25 18:38:50 UTC (rev 15618)
@@ -1,36 +1,93 @@
package org.hibernate.search.backend.impl.lucene;
-import java.util.Collection;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
import org.hibernate.search.backend.LuceneWork;
-import org.hibernate.search.backend.impl.lucene.works.LuceneWorkVisitor;
import org.hibernate.search.store.DirectoryProvider;
/**
- * Container used to split work by DirectoryProviders.
+ * Container used to split work by DirectoryProviders and execute
+ * them concurrently.
* @author Sanne Grinovero
*/
class QueueProcessors {
- private final Map<DirectoryProvider, LuceneWorkVisitor> visitorsMap;
+ private final Map<DirectoryProvider, PerDPResources> resourcesMap;
private final Map<DirectoryProvider, PerDPQueueProcessor> dpProcessors = new HashMap<DirectoryProvider, PerDPQueueProcessor>();
- QueueProcessors(Map<DirectoryProvider, LuceneWorkVisitor> visitorsMap) {
- this.visitorsMap = visitorsMap;
+ QueueProcessors(Map<DirectoryProvider, PerDPResources> resourcesMap) {
+ this.resourcesMap = resourcesMap;
}
void addWorkToDpProcessor(DirectoryProvider dp, LuceneWork work) {
if ( ! dpProcessors.containsKey( dp ) ) {
- dpProcessors.put( dp, new PerDPQueueProcessor( visitorsMap.get( dp ) ) );
+ dpProcessors.put( dp, new PerDPQueueProcessor( resourcesMap.get( dp ) ) );
}
PerDPQueueProcessor processor = dpProcessors.get( dp );
processor.addWork ( work );
}
- Collection<PerDPQueueProcessor> getQueueProcessors(){
- return dpProcessors.values();
+ /**
+ * Run all index modifications queued so far
+ * @param sync when true this method blocks until all job is done.
+ * @throws InterruptedException only relevant when sync is true.
+ */
+ void runAll(boolean sync) throws InterruptedException {
+ if ( sync ) {
+ runAllWaiting();
+ }
+ else {
+ runAllAsync();
+ }
}
+
+ /**
+ * Runs all PerDPQueueProcessor and don't wait fot them to finish.
+ */
+ private void runAllAsync() {
+ // execute all work in parallel on each DirectoryProvider;
+ // each DP has it's own ExecutorService.
+ for ( PerDPQueueProcessor process : dpProcessors.values() ) {
+ ExecutorService executor = process.getOwningExecutor();
+ executor.execute( process );
+ }
+ }
+ /**
+ * Runs all PerDPQueueProcessor and waits until all have been processed.
+ * @throws InterruptedException
+ */
+ private void runAllWaiting() throws InterruptedException {
+ List<Future<Object>> futures = new ArrayList<Future<Object>>( dpProcessors.size() );
+ // execute all work in parallel on each DirectoryProvider;
+ // each DP has it's own ExecutorService.
+ for ( PerDPQueueProcessor process : dpProcessors.values() ) {
+ ExecutorService executor = process.getOwningExecutor();
+ //wrap each Runnable in a Future
+ FutureTask<Object> f = new FutureTask<Object>( process, null );
+ futures.add( f );
+ executor.execute( f );
+ }
+ // and then wait for all tasks to be finished:
+ for ( Future<Object> f : futures ) {
+ if ( !f.isDone() ) {
+ try {
+ f.get();
+ } catch(CancellationException ignore) {
+ //ignored, as in java.util.concurrent.AbstractExecutorService.invokeAll(Collection<Callable<T>> tasks)
+ } catch(ExecutionException ignore) {
+ //ignored, as in java.util.concurrent.AbstractExecutorService.invokeAll(Collection<Callable<T>> tasks)
+ }
+ }
+ }
+ }
+
}
Modified: search/trunk/src/java/org/hibernate/search/backend/impl/lucene/works/LuceneWorkVisitor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/lucene/works/LuceneWorkVisitor.java 2008-11-25 18:25:17 UTC (rev 15617)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/lucene/works/LuceneWorkVisitor.java 2008-11-25 18:38:50 UTC (rev 15618)
@@ -17,13 +17,6 @@
private final OptimizeWorkDelegate optimizeDelegate;
private final PurgeAllWorkDelegate purgeAllDelegate;
- /**
- * The Workspace this visitor has been created for;
- * different workspaces could use different Delegates for specific
- * needs basing on workspace or DirectoryProvider configuration.
- */
- private final Workspace linkedWorkspace;
-
public LuceneWorkVisitor(Workspace workspace) {
if ( workspace.getEntitiesInDirectory().size() == 1 ) {
this.deleteDelegate = new DeleteExtWorkDelegate( workspace );
@@ -34,7 +27,6 @@
this.purgeAllDelegate = new PurgeAllWorkDelegate();
this.addDelegate = new AddWorkDelegate( workspace );
this.optimizeDelegate = new OptimizeWorkDelegate( workspace );
- this.linkedWorkspace = workspace;
}
public LuceneWorkDelegate getDelegate(AddLuceneWork addLuceneWork) {
@@ -53,8 +45,4 @@
return purgeAllDelegate;
}
- public Workspace getWorkspace(){
- return linkedWorkspace;
- }
-
}
16 years, 1 month
Hibernate SVN: r15617 - search/trunk/src/java/org/hibernate/search/backend/impl.
by hibernate-commits@lists.jboss.org
Author: sannegrinovero
Date: 2008-11-25 13:25:17 -0500 (Tue, 25 Nov 2008)
New Revision: 15617
Modified:
search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
Log:
HSEARCH-311 actually call the new close()
Modified: search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java 2008-11-25 17:56:50 UTC (rev 15616)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/BatchedQueueingProcessor.java 2008-11-25 18:25:17 UTC (rev 15617)
@@ -192,6 +192,8 @@
log.error( "Unable to properly shut down asynchronous indexing work", e );
}
}
+ //and stop the backend
+ backendQueueProcessorFactory.close();
}
private static enum Layer {
16 years, 1 month
Hibernate SVN: r15616 - in search/trunk/src/java/org/hibernate/search/backend: impl/jms and 1 other directories.
by hibernate-commits@lists.jboss.org
Author: sannegrinovero
Date: 2008-11-25 12:56:50 -0500 (Tue, 25 Nov 2008)
New Revision: 15616
Modified:
search/trunk/src/java/org/hibernate/search/backend/BackendQueueProcessorFactory.java
search/trunk/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java
search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessorFactory.java
Log:
HSEARCH-311 interface change in BackendQueueProcessorFactory: adding a close() method to release resources.
Modified: search/trunk/src/java/org/hibernate/search/backend/BackendQueueProcessorFactory.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/BackendQueueProcessorFactory.java 2008-11-25 15:25:46 UTC (rev 15615)
+++ search/trunk/src/java/org/hibernate/search/backend/BackendQueueProcessorFactory.java 2008-11-25 17:56:50 UTC (rev 15616)
@@ -13,6 +13,12 @@
* @author Emmanuel Bernard
*/
public interface BackendQueueProcessorFactory {
+
+ /**
+ * Used at startup, called once as first method.
+ * @param props all configuration properties
+ * @param searchFactory the client
+ */
void initialize(Properties props, SearchFactoryImplementor searchFactory);
/**
@@ -22,4 +28,11 @@
* @return <code>Runnable</code> which processes <code>queue</code> when started.
*/
Runnable getProcessor(List<LuceneWork> queue);
+
+ /**
+ * Used to shutdown and eventually release resources.
+ * no other method should used after this one.
+ */
+ void close();
+
}
Modified: search/trunk/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java 2008-11-25 15:25:46 UTC (rev 15615)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/jms/JMSBackendQueueProcessorFactory.java 2008-11-25 17:56:50 UTC (rev 15616)
@@ -116,4 +116,8 @@
return result;
}
+ public void close() {
+ // no need to release anything
+ }
+
}
Modified: search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessorFactory.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessorFactory.java 2008-11-25 15:25:46 UTC (rev 15615)
+++ search/trunk/src/java/org/hibernate/search/backend/impl/lucene/LuceneBackendQueueProcessorFactory.java 2008-11-25 17:56:50 UTC (rev 15616)
@@ -48,5 +48,9 @@
public Runnable getProcessor(List<LuceneWork> queue) {
return new LuceneBackendQueueProcessor( queue, searchFactoryImp, visitorsMap );
}
+
+ public void close() {
+ // no need to release anything
+ }
}
16 years, 1 month
Hibernate SVN: r15615 - core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy.
by hibernate-commits@lists.jboss.org
Author: adamw
Date: 2008-11-25 10:25:46 -0500 (Tue, 25 Nov 2008)
New Revision: 15615
Modified:
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/CollectionProxy.java
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/ListProxy.java
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/MapProxy.java
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SetProxy.java
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedMapProxy.java
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedSetProxy.java
Log:
HHH-3623: collectin proxies are serializable
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/CollectionProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/CollectionProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/CollectionProxy.java 2008-11-25 15:25:46 UTC (rev 15615)
@@ -35,6 +35,9 @@
private org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor<T> initializor;
protected T delegate;
+ protected CollectionProxy() {
+ }
+
public CollectionProxy(Initializor<T> initializor) {
this.initializor = initializor;
}
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/ListProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/ListProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/ListProxy.java 2008-11-25 15:25:46 UTC (rev 15615)
@@ -23,6 +23,8 @@
*/
package org.hibernate.envers.entities.mapper.relation.lazy.proxy;
+import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor;
+
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
@@ -34,6 +36,9 @@
public class ListProxy<U> extends CollectionProxy<U, List<U>> implements List<U>, Serializable {
private static final long serialVersionUID = -5479232938279790987L;
+ public ListProxy() {
+ }
+
public ListProxy(org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor<List<U>> initializor) {
super(initializor);
}
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/MapProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/MapProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/MapProxy.java 2008-11-25 15:25:46 UTC (rev 15615)
@@ -39,6 +39,9 @@
private Initializor<Map<K, V>> initializor;
protected Map<K, V> delegate;
+ public MapProxy() {
+ }
+
public MapProxy(org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor<Map<K, V>> initializor) {
this.initializor = initializor;
}
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SetProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SetProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SetProxy.java 2008-11-25 15:25:46 UTC (rev 15615)
@@ -32,6 +32,9 @@
public class SetProxy<U> extends CollectionProxy<U, Set<U>> implements Set<U>, Serializable {
private static final long serialVersionUID = 131464133074137701L;
+ public SetProxy() {
+ }
+
public SetProxy(org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor<Set<U>> initializor) {
super(initializor);
}
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedMapProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedMapProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedMapProxy.java 2008-11-25 15:25:46 UTC (rev 15615)
@@ -41,6 +41,9 @@
private Initializor<SortedMap<K, V>> initializor;
protected SortedMap<K, V> delegate;
+ public SortedMapProxy() {
+ }
+
public SortedMapProxy(org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor<SortedMap<K, V>> initializor) {
this.initializor = initializor;
}
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedSetProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedSetProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedSetProxy.java 2008-11-25 15:25:46 UTC (rev 15615)
@@ -33,6 +33,9 @@
public class SortedSetProxy<U> extends CollectionProxy<U, SortedSet<U>> implements SortedSet<U>, Serializable {
private static final long serialVersionUID = 2092884107178125905L;
+ public SortedSetProxy() {
+ }
+
public SortedSetProxy(org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor<SortedSet<U>> initializor) {
super(initializor);
}
16 years, 1 month
Hibernate SVN: r15614 - core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy.
by hibernate-commits@lists.jboss.org
Author: adamw
Date: 2008-11-25 10:23:40 -0500 (Tue, 25 Nov 2008)
New Revision: 15614
Modified:
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/ListProxy.java
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/MapProxy.java
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SetProxy.java
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedMapProxy.java
core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedSetProxy.java
Log:
HHH-3623: collectin proxies are serializable
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/ListProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/ListProxy.java 2008-11-25 15:05:58 UTC (rev 15613)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/ListProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
@@ -26,11 +26,14 @@
import java.util.Collection;
import java.util.List;
import java.util.ListIterator;
+import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
-public class ListProxy<U> extends CollectionProxy<U, List<U>> implements List<U> {
+public class ListProxy<U> extends CollectionProxy<U, List<U>> implements List<U>, Serializable {
+ private static final long serialVersionUID = -5479232938279790987L;
+
public ListProxy(org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor<List<U>> initializor) {
super(initializor);
}
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/MapProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/MapProxy.java 2008-11-25 15:05:58 UTC (rev 15613)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/MapProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
@@ -26,13 +26,16 @@
import java.util.Collection;
import java.util.Map;
import java.util.Set;
+import java.io.Serializable;
import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor;
/**
* @author Adam Warski (adam at warski dot org)
*/
-public class MapProxy<K, V> implements Map<K, V> {
+public class MapProxy<K, V> implements Map<K, V>, Serializable {
+ private static final long serialVersionUID = 8418037541773074646L;
+
private Initializor<Map<K, V>> initializor;
protected Map<K, V> delegate;
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SetProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SetProxy.java 2008-11-25 15:05:58 UTC (rev 15613)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SetProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
@@ -24,11 +24,14 @@
package org.hibernate.envers.entities.mapper.relation.lazy.proxy;
import java.util.Set;
+import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
-public class SetProxy<U> extends CollectionProxy<U, Set<U>> implements Set<U> {
+public class SetProxy<U> extends CollectionProxy<U, Set<U>> implements Set<U>, Serializable {
+ private static final long serialVersionUID = 131464133074137701L;
+
public SetProxy(org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor<Set<U>> initializor) {
super(initializor);
}
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedMapProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedMapProxy.java 2008-11-25 15:05:58 UTC (rev 15613)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedMapProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
@@ -28,13 +28,16 @@
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
+import java.io.Serializable;
import org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor;
/**
* @author Adam Warski (adam at warski dot org)
*/
-public class SortedMapProxy<K, V> implements SortedMap<K, V> {
+public class SortedMapProxy<K, V> implements SortedMap<K, V>, Serializable {
+ private static final long serialVersionUID = 2645817952901452375L;
+
private Initializor<SortedMap<K, V>> initializor;
protected SortedMap<K, V> delegate;
Modified: core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedSetProxy.java
===================================================================
--- core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedSetProxy.java 2008-11-25 15:05:58 UTC (rev 15613)
+++ core/trunk/envers/src/main/java/org/hibernate/envers/entities/mapper/relation/lazy/proxy/SortedSetProxy.java 2008-11-25 15:23:40 UTC (rev 15614)
@@ -25,11 +25,14 @@
import java.util.Comparator;
import java.util.SortedSet;
+import java.io.Serializable;
/**
* @author Adam Warski (adam at warski dot org)
*/
-public class SortedSetProxy<U> extends CollectionProxy<U, SortedSet<U>> implements SortedSet<U> {
+public class SortedSetProxy<U> extends CollectionProxy<U, SortedSet<U>> implements SortedSet<U>, Serializable {
+ private static final long serialVersionUID = 2092884107178125905L;
+
public SortedSetProxy(org.hibernate.envers.entities.mapper.relation.lazy.initializor.Initializor<SortedSet<U>> initializor) {
super(initializor);
}
16 years, 1 month
Hibernate SVN: r15613 - search/trunk/src/java/org/hibernate/search/engine.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2008-11-25 10:05:58 -0500 (Tue, 25 Nov 2008)
New Revision: 15613
Modified:
search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java
Log:
added some documentation
Modified: search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java 2008-11-25 13:29:35 UTC (rev 15612)
+++ search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java 2008-11-25 15:05:58 UTC (rev 15613)
@@ -328,29 +328,39 @@
super.addWorkToQueue( entityClass, entity, id, workType, queue, searchFactoryImplementor );
}
+ /**
+ * Builds the Lucene <code>Document</code> for a given entity <code>instance</code> and its <code>id</code>.
+ *
+ * @param instance The entity for which to build the matching Lucene <code>Document</code>
+ * @param id the entity id.
+ * @return The Lucene <code>Document</code> for the specified entity.
+ */
public Document getDocument(T instance, Serializable id) {
Document doc = new Document();
final Class<?> entityType = Hibernate.getClass( instance );
- //XClass instanceClass = reflectionManager.toXClass( entityType );
if ( metadata.boost != null ) {
doc.setBoost( metadata.boost );
}
- {
- Field classField =
- new Field(
- CLASS_FIELDNAME,
- entityType.getName(),
- Field.Store.YES,
- Field.Index.NOT_ANALYZED,
- Field.TermVector.NO
- );
- doc.add( classField );
- LuceneOptions luceneOptions = new LuceneOptionsImpl(
- Field.Store.YES,
- Field.Index.NOT_ANALYZED, Field.TermVector.NO, idBoost
- );
- idBridge.set( idKeywordName, id, doc, luceneOptions );
- }
+
+ // add the class name of the entity to the document
+ Field classField =
+ new Field(
+ CLASS_FIELDNAME,
+ entityType.getName(),
+ Field.Store.YES,
+ Field.Index.NOT_ANALYZED,
+ Field.TermVector.NO
+ );
+ doc.add( classField );
+
+ // now add the entity id to the document
+ LuceneOptions luceneOptions = new LuceneOptionsImpl(
+ Field.Store.YES,
+ Field.Index.NOT_ANALYZED, Field.TermVector.NO, idBoost
+ );
+ idBridge.set( idKeywordName, id, doc, luceneOptions );
+
+ // finally add all other document fields
buildDocumentFields( instance, doc, metadata );
return doc;
}
16 years, 1 month
Hibernate SVN: r15612 - in search/trunk/src/java/org/hibernate/search: event and 2 other directories.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2008-11-25 08:29:35 -0500 (Tue, 25 Nov 2008)
New Revision: 15612
Modified:
search/trunk/src/java/org/hibernate/search/engine/MultiClassesQueryLoader.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/SearchFactoryImpl.java
search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java
Log:
HSEARCH-285
Renamed SearchFactoryImplementor.getDocumentBuilders to getDocumentBuildersIndexedEntities
Modified: search/trunk/src/java/org/hibernate/search/engine/MultiClassesQueryLoader.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/MultiClassesQueryLoader.java 2008-11-25 13:10:25 UTC (rev 15611)
+++ search/trunk/src/java/org/hibernate/search/engine/MultiClassesQueryLoader.java 2008-11-25 13:29:35 UTC (rev 15612)
@@ -35,7 +35,7 @@
// root entity could lead to quite inefficient queries in Hibernate when using table per class
if ( entityTypes.size() == 0 ) {
//support all classes
- for( Map.Entry<Class<?>, DocumentBuilderIndexedEntity<?>> entry : searchFactoryImplementor.getDocumentBuilders().entrySet() ) {
+ for( Map.Entry<Class<?>, DocumentBuilderIndexedEntity<?>> entry : searchFactoryImplementor.getDocumentBuildersIndexedEntities().entrySet() ) {
//get only root entities to limit queries
if ( entry.getValue().isRoot() ) {
safeEntityTypes.add( entry.getKey() );
Modified: search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java 2008-11-25 13:10:25 UTC (rev 15611)
+++ search/trunk/src/java/org/hibernate/search/engine/SearchFactoryImplementor.java 2008-11-25 13:29:35 UTC (rev 15612)
@@ -24,7 +24,7 @@
void setBackendQueueProcessorFactory(BackendQueueProcessorFactory backendQueueProcessorFactory);
- Map<Class<?>, DocumentBuilderIndexedEntity<?>> getDocumentBuilders();
+ Map<Class<?>, DocumentBuilderIndexedEntity<?>> getDocumentBuildersIndexedEntities();
<T> DocumentBuilderIndexedEntity<T> getDocumentBuilderIndexedEntity(Class<T> entityType);
Modified: search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java 2008-11-25 13:10:25 UTC (rev 15611)
+++ search/trunk/src/java/org/hibernate/search/event/FullTextIndexEventListener.java 2008-11-25 13:29:35 UTC (rev 15612)
@@ -59,7 +59,7 @@
searchFactoryImplementor = ContextHolder.getOrBuildSearchFactory( cfg );
String indexingStrategy = searchFactoryImplementor.getIndexingStrategy();
if ( "event".equals( indexingStrategy ) ) {
- used = searchFactoryImplementor.getDocumentBuilders().size() != 0;
+ used = searchFactoryImplementor.getDocumentBuildersIndexedEntities().size() != 0;
}
else if ( "manual".equals( indexingStrategy ) ) {
used = false;
@@ -73,7 +73,7 @@
public void onPostDelete(PostDeleteEvent event) {
if ( used ) {
final Class<?> entityType = event.getEntity().getClass();
- if ( searchFactoryImplementor.getDocumentBuilders().containsKey( entityType )
+ if ( searchFactoryImplementor.getDocumentBuildersIndexedEntities().containsKey( entityType )
|| searchFactoryImplementor.getDocumentBuilderContainedEntity( entityType ) != null ) {
processWork( event.getEntity(), event.getId(), WorkType.DELETE, event );
}
Modified: search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java 2008-11-25 13:10:25 UTC (rev 15611)
+++ search/trunk/src/java/org/hibernate/search/impl/SearchFactoryImpl.java 2008-11-25 13:29:35 UTC (rev 15612)
@@ -261,7 +261,7 @@
}
- public Map<Class<?>, DocumentBuilderIndexedEntity<?>> getDocumentBuilders() {
+ public Map<Class<?>, DocumentBuilderIndexedEntity<?>> getDocumentBuildersIndexedEntities() {
if ( barrier != 0 ) {
} //read barrier
return documentBuildersIndexedEntities;
@@ -336,7 +336,7 @@
public void optimize() {
if ( barrier != 0 ) {
} //read barrier
- Set<Class<?>> clazzs = getDocumentBuilders().keySet();
+ Set<Class<?>> clazzs = getDocumentBuildersIndexedEntities().keySet();
for ( Class clazz : clazzs ) {
optimize( clazz );
}
@@ -345,7 +345,7 @@
public void optimize(Class entityType) {
if ( barrier != 0 ) {
} //read barrier
- if ( !getDocumentBuilders().containsKey( entityType ) ) {
+ if ( !getDocumentBuildersIndexedEntities().containsKey( entityType ) ) {
throw new SearchException( "Entity not indexed: " + entityType );
}
List<LuceneWork> queue = new ArrayList<LuceneWork>( 1 );
Modified: search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java 2008-11-25 13:10:25 UTC (rev 15611)
+++ search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java 2008-11-25 13:29:35 UTC (rev 15612)
@@ -607,7 +607,7 @@
* TODO change classesAndSubclasses by side effect, which is a mismatch with the Searcher return, fix that.
*/
private IndexSearcher buildSearcher(SearchFactoryImplementor searchFactoryImplementor) {
- Map<Class<?>, DocumentBuilderIndexedEntity<?>> builders = searchFactoryImplementor.getDocumentBuilders();
+ Map<Class<?>, DocumentBuilderIndexedEntity<?>> builders = searchFactoryImplementor.getDocumentBuildersIndexedEntities();
List<DirectoryProvider> directories = new ArrayList<DirectoryProvider>();
Set<String> idFieldNames = new HashSet<String>();
16 years, 1 month
Hibernate SVN: r15611 - search/trunk/src/java/org/hibernate/search/engine.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2008-11-25 08:10:25 -0500 (Tue, 25 Nov 2008)
New Revision: 15611
Modified:
search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderContainedEntity.java
search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java
Log:
HSEARCH-285
Moved all methods specific to entities with are actually indexed with @Indexed into DocumentBuilderIndexedEntity
Modified: search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderContainedEntity.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderContainedEntity.java 2008-11-25 12:56:25 UTC (rev 15610)
+++ search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderContainedEntity.java 2008-11-25 13:10:25 UTC (rev 15611)
@@ -13,9 +13,7 @@
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.Term;
import org.apache.lucene.search.Similarity;
import org.slf4j.Logger;
@@ -26,9 +24,7 @@
import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XMember;
import org.hibernate.annotations.common.reflection.XProperty;
-import org.hibernate.annotations.common.util.ReflectHelper;
import org.hibernate.annotations.common.util.StringHelper;
-import org.hibernate.proxy.HibernateProxy;
import org.hibernate.search.SearchException;
import org.hibernate.search.annotations.AnalyzerDef;
import org.hibernate.search.annotations.AnalyzerDefs;
@@ -46,16 +42,14 @@
import org.hibernate.search.bridge.BridgeFactory;
import org.hibernate.search.bridge.FieldBridge;
import org.hibernate.search.bridge.LuceneOptions;
-import org.hibernate.search.bridge.TwoWayFieldBridge;
-import org.hibernate.search.bridge.TwoWayString2FieldBridgeAdaptor;
-import org.hibernate.search.bridge.TwoWayStringBridge;
import org.hibernate.search.impl.InitContext;
import org.hibernate.search.util.LoggerFactory;
import org.hibernate.search.util.ReflectionHelper;
import org.hibernate.search.util.ScopedAnalyzer;
/**
- * Set up and provide a manager for indexed classes.
+ * Set up and provide a manager for classes which are indexed via <code>@IndexedEmbedded</code>, but themselves do not
+ * contain the <code>@Indexed</code> annotation.
*
* @author Gavin King
* @author Emmanuel Bernard
@@ -68,33 +62,13 @@
protected final PropertiesMetadata metadata = new PropertiesMetadata();
protected final XClass beanClass;
- protected String idKeywordName;
-
- /**
- * Flag indicating whether <code>@DocumentId</code> was explicitly specified.
- */
- protected boolean explicitDocumentId = false;
-
- /**
- * Flag indicating whether {@link org.apache.lucene.search.Searcher#doc(int, org.apache.lucene.document.FieldSelector)}
- * can be used in order to retrieve documents. This is only safe to do if we know that
- * all involved bridges are implementing <code>TwoWayStringBridge</code>. See HSEARCH-213.
- */
- private boolean allowFieldSelectionInProjection = false;
-
- protected XMember idGetter;
- protected Float idBoost;
- protected TwoWayFieldBridge idBridge;
protected Set<Class<?>> mappedSubclasses = new HashSet<Class<?>>();
- private ReflectionManager reflectionManager; //available only during initializationa nd post-initialization
+ protected ReflectionManager reflectionManager; //available only during initializationa and post-initialization
protected int level = 0;
protected int maxLevel = Integer.MAX_VALUE;
protected final ScopedAnalyzer analyzer = new ScopedAnalyzer();
protected Similarity similarity;
protected boolean isRoot;
- //if composite id, use of (a, b) in ((1,2), (3,4)) fails on most database
- private boolean safeFromTupleId;
- protected boolean idProvided = false;
protected EntityState entityState;
/**
@@ -116,16 +90,12 @@
init( clazz, context );
- if ( this.similarity == null ) {
- this.similarity = context.getDefaultSimilarity();
- }
-
if ( metadata.containedInGetters.size() == 0 ) {
this.entityState = EntityState.NON_INDEXABLE;
}
}
- private void init(XClass clazz, InitContext context) {
+ protected void init(XClass clazz, InitContext context) {
metadata.boost = getBoost( clazz );
metadata.analyzer = context.getDefaultAnalyzer();
@@ -135,55 +105,102 @@
this.analyzer.setGlobalAnalyzer( metadata.analyzer );
- //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 = entityState != EntityState.INDEXED || TwoWayString2FieldBridgeAdaptor.class.isAssignableFrom(
- idBridge.getClass()
- );
+ // set the default similarity in case that after processing all classes there is still no similarity set
+ if ( this.similarity == null ) {
+ this.similarity = context.getDefaultSimilarity();
+ }
+ }
- checkAllowFieldSelection();
- if ( log.isDebugEnabled() ) {
- log.debug(
- "Field selection in projections is set to {} for entity {}.",
- allowFieldSelectionInProjection,
- clazz.getName()
- );
+ public boolean isRoot() {
+ return isRoot;
+ }
+
+ private void initializeMembers(XClass clazz, PropertiesMetadata propertiesMetadata, boolean isRoot, String prefix,
+ Set<XClass> processedClasses, InitContext context) {
+ List<XClass> hierarchy = new ArrayList<XClass>();
+ for ( XClass currClass = clazz; currClass != null; currClass = currClass.getSuperclass() ) {
+ hierarchy.add( currClass );
}
+
+ /*
+ * Iterate the class hierarchy top down. This allows to override the default analyzer for the properties if the class holds one
+ */
+ for ( int index = hierarchy.size() - 1; index >= 0; index-- ) {
+ XClass currClass = hierarchy.get( index );
+
+ initalizeClassLevelAnnotations( currClass, propertiesMetadata, isRoot, prefix, context );
+
+ // rejecting non properties (ie regular methods) because the object is loaded from Hibernate,
+ // so indexing a non property does not make sense
+ List<XProperty> methods = currClass.getDeclaredProperties( XClass.ACCESS_PROPERTY );
+ for ( XProperty method : methods ) {
+ initializeMemberLevelAnnotations(
+ method, propertiesMetadata, isRoot, prefix, processedClasses, context
+ );
+ }
+
+ List<XProperty> fields = currClass.getDeclaredProperties( XClass.ACCESS_FIELD );
+ for ( XProperty field : fields ) {
+ initializeMemberLevelAnnotations(
+ field, propertiesMetadata, isRoot, prefix, processedClasses, context
+ );
+ }
+ }
}
/**
- * Checks whether all involved bridges are two way string bridges. If so we can optimize document retrieval
- * by using <code>FieldSelector</code>. See HSEARCH-213.
+ * Checks for class level annotations.
*/
- private void checkAllowFieldSelection() {
- allowFieldSelectionInProjection = true;
- if ( !( idBridge instanceof TwoWayStringBridge || idBridge instanceof TwoWayString2FieldBridgeAdaptor ) ) {
- allowFieldSelectionInProjection = false;
- return;
+ private void initalizeClassLevelAnnotations(XClass clazz, PropertiesMetadata propertiesMetadata, boolean isRoot, String prefix, InitContext context) {
+ Analyzer analyzer = getAnalyzer( clazz, context );
+
+ if ( analyzer != null ) {
+ propertiesMetadata.analyzer = analyzer;
}
- for ( FieldBridge bridge : metadata.fieldBridges ) {
- if ( !( bridge instanceof TwoWayStringBridge || bridge instanceof TwoWayString2FieldBridgeAdaptor ) ) {
- allowFieldSelectionInProjection = false;
- return;
+ checkForAnalyzerDefs( clazz, context );
+
+ // Check for any ClassBridges annotation.
+ ClassBridges classBridgesAnn = clazz.getAnnotation( ClassBridges.class );
+ if ( classBridgesAnn != null ) {
+ ClassBridge[] cbs = classBridgesAnn.value();
+ for ( ClassBridge cb : cbs ) {
+ bindClassAnnotation( prefix, propertiesMetadata, cb, context );
}
}
- }
- public boolean isRoot() {
- return isRoot;
+ // Check for any ClassBridge style of annotations.
+ ClassBridge classBridgeAnn = clazz.getAnnotation( ClassBridge.class );
+ if ( classBridgeAnn != null ) {
+ bindClassAnnotation( prefix, propertiesMetadata, classBridgeAnn, context );
+ }
+
+ // Get similarity
+ //TODO: similarity form @IndexedEmbedded are not taken care of. Exception??
+ if ( isRoot ) {
+ checkForSimilarity( clazz );
+ }
}
- public boolean allowFieldSelectionInProjection() {
- return allowFieldSelectionInProjection;
+ /**
+ * Check for field and method level annotations.
+ */
+ protected void initializeMemberLevelAnnotations(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot,
+ String prefix, Set<XClass> processedClasses, InitContext context) {
+ checkDocumentId( member, propertiesMetadata, isRoot, prefix, context );
+ checkForField( member, propertiesMetadata, prefix, context );
+ checkForFields( member, propertiesMetadata, prefix, context );
+ checkForAnalyzerDefs( member, context );
+ checkForIndexedEmbedded( member, propertiesMetadata, prefix, processedClasses, context );
+ checkForContainedIn( member, propertiesMetadata );
}
- private Analyzer getAnalyzer(XAnnotatedElement annotatedElement, InitContext context) {
+ protected Analyzer getAnalyzer(XAnnotatedElement annotatedElement, InitContext context) {
org.hibernate.search.annotations.Analyzer analyzerAnn =
annotatedElement.getAnnotation( org.hibernate.search.annotations.Analyzer.class );
return getAnalyzer( analyzerAnn, context );
}
- private Analyzer getAnalyzer(org.hibernate.search.annotations.Analyzer analyzerAnn, InitContext context) {
+ protected Analyzer getAnalyzer(org.hibernate.search.annotations.Analyzer analyzerAnn, InitContext context) {
Class analyzerClass = analyzerAnn == null ? void.class : analyzerAnn.impl();
if ( analyzerClass == void.class ) {
String definition = analyzerAnn == null ? "" : analyzerAnn.definition();
@@ -213,70 +230,6 @@
}
}
- private void initializeMembers(XClass clazz, PropertiesMetadata propertiesMetadata, boolean isRoot, String prefix,
- Set<XClass> processedClasses, InitContext context) {
- List<XClass> hierarchy = new ArrayList<XClass>();
- for ( XClass currClass = clazz; currClass != null; currClass = currClass.getSuperclass() ) {
- hierarchy.add( currClass );
- }
- for ( int index = hierarchy.size() - 1; index >= 0; index-- ) {
- XClass currClass = hierarchy.get( index );
- /*
- * Override the default analyzer for the properties if the class hold one
- * That's the reason we go down the hierarchy
- */
- Analyzer analyzer = getAnalyzer( currClass, context );
-
- if ( analyzer != null ) {
- propertiesMetadata.analyzer = analyzer;
- }
- checkForAnalyzerDefs( currClass, context );
-
- // Check for any ClassBridges annotation.
- ClassBridges classBridgesAnn = currClass.getAnnotation( ClassBridges.class );
- if ( classBridgesAnn != null ) {
- ClassBridge[] cbs = classBridgesAnn.value();
- for ( ClassBridge cb : cbs ) {
- bindClassAnnotation( prefix, propertiesMetadata, cb, context );
- }
- }
-
- // Check for any ClassBridge style of annotations.
- ClassBridge classBridgeAnn = currClass.getAnnotation( ClassBridge.class );
- if ( classBridgeAnn != null ) {
- bindClassAnnotation( prefix, propertiesMetadata, classBridgeAnn, context );
- }
-
- //Get similarity
- //TODO: similarity form @IndexedEmbedded are not taken care of. Exception??
- if ( isRoot ) {
- checkForSimilarity( currClass );
- }
-
- // rejecting non properties (ie regular methods) because the object is loaded from Hibernate,
- // so indexing a non property does not make sense
- List<XProperty> methods = currClass.getDeclaredProperties( XClass.ACCESS_PROPERTY );
- for ( XProperty method : methods ) {
- initializeMember( method, propertiesMetadata, isRoot, prefix, processedClasses, context );
- }
-
- List<XProperty> fields = currClass.getDeclaredProperties( XClass.ACCESS_FIELD );
- for ( XProperty field : fields ) {
- initializeMember( field, propertiesMetadata, isRoot, prefix, processedClasses, context );
- }
- }
- }
-
- private void initializeMember(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot,
- String prefix, Set<XClass> processedClasses, InitContext context) {
- checkDocumentId( member, propertiesMetadata, isRoot, prefix, context );
- checkForField( member, propertiesMetadata, prefix, context );
- checkForFields( member, propertiesMetadata, prefix, context );
- checkForAnalyzerDefs( member, context );
- checkForIndexedEmbedded( member, propertiesMetadata, prefix, processedClasses, context );
- checkForContainedIn( member, propertiesMetadata );
- }
-
private void checkForAnalyzerDefs(XAnnotatedElement annotatedElement, InitContext context) {
AnalyzerDefs defs = annotatedElement.getAnnotation( AnalyzerDefs.class );
if ( defs != null ) {
@@ -288,10 +241,8 @@
context.addAnalyzerDef( def );
}
- public String getIdentifierName() {
- return idGetter.getName();
- }
+
public Similarity getSimilarity() {
return similarity;
}
@@ -414,89 +365,13 @@
}
}
- private void checkDocumentId(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot, String prefix, InitContext context) {
- Annotation idAnnotation = getIdAnnotation( member, context );
- if ( idAnnotation != null ) {
- String attributeName = getIdAttributeName( member, idAnnotation );
- if ( isRoot ) {
- if ( idKeywordName != null && explicitDocumentId ) {
- throw new AssertionFailure(
- "Two document id assigned: "
- + idKeywordName + " and " + attributeName
- );
- }
- idKeywordName = prefix + attributeName;
- FieldBridge fieldBridge = BridgeFactory.guessType( null, member, reflectionManager );
- if ( fieldBridge instanceof TwoWayFieldBridge ) {
- idBridge = ( TwoWayFieldBridge ) fieldBridge;
- }
- else {
- throw new SearchException(
- "Bridge for document id does not implement TwoWayFieldBridge: " + member.getName()
- );
- }
- idBoost = getBoost( member, null );
- ReflectionHelper.setAccessible( member );
- idGetter = member;
- }
- else {
- //component should index their document id
- ReflectionHelper.setAccessible( member );
- propertiesMetadata.fieldGetters.add( member );
- String fieldName = prefix + attributeName;
- propertiesMetadata.fieldNames.add( fieldName );
- propertiesMetadata.fieldStore.add( getStore( Store.YES ) );
- propertiesMetadata.fieldIndex.add( getIndex( Index.UN_TOKENIZED ) );
- propertiesMetadata.fieldTermVectors.add( getTermVector( TermVector.NO ) );
- propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( null, member, reflectionManager ) );
- propertiesMetadata.fieldBoosts.add( getBoost( member, null ) );
- // property > entity analyzer (no field analyzer)
- Analyzer analyzer = getAnalyzer( member, context );
- if ( analyzer == null ) {
- analyzer = propertiesMetadata.analyzer;
- }
- if ( analyzer == null ) {
- throw new AssertionFailure( "Analizer should not be undefined" );
- }
- this.analyzer.addScopedAnalyzer( fieldName, analyzer );
- }
- }
- }
-
- /**
- * Checks whether the specified property contains an annotation used as document id.
- * This can either be an explicit <code>@DocumentId</code> or if no <code>@DocumentId</code> is specified a
- * JPA <code>@Id</code> annotation. The check for the JPA annotation is indirectly to avoid a hard dependency
- * to Hibernate Annotations.
- *
- * @param member the property to check for the id annotation.
- * @param context Handle to default configuration settings.
- *
- * @return the annotation used as document id or <code>null</code> if id annotation is specified on the property.
- */
- private Annotation getIdAnnotation(XProperty member, InitContext context) {
- // check for explicit DocumentId
+ protected void checkDocumentId(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot, String prefix, InitContext context) {
Annotation documentIdAnn = member.getAnnotation( DocumentId.class );
if ( documentIdAnn != null ) {
- explicitDocumentId = true;
- return documentIdAnn;
+ log.warn(
+ "@DocumentId specified on an entity which is not indexed by itself. Annotation gets ignored. Use @Field instead."
+ );
}
-
- // check for JPA @Id
- if ( !explicitDocumentId && context.isJpaPresent() ) {
- Class idClass;
- try {
- idClass = org.hibernate.util.ReflectHelper.classForName( "javax.persistence.Id", InitContext.class );
- }
- catch ( ClassNotFoundException e ) {
- throw new SearchException( "Unable to load @Id.class even though it should be present ?!" );
- }
- documentIdAnn = member.getAnnotation( idClass );
- if ( documentIdAnn != null ) {
- log.debug( "Found JPA id and using it as document id" );
- }
- }
- return documentIdAnn;
}
/**
@@ -508,7 +383,7 @@
*
* @return property name to be used as document id.
*/
- private String getIdAttributeName(XProperty member, Annotation idAnnotation) {
+ protected String getIdAttributeName(XProperty member, Annotation idAnnotation) {
String name = null;
try {
Method m = idAnnotation.getClass().getMethod( "name" );
@@ -562,7 +437,7 @@
}
}
- private Float getBoost(XProperty member, org.hibernate.search.annotations.Field fieldAnn) {
+ protected Float getBoost(XProperty member, org.hibernate.search.annotations.Field fieldAnn) {
float computedBoost = 1.0f;
Boost boostAnn = member.getAnnotation( Boost.class );
if ( boostAnn != null ) {
@@ -586,7 +461,7 @@
return localPrefix;
}
- private Field.Store getStore(Store store) {
+ protected Field.Store getStore(Store store) {
switch ( store ) {
case NO:
return Field.Store.NO;
@@ -599,7 +474,7 @@
}
}
- private Field.TermVector getTermVector(TermVector vector) {
+ protected Field.TermVector getTermVector(TermVector vector) {
switch ( vector ) {
case NO:
return Field.TermVector.NO;
@@ -616,7 +491,7 @@
}
}
- private Field.Index getIndex(Index index) {
+ protected Field.Index getIndex(Index index) {
switch ( index ) {
case NO:
return Field.Index.NO;
@@ -631,7 +506,7 @@
}
}
- private Float getBoost(XClass element) {
+ protected Float getBoost(XClass element) {
if ( element == null ) {
return null;
}
@@ -653,7 +528,7 @@
}
}
- protected void processContainedIn(Object instance, List<LuceneWork> queue, PropertiesMetadata metadata, SearchFactoryImplementor searchFactoryImplementor) {
+ private void processContainedIn(Object instance, List<LuceneWork> queue, PropertiesMetadata metadata, SearchFactoryImplementor searchFactoryImplementor) {
for ( int i = 0; i < metadata.containedInGetters.size(); i++ ) {
XMember member = metadata.containedInGetters.get( i );
Object value = ReflectionHelper.getMemberValue( instance, member );
@@ -665,12 +540,16 @@
for ( Object arrayValue : ( Object[] ) value ) {
//highly inneficient but safe wrt the actual targeted class
Class<?> valueClass = Hibernate.getClass( arrayValue );
- DocumentBuilderIndexedEntity<?> builderIndexedEntity = searchFactoryImplementor.getDocumentBuilderIndexedEntity( valueClass );
+ DocumentBuilderIndexedEntity<?> builderIndexedEntity = searchFactoryImplementor.getDocumentBuilderIndexedEntity(
+ valueClass
+ );
if ( builderIndexedEntity == null ) {
continue;
}
- processContainedInValue( arrayValue, queue, valueClass,
- builderIndexedEntity, searchFactoryImplementor );
+ processContainedInValue(
+ arrayValue, queue, valueClass,
+ builderIndexedEntity, searchFactoryImplementor
+ );
}
}
else if ( member.isCollection() ) {
@@ -685,17 +564,23 @@
for ( Object collectionValue : collection ) {
//highly inneficient but safe wrt the actual targeted class
Class<?> valueClass = Hibernate.getClass( collectionValue );
- DocumentBuilderIndexedEntity<?> builderIndexedEntity = searchFactoryImplementor.getDocumentBuilderIndexedEntity( valueClass );
+ DocumentBuilderIndexedEntity<?> builderIndexedEntity = searchFactoryImplementor.getDocumentBuilderIndexedEntity(
+ valueClass
+ );
if ( builderIndexedEntity == null ) {
continue;
}
- processContainedInValue( collectionValue, queue, valueClass,
- builderIndexedEntity, searchFactoryImplementor );
+ processContainedInValue(
+ collectionValue, queue, valueClass,
+ builderIndexedEntity, searchFactoryImplementor
+ );
}
}
else {
Class<?> valueClass = Hibernate.getClass( value );
- DocumentBuilderIndexedEntity<?> builderIndexedEntity = searchFactoryImplementor.getDocumentBuilderIndexedEntity( valueClass );
+ DocumentBuilderIndexedEntity<?> builderIndexedEntity = searchFactoryImplementor.getDocumentBuilderIndexedEntity(
+ valueClass
+ );
if ( builderIndexedEntity == null ) {
continue;
}
@@ -712,211 +597,10 @@
builderIndexedEntity.addWorkToQueue( valueClass, value, id, WorkType.UPDATE, queue, searchFactoryImplementor );
}
- public Document getDocument(T instance, Serializable id) {
- Document doc = new Document();
- final Class<?> entityType = Hibernate.getClass( instance );
- //XClass instanceClass = reflectionManager.toXClass( entityType );
- if ( metadata.boost != null ) {
- doc.setBoost( metadata.boost );
- }
- {
- Field classField =
- new Field(
- CLASS_FIELDNAME,
- entityType.getName(),
- Field.Store.YES,
- Field.Index.NOT_ANALYZED,
- Field.TermVector.NO
- );
- doc.add( classField );
- LuceneOptions luceneOptions = new LuceneOptionsImpl(
- Field.Store.YES,
- Field.Index.NOT_ANALYZED, Field.TermVector.NO, idBoost
- );
- idBridge.set( idKeywordName, id, doc, luceneOptions );
- }
- buildDocumentFields( instance, doc, metadata );
- return doc;
- }
-
- private void buildDocumentFields(Object instance, Document doc, PropertiesMetadata propertiesMetadata) {
- if ( instance == null ) {
- return;
- }
- //needed for field access: I cannot work in the proxied version
- Object unproxiedInstance = unproxy( instance );
- for ( int i = 0; i < propertiesMetadata.classBridges.size(); i++ ) {
- FieldBridge fb = propertiesMetadata.classBridges.get( i );
- fb.set(
- propertiesMetadata.classNames.get( i ), unproxiedInstance,
- doc, propertiesMetadata.getClassLuceneOptions( i )
- );
- }
- for ( int i = 0; i < propertiesMetadata.fieldNames.size(); i++ ) {
- XMember member = propertiesMetadata.fieldGetters.get( i );
- Object value = ReflectionHelper.getMemberValue( unproxiedInstance, member );
- propertiesMetadata.fieldBridges.get( i ).set(
- propertiesMetadata.fieldNames.get( i ), value, doc,
- propertiesMetadata.getFieldLuceneOptions( i )
- );
- }
- for ( int i = 0; i < propertiesMetadata.embeddedGetters.size(); i++ ) {
- XMember member = propertiesMetadata.embeddedGetters.get( i );
- Object value = ReflectionHelper.getMemberValue( unproxiedInstance, member );
- //TODO handle boost at embedded level: already stored in propertiesMedatada.boost
-
- if ( value == null ) {
- continue;
- }
- PropertiesMetadata embeddedMetadata = propertiesMetadata.embeddedPropertiesMetadata.get( i );
- switch ( propertiesMetadata.embeddedContainers.get( i ) ) {
- case ARRAY:
- for ( Object arrayValue : ( Object[] ) value ) {
- buildDocumentFields( arrayValue, doc, embeddedMetadata );
- }
- break;
- case COLLECTION:
- for ( Object collectionValue : ( Collection ) value ) {
- buildDocumentFields( collectionValue, doc, embeddedMetadata );
- }
- break;
- case MAP:
- for ( Object collectionValue : ( ( Map ) value ).values() ) {
- buildDocumentFields( collectionValue, doc, embeddedMetadata );
- }
- break;
- case OBJECT:
- buildDocumentFields( value, doc, embeddedMetadata );
- break;
- default:
- throw new AssertionFailure(
- "Unknown embedded container: "
- + propertiesMetadata.embeddedContainers.get( i )
- );
- }
- }
- }
-
- private Object unproxy(Object value) {
- //FIXME this service should be part of Core?
- if ( value instanceof HibernateProxy ) {
- // .getImplementation() initializes the data by side effect
- value = ( ( HibernateProxy ) value ).getHibernateLazyInitializer()
- .getImplementation();
- }
- return value;
- }
-
- public Term getTerm(Serializable id) {
- if ( idProvided ) {
- return new Term( idKeywordName, ( String ) id );
- }
-
- return new Term( idKeywordName, idBridge.objectToString( id ) );
- }
-
public Analyzer getAnalyzer() {
return analyzer;
}
- public TwoWayFieldBridge getIdBridge() {
- return idBridge;
- }
-
- public String getIdKeywordName() {
- return idKeywordName;
- }
-
- public static Class getDocumentClass(Document document) {
- String className = document.get( CLASS_FIELDNAME );
- try {
- return ReflectHelper.classForName( className );
- }
- catch ( ClassNotFoundException e ) {
- throw new SearchException( "Unable to load indexed class: " + className, e );
- }
- }
-
- public static Serializable getDocumentId(SearchFactoryImplementor searchFactoryImplementor, Class<?> clazz, Document document) {
- DocumentBuilderIndexedEntity<?> builderIndexedEntity = searchFactoryImplementor.getDocumentBuilderIndexedEntity( clazz );
- if ( builderIndexedEntity == null ) {
- throw new SearchException( "No Lucene configuration set up for: " + clazz.getName() );
- }
- return ( Serializable ) builderIndexedEntity.getIdBridge().get( builderIndexedEntity.getIdKeywordName(), document );
- }
-
- public static Object[] getDocumentFields(SearchFactoryImplementor searchFactoryImplementor, Class<?> clazz, Document document, String[] fields) {
- DocumentBuilderIndexedEntity<?> builderIndexedEntity = searchFactoryImplementor.getDocumentBuilderIndexedEntity( clazz );
- if ( builderIndexedEntity == null ) {
- throw new SearchException( "No Lucene configuration set up for: " + clazz.getName() );
- }
- final int fieldNbr = fields.length;
- Object[] result = new Object[fieldNbr];
-
- if ( builderIndexedEntity.idKeywordName != null ) {
- populateResult( builderIndexedEntity.idKeywordName, builderIndexedEntity.idBridge, Field.Store.YES, fields, result, document );
- }
-
- final PropertiesMetadata metadata = builderIndexedEntity.metadata;
- processFieldsForProjection( metadata, fields, result, document );
- return result;
- }
-
- private static void processFieldsForProjection(PropertiesMetadata metadata, String[] fields, Object[] result, Document document) {
- final int nbrFoEntityFields = metadata.fieldNames.size();
- for ( int index = 0; index < nbrFoEntityFields; index++ ) {
- populateResult(
- metadata.fieldNames.get( index ),
- metadata.fieldBridges.get( index ),
- metadata.fieldStore.get( index ),
- fields,
- result,
- document
- );
- }
- final int nbrOfEmbeddedObjects = metadata.embeddedPropertiesMetadata.size();
- for ( int index = 0; index < nbrOfEmbeddedObjects; index++ ) {
- //there is nothing we can do for collections
- if ( metadata.embeddedContainers.get( index ) == PropertiesMetadata.Container.OBJECT ) {
- processFieldsForProjection(
- metadata.embeddedPropertiesMetadata.get( index ), fields, result, document
- );
- }
- }
- }
-
- private static void populateResult(String fieldName, FieldBridge fieldBridge, Field.Store store,
- String[] fields, Object[] result, Document document) {
- int matchingPosition = getFieldPosition( fields, fieldName );
- if ( matchingPosition != -1 ) {
- //TODO make use of an isTwoWay() method
- if ( store != Field.Store.NO && TwoWayFieldBridge.class.isAssignableFrom( fieldBridge.getClass() ) ) {
- result[matchingPosition] = ( ( TwoWayFieldBridge ) fieldBridge ).get( fieldName, document );
- if ( log.isTraceEnabled() ) {
- log.trace( "Field {} projected as {}", fieldName, result[matchingPosition] );
- }
- }
- else {
- if ( store == Field.Store.NO ) {
- throw new SearchException( "Projecting an unstored field: " + fieldName );
- }
- else {
- throw new SearchException( "FieldBridge is not a TwoWayFieldBridge: " + fieldBridge.getClass() );
- }
- }
- }
- }
-
- private static int getFieldPosition(String[] fields, String fieldName) {
- int fieldNbr = fields.length;
- for ( int index = 0; index < fieldNbr; index++ ) {
- if ( fieldName.equals( fields[index] ) ) {
- return index;
- }
- }
- return -1;
- }
-
public void postInitialize(Set<Class<?>> indexedClasses) {
if ( entityState == EntityState.NON_INDEXABLE ) {
throw new AssertionFailure( "A non indexed entity is post processed" );
@@ -952,14 +636,6 @@
}
/**
- * Make sure to return false if there is a risk of composite id
- * if composite id, use of (a, b) in ((1,2), (3,4)) fails on most database
- */
- public boolean isSafeFromTupleId() {
- return safeFromTupleId;
- }
-
- /**
* Wrapper class containing all the meta data extracted out of the entities.
*/
protected static class PropertiesMetadata {
Modified: search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java 2008-11-25 12:56:25 UTC (rev 15610)
+++ search/trunk/src/java/org/hibernate/search/engine/DocumentBuilderIndexedEntity.java 2008-11-25 13:10:25 UTC (rev 15611)
@@ -2,28 +2,51 @@
package org.hibernate.search.engine;
import java.io.Serializable;
+import java.lang.annotation.Annotation;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
+import java.util.Map;
+import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+import org.apache.lucene.index.Term;
+import org.slf4j.Logger;
+import org.hibernate.Hibernate;
import org.hibernate.annotations.common.AssertionFailure;
import org.hibernate.annotations.common.reflection.ReflectionManager;
import org.hibernate.annotations.common.reflection.XClass;
+import org.hibernate.annotations.common.reflection.XMember;
+import org.hibernate.annotations.common.reflection.XProperty;
+import org.hibernate.annotations.common.util.ReflectHelper;
+import org.hibernate.proxy.HibernateProxy;
import org.hibernate.search.SearchException;
+import org.hibernate.search.annotations.DocumentId;
+import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.ProvidedId;
+import org.hibernate.search.annotations.Store;
+import org.hibernate.search.annotations.TermVector;
import org.hibernate.search.backend.AddLuceneWork;
import org.hibernate.search.backend.DeleteLuceneWork;
import org.hibernate.search.backend.LuceneWork;
import org.hibernate.search.backend.PurgeAllLuceneWork;
import org.hibernate.search.backend.WorkType;
import org.hibernate.search.bridge.BridgeFactory;
+import org.hibernate.search.bridge.FieldBridge;
+import org.hibernate.search.bridge.LuceneOptions;
+import org.hibernate.search.bridge.TwoWayFieldBridge;
+import org.hibernate.search.bridge.TwoWayString2FieldBridgeAdaptor;
+import org.hibernate.search.bridge.TwoWayStringBridge;
import org.hibernate.search.impl.InitContext;
import org.hibernate.search.store.DirectoryProvider;
import org.hibernate.search.store.IndexShardingStrategy;
+import org.hibernate.search.util.LoggerFactory;
+import org.hibernate.search.util.ReflectionHelper;
/**
- * Set up and provide a manager for indexed classes.
+ * Set up and provide a manager for classes which are directly annotated with <code>@Indexed</code>.
*
* @author Gavin King
* @author Emmanuel Bernard
@@ -32,15 +55,71 @@
* @author Hardy Ferentschik
*/
public class DocumentBuilderIndexedEntity<T> extends DocumentBuilderContainedEntity<T> {
+ private static final Logger log = LoggerFactory.make();
+ /**
+ * Arrays of directory providers for the underlying Lucene indexes of the indexed entity.
+ */
private final DirectoryProvider[] directoryProviders;
+
+ /**
+ * The sharding strategy used for the indexed entity.
+ */
private final IndexShardingStrategy shardingStrategy;
/**
- * Constructor used on an @Indexed entity.
+ * Flag indicating whether <code>@DocumentId</code> was explicitly specified.
*/
+ private boolean explicitDocumentId = false;
+
+ /**
+ * Flag indicating whether {@link org.apache.lucene.search.Searcher#doc(int, org.apache.lucene.document.FieldSelector)}
+ * can be used in order to retrieve documents. This is only safe to do if we know that
+ * all involved bridges are implementing <code>TwoWayStringBridge</code>. See HSEARCH-213.
+ */
+ private boolean allowFieldSelectionInProjection = false;
+
+ /**
+ * The class member used as document id.
+ */
+ protected XMember idGetter;
+
+ /**
+ * Name of the document id field.
+ */
+ protected String idKeywordName;
+
+ /**
+ * Boost specified on the document id.
+ */
+ private Float idBoost;
+
+ /**
+ * The bridge used for the document id.
+ */
+ private TwoWayFieldBridge idBridge;
+
+ /**
+ * Flag indicating whether there is an explicit id (@DocumentId or @Id) or not. When Search is used as make
+ * for example JBoss Cache searchable the <code>idKeywordName</code> wil be provided.
+ */
+ private boolean idProvided = false;
+
+
+ //if composite id, use of (a, b) in ((1,2), (3,4)) fails on most database
+ private boolean safeFromTupleId;
+
+ /**
+ * Creates a document builder for entities annotated with <code>@Indexed</code>.
+ *
+ * @param clazz The class for which to build a <code>DocumentBuilderContainedEntity</code>.
+ * @param context Handle to default configuration settings.
+ * @param directoryProviders Arrays of directory providers for the underlying Lucene indexes of the indexed entity.
+ * @param shardingStrategy The sharding strategy used for the indexed entity.
+ * @param reflectionManager Reflection manager to use for processing the annotations.
+ */
public DocumentBuilderIndexedEntity(XClass clazz, InitContext context, DirectoryProvider[] directoryProviders,
- IndexShardingStrategy shardingStrategy, ReflectionManager reflectionManager) {
+ IndexShardingStrategy shardingStrategy, ReflectionManager reflectionManager) {
super( clazz, context, reflectionManager );
@@ -60,6 +139,111 @@
}
}
+ protected void init(XClass clazz, InitContext context) {
+ super.init( clazz, context );
+
+ //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 = entityState != EntityState.INDEXED || TwoWayString2FieldBridgeAdaptor.class.isAssignableFrom(
+ idBridge.getClass()
+ );
+
+ checkAllowFieldSelection();
+ if ( log.isDebugEnabled() ) {
+ log.debug(
+ "Field selection in projections is set to {} for entity {}.",
+ allowFieldSelectionInProjection,
+ clazz.getName()
+ );
+ }
+ }
+
+
+ protected void checkDocumentId(XProperty member, PropertiesMetadata propertiesMetadata, boolean isRoot, String prefix, InitContext context) {
+ Annotation idAnnotation = getIdAnnotation( member, context );
+ if ( idAnnotation != null ) {
+ String attributeName = getIdAttributeName( member, idAnnotation );
+ if ( isRoot ) {
+ if ( idKeywordName != null && explicitDocumentId ) {
+ throw new AssertionFailure(
+ "Two document id assigned: "
+ + idKeywordName + " and " + attributeName
+ );
+ }
+ idKeywordName = prefix + attributeName;
+ FieldBridge fieldBridge = BridgeFactory.guessType( null, member, reflectionManager );
+ if ( fieldBridge instanceof TwoWayFieldBridge ) {
+ idBridge = ( TwoWayFieldBridge ) fieldBridge;
+ }
+ else {
+ throw new SearchException(
+ "Bridge for document id does not implement TwoWayFieldBridge: " + member.getName()
+ );
+ }
+ idBoost = getBoost( member, null );
+ ReflectionHelper.setAccessible( member );
+ idGetter = member;
+ }
+ else {
+ //component should index their document id
+ ReflectionHelper.setAccessible( member );
+ propertiesMetadata.fieldGetters.add( member );
+ String fieldName = prefix + attributeName;
+ propertiesMetadata.fieldNames.add( fieldName );
+ propertiesMetadata.fieldStore.add( getStore( Store.YES ) );
+ propertiesMetadata.fieldIndex.add( getIndex( Index.UN_TOKENIZED ) );
+ propertiesMetadata.fieldTermVectors.add( getTermVector( TermVector.NO ) );
+ propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( null, member, reflectionManager ) );
+ propertiesMetadata.fieldBoosts.add( getBoost( member, null ) );
+ // property > entity analyzer (no field analyzer)
+ Analyzer analyzer = getAnalyzer( member, context );
+ if ( analyzer == null ) {
+ analyzer = propertiesMetadata.analyzer;
+ }
+ if ( analyzer == null ) {
+ throw new AssertionFailure( "Analizer should not be undefined" );
+ }
+ this.analyzer.addScopedAnalyzer( fieldName, analyzer );
+ }
+ }
+ }
+
+ /**
+ * Checks whether the specified property contains an annotation used as document id.
+ * This can either be an explicit <code>@DocumentId</code> or if no <code>@DocumentId</code> is specified a
+ * JPA <code>@Id</code> annotation. The check for the JPA annotation is indirectly to avoid a hard dependency
+ * to Hibernate Annotations.
+ *
+ * @param member the property to check for the id annotation.
+ * @param context Handle to default configuration settings.
+ *
+ * @return the annotation used as document id or <code>null</code> if id annotation is specified on the property.
+ */
+ private Annotation getIdAnnotation(XProperty member, InitContext context) {
+ // check for explicit DocumentId
+ Annotation documentIdAnn = member.getAnnotation( DocumentId.class );
+ if ( documentIdAnn != null ) {
+ explicitDocumentId = true;
+ return documentIdAnn;
+ }
+
+ // check for JPA @Id
+ if ( !explicitDocumentId && context.isJpaPresent() ) {
+ Class idClass;
+ try {
+ idClass = org.hibernate.util.ReflectHelper.classForName( "javax.persistence.Id", InitContext.class );
+ }
+ catch ( ClassNotFoundException e ) {
+ throw new SearchException( "Unable to load @Id.class even though it should be present ?!" );
+ }
+ documentIdAnn = member.getAnnotation( idClass );
+ if ( documentIdAnn != null ) {
+ log.debug( "Found JPA id and using it as document id" );
+ }
+ }
+ return documentIdAnn;
+ }
+
private ProvidedId findProvidedId(XClass clazz, ReflectionManager reflectionManager) {
ProvidedId id = null;
XClass currentClass = clazz;
@@ -141,9 +325,108 @@
throw new AssertionFailure( "Unknown WorkType: " + workType );
}
- super.addWorkToQueue(entityClass, entity, id, workType, queue, searchFactoryImplementor);
+ super.addWorkToQueue( entityClass, entity, id, workType, queue, searchFactoryImplementor );
}
+ public Document getDocument(T instance, Serializable id) {
+ Document doc = new Document();
+ final Class<?> entityType = Hibernate.getClass( instance );
+ //XClass instanceClass = reflectionManager.toXClass( entityType );
+ if ( metadata.boost != null ) {
+ doc.setBoost( metadata.boost );
+ }
+ {
+ Field classField =
+ new Field(
+ CLASS_FIELDNAME,
+ entityType.getName(),
+ Field.Store.YES,
+ Field.Index.NOT_ANALYZED,
+ Field.TermVector.NO
+ );
+ doc.add( classField );
+ LuceneOptions luceneOptions = new LuceneOptionsImpl(
+ Field.Store.YES,
+ Field.Index.NOT_ANALYZED, Field.TermVector.NO, idBoost
+ );
+ idBridge.set( idKeywordName, id, doc, luceneOptions );
+ }
+ buildDocumentFields( instance, doc, metadata );
+ return doc;
+ }
+
+ private void buildDocumentFields(Object instance, Document doc, PropertiesMetadata propertiesMetadata) {
+ if ( instance == null ) {
+ return;
+ }
+ //needed for field access: I cannot work in the proxied version
+ Object unproxiedInstance = unproxy( instance );
+ for ( int i = 0; i < propertiesMetadata.classBridges.size(); i++ ) {
+ FieldBridge fb = propertiesMetadata.classBridges.get( i );
+ fb.set(
+ propertiesMetadata.classNames.get( i ), unproxiedInstance,
+ doc, propertiesMetadata.getClassLuceneOptions( i )
+ );
+ }
+ for ( int i = 0; i < propertiesMetadata.fieldNames.size(); i++ ) {
+ XMember member = propertiesMetadata.fieldGetters.get( i );
+ Object value = ReflectionHelper.getMemberValue( unproxiedInstance, member );
+ propertiesMetadata.fieldBridges.get( i ).set(
+ propertiesMetadata.fieldNames.get( i ), value, doc,
+ propertiesMetadata.getFieldLuceneOptions( i )
+ );
+ }
+ for ( int i = 0; i < propertiesMetadata.embeddedGetters.size(); i++ ) {
+ XMember member = propertiesMetadata.embeddedGetters.get( i );
+ Object value = ReflectionHelper.getMemberValue( unproxiedInstance, member );
+ //TODO handle boost at embedded level: already stored in propertiesMedatada.boost
+
+ if ( value == null ) {
+ continue;
+ }
+ PropertiesMetadata embeddedMetadata = propertiesMetadata.embeddedPropertiesMetadata.get( i );
+ switch ( propertiesMetadata.embeddedContainers.get( i ) ) {
+ case ARRAY:
+ for ( Object arrayValue : ( Object[] ) value ) {
+ buildDocumentFields( arrayValue, doc, embeddedMetadata );
+ }
+ break;
+ case COLLECTION:
+ for ( Object collectionValue : ( Collection ) value ) {
+ buildDocumentFields( collectionValue, doc, embeddedMetadata );
+ }
+ break;
+ case MAP:
+ for ( Object collectionValue : ( ( Map ) value ).values() ) {
+ buildDocumentFields( collectionValue, doc, embeddedMetadata );
+ }
+ break;
+ case OBJECT:
+ buildDocumentFields( value, doc, embeddedMetadata );
+ break;
+ default:
+ throw new AssertionFailure(
+ "Unknown embedded container: "
+ + propertiesMetadata.embeddedContainers.get( i )
+ );
+ }
+ }
+ }
+
+ private Object unproxy(Object value) {
+ //FIXME this service should be part of Core?
+ if ( value instanceof HibernateProxy ) {
+ // .getImplementation() initializes the data by side effect
+ value = ( ( HibernateProxy ) value ).getHibernateLazyInitializer()
+ .getImplementation();
+ }
+ return value;
+ }
+
+ public String getIdentifierName() {
+ return idGetter.getName();
+ }
+
public DirectoryProvider[] getDirectoryProviders() {
if ( entityState != EntityState.INDEXED ) {
throw new AssertionFailure( "Contained in only entity: getDirectoryProvider should not have been called." );
@@ -159,4 +442,151 @@
}
return shardingStrategy;
}
+
+ public boolean allowFieldSelectionInProjection() {
+ return allowFieldSelectionInProjection;
+ }
+
+ /**
+ * @return <code>false</code> if there is a risk of composite id. If composite id, use of (a, b) in ((1,2), (3,4)) fails on most database
+ */
+ public boolean isSafeFromTupleId() {
+ return safeFromTupleId;
+ }
+
+ public Term getTerm(Serializable id) {
+ if ( idProvided ) {
+ return new Term( idKeywordName, ( String ) id );
+ }
+
+ return new Term( idKeywordName, idBridge.objectToString( id ) );
+ }
+
+ public TwoWayFieldBridge getIdBridge() {
+ return idBridge;
+ }
+
+ public static Class getDocumentClass(Document document) {
+ String className = document.get( CLASS_FIELDNAME );
+ try {
+ return ReflectHelper.classForName( className );
+ }
+ catch ( ClassNotFoundException e ) {
+ throw new SearchException( "Unable to load indexed class: " + className, e );
+ }
+ }
+
+ public String getIdKeywordName() {
+ return idKeywordName;
+ }
+
+ public static Serializable getDocumentId(SearchFactoryImplementor searchFactoryImplementor, Class<?> clazz, Document document) {
+ DocumentBuilderIndexedEntity<?> builderIndexedEntity = searchFactoryImplementor.getDocumentBuilderIndexedEntity(
+ clazz
+ );
+ if ( builderIndexedEntity == null ) {
+ throw new SearchException( "No Lucene configuration set up for: " + clazz.getName() );
+ }
+ return ( Serializable ) builderIndexedEntity.getIdBridge()
+ .get( builderIndexedEntity.getIdKeywordName(), document );
+ }
+
+ public static Object[] getDocumentFields(SearchFactoryImplementor searchFactoryImplementor, Class<?> clazz, Document document, String[] fields) {
+ DocumentBuilderIndexedEntity<?> builderIndexedEntity = searchFactoryImplementor.getDocumentBuilderIndexedEntity(
+ clazz
+ );
+ if ( builderIndexedEntity == null ) {
+ throw new SearchException( "No Lucene configuration set up for: " + clazz.getName() );
+ }
+ final int fieldNbr = fields.length;
+ Object[] result = new Object[fieldNbr];
+
+ if ( builderIndexedEntity.idKeywordName != null ) {
+ populateResult(
+ builderIndexedEntity.idKeywordName,
+ builderIndexedEntity.idBridge,
+ Field.Store.YES,
+ fields,
+ result,
+ document
+ );
+ }
+
+ final PropertiesMetadata metadata = builderIndexedEntity.metadata;
+ processFieldsForProjection( metadata, fields, result, document );
+ return result;
+ }
+
+ private static void populateResult(String fieldName, FieldBridge fieldBridge, Field.Store store,
+ String[] fields, Object[] result, Document document) {
+ int matchingPosition = getFieldPosition( fields, fieldName );
+ if ( matchingPosition != -1 ) {
+ //TODO make use of an isTwoWay() method
+ if ( store != Field.Store.NO && TwoWayFieldBridge.class.isAssignableFrom( fieldBridge.getClass() ) ) {
+ result[matchingPosition] = ( ( TwoWayFieldBridge ) fieldBridge ).get( fieldName, document );
+ if ( log.isTraceEnabled() ) {
+ log.trace( "Field {} projected as {}", fieldName, result[matchingPosition] );
+ }
+ }
+ else {
+ if ( store == Field.Store.NO ) {
+ throw new SearchException( "Projecting an unstored field: " + fieldName );
+ }
+ else {
+ throw new SearchException( "FieldBridge is not a TwoWayFieldBridge: " + fieldBridge.getClass() );
+ }
+ }
+ }
+ }
+
+ private static void processFieldsForProjection(PropertiesMetadata metadata, String[] fields, Object[] result, Document document) {
+ final int nbrFoEntityFields = metadata.fieldNames.size();
+ for ( int index = 0; index < nbrFoEntityFields; index++ ) {
+ populateResult(
+ metadata.fieldNames.get( index ),
+ metadata.fieldBridges.get( index ),
+ metadata.fieldStore.get( index ),
+ fields,
+ result,
+ document
+ );
+ }
+ final int nbrOfEmbeddedObjects = metadata.embeddedPropertiesMetadata.size();
+ for ( int index = 0; index < nbrOfEmbeddedObjects; index++ ) {
+ //there is nothing we can do for collections
+ if ( metadata.embeddedContainers.get( index ) == PropertiesMetadata.Container.OBJECT ) {
+ processFieldsForProjection(
+ metadata.embeddedPropertiesMetadata.get( index ), fields, result, document
+ );
+ }
+ }
+ }
+
+ private static int getFieldPosition(String[] fields, String fieldName) {
+ int fieldNbr = fields.length;
+ for ( int index = 0; index < fieldNbr; index++ ) {
+ if ( fieldName.equals( fields[index] ) ) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Checks whether all involved bridges are two way string bridges. If so we can optimize document retrieval
+ * by using <code>FieldSelector</code>. See HSEARCH-213.
+ */
+ private void checkAllowFieldSelection() {
+ allowFieldSelectionInProjection = true;
+ if ( !( idBridge instanceof TwoWayStringBridge || idBridge instanceof TwoWayString2FieldBridgeAdaptor ) ) {
+ allowFieldSelectionInProjection = false;
+ return;
+ }
+ for ( FieldBridge bridge : metadata.fieldBridges ) {
+ if ( !( bridge instanceof TwoWayStringBridge || bridge instanceof TwoWayString2FieldBridgeAdaptor ) ) {
+ allowFieldSelectionInProjection = false;
+ return;
+ }
+ }
+ }
}
16 years, 1 month
Hibernate SVN: r15610 - branches/Branch_3_2/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo.
by hibernate-commits@lists.jboss.org
Author: anthonyHib
Date: 2008-11-25 07:56:25 -0500 (Tue, 25 Nov 2008)
New Revision: 15610
Modified:
branches/Branch_3_2/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/EntityPOJOClass.java
Log:
HBX-524 : jpa fix
Modified: branches/Branch_3_2/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/EntityPOJOClass.java
===================================================================
--- branches/Branch_3_2/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/EntityPOJOClass.java 2008-11-25 09:05:02 UTC (rev 15609)
+++ branches/Branch_3_2/HibernateExt/tools/src/java/org/hibernate/tool/hbm2x/pojo/EntityPOJOClass.java 2008-11-25 12:56:25 UTC (rev 15610)
@@ -454,10 +454,13 @@
OneToOne oneToOne = (OneToOne)property.getValue();
if (oneToOne.isConstrained())
ab.addQuotedAttribute("mappedBy", getOneToOneMappedBy(cfg, oneToOne));
-
StringBuffer buffer = new StringBuffer(ab.getResult());
+ buffer.append(getHibernateCascadeTypeAnnotation(property));
+ if (!oneToOne.isConstrained()){
+ AnnotationBuilder ab1 = AnnotationBuilder.createAnnotation( importType("javax.persistence.PrimaryKeyJoinColumn") );
+ buffer.append(ab1.getResult());
+ }
- buffer.append(getHibernateCascadeTypeAnnotation(property));
return buffer.toString();
}
16 years, 1 month
Hibernate SVN: r15609 - search/trunk/src/java/org/hibernate/search/query.
by hibernate-commits@lists.jboss.org
Author: hardy.ferentschik
Date: 2008-11-25 04:05:02 -0500 (Tue, 25 Nov 2008)
New Revision: 15609
Modified:
search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java
Log:
HSEARCH-308
Made sure that only one top doc is retrieved when getResultSize() is called.
Modified: search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java
===================================================================
--- search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java 2008-11-24 16:27:32 UTC (rev 15608)
+++ search/trunk/src/java/org/hibernate/search/query/FullTextQueryImpl.java 2008-11-25 09:05:02 UTC (rev 15609)
@@ -144,7 +144,7 @@
return new IteratorImpl( Collections.EMPTY_LIST, noLoader );
}
try {
- QueryHits queryHits = getQueryHits( searcher );
+ QueryHits queryHits = getQueryHits( searcher, calculateTopDocsRetrievalSize() );
int first = first();
int max = max( first, queryHits.totalHits );
Session sess = ( Session ) this.session;
@@ -186,7 +186,10 @@
}
if ( criteria instanceof CriteriaImpl ) {
String targetEntity = ( ( CriteriaImpl ) criteria ).getEntityOrClassName();
- if ( targetedEntities.size() == 1 && !targetedEntities.iterator().next().getName().equals( targetEntity ) ) {
+ if ( targetedEntities.size() == 1 && !targetedEntities.iterator()
+ .next()
+ .getName()
+ .equals( targetEntity ) ) {
throw new SearchException( "Criteria query entity should match query entity" );
}
else {
@@ -228,7 +231,7 @@
IndexSearcher searcher = buildSearcher( searchFactory );
//FIXME: handle null searcher
try {
- QueryHits queryHits = getQueryHits( searcher );
+ QueryHits queryHits = getQueryHits( searcher, calculateTopDocsRetrievalSize() );
int first = first();
int max = max( first, queryHits.totalHits );
DocumentExtractor extractor = new DocumentExtractor(
@@ -264,7 +267,7 @@
return Collections.EMPTY_LIST;
}
try {
- QueryHits queryHits = getQueryHits( searcher );
+ QueryHits queryHits = getQueryHits( searcher, calculateTopDocsRetrievalSize() );
int first = first();
int max = max( first, queryHits.totalHits );
Session sess = ( Session ) this.session;
@@ -334,24 +337,40 @@
* Execute the lucene search and return the machting hits.
*
* @param searcher The index searcher.
+ * @param n Numer of documents to retrieve
*
* @return An instance of <code>QueryHits</code> wrapping the Lucene query and the matching documents.
*
* @throws IOException in case there is an error executing the lucene search.
*/
- private QueryHits getQueryHits(Searcher searcher) throws IOException {
+ private QueryHits getQueryHits(Searcher searcher, Integer n) throws IOException {
org.apache.lucene.search.Query query = filterQueryByClasses( luceneQuery );
buildFilters();
QueryHits queryHits;
- if ( maxResults == null ) { // try to make sure that we get the right amount of top docs
+ if ( n == null ) { // try to make sure that we get the right amount of top docs
queryHits = new QueryHits( searcher, query, filter, sort );
- } else {
- queryHits = new QueryHits( searcher, query, filter, sort, first() + maxResults );
}
+ else {
+ queryHits = new QueryHits( searcher, query, filter, sort, n );
+ }
resultSize = queryHits.totalHits;
return queryHits;
}
+ /**
+ * @return Calculates the number of <code>TopDocs</code> which should be retrieved as part of the query. If Hibernate's
+ * pagination parameters are set returned value is <code>first + maxResults</code>. Otherwise <code>null</code> is
+ * returned.
+ */
+ private Integer calculateTopDocsRetrievalSize() {
+ if ( maxResults == null ) {
+ return null;
+ }
+ else {
+ return first() + maxResults;
+ }
+ }
+
private void buildFilters() {
if ( filterDefinitions == null || filterDefinitions.size() == 0 ) {
return; // there is nothing to do if we don't have any filter definitions
@@ -719,7 +738,7 @@
else {
TopDocs hits;
try {
- hits = getQueryHits( searcher ).topDocs;
+ hits = getQueryHits( searcher, 1 ).topDocs; // Lucene enforces that at least one top doc will be retrieved.
resultSize = hits.totalHits;
}
catch ( IOException e ) {
16 years, 1 month