package org.infinispan.query.remote.impl.filter; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Arrays; import java.util.Collections; import java.util.Map; import java.util.Optional; import java.util.Set; import org.infinispan.commons.marshall.AbstractExternalizer; import org.infinispan.factories.ComponentRegistry; import org.infinispan.factories.annotations.Inject; import org.infinispan.filter.AbstractKeyValueFilterConverter; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.metadata.Metadata; import org.infinispan.objectfilter.ObjectFilter; import org.infinispan.protostream.ProtobufUtil; import org.infinispan.protostream.SerializationContext; import org.infinispan.query.remote.impl.ExternalizerIds; import org.infinispan.query.remote.impl.ProtobufMetadataManagerImpl; /** * Adapter for {@link IckleProtobufFilterAndConverter} that produces binary values as a result of filter/conversion. * * @author gustavonalle * @since 8.1 */ public final class IckleBinaryProtobufFilterAndConverter<K, V> extends AbstractKeyValueFilterConverter<K, V, Object> { private SerializationContext serCtx; private final IckleProtobufFilterAndConverter delegate; @Inject @SuppressWarnings("unused") protected void injectDependencies(ComponentRegistry componentRegistry, EmbeddedCacheManager cacheManager) { componentRegistry.wireDependencies(delegate); serCtx = ProtobufMetadataManagerImpl.getSerializationContextInternal(cacheManager); } public IckleBinaryProtobufFilterAndConverter(String queryString, Map<String, Object> namedParameters) { this.delegate = new IckleProtobufFilterAndConverter(queryString, namedParameters); } private IckleBinaryProtobufFilterAndConverter(IckleProtobufFilterAndConverter delegate) { this.delegate = delegate; } @Override public Object filterAndConvert(K key, V value, Metadata metadata) { Optional<ObjectFilter.FilterResult> filterResult = Optional.ofNullable(delegate.filterAndConvert(key, value, metadata)); return filterResult.map(fr -> { Object instance = fr.getInstance(); if (instance != null) return instance; return Arrays.stream(fr.getProjection()).map(this::toByteArray).toArray(); }).orElse(null); } private Object toByteArray(Object ref) { try { return ProtobufUtil.toWrappedByteArray(serCtx, ref); } catch (IOException e) { throw new RuntimeException(e); } } public static final class Externalizer extends AbstractExternalizer<IckleBinaryProtobufFilterAndConverter> { @Override public void writeObject(ObjectOutput output, IckleBinaryProtobufFilterAndConverter object) throws IOException { output.writeObject(object.delegate); } @Override public IckleBinaryProtobufFilterAndConverter readObject(ObjectInput input) throws IOException, ClassNotFoundException { IckleProtobufFilterAndConverter delegate = (IckleProtobufFilterAndConverter) input.readObject(); return new IckleBinaryProtobufFilterAndConverter(delegate); } @Override public Integer getId() { return ExternalizerIds.ICKLE_BINARY_PROTOBUF_FILTER_AND_CONVERTER; } @Override public Set<Class<? extends IckleBinaryProtobufFilterAndConverter>> getTypeClasses() { return Collections.singleton(IckleBinaryProtobufFilterAndConverter.class); } } }