package org.infinispan.interceptors.impl;
import java.util.Map;
import org.infinispan.commands.FlagAffectedCommand;
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.NotSerializableException;
import org.infinispan.commons.marshall.StreamingMarshaller;
import org.infinispan.context.InvocationContext;
import org.infinispan.context.impl.FlagBitSets;
import org.infinispan.factories.annotations.Inject;
import org.infinispan.factories.annotations.Start;
import org.infinispan.interceptors.DDAsyncInterceptor;
/**
* Interceptor to verify whether parameters passed into cache are marshallables
* or not.
*
* <p>This is handy when marshalling happens in a separate
* thread and marshalling failures might be swallowed.
* Currently, this only happens when we have an asynchronous store.</p>
*
* @author Galder ZamarreƱo
* @since 9.0
*/
public class IsMarshallableInterceptor extends DDAsyncInterceptor {
private StreamingMarshaller marshaller;
private boolean usingAsyncStore;
@Inject
protected void injectMarshaller(StreamingMarshaller marshaller) {
this.marshaller = marshaller;
}
@Start
protected void start() {
usingAsyncStore = cacheConfiguration.persistence().usingAsyncStore();
}
@Override
public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable {
if (isUsingAsyncStore(ctx, command)) {
checkMarshallable(command.getValue());
}
return invokeNext(ctx, command);
}
@Override
public Object visitPutMapCommand(InvocationContext ctx, PutMapCommand command) throws Throwable {
if (isUsingAsyncStore(ctx, command)) {
checkMarshallable(command.getMap());
}
return invokeNext(ctx, command);
}
@Override
public Object visitRemoveCommand(InvocationContext ctx, RemoveCommand command) throws Throwable {
if (isUsingAsyncStore(ctx, command)) {
checkMarshallable(command.getKey());
}
return invokeNext(ctx, command);
}
@Override
public Object visitReplaceCommand(InvocationContext ctx, ReplaceCommand command) throws Throwable {
if (isUsingAsyncStore(ctx, command)) {
checkMarshallable(command.getNewValue());
}
return invokeNext(ctx, command);
}
private boolean isUsingAsyncStore(InvocationContext ctx, FlagAffectedCommand command) {
return usingAsyncStore && ctx.isOriginLocal() && !command.hasAnyFlag(FlagBitSets.SKIP_CACHE_STORE);
}
private void checkMarshallable(Object o) throws NotSerializableException {
boolean marshallable = false;
try {
marshallable = marshaller.isMarshallable(o);
} catch (Exception e) {
throwNotSerializable(o, e);
}
if (!marshallable)
throwNotSerializable(o, null);
}
private void throwNotSerializable(Object o, Throwable t) {
String msg = String.format(
"Object of type %s expected to be marshallable", o.getClass());
if (t == null)
throw new NotSerializableException(msg);
else
throw new NotSerializableException(msg, t);
}
private void checkMarshallable(Map<Object, Object> objs) throws NotSerializableException {
for (Map.Entry<Object, Object> entry : objs.entrySet()) {
checkMarshallable(entry.getKey());
checkMarshallable(entry.getValue());
}
}
}