All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.infinispan.interceptors.MarshalledValueInterceptor Maven / Gradle / Ivy

There is a newer version: 9.1.7.Final
Show newest version
package org.infinispan.interceptors;

import static org.infinispan.factories.KnownComponentNames.CACHE_MARSHALLER;
import static org.infinispan.marshall.core.MarshalledValue.isTypeExcluded;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;

import org.infinispan.Cache;
import org.infinispan.CacheSet;
import org.infinispan.commands.control.LockControlCommand;
import org.infinispan.commands.read.AbstractDataCommand;
import org.infinispan.commands.read.EntrySetCommand;
import org.infinispan.commands.read.GetCacheEntryCommand;
import org.infinispan.commands.read.GetKeyValueCommand;
import org.infinispan.commands.read.GetAllCommand;
import org.infinispan.commands.read.KeySetCommand;
import org.infinispan.commands.write.PutKeyValueCommand;
import org.infinispan.commands.write.PutMapCommand;
import org.infinispan.commands.write.RemoveCommand;
import org.infinispan.commands.write.ReplaceCommand;
import org.infinispan.commons.marshall.StreamingMarshaller;
import org.infinispan.commons.util.CloseableIterator;
import org.infinispan.commons.util.CloseableIteratorMapper;
import org.infinispan.commons.util.CloseableSpliterator;
import org.infinispan.container.InternalEntryFactory;
import org.infinispan.container.entries.CacheEntry;
import org.infinispan.context.InvocationContext;
import org.infinispan.context.impl.TxInvocationContext;
import org.infinispan.factories.annotations.ComponentName;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.factories.annotations.Start;
import org.infinispan.interceptors.base.CommandInterceptor;
import org.infinispan.marshall.core.MarshalledValue;
import org.infinispan.stream.impl.interceptor.AbstractDelegatingEntryCacheSet;
import org.infinispan.stream.impl.interceptor.AbstractDelegatingKeyCacheSet;
import org.infinispan.stream.impl.spliterators.IteratorAsSpliterator;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;

