package org.infinispan.query.remote.impl.indexing;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.IndexableField;
import org.apache.lucene.search.Query;
import org.hibernate.search.bridge.FieldBridge;
import org.hibernate.search.bridge.LuceneOptions;
import org.hibernate.search.bridge.builtin.BooleanBridge;
import org.hibernate.search.bridge.builtin.NumericFieldBridge;
import org.hibernate.search.bridge.builtin.StringBridge;
import org.hibernate.search.bridge.builtin.impl.NullEncodingTwoWayFieldBridge;
import org.hibernate.search.bridge.spi.NullMarker;
import org.hibernate.search.bridge.util.impl.ToStringNullMarker;
import org.hibernate.search.bridge.util.impl.TwoWayString2FieldBridgeAdaptor;
import org.hibernate.search.engine.nulls.codec.impl.LuceneIntegerNullMarkerCodec;
import org.hibernate.search.engine.nulls.codec.impl.LuceneLongNullMarkerCodec;
import org.hibernate.search.engine.nulls.codec.impl.LuceneStringNullMarkerCodec;
import org.hibernate.search.engine.nulls.codec.impl.NullMarkerCodec;
import org.infinispan.protostream.descriptors.EnumValueDescriptor;
import org.infinispan.protostream.descriptors.FieldDescriptor;
/**
* A mapping from an object field to an index field and the flags that enable indexing, storage and analysis.
*
* @author anistor@redhat.com
* @since 9.0
*/
public final class FieldMapping {
private static final NullMarkerCodec NOT_ENCODING_NULL = new NullMarkerCodec() {
@Override
public NullMarker getNullMarker() {
return null;
}
@Override
public void encodeNullValue(String fieldName, Document document, LuceneOptions luceneOptions) {
}
@Override
public Query createNullMatchingQuery(String fieldName) {
throw new IllegalStateException("Cannot build IS NULL query for field '" + fieldName + "' which does not have indexNullAs configured for indexing null values.");
}
@Override
public boolean representsNullValue(IndexableField field) {
return field == null;
}
};
/**
* The name of the field in the index.
*/
private final String name;
/**
* Enable indexing.
*/
private final boolean index;
private final float boost;
/**
* Enable analysis.
*/
private final boolean analyze;
/**
* Enable storage.
*/
private final boolean store;
private final boolean sortable;
/**
* The name of the analyzer definition.
*/
private final String analyzer;
private final String indexNullAs;
private final LuceneOptions luceneOptions;
private final FieldDescriptor fieldDescriptor;
// indexNullAsObj and fieldBridge are lazily initialised
private boolean isInitialized = false;
private Object indexNullAsObj;
private FieldBridge fieldBridge;
FieldMapping(String name, boolean index, float boost, boolean analyze, boolean store, boolean sortable, String analyzer,
String indexNullAs,
LuceneOptions luceneOptions,
FieldDescriptor fieldDescriptor) {
if (name == null) {
throw new IllegalArgumentException("name argument cannot be null");
}
if (luceneOptions == null) {
throw new IllegalArgumentException("luceneOptions argument cannot be null");
}
if (fieldDescriptor == null) {
throw new IllegalArgumentException("fieldDescriptor argument cannot be null");
}
this.name = name;
this.index = index;
this.boost = boost;
this.analyze = analyze;
this.store = store;
this.sortable = sortable;
this.analyzer = analyzer;
this.indexNullAs = indexNullAs;
this.fieldDescriptor = fieldDescriptor;
this.luceneOptions = luceneOptions;
}
public String name() {
return name;
}
public boolean index() {
return index;
}
public float boost() {
return boost;
}
public boolean analyze() {
return analyze;
}
public boolean store() {
return store;
}
public boolean sortable() {
return sortable;
}
public String analyzer() {
return analyzer;
}
public LuceneOptions luceneOptions() {
return luceneOptions;
}
public Object indexNullAs() {
init();
return indexNullAsObj;
}
public FieldBridge fieldBridge() {
init();
return fieldBridge;
}
private void init() {
if (!isInitialized) {
if (fieldDescriptor.getType() == null) {
throw new IllegalStateException("FieldDescriptors are not fully initialised!");
}
indexNullAsObj = parseIndexNullAs();
fieldBridge = makeFieldBridge();
isInitialized = true;
}
}
private Object parseIndexNullAs() {
if (indexNullAs != null) {
switch (fieldDescriptor.getType()) {
case DOUBLE:
return Double.parseDouble(indexNullAs);
case FLOAT:
return Float.parseFloat(indexNullAs);
case INT64:
case UINT64:
case FIXED64:
case SFIXED64:
case SINT64:
return Long.parseLong(indexNullAs);
case INT32:
case FIXED32:
case UINT32:
case SFIXED32:
case SINT32:
return Integer.parseInt(indexNullAs);
case ENUM:
EnumValueDescriptor enumVal = fieldDescriptor.getEnumType().findValueByName(indexNullAs);
if (enumVal == null) {
throw new IllegalArgumentException("Enum value not found : " + indexNullAs);
}
return enumVal.getNumber();
case BOOL:
return Boolean.valueOf(indexNullAs);
}
}
return indexNullAs;
}
private FieldBridge makeFieldBridge() {
switch (fieldDescriptor.getType()) {
case DOUBLE:
return indexNullAsObj == null ?
new NullEncodingTwoWayFieldBridge(NumericFieldBridge.DOUBLE_FIELD_BRIDGE, NOT_ENCODING_NULL) :
new NullEncodingTwoWayFieldBridge(NumericFieldBridge.DOUBLE_FIELD_BRIDGE, new LuceneLongNullMarkerCodec(new ToStringNullMarker(indexNullAsObj)));
case FLOAT:
return indexNullAsObj == null ?
new NullEncodingTwoWayFieldBridge(NumericFieldBridge.FLOAT_FIELD_BRIDGE, NOT_ENCODING_NULL) :
new NullEncodingTwoWayFieldBridge(NumericFieldBridge.FLOAT_FIELD_BRIDGE, new LuceneLongNullMarkerCodec(new ToStringNullMarker(indexNullAsObj)));
case INT64:
case UINT64:
case FIXED64:
case SFIXED64:
case SINT64:
return indexNullAsObj == null ?
new NullEncodingTwoWayFieldBridge(NumericFieldBridge.LONG_FIELD_BRIDGE, NOT_ENCODING_NULL) :
new NullEncodingTwoWayFieldBridge(NumericFieldBridge.LONG_FIELD_BRIDGE, new LuceneLongNullMarkerCodec(new ToStringNullMarker(indexNullAsObj)));
case INT32:
case FIXED32:
case UINT32:
case SFIXED32:
case SINT32:
case ENUM:
return indexNullAsObj == null ?
new NullEncodingTwoWayFieldBridge(NumericFieldBridge.INT_FIELD_BRIDGE, NOT_ENCODING_NULL) :
new NullEncodingTwoWayFieldBridge(NumericFieldBridge.INT_FIELD_BRIDGE, new LuceneIntegerNullMarkerCodec(new ToStringNullMarker(indexNullAsObj)));
case BOOL:
return indexNullAsObj == null ?
new NullEncodingTwoWayFieldBridge(new TwoWayString2FieldBridgeAdaptor(new BooleanBridge()), NOT_ENCODING_NULL) :
new NullEncodingTwoWayFieldBridge(new TwoWayString2FieldBridgeAdaptor(new BooleanBridge()), new LuceneStringNullMarkerCodec(new ToStringNullMarker(indexNullAsObj)));
default:
return indexNullAsObj == null ?
new NullEncodingTwoWayFieldBridge(new TwoWayString2FieldBridgeAdaptor(StringBridge.INSTANCE), NOT_ENCODING_NULL) :
new NullEncodingTwoWayFieldBridge(new TwoWayString2FieldBridgeAdaptor(StringBridge.INSTANCE), new LuceneStringNullMarkerCodec(new ToStringNullMarker(indexNullAsObj)));
}
}
@Override
public String toString() {
return "FieldMapping{" +
"name='" + name + '\'' +
", index=" + index +
", boost=" + boost +
", analyze=" + analyze +
", store=" + store +
", sortable=" + sortable +
", analyzer='" + analyzer + '\'' +
", indexNullAs=" + indexNullAs +
", luceneOptions=" + luceneOptions +
'}';
}
}