package org.infinispan.query.remote.impl.filter;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.infinispan.Cache;
import org.infinispan.commons.CacheException;
import org.infinispan.commons.io.UnsignedNumeric;
import org.infinispan.commons.marshall.AbstractExternalizer;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.metadata.Metadata;
import org.infinispan.notifications.cachelistener.filter.EventType;
import org.infinispan.objectfilter.Matcher;
import org.infinispan.objectfilter.ObjectFilter;
import org.infinispan.protostream.ProtobufUtil;
import org.infinispan.protostream.SerializationContext;
import org.infinispan.query.continuous.impl.IckleContinuousQueryCacheEventFilterConverter;
import org.infinispan.query.remote.client.ContinuousQueryResult;
import org.infinispan.query.remote.impl.CompatibilityReflectionMatcher;
import org.infinispan.query.remote.impl.ExternalizerIds;
import org.infinispan.query.remote.impl.ProtobufMetadataManagerImpl;
import org.infinispan.query.remote.impl.indexing.ProtobufValueWrapper;
/**
* @author anistor@redhat.com
* @since 8.0
*/
public final class IckleContinuousQueryProtobufCacheEventFilterConverter extends IckleContinuousQueryCacheEventFilterConverter<Object, Object, Object> {
private SerializationContext serCtx;
private boolean usesValueWrapper;
private boolean isCompatMode;
public IckleContinuousQueryProtobufCacheEventFilterConverter(String queryString, Map<String, Object> namedParameters, Class<? extends Matcher> matcherImplClass) {
super(queryString, namedParameters, matcherImplClass);
}
@Override
protected void injectDependencies(Cache cache) {
serCtx = ProtobufMetadataManagerImpl.getSerializationContextInternal(cache.getCacheManager());
Configuration cfg = cache.getCacheConfiguration();
isCompatMode = cfg.compatibility().enabled();
usesValueWrapper = cfg.indexing().index().isEnabled() && !isCompatMode;
if (isCompatMode) {
matcherImplClass = CompatibilityReflectionMatcher.class;
}
super.injectDependencies(cache);
}
@Override
public Object filterAndConvert(Object key, Object oldValue, Metadata oldMetadata, Object newValue, Metadata newMetadata, EventType eventType) {
if (usesValueWrapper) {
oldValue = oldValue != null ? ((ProtobufValueWrapper) oldValue).getBinary() : null;
newValue = newValue != null ? ((ProtobufValueWrapper) newValue).getBinary() : null;
}
if (eventType.isExpired()) {
oldValue = newValue; // expired events have the expired value as newValue
newValue = null;
}
ObjectFilter objectFilter = getObjectFilter();
ObjectFilter.FilterResult f1 = oldValue == null ? null : objectFilter.filter(oldValue);
ObjectFilter.FilterResult f2 = newValue == null ? null : objectFilter.filter(newValue);
if (f1 == null && f2 != null) {
// result joining
return makeFilterResult(ContinuousQueryResult.ResultType.JOINING, key, f2.getProjection() == null ? newValue : null, f2.getProjection());
} else if (f1 != null && f2 == null) {
// result leaving
return makeFilterResult(ContinuousQueryResult.ResultType.LEAVING, key, null, null);
} else {
return null;
}
}
protected Object makeFilterResult(ContinuousQueryResult.ResultType resultType, Object key, Object value, Object[] projection) {
try {
if (isCompatMode) {
key = ProtobufUtil.toWrappedByteArray(serCtx, key);
if (value != null) {
value = ProtobufUtil.toWrappedByteArray(serCtx, value);
}
}
Object result = new ContinuousQueryResult(resultType, (byte[]) key, (byte[]) value, projection);
if (!isCompatMode) {
result = ProtobufUtil.toWrappedByteArray(serCtx, result);
}
return result;
} catch (IOException e) {
throw new CacheException(e);
}
}
@Override
public String toString() {
return "IckleContinuousQueryProtobufCacheEventFilterConverter{queryString='" + queryString + "'}";
}
public static final class Externalizer extends AbstractExternalizer<IckleContinuousQueryProtobufCacheEventFilterConverter> {
@Override
public void writeObject(ObjectOutput output, IckleContinuousQueryProtobufCacheEventFilterConverter filterAndConverter) throws IOException {
output.writeUTF(filterAndConverter.queryString);
Map<String, Object> namedParameters = filterAndConverter.namedParameters;
if (namedParameters != null) {
UnsignedNumeric.writeUnsignedInt(output, namedParameters.size());
for (Map.Entry<String, Object> e : namedParameters.entrySet()) {
output.writeUTF(e.getKey());
output.writeObject(e.getValue());
}
} else {
UnsignedNumeric.writeUnsignedInt(output, 0);
}
output.writeObject(filterAndConverter.matcherImplClass);
}
@Override
public IckleContinuousQueryProtobufCacheEventFilterConverter readObject(ObjectInput input) throws IOException, ClassNotFoundException {
String queryString = input.readUTF();
int paramsSize = UnsignedNumeric.readUnsignedInt(input);
Map<String, Object> namedParameters = null;
if (paramsSize != 0) {
namedParameters = new HashMap<>(paramsSize);
for (int i = 0; i < paramsSize; i++) {
String paramName = input.readUTF();
Object paramValue = input.readObject();
namedParameters.put(paramName, paramValue);
}
}
Class<? extends Matcher> matcherImplClass = (Class<? extends Matcher>) input.readObject();
return new IckleContinuousQueryProtobufCacheEventFilterConverter(queryString, namedParameters, matcherImplClass);
}
@Override
public Integer getId() {
return ExternalizerIds.ICKLE_CONTINUOUS_QUERY_CACHE_EVENT_FILTER_CONVERTER;
}
@Override
public Set<Class<? extends IckleContinuousQueryProtobufCacheEventFilterConverter>> getTypeClasses() {
return Collections.singleton(IckleContinuousQueryProtobufCacheEventFilterConverter.class);
}
}
}