package org.infinispan.objectfilter.impl;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.infinispan.objectfilter.FilterCallback;
import org.infinispan.objectfilter.FilterSubscription;
import org.infinispan.objectfilter.SortField;
import org.infinispan.objectfilter.impl.predicateindex.PredicateIndex;
import org.infinispan.objectfilter.impl.predicateindex.be.BETree;
import org.infinispan.objectfilter.impl.predicateindex.be.BETreeMaker;
import org.infinispan.objectfilter.impl.syntax.BooleanExpr;
import org.infinispan.objectfilter.impl.syntax.BooleanFilterNormalizer;
import org.infinispan.objectfilter.impl.util.StringHelper;
/**
* A registry for filters on the same type of entity.
*
* @author anistor@redhat.com
* @since 7.0
*/
public final class FilterRegistry<TypeMetadata, AttributeMetadata, AttributeId extends Comparable<AttributeId>> {
private final PredicateIndex<AttributeMetadata, AttributeId> predicateIndex;
private final List<FilterSubscriptionImpl> filterSubscriptions = new ArrayList<>();
private final BooleanFilterNormalizer booleanFilterNormalizer = new BooleanFilterNormalizer();
private final BETreeMaker<AttributeId> treeMaker;
private final MetadataAdapter<TypeMetadata, AttributeMetadata, AttributeId> metadataAdapter;
private final boolean useIntervals;
public FilterRegistry(MetadataAdapter<TypeMetadata, AttributeMetadata, AttributeId> metadataAdapter, boolean useIntervals) {
this.metadataAdapter = metadataAdapter;
this.useIntervals = useIntervals;
treeMaker = new BETreeMaker<>(metadataAdapter, useIntervals);
predicateIndex = new PredicateIndex<>(metadataAdapter);
}
public MetadataAdapter<TypeMetadata, AttributeMetadata, AttributeId> getMetadataAdapter() {
return metadataAdapter;
}
public PredicateIndex<AttributeMetadata, AttributeId> getPredicateIndex() {
return predicateIndex;
}
public List<FilterSubscriptionImpl> getFilterSubscriptions() {
return filterSubscriptions;
}
public FilterSubscriptionImpl<TypeMetadata, AttributeMetadata, AttributeId> addFilter(String queryString, Map<String, Object> namedParameters, BooleanExpr query, String[] projection, Class<?>[] projectionTypes, SortField[] sortFields, FilterCallback callback, boolean isDeltaFilter, Object[] eventTypes) {
if (eventTypes != null) {
if (eventTypes.length == 0) {
eventTypes = null;
} else {
for (Object et : eventTypes) {
if (et == null) {
eventTypes = null;
break;
}
}
}
}
List<List<AttributeId>> translatedProjections = null;
if (projection != null && projection.length != 0) {
translatedProjections = new ArrayList<>(projection.length);
for (String projectionPath : projection) {
translatedProjections.add(metadataAdapter.mapPropertyNamePathToFieldIdPath(StringHelper.split(projectionPath)));
}
}
List<List<AttributeId>> translatedSortFields = null;
if (sortFields != null) {
// deduplicate sort fields
LinkedHashMap<String, SortField> sortFieldMap = new LinkedHashMap<>();
for (SortField sf : sortFields) {
String path = sf.getPath().asStringPath();
if (!sortFieldMap.containsKey(path)) {
sortFieldMap.put(path, sf);
}
}
sortFields = sortFieldMap.values().toArray(new SortField[sortFieldMap.size()]);
// translate sort field paths
translatedSortFields = new ArrayList<>(sortFields.length);
for (SortField sortField : sortFields) {
translatedSortFields.add(metadataAdapter.mapPropertyNamePathToFieldIdPath(sortField.getPath().asArrayPath()));
}
}
BooleanExpr normalizedQuery = booleanFilterNormalizer.normalize(query);
BETree beTree = treeMaker.make(normalizedQuery, namedParameters);
FilterSubscriptionImpl<TypeMetadata, AttributeMetadata, AttributeId> filterSubscription = new FilterSubscriptionImpl<>(queryString, namedParameters, useIntervals, metadataAdapter, beTree, callback, isDeltaFilter, projection, projectionTypes, translatedProjections, sortFields, translatedSortFields, eventTypes);
filterSubscription.registerProjection(predicateIndex);
filterSubscription.subscribe(predicateIndex);
filterSubscription.index = filterSubscriptions.size();
filterSubscriptions.add(filterSubscription);
return filterSubscription;
}
public void removeFilter(FilterSubscription filterSubscription) {
FilterSubscriptionImpl<TypeMetadata, AttributeMetadata, AttributeId> filterSubscriptionImpl = (FilterSubscriptionImpl<TypeMetadata, AttributeMetadata, AttributeId>) filterSubscription;
filterSubscriptionImpl.unregisterProjection(predicateIndex);
filterSubscriptionImpl.unsubscribe(predicateIndex);
filterSubscriptions.remove(filterSubscriptionImpl);
for (int i = filterSubscriptionImpl.index; i < filterSubscriptions.size(); i++) {
filterSubscriptions.get(i).index--;
}
filterSubscriptionImpl.index = -1;
}
}