package org.infinispan.query.remote.impl; import org.apache.lucene.analysis.Analyzer; import org.hibernate.search.bridge.FieldBridge; 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.util.impl.ToStringNullMarker; import org.hibernate.search.bridge.util.impl.TwoWayString2FieldBridgeAdaptor; import org.hibernate.search.engine.nulls.codec.impl.LuceneStringNullMarkerCodec; import org.hibernate.search.query.dsl.EntityContext; import org.hibernate.search.spi.SearchIntegrator; import org.infinispan.commons.logging.LogFactory; import org.infinispan.objectfilter.impl.syntax.AggregationExpr; import org.infinispan.objectfilter.impl.syntax.AndExpr; import org.infinispan.objectfilter.impl.syntax.BooleanExpr; import org.infinispan.objectfilter.impl.syntax.ComparisonExpr; import org.infinispan.objectfilter.impl.syntax.ConstantBooleanExpr; import org.infinispan.objectfilter.impl.syntax.ConstantValueExpr; import org.infinispan.objectfilter.impl.syntax.ExprVisitor; import org.infinispan.objectfilter.impl.syntax.FullTextBoostExpr; import org.infinispan.objectfilter.impl.syntax.FullTextOccurExpr; import org.infinispan.objectfilter.impl.syntax.FullTextRangeExpr; import org.infinispan.objectfilter.impl.syntax.FullTextRegexpExpr; import org.infinispan.objectfilter.impl.syntax.FullTextTermExpr; import org.infinispan.objectfilter.impl.syntax.IsNullExpr; import org.infinispan.objectfilter.impl.syntax.LikeExpr; import org.infinispan.objectfilter.impl.syntax.NotExpr; import org.infinispan.objectfilter.impl.syntax.OrExpr; import org.infinispan.objectfilter.impl.syntax.PropertyValueExpr; import org.infinispan.objectfilter.impl.syntax.ValueExpr; import org.infinispan.objectfilter.impl.syntax.parser.IckleParsingResult; import org.infinispan.protostream.descriptors.Descriptor; import org.infinispan.protostream.descriptors.FieldDescriptor; import org.infinispan.query.dsl.embedded.impl.LuceneQueryMaker; import org.infinispan.query.remote.impl.indexing.FieldMapping; import org.infinispan.query.remote.impl.indexing.IndexingMetadata; import org.infinispan.query.remote.impl.logging.Log; /** * @author anistor@redhat.com * @since 9.0 */ final class ProtobufFieldBridgeAndAnalyzerProvider implements LuceneQueryMaker.FieldBridgeAndAnalyzerProvider<Descriptor> { private static final Log log = LogFactory.getLog(ProtobufFieldBridgeAndAnalyzerProvider.class, Log.class); private static final LuceneStringNullMarkerCodec LUCENE_STRING_NULL_MARKER_CODEC = new LuceneStringNullMarkerCodec(new ToStringNullMarker(IndexingMetadata.DEFAULT_NULL_TOKEN)); private static final FieldBridge DOUBLE_FIELD_BRIDGE = new NullEncodingTwoWayFieldBridge(NumericFieldBridge.DOUBLE_FIELD_BRIDGE, LUCENE_STRING_NULL_MARKER_CODEC); private static final FieldBridge FLOAT_FIELD_BRIDGE = new NullEncodingTwoWayFieldBridge(NumericFieldBridge.FLOAT_FIELD_BRIDGE, LUCENE_STRING_NULL_MARKER_CODEC); private static final FieldBridge LONG_FIELD_BRIDGE = new NullEncodingTwoWayFieldBridge(NumericFieldBridge.LONG_FIELD_BRIDGE, LUCENE_STRING_NULL_MARKER_CODEC); private static final FieldBridge INT_FIELD_BRIDGE = new NullEncodingTwoWayFieldBridge(NumericFieldBridge.INT_FIELD_BRIDGE, LUCENE_STRING_NULL_MARKER_CODEC); private static final FieldBridge STRING_FIELD_BRIDGE = new NullEncodingTwoWayFieldBridge(new TwoWayString2FieldBridgeAdaptor(StringBridge.INSTANCE), LUCENE_STRING_NULL_MARKER_CODEC); private static final FieldBridge BOOL_FIELD_BRIDGE = new NullEncodingTwoWayFieldBridge(new TwoWayString2FieldBridgeAdaptor(new BooleanBridge()), LUCENE_STRING_NULL_MARKER_CODEC); ProtobufFieldBridgeAndAnalyzerProvider() { } @Override public FieldBridge getFieldBridge(Descriptor typeMetadata, String[] propertyPath) { FieldDescriptor fd = getFieldDescriptor(typeMetadata, propertyPath); IndexingMetadata indexingMetadata = fd.getContainingMessage().getProcessedAnnotation(IndexingMetadata.INDEXED_ANNOTATION); FieldMapping fieldMapping = indexingMetadata != null ? indexingMetadata.getFieldMapping(fd.getName()) : null; if (fieldMapping != null) { return fieldMapping.fieldBridge(); } switch (fd.getType()) { case DOUBLE: return DOUBLE_FIELD_BRIDGE; case FLOAT: return FLOAT_FIELD_BRIDGE; case INT64: case UINT64: case FIXED64: case SFIXED64: case SINT64: return LONG_FIELD_BRIDGE; case INT32: case FIXED32: case UINT32: case SFIXED32: case SINT32: case ENUM: return INT_FIELD_BRIDGE; case BOOL: return BOOL_FIELD_BRIDGE; case STRING: case BYTES: case GROUP: case MESSAGE: return STRING_FIELD_BRIDGE; } return null; } private FieldDescriptor getFieldDescriptor(Descriptor typeMetadata, String[] propertyPath) { Descriptor messageDescriptor = typeMetadata; FieldDescriptor fd = null; for (int i = 0; i < propertyPath.length; i++) { String name = propertyPath[i]; fd = messageDescriptor.findFieldByName(name); if (fd == null) { throw log.unknownField(name, messageDescriptor.getFullName()); } IndexingMetadata indexingMetadata = messageDescriptor.getProcessedAnnotation(IndexingMetadata.INDEXED_ANNOTATION); if (indexingMetadata != null && !indexingMetadata.isFieldIndexed(name)) { throw log.fieldIsNotIndexed(name, messageDescriptor.getFullName()); } if (i < propertyPath.length - 1) { messageDescriptor = fd.getMessageType(); } } return fd; } @Override public Analyzer getAnalyzer(SearchIntegrator searchIntegrator, Descriptor typeMetadata, String[] propertyPath) { String analyzerName = getAnalyzerName(typeMetadata, propertyPath, true); return analyzerName != null ? searchIntegrator.getAnalyzer(analyzerName) : null; } private String getAnalyzerName(Descriptor typeMetadata, String[] propertyPath, boolean complain) { Descriptor messageDescriptor = typeMetadata; for (int i = 0; i < propertyPath.length; i++) { String name = propertyPath[i]; FieldDescriptor fd = messageDescriptor.findFieldByName(name); if (fd == null) { throw log.unknownField(name, messageDescriptor.getFullName()); } IndexingMetadata indexingMetadata = messageDescriptor.getProcessedAnnotation(IndexingMetadata.INDEXED_ANNOTATION); if (indexingMetadata == null || !indexingMetadata.isFieldIndexed(name)) { if (complain) { throw log.fieldIsNotIndexed(name, messageDescriptor.getFullName()); } else { break; } } if (i < propertyPath.length - 1) { messageDescriptor = fd.getMessageType(); } else { FieldMapping fieldMapping = indexingMetadata.getFieldMapping(name); if (fieldMapping == null) { if (complain) { throw log.fieldIsNotAnalyzed(name, messageDescriptor.getFullName()); } else { break; } } String analyzerName = fieldMapping.analyzer(); if (analyzerName == null || analyzerName.isEmpty()) { analyzerName = indexingMetadata.analyzer(); } if (analyzerName != null && !analyzerName.isEmpty()) { return analyzerName; } } } return null; } @Override public void overrideAnalyzers(IckleParsingResult<Descriptor> parsingResult, EntityContext entityContext) { // Visit an expression tree and collect analyzers of all analyzed properties class AnalyzerCollector extends ExprVisitor { private void collectAnalyzer(PropertyValueExpr propertyValueExpr) { String analyzerName = getAnalyzerName(parsingResult.getTargetEntityMetadata(), propertyValueExpr.getPropertyPath().asArrayPath(), false); if (analyzerName != null) { entityContext.overridesForField(propertyValueExpr.getPropertyPath().asStringPathWithoutAlias(), analyzerName); } } @Override public BooleanExpr visit(FullTextBoostExpr fullTextBoostExpr) { fullTextBoostExpr.getChild().acceptVisitor(this); return fullTextBoostExpr; } @Override public BooleanExpr visit(FullTextOccurExpr fullTextOccurExpr) { fullTextOccurExpr.getChild().acceptVisitor(this); return fullTextOccurExpr; } @Override public BooleanExpr visit(FullTextTermExpr fullTextTermExpr) { PropertyValueExpr propertyValueExpr = (PropertyValueExpr) fullTextTermExpr.getChild(); collectAnalyzer(propertyValueExpr); return fullTextTermExpr; } @Override public BooleanExpr visit(FullTextRegexpExpr fullTextRegexpExpr) { PropertyValueExpr propertyValueExpr = (PropertyValueExpr) fullTextRegexpExpr.getChild(); collectAnalyzer(propertyValueExpr); return fullTextRegexpExpr; } @Override public BooleanExpr visit(FullTextRangeExpr fullTextRangeExpr) { PropertyValueExpr propertyValueExpr = (PropertyValueExpr) fullTextRangeExpr.getChild(); collectAnalyzer(propertyValueExpr); return fullTextRangeExpr; } @Override public BooleanExpr visit(NotExpr notExpr) { notExpr.getChild().acceptVisitor(this); return notExpr; } @Override public BooleanExpr visit(OrExpr orExpr) { for (BooleanExpr c : orExpr.getChildren()) { c.acceptVisitor(this); } return orExpr; } @Override public BooleanExpr visit(AndExpr andExpr) { for (BooleanExpr c : andExpr.getChildren()) { c.acceptVisitor(this); } return andExpr; } @Override public BooleanExpr visit(ConstantBooleanExpr constantBooleanExpr) { return constantBooleanExpr; } @Override public BooleanExpr visit(IsNullExpr isNullExpr) { PropertyValueExpr propertyValueExpr = (PropertyValueExpr) isNullExpr.getChild(); collectAnalyzer(propertyValueExpr); return isNullExpr; } @Override public BooleanExpr visit(ComparisonExpr comparisonExpr) { PropertyValueExpr propertyValueExpr = (PropertyValueExpr) comparisonExpr.getLeftChild(); collectAnalyzer(propertyValueExpr); return comparisonExpr; } @Override public BooleanExpr visit(LikeExpr likeExpr) { PropertyValueExpr propertyValueExpr = (PropertyValueExpr) likeExpr.getChild(); collectAnalyzer(propertyValueExpr); return likeExpr; } @Override public ValueExpr visit(ConstantValueExpr constantValueExpr) { return constantValueExpr; } @Override public ValueExpr visit(PropertyValueExpr propertyValueExpr) { return propertyValueExpr; } @Override public ValueExpr visit(AggregationExpr aggregationExpr) { return aggregationExpr; } } if (parsingResult.getWhereClause() != null) { parsingResult.getWhereClause().acceptVisitor(new AnalyzerCollector()); } if (parsingResult.getHavingClause() != null) { parsingResult.getHavingClause().acceptVisitor(new AnalyzerCollector()); } } }