package org.infinispan.server.hotrod.iteration; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Optional; import java.util.Set; import org.infinispan.Cache; import org.infinispan.commons.CacheException; import org.infinispan.commons.marshall.AbstractExternalizer; import org.infinispan.commons.marshall.Marshaller; import org.infinispan.commons.util.Util; import org.infinispan.factories.annotations.Inject; import org.infinispan.filter.AbstractKeyValueFilterConverter; import org.infinispan.filter.KeyValueFilterConverter; import org.infinispan.metadata.Metadata; /** * @author gustavonalle * @author wburns * @since 8.0 */ public class IterationFilter<K, V, C> extends AbstractKeyValueFilterConverter<K, V, C> { final boolean compat; final Optional<KeyValueFilterConverter<K, V, C>> providedFilter; final Optional<Marshaller> marshaller; final boolean binary; protected Marshaller filterMarshaller; public IterationFilter(boolean compat, Optional<KeyValueFilterConverter<K, V, C>> providedFilter, Optional<Marshaller> marshaller, boolean binary) { this.compat = compat; this.providedFilter = providedFilter; this.marshaller = marshaller; this.binary = binary; } @Override public C filterAndConvert(K key, V value, Metadata metadata) { if (providedFilter.isPresent()) { KeyValueFilterConverter<K, V, C> f = providedFilter.get(); if (!compat && !binary) { try { K unmarshalledKey = (K) filterMarshaller.objectFromByteBuffer((byte[]) key); V unmarshalledValue = (V) filterMarshaller.objectFromByteBuffer((byte[]) value); C result = f.filterAndConvert(unmarshalledKey, unmarshalledValue, metadata); if (result != null) { return (C) filterMarshaller.objectToByteBuffer(result); } else { return null; } } catch (IOException | ClassNotFoundException | InterruptedException e) { throw new CacheException(e); } } else { return (C) f.filterAndConvert(key, value, metadata); } } else { return (C) value; } } @Inject public void injectDependencies(Cache cache) { filterMarshaller = compat ? cache.getCacheConfiguration().compatibility().marshaller() : marshaller.orElse(MarshallerBuilder.genericFromInstance(providedFilter)); providedFilter.ifPresent(kvfc -> cache.getAdvancedCache().getComponentRegistry().wireDependencies(kvfc)); } public static class IterationFilterExternalizer extends AbstractExternalizer<IterationFilter> { @Override public Set<Class<? extends IterationFilter>> getTypeClasses() { return Util.asSet(IterationFilter.class); } @Override public void writeObject(ObjectOutput output, IterationFilter object) throws IOException { output.writeBoolean(object.compat); output.writeBoolean(object.binary); if (object.providedFilter.isPresent()) { output.writeBoolean(true); output.writeObject(object.providedFilter.get()); } else { output.writeBoolean(false); } Class<?> marshallerClass = MarshallerBuilder.toClass(object); if (marshallerClass != null) { output.writeBoolean(true); output.writeObject(marshallerClass); } else { output.writeBoolean(false); } } @Override public IterationFilter readObject(ObjectInput input) throws IOException, ClassNotFoundException { boolean compat = input.readBoolean(); boolean binary = input.readBoolean(); Optional<KeyValueFilterConverter> filter; if (input.readBoolean()) { filter = Optional.of((KeyValueFilterConverter) input.readObject()); } else { filter = Optional.empty(); } Optional<Class<Marshaller>> marshallerClass = input.readBoolean() ? Optional.of((Class) input.readObject()) : Optional.empty(); return new IterationFilter(compat, filter, Optional.ofNullable(MarshallerBuilder.fromClass(marshallerClass, filter)), binary); } } }