Skip to content

Commit

Permalink
HSEARCH-115 Added handling of a default null token specified via the …
Browse files Browse the repository at this point in the history
…configuration

Improving the encapsualtion of AbstractDocumentBuilder by making fields private.
  • Loading branch information
hferentschik committed Nov 5, 2010
1 parent 463dc55 commit 699e926
Show file tree
Hide file tree
Showing 9 changed files with 186 additions and 49 deletions.
Expand Up @@ -143,4 +143,9 @@ private Environment() {
* The Lucene match version parameter. Needed since Lucene 3.x
*/
public static final String LUCENE_MATCH_VERSION = "hibernate.search.lucene_version";

/**
* Parameter name used to configure the default null token
*/
public static final String DEFAULT_NULL_TOKEN = "hibernate.search.default_null_token";
}
Expand Up @@ -44,7 +44,15 @@
@Target({ ElementType.METHOD, ElementType.FIELD })
@Documented
public @interface Field {
public static final String NO_NULL_INDEXING = "VALUE USED AS DEFAULT FOR nullIndexToken";
/**
* Default value for {@link #indexNullAs} parameter. Indicates that {@code null} values should not be indexed.
*/
public static final String DO_NOT_INDEX_NULL = "__DO_NOT_INDEX_NULL__";

/**
* Value for {@link #indexNullAs} parameter indicating that {@code null} values should not indexed using the
*/
public static final String DEFAULT_NULL_TOKEN = "__DEFAULT_NULL_TOKEN__";

/**
* @return Returns the field name. Defaults to the JavaBean property name.
Expand Down Expand Up @@ -85,5 +93,5 @@
* @return Returns the value to be used for indexing {@code null}. Per default {@code Field.NO_NULL_INDEXING} is returned indicating that
* null values are not indexed.
*/
String nullIndexToken() default NO_NULL_INDEXING;
String indexNullAs() default DO_NOT_INDEX_NULL;
}
Expand Up @@ -67,6 +67,8 @@
import org.hibernate.search.bridge.BridgeFactory;
import org.hibernate.search.bridge.FieldBridge;
import org.hibernate.search.bridge.LuceneOptions;
import org.hibernate.search.bridge.NullEncodingTwoWayFieldBridge;
import org.hibernate.search.bridge.TwoWayFieldBridge;
import org.hibernate.search.impl.ConfigContext;
import org.hibernate.search.util.ClassLoaderHelper;
import org.hibernate.search.util.HibernateHelper;
Expand All @@ -83,19 +85,20 @@
public abstract class AbstractDocumentBuilder<T> implements DocumentBuilder {
private static final Logger log = LoggerFactory.make();

protected final PropertiesMetadata metadata = new PropertiesMetadata();
protected final XClass beanXClass;
protected final Class<?> beanClass;
protected Set<Class<?>> mappedSubclasses = new HashSet<Class<?>>();
protected ReflectionManager reflectionManager; //available only during initialization and post-initialization
protected int level = 0;
protected int maxLevel = Integer.MAX_VALUE;
protected final ScopedAnalyzer analyzer = new ScopedAnalyzer();
protected Similarity similarity; //there is only 1 similarity per class hierarchy, and only 1 per index
protected boolean isRoot;
protected EntityState entityState;
private final PropertiesMetadata metadata = new PropertiesMetadata();
private final XClass beanXClass;
private final Class<?> beanClass;
private Set<Class<?>> mappedSubclasses = new HashSet<Class<?>>();
private int level = 0;
private int maxLevel = Integer.MAX_VALUE;
private final ScopedAnalyzer analyzer = new ScopedAnalyzer();
private Similarity similarity; //there is only 1 similarity per class hierarchy, and only 1 per index
private boolean isRoot;
private EntityState entityState;
private Analyzer passThroughAnalyzer = new PassThroughAnalyzer();

protected ReflectionManager reflectionManager; //available only during initialization and post-initialization

/**
* Constructor used on contained entities not annotated with {@code @Indexed} themselves.
*
Expand Down Expand Up @@ -133,6 +136,18 @@ public boolean isRoot() {
return isRoot;
}

public Class<?> getBeanClass() {
return beanClass;
}

public XClass getBeanXClass() {
return beanXClass;
}

public PropertiesMetadata getMetadata() {
return metadata;
}

public Similarity getSimilarity() {
return similarity;
}
Expand All @@ -145,6 +160,10 @@ public EntityState getEntityState() {
return entityState;
}

public void setEntityState(EntityState entityState) {
this.entityState = entityState;
}

public Set<Class<?>> getMappedSubclasses() {
return mappedSubclasses;
}
Expand Down Expand Up @@ -388,14 +407,14 @@ private void initializeClassLevelAnnotations(XClass clazz, PropertiesMetadata pr
if ( classBridgesAnn != null ) {
ClassBridge[] classBridges = classBridgesAnn.value();
for ( ClassBridge cb : classBridges ) {
bindClassBridgeAnnotation( prefix, propertiesMetadata, cb, context );
bindClassBridgeAnnotation( prefix, propertiesMetadata, cb, clazz, context );
}
}

// Check for any ClassBridge style of annotations.
ClassBridge classBridgeAnn = clazz.getAnnotation( ClassBridge.class );
if ( classBridgeAnn != null ) {
bindClassBridgeAnnotation( prefix, propertiesMetadata, classBridgeAnn, context );
bindClassBridgeAnnotation( prefix, propertiesMetadata, classBridgeAnn, clazz, context );
}

checkForAnalyzerDiscriminator( clazz, propertiesMetadata );
Expand Down Expand Up @@ -626,13 +645,13 @@ else if ( log.isTraceEnabled() ) {
}
}

private void bindClassBridgeAnnotation(String prefix, PropertiesMetadata propertiesMetadata, ClassBridge ann, ConfigContext context) {
private void bindClassBridgeAnnotation(String prefix, PropertiesMetadata propertiesMetadata, ClassBridge ann, XClass clazz, ConfigContext context) {
String fieldName = prefix + ann.name();
propertiesMetadata.classNames.add( fieldName );
propertiesMetadata.classStores.add( ann.store() );
propertiesMetadata.classIndexes.add( getIndex( ann.index() ) );
propertiesMetadata.classTermVectors.add( getTermVector( ann.termVector() ) );
propertiesMetadata.classBridges.add( BridgeFactory.extractType( ann ) );
propertiesMetadata.classBridges.add( BridgeFactory.extractType( ann, clazz ) );
propertiesMetadata.classBoosts.add( ann.boost().value() );

Analyzer analyzer = getAnalyzer( ann.analyzer(), context );
Expand All @@ -656,23 +675,28 @@ private void bindFieldAnnotation(XProperty member, PropertiesMetadata properties
propertiesMetadata.dynamicFieldBoosts.add( getDynamicBoost( member ) );
propertiesMetadata.fieldTermVectors.add( getTermVector( fieldAnn.termVector() ) );
propertiesMetadata.precisionSteps.add( getPrecisionStep( numericFieldAnn ) );
propertiesMetadata.fieldBridges
.add( BridgeFactory.guessType( fieldAnn, numericFieldAnn, member, reflectionManager ) );

// null token
String indexNullAs = fieldAnn.indexNullAs();
if ( indexNullAs.equals( org.hibernate.search.annotations.Field.DO_NOT_INDEX_NULL ) ) {
indexNullAs = null;
} else if(indexNullAs.equals( org.hibernate.search.annotations.Field.DEFAULT_NULL_TOKEN )) {
indexNullAs = context.getDefaultNullToken();
}
propertiesMetadata.fieldNullTokens.add( indexNullAs );

FieldBridge fieldBridge = BridgeFactory.guessType( fieldAnn, numericFieldAnn, member, reflectionManager );
if ( indexNullAs != null && fieldBridge instanceof TwoWayFieldBridge ) {
fieldBridge = new NullEncodingTwoWayFieldBridge( (TwoWayFieldBridge) fieldBridge, indexNullAs );
}
propertiesMetadata.fieldBridges.add( fieldBridge );

// Field > property > entity analyzer
Analyzer analyzer = getAnalyzer( fieldAnn.analyzer(), context );
if ( analyzer == null ) {
analyzer = getAnalyzer( member, context );
}
addToScopedAnalyzer( fieldName, analyzer, fieldAnn.index() );

// null token
String indexNullAs = fieldAnn.nullIndexToken();
if(indexNullAs.equals(org.hibernate.search.annotations.Field.NO_NULL_INDEXING)) {
propertiesMetadata.fieldNullTokens.add( null );
} else {
propertiesMetadata.fieldNullTokens.add( indexNullAs );
}
}

protected Integer getPrecisionStep(NumericField numericFieldAnn) {
Expand Down Expand Up @@ -760,7 +784,7 @@ private <T> void processSingleContainedInInstance(List<LuceneWork> queue, Search
DocumentBuilderContainedEntity<T> builderContainedEntity =
searchFactoryImplementor.getDocumentBuilderContainedEntity( valueClass );
if ( builderContainedEntity != null ) {
processContainedInInstances( value, queue, builderContainedEntity.metadata, searchFactoryImplementor );
processContainedInInstances( value, queue, builderContainedEntity.getMetadata(), searchFactoryImplementor );
}
}
else {
Expand Down
Expand Up @@ -68,7 +68,7 @@ public void addWorkToQueue(Class<T> entityClass, T entity, Serializable id, Work
* When the internal object is changed, we apply the {Add|Update}Work on containedIns
*/
if ( workType.searchForContainers() ) {
processContainedInInstances( entity, queue, metadata, searchFactoryImplementor );
processContainedInInstances( entity, queue, getMetadata(), searchFactoryImplementor );
}
}
}
Expand Up @@ -117,7 +117,7 @@ public static Object[] getDocumentFields(SearchFactoryImplementor searchFactoryI
}
}

