|
From: <hib...@li...> - 2006-07-13 02:16:28
|
Author: epbernard
Date: 2006-07-12 22:16:13 -0400 (Wed, 12 Jul 2006)
New Revision: 10114
Added:
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/FieldBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/LuceneSession.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/BridgeFactory.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/DateBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/DoubleBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/FieldBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/FloatBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/IntegerBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/LongBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/NumberBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/ParameterizedBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/Resolution.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/String2FieldBridgeAdaptor.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/StringBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/StringImplBridge.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/EntityInfo.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/IteratorImpl.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/LuceneQueryImpl.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/ScrollableResultsImpl.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/util/
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/util/BinderHelper.java
branches/Lucene_Integration/HibernateExt/metadata/src/test/org/hibernate/lucene/test/Document.java
branches/Lucene_Integration/HibernateExt/metadata/src/test/org/hibernate/lucene/test/MappingTest.java
branches/Lucene_Integration/HibernateExt/metadata/src/test/org/hibernate/lucene/test/TestCase.java
branches/Lucene_Integration/HibernateExt/metadata/src/test/org/hibernate/lucene/test/query/
branches/Lucene_Integration/HibernateExt/metadata/src/test/org/hibernate/lucene/test/query/Book.java
branches/Lucene_Integration/HibernateExt/metadata/src/test/org/hibernate/lucene/test/query/Clock.java
branches/Lucene_Integration/HibernateExt/metadata/src/test/org/hibernate/lucene/test/query/QueryTest.java
Modified:
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/DocumentBuilder.java
branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/event/LuceneEventListener.java
Log:
Prototype for Hibernate Lucene Query + field bridge
Modified: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/DocumentBuilder.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/DocumentBuilder.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/DocumentBuilder.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -1,7 +1,6 @@
//$Id$
package org.hibernate.lucene;
-import java.beans.Introspector;
import java.io.Serializable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.AnnotatedElement;
@@ -17,8 +16,13 @@
import org.apache.lucene.index.Term;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
+import org.hibernate.util.ReflectHelper;
import org.hibernate.cfg.annotations.Version;
import org.hibernate.lucene.store.DirectoryProvider;
+import org.hibernate.lucene.bridge.FieldBridge;
+import org.hibernate.lucene.bridge.BridgeFactory;
+import org.hibernate.lucene.util.BinderHelper;
+import org.hibernate.lucene.event.LuceneEventListener;
//TODO handle attribute (only getters are handled currently)
public class DocumentBuilder<T> {
@@ -39,6 +43,8 @@
private String idKeywordName;
private final Analyzer analyzer;
private Float idBoost;
+ public static final String CLASS_FIELDNAME = "_hibernate_class";
+ private FieldBridge idBridge;
public DocumentBuilder(Class<?> clazz, Analyzer analyzer, DirectoryProvider directory) {
//this.beanClass = clazz;
@@ -51,10 +57,11 @@
Method method = methods[i];
Keyword keywordAnn = method.getAnnotation( Keyword.class );
if ( keywordAnn != null ) {
- String name = getAttributeName( method, keywordAnn.name() );
+ String name = BinderHelper.getAttributeName( method, keywordAnn.name() );
if ( keywordAnn.id() ) {
idKeywordName = name;
idBoost = getBoost( method );
+ idBridge = BridgeFactory.guessType( method );
}
else {
setAccessible( method );
@@ -66,12 +73,12 @@
if ( unstoredAnn != null ) {
setAccessible( method );
unstoredGetters.add( method );
- unstoredNames.add( getAttributeName( method, unstoredAnn.name() ) );
+ unstoredNames.add( BinderHelper.getAttributeName( method, unstoredAnn.name() ) );
}
Text textAnn = method.getAnnotation( Text.class );
if ( textAnn != null ) {
textGetters.add( method );
- textNames.add( getAttributeName( method, textAnn.name() ) );
+ textNames.add( BinderHelper.getAttributeName( method, textAnn.name() ) );
}
}
}
@@ -111,11 +118,9 @@
doc.setBoost( boost.floatValue() );
}
{
- Field idField = new Field( idKeywordName, id.toString(), Field.Store.YES, Field.Index.UN_TOKENIZED );
- if (idBoost != null) {
- idField.setBoost( idBoost.floatValue() );
- }
- doc.add( idField );
+ Field classField = new Field( CLASS_FIELDNAME, instance.getClass().getName(), Field.Store.YES, Field.Index.NO);
+ doc.add( classField );
+ idBridge.set( idKeywordName, id, doc, Field.Store.YES, Field.Index.UN_TOKENIZED, idBoost );
}
for ( int i = 0; i < keywordNames.size() ; i++ ) {
Member member = keywordGetters.get( i );
@@ -161,19 +166,6 @@
return new Term( idKeywordName, id.toString() );
}
- private static String getAttributeName(Method method, String name) {
- if( ! "".equals( name ) ) return name; //explicit field name
-
- //decapitalize
- String methodName = method.getName();
- //FIXME we probably should exclude methods not starting with "get" nor "is"
- int startIndex = 3;
- if( methodName.startsWith("is") ) {
- startIndex = 2;
- }
- return Introspector.decapitalize( methodName.substring( startIndex ) );
- }
-
public DirectoryProvider getDirectoryProvider() {
return directoryProvider;
}
@@ -187,4 +179,30 @@
( (AccessibleObject) member ).setAccessible( true );
}
}
+
+ public FieldBridge getIdBridge() {
+ return idBridge;
+ }
+
+ public String getIdKeywordName() {
+ return idKeywordName;
+ }
+
+ public static Class getDocumentClass(Document document) {
+ String className = document.get( DocumentBuilder.CLASS_FIELDNAME );
+ try {
+ return ReflectHelper.classForName( className );
+ }
+ catch (ClassNotFoundException e) {
+ throw new HibernateException("Unable to load indexed class: " + className, e);
+ }
+ }
+
+ public static Serializable getDocumentId(LuceneEventListener listener, Class clazz, Document document) {
+ DocumentBuilder builder = listener.getDocumentBuilders().get( clazz );
+ if (builder == null) throw new HibernateException("No Lucene configuration set up for: " + clazz.getName() );
+ Serializable id = (Serializable) builder.getIdBridge().get( builder.getIdKeywordName(), document );
+ return id;
+ }
+
}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/FieldBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/FieldBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/FieldBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,22 @@
+//$Id: $
+package org.hibernate.lucene;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Documented;
+
+import org.hibernate.annotations.Parameter;
+
+/**
+ * specifies a given field bridge implementation
+ * @author Emmanuel Bernard
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD})
+@Documented
+public @interface FieldBridge {
+ public Class impl() default void.class;
+ public Parameter[] params() default {};
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/LuceneSession.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/LuceneSession.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/LuceneSession.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,408 @@
+//$Id: $
+package org.hibernate.lucene;
+
+import java.io.Serializable;
+import java.sql.Connection;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.hibernate.CacheMode;
+import org.hibernate.Criteria;
+import org.hibernate.EntityMode;
+import org.hibernate.Filter;
+import org.hibernate.FlushMode;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.ReplicationMode;
+import org.hibernate.SQLQuery;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.Transaction;
+import org.hibernate.cfg.NotYetImplementedException;
+import org.hibernate.engine.query.ParameterMetadata;
+import org.hibernate.impl.SessionImpl;
+import org.hibernate.lucene.query.LuceneQueryImpl;
+import org.hibernate.stat.SessionStatistics;
+import org.hibernate.type.Type;
+
+/**
+ * Lucene aware session that allows lucene query creations
+ *
+ * @author Emmanuel Bernard
+ */
+public class LuceneSession implements Session {
+ private final SessionImpl session;
+
+ public LuceneSession(Session session) {
+ this.session = (SessionImpl) session;
+ }
+
+ /**
+ * Execute a Lucene query and retrieve managed objects
+ * @param entities must be immutable for the lifetime of the query object
+ */
+ public Query createLuceneQuery(org.apache.lucene.search.Query luceneQuery, Class... entities) {
+ return new LuceneQueryImpl( luceneQuery, entities, session, new ParameterMetadata(null, null) );
+ }
+
+ public void index(Object object) {
+ throw new NotYetImplementedException("");
+ //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)
+ //an other solution would be to subclass SessionImpl instead of having this LuceneSession delecation model
+ // this is an open discussion
+ }
+
+ public Query createSQLQuery(String sql, String returnAlias, Class returnClass) {
+ return session.createSQLQuery( sql, returnAlias, returnClass );
+ }
+
+ public Query createSQLQuery(String sql, String[] returnAliases, Class[] returnClasses) {
+ return session.createSQLQuery( sql, returnAliases, returnClasses );
+ }
+
+ public int delete(String query) throws HibernateException {
+ return session.delete( query );
+ }
+
+ public int delete(String query, Object value, Type type) throws HibernateException {
+ return session.delete( query, value, type );
+ }
+
+ public int delete(String query, Object[] values, Type[] types) throws HibernateException {
+ return session.delete( query, values, types );
+ }
+
+ public Collection filter(Object collection, String filter) throws HibernateException {
+ return session.filter( collection, filter );
+ }
+
+ public Collection filter(Object collection, String filter, Object value, Type type) throws HibernateException {
+ return session.filter( collection, filter, value, type );
+ }
+
+ public Collection filter(Object collection, String filter, Object[] values, Type[] types) throws HibernateException {
+ return session.filter( collection, filter, values, types );
+ }
+
+ public List find(String query) throws HibernateException {
+ return session.find( query );
+ }
+
+ public List find(String query, Object value, Type type) throws HibernateException {
+ return session.find( query, value, type );
+ }
+
+ public List find(String query, Object[] values, Type[] types) throws HibernateException {
+ return session.find( query, values, types );
+ }
+
+ public Iterator iterate(String query) throws HibernateException {
+ return session.iterate( query );
+ }
+
+ public Iterator iterate(String query, Object value, Type type) throws HibernateException {
+ return session.iterate( query, value, type );
+ }
+
+ public Iterator iterate(String query, Object[] values, Type[] types) throws HibernateException {
+ return session.iterate( query, values, types );
+ }
+
+ public void save(String entityName, Object object, Serializable id) throws HibernateException {
+ session.save( entityName, object, id );
+ }
+
+ public void save(Object object, Serializable id) throws HibernateException {
+ session.save( object, id );
+ }
+
+ public Object saveOrUpdateCopy(String entityName, Object object) throws HibernateException {
+ return session.saveOrUpdateCopy( entityName, object );
+ }
+
+ public Object saveOrUpdateCopy(String entityName, Object object, Serializable id) throws HibernateException {
+ return session.saveOrUpdateCopy( entityName, object, id );
+ }
+
+ public Object saveOrUpdateCopy(Object object) throws HibernateException {
+ return session.saveOrUpdateCopy( object );
+ }
+
+ public Object saveOrUpdateCopy(Object object, Serializable id) throws HibernateException {
+ return session.saveOrUpdateCopy( object, id );
+ }
+
+ public void update(String entityName, Object object, Serializable id) throws HibernateException {
+ session.update( entityName, object, id );
+ }
+
+ public void update(Object object, Serializable id) throws HibernateException {
+ session.update( object, id );
+ }
+
+ public Transaction beginTransaction() throws HibernateException {
+ return session.beginTransaction();
+ }
+
+ public void cancelQuery() throws HibernateException {
+ session.cancelQuery();
+ }
+
+ public void clear() {
+ session.clear();
+ }
+
+ public Connection close() throws HibernateException {
+ return session.close();
+ }
+
+ public Connection connection() throws HibernateException {
+ return session.connection();
+ }
+
+ public boolean contains(Object object) {
+ return session.contains( object );
+ }
+
+ public Criteria createCriteria(String entityName) {
+ return session.createCriteria( entityName );
+ }
+
+ public Criteria createCriteria(String entityName, String alias) {
+ return session.createCriteria( entityName, alias );
+ }
+
+ public Criteria createCriteria(Class persistentClass) {
+ return session.createCriteria( persistentClass );
+ }
+
+ public Criteria createCriteria(Class persistentClass, String alias) {
+ return session.createCriteria( persistentClass, alias );
+ }
+
+ public Query createFilter(Object collection, String queryString) throws HibernateException {
+ return session.createFilter( collection, queryString );
+ }
+
+ public Query createQuery(String queryString) throws HibernateException {
+ return session.createQuery( queryString );
+ }
+
+ public SQLQuery createSQLQuery(String queryString) throws HibernateException {
+ return session.createSQLQuery( queryString );
+ }
+
+ public void delete(String entityName, Object object) throws HibernateException {
+ session.delete( entityName, object );
+ }
+
+ public void delete(Object object) throws HibernateException {
+ session.delete( object );
+ }
+
+ public void disableFilter(String filterName) {
+ session.disableFilter( filterName );
+ }
+
+ public Connection disconnect() throws HibernateException {
+ return session.disconnect();
+ }
+
+ public Filter enableFilter(String filterName) {
+ return session.enableFilter( filterName );
+ }
+
+ public void evict(Object object) throws HibernateException {
+ session.evict( object );
+ }
+
+ public void flush() throws HibernateException {
+ session.flush();
+ }
+
+ public Object get(Class clazz, Serializable id) throws HibernateException {
+ return session.get( clazz, id );
+ }
+
+ public Object get(Class clazz, Serializable id, LockMode lockMode) throws HibernateException {
+ return session.get( clazz, id, lockMode );
+ }
+
+ public Object get(String entityName, Serializable id) throws HibernateException {
+ return session.get( entityName, id );
+ }
+
+ public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
+ return session.get( entityName, id, lockMode );
+ }
+
+ public CacheMode getCacheMode() {
+ return session.getCacheMode();
+ }
+
+ public LockMode getCurrentLockMode(Object object) throws HibernateException {
+ return session.getCurrentLockMode( object );
+ }
+
+ public Filter getEnabledFilter(String filterName) {
+ return session.getEnabledFilter( filterName );
+ }
+
+ public EntityMode getEntityMode() {
+ return session.getEntityMode();
+ }
+
+ public String getEntityName(Object object) throws HibernateException {
+ return session.getEntityName( object );
+ }
+
+ public FlushMode getFlushMode() {
+ return session.getFlushMode();
+ }
+
+ public Serializable getIdentifier(Object object) throws HibernateException {
+ return session.getIdentifier( object );
+ }
+
+ public Query getNamedQuery(String queryName) throws HibernateException {
+ return session.getNamedQuery( queryName );
+ }
+
+ public org.hibernate.Session getSession(EntityMode entityMode) {
+ return session.getSession( entityMode );
+ }
+
+ public SessionFactory getSessionFactory() {
+ return session.getSessionFactory();
+ }
+
+ public SessionStatistics getStatistics() {
+ return session.getStatistics();
+ }
+
+ public Transaction getTransaction() {
+ return session.getTransaction();
+ }
+
+ public boolean isConnected() {
+ return session.isConnected();
+ }
+
+ public boolean isDirty() throws HibernateException {
+ return session.isDirty();
+ }
+
+ public boolean isOpen() {
+ return session.isOpen();
+ }
+
+ public Object load(String entityName, Serializable id) throws HibernateException {
+ return session.load( entityName, id );
+ }
+
+ public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
+ return session.load( entityName, id, lockMode );
+ }
+
+ public void load(Object object, Serializable id) throws HibernateException {
+ session.load( object, id );
+ }
+
+ public Object load(Class theClass, Serializable id) throws HibernateException {
+ return session.load( theClass, id );
+ }
+
+ public Object load(Class theClass, Serializable id, LockMode lockMode) throws HibernateException {
+ return session.load( theClass, id, lockMode );
+ }
+
+ public void lock(String entityName, Object object, LockMode lockMode) throws HibernateException {
+ session.lock( entityName, object, lockMode );
+ }
+
+ public void lock(Object object, LockMode lockMode) throws HibernateException {
+ session.lock( object, lockMode );
+ }
+
+ public Object merge(String entityName, Object object) throws HibernateException {
+ return session.merge( entityName, object );
+ }
+
+ public Object merge(Object object) throws HibernateException {
+ return session.merge( object );
+ }
+
+ public void persist(String entityName, Object object) throws HibernateException {
+ session.persist( entityName, object );
+ }
+
+ public void persist(Object object) throws HibernateException {
+ session.persist( object );
+ }
+
+ public void reconnect() throws HibernateException {
+ session.reconnect();
+ }
+
+ public void reconnect(Connection connection) throws HibernateException {
+ session.reconnect( connection );
+ }
+
+ public void refresh(Object object) throws HibernateException {
+ session.refresh( object );
+ }
+
+ public void refresh(Object object, LockMode lockMode) throws HibernateException {
+ session.refresh( object, lockMode );
+ }
+
+ public void replicate(String entityName, Object object, ReplicationMode replicationMode) throws HibernateException {
+ session.replicate( entityName, object, replicationMode );
+ }
+
+ public void replicate(Object object, ReplicationMode replicationMode) throws HibernateException {
+ session.replicate( object, replicationMode );
+ }
+
+ public Serializable save(String entityName, Object object) throws HibernateException {
+ return session.save( entityName, object );
+ }
+
+ public Serializable save(Object object) throws HibernateException {
+ return session.save( object );
+ }
+
+ public void saveOrUpdate(String entityName, Object object) throws HibernateException {
+ session.saveOrUpdate( entityName, object );
+ }
+
+ public void saveOrUpdate(Object object) throws HibernateException {
+ session.saveOrUpdate( object );
+ }
+
+ public void setCacheMode(CacheMode cacheMode) {
+ session.setCacheMode( cacheMode );
+ }
+
+ public void setFlushMode(FlushMode flushMode) {
+ session.setFlushMode( flushMode );
+ }
+
+ public void setReadOnly(Object entity, boolean readOnly) {
+ session.setReadOnly( entity, readOnly );
+ }
+
+ public void update(String entityName, Object object) throws HibernateException {
+ session.update( entityName, object );
+ }
+
+ public void update(Object object) throws HibernateException {
+ session.update( object );
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/BridgeFactory.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/BridgeFactory.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/BridgeFactory.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,99 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Member;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.HibernateException;
+import org.hibernate.annotations.Parameter;
+import org.hibernate.lucene.util.BinderHelper;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class BridgeFactory {
+ private static Map<String, FieldBridge> builtInBridges = new HashMap<String, FieldBridge>();
+ private BridgeFactory() {}
+
+ public static final FieldBridge DOUBLE = new String2FieldBridgeAdaptor( new DoubleBridge() );
+
+ public static final FieldBridge FLOAT = new String2FieldBridgeAdaptor( new FloatBridge() );
+
+ public static final FieldBridge INTEGER = new String2FieldBridgeAdaptor( new IntegerBridge() );
+
+ public static final FieldBridge LONG = new String2FieldBridgeAdaptor( new LongBridge() );
+
+ public static final FieldBridge STRING = new String2FieldBridgeAdaptor( new StringImplBridge() );
+
+ public static final FieldBridge DATE_YEAR;
+ public static final FieldBridge DATE_MONTH;
+ public static final FieldBridge DATE_DAY;
+ public static final FieldBridge DATE_HOUR;
+ public static final FieldBridge DATE_MINUTE;
+ public static final FieldBridge DATE_SECOND;
+ public static final FieldBridge DATE_MILLISECOND;
+
+ static {
+ builtInBridges.put( Double.class.getName(), DOUBLE );
+ builtInBridges.put( Float.class.getName(), FLOAT );
+ builtInBridges.put( Integer.class.getName(), INTEGER );
+ builtInBridges.put( Long.class.getName(), LONG );
+ builtInBridges.put( String.class.getName(), STRING );
+
+ DATE_YEAR = createDateBridge( Resolution.YEAR );
+ DATE_MONTH = createDateBridge( Resolution.MONTH );
+ DATE_DAY = createDateBridge( Resolution.DAY );
+ DATE_HOUR = createDateBridge( Resolution.HOUR );
+ DATE_MINUTE = createDateBridge( Resolution.MINUTE );
+ DATE_SECOND = createDateBridge( Resolution.SECOND );
+ DATE_MILLISECOND = createDateBridge( Resolution.MILLISECOND );
+ builtInBridges.put( Date.class.getName(), DATE_MILLISECOND );
+ }
+
+ private static FieldBridge createDateBridge(Resolution resolution) {
+ DateBridge date;
+ Map params = new HashMap(1);
+ params.put( "resolution", resolution );
+ date = new DateBridge();
+ date.setParameterValues( params );
+ return new String2FieldBridgeAdaptor( date );
+ }
+
+ public static FieldBridge guessType(Member member) {
+ FieldBridge bridge = null;
+ org.hibernate.lucene.FieldBridge bridgeAnn = ( (AnnotatedElement) member ).getAnnotation( org.hibernate.lucene.FieldBridge.class );
+ if (bridgeAnn != null) {
+ Class impl = bridgeAnn.impl();
+ try {
+ Object instance = impl.newInstance();
+ if ( FieldBridge.class.isAssignableFrom( impl ) ) {
+ bridge = (FieldBridge) instance;
+ }
+ else if ( StringBridge.class.isAssignableFrom( impl ) ) {
+ bridge = new String2FieldBridgeAdaptor( (StringBridge) instance );
+ }
+ if ( bridgeAnn.params().length > 0 && ParameterizedBridge.class.isAssignableFrom( impl ) ) {
+ Map params = new HashMap( bridgeAnn.params().length );
+ for ( Parameter param : bridgeAnn.params() ) {
+ params.put( param.name(), param.value() );
+ }
+ ( (ParameterizedBridge) instance ).setParameterValues( params );
+ }
+ }
+ catch (Exception e) {
+ throw new HibernateException("Unable to instanciate FieldBridge for " + BinderHelper.getAttributeName(member), e );
+ }
+ }
+ else {
+ //find in built-ins
+ Class<?> returnType = BinderHelper.getReturnType( member );
+ bridge = builtInBridges.get( returnType.getName() );
+ }
+ if (bridge == null) throw new HibernateException("Unable to guess FieldBridge for " + BinderHelper.getAttributeName(member) );
+ return bridge;
+ }
+
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/DateBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/DateBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/DateBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,62 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Map;
+
+import org.apache.lucene.document.DateTools;
+import org.hibernate.AssertionFailure;
+import org.hibernate.HibernateException;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class DateBridge implements StringBridge, ParameterizedBridge {
+ //TODO don't depend on such a weak 3rd party API for a public API of ours
+ DateTools.Resolution resolution;
+
+ public Object stringToObject(String stringValue) {
+ //usually does not make sense
+ try {
+ return DateTools.stringToDate( stringValue );
+ }
+ catch (ParseException e) {
+ throw new HibernateException( "Unable to parse into date: " + stringValue, e );
+ }
+ }
+
+ public String objectToString(Object object) {
+ return DateTools.dateToString( (Date) object, resolution );
+ }
+
+ public void setParameterValues(Map parameters) {
+ Resolution hibResolution = (Resolution) parameters.get( "resolution" );
+ switch ( hibResolution ) {
+ case YEAR:
+ resolution = DateTools.Resolution.YEAR;
+ break;
+ case MONTH:
+ resolution = DateTools.Resolution.MONTH;
+ break;
+ case DAY:
+ resolution = DateTools.Resolution.DAY;
+ break;
+ case HOUR:
+ resolution = DateTools.Resolution.HOUR;
+ break;
+ case MINUTE:
+ resolution = DateTools.Resolution.MINUTE;
+ break;
+ case SECOND:
+ resolution = DateTools.Resolution.SECOND;
+ break;
+ case MILLISECOND:
+ resolution = DateTools.Resolution.MILLISECOND;
+ break;
+ default:
+ throw new AssertionFailure( "Unknown Resolution: " + hibResolution );
+
+ }
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/DoubleBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/DoubleBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/DoubleBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,11 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class DoubleBridge extends NumberBridge {
+ public Object stringToObject(String stringValue) {
+ return new Double(stringValue);
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/FieldBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/FieldBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/FieldBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,18 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+
+/**
+ * Link between a java property and a Lucene Document
+ * Usually a Java property will be linked to a Document Field
+ *
+ * @author Emmanuel Bernard
+ */
+//TODO should show Field or document?
+//document is nice since I can save an object into several fields
+public interface FieldBridge {
+ Object get(String name, Document document);
+ void set(String name, Object value, Document document, Field.Store store, Field.Index index, Float boost);
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/FloatBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/FloatBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/FloatBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,11 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class FloatBridge extends NumberBridge {
+ public Object stringToObject(String stringValue) {
+ return new Float(stringValue);
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/IntegerBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/IntegerBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/IntegerBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,11 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class IntegerBridge extends NumberBridge {
+ public Object stringToObject(String stringValue) {
+ return new Integer(stringValue);
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/LongBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/LongBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/LongBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,11 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class LongBridge extends NumberBridge {
+ public Object stringToObject(String stringValue) {
+ return new Long(stringValue);
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/NumberBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/NumberBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/NumberBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,11 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public abstract class NumberBridge implements StringBridge {
+ public String objectToString(Object object) {
+ return object.toString();
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/ParameterizedBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/ParameterizedBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/ParameterizedBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,13 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+import java.util.Map;
+
+/**
+ * Allow parameter injection to a given bridge
+ *
+ * @author Emmanuel Bernard
+ */
+public interface ParameterizedBridge {
+ void setParameterValues(Map parameters);
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/Resolution.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/Resolution.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/Resolution.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,17 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+/**
+ * Date indexing resolution
+ *
+ * @author Emmanuel Bernard
+ */
+public enum Resolution {
+ YEAR,
+ MONTH,
+ DAY,
+ HOUR,
+ MINUTE,
+ SECOND,
+ MILLISECOND
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/String2FieldBridgeAdaptor.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/String2FieldBridgeAdaptor.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/String2FieldBridgeAdaptor.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,31 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.document.Field;
+
+/**
+ * Bridge to use a Java2String as a Java2Field
+ *
+ * @author Emmanuel Bernard
+ */
+public class String2FieldBridgeAdaptor implements FieldBridge {
+
+ private StringBridge stringBridge;
+
+ public String2FieldBridgeAdaptor(StringBridge stringBridge) {
+ this.stringBridge = stringBridge;
+ }
+ public Object get(String name, Document document) {
+ Field field = document.getField( name );
+ return stringBridge.stringToObject( field.stringValue() );
+ }
+
+ public void set(String name, Object value, Document document, Field.Store store, Field.Index index, Float boost) {
+ Field field = new Field(name, stringBridge.objectToString( value ), store, index);
+ if (boost != null) field.setBoost( boost );
+ document.add( field );
+ }
+
+
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/StringBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/StringBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/StringBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,20 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+/**
+ * Transform an object into a stirng representation and vice versa
+ *
+ * @author Emmanuel Bernard
+ */
+public interface StringBridge {
+ /**
+ * Convert the string representation to an object
+ * FIXME: This operation might not always be possible
+ */
+ Object stringToObject(String stringValue);
+
+ /**
+ * convert the object representation to a String
+ */
+ String objectToString(Object object);
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/StringImplBridge.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/StringImplBridge.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/bridge/StringImplBridge.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,15 @@
+//$Id: $
+package org.hibernate.lucene.bridge;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class StringImplBridge implements StringBridge {
+ public Object stringToObject(String stringValue) {
+ return stringValue;
+ }
+
+ public String objectToString(Object object) {
+ return (String) object;
+ }
+}
Modified: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/event/LuceneEventListener.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/event/LuceneEventListener.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/event/LuceneEventListener.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -41,10 +41,17 @@
* @author Emmanuel Bernard
* @author Mattias Arbin
*/
-//TODO takes care of synchronization and index concurrent index change
+//TODO work on sharing the same indexWriters and readers across a single post operation...
public class LuceneEventListener implements PostDeleteEventListener, PostInsertEventListener,
PostUpdateEventListener, Initializable {
+ //FIXME keeping this here is a bad decision since you might want to search indexes wo maintain it
+ @Deprecated
+ public Map<Class, DocumentBuilder<Object>> getDocumentBuilders() {
+ return documentBuilders;
+ }
+
+
private Map<Class, DocumentBuilder<Object>> documentBuilders = new HashMap<Class, DocumentBuilder<Object>>();
//** keep track of the index modifiers per file since 1 index modifier can be present at a time */
private Map<DirectoryProvider, Lock> indexLock = new HashMap<DirectoryProvider, Lock>();
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/EntityInfo.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/EntityInfo.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/EntityInfo.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,12 @@
+//$Id: $
+package org.hibernate.lucene.query;
+
+import java.io.Serializable;
+
+/**
+ * @author Emmanuel Bernard
+ */
+class EntityInfo {
+ public Class clazz;
+ public Serializable id;
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/IteratorImpl.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/IteratorImpl.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/IteratorImpl.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,38 @@
+//$Id: $
+package org.hibernate.lucene.query;
+
+import java.util.Iterator;
+
+import org.hibernate.Session;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class IteratorImpl implements Iterator {
+
+ private final EntityInfo[] entityInfos;
+ private final Session session;
+ private int index = 0;
+ private final int size;
+
+ public IteratorImpl(EntityInfo[] entityInfos, Session session) {
+ this.entityInfos = entityInfos;
+ this.session = session;
+ this.size = entityInfos.length;
+ }
+
+ public boolean hasNext() {
+ return index < size;
+ }
+
+ public Object next() {
+ Object object = session.get( entityInfos[index].clazz, entityInfos[index].id );
+ index++;
+ return object;
+ }
+
+ public void remove() {
+ //TODO this is theorically doable
+ throw new UnsupportedOperationException( "Cannot remove from a lucene query interator" );
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/LuceneQueryImpl.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/LuceneQueryImpl.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/LuceneQueryImpl.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,258 @@
+//$Id: $
+package org.hibernate.lucene.query;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.lucene.document.Document;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.MultiSearcher;
+import org.apache.lucene.search.Searcher;
+import org.apache.lucene.store.Directory;
+import org.hibernate.Hibernate;
+import org.hibernate.HibernateException;
+import org.hibernate.LockMode;
+import org.hibernate.Query;
+import org.hibernate.ScrollMode;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.engine.SessionImplementor;
+import org.hibernate.engine.query.ParameterMetadata;
+import org.hibernate.event.PostInsertEventListener;
+import org.hibernate.impl.AbstractQueryImpl;
+import org.hibernate.lucene.DocumentBuilder;
+import org.hibernate.lucene.event.LuceneEventListener;
+
+/**
+ * @author Emmanuel Bernard
+ */
+//implements setParameter()
+public class LuceneQueryImpl extends AbstractQueryImpl {
+ private static final Log log = LogFactory.getLog( LuceneQueryImpl.class );
+ private org.apache.lucene.search.Query luceneQuery;
+ private Class[] classes;
+ private Integer firstResult;
+ private Integer maxResults;
+ private int resultSize;
+
+ /** classes must be immutable */
+ public LuceneQueryImpl(org.apache.lucene.search.Query query, Class[] classes, SessionImplementor session, ParameterMetadata parameterMetadata) {
+ //TODO handle flushMode
+ super( query.toString(), null, session, parameterMetadata );
+ this.luceneQuery = query;
+ this.classes = classes;
+ }
+
+ /**
+ * Return an interator on the results.
+ * Retrieve the object one by one (initialize it during the next() operation)
+ */
+ public Iterator iterate() throws HibernateException {
+ //implement an interator which keep the id/class for each hit and get the object on demand
+ //cause I can't keep the searcher and hence the hit opened. I dont have any hook to know when the
+ //user stop using it
+ //scrollable is better in this area
+
+ LuceneEventListener listener = getLuceneEventListener();
+ //find the directories
+ Searcher searcher = buildSearcher( listener );
+ Hits hits;
+ try {
+ hits = searcher.search( luceneQuery );
+ setResultSize(hits);
+ int first = first();
+ int max = max( first, hits );
+ EntityInfo[] entityInfos = new EntityInfo[max - first + 1];
+ for (int index = first ; index <= max ; index++ ) {
+ Document document = hits.doc( index );
+ EntityInfo entityInfo = new EntityInfo();
+ entityInfo.clazz = DocumentBuilder.getDocumentClass( document );
+ //FIXME should check that clazz match classes but this complexify a lot the firstResult/maxResult
+ entityInfo.id = DocumentBuilder.getDocumentId( listener, entityInfo.clazz, document );
+ entityInfos[ index - first ] = entityInfo;
+ }
+ return new IteratorImpl( entityInfos, (Session) this.session );
+ }
+ catch (IOException e) {
+ throw new HibernateException("Unable to query Lucene index", e);
+ }
+ finally {
+ if (searcher != null) try {
+ searcher.close();
+ }
+ catch (IOException e) {
+ log.warn( "Unable to properly close searcher during lucene query: " + getQueryString(), e );
+ }
+ }
+ }
+
+ public ScrollableResults scroll() throws HibernateException {
+ //keep the searcher open until the resultset is closed
+ LuceneEventListener listener = getLuceneEventListener();
+ //find the directories
+ Searcher searcher = buildSearcher( listener );
+ Hits hits;
+ try {
+ hits = searcher.search( luceneQuery );
+ setResultSize(hits);
+ int first = first();
+ int max = max( first, hits );
+ return new ScrollableResultsImpl( searcher, hits, first, max, (Session) this.session, listener );
+ }
+ catch (IOException e) {
+ try {
+ if ( searcher != null ) searcher.close();
+ }
+ catch (IOException ee) {
+ //we have the initial issue already
+ }
+ throw new HibernateException("Unable to query Lucene index", e);
+ }
+ }
+
+ public ScrollableResults scroll(ScrollMode scrollMode) throws HibernateException {
+ //TODO think about this scrollmode
+ return scroll();
+ }
+
+ public List list() throws HibernateException {
+ LuceneEventListener listener = getLuceneEventListener();
+ //find the directories
+ Searcher searcher = buildSearcher( listener );
+ Hits hits;
+ try {
+ hits = searcher.search( luceneQuery );
+ setResultSize(hits);
+ int first = first();
+ int max = max( first, hits );
+ List result = new ArrayList( max - first + 1);
+ Session sess = (Session) this.session;
+ for (int index = first ; index <= max ; index++ ) {
+ Document document = hits.doc( index );
+ Class clazz = DocumentBuilder.getDocumentClass( document );
+ //FIXME should check that clazz match classes but this complexify a lot the firstResult/maxResult
+ Serializable id = DocumentBuilder.getDocumentId( listener, clazz, document );
+ result.add( sess.load( clazz, id ) );
+ //use load to benefit from the batch-size (but facing some proxy casting issues...
+ }
+ //then initialize the objects
+ for (Object element : result) {
+ Hibernate.initialize(element);
+ }
+ return result;
+ }
+ catch (IOException e) {
+ throw new HibernateException("Unable to query Lucene index", e);
+ }
+ finally {
+ if (searcher != null) try {
+ searcher.close();
+ }
+ catch (IOException e) {
+ log.warn( "Unable to properly close searcher during lucene query: " + getQueryString(), e );
+ }
+ }
+ }
+
+ private int max(int first, Hits hits) {
+ return maxResults == null ?
+ first + hits.length() - 1 :
+ maxResults + first < hits.length() ?
+ first + maxResults :
+ hits.length() - 1;
+ }
+
+ private int first() {
+ return firstResult != null ? firstResult : 0;
+ }
+
+ private Searcher buildSearcher(LuceneEventListener listener) {
+ Map<Class, DocumentBuilder<Object>> builders = listener.getDocumentBuilders();
+ Set<Directory> directories = new HashSet<Directory>();
+ for (Class clazz : classes) {
+ DocumentBuilder builder = builders.get(clazz);
+ if (builder == null) throw new HibernateException( "Not a mapped entity: " + clazz);
+ directories.add( builder.getDirectoryProvider().getDirectory() );
+ }
+
+ //set up the searcher
+ Searcher searcher;
+ int dirNbr = directories.size();
+ if (dirNbr > 1) {
+ try {
+ IndexSearcher[] searchers = new IndexSearcher[ dirNbr ];
+ Iterator<Directory> it = directories.iterator();
+ for (int index = 0 ; index < dirNbr ; index++) {
+ searchers[index] = new IndexSearcher( it.next() );
+ }
+ searcher = new MultiSearcher(searchers);
+ }
+ catch(IOException e) {
+ throw new HibernateException("Unable to read Lucene directory", e);
+ }
+ }
+ else {
+ try {
+ searcher = new IndexSearcher( directories.iterator().next() );
+ }
+ catch (IOException e) {
+ throw new HibernateException("Unable to read Lucene directory", e);
+ }
+ }
+ return searcher;
+ }
+
+ private void setResultSize(Hits hits) {
+ resultSize = hits.length();
+ }
+
+ //FIXME does it make sense
+ public int resultSize() {
+ return this.resultSize;
+ }
+
+ public Query setFirstResult(int firstResult) {
+ this.firstResult = firstResult;
+ return this;
+ }
+
+ public Query setMaxResults(int maxResults) {
+ this.maxResults = maxResults;
+ return this;
+ }
+
+ private LuceneEventListener getLuceneEventListener() {
+ PostInsertEventListener[] listeners = session.getListeners().getPostCommitInsertEventListeners();
+ LuceneEventListener listener = null;
+ //FIXME this sucks since we mandante the event listener use
+ for(PostInsertEventListener candidate : listeners ) {
+ if (candidate instanceof LuceneEventListener) {
+ listener = (LuceneEventListener) candidate;
+ break;
+ }
+ }
+ if (listener == null) throw new HibernateException("Lucene event listener not initialized");
+ return listener;
+ }
+
+ public int executeUpdate() throws HibernateException {
+ throw new HibernateException( "Not supported operation" );
+ }
+
+ public Query setLockMode(String alias, LockMode lockMode) {
+ return null;
+ }
+
+ protected Map getLockModes() {
+ return null;
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/ScrollableResultsImpl.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/ScrollableResultsImpl.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/query/ScrollableResultsImpl.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,217 @@
+//$Id: $
+package org.hibernate.lucene.query;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import org.apache.lucene.document.Document;
+import org.apache.lucene.search.Hits;
+import org.apache.lucene.search.Searcher;
+import org.hibernate.HibernateException;
+import org.hibernate.ScrollableResults;
+import org.hibernate.Session;
+import org.hibernate.lucene.DocumentBuilder;
+import org.hibernate.lucene.event.LuceneEventListener;
+import org.hibernate.type.Type;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public class ScrollableResultsImpl implements ScrollableResults {
+ private final Searcher searcher;
+ private final Hits hits;
+ private final int first;
+ private final int max;
+ private int current;
+ private final Session session;
+ private final LuceneEventListener listener;
+ private EntityInfo[] entityInfos;
+
+ public ScrollableResultsImpl(
+ Searcher searcher, Hits hits, int first, int max, Session session, LuceneEventListener listener
+ ) {
+ this.searcher = searcher;
+ this.hits = hits;
+ this.first = first;
+ this.max = max;
+ this.current = first;
+ this.session = session;
+ this.listener = listener;
+ entityInfos = new EntityInfo[max - first + 1];
+ }
+ public boolean next() throws HibernateException {
+ return ++current <= max;
+ }
+
+ public boolean previous() throws HibernateException {
+ return --current >= first;
+ }
+
+ public boolean scroll(int i) throws HibernateException {
+ current = current + i;
+ return current >= first && current <= max;
+ }
+
+ public boolean last() throws HibernateException {
+ current = max;
+ return max >= first;
+ }
+
+ public boolean first() throws HibernateException {
+ current = first;
+ return max >= first;
+ }
+
+ public void beforeFirst() throws HibernateException {
+ current = first - 1;
+ }
+
+ public void afterLast() throws HibernateException {
+ current = max + 1;
+ }
+
+ public boolean isFirst() throws HibernateException {
+ return current == first;
+ }
+
+ public boolean isLast() throws HibernateException {
+ return current == max;
+ }
+
+ public void close() throws HibernateException {
+ try {
+ searcher.close();
+ }
+ catch (IOException e) {
+ throw new HibernateException( "Unable to close Lucene searcher", e);
+ }
+ }
+
+ public Object[] get() throws HibernateException {
+ if (current < first || current > max) return null; //or exception?
+ EntityInfo info = entityInfos[current - first];
+ if ( info == null ) {
+ info = new EntityInfo();
+ Document document = null;
+ try {
+ document = hits.doc( current );
+ }
+ catch (IOException e) {
+ throw new HibernateException( "Unable to read Lucene hits[" + current + "]", e);
+ }
+ info.clazz = DocumentBuilder.getDocumentClass( document );
+ //FIXME should check that clazz match classes but this complexify a lot the firstResult/maxResult
+ info.id = DocumentBuilder.getDocumentId( listener, info.clazz, document );
+ entityInfos[current - first] = info;
+ }
+ return new Object[] {
+ session.get( info.clazz, info.id )
+ };
+ }
+
+ public Object get(int i) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Type getType(int i) {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Integer getInteger(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Long getLong(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Float getFloat(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Boolean getBoolean(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Double getDouble(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Short getShort(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Byte getByte(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Character getCharacter(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public byte[] getBinary(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public String getText(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Blob getBlob(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Clob getClob(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public String getString(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public BigDecimal getBigDecimal(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public BigInteger getBigInteger(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Date getDate(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Locale getLocale(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public Calendar getCalendar(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public TimeZone getTimeZone(int col) throws HibernateException {
+ throw new UnsupportedOperationException( "Lucene does not work on columns" );
+ }
+
+ public int getRowNumber() throws HibernateException {
+ if ( max < first ) return -1;
+ return current - first;
+ }
+
+ public boolean setRowNumber(int rowNumber) throws HibernateException {
+ if (rowNumber >= 0) {
+ current = first + rowNumber;
+ }
+ else {
+ current = max + rowNumber + 1; //max row start at -1
+ }
+ return current >= first && current <= max;
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/util/BinderHelper.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/util/BinderHelper.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/java/org/hibernate/lucene/util/BinderHelper.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,51 @@
+//$Id: $
+package org.hibernate.lucene.util;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Member;
+import java.lang.reflect.Field;
+import java.beans.Introspector;
+
+import org.hibernate.util.StringHelper;
+
+/**
+ * @author Emmanuel Bernard
+ */
+public abstract class BinderHelper {
+
+ private BinderHelper() {}
+
+ public static String getAttributeName(Member member) {
+ return getAttributeName( member, null );
+ }
+ /**
+ * Get attribute name out of member unless overriden by <code>name</code>
+ */
+ //TODO move to reflection layer
+ public static String getAttributeName(Member member, String name) {
+ if( StringHelper.isNotEmpty( name ) ) return name; //explicit field name
+ if (member instanceof Field ) {
+ return ( (Field) member ).getName();
+ }
+ else {
+ //decapitalize
+ String methodName = ( (Method) member).getName();
+ //FIXME we probably should exclude methods not starting with "get" nor "is"
+ int startIndex = 3;
+ if( methodName.startsWith("is") ) {
+ startIndex = 2;
+ }
+ return Introspector.decapitalize( methodName.substring( startIndex ) );
+ }
+ }
+
+ //TODO move to reflection layer
+ public static Class<?> getReturnType(Member member) {
+ if (member instanceof Field) {
+ return ( (Field) member ).getType();
+ }
+ else {
+ return ( (Method) member ).getReturnType();
+ }
+ }
+}
Added: branches/Lucene_Integration/HibernateExt/metadata/src/test/org/hibernate/lucene/test/Document.java
===================================================================
--- branches/Lucene_Integration/HibernateExt/metadata/src/test/org/hibernate/lucene/test/Document.java 2006-07-13 01:52:08 UTC (rev 10113)
+++ branches/Lucene_Integration/HibernateExt/metadata/src/test/org/hibernate/lucene/test/Document.java 2006-07-13 02:16:13 UTC (rev 10114)
@@ -0,0 +1,72 @@
+//$Id: Document.java 10014 2006-06-12 09:56:27 -0700 (lun., 12 juin 2006) epbernard $
+package org.hibernate.lucene.test;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Lob;
+
+import org.hibernate.lu...
[truncated message content] |