Sidequestion:
How transactional is the index update in it self ? If you are indexing 10
objects after tx.commit() and
the 7th object fails to index does the 6 previous indexed objects go to
the index or are the "rolled" back ?
/max
> What I expect to add is a better implementation of what's currently
> happening. Especially, I want to batch all operations for a single
> transaction using the same DirectoryProvider I/O (there are several
> currently). But this is a speed improvement, not a behavioral change.
> I'm also considering adding an asynchronous batch mode. but that's
mode
> a mid term work.
>
> WDYT?
>
> Richard Hallier wrote:
>>
>> Oui oui j'avais bien compris, je plaisantais :-)
>> J'avais une autre question tant que j'y étais, par rapport à la gestion
>> transactionnelle des opérations Lucene, y a t il quelque chose de
prévu
>> ?
>>
>> > -----Message d'origine-----
>> > De : Emmanuel Bernard [mailto:emmanuel.bernard@jboss.com]
>> > Envoyé : vendredi 13 octobre 2006 16:00
>> > À : Richard Hallier
>> > Objet : Re: Hibernate Lucene & fields
>> >
>> > je parlais des Bridges pour toutes les propriétés
>> >
>> > Richard Hallier wrote:
>> > >
>> > > Développé dans l'avion? J'espère que tu as fait un vol long
>> > courrier
>> > > ;-) Tiens moi au courant pour le patch.
>> > > Richard
>> > >
>> > > > -----Message d'origine-----
>> > > > De : Emmanuel Bernard [mailto:emmanuel.bernard@jboss.com]
>> > > > Envoyé : vendredi 13 octobre 2006 01:36 À : Richard
>> > Hallier Objet :
>> > > > Re: Hibernate Lucene & fields
>> > > >
>> > > > Si, je viens de le développer dans l'avion aujourd'hui
;-) Merci
>> > > > pour le patch je vais regarder ca demain
>> > > >
>> > > > Richard Hallier wrote:
>> > > > >
>> > > > > Salut Emmanuel,
>> > > > > Tu trouveras le patch en question en pièce jointe.
>> > > > > J'ai rajouté une classe de test plutot sommaire, cela
>> > > > peut-etre amélioré.
>> > > > >
>> > > > > J'ai une question. J'ai vu que la conversion (hors
identifiant)
>> > > > > des properties des entités en valeur lucene se fait par
>> > une simple
>> > > > > conversion texte, alors que tu as mis en place pour la
>> > gestion de
>> > > > > l'identifiant un bridge. Ce concept de
"converter" ne
>> > > > pourrait il pas
>> > > > > etre appliqué à toute conversion (pas seulement l'id)
en
>> > > > valeur Lucene?
>> > > > >
>> > > > > Richard.
>> > > > >
>> > > > > > -----Message d'origine-----
>> > > > > > De : Emmanuel Bernard [mailto:emmanuel@hibernate.org]
Envoyé :
>> > > > > > mercredi 11 octobre 2006 05:24 À :
>> > > > richard.hallier(a)freesbee.fr Objet
>> > > > > > : Hibernate Lucene & fields
>> > > > > >
>> > > > > > Hi,
>> > > > > > I bet you're French so I'll switch to it.
>> > > > > >
>> > > > > > J'ai pensé au code qui permettrait d'annoter
les attributs.
>> > > > > > En fait je voudrais utiliser une abstraction que
l'on a
>> > > > écrit pour
>> > > > > > Hibernate Annotations. Cela abstrait le code de la
résolution
>> > > > > > Generics de Java 5 et des propriétés vs attributs.
>> > > > > >
>> > > > > > Quand tu commences le patch, regarde
>> > > > > > org.hibernate.validator.ClassValidator, les accès aux
>> > > > annotations se
>> > > > > > font via ReflectionManager reflectionManager = new
>> > > > JavaXFactory();
>> > > > > > dans la methode
>> > > > > > ClassValidator.initValidator(...)
>> > > > > >
>> > > > > > Si tu as des questions, n'hésites pas à me
demander.
>> > > > > >
>> > > > > > Emmanuel
>> > > > > >
>> > > > >
>> > > > >
>> > > >
>> > --------------------------------------------------------------------
>> > > > --
>> > > > > --
>> > > > >
>> > > > > Index:
>> > > > >
>> > > >
>> > C:/dev/source/workspace1.5/HibernateExt/metadata/src/test/org/hibern
>> > > > at
>> > > > > e/lucene/test/FieldMappingTest.java
>> > > > >
>> > ==================================================================
>> > > > > =
>> > > > > ---
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/test/org/
>> > > > hibernate/lucene/test/FieldMappingTest.java (revision 0)
>> > > > > +++
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/test/org/
>> > > > hibernate/lucene/test/FieldMappingTest.java (revision 0)
>> > > > > @@ -0,0 +1,191 @@
>> > > > > +//$Id: LuceneTest.java 10014 2006-06-12 09:56:27 -0700
>> > > > (lun., 12 juin
>> > > > > +2006) epbernard $ package org.hibernate.lucene.test;
>> > > > > +
>> > > > > +import java.io.File;
>> > > > > +import java.util.List;
>> > > > > +
>> > > > > +import org.apache.lucene.analysis.StopAnalyzer;
>> > > > > +import
org.apache.lucene.analysis.standard.StandardAnalyzer;
>> > > > > +import org.apache.lucene.index.IndexReader;
>> > > > > +import org.apache.lucene.index.Term; import
>> > > > > +org.apache.lucene.index.TermDocs; import
>> > > > > +org.apache.lucene.queryParser.QueryParser;
>> > > > > +import org.apache.lucene.search.Hits; import
>> > > > > +org.apache.lucene.search.IndexSearcher;
>> > > > > +import org.apache.lucene.search.Query; import
>> > > > org.hibernate.Session;
>> > > > > +import org.hibernate.event.PostDeleteEventListener;
>> > > > > +import org.hibernate.event.PostInsertEventListener;
>> > > > > +import org.hibernate.event.PostUpdateEventListener;
>> > > > > +import org.hibernate.lucene.Environment; import
>> > > > > +org.hibernate.lucene.store.FSDirectoryProvider;
>> > > > > +import org.hibernate.lucene.event.LuceneEventListener;
>> > > > > +
>> > > > > +/**
>> > > > > + * @author Richard Hallier
>> > > > > + */
>> > > > > +public class FieldMappingTest extends TestCase {
>> > > > > +
>> > > > > +
>> > > > > + protected void setUp() throws Exception {
>> > > > > + File sub = getBaseIndexDir();
>> > > > > + sub.mkdir();
>> > > > > + File[] files = sub.listFiles();
>> > > > > + for (File file : files) {
>> > > > > + if ( file.isDirectory() ) {
>> > > > > + delete( file );
>> > > > > + }
>> > > > > + }
>> > > > > + //super.setUp(); //we need a fresh session
>> > > > factory each time for index set up
>> > > > > + buildSessionFactory( getMappings(),
>> > > > getAnnotatedPackages(), getXmlFiles() );
>> > > > > + }
>> > > > > +
>> > > > > + private File getBaseIndexDir() {
>> > > > > + File current = new File( "." );
>> > > > > + File sub = new File( current,
"indextemp" );
>> > > > > + return sub;
>> > > > > + }
>> > > > > +
>> > > > > + protected void tearDown() throws Exception {
>> > > > > + super.tearDown();
>> > > > > + File sub = getBaseIndexDir();
>> > > > > + delete( sub );
>> > > > > + }
>> > > > > +
>> > > > > + private void delete(File sub) {
>> > > > > + if ( sub.isDirectory() ) {
>> > > > > + for ( File file : sub.listFiles() ) {
>> > > > > + delete( file );
>> > > > > + }
>> > > > > + sub.delete();
>> > > > > + }
>> > > > > + else {
>> > > > > + sub.delete();
>> > > > > + }
>> > > > > + }
>> > > > > +
>> > > > > + public void testEventIntegration() throws Exception {
>> > > > > +
>> > > > > +
>> > > > > + Session s = getSessions().openSession();
>> > > > > + s.getTransaction().begin();
>> > > > > + s.persist(
>> > > > > + new Document2( "Hibernate
in
>> > > > Action", "Object/relational mapping with
Hibernate", "blah blah
>> > > > blah" )
>> > > > > + );
>> > > > > + s.getTransaction().commit();
>> > > > > + s.close();
>> > > > > + IndexReader reader = IndexReader.open( new
>> > > > File( getBaseIndexDir(), "Documents" ) );
>> > > > > + try {
>> > > > > + int num = reader.numDocs();
>> > > > > + assertEquals( 1, num );
>> > > > > + TermDocs docs = reader.termDocs( new
>> > > > Term( "Abstract", "Hibernate" ) );
>> > > > > + org.apache.lucene.document.Document doc
>> > > > = reader.document( docs.doc() );
>> > > > > + assertFalse( docs.next() );
>> > > > > + docs = reader.termDocs( new Term(
>> > > > "Title", "Action" ) );
>> > > > > + doc = reader.document( docs.doc() );
>> > > > > + assertFalse( docs.next() );
>> > > > > + assertEquals( "1",
doc.getField( "id"
>> > > ).stringValue() );
>> > > > > + }
>> > > > > + finally {
>> > > > > + reader.close();
>> > > > > + }
>> > > > > +
>> > > > > + s = getSessions().openSession();
>> > > > > + s.getTransaction().begin();
>> > > > > + Document2 entity = (Document2) s.get(
>> > > > Document2.class, new Long( 1 ) );
>> > > > > + entity.setSummary( "Object/relational
mapping
>> > > > with EJB3" );
>> > > > > + s.persist( new Document2( "Seam in
Action", "",
>> > > > "blah blah blah blah" ) );
>> > > > > + s.getTransaction().commit();
>> > > > > + s.close();
>> > > > > +
>> > > > > + reader = IndexReader.open( new File(
>> > > > getBaseIndexDir(), "Documents" ) );
>> > > > > + try {
>> > > > > + int num = reader.numDocs();
>> > > > > + assertEquals( 2, num );
>> > > > > + TermDocs docs = reader.termDocs( new
>> > > > Term( "Abstract", "EJB3" ) );
>> > > > > + org.apache.lucene.document.Document doc
>> > > > = reader.document( docs.doc() );
>> > > > > + assertFalse( docs.next() );
>> > > > > + }
>> > > > > + finally {
>> > > > > + reader.close();
>> > > > > + }
>> > > > > +
>> > > > > + s = getSessions().openSession();
>> > > > > + s.getTransaction().begin();
>> > > > > + s.delete( entity );
>> > > > > + s.getTransaction().commit();
>> > > > > + s.close();
>> > > > > +
>> > > > > + reader = IndexReader.open( new File(
>> > > > getBaseIndexDir(), "Documents" ) );
>> > > > > + try {
>> > > > > + int num = reader.numDocs();
>> > > > > + assertEquals( 1, num );
>> > > > > + TermDocs docs = reader.termDocs( new
>> > > > Term( "Title", "Seam" ) );
>> > > > > + org.apache.lucene.document.Document doc
>> > > > = reader.document( docs.doc() );
>> > > > > + assertFalse( docs.next() );
>> > > > > + assertEquals( "2",
doc.getField( "id"
>> > > ).stringValue() );
>> > > > > + }
>> > > > > + finally {
>> > > > > + reader.close();
>> > > > > + }
>> > > > > +
>> > > > > + s = getSessions().openSession();
>> > > > > + s.getTransaction().begin();
>> > > > > + s.delete( s.createCriteria( Document2.class
>> > > > ).uniqueResult() );
>> > > > > + s.getTransaction().commit();
>> > > > > + s.close();
>> > > > > + }
>> > > > > +
>> > > > > + public void testBoost() throws Exception {
>> > > > > + Session s = getSessions().openSession();
>> > > > > + s.getTransaction().begin();
>> > > > > + s.persist(
>> > > > > + new Document2( "Hibernate
in
>> > > > Action", "Object and Relational", "blah blah
blah" )
>> > > > > + );
>> > > > > + s.persist(
>> > > > > + new Document2( "Object and
>> > > > Relational", "Hibernate in Action", "blah
blah blah" )
>> > > > > + );
>> > > > > + s.getTransaction().commit();
>> > > > > + s.close();
>> > > > > +
>> > > > > + IndexSearcher searcher = new IndexSearcher( new
>> > > > File( getBaseIndexDir(), "Documents"
).getCanonicalPath() );
>> > > > > + try {
>> > > > > + QueryParser qp = new QueryParser(
"id",
>> > > > new StandardAnalyzer() );
>> > > > > + Query query = qp.parse(
"title:Action
>> > > > OR Abstract:Action" );
>> > > > > + Hits hits = searcher.search( query );
>> > > > > + assertEquals( 2, hits.length() );
>> > > > > + assertTrue( hits.score( 0 ) == 2 *
>> > > > hits.score( 1 ) );
>> > > > > + assertEquals( "Hibernate in
Action",
>> > > > hits.doc( 0 ).get( "title" ) );
>> > > > > + }
>> > > > > + finally {
>> > > > > + if ( searcher != null )
searcher.close();
>> > > > > + }
>> > > > > +
>> > > > > +
>> > > > > + s = getSessions().openSession();
>> > > > > + s.getTransaction().begin();
>> > > > > + List list = s.createQuery( "from
Document2"
>> > ).list();
>> > > > > + for ( Document2 document :
>> > (List<Document2>) list ) {
>> > > > > + s.delete( document );
>> > > > > + }
>> > > > > + s.getTransaction().commit();
>> > > > > + s.close();
>> > > > > + }
>> > > > > +
>> > > > > + protected Class[] getMappings() {
>> > > > > + return new Class[]{Document2.class};
>> > > > > + }
>> > > > > +
>> > > > > + protected void
>> > configure(org.hibernate.cfg.Configuration cfg) {
>> > > > > + File sub = getBaseIndexDir();
>> > > > > + cfg.setProperty(
>> > > > "hibernate.lucene.default.indexBase",
sub.getAbsolutePath() );
>> > > > > + cfg.setProperty(
>> > > > "hibernate.lucene.Clock.directory_provider",
>> > > > FSDirectoryProvider.class.getName() );
>> > > > > + cfg.setProperty( Environment.ANALYZER_CLASS,
>> > > > StopAnalyzer.class.getName() );
>> > > > > + LuceneEventListener del = new
LuceneEventListener();
>> > > > > + > > >
>> cfg.getEventListeners().setPostCommitDeleteEventListeners(
>> > > > new PostDeleteEventListener[]{del} );
>> > > > > + > > >
>> cfg.getEventListeners().setPostCommitUpdateEventListeners(
>> > > > new PostUpdateEventListener[]{del} );
>> > > > > + > > >
>> cfg.getEventListeners().setPostCommitInsertEventListeners(
>> > > > new PostInsertEventListener[]{del} );
>> > > > > + }
>> > > > > +
>> > > > > +}
>> > > > > +
>> > > > > Index:
>> > > > >
>> > > >
>> > C:/dev/source/workspace1.5/HibernateExt/metadata/src/test/org/hibern
>> > > > at
>> > > > > e/lucene/test/Document2.java
>> > > > >
>> > ==================================================================
>> > > > > =
>> > > > > ---
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/test/org/
>> > > > hibernate/lucene/test/Document2.java (revision 0)
>> > > > > +++
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/test/org/
>> > > > hibernate/lucene/test/Document2.java (revision 0)
>> > > > > @@ -0,0 +1,75 @@
>> > > > > +//$Id: Document.java 10566 2006-10-11 04:01:11Z 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.lucene.Indexed; import
>> > > > > +org.hibernate.lucene.Keyword; import
>> > org.hibernate.lucene.Text;
>> > > > > +import org.hibernate.lucene.Unstored; import
>> > > > > +org.hibernate.lucene.Boost;
>> > > > > +
>> > > > > +@Entity
>> > > > > +@Indexed(index = "Documents")
>> > > > > +public class Document2 {
>> > > > > + @Id
>> > > > > + @GeneratedValue
>> > > > > + @Keyword(id = true)
>> > > > > + private Long id;
>> > > > > +
>> > > > > + @Text
>> > > > > + @Boost(2)
>> > > > > + private String title;
>> > > > > + > > > > + @Unstored(name =
"Abstract")
>> > > > > + private String summary;
>> > > > > +
>> > > > > + @Lob
>> > > > > + @Unstored
>> > > > > + private String text;
>> > > > > +
>> > > > > + Document2() {
>> > > > > + }
>> > > > > +
>> > > > > + public Document2(String title, String summary,
>> > String text) {
>> > > > > + super();
>> > > > > + this.summary = summary;
>> > > > > + this.text = text;
>> > > > > + this.title = title;
>> > > > > + }
>> > > > > +
>> > > > > + public Long getId() {
>> > > > > + return id;
>> > > > > + }
>> > > > > +
>> > > > > + public void setId(Long id) {
>> > > > > + this.id = id;
>> > > > > + }
>> > > > > +
>> > > > > + public String getTitle() {
>> > > > > + return title;
>> > > > > + }
>> > > > > +
>> > > > > + public void setTitle(String title) {
>> > > > > + this.title = title;
>> > > > > + }
>> > > > > +
>> > > > > + public String getSummary() {
>> > > > > + return summary;
>> > > > > + }
>> > > > > +
>> > > > > + public void setSummary(String summary) {
>> > > > > + this.summary = summary;
>> > > > > + }
>> > > > > +
>> > > > > + public String getText() {
>> > > > > + return text;
>> > > > > + }
>> > > > > +
>> > > > > + public void setText(String text) {
>> > > > > + this.text = text;
>> > > > > + }
>> > > > > +}
>> > > > > Index:
>> > > > >
>> > > >
>> > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/hibern
>> > > > at
>> > > > > e/lucene/event/LuceneEventListener.java
>> > > > >
>> > ==================================================================
>> > > > > =
>> > > > > ---
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/event/LuceneEventListener.java >
(revision
>> 10571)
>> > > > > +++
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/event/LuceneEventListener.java >
(working
>> copy)
>> > > > > @@ -99,13 +99,10 @@
>> > > > > PersistentClass clazz = (PersistentClass)
>> > iter.next();
>> > > > > Class<?> mappedClass =
clazz.getMappedClass();
>> > > > > if (mappedClass != null) {
>> > > > > - if
>> > > > (mappedClass.isAnnotationPresent(Indexed.class)) {
>> > > > > - DirectoryProvider provider =
>> > > > factory.createDirectoryProvider(mappedClass, cfg);
>> > > > > - final DocumentBuilder<Object>
>> > > > documentBuilder = new DocumentBuilder<Object>(
>> > > > > - (Class<Object>)
mappedClass,
>> > > > analyzer, provider
>> > > > > - );
>> > > > > - if (!indexLock.containsKey(provider))
{
>> > > > > - indexLock.put(provider, new
>> > > > ReentrantLock());
>> > > > > + final DocumentBuilder documentBuilder =
>> > > > DocumentBuilder.createDocumentBuilder(mappedClass, analyzer,
>> > > > factory, cfg);
>> > > > > + if(documentBuilder!=null) {
>> > > > > + if
>> > > >
(!indexLock.containsKey(documentBuilder.getDirectoryProvider())) {
>> > > > > + > > > >
>> + indexLock.put(documentBuilder.getDirectoryProvider(), new
>> > > > > + ReentrantLock());
>> > > > > }
>> > > > > documentBuilders.put(mappedClass,
>> > > > documentBuilder);
>> > > > > }
>> > > > > Index:
>> > > > >
>> > > >
>> > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/hibern
>> > > > at
>> > > > > e/lucene/Unstored.java
>> > > > >
>> > ==================================================================
>> > > > > =
>> > > > > ---
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/Unstored.java (revision 10571)
>> > > > > +++
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/Unstored.java (working copy)
>> > > > > @@ -8,7 +8,7 @@
>> > > > > import java.lang.annotation.Target;
>> > > > >
>> > > > > @Retention(RetentionPolicy.RUNTIME)
>> > > > > -(a)Target(ElementType.METHOD)
>> > > > > +(a)Target({ElementType.METHOD, ElementType.FIELD})
>> > > > > @Documented
>> > > > > /**
>> > > > > * Specifies that a property of an entity is a Lucene
>> > > > > Index:
>> > > > >
>> > > >
>> > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/hibern
>> > > > at
>> > > > > e/lucene/Keyword.java
>> > > > >
>> > ==================================================================
>> > > > > =
>> > > > > ---
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/Keyword.java (revision 10571)
>> > > > > +++
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/Keyword.java (working copy)
>> > > > > @@ -8,7 +8,7 @@
>> > > > > import java.lang.annotation.Target;
>> > > > >
>> > > > > @Retention(RetentionPolicy.RUNTIME)
>> > > > > -(a)Target(ElementType.METHOD)
>> > > > > +(a)Target({ElementType.METHOD, ElementType.FIELD})
>> > > > > @Documented
>> > > > > /**
>> > > > > * Specifies that a property of an entity is a Lucene
>> > > > > Index:
>> > > > >
>> > > >
>> > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/hibern
>> > > > at
>> > > > > e/lucene/Text.java
>> > > > >
>> > ==================================================================
>> > > > > =
>> > > > > ---
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/Text.java (revision 10571)
>> > > > > +++
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/Text.java (working copy)
>> > > > > @@ -8,7 +8,7 @@
>> > > > > import java.lang.annotation.Target;
>> > > > >
>> > > > > @Retention(RetentionPolicy.RUNTIME)
>> > > > > -(a)Target(ElementType.METHOD)
>> > > > > +(a)Target({ElementType.METHOD, ElementType.FIELD})
>> > > > > @Documented
>> > > > > /**
>> > > > > * Specifies that a property of an entity is a Lucene
>> > > > > Index:
>> > > > >
>> > > >
>> > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/hibern
>> > > > at
>> > > > > e/lucene/DocumentBuilder.java
>> > > > >
>> > ==================================================================
>> > > > > =
>> > > > > ---
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/DocumentBuilder.java (revision 10571)
>> > > > > +++
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/DocumentBuilder.java (working copy)
>> > > > > @@ -2,10 +2,6 @@
>> > > > > package org.hibernate.lucene;
>> > > > >
>> > > > > import java.io.Serializable;
>> > > > > -import java.lang.reflect.AccessibleObject;
>> > > > > -import java.lang.reflect.AnnotatedElement;
>> > > > > -import java.lang.reflect.Member;
>> > > > > -import java.lang.reflect.Method;
>> > > > > import java.lang.reflect.Modifier; import
>> > java.util.ArrayList; > > > > import java.util.Collections; @@
-17,31
>> +13,46 @@ import
>> > > > > org.apache.lucene.document.Document;
>> > > > > import org.apache.lucene.document.Field; import
>> > > > > org.apache.lucene.index.Term; -import
>> > > > org.hibernate.AssertionFailure;
>> > > > > import org.hibernate.HibernateException;
>> > > > > +import org.hibernate.cfg.Configuration;
>> > > > > import org.hibernate.cfg.annotations.Version;
>> > > > > import org.hibernate.lucene.bridge.BridgeFactory;
>> > > > > import org.hibernate.lucene.bridge.FieldBridge;
>> > > > > import org.hibernate.lucene.event.LuceneEventListener;
>> > > > > import org.hibernate.lucene.store.DirectoryProvider;
>> > > > > +import
org.hibernate.lucene.store.DirectoryProviderFactory;
>> > > > > import org.hibernate.lucene.util.BinderHelper;
>> > > > > +import org.hibernate.reflection.ReflectionManager;
>> > > > > +import org.hibernate.reflection.XAnnotatedElement;
>> > > > > +import org.hibernate.reflection.XClass; import
>> > > > > +org.hibernate.reflection.XMember;
>> > > > > +import org.hibernate.reflection.XMethod; import
>> > > > > +org.hibernate.reflection.XProperty;
>> > > > > +import org.hibernate.reflection.java.JavaXFactory;
>> > > > > import org.hibernate.util.ReflectHelper;
>> > > > >
>> > > > > -//TODO handle attribute (only getters are handled
currently)
>> > > > > +/**
>> > > > > + * Set up and provide a manager for indexes classes
>> > > > > + *
>> > > > > + * @author Gavin King
>> > > > > + * @author Emmanuel Bernard
>> > > > > + * @author Sylvain Vieujot
>> > > > > + */
>> > > > > public class DocumentBuilder<T> {
>> > > > >
>> > > > > static {
>> > > > > Version.touch(); //touch version
>> > > > > }
>> > > > >
>> > > > > - private final List<Member> keywordGetters = new
>> > > > ArrayList<Member>();
>> > > > > + private final List<XMember> keywordGetters = new
>> > > > > + ArrayList<XMember>();
>> > > > > private final List<String> keywordNames = new
>> > > > ArrayList<String>();
>> > > > > - private final List<Member> unstoredGetters = new
>> > > > ArrayList<Member>();
>> > > > > + private final List<XMember> unstoredGetters =
new
>> > > > > + ArrayList<XMember>();
>> > > > > private final List<String> unstoredNames = new
>> > > > ArrayList<String>();
>> > > > > - private final List<Member> textGetters = new
>> > > > ArrayList<Member>();
>> > > > > + private final List<XMember> textGetters = new
>> > > > > + ArrayList<XMember>();
>> > > > > private final List<String> textNames = new
>> > > > > ArrayList<String>();
>> > > > >
>> > > > > private final Class<T> beanClass;
>> > > > > + > > > > private final DirectoryProvider
>> directoryProvider;
>> > > > > private String idKeywordName;
>> > > > > private final Analyzer analyzer; @@ -50,40 +61,30 @@
>> > > > > private FieldBridge idBridge;
>> > > > > private Set<Class> mappedSubclasses = new
HashSet<Class>();
>> > > > >
>> > > > > - public DocumentBuilder(Class<T> clazz, Analyzer
>> > > > analyzer, DirectoryProvider directory) {
>> > > > > - this.beanClass = clazz;
>> > > > > + private ReflectionManager reflectionManager = new
>> > > > JavaXFactory();
>> > > > > +
>> > > > > + private DocumentBuilder(Class<T> clazz, Analyzer
analyzer,
>> > > > > +DirectoryProvider directory) {
>> > > > > +
>> > > > > + XClass beanXClass =
>> > reflectionManager.toXClass( clazz );
>> > > > > + if(
!beanXClass.isAnnotationPresent(Indexed.class))
>> > > > > + throw new IllegalArgumentException();
>> > > > > + > > > > +
this.beanClass = clazz;
>> > > > > this.analyzer = analyzer;
>> > > > > this.directoryProvider = directory;
>> > > > >
>> > > > > - for (Class currClass = clazz; currClass != null;
>> > > > currClass = currClass.getSuperclass()) {
>> > > > > - Method[] methods =
currClass.getDeclaredMethods();
>> > > > > - for (int i = 0; i < methods.length; i++) {
>> > > > > - Method method = methods[i];
>> > > > > - Keyword keywordAnn =
>> > > > method.getAnnotation(Keyword.class);
>> > > > > - if (keywordAnn != null) {
>> > > > > - String name =
>> > > > BinderHelper.getAttributeName(method, keywordAnn.name());
>> > > > > - if (keywordAnn.id()) {
>> > > > > - idKeywordName = name;
>> > > > > - idBoost = getBoost(method);
>> > > > > - idBridge =
>> > BridgeFactory.guessType(method);
>> > > > > - } else {
>> > > > > - setAccessible(method);
>> > > > > - keywordGetters.add(method);
>> > > > > - keywordNames.add(name);
>> > > > > - }
>> > > > > - }
>> > > > > - Unstored unstoredAnn =
>> > > > method.getAnnotation(Unstored.class);
>> > > > > - if (unstoredAnn != null) {
>> > > > > - setAccessible(method);
>> > > > > - unstoredGetters.add(method);
>> > > > > - > > >
>> unstoredNames.add(BinderHelper.getAttributeName(method,
>> > > > unstoredAnn.name()));
>> > > > > - }
>> > > > > - Text textAnn =
>> > method.getAnnotation(Text.class);
>> > > > > - if (textAnn != null) {
>> > > > > - textGetters.add(method);
>> > > > > - > > >
>> textNames.add(BinderHelper.getAttributeName(method,
>> > > > textAnn.name()));
>> > > > > - }
>> > > > > - }
>> > > > > +
>> > > > > + for (XClass currClass = beanXClass; currClass !=
>> > > > null; currClass = currClass.getSuperclass()) {
>> > > > > + List<XMethod> methods =
>> > > > currClass.getDeclaredMethods();
>> > > > > + for ( XMethod method : methods ) {
>> > > > > + >
>> createMemberLuceneAttribute( method );
>> > > > > + }
>> > > > > +
>> > > > > + // No filter applied = default filter (
>> > > > no transient, no static fields)
>> > > > > + List<XProperty> fields =
>> > > > currClass.getDeclaredProperties("field");
>> > > > > + for ( XProperty field : fields ) {
>> > > > > + > createMemberLuceneAttribute(
field
>> );
>> > > > > + }
>> > > > > }
>> > > > >
>> > > > > if (idKeywordName == null) { @@ -91,42 +92,84 @@
>> > > > > }
>> > > > > }
>> > > > >
>> > > > > + public static <S> DocumentBuilder<S>
>> > > > createDocumentBuilder(Class<S> clazz, Analyzer analyzer,
>> > > > DirectoryProviderFactory factory, Configuration cfg)
>> > > > > + {
>> > > > > + DocumentBuilder<S> result = null;
>> > > > > + > > > > + try {
>> > > > > + result = new
DocumentBuilder<S>(clazz,
>> > > > analyzer, factory.createDirectoryProvider(clazz, cfg));
>> > > > > + }
>> > > > > + catch (Exception e) {
>> > > > > + }
>> > > > > + > > > > + return result;
>> > > > > + } > > > >
>> > > > > - private Float getBoost(AnnotatedElement element) {
>> > > > > + private void createMemberLuceneAttribute(XMember member)
{
>> > > > > + Keyword keywordAnn =
>> > > > member.getAnnotation(Keyword.class);
>> > > > > + if (keywordAnn != null) {
>> > > > > + String name =
>> > > > BinderHelper.getAttributeName(member, keywordAnn.name());
>> > > > > + if (keywordAnn.id()) {
>> > > > > + idKeywordName = name;
>> > > > > + idBoost = getBoost(member);
>> > > > > + idBridge =
BridgeFactory.guessType(member);
>> > > > > + } else {
>> > > > > + setAccessible(member);
>> > > > > + keywordGetters.add(member);
>> > > > > + keywordNames.add(name);
>> > > > > + }
>> > > > > + }
>> > > > > +
>> > > > > + Unstored unstoredAnn =
>> > > > member.getAnnotation(Unstored.class);
>> > > > > + if (unstoredAnn != null) {
>> > > > > + setAccessible(member);
>> > > > > + unstoredGetters.add(member);
>> > > > > + > > >
>> unstoredNames.add(BinderHelper.getAttributeName(member,
>> > > > unstoredAnn.name()));
>> > > > > + }
>> > > > > +
>> > > > > + Text textAnn = member.getAnnotation(Text.class);
>> > > > > + if (textAnn != null) {
>> > > > > + setAccessible(member);
>> > > > > + textGetters.add(member);
>> > > > > + > > >
>> textNames.add(BinderHelper.getAttributeName(member,
>> > > > textAnn.name()));
>> > > > > + }
>> > > > > + }
>> > > > > +
>> > > > > + private Float getBoost(XAnnotatedElement element) {
>> > > > > if (element == null) return null;
>> > > > > Boost boost = element.getAnnotation(Boost.class);
>> > > > > return boost != null ?
>> > Float.valueOf(boost.value()) : null;
>> > > > > }
>> > > > >
>> > > > > - private Object getValue(Member member, T bean) {
>> > > > > - try {
>> > > > > - if (member instanceof java.lang.reflect.Field)
{
>> > > > > - return ((java.lang.reflect.Field)
>> > > > member).get(bean);
>> > > > > - } else if (member instanceof Method) {
>> > > > > - return ((Method) member).invoke(bean);
>> > > > > - } else {
>> > > > > - throw new
AssertionFailure("Unexpected
>> > > > member: " + member.getClass().getName());
>> > > > > - }
>> > > > > - }
>> > > > > - catch (Exception e) {
>> > > > > - throw new IllegalStateException("Could not
get
>> > > > property value", e);
>> > > > > - }
>> > > > > + private Object getMemberValue(XMember member, T bean)
{
>> > > > > + Object value;
>> > > > > + try {
>> > > > > + value = member.invoke( bean );
>> > > > > + }
>> > > > > + catch (Exception e) {
>> > > > > + throw new IllegalStateException(
"Could
>> > > > not get property value", e );
>> > > > > + }
>> > > > > + return value;
>> > > > > }
>> > > > >
>> > > > > public Document getDocument(T instance, Serializable
id) {
>> > > > > + XClass xClazz =
>> > > > reflectionManager.toXClass(instance.getClass());
>> > > > > + > > > > Document doc = new
Document();
>> > > > > - Float boost = getBoost(instance.getClass());
>> > > > > + Float boost = getBoost(xClazz);
>> > > > > if (boost != null) {
>> > > > > doc.setBoost(boost.floatValue());
>> > > > > }
>> > > > > +
>> > > > > {
>> > > > > - Field classField = new Field(CLASS_FIELDNAME,
>> > > > instance.getClass().getName(), Field.Store.YES, Field.Index.NO);
>> > > > > + Field classField = new Field(CLASS_FIELDNAME,
>> > > > > + xClazz.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);
>> > > > > - Object value = getValue(member, instance);
>> > > > > + XMember member = keywordGetters.get(i);
>> > > > > + Object value = getMemberValue(member,
instance);
>> > > > > if (value != null) {
>> > > > > Field field = new
>> > > > Field(keywordNames.get(i), toString(value), Field.Store.YES,
>> > > > Field.Index.UN_TOKENIZED);
>> > > > > boostField(field, member); @@ -134,8 +177,8
@@
>> > > > > }
>> > > > > }
>> > > > > for (int i = 0; i < textNames.size(); i++) {
>> > > > > - Member member = textGetters.get(i);
>> > > > > - Object value = getValue(member, instance);
>> > > > > + XMember member = textGetters.get(i);
>> > > > > + Object value = getMemberValue(member,
instance);
>> > > > > if (value != null) {
>> > > > > Field field = new Field(textNames.get(i),
>> > > > toString(value), Field.Store.YES, Field.Index.TOKENIZED);
>> > > > > boostField(field, member); @@ -143,8 +186,8
@@
>> > > > > }
>> > > > > }
>> > > > > for (int i = 0; i < unstoredNames.size(); i++)
{
>> > > > > - Member member = unstoredGetters.get(i);
>> > > > > - Object value = getValue(member, instance);
>> > > > > + XMember member = unstoredGetters.get(i);
>> > > > > + Object value = getMemberValue(member,
instance);
>> > > > > if (value != null) {
>> > > > > Field field = new
>> > > > Field(unstoredNames.get(i), toString(value), Field.Store.NO,
>> > > > Field.Index.TOKENIZED);
>> > > > > boostField(field, member); @@ -155,8 +198,8
@@
>> > > > > return doc;
>> > > > > }
>> > > > >
>> > > > > - private void boostField(Field field, Member member) {
>> > > > > - Float boost = getBoost((AnnotatedElement) member);
>> > > > > + private void boostField(Field field, XMember member) {
>> > > > > + Float boost = getBoost(member);
>> > > > > if (boost != null)
field.setBoost(boost.floatValue());
>> > > > > }
>> > > > >
>> > > > > @@ -176,11 +219,11 @@
>> > > > > return analyzer;
>> > > > > }
>> > > > >
>> > > > > - private static void setAccessible(Member member) {
>> > > > > - if (!Modifier.isPublic(member.getModifiers())) {
>> > > > > - ((AccessibleObject)
member).setAccessible(true);
>> > > > > - }
>> > > > > - }
>> > > > > + private static void setAccessible(XMember member) {
>> > > > > + if ( !Modifier.isPublic( member.getModifiers()
) ) {
>> > > > > + member.setAccessible( true );
>> > > > > + }
>> > > > > + }
>> > > > >
>> > > > > public FieldBridge getIdBridge() {
>> > > > > return idBridge;
>> > > > > Index:
>> > > > >
>> > > >
>> > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/hibern
>> > > > at
>> > > > > e/lucene/Boost.java
>> > > > >
>> > ==================================================================
>> > > > > =
>> > > > > ---
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/Boost.java (revision 10571)
>> > > > > +++
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/Boost.java (working copy)
>> > > > > @@ -13,7 +13,7 @@
>> > > > > * @author Emmanuel Bernard
>> > > > > */
>> > > > > @Retention(RetentionPolicy.RUNTIME)
>> > > > > -(a)Target({ElementType.TYPE, ElementType.METHOD})
>> > > > > +(a)Target({ElementType.TYPE, ElementType.METHOD,
>> > > > > +ElementType.FIELD})
>> > > > > @Documented
>> > > > > public @interface Boost {
>> > > > > float value();
>> > > > > Index:
>> > > > >
>> > > >
>> > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/hibern
>> > > > at
>> > > > > e/lucene/bridge/BridgeFactory.java
>> > > > >
>> > ==================================================================
>> > > > > =
>> > > > > ---
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/bridge/BridgeFactory.java (revision 10571)
>> > > > > +++
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/bridge/BridgeFactory.java (working copy)
>> > > > > @@ -1,8 +1,6 @@
>> > > > > //$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;
>> > > > > @@ -10,6 +8,8 @@
>> > > > > import org.hibernate.HibernateException; import
>> > > > > org.hibernate.annotations.Parameter;
>> > > > > import org.hibernate.lucene.util.BinderHelper;
>> > > > > +import org.hibernate.reflection.XClass; import
>> > > > > +org.hibernate.reflection.XMember;
>> > > > >
>> > > > > /**
>> > > > > * @author Emmanuel Bernard
>> > > > > @@ -62,9 +62,9 @@
>> > > > > return new String2FieldBridgeAdaptor( date );
>> > > > > }
>> > > > >
>> > > > > - public static FieldBridge guessType(Member member) {
>> > > > > + public static FieldBridge guessType(XMember member) {
>> > > > > FieldBridge bridge = null;
>> > > > > - org.hibernate.lucene.FieldBridge bridgeAnn = (
>> > > > (AnnotatedElement) member ).getAnnotation(
>> > > > org.hibernate.lucene.FieldBridge.class );
>> > > > > + org.hibernate.lucene.FieldBridge bridgeAnn =
>> > > > member.getAnnotation(
>> > > > > +org.hibernate.lucene.FieldBridge.class );
>> > > > > if (bridgeAnn != null) {
>> > > > > Class impl = bridgeAnn.impl();
>> > > > > try {
>> > > > > @@ -89,7 +89,7 @@
>> > > > > }
>> > > > > else {
>> > > > > //find in built-ins
>> > > > > - Class<?> returnType =
>> > > > BinderHelper.getReturnType( member );
>> > > > > + XClass returnType =
>> > > > BinderHelper.getReturnType( member );
>> > > > > bridge = builtInBridges.get(
>> > > > returnType.getName() );
>> > > > > }
>> > > > > if (bridge == null) throw new
>> > > > HibernateException("Unable to guess
>> > > > > FieldBridge for " +
BinderHelper.getAttributeName(member) );
>> > > > > Index:
>> > > > >
>> > > >
>> > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/hibern
>> > > > at
>> > > > > e/lucene/util/BinderHelper.java
>> > > > >
>> > ==================================================================
>> > > > > =
>> > > > > ---
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/util/BinderHelper.java (revision 10571)
>> > > > > +++
>> > > > C:/dev/source/workspace1.5/HibernateExt/metadata/src/java/org/
>> > > > hibernate/lucene/util/BinderHelper.java (working copy)
>> > > > > @@ -1,11 +1,13 @@
>> > > > > //$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.AssertionFailure; import
>> > > > > +org.hibernate.reflection.XClass; import
>> > > > > +org.hibernate.reflection.XMember;
>> > > > > +import org.hibernate.reflection.XMethod; import
>> > > > > +org.hibernate.reflection.XProperty;
>> > > > > import org.hibernate.util.StringHelper;
>> > > > >
>> > > > > /**
>> > > > > @@ -15,37 +17,41 @@
>> > > > >
>> > > > > private BinderHelper() {}
>> > > > >
>> > > > > - public static String getAttributeName(Member member) {
>> > > > > + public static String getAttributeName(XMember 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();
>> > > > > + public static String getAttributeName(XMember member,
>> > > > String name) {
>> > > > > + return StringHelper.isNotEmpty( name ) ? name :
>> > > > getPropertyName(member);
>> > > > > + }
>> > > > > +
>> > > > > + public static XClass getReturnType(XMember member) {
>> > > > > + return member.getType();
>> > > > > + }
>> > > > > + > > > > + // Could be located in a better
place, shared
>> method
>> > > > with ClassValidator
>> > > > > + public static String getPropertyName(XMember member) {
>> > > > > + //Do no try to cache the result in a map,
it's
>> > > > actually much slower (2.x time)
>> > > > > + String propertyName;
>> > > > > + if ( XProperty.class.isAssignableFrom(
>> > > > member.getClass() ) ) {
>> > > > > + propertyName = 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;
>> > > > > + else if ( XMethod.class.isAssignableFrom(
>> > > > member.getClass() ) ) {
>> > > > > + propertyName = member.getName();
>> > > > > + if ( propertyName.startsWith(
"is" ) ) {
>> > > > > + propertyName =
>> > > > Introspector.decapitalize( propertyName.substring(
>> > > > > +2 ) );
>> > > > > }
>> > > > > - return Introspector.decapitalize(
>> > > > methodName.substring( startIndex ) );
>> > > > > + else if ( propertyName.startsWith(
>> > "get" ) ) {
>> > > > > + propertyName =
>> > > > Introspector.decapitalize( propertyName.substring( 3 ) );
>> > > > > + }
>> > > > > + //do nothing for non getter method, in
>> > > > case someone want to
>> > > > > +validate a PO Method
>> > > > > }
>> > > > > - }
>> > > > > -
>> > > > > - //TODO move to reflection layer
>> > > > > - public static Class<?> getReturnType(Member
member) {
>> > > > > - if (member instanceof Field) {
>> > > > > - return ( (Field) member ).getType();
>> > > > > - }
>> > > > > else {
>> > > > > - return ( (Method) member
).getReturnType();
>> > > > > + throw new AssertionFailure(
"Unexpected
>> > > > member: " +
>> > > > > +member.getClass().getName() );
>> > > > > }
>> > > > > + return propertyName;
>> > > > > }
>> > > > > +
>> > > > > }
>> > > > > > > >
>> > >
>> >
>>
> _______________________________________________
> hibernate-dev mailing list
> hibernate-dev(a)lists.jboss.org
>
https://lists.jboss.org/mailman/listinfo/hibernate-dev
--
--
Max Rydahl Andersen
callto://max.rydahl.andersen
Hibernate
max(a)hibernate.org
http://hibernate.org
JBoss a division of Red Hat
max.andersen(a)jboss.com