final AbstractDocumentBuilder.PropertiesMetadata metadata = builderIndexedEntity.metadata;
final AbstractDocumentBuilder.PropertiesMetadata metadata = builderIndexedEntity.getMetadata();
processFieldsForProjection( metadata, fields, result, document, contextualBridge );
return result;
}
Expand Down
Expand Up @@ -149,7 +149,7 @@ public DocumentBuilderIndexedEntity(

super( clazz, context, providerWrapper.getSimilarity(), reflectionManager );

this.entityState = EntityState.INDEXED;
setEntityState( EntityState.INDEXED );
this.directoryProviders = providerWrapper.getProviders();
this.shardingStrategy = providerWrapper.getSelectionStrategy();
}
Expand Down Expand Up @@ -191,7 +191,7 @@ protected void checkDocumentId(XProperty member, PropertiesMetadata propertiesMe
String attributeName = getIdAttributeName( member, idAnnotation );
if ( isRoot ) {
if ( explicitDocumentId ) {
throw new SearchException( "More than one @DocumentId specified on entity " + beanClass.getName() );
throw new SearchException( "More than one @DocumentId specified on entity " + getBeanClass().getName() );
}
if ( idAnnotation instanceof DocumentId ) {
explicitDocumentId = true;
Expand Down Expand Up @@ -367,21 +367,21 @@ else if ( workType == WorkType.INDEX ) {
}

if ( workType.searchForContainers() ) {
processContainedInInstances( entity, queue, metadata, searchFactoryImplementor );
processContainedInInstances( entity, queue, getMetadata(), searchFactoryImplementor );
}
}

private String objectToString(TwoWayFieldBridge bridge, String fieldName, Object value) {
ContextualException2WayBridge contextualBridge = new ContextualException2WayBridge()
.setClass( beanClass )
.setClass( getBeanClass() )
.setFieldBridge( bridge )
.setFieldName( fieldName );
return contextualBridge.objectToString( value );
}

private String objectToString(StringBridge bridge, String fieldName, Object value) {
ContextualException2WayBridge contextualBridge = new ContextualException2WayBridge()
.setClass( beanClass )
.setClass( getBeanClass() )
.setStringBridge( bridge )
.setFieldName( fieldName );
return contextualBridge.objectToString( value );
Expand Down Expand Up @@ -417,7 +417,7 @@ public Document getDocument(T instance, Serializable id, Map<String, String> fie

Document doc = new Document();
final Class<?> entityType = HibernateHelper.getClass( instance );
doc.setBoost( metadata.getClassBoost( instance ) );
doc.setBoost( getMetadata().getClassBoost( instance ) );

// add the class name of the entity to the document
Field classField =
Expand Down Expand Up @@ -451,7 +451,7 @@ public Document getDocument(T instance, Serializable id, Map<String, String> fie

// finally add all other document fields
Set<String> processedFieldNames = new HashSet<String>();
buildDocumentFields( instance, doc, metadata, fieldToAnalyzerMap, processedFieldNames, contextualBridge );
buildDocumentFields( instance, doc, getMetadata(), fieldToAnalyzerMap, processedFieldNames, contextualBridge );
return doc;
}

Expand Down Expand Up @@ -606,14 +606,14 @@ public String getIdentifierName() {
}

public DirectoryProvider[] getDirectoryProviders() {
if ( entityState != EntityState.INDEXED ) {
if ( getEntityState() != EntityState.INDEXED ) {
throw new AssertionFailure( "Contained in only entity: getDirectoryProvider should not have been called." );
}
return directoryProviders;
}

public IndexShardingStrategy getDirectoryProviderSelectionStrategy() {
if ( entityState != EntityState.INDEXED ) {
if ( getEntityState() != EntityState.INDEXED ) {
throw new AssertionFailure(
"Contained in only entity: getDirectoryProviderSelectionStrategy should not have been called."
);
Expand Down Expand Up @@ -666,7 +666,7 @@ public String objectToString(String fieldName, Object value) {
return objectToString( idBridge, idKeywordName, value );
}
else {
FieldBridge bridge = getBridge( metadata, fieldName );
FieldBridge bridge = getBridge( getMetadata(), fieldName );
if ( bridge != null ) {
final Class<? extends FieldBridge> bridgeClass = bridge.getClass();
if ( TwoWayFieldBridge.class.isAssignableFrom( bridgeClass ) ) {
Expand All @@ -677,11 +677,11 @@ else if ( StringBridge.class.isAssignableFrom( bridgeClass ) ) {
}
throw new SearchException(
"FieldBridge " + bridgeClass + "does not have a objectToString method: field "
+ fieldName + " in " + beanXClass
+ fieldName + " in " + getBeanXClass()
);
}
}
throw new SearchException( "Unable to find field " + fieldName + " in " + beanXClass );
throw new SearchException( "Unable to find field " + fieldName + " in " + getBeanXClass() );
}

private FieldBridge getBridge(List<String> names, List<FieldBridge> bridges, String fieldName) {
Expand All @@ -695,7 +695,7 @@ private FieldBridge getBridge(List<String> names, List<FieldBridge> bridges, Str
}

public FieldBridge getBridge(String fieldName) {
return getBridge( metadata, fieldName );
return getBridge( getMetadata(), fieldName );
}

private FieldBridge getBridge(PropertiesMetadata metadata, String fieldName) {
Expand Down Expand Up @@ -732,13 +732,13 @@ private void checkAllowFieldSelection() {
allowFieldSelectionInProjection = false;
return;
}
for ( FieldBridge bridge : metadata.fieldBridges ) {
for ( FieldBridge bridge : getMetadata().fieldBridges ) {
if ( !( bridge instanceof TwoWayStringBridge || bridge instanceof TwoWayString2FieldBridgeAdaptor ) ) {
allowFieldSelectionInProjection = false;
return;
}
}
for ( FieldBridge bridge : metadata.classBridges ) {
for ( FieldBridge bridge : getMetadata().classBridges ) {
if ( !( bridge instanceof TwoWayStringBridge || bridge instanceof TwoWayString2FieldBridgeAdaptor ) ) {
allowFieldSelectionInProjection = false;
return;
Expand Down
Expand Up @@ -60,6 +60,7 @@ public final class ConfigContext {

private static final Logger log = LoggerFactory.make();
private static final Version DEFAULT_LUCENE_MATCH_VERSION = Version.LUCENE_30;
private static final String DEFAULT_NULL_INDEX_TOKEN = "_null_";

/**
* Constant used as definition point it is a global (programmatic) definition and there is no annotated element
Expand All @@ -80,15 +81,16 @@ public final class ConfigContext {
private final Similarity defaultSimilarity;
private final boolean solrPresent;
private final boolean jpaPresent;

private final Version luceneMatchVersion;
private final String nullToken;

public ConfigContext(SearchConfiguration cfg) {
luceneMatchVersion = getLuceneMatchVersion( cfg );
defaultAnalyzer = initAnalyzer( cfg );
defaultSimilarity = initSimilarity( cfg );
solrPresent = isPresent( "org.apache.solr.analysis.TokenizerFactory" );
jpaPresent = isPresent( "javax.persistence.Id" );
nullToken = initNullToken(cfg);
}

/**
Expand Down Expand Up @@ -178,6 +180,18 @@ private Similarity initSimilarity(SearchConfiguration cfg) {
return defaultSimilarity;
}

private String initNullToken(SearchConfiguration cfg) {
String defaultNullIndexToken = cfg.getProperty( Environment.DEFAULT_NULL_TOKEN );
if(StringHelper.isEmpty( defaultNullIndexToken )) {
defaultNullIndexToken = DEFAULT_NULL_INDEX_TOKEN;
}
return defaultNullIndexToken;
}

public String getDefaultNullToken() {
return nullToken;
}

public Analyzer getDefaultAnalyzer() {
return defaultAnalyzer;
}
Expand Down

0 comments on commit 699e926

Please sign in to comment.