From hibernate-commits at lists.jboss.org Mon Aug 18 08:28:59 2008 Content-Type: multipart/mixed; boundary="===============1839822446926121209==" MIME-Version: 1.0 From: hibernate-commits at lists.jboss.org To: hibernate-commits at lists.jboss.org Subject: [hibernate-commits] Hibernate SVN: r15092 - in search/trunk: src/java/org/hibernate/search/bridge and 1 other directories. Date: Mon, 18 Aug 2008 08:28:58 -0400 Message-ID: --===============1839822446926121209== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Author: navssurtani Date: 2008-08-18 08:28:57 -0400 (Mon, 18 Aug 2008) New Revision: 15092 Modified: search/trunk/doc/reference/en/modules/mapping.xml search/trunk/src/java/org/hibernate/search/bridge/BridgeFactory.java search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java Log: Finished @ProvidedId documentation in mapping.xml and @ProvidedId can now b= e set on superclass Modified: search/trunk/doc/reference/en/modules/mapping.xml =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- search/trunk/doc/reference/en/modules/mapping.xml 2008-08-15 21:20:15 U= TC (rev 15091) +++ search/trunk/doc/reference/en/modules/mapping.xml 2008-08-18 12:28:57 U= TC (rev 15092) @@ -1136,4 +1136,35 @@ + +
+ Providing your own id + = + You can provide your own id for Hibernate Search if you are extendi= ng the internals. You will have to generate a unique value so it can be giv= en to Lucene to + be indexed. This will have to be given to Hibernate Search when you crea= te an org.hibernate.search.Work object - the document id is required in the= constructor. + + = +
+ The @ProvidedId annotation + = + Unlike conventional Hibernate Search API and @DocumentId, this an= notation is used on the class and not a field. You also can provide your ow= n bridge implementation when you put in this annotation by calling the brid= ge() which is on @ProvidedId. Also, if you annotate a class with @ProvidedI= d, your subclasses will also get the annotation - but it is not done by usi= ng the java.lang.annotations.(a)Inherited. Be sure however, to no= t use this annotation with @DocumentId as your system will break. + + = + + = + @ProvidedId (bridge =3D org.my.own.package.MyCustomBridge) + @Indexed + public class MyClass{ + = + @Field + String MyString; + = + ... + = + } + = + = + = +
+
= \ No newline at end of file Modified: search/trunk/src/java/org/hibernate/search/bridge/BridgeFactory.j= ava =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- search/trunk/src/java/org/hibernate/search/bridge/BridgeFactory.java 20= 08-08-15 21:20:15 UTC (rev 15091) +++ search/trunk/src/java/org/hibernate/search/bridge/BridgeFactory.java 20= 08-08-18 12:28:57 UTC (rev 15092) @@ -293,11 +293,11 @@ } } catch (Exception e) { - throw new HibernateException( "Unable to instantiate FieldB= ridge for " + ClassBridge.class.getName(), e ); + throw new HibernateException( "Unable to instantiate FieldB= ridge for " + org.hibernate.search.annotations.FieldBridge.class.getName(),= e ); } } } - if ( bridge =3D=3D null ) throw new SearchException( "Unable to gues= s FieldBridge for " + ClassBridge.class.getName() ); + if ( bridge =3D=3D null ) throw new SearchException( "Unable to gues= s FieldBridge for " + org.hibernate.search.annotations.FieldBridge.class.ge= tName() ); = return bridge; } Modified: search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder= .java =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java = 2008-08-15 21:20:15 UTC (rev 15091) +++ search/trunk/src/java/org/hibernate/search/engine/DocumentBuilder.java = 2008-08-18 12:28:57 UTC (rev 15092) @@ -67,808 +67,832 @@ * @author Richard Hallier * @author Hardy Ferentschik */ -(a)SuppressWarnings( "unchecked" ) +(a)SuppressWarnings("unchecked") public class DocumentBuilder { - private static final Logger log =3D LoggerFactory.getLogger( DocumentBuil= der.class ); + private static final Logger log =3D LoggerFactory.getLogger(DocumentBui= lder.class); = - private final PropertiesMetadata rootPropertiesMetadata =3D new Propertie= sMetadata(); - private final XClass beanClass; - private final DirectoryProvider[] directoryProviders; - private final IndexShardingStrategy shardingStrategy; - private String idKeywordName; - private XMember idGetter; - private Float idBoost; - public static final String CLASS_FIELDNAME =3D "_hibernate_class"; - private TwoWayFieldBridge idBridge; - private Set mappedSubclasses =3D new HashSet(); - private ReflectionManager reflectionManager; - private int level =3D 0; - private int maxLevel =3D Integer.MAX_VALUE; - private final ScopedAnalyzer analyzer =3D new ScopedAnalyzer(); - private Similarity similarity; - private boolean isRoot; - //if composite id, use of (a, b) in ((1,2), (3,4)) fails on most database - private boolean safeFromTupleId; - private boolean idProvided =3D false; + private final PropertiesMetadata rootPropertiesMetadata =3D new Propert= iesMetadata(); + private final XClass beanClass; + private final DirectoryProvider[] directoryProviders; + private final IndexShardingStrategy shardingStrategy; + private String idKeywordName; + private XMember idGetter; + private Float idBoost; + public static final String CLASS_FIELDNAME =3D "_hibernate_class"; + private TwoWayFieldBridge idBridge; + private Set mappedSubclasses =3D new HashSet(); + private ReflectionManager reflectionManager; + private int level =3D 0; + private int maxLevel =3D Integer.MAX_VALUE; + private final ScopedAnalyzer analyzer =3D new ScopedAnalyzer(); + private Similarity similarity; + private boolean isRoot; + //if composite id, use of (a, b) in ((1,2), (3,4)) fails on most databa= se + private boolean safeFromTupleId; + private boolean idProvided =3D false; = = - public boolean isRoot() { - return isRoot; - } + public boolean isRoot() { + return isRoot; + } = - public DocumentBuilder(XClass clazz, InitContext context, DirectoryProvid= er[] directoryProviders, - IndexShardingStrategy shardingStrategy, ReflectionManager reflect= ionManager) { - this.beanClass =3D clazz; - this.directoryProviders =3D directoryProviders; - this.shardingStrategy =3D shardingStrategy; - //FIXME get rid of it when boost is stored? - this.reflectionManager =3D reflectionManager; - this.similarity =3D context.getDefaultSimilarity(); + public DocumentBuilder(XClass clazz, InitContext context, DirectoryProv= ider[] directoryProviders, + IndexShardingStrategy shardingStrategy, Reflecti= onManager reflectionManager) { + this.beanClass =3D clazz; + this.directoryProviders =3D directoryProviders; + this.shardingStrategy =3D shardingStrategy; + //FIXME get rid of it when boost is stored? + this.reflectionManager =3D reflectionManager; + this.similarity =3D context.getDefaultSimilarity(); = - if ( clazz =3D=3D null ) throw new AssertionFailure( "Unable to build a = DocumentBuilder with a null class" ); - rootPropertiesMetadata.boost =3D getBoost( clazz ); - rootPropertiesMetadata.analyzer =3D context.getDefaultAnalyzer(); - Set processedClasses =3D new HashSet(); - processedClasses.add( clazz ); - initializeMembers( clazz, rootPropertiesMetadata, true, "", processedCla= sses, context ); - //processedClasses.remove( clazz ); for the sake of completness - this.analyzer.setGlobalAnalyzer( rootPropertiesMetadata.analyzer ); - if ( idKeywordName =3D=3D null ) { - // if no DocumentId then check if we have a ProvidedId instead - ProvidedId provided =3D clazz.getAnnotation( org.hibernate.search.annot= ations.ProvidedId.class ); - if ( provided =3D=3D null ) throw new SearchException( "No document id = in: " + clazz.getName() ); + if (clazz =3D=3D null) throw new AssertionFailure("Unable to build a= DocumentBuilder with a null class"); + rootPropertiesMetadata.boost =3D getBoost(clazz); + rootPropertiesMetadata.analyzer =3D context.getDefaultAnalyzer(); + Set processedClasses =3D new HashSet(); + processedClasses.add(clazz); + initializeMembers(clazz, rootPropertiesMetadata, true, "", processed= Classes, context); + //processedClasses.remove( clazz ); for the sake of completness + this.analyzer.setGlobalAnalyzer(rootPropertiesMetadata.analyzer); + if (idKeywordName =3D=3D null) { + // if no DocumentId then check if we have a ProvidedId instead + ProvidedId provided =3D findProvidedId(clazz); + if (provided =3D=3D null) throw new SearchException("No document = id in: " + clazz.getName()); = - idBridge =3D BridgeFactory.extractTwoWayType(provided.bridge()); - idKeywordName =3D provided.name(); - } - //if composite id, use of (a, b) in ((1,2)TwoWayString2FieldBridgeAdapto= r, (3,4)) fails on most database - //a TwoWayString2FieldBridgeAdaptor is never a composite id - safeFromTupleId =3D TwoWayString2FieldBridgeAdaptor.class.isAssignableFr= om( idBridge.getClass() ); - } + idBridge =3D BridgeFactory.extractTwoWayType(provided.bridge()); + idKeywordName =3D provided.name(); + } + //if composite id, use of (a, b) in ((1,2)TwoWayString2FieldBridgeAd= aptor, (3,4)) fails on most database + //a TwoWayString2FieldBridgeAdaptor is never a composite id + safeFromTupleId =3D TwoWayString2FieldBridgeAdaptor.class.isAssignab= leFrom(idBridge.getClass()); + } = - private Analyzer getAnalyzer(XAnnotatedElement annotatedElement, InitCont= ext context) { - org.hibernate.search.annotations.Analyzer analyzerAnn =3D - annotatedElement.getAnnotation( org.hibernate.search.annotations.Analy= zer.class ); - return getAnalyzer( analyzerAnn, context ); - } + private ProvidedId findProvidedId(XClass clazz) { + ProvidedId id =3D clazz.getAnnotation(ProvidedId.class); + if (id =3D=3D null) { + if (clazz.getClass().equals(Object.class)) { + // no superclass! + return null; + } + else { + // look at superclass + return findProvidedId(clazz.getSuperclass()); + } + } + else { + return id; + } + } = - private Analyzer getAnalyzer(org.hibernate.search.annotations.Analyzer an= alyzerAnn, InitContext context) { - Class analyzerClass =3D analyzerAnn =3D=3D null ? void.class : analyzerA= nn.impl(); - if ( analyzerClass =3D=3D void.class ) { - String definition =3D analyzerAnn =3D=3D null ? "" : analyzerAnn.defini= tion(); - if ( StringHelper.isEmpty( definition ) ) { - return null; - } - else { + private Analyzer getAnalyzer(XAnnotatedElement annotatedElement, InitCo= ntext context) { + org.hibernate.search.annotations.Analyzer analyzerAnn =3D + annotatedElement.getAnnotation(org.hibernate.search.annotati= ons.Analyzer.class); + return getAnalyzer(analyzerAnn, context); + } = - return context.buildLazyAnalyzer( definition ); - } - } - else { - try { - return (Analyzer) analyzerClass.newInstance(); - } - catch (ClassCastException e) { - throw new SearchException( - "Lucene analyzer does not implement " + Analyzer.class.getName() + "= : " + analyzerClass.getName(), e - ); - } - catch (Exception e) { - throw new SearchException( "Failed to instantiate lucene analyzer with= type " + analyzerClass.getName(), e ); - } - } - } + private Analyzer getAnalyzer(org.hibernate.search.annotations.Analyzer = analyzerAnn, InitContext context) { + Class analyzerClass =3D analyzerAnn =3D=3D null ? void.class : analy= zerAnn.impl(); + if (analyzerClass =3D=3D void.class) { + String definition =3D analyzerAnn =3D=3D null ? "" : analyzerAnn.= definition(); + if (StringHelper.isEmpty(definition)) { + return null; + } + else { = - private void initializeMembers(XClass clazz, PropertiesMetadata propertie= sMetadata, boolean isRoot, String prefix, - Set processedClasses, InitContext context) { - List hierarchy =3D new ArrayList(); - for (XClass currClass =3D clazz; currClass !=3D null; currClass =3D curr= Class.getSuperclass()) { - hierarchy.add( currClass ); - } - Class similarityClass =3D null; - for (int index =3D hierarchy.size() - 1; index >=3D 0; index--) { - XClass currClass =3D hierarchy.get( index ); - /** - * Override the default analyzer for the properties if the class hold o= ne - * That's the reason we go down the hierarchy - */ - Analyzer analyzer =3D getAnalyzer( currClass, context ); + return context.buildLazyAnalyzer(definition); + } + } + else { + try { + return (Analyzer) analyzerClass.newInstance(); + } + catch (ClassCastException e) { + throw new SearchException( + "Lucene analyzer does not implement " + Analyzer.class= .getName() + ": " + analyzerClass.getName(), e + ); + } + catch (Exception e) { + throw new SearchException("Failed to instantiate lucene analyz= er with type " + analyzerClass.getName(), e); + } + } + } = - if ( analyzer !=3D null ) { - propertiesMetadata.analyzer =3D analyzer; - } - getAnalyzerDefs( currClass, context ); - // Check for any ClassBridges annotation. - ClassBridges classBridgesAnn =3D currClass.getAnnotation( ClassBridges.= class ); - if ( classBridgesAnn !=3D null ) { - ClassBridge[] cbs =3D classBridgesAnn.value(); - for (ClassBridge cb : cbs) { - bindClassAnnotation( prefix, propertiesMetadata, cb, context ); - } - } + private void initializeMembers(XClass clazz, PropertiesMetadata propert= iesMetadata, boolean isRoot, String prefix, + Set processedClasses, InitContex= t context) { + List hierarchy =3D new ArrayList(); + for (XClass currClass =3D clazz; currClass !=3D null; currClass =3D = currClass.getSuperclass()) { + hierarchy.add(currClass); + } + Class similarityClass =3D null; + for (int index =3D hierarchy.size() - 1; index >=3D 0; index--) { + XClass currClass =3D hierarchy.get(index); + /** + * Override the default analyzer for the properties if the class = hold one + * That's the reason we go down the hierarchy + */ + Analyzer analyzer =3D getAnalyzer(currClass, context); = - // Check for any ClassBridge style of annotations. - ClassBridge classBridgeAnn =3D currClass.getAnnotation( ClassBridge.cla= ss ); - if ( classBridgeAnn !=3D null ) { - bindClassAnnotation( prefix, propertiesMetadata, classBridgeAnn, conte= xt ); - } + if (analyzer !=3D null) { + propertiesMetadata.analyzer =3D analyzer; + } + getAnalyzerDefs(currClass, context); + // Check for any ClassBridges annotation. + ClassBridges classBridgesAnn =3D currClass.getAnnotation(ClassBri= dges.class); + if (classBridgesAnn !=3D null) { + ClassBridge[] cbs =3D classBridgesAnn.value(); + for (ClassBridge cb : cbs) { + bindClassAnnotation(prefix, propertiesMetadata, cb, context= ); + } + } = - //Get similarity - //TODO: similarity form @IndexedEmbedded are not taken care of. Excepti= on?? - if ( isRoot ) { - org.hibernate.search.annotations.Similarity similarityAnn =3D currClas= s.getAnnotation( org.hibernate.search.annotations.Similarity.class ); - if ( similarityAnn !=3D null ) { - if ( similarityClass !=3D null ) { - throw new SearchException( "Multiple Similarities defined in the sam= e class hierarchy: " + beanClass.getName() ); - } - similarityClass =3D similarityAnn.impl(); - } - } + // Check for any ClassBridge style of annotations. + ClassBridge classBridgeAnn =3D currClass.getAnnotation(ClassBridg= e.class); + if (classBridgeAnn !=3D null) { + bindClassAnnotation(prefix, propertiesMetadata, classBridgeAnn= , context); + } = - //rejecting non properties (ie regular methods) because the object is l= oaded from Hibernate, - // so indexing a non property does not make sense - List methods =3D currClass.getDeclaredProperties( XClass.ACC= ESS_PROPERTY ); - for (XProperty method : methods) { - initializeMember( method, propertiesMetadata, isRoot, prefix, processe= dClasses, context ); - } + //Get similarity + //TODO: similarity form @IndexedEmbedded are not taken care of. E= xception?? + if (isRoot) { + org.hibernate.search.annotations.Similarity similarityAnn =3D = currClass.getAnnotation(org.hibernate.search.annotations.Similarity.class); + if (similarityAnn !=3D null) { + if (similarityClass !=3D null) { + throw new SearchException("Multiple Similarities defined= in the same class hierarchy: " + beanClass.getName()); + } + similarityClass =3D similarityAnn.impl(); + } + } = - List fields =3D currClass.getDeclaredProperties( XClass.ACCE= SS_FIELD ); - for (XProperty field : fields) { - initializeMember( field, propertiesMetadata, isRoot, prefix, processed= Classes, context ); - } - } - if ( isRoot && similarityClass !=3D null ) { - try { - similarity =3D (Similarity) similarityClass.newInstance(); - } - catch (Exception e) { - log.error( "Exception attempting to instantiate Similarity '{}' set fo= r {}", - similarityClass.getName(), beanClass.getName() ); - } - } - } + //rejecting non properties (ie regular methods) because the objec= t is loaded from Hibernate, + // so indexing a non property does not make sense + List methods =3D currClass.getDeclaredProperties(XClas= s.ACCESS_PROPERTY); + for (XProperty method : methods) { + initializeMember(method, propertiesMetadata, isRoot, prefix, p= rocessedClasses, context); + } = - private void getAnalyzerDefs(XAnnotatedElement annotatedElement, InitCont= ext context) { - AnalyzerDefs defs =3D annotatedElement.getAnnotation( AnalyzerDefs.class= ); - if ( defs !=3D null ) { - for (AnalyzerDef def : defs.value()) { - context.addAnalyzerDef( def ); - } - } - AnalyzerDef def =3D annotatedElement.getAnnotation( AnalyzerDef.class ); - context.addAnalyzerDef( def ); - } + List fields =3D currClass.getDeclaredProperties(XClass= .ACCESS_FIELD); + for (XProperty field : fields) { + initializeMember(field, propertiesMetadata, isRoot, prefix, pr= ocessedClasses, context); + } + } + if (isRoot && similarityClass !=3D null) { + try { + similarity =3D (Similarity) similarityClass.newInstance(); + } + catch (Exception e) { + log.error("Exception attempting to instantiate Similarity '{}'= set for {}", + similarityClass.getName(), beanClass.getName()); + } + } + } = - public String getIdentifierName() { - return idGetter.getName(); - } + private void getAnalyzerDefs(XAnnotatedElement annotatedElement, InitCo= ntext context) { + AnalyzerDefs defs =3D annotatedElement.getAnnotation(AnalyzerDefs.cl= ass); + if (defs !=3D null) { + for (AnalyzerDef def : defs.value()) { + context.addAnalyzerDef(def); + } + } + AnalyzerDef def =3D annotatedElement.getAnnotation(AnalyzerDef.class= ); + context.addAnalyzerDef(def); + } = - public Similarity getSimilarity() { - return similarity; - } + public String getIdentifierName() { + return idGetter.getName(); + } = - private void initializeMember(XProperty member, PropertiesMetadata proper= tiesMetadata, boolean isRoot, - String prefix, Set processedClasses, InitContext context= ) { + public Similarity getSimilarity() { + return similarity; + } = - DocumentId documentIdAnn =3D member.getAnnotation( DocumentId.class ); - if ( documentIdAnn !=3D null ) { - if ( isRoot ) { - if ( idKeywordName !=3D null ) { - throw new AssertionFailure( "Two document id assigned: " - + idKeywordName + " and " + BinderHelper.getAttributeName( member, = documentIdAnn.name() ) ); - } - idKeywordName =3D prefix + BinderHelper.getAttributeName( member, docu= mentIdAnn.name() ); - FieldBridge fieldBridge =3D BridgeFactory.guessType( null, member, ref= lectionManager ); - if ( fieldBridge instanceof TwoWayFieldBridge ) { - idBridge =3D (TwoWayFieldBridge) fieldBridge; - } - else { - throw new SearchException( - "Bridge for document id does not implement TwoWayFieldBridge: " + m= ember.getName() ); - } - idBoost =3D getBoost( member ); - setAccessible( member ); - idGetter =3D member; - } - else { - //component should index their document id - setAccessible( member ); - propertiesMetadata.fieldGetters.add( member ); - String fieldName =3D prefix + BinderHelper.getAttributeName( member, d= ocumentIdAnn.name() ); - propertiesMetadata.fieldNames.add( fieldName ); - propertiesMetadata.fieldStore.add( getStore( Store.YES ) ); - propertiesMetadata.fieldIndex.add( getIndex( Index.UN_TOKENIZED ) ); - propertiesMetadata.fieldTermVectors.add( getTermVector( TermVector.NO = ) ); - propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( null, me= mber, reflectionManager ) ); - // property > entity analyzer (no field analyzer) - Analyzer analyzer =3D getAnalyzer( member, context ); - if ( analyzer =3D=3D null ) analyzer =3D propertiesMetadata.analyzer; - if ( analyzer =3D=3D null ) throw new AssertionFailure( "Analizer shou= ld not be undefined" ); - this.analyzer.addScopedAnalyzer( fieldName, analyzer ); - } - } - { - org.hibernate.search.annotations.Field fieldAnn =3D - member.getAnnotation( org.hibernate.search.annotations.Field.class ); - if ( fieldAnn !=3D null ) { - bindFieldAnnotation( member, propertiesMetadata, prefix, fieldAnn, con= text ); - } - } - { - org.hibernate.search.annotations.Fields fieldsAnn =3D - member.getAnnotation( org.hibernate.search.annotations.Fields.class ); - if ( fieldsAnn !=3D null ) { - for (org.hibernate.search.annotations.Field fieldAnn : fieldsAnn.value= ()) { - bindFieldAnnotation( member, propertiesMetadata, prefix, fieldAnn, co= ntext ); - } - } - } - getAnalyzerDefs( member, context ); + private void initializeMember(XProperty member, PropertiesMetadata prop= ertiesMetadata, boolean isRoot, + String prefix, Set processedClass= es, InitContext context) { = - IndexedEmbedded embeddedAnn =3D member.getAnnotation( IndexedEmbedded.cl= ass ); - if ( embeddedAnn !=3D null ) { - int oldMaxLevel =3D maxLevel; - int potentialLevel =3D embeddedAnn.depth() + level; - if ( potentialLevel < 0 ) { - potentialLevel =3D Integer.MAX_VALUE; - } - maxLevel =3D potentialLevel > maxLevel ? maxLevel : potentialLevel; - level++; + DocumentId documentIdAnn =3D member.getAnnotation(DocumentId.class); + if (documentIdAnn !=3D null) { + if (isRoot) { + if (idKeywordName !=3D null) { + throw new AssertionFailure("Two document id assigned: " + + idKeywordName + " and " + BinderHelper.getAttribu= teName(member, documentIdAnn.name())); + } + idKeywordName =3D prefix + BinderHelper.getAttributeName(membe= r, documentIdAnn.name()); + FieldBridge fieldBridge =3D BridgeFactory.guessType(null, memb= er, reflectionManager); + if (fieldBridge instanceof TwoWayFieldBridge) { + idBridge =3D (TwoWayFieldBridge) fieldBridge; + } + else { + throw new SearchException( + "Bridge for document id does not implement TwoWayFi= eldBridge: " + member.getName()); + } + idBoost =3D getBoost(member); + setAccessible(member); + idGetter =3D member; + } + else { + //component should index their document id + setAccessible(member); + propertiesMetadata.fieldGetters.add(member); + String fieldName =3D prefix + BinderHelper.getAttributeName(me= mber, documentIdAnn.name()); + propertiesMetadata.fieldNames.add(fieldName); + propertiesMetadata.fieldStore.add(getStore(Store.YES)); + propertiesMetadata.fieldIndex.add(getIndex(Index.UN_TOKENIZED)= ); + propertiesMetadata.fieldTermVectors.add(getTermVector(TermVect= or.NO)); + propertiesMetadata.fieldBridges.add(BridgeFactory.guessType(nu= ll, member, reflectionManager)); + // property > entity analyzer (no field analyzer) + Analyzer analyzer =3D getAnalyzer(member, context); + if (analyzer =3D=3D null) analyzer =3D propertiesMetadata.anal= yzer; + if (analyzer =3D=3D null) throw new AssertionFailure("Analizer= should not be undefined"); + this.analyzer.addScopedAnalyzer(fieldName, analyzer); + } + } + { + org.hibernate.search.annotations.Field fieldAnn =3D + member.getAnnotation(org.hibernate.search.annotations.Fie= ld.class); + if (fieldAnn !=3D null) { + bindFieldAnnotation(member, propertiesMetadata, prefix, fieldA= nn, context); + } + } + { + org.hibernate.search.annotations.Fields fieldsAnn =3D + member.getAnnotation(org.hibernate.search.annotations.Fie= lds.class); + if (fieldsAnn !=3D null) { + for (org.hibernate.search.annotations.Field fieldAnn : fieldsA= nn.value()) { + bindFieldAnnotation(member, propertiesMetadata, prefix, fie= ldAnn, context); + } + } + } + getAnalyzerDefs(member, context); = - XClass elementClass; - if ( void.class =3D=3D embeddedAnn.targetElement() ) { - elementClass =3D member.getElementClass(); - } - else { - elementClass =3D reflectionManager.toXClass( embeddedAnn.targetElement= () ); - } - if ( maxLevel =3D=3D Integer.MAX_VALUE //infinite - && processedClasses.contains( elementClass ) ) { - throw new SearchException( - "Circular reference. Duplicate use of " - + elementClass.getName() - + " in root entity " + beanClass.getName() - + "#" + buildEmbeddedPrefix( prefix, embeddedAnn, member ) - ); - } - if ( level <=3D maxLevel ) { - processedClasses.add( elementClass ); //push + IndexedEmbedded embeddedAnn =3D member.getAnnotation(IndexedEmbedded= .class); + if (embeddedAnn !=3D null) { + int oldMaxLevel =3D maxLevel; + int potentialLevel =3D embeddedAnn.depth() + level; + if (potentialLevel < 0) { + potentialLevel =3D Integer.MAX_VALUE; + } + maxLevel =3D potentialLevel > maxLevel ? maxLevel : potentialLeve= l; + level++; = - setAccessible( member ); - propertiesMetadata.embeddedGetters.add( member ); - PropertiesMetadata metadata =3D new PropertiesMetadata(); - propertiesMetadata.embeddedPropertiesMetadata.add( metadata ); - metadata.boost =3D getBoost( member ); - //property > entity analyzer - Analyzer analyzer =3D getAnalyzer( member, context ); - metadata.analyzer =3D analyzer !=3D null ? analyzer : propertiesMetada= ta.analyzer; - String localPrefix =3D buildEmbeddedPrefix( prefix, embeddedAnn, membe= r ); - initializeMembers( elementClass, metadata, false, localPrefix, process= edClasses, context ); - /** - * We will only index the "expected" type but that's OK, HQL cannot do= downcasting either - */ - if ( member.isArray() ) { - propertiesMetadata.embeddedContainers.add( PropertiesMetadata.Contain= er.ARRAY ); - } - else if ( member.isCollection() ) { - if ( Map.class.equals( member.getCollectionClass() ) ) { - //hum subclasses etc etc?? - propertiesMetadata.embeddedContainers.add( PropertiesMetadata.Contai= ner.MAP ); - } - else { - propertiesMetadata.embeddedContainers.add( PropertiesMetadata.Contai= ner.COLLECTION ); - } - } - else { - propertiesMetadata.embeddedContainers.add( PropertiesMetadata.Contain= er.OBJECT ); - } + XClass elementClass; + if (void.class =3D=3D embeddedAnn.targetElement()) { + elementClass =3D member.getElementClass(); + } + else { + elementClass =3D reflectionManager.toXClass(embeddedAnn.target= Element()); + } + if (maxLevel =3D=3D Integer.MAX_VALUE //infinite + && processedClasses.contains(elementClass)) { + throw new SearchException( + "Circular reference. Duplicate use of " + + elementClass.getName() + + " in root entity " + beanClass.getName() + + "#" + buildEmbeddedPrefix(prefix, embeddedAn= n, member) + ); + } + if (level <=3D maxLevel) { + processedClasses.add(elementClass); //push = - processedClasses.remove( elementClass ); //pop - } - else if ( log.isTraceEnabled() ) { - String localPrefix =3D buildEmbeddedPrefix( prefix, embeddedAnn, membe= r ); - log.trace( "depth reached, ignoring {}", localPrefix ); - } + setAccessible(member); + propertiesMetadata.embeddedGetters.add(member); + PropertiesMetadata metadata =3D new PropertiesMetadata(); + propertiesMetadata.embeddedPropertiesMetadata.add(metadata); + metadata.boost =3D getBoost(member); + //property > entity analyzer + Analyzer analyzer =3D getAnalyzer(member, context); + metadata.analyzer =3D analyzer !=3D null ? analyzer : properti= esMetadata.analyzer; + String localPrefix =3D buildEmbeddedPrefix(prefix, embeddedAnn= , member); + initializeMembers(elementClass, metadata, false, localPrefix, = processedClasses, context); + /** + * We will only index the "expected" type but that's OK, HQL c= annot do downcasting either + */ + if (member.isArray()) { + propertiesMetadata.embeddedContainers.add(PropertiesMetadat= a.Container.ARRAY); + } + else + if (member.isCollection()) { + if (Map.class.equals(member.getCollectionClass())) { + //hum subclasses etc etc?? + propertiesMetadata.embeddedContainers.add(PropertiesM= etadata.Container.MAP); + } + else { + propertiesMetadata.embeddedContainers.add(PropertiesM= etadata.Container.COLLECTION); + } + } + else { + propertiesMetadata.embeddedContainers.add(PropertiesMeta= data.Container.OBJECT); + } = - level--; - maxLevel =3D oldMaxLevel; //set back the the old max level - } + processedClasses.remove(elementClass); //pop + } + else + if (log.isTraceEnabled()) { + String localPrefix =3D buildEmbeddedPrefix(prefix, embedded= Ann, member); + log.trace("depth reached, ignoring {}", localPrefix); + } = - ContainedIn containedAnn =3D member.getAnnotation( ContainedIn.class ); - if ( containedAnn !=3D null ) { - setAccessible( member ); - propertiesMetadata.containedInGetters.add( member ); - } - } + level--; + maxLevel =3D oldMaxLevel; //set back the the old max level + } = - private void bindClassAnnotation(String prefix, PropertiesMetadata proper= tiesMetadata, ClassBridge ann, InitContext context) { - //FIXME name should be prefixed - String fieldName =3D prefix + ann.name(); - propertiesMetadata.classNames.add( fieldName ); - propertiesMetadata.classStores.add( getStore( ann.store() ) ); - propertiesMetadata.classIndexes.add( getIndex( ann.index() ) ); - propertiesMetadata.classTermVectors.add( getTermVector( ann.termVector()= ) ); - propertiesMetadata.classBridges.add( BridgeFactory.extractType( ann ) ); - propertiesMetadata.classBoosts.add( ann.boost().value() ); + ContainedIn containedAnn =3D member.getAnnotation(ContainedIn.class); + if (containedAnn !=3D null) { + setAccessible(member); + propertiesMetadata.containedInGetters.add(member); + } + } = - Analyzer analyzer =3D getAnalyzer( ann.analyzer(), context ); - if ( analyzer =3D=3D null ) analyzer =3D propertiesMetadata.analyzer; - if ( analyzer =3D=3D null ) throw new AssertionFailure( "Analyzer should= not be undefined" ); - this.analyzer.addScopedAnalyzer( fieldName, analyzer ); - } + private void bindClassAnnotation(String prefix, PropertiesMetadata prop= ertiesMetadata, ClassBridge ann, InitContext context) { + //FIXME name should be prefixed + String fieldName =3D prefix + ann.name(); + propertiesMetadata.classNames.add(fieldName); + propertiesMetadata.classStores.add(getStore(ann.store())); + propertiesMetadata.classIndexes.add(getIndex(ann.index())); + propertiesMetadata.classTermVectors.add(getTermVector(ann.termVector= ())); + propertiesMetadata.classBridges.add(BridgeFactory.extractType(ann)); + propertiesMetadata.classBoosts.add(ann.boost().value()); = - private void bindFieldAnnotation(XProperty member, PropertiesMetadata pro= pertiesMetadata, String prefix, org.hibernate.search.annotations.Field fiel= dAnn, InitContext context) { - setAccessible( member ); - propertiesMetadata.fieldGetters.add( member ); - String fieldName =3D prefix + BinderHelper.getAttributeName( member, fie= ldAnn.name() ); - propertiesMetadata.fieldNames.add( fieldName ); - propertiesMetadata.fieldStore.add( getStore( fieldAnn.store() ) ); - propertiesMetadata.fieldIndex.add( getIndex( fieldAnn.index() ) ); - propertiesMetadata.fieldTermVectors.add( getTermVector( fieldAnn.termVec= tor() ) ); - propertiesMetadata.fieldBridges.add( BridgeFactory.guessType( fieldAnn, = member, reflectionManager ) ); + Analyzer analyzer =3D getAnalyzer(ann.analyzer(), context); + if (analyzer =3D=3D null) analyzer =3D propertiesMetadata.analyzer; + if (analyzer =3D=3D null) throw new AssertionFailure("Analyzer shoul= d not be undefined"); + this.analyzer.addScopedAnalyzer(fieldName, analyzer); + } = - // Field > property > entity analyzer - Analyzer analyzer =3D getAnalyzer( fieldAnn.analyzer(), context ); - if ( analyzer =3D=3D null ) analyzer =3D getAnalyzer( member, context ); - if ( analyzer =3D=3D null ) analyzer =3D propertiesMetadata.analyzer; - if ( analyzer =3D=3D null ) throw new AssertionFailure( "Analizer should= not be undefined" ); - this.analyzer.addScopedAnalyzer( fieldName, analyzer ); - } + private void bindFieldAnnotation(XProperty member, PropertiesMetadata p= ropertiesMetadata, String prefix, org.hibernate.search.annotations.Field fi= eldAnn, InitContext context) { + setAccessible(member); + propertiesMetadata.fieldGetters.add(member); + String fieldName =3D prefix + BinderHelper.getAttributeName(member, = fieldAnn.name()); + propertiesMetadata.fieldNames.add(fieldName); + propertiesMetadata.fieldStore.add(getStore(fieldAnn.store())); + propertiesMetadata.fieldIndex.add(getIndex(fieldAnn.index())); + propertiesMetadata.fieldTermVectors.add(getTermVector(fieldAnn.termV= ector())); + propertiesMetadata.fieldBridges.add(BridgeFactory.guessType(fieldAnn= , member, reflectionManager)); = - private String buildEmbeddedPrefix(String prefix, IndexedEmbedded embedde= dAnn, XProperty member) { - String localPrefix =3D prefix; - if ( ".".equals( embeddedAnn.prefix() ) ) { - //default to property name - localPrefix +=3D member.getName() + '.'; - } - else { - localPrefix +=3D embeddedAnn.prefix(); - } - return localPrefix; - } + // Field > property > entity analyzer + Analyzer analyzer =3D getAnalyzer(fieldAnn.analyzer(), context); + if (analyzer =3D=3D null) analyzer =3D getAnalyzer(member, context); + if (analyzer =3D=3D null) analyzer =3D propertiesMetadata.analyzer; + if (analyzer =3D=3D null) throw new AssertionFailure("Analizer shoul= d not be undefined"); + this.analyzer.addScopedAnalyzer(fieldName, analyzer); + } = - private Field.Store getStore(Store store) { - switch ( store ) { - case NO: - return Field.Store.NO; - case YES: - return Field.Store.YES; - case COMPRESS: - return Field.Store.COMPRESS; - default: - throw new AssertionFailure( "Unexpected Store: " + store ); - } - } + private String buildEmbeddedPrefix(String prefix, IndexedEmbedded embed= dedAnn, XProperty member) { + String localPrefix =3D prefix; + if (".".equals(embeddedAnn.prefix())) { + //default to property name + localPrefix +=3D member.getName() + '.'; + } + else { + localPrefix +=3D embeddedAnn.prefix(); + } + return localPrefix; + } = - private Field.TermVector getTermVector(TermVector vector) { - switch ( vector ) { - case NO: - return Field.TermVector.NO; - case YES: - return Field.TermVector.YES; - case WITH_OFFSETS: - return Field.TermVector.WITH_OFFSETS; - case WITH_POSITIONS: - return Field.TermVector.WITH_POSITIONS; - case WITH_POSITION_OFFSETS: - return Field.TermVector.WITH_POSITIONS_OFFSETS; - default: - throw new AssertionFailure( "Unexpected TermVector: " + vector ); - } - } + private Field.Store getStore(Store store) { + switch (store) { + case NO: + return Field.Store.NO; + case YES: + return Field.Store.YES; + case COMPRESS: + return Field.Store.COMPRESS; + default: + throw new AssertionFailure("Unexpected Store: " + store); + } + } = - private Field.Index getIndex(Index index) { - switch ( index ) { - case NO: - return Field.Index.NO; - case NO_NORMS: - return Field.Index.NO_NORMS; - case TOKENIZED: - return Field.Index.TOKENIZED; - case UN_TOKENIZED: - return Field.Index.UN_TOKENIZED; - default: - throw new AssertionFailure( "Unexpected Index: " + index ); - } - } + private Field.TermVector getTermVector(TermVector vector) { + switch (vector) { + case NO: + return Field.TermVector.NO; + case YES: + return Field.TermVector.YES; + case WITH_OFFSETS: + return Field.TermVector.WITH_OFFSETS; + case WITH_POSITIONS: + return Field.TermVector.WITH_POSITIONS; + case WITH_POSITION_OFFSETS: + return Field.TermVector.WITH_POSITIONS_OFFSETS; + default: + throw new AssertionFailure("Unexpected TermVector: " + vector); + } + } = - private Float getBoost(XAnnotatedElement element) { - if ( element =3D=3D null ) return null; - Boost boost =3D element.getAnnotation( Boost.class ); - return boost !=3D null ? - boost.value() : - null; - } + private Field.Index getIndex(Index index) { + switch (index) { + case NO: + return Field.Index.NO; + case NO_NORMS: + return Field.Index.NO_NORMS; + case TOKENIZED: + return Field.Index.TOKENIZED; + case UN_TOKENIZED: + return Field.Index.UN_TOKENIZED; + default: + throw new AssertionFailure("Unexpected Index: " + index); + } + } = - private Object getMemberValue(Object bean, XMember getter) { - Object value; - try { - value =3D getter.invoke( bean ); - } - catch (Exception e) { - throw new IllegalStateException( "Could not get property value", e ); - } - return value; - } + private Float getBoost(XAnnotatedElement element) { + if (element =3D=3D null) return null; + Boost boost =3D element.getAnnotation(Boost.class); + return boost !=3D null ? + boost.value() : + null; + } = - //TODO could we use T instead of EntityClass? - public void addWorkToQueue(Class entityClass, T entity, Serializable id, = WorkType workType, List queue, SearchFactoryImplementor searchF= actoryImplementor) { - //TODO with the caller loop we are in a n^2: optimize it using a HashMap= for work recognition - for (LuceneWork luceneWork : queue) { - //any work on the same entity should be ignored - if ( luceneWork.getEntityClass() =3D=3D entityClass - ) { - Serializable currentId =3D luceneWork.getId(); - if ( currentId !=3D null && currentId.equals( id ) ) { //find a way to= use Type.equals(x,y) - return; - } - //TODO do something to avoid multiple PURGE ALL and OPTIMIZE - } + private Object getMemberValue(Object bean, XMember getter) { + Object value; + try { + value =3D getter.invoke(bean); + } + catch (Exception e) { + throw new IllegalStateException("Could not get property value", e= ); + } + return value; + } = - } - boolean searchForContainers =3D false; - String idInString =3D idBridge.objectToString( id ); - if ( workType =3D=3D WorkType.ADD ) { - Document doc =3D getDocument( entity, id ); - queue.add( new AddLuceneWork( id, idInString, entityClass, doc ) ); - searchForContainers =3D true; - } - else if ( workType =3D=3D WorkType.DELETE || workType =3D=3D WorkType.PU= RGE ) { - queue.add( new DeleteLuceneWork( id, idInString, entityClass ) ); - } - else if ( workType =3D=3D WorkType.PURGE_ALL ) { - queue.add( new PurgeAllLuceneWork( entityClass ) ); - } - else if ( workType =3D=3D WorkType.UPDATE || workType =3D=3D WorkType.CO= LLECTION ) { - Document doc =3D getDocument( entity, id ); - /** - * even with Lucene 2.1, use of indexWriter to update is not an option - * We can only delete by term, and the index doesn't have a term that - * uniquely identify the entry. - * But essentially the optimization we are doing is the same Lucene is = doing, the only extra cost is the - * double file opening. - */ - queue.add( new DeleteLuceneWork( id, idInString, entityClass ) ); - queue.add( new AddLuceneWork( id, idInString, entityClass, doc ) ); - searchForContainers =3D true; - } - else if ( workType =3D=3D WorkType.INDEX ) { - Document doc =3D getDocument( entity, id ); - queue.add( new DeleteLuceneWork( id, idInString, entityClass ) ); - LuceneWork work =3D new AddLuceneWork( id, idInString, entityClass, doc= ); - work.setBatch( true ); - queue.add( work ); - searchForContainers =3D true; - } + //TODO could we use T instead of EntityClass? + public void addWorkToQueue(Class entityClass, T entity, Serializable id= , WorkType workType, List queue, SearchFactoryImplementor searc= hFactoryImplementor) { + //TODO with the caller loop we are in a n^2: optimize it using a Has= hMap for work recognition + for (LuceneWork luceneWork : queue) { + //any work on the same entity should be ignored + if (luceneWork.getEntityClass() =3D=3D entityClass + ) { + Serializable currentId =3D luceneWork.getId(); + if (currentId !=3D null && currentId.equals(id)) { //find a wa= y to use Type.equals(x,y) + return; + } + //TODO do something to avoid multiple PURGE ALL and OPTIMIZE + } = - else { - throw new AssertionFailure( "Unknown WorkType: " + workType ); - } + } + boolean searchForContainers =3D false; + String idInString =3D idBridge.objectToString(id); + if (workType =3D=3D WorkType.ADD) { + Document doc =3D getDocument(entity, id); + queue.add(new AddLuceneWork(id, idInString, entityClass, doc)); + searchForContainers =3D true; + } + else + if (workType =3D=3D WorkType.DELETE || workType =3D=3D WorkType.P= URGE) { + queue.add(new DeleteLuceneWork(id, idInString, entityClass)); + } + else + if (workType =3D=3D WorkType.PURGE_ALL) { + queue.add(new PurgeAllLuceneWork(entityClass)); + } + else + if (workType =3D=3D WorkType.UPDATE || workType =3D=3D Work= Type.COLLECTION) { + Document doc =3D getDocument(entity, id); + /** + * even with Lucene 2.1, use of indexWriter to update is= not an option + * We can only delete by term, and the index doesn't hav= e a term that + * uniquely identify the entry. + * But essentially the optimization we are doing is the = same Lucene is doing, the only extra cost is the + * double file opening. + */ + queue.add(new DeleteLuceneWork(id, idInString, entityCla= ss)); + queue.add(new AddLuceneWork(id, idInString, entityClass,= doc)); + searchForContainers =3D true; + } + else + if (workType =3D=3D WorkType.INDEX) { + Document doc =3D getDocument(entity, id); + queue.add(new DeleteLuceneWork(id, idInString, entity= Class)); + LuceneWork work =3D new AddLuceneWork(id, idInString,= entityClass, doc); + work.setBatch(true); + queue.add(work); + searchForContainers =3D true; + } = - /** - * When references are changed, either null or another one, we expect di= rty checking to be triggered (both sides - * have to be updated) - * When the internal object is changed, we apply the {Add|Update}Work on= containedIns - */ - if ( searchForContainers ) { - processContainedIn( entity, queue, rootPropertiesMetadata, searchFactor= yImplementor ); - } - } + else { + throw new AssertionFailure("Unknown WorkType: " + wor= kType); + } = - private void processContainedIn(Object instance, List queue, = PropertiesMetadata metadata, SearchFactoryImplementor searchFactoryImplemen= tor) { - for (int i =3D 0; i < metadata.containedInGetters.size(); i++) { - XMember member =3D metadata.containedInGetters.get( i ); - Object value =3D getMemberValue( instance, member ); - if ( value =3D=3D null ) continue; + /** + * When references are changed, either null or another one, we expec= t dirty checking to be triggered (both sides + * have to be updated) + * When the internal object is changed, we apply the {Add|Update}Wor= k on containedIns + */ + if (searchForContainers) { + processContainedIn(entity, queue, rootPropertiesMetadata, searchF= actoryImplementor); + } + } = - if ( member.isArray() ) { - for (Object arrayValue : (Object[]) value) { - //highly inneficient but safe wrt the actual targeted class - Class valueClass =3D Hibernate.getClass( arrayValue ); - DocumentBuilder builder =3D searchFactoryImplementor.getDocumentBuild= ers().get( valueClass ); - if ( builder =3D=3D null ) continue; - processContainedInValue( arrayValue, queue, valueClass, builder, sear= chFactoryImplementor ); - } - } - else if ( member.isCollection() ) { - Collection collection; - if ( Map.class.equals( member.getCollectionClass() ) ) { - //hum - collection =3D ( (Map) value ).values(); - } - else { - collection =3D (Collection) value; - } - for (Object collectionValue : collection) { - //highly inneficient but safe wrt the actual targeted class - Class valueClass =3D Hibernate.getClass( collectionValue ); - DocumentBuilder builder =3D searchFactoryImplementor.getDocumentBuild= ers().get( valueClass ); - if ( builder =3D=3D null ) continue; - processContainedInValue( collectionValue, queue, valueClass, builder,= searchFactoryImplementor ); - } - } - else { - Class valueClass =3D Hibernate.getClass( value ); - DocumentBuilder builder =3D searchFactoryImplementor.getDocumentBuilde= rs().get( valueClass ); - if ( builder =3D=3D null ) continue; - processContainedInValue( value, queue, valueClass, builder, searchFact= oryImplementor ); - } - } - //an embedded cannot have a useful @ContainedIn (no shared reference) - //do not walk through them - } + private void processContainedIn(Object instance, List queue= , PropertiesMetadata metadata, SearchFactoryImplementor searchFactoryImplem= entor) { + for (int i =3D 0; i < metadata.containedInGetters.size(); i++) { + XMember member =3D metadata.containedInGetters.get(i); + Object value =3D getMemberValue(instance, member); + if (value =3D=3D null) continue; = - private void processContainedInValue(Object value, List queue= , Class valueClass, - DocumentBuilder builder, SearchFactoryImplementor searchFactory= Implementor) { - Serializable id =3D (Serializable) builder.getMemberValue( value, builde= r.idGetter ); - builder.addWorkToQueue( valueClass, value, id, WorkType.UPDATE, queue, s= earchFactoryImplementor ); - } + if (member.isArray()) { + for (Object arrayValue : (Object[]) value) { + //highly inneficient but safe wrt the actual targeted class + Class valueClass =3D Hibernate.getClass(arrayValue); + DocumentBuilder builder =3D searchFactoryImplementor.getDoc= umentBuilders().get(valueClass); + if (builder =3D=3D null) continue; + processContainedInValue(arrayValue, queue, valueClass, buil= der, searchFactoryImplementor); + } + } + else + if (member.isCollection()) { + Collection collection; + if (Map.class.equals(member.getCollectionClass())) { + //hum + collection =3D ((Map) value).values(); + } + else { + collection =3D (Collection) value; + } + for (Object collectionValue : collection) { + //highly inneficient but safe wrt the actual targeted cl= ass + Class valueClass =3D Hibernate.getClass(collectionValue); + DocumentBuilder builder =3D searchFactoryImplementor.get= DocumentBuilders().get(valueClass); + if (builder =3D=3D null) continue; + processContainedInValue(collectionValue, queue, valueCla= ss, builder, searchFactoryImplementor); + } + } + else { + Class valueClass =3D Hibernate.getClass(value); + DocumentBuilder builder =3D searchFactoryImplementor.getDoc= umentBuilders().get(valueClass); + if (builder =3D=3D null) continue; + processContainedInValue(value, queue, valueClass, builder, = searchFactoryImplementor); + } + } + //an embedded cannot have a useful @ContainedIn (no shared reference) + //do not walk through them + } = - public Document getDocument(T instance, Serializable id) { - Document doc =3D new Document(); - XClass instanceClass =3D reflectionManager.toXClass( Hibernate.getClass(= instance ) ); - if ( rootPropertiesMetadata.boost !=3D null ) { - doc.setBoost( rootPropertiesMetadata.boost ); - } - { - Field classField =3D - new Field( CLASS_FIELDNAME, instanceClass.getName(), Field.Store.YES,= Field.Index.UN_TOKENIZED, Field.TermVector.NO ); - doc.add( classField ); - LuceneOptions luceneOptions =3D new LuceneOptions( Field.Store.YES, - Field.Index.UN_TOKENIZED, Field.TermVector.NO, idBoost ); - idBridge.set( idKeywordName, id, doc, luceneOptions ); - } - buildDocumentFields( instance, doc, rootPropertiesMetadata ); - return doc; - } + private void processContainedInValue(Object value, List que= ue, Class valueClass, + DocumentBuilder builder, SearchFac= toryImplementor searchFactoryImplementor) { + Serializable id =3D (Serializable) builder.getMemberValue(value, bui= lder.idGetter); + builder.addWorkToQueue(valueClass, value, id, WorkType.UPDATE, queue= , searchFactoryImplementor); + } = - private void buildDocumentFields(Object instance, Document doc, Propertie= sMetadata propertiesMetadata) { - if ( instance =3D=3D null ) return; - //needed for field access: I cannot work in the proxied version - Object unproxiedInstance =3D unproxy( instance ); - for (int i =3D 0; i < propertiesMetadata.classBridges.size(); i++) { - FieldBridge fb =3D propertiesMetadata.classBridges.get( i ); - fb.set( propertiesMetadata.classNames.get( i ), unproxiedInstance, - doc, propertiesMetadata.getClassLuceneOptions( i ) ); - } - for (int i =3D 0; i < propertiesMetadata.fieldNames.size(); i++) { - XMember member =3D propertiesMetadata.fieldGetters.get( i ); - Object value =3D getMemberValue( unproxiedInstance, member ); - propertiesMetadata.fieldBridges.get( i ).set( - propertiesMetadata.fieldNames.get( i ), value, doc, - propertiesMetadata.getFieldLuceneOptions( i, getBoost( member ) ) ); - } - for (int i =3D 0; i < propertiesMetadata.embeddedGetters.size(); i++) { - XMember member =3D propertiesMetadata.embeddedGetters.get( i ); - Object value =3D getMemberValue( unproxiedInstance, member ); - //TODO handle boost at embedded level: already stored in propertiesMeda= tada.boost + public Document getDocument(T instance, Serializable id) { + Document doc =3D new Document(); + XClass instanceClass =3D reflectionManager.toXClass(Hibernate.getCla= ss(instance)); + if (rootPropertiesMetadata.boost !=3D null) { + doc.setBoost(rootPropertiesMetadata.boost); + } + { + Field classField =3D + new Field(CLASS_FIELDNAME, instanceClass.getName(), Field= .Store.YES, Field.Index.UN_TOKENIZED, Field.TermVector.NO); + doc.add(classField); + LuceneOptions luceneOptions =3D new LuceneOptions(Field.Store.YES, + Field.Index.UN_TOKENIZED, Field.TermVector.NO, idBoost); + idBridge.set(idKeywordName, id, doc, luceneOptions); + } + buildDocumentFields(instance, doc, rootPropertiesMetadata); + return doc; + } = - if ( value =3D=3D null ) continue; - PropertiesMetadata embeddedMetadata =3D propertiesMetadata.embeddedProp= ertiesMetadata.get( i ); - switch ( propertiesMetadata.embeddedContainers.get( i ) ) { - case ARRAY: - for (Object arrayValue : (Object[]) value) { - buildDocumentFields( arrayValue, doc, embeddedMetadata ); - } - break; - case COLLECTION: - for (Object collectionValue : (Collection) value) { - buildDocumentFields( collectionValue, doc, embeddedMetadata ); - } - break; - case MAP: - for (Object collectionValue : ( (Map) value ).values()) { - buildDocumentFields( collectionValue, doc, embeddedMetadata ); - } - break; - case OBJECT: - buildDocumentFields( value, doc, embeddedMetadata ); - break; - default: - throw new AssertionFailure( "Unknown embedded container: " - + propertiesMetadata.embeddedContainers.get( i ) ); - } - } - } + private void buildDocumentFields(Object instance, Document doc, Propert= iesMetadata propertiesMetadata) { + if (instance =3D=3D null) return; + //needed for field access: I cannot work in the proxied version + Object unproxiedInstance =3D unproxy(instance); + for (int i =3D 0; i < propertiesMetadata.classBridges.size(); i++) { + FieldBridge fb =3D propertiesMetadata.classBridges.get(i); + fb.set(propertiesMetadata.classNames.get(i), unproxiedInstance, + doc, propertiesMetadata.getClassLuceneOptions(i)); + } + for (int i =3D 0; i < propertiesMetadata.fieldNames.size(); i++) { + XMember member =3D propertiesMetadata.fieldGetters.get(i); + Object value =3D getMemberValue(unproxiedInstance, member); + propertiesMetadata.fieldBridges.get(i).set( + propertiesMetadata.fieldNames.get(i), value, doc, + propertiesMetadata.getFieldLuceneOptions(i, getBoost(memb= er))); + } + for (int i =3D 0; i < propertiesMetadata.embeddedGetters.size(); i++= ) { + XMember member =3D propertiesMetadata.embeddedGetters.get(i); + Object value =3D getMemberValue(unproxiedInstance, member); + //TODO handle boost at embedded level: already stored in properti= esMedatada.boost = - private Object unproxy(Object value) { - //FIXME this service should be part of Core? - if ( value instanceof HibernateProxy ) { - // .getImplementation() initializes the data by side effect - value =3D ( (HibernateProxy) value ).getHibernateLazyInitializer() - .getImplementation(); - } - return value; - } + if (value =3D=3D null) continue; + PropertiesMetadata embeddedMetadata =3D propertiesMetadata.embedd= edPropertiesMetadata.get(i); + switch (propertiesMetadata.embeddedContainers.get(i)) { + case ARRAY: + for (Object arrayValue : (Object[]) value) { + buildDocumentFields(arrayValue, doc, embeddedMetadata); + } + break; + case COLLECTION: + for (Object collectionValue : (Collection) value) { + buildDocumentFields(collectionValue, doc, embeddedMetadata); + } + break; + case MAP: + for (Object collectionValue : ((Map) value).values()) { + buildDocumentFields(collectionValue, doc, embeddedMetadata); + } + break; + case OBJECT: + buildDocumentFields(value, doc, embeddedMetadata); + break; + default: + throw new AssertionFailure("Unknown embedded container: " + + propertiesMetadata.embeddedContainers.get(i)); + } + } + } = - public Term getTerm(Serializable id) { - if ( idProvided ) { - return new Term( idKeywordName, (String) id ); - } + private Object unproxy(Object value) { + //FIXME this service should be part of Core? + if (value instanceof HibernateProxy) { + // .getImplementation() initializes the data by side effect + value =3D ((HibernateProxy) value).getHibernateLazyInitializer() + .getImplementation(); + } + return value; + } = - return new Term( idKeywordName, idBridge.objectToString( id ) ); - } + public Term getTerm(Serializable id) { + if (idProvided) { + return new Term(idKeywordName, (String) id); + } = - public DirectoryProvider[] getDirectoryProviders() { - return directoryProviders; - } + return new Term(idKeywordName, idBridge.objectToString(id)); + } = - public IndexShardingStrategy getDirectoryProviderSelectionStrategy() { - return shardingStrategy; - } + public DirectoryProvider[] getDirectoryProviders() { + return directoryProviders; + } = - public Analyzer getAnalyzer() { - return analyzer; - } + public IndexShardingStrategy getDirectoryProviderSelectionStrategy() { + return shardingStrategy; + } = - private static void setAccessible(XMember member) { - if ( !Modifier.isPublic( member.getModifiers() ) ) { - member.setAccessible( true ); - } - } + public Analyzer getAnalyzer() { + return analyzer; + } = - public TwoWayFieldBridge getIdBridge() { - return idBridge; - } + private static void setAccessible(XMember member) { + if (!Modifier.isPublic(member.getModifiers())) { + member.setAccessible(true); + } + } = - public String getIdKeywordName() { - return idKeywordName; - } + public TwoWayFieldBridge getIdBridge() { + return idBridge; + } = - public static Class getDocumentClass(Document document) { - String className =3D document.get( DocumentBuilder.CLASS_FIELDNAME ); - try { - return ReflectHelper.classForName( className ); - } - catch (ClassNotFoundException e) { - throw new SearchException( "Unable to load indexed class: " + className= , e ); - } - } + public String getIdKeywordName() { + return idKeywordName; + } = - public static Serializable getDocumentId(SearchFactoryImplementor searchF= actoryImplementor, Class clazz, Document document) { - DocumentBuilder builder =3D searchFactoryImplementor.getDocumentBuilders= ().get( clazz ); - if ( builder =3D=3D null ) throw new SearchException( "No Lucene configu= ration set up for: " + clazz.getName() ); - return (Serializable) builder.getIdBridge().get( builder.getIdKeywordNam= e(), document ); - } + public static Class getDocumentClass(Document document) { + String className =3D document.get(DocumentBuilder.CLASS_FIELDNAME); + try { + return ReflectHelper.classForName(className); + } + catch (ClassNotFoundException e) { + throw new SearchException("Unable to load indexed class: " + clas= sName, e); + } + } = - public static Object[] getDocumentFields(SearchFactoryImplementor searchF= actoryImplementor, Class clazz, Document document, String[] fields) { - DocumentBuilder builder =3D searchFactoryImplementor.getDocumentBuilders= ().get( clazz ); - if ( builder =3D=3D null ) throw new SearchException( "No Lucene configu= ration set up for: " + clazz.getName() ); - final int fieldNbr =3D fields.length; - Object[] result =3D new Object[fieldNbr]; + public static Serializable getDocumentId(SearchFactoryImplementor searc= hFactoryImplementor, Class clazz, Document document) { + DocumentBuilder builder =3D searchFactoryImplementor.getDocumentBuil= ders().get(clazz); + if (builder =3D=3D null) throw new SearchException("No Lucene config= uration set up for: " + clazz.getName()); + return (Serializable) builder.getIdBridge().get(builder.getIdKeyword= Name(), document); + } = - if ( builder.idKeywordName !=3D null ) { - populateResult( builder.idKeywordName, builder.idBridge, Field.Store.YE= S, fields, result, document ); - } + public static Object[] getDocumentFields(SearchFactoryImplementor searc= hFactoryImplementor, Class clazz, Document document, String[] fields) { + DocumentBuilder builder =3D searchFactoryImplementor.getDocumentBuil= ders().get(clazz); + if (builder =3D=3D null) throw new SearchException("No Lucene config= uration set up for: " + clazz.getName()); + final int fieldNbr =3D fields.length; + Object[] result =3D new Object[fieldNbr]; = - final PropertiesMetadata metadata =3D builder.rootPropertiesMetadata; - processFieldsForProjection( metadata, fields, result, document ); - return result; - } + if (builder.idKeywordName !=3D null) { + populateResult(builder.idKeywordName, builder.idBridge, Field.Sto= re.YES, fields, result, document); + } = - private static void processFieldsForProjection(PropertiesMetadata metadat= a, String[] fields, Object[] result, Document document) { - final int nbrFoEntityFields =3D metadata.fieldNames.size(); - for (int index =3D 0; index < nbrFoEntityFields; index++) { - populateResult( metadata.fieldNames.get( index ), - metadata.fieldBridges.get( index ), - metadata.fieldStore.get( index ), - fields, - result, - document - ); - } - final int nbrOfEmbeddedObjects =3D metadata.embeddedPropertiesMetadata.s= ize(); - for (int index =3D 0; index < nbrOfEmbeddedObjects; index++) { - //there is nothing we can do for collections - if ( metadata.embeddedContainers.get( index ) =3D=3D PropertiesMetadata= .Container.OBJECT ) { - processFieldsForProjection( metadata.embeddedPropertiesMetadata.get( i= ndex ), fields, result, document ); - } - } - } + final PropertiesMetadata metadata =3D builder.rootPropertiesMetadata; + processFieldsForProjection(metadata, fields, result, document); + return result; + } = - private static void populateResult(String fieldName, FieldBridge fieldBri= dge, Field.Store store, - String[] fields, Object[] result, Document document) { - int matchingPosition =3D getFieldPosition( fields, fieldName ); - if ( matchingPosition !=3D -1 ) { - //TODO make use of an isTwoWay() method - if ( store !=3D Field.Store.NO && TwoWayFieldBridge.class.isAssignableF= rom( fieldBridge.getClass() ) ) { - result[matchingPosition] =3D ( (TwoWayFieldBridge) fieldBridge ).get( = fieldName, document ); - if ( log.isTraceEnabled() ) { - log.trace( "Field {} projected as {}", fieldName, result[matchingPosi= tion] ); - } - } - else { - if ( store =3D=3D Field.Store.NO ) { - throw new SearchException( "Projecting an unstored field: " + fieldNa= me ); - } - else { - throw new SearchException( "FieldBridge is not a TwoWayFieldBridge: "= + fieldBridge.getClass() ); - } - } - } - } + private static void processFieldsForProjection(PropertiesMetadata metad= ata, String[] fields, Object[] result, Document document) { + final int nbrFoEntityFields =3D metadata.fieldNames.size(); + for (int index =3D 0; index < nbrFoEntityFields; index++) { + populateResult(metadata.fieldNames.get(index), + metadata.fieldBridges.get(index), + metadata.fieldStore.get(index), + fields, + result, + document + ); + } + final int nbrOfEmbeddedObjects =3D metadata.embeddedPropertiesMetada= ta.size(); + for (int index =3D 0; index < nbrOfEmbeddedObjects; index++) { + //there is nothing we can do for collections + if (metadata.embeddedContainers.get(index) =3D=3D PropertiesMetad= ata.Container.OBJECT) { + processFieldsForProjection(metadata.embeddedPropertiesMetadata= .get(index), fields, result, document); + } + } + } = - private static int getFieldPosition(String[] fields, String fieldName) { - int fieldNbr =3D fields.length; - for (int index =3D 0; index < fieldNbr; index++) { - if ( fieldName.equals( fields[index] ) ) return index; - } - return -1; - } + private static void populateResult(String fieldName, FieldBridge fieldB= ridge, Field.Store store, + String[] fields, Object[] result, Do= cument document) { + int matchingPosition =3D getFieldPosition(fields, fieldName); + if (matchingPosition !=3D -1) { + //TODO make use of an isTwoWay() method + if (store !=3D Field.Store.NO && TwoWayFieldBridge.class.isAssign= ableFrom(fieldBridge.getClass())) { + result[matchingPosition] =3D ((TwoWayFieldBridge) fieldBridge)= .get(fieldName, document); + if (log.isTraceEnabled()) { + log.trace("Field {} projected as {}", fieldName, result[mat= chingPosition]); + } + } + else { + if (store =3D=3D Field.Store.NO) { + throw new SearchException("Projecting an unstored field: " = + fieldName); + } + else { + throw new SearchException("FieldBridge is not a TwoWayField= Bridge: " + fieldBridge.getClass()); + } + } + } + } = - public void postInitialize(Set indexedClasses) { - //this method does not requires synchronization - Class plainClass =3D reflectionManager.toClass( beanClass ); - Set tempMappedSubclasses =3D new HashSet(); - //together with the caller this creates a o(2), but I think it's still f= aster than create the up hierarchy for each class - for (Class currentClass : indexedClasses) { - if ( plainClass.isAssignableFrom( currentClass ) ) tempMappedSubclasses= .add( currentClass ); - } - this.mappedSubclasses =3D Collections.unmodifiableSet( tempMappedSubclas= ses ); - Class superClass =3D plainClass.getSuperclass(); - this.isRoot =3D true; - while ( superClass !=3D null ) { - if ( indexedClasses.contains( superClass ) ) { - this.isRoot =3D false; - break; - } - superClass =3D superClass.getSuperclass(); - } - } + private static int getFieldPosition(String[] fields, String fieldName) { + int fieldNbr =3D fields.length; + for (int index =3D 0; index < fieldNbr; index++) { + if (fieldName.equals(fields[index])) return index; + } + return -1; + } = + public void postInitialize(Set indexedClasses) { + //this method does not requires synchronization + Class plainClass =3D reflectionManager.toClass(beanClass); + Set tempMappedSubclasses =3D new HashSet(); + //together with the caller this creates a o(2), but I think it's sti= ll faster than create the up hierarchy for each class + for (Class currentClass : indexedClasses) { + if (plainClass.isAssignableFrom(currentClass)) tempMappedSubclass= es.add(currentClass); + } + this.mappedSubclasses =3D Collections.unmodifiableSet(tempMappedSubc= lasses); + Class superClass =3D plainClass.getSuperclass(); + this.isRoot =3D true; + while (superClass !=3D null) { + if (indexedClasses.contains(superClass)) { + this.isRoot =3D false; + break; + } + superClass =3D superClass.getSuperclass(); + } + } = - public Set getMappedSubclasses() { - return mappedSubclasses; - } = - /** - * Make sure to return false if there is a risk of composite id - * if composite id, use of (a, b) in ((1,2), (3,4)) fails on most database - */ - public boolean isSafeFromTupleId() { - return safeFromTupleId; - } + public Set getMappedSubclasses() { + return mappedSubclasses; + } = - /** - * Wrapper class containing all the meta data extracted out of the entiti= es. - */ - private static class PropertiesMetadata { - public Float boost; - public Analyzer analyzer; - public final List fieldNames =3D new ArrayList(); - public final List fieldGetters =3D new ArrayList(); - public final List fieldBridges =3D new ArrayList(); - public final List fieldStore =3D new ArrayList= (); - public final List fieldIndex =3D new ArrayList= (); - public final List fieldTermVectors =3D new ArrayList(); - public final List embeddedGetters =3D new ArrayList(); - public final List embeddedPropertiesMetadata =3D new= ArrayList(); - public final List embeddedContainers =3D new ArrayList(); - public final List containedInGetters =3D new ArrayList= (); - public final List classNames =3D new ArrayList(); - public final List classStores =3D new ArrayList(); - public final List classIndexes =3D new ArrayList(); - public final List classBridges =3D new ArrayList(); - public final List classTermVectors =3D new ArrayList(); - public final List classBoosts =3D new ArrayList(); + /** + * Make sure to return false if there is a risk of composite id + * if composite id, use of (a, b) in ((1,2), (3,4)) fails on most datab= ase + */ + public boolean isSafeFromTupleId() { + return safeFromTupleId; + } = - public enum Container { - OBJECT, - COLLECTION, - MAP, - ARRAY - } + /** + * Wrapper class containing all the meta data extracted out of the enti= ties. + */ + private static class PropertiesMetadata { + public Float boost; + public Analyzer analyzer; + public final List fieldNames =3D new ArrayList(); + public final List fieldGetters =3D new ArrayList(); + public final List fieldBridges =3D new ArrayList(); + public final List fieldStore =3D new ArrayList(); + public final List fieldIndex =3D new ArrayList(); + public final List fieldTermVectors =3D new ArrayLi= st(); + public final List embeddedGetters =3D new ArrayList(); + public final List embeddedPropertiesMetadata =3D= new ArrayList(); + public final List embeddedContainers =3D new ArrayList(); + public final List containedInGetters =3D new ArrayList(); + public final List classNames =3D new ArrayList(); + public final List classStores =3D new ArrayList(); + public final List classIndexes =3D new ArrayList(); + public final List classBridges =3D new ArrayList(); + public final List classTermVectors =3D new ArrayLi= st(); + public final List classBoosts =3D new ArrayList(); = - private LuceneOptions getClassLuceneOptions(int i) { - LuceneOptions options =3D new LuceneOptions( classStores.get( i ), - classIndexes.get( i ), classTermVectors.get( i ), classBoosts.get( i = ) ); - return options; - } + public enum Container { + OBJECT, + COLLECTION, + MAP, + ARRAY + } = - private LuceneOptions getFieldLuceneOptions(int i, Float boost) { - LuceneOptions options =3D new LuceneOptions( fieldStore.get( i ), - fieldIndex.get( i ), fieldTermVectors.get( i ), boost ); - return options; - } - } + private LuceneOptions getClassLuceneOptions(int i) { + LuceneOptions options =3D new LuceneOptions(classStores.get(i), + classIndexes.get(i), classTermVectors.get(i), classBoosts= .get(i)); + return options; + } + + private LuceneOptions getFieldLuceneOptions(int i, Float boost) { + LuceneOptions options =3D new LuceneOptions(fieldStore.get(i), + fieldIndex.get(i), fieldTermVectors.get(i), boost); + return options; + } + } } --===============1839822446926121209==--