[hibernate-commits] Hibernate SVN: r17833 - in search/trunk/src/main/java/org/hibernate/search: sandbox and 1 other directories.
hibernate-commits at lists.jboss.org
hibernate-commits at lists.jboss.org
Sun Oct 25 14:30:03 EDT 2009
Author: epbernard
Date: 2009-10-25 14:30:03 -0400 (Sun, 25 Oct 2009)
New Revision: 17833
Added:
search/trunk/src/main/java/org/hibernate/search/sandbox/
search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/
search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/FullTextManager.java
search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/FullTextQuery.java
search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/InstanceTransactionContext.java
search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/LuceneFullTextManager.java
Log:
HSEARCH-407 Initial PoC start on a pure Lucene storage (ie not relying on Hibernate Core
Added: search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/FullTextManager.java
===================================================================
--- search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/FullTextManager.java (rev 0)
+++ search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/FullTextManager.java 2009-10-25 18:30:03 UTC (rev 17833)
@@ -0,0 +1,82 @@
+package org.hibernate.search.sandbox.standalone;
+
+import org.hibernate.search.*;
+
+import java.io.Serializable;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface FullTextManager {
+
+ /**
+ * Returns the entity instance of a given type and id value
+ */
+ public <T> T get(Class<T> entityType, Serializable id);
+
+ /**
+ * Create a fulltext query on top of a native Lucene query returning the matching objects
+ * of type <code>entities</code> and their respective subclasses.
+ *
+ * @param luceneQuery The native Lucene query to be rn against the Lucene index.
+ * @param entities List of classes for type filtering. The query result will only return entities of
+ * the specified types and their respective subtype. If no class is specified no type filtering will take place.
+ *
+ * @return A <code>FullTextQuery</code> wrapping around the native Lucene wuery.
+ *
+ * @throws IllegalArgumentException if entityType is <code>null</code> or not a class or superclass annotated with <code>@Indexed</code>.
+ */
+ FullTextQuery createFullTextQuery(org.apache.lucene.search.Query luceneQuery, Class<?>... entities);
+
+ /**
+ * Force the (re)indexing of a given <b>managed</b> object.
+ * Indexation is batched per transaction: if a transaction is active, the operation
+ * will not affect the index at least until commit.
+ *
+ * @param entity The entity to index - must not be <code>null</code>.
+ *
+ * @throws IllegalArgumentException if entity is null or not an @Indexed entity
+ */
+ <T> void index(T entity);
+
+ /**
+ * @return the <code>SearchFactory</code> instance.
+ */
+ SearchFactory getSearchFactory();
+
+ /**
+ * Remove the entity with the type <code>entityType</code> and the identifier <code>id</code> from the index.
+ * If <code>id == null</code> all indexed entities of this type and its indexed subclasses are deleted. In this
+ * case this method behaves like {@link #purgeAll(Class)}.
+ *
+ * @param entityType The type of the entity to delete.
+ * @param id The id of the entity to delete.
+ *
+ * @throws IllegalArgumentException if entityType is <code>null</code> or not a class or superclass annotated with <code>@Indexed</code>.
+ */
+ public <T> void purge(Class<T> entityType, Serializable id);
+
+ /**
+ * Remove all entities from of particular class and all its subclasses from the index.
+ *
+ * @param entityType The class of the entities to remove.
+ *
+ * @throws IllegalArgumentException if entityType is <code>null</code> or not a class or superclass annotated with <code>@Indexed</code>.
+ */
+ public <T> void purgeAll(Class<T> entityType);
+
+ /**
+ * Flush all index changes forcing Hibernate Search to apply all changes to the index not waiting for the batch limit.
+ */
+ public void flushToIndexes();
+
+ //FIXME add support for mass indexer: does it even makes sense?
+ /**
+ * Creates a MassIndexer to rebuild the indexes of some
+ * or all indexed entity types.
+ * Instances cannot be reused.
+ * @param types optionally restrict the operation to selected types
+ * @return
+ */
+ //public MassIndexer createIndexer(Class<?>... types);
+}
Added: search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/FullTextQuery.java
===================================================================
--- search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/FullTextQuery.java (rev 0)
+++ search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/FullTextQuery.java 2009-10-25 18:30:03 UTC (rev 17833)
@@ -0,0 +1,10 @@
+package org.hibernate.search.sandbox.standalone;
+
+import java.util.List;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public interface FullTextQuery {
+ List<?> list();
+}
Added: search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/InstanceTransactionContext.java
===================================================================
--- search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/InstanceTransactionContext.java (rev 0)
+++ search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/InstanceTransactionContext.java 2009-10-25 18:30:03 UTC (rev 17833)
@@ -0,0 +1,80 @@
+package org.hibernate.search.sandbox.standalone;
+
+import org.hibernate.search.backend.TransactionContext;
+
+import javax.transaction.Synchronization;
+import javax.transaction.Status;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Transaction context that contains transaction boundaries methods.
+ * While not "transactional" it allows to call Synchronization elements
+ *
+ * @author Emmanuel Bernard
+ */
+public class InstanceTransactionContext implements TransactionContext {
+ private State transactionState = State.NO_TRANSACTION;
+ private final List<Synchronization> synchronizations = new ArrayList<Synchronization>(5);
+
+ public void beginTransaction() {
+ if (transactionState != State.NO_TRANSACTION) {
+ throw new IllegalStateException( "Transaction context already started: " + transactionState);
+ }
+ transactionState = State.IN_TRANSACTION;
+ }
+
+ public void commit() {
+ if ( transactionState != State.IN_TRANSACTION ) {
+ throw new IllegalStateException( "Transaction context not in active state: " + transactionState);
+ }
+ try {
+ for (Synchronization sync : synchronizations) {
+ sync.beforeCompletion();
+ }
+ for (Synchronization sync : synchronizations) {
+ sync.afterCompletion( Status.STATUS_COMMITTED );
+ }
+ }
+ finally {
+ synchronizations.clear();
+ transactionState = State.TRANSACTION_CLOSED;
+ }
+ }
+
+ public void rollback() {
+ if ( transactionState != State.IN_TRANSACTION ) {
+ throw new IllegalStateException( "Transaction context not in active state: " + transactionState);
+ }
+ try {
+ for (Synchronization sync : synchronizations) {
+ sync.beforeCompletion();
+ }
+ for (Synchronization sync : synchronizations) {
+ sync.afterCompletion( Status.STATUS_ROLLEDBACK );
+ }
+ }
+ finally {
+ synchronizations.clear();
+ transactionState = State.TRANSACTION_CLOSED;
+ }
+ }
+
+ public boolean isTransactionInProgress() {
+ return transactionState == State.IN_TRANSACTION;
+ }
+
+ public Object getTransactionIdentifier() {
+ return this;
+ }
+
+ public void registerSynchronization(Synchronization synchronization) {
+ synchronizations.add( synchronization );
+ }
+
+ private static enum State {
+ NO_TRANSACTION,
+ IN_TRANSACTION,
+ TRANSACTION_CLOSED
+ }
+}
Added: search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/LuceneFullTextManager.java
===================================================================
--- search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/LuceneFullTextManager.java (rev 0)
+++ search/trunk/src/main/java/org/hibernate/search/sandbox/standalone/LuceneFullTextManager.java 2009-10-25 18:30:03 UTC (rev 17833)
@@ -0,0 +1,140 @@
+package org.hibernate.search.sandbox.standalone;
+
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.BooleanQuery;
+import org.apache.lucene.search.BooleanClause;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.index.Term;
+import org.hibernate.search.MassIndexer;
+import org.hibernate.search.SearchFactory;
+import org.hibernate.search.ProjectionConstants;
+import org.hibernate.search.SearchException;
+import org.hibernate.search.backend.Work;
+import org.hibernate.search.backend.WorkType;
+import org.hibernate.search.engine.DocumentBuilderIndexedEntity;
+import org.hibernate.search.engine.SearchFactoryImplementor;
+
+import java.io.Serializable;
+import java.util.Set;
+import java.util.List;
+
+/**
+ * Implements a standalone full text service.
+ * Data is stored in Lucene
+ *
+ * @author Emmanuel Bernard
+ */
+public class LuceneFullTextManager implements FullTextManager {
+ private final SearchFactoryImplementor searchFactory;
+ private final InstanceTransactionContext transactionContext;
+
+ LuceneFullTextManager(SearchFactoryImplementor sfi) {
+ this.searchFactory = sfi;
+ this.transactionContext = new InstanceTransactionContext();
+ transactionContext.beginTransaction();
+ }
+
+ public <T> T get(Class<T> entityType, Serializable id) {
+ final DocumentBuilderIndexedEntity<?> docBuilder = searchFactory.getDocumentBuilderIndexedEntity( entityType );
+ if ( docBuilder == null ) {
+ String msg = "Entity to retrueve is not an @Indexed entity: " + entityType.getClass().getName();
+ throw new IllegalArgumentException( msg );
+ }
+ if (id == null) {
+ throw new IllegalArgumentException( "Identifier cannot be null" );
+ }
+ Query luceneQuery = new TermQuery( docBuilder.getTerm( id ) );
+ FullTextQuery searchQuery = createFullTextQuery( luceneQuery, entityType );
+ List<?> results = searchQuery.list();
+ if (results.size() > 1) {
+ //TODO find correct exception
+ throw new SearchException("Several entities with he same id found: " + entityType + "#" + id);
+ }
+ @SuppressWarnings( "unchecked" )
+ final T result = (T) ( results.size() == 0 ? null : results.get( 0 ) );
+ return result;
+ }
+
+ public FullTextQuery createFullTextQuery(Query luceneQuery, Class<?>... entities) {
+ return null; //To change body of implemented methods use File | Settings | File Templates.
+ }
+
+
+
+ /**
+ * (Re-)index an entity.
+ * The entity must be associated with the session and non indexable entities are ignored.
+ *
+ * @param entity The entity to index - must not be <code>null</code>.
+ *
+ * @throws IllegalArgumentException if entity is null or not an @Indexed entity
+ */
+ public <T> void index(T entity) {
+ if ( entity == null ) {
+ throw new IllegalArgumentException( "Entity to index should not be null" );
+ }
+
+ Class<?> clazz = getClass( entity );
+ //TODO cache that at the FTSession level
+ //not strictly necessary but a small optimization
+ final DocumentBuilderIndexedEntity<?> docBuilder = searchFactory.getDocumentBuilderIndexedEntity( clazz );
+ if ( docBuilder == null ) {
+ String msg = "Entity to index is not an @Indexed entity: " + entity.getClass().getName();
+ throw new IllegalArgumentException( msg );
+ }
+ Serializable id = docBuilder.getId( entity );
+ Work<T> work = new Work<T>( entity, id, WorkType.INDEX );
+ searchFactory.getWorker().performWork( work, transactionContext );
+
+ //TODO
+ //need to add elements in a queue kept at the Session level
+ //the queue will be processed by a Lucene(Auto)FlushEventListener
+ //note that we could keep this queue somewhere in the event listener in the mean time but that requires
+ //a synchronized hashmap holding this queue on a per session basis plus some session house keeping (yuk)
+ //another solution would be to subclass SessionImpl instead of having this LuceneSession delegation model
+ //this is an open discussion
+ }
+
+ private Class<?> getClass(Object entity) {
+ return entity.getClass();
+ }
+
+ public SearchFactory getSearchFactory() {
+ return searchFactory;
+ }
+
+ public <T> void purge(Class<T> entityType, Serializable id) {
+ if ( entityType == null ) {
+ return;
+ }
+
+ Set<Class<?>> targetedClasses = searchFactory.getIndexedTypesPolymorphic( new Class[] {entityType} );
+ if ( targetedClasses.isEmpty() ) {
+ String msg = entityType.getName() + " is not an indexed entity or a subclass of an indexed entity";
+ throw new IllegalArgumentException( msg );
+ }
+
+ for ( Class<?> clazz : targetedClasses ) {
+ if ( id == null ) {
+ createAndPerformWork( clazz, null, WorkType.PURGE_ALL );
+ }
+ else {
+ createAndPerformWork( clazz, id, WorkType.PURGE );
+ }
+ }
+ }
+
+ private <T> void createAndPerformWork(Class<T> clazz, Serializable id, WorkType workType) {
+ Work<T> work;
+ work = new Work<T>( clazz, id, workType );
+ searchFactory.getWorker().performWork( work, transactionContext );
+ }
+
+ public <T> void purgeAll(Class<T> entityType) {
+ purge( entityType, null );
+ }
+
+ public void flushToIndexes() {
+ searchFactory.getWorker().flushWorks( transactionContext );
+ }
+}
More information about the hibernate-commits
mailing list