/**
 * Interceptor that handles the wrapping and unwrapping of cached data using {@link
 * org.infinispan.marshall.core.MarshalledValue}s. Known "excluded" types are not wrapped/unwrapped, which at this time
 * include {@link String}, Java primitives and their Object wrappers, as well as arrays of excluded types.
 * 

* The {@link org.infinispan.marshall.core.MarshalledValue} wrapper handles lazy deserialization from byte array * representations. * * @author Manik Surtani ([email protected]) * @author [email protected] * @author Galder Zamarreño * @see org.infinispan.marshall.core.MarshalledValue * @deprecated Since 8.2, no longer public API. */ @Deprecated public class MarshalledValueInterceptor extends CommandInterceptor { private StreamingMarshaller marshaller; private boolean wrapKeys = true; private boolean wrapValues = true; private InternalEntryFactory entryFactory; private Cache cache; private static final Log log = LogFactory.getLog(MarshalledValueInterceptor.class); private static final boolean trace = log.isTraceEnabled(); @Override protected Log getLog() { return log; } @Inject protected void inject(@ComponentName(CACHE_MARSHALLER) StreamingMarshaller marshaller, InternalEntryFactory entryFactory, Cache cache) { this.marshaller = marshaller; this.entryFactory = entryFactory; this.cache = cache; } @Start protected void start() { wrapKeys = cacheConfiguration.storeAsBinary().storeKeysAsBinary(); wrapValues = cacheConfiguration.storeAsBinary().storeValuesAsBinary(); } @Override public Object visitLockControlCommand(TxInvocationContext ctx, LockControlCommand command) throws Throwable { if (wrapKeys) { if (command.multipleKeys()) { Collection rawKeys = command.getKeys(); Map keyToMarshalledKeyMapping = new HashMap(rawKeys.size()); for (Object k : rawKeys) { if (!isTypeExcluded(k.getClass())) keyToMarshalledKeyMapping.put(k, createMarshalledValue(k, ctx)); } if (!keyToMarshalledKeyMapping.isEmpty()) command.replaceKeys(keyToMarshalledKeyMapping); } else { Object key = command.getSingleKey(); if (!isTypeExcluded(key.getClass())) command.replaceKey(key, createMarshalledValue(key, ctx)); } } return invokeNextInterceptor(ctx, command); } @Override public Object visitPutMapCommand(InvocationContext ctx, PutMapCommand command) throws Throwable { Set marshalledValues = new HashSet(command.getMap().size()); Map map = wrapMap(command.getMap(), marshalledValues, ctx); command.setMap(map); Object retVal = invokeNextInterceptor(ctx, command); return processRetVal(retVal, ctx); } @Override public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable { MarshalledValue key; MarshalledValue value; if (wrapKeys) { if (!isTypeExcluded(command.getKey().getClass())) { key = createMarshalledValue(command.getKey(), ctx); command.setKey(key); } } if (wrapValues) { if (!isTypeExcluded(command.getValue().getClass())) { value = createMarshalledValue(command.getValue(), ctx); command.setValue(value); } } Object retVal = invokeNextInterceptor(ctx, command); return processRetVal(retVal, ctx); } @Override public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable { MarshalledValue value; if (wrapKeys) { if (!isTypeExcluded(command.getKey().getClass())) { value = createMarshalledValue(command.getKey(), ctx); command.setKey(value); } } Object retVal = invokeNextInterceptor(ctx, command); return processRetVal(retVal, ctx); } @Override public Object visitEvictCommand(InvocationContext ctx, org.infinispan.commands.write.EvictCommand command) throws Throwable { MarshalledValue value; if (wrapKeys) { if (!isTypeExcluded(command.getKey().getClass())) { value = createMarshalledValue(command.getKey(), ctx); command.setKey(value); } } Object retVal = invokeNextInterceptor(ctx, command); return processRetVal(retVal, ctx); } @Override public final Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable { return visitDataReadCommand(ctx, command); } @Override public final Object visitGetCacheEntryCommand(InvocationContext ctx, GetCacheEntryCommand command) throws Throwable { return visitDataReadCommand(ctx, command); } private Object visitDataReadCommand(InvocationContext ctx, AbstractDataCommand command) throws Throwable { MarshalledValue mv; if (wrapKeys) { if (!isTypeExcluded(command.getKey().getClass())) { mv = createMarshalledValue(command.getKey(), ctx); command.setKey(mv); } } Object retVal = invokeNextInterceptor(ctx, command); return processRetVal(retVal, ctx); } @Override public Object visitGetAllCommand(InvocationContext ctx, GetAllCommand command) throws Throwable { if (wrapKeys) { Set marshalledKeys = new LinkedHashSet<>(); for (Object key : command.getKeys()) { if (!isTypeExcluded(key.getClass())) { MarshalledValue mv = createMarshalledValue(key, ctx); marshalledKeys.add(mv); } else { marshalledKeys.add(key); } } command.setKeys(marshalledKeys); } Map map = (Map) invokeNextInterceptor(ctx, command); Map unmarshalled = command.createMap(); for (Map.Entry entry : map.entrySet()) { // TODO: how does this apply to CacheEntries if command.isReturnEntries()? unmarshalled.put(processRetVal(entry.getKey(), ctx), processRetVal(entry.getValue(), ctx)); } return unmarshalled; } @Override public Object visitReplaceCommand(InvocationContext ctx, ReplaceCommand command) throws Throwable { MarshalledValue key, newValue, oldValue; if (wrapKeys && !isTypeExcluded(command.getKey().getClass())) { key = createMarshalledValue(command.getKey(), ctx); command.setKey(key); } if (wrapValues && !isTypeExcluded(command.getNewValue().getClass())) { newValue = createMarshalledValue(command.getNewValue(), ctx); command.setNewValue(newValue); } if (wrapValues && command.getOldValue() != null && !isTypeExcluded(command.getOldValue().getClass())) { oldValue = createMarshalledValue(command.getOldValue(), ctx); command.setOldValue(oldValue); } Object retVal = invokeNextInterceptor(ctx, command); return processRetVal(retVal, ctx); } protected R processRetVal(R retVal, InvocationContext ctx) { if (retVal instanceof MarshalledValue) { if (ctx == null || ctx.isOriginLocal()) { if (trace) log.tracef("Return is a marshall value, so extract instance from: %s", retVal); retVal = (R) ((MarshalledValue) retVal).get(); } } return retVal; } private final CacheEntry unwrapEntry(CacheEntry e, InvocationContext ctx) { Object originalKey = e.getKey(); Object key = processRetVal(originalKey, ctx); Object originalValue = e.getValue(); Object value = processRetVal(originalValue, ctx); if (originalKey != key || originalValue != value) { return (CacheEntry) entryFactory.create(key, value, e.getMetadata()); } return e; } @Override public CacheSet> visitEntrySetCommand(InvocationContext ctx, EntrySetCommand command) throws Throwable { CacheSet> set = (CacheSet>)super.visitEntrySetCommand(ctx, command); return new AbstractDelegatingEntryCacheSet(getCacheWithFlags(cache, command), set) { @Override public CloseableIterator> iterator() { // We pass a null ctx, since we always want this value unwrapped. If iterator was invoked locally, it would // behave the same, however for a remote invocation which is usually part of a stream invocation we have // to have the actual unmarshalled value to perform the intermediate operations upon. return new CloseableIteratorMapper<>(super.iterator(), e -> unwrapEntry(e, null)); } @Override public CloseableSpliterator> spliterator() { return new IteratorAsSpliterator.Builder<>(iterator()) .setEstimateRemaining(super.spliterator().estimateSize()) .setCharacteristics(Spliterator.CONCURRENT | Spliterator.DISTINCT | Spliterator.NONNULL) .get(); } }; } @Override public CacheSet visitKeySetCommand(InvocationContext ctx, KeySetCommand command) throws Throwable { CacheSet set = (CacheSet) super.visitKeySetCommand(ctx, command); return new AbstractDelegatingKeyCacheSet(getCacheWithFlags(cache, command), set) { @Override public CloseableIterator iterator() { // We pass a null ctx, since this is always local invocation - if it was remote it would use // DistributionBulkInterceptor return new CloseableIteratorMapper<>(super.iterator(), e -> processRetVal(e, null)); } @Override public CloseableSpliterator spliterator() { return new IteratorAsSpliterator.Builder<>(iterator()) .setEstimateRemaining(super.spliterator().estimateSize()) .setCharacteristics(Spliterator.CONCURRENT | Spliterator.DISTINCT | Spliterator.NONNULL) .get(); } }; } @SuppressWarnings("unchecked") protected Map wrapMap(Map m, Set marshalledValues, InvocationContext ctx) { if (m == null) { if (trace) log.trace("Map is nul; returning an empty map."); return Collections.emptyMap(); } if (trace) log.tracef("Wrapping map contents of argument %s", m); Map copy = new HashMap(m.size()); for (Map.Entry me : m.entrySet()) { Object key = me.getKey(); Object value = me.getValue(); Object newKey = (key == null || isTypeExcluded(key.getClass())) || !wrapKeys ? key : createMarshalledValue(key, ctx); Object newValue = (value == null || isTypeExcluded(value.getClass()) || !wrapValues) ? value : createMarshalledValue(value, ctx); if (newKey instanceof MarshalledValue) marshalledValues.add((MarshalledValue) newKey); if (newValue instanceof MarshalledValue) marshalledValues.add((MarshalledValue) newValue); copy.put(newKey, newValue); } return copy; } protected MarshalledValue createMarshalledValue(Object toWrap, InvocationContext ctx) { return new MarshalledValue(toWrap, marshaller); } }