package org.infinispan.commons.marshall; import static org.infinispan.commons.marshall.MarshallableFunctions.LambdaWithMetas; import static org.infinispan.commons.marshall.MarshallableFunctions.SetValueIfEqualsReturnBoolean; import static org.infinispan.commons.marshall.MarshallableFunctions.SetValueMetas; import static org.infinispan.commons.marshall.MarshallableFunctions.SetValueMetasIfAbsentReturnBoolean; import static org.infinispan.commons.marshall.MarshallableFunctions.SetValueMetasIfAbsentReturnPrevOrNull; import static org.infinispan.commons.marshall.MarshallableFunctions.SetValueMetasIfPresentReturnBoolean; import static org.infinispan.commons.marshall.MarshallableFunctions.SetValueMetasIfPresentReturnPrevOrNull; import static org.infinispan.commons.marshall.MarshallableFunctions.SetValueMetasReturnPrevOrNull; import static org.infinispan.commons.marshall.MarshallableFunctions.SetValueMetasReturnView; import static org.infinispan.commons.marshall.MarshallableFunctions.identity; import static org.infinispan.commons.marshall.MarshallableFunctions.removeConsumer; import static org.infinispan.commons.marshall.MarshallableFunctions.removeIfValueEqualsReturnBoolean; import static org.infinispan.commons.marshall.MarshallableFunctions.removeReturnBoolean; import static org.infinispan.commons.marshall.MarshallableFunctions.removeReturnPrevOrNull; import static org.infinispan.commons.marshall.MarshallableFunctions.returnReadOnlyFindIsPresent; import static org.infinispan.commons.marshall.MarshallableFunctions.returnReadOnlyFindOrNull; import static org.infinispan.commons.marshall.MarshallableFunctions.returnReadWriteFind; import static org.infinispan.commons.marshall.MarshallableFunctions.returnReadWriteGet; import static org.infinispan.commons.marshall.MarshallableFunctions.returnReadWriteView; import static org.infinispan.commons.marshall.MarshallableFunctions.setValueConsumer; import static org.infinispan.commons.marshall.MarshallableFunctions.setValueIfAbsentReturnBoolean; import static org.infinispan.commons.marshall.MarshallableFunctions.setValueIfAbsentReturnPrevOrNull; import static org.infinispan.commons.marshall.MarshallableFunctions.setValueIfPresentReturnBoolean; import static org.infinispan.commons.marshall.MarshallableFunctions.setValueIfPresentReturnPrevOrNull; import static org.infinispan.commons.marshall.MarshallableFunctions.setValueReturnPrevOrNull; import static org.infinispan.commons.marshall.MarshallableFunctions.setValueReturnView; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Set; import org.infinispan.commons.api.functional.MetaParam; import org.infinispan.commons.util.Util; import org.jboss.marshalling.util.IdentityIntMap; public class MarshallableFunctionExternalizers { // TODO: Should really rely on ValuteMatcherMode enumeration ordering private static final short VALUE_MATCH_ALWAYS = 0x1000; private static final short VALUE_MATCH_EXPECTED = 0x2000; private static final short VALUE_MATCH_EXPECTED_OR_NEW = 0x3000; private static final short VALUE_MATCH_NON_NULL = 0x4000; private static final short VALUE_MATCH_NEVER = 0x5000; private static final int VALUE_MATCH_MASK = 0xF000; private static final int SET_VALUE_RETURN_PREV_OR_NULL = 1 | VALUE_MATCH_ALWAYS; private static final int SET_VALUE_RETURN_VIEW = 2 | VALUE_MATCH_ALWAYS; private static final int SET_VALUE_IF_ABSENT_RETURN_PREV_OR_NULL = 3 | VALUE_MATCH_EXPECTED; private static final int SET_VALUE_IF_ABSENT_RETURN_BOOLEAN = 4 | VALUE_MATCH_EXPECTED; private static final int SET_VALUE_IF_PRESENT_RETURN_PREV_OR_NULL = 5 | VALUE_MATCH_NON_NULL; private static final int SET_VALUE_IF_PRESENT_RETURN_BOOLEAN = 6 | VALUE_MATCH_NON_NULL; private static final int REMOVE_RETURN_PREV_OR_NULL = 7 | VALUE_MATCH_ALWAYS; private static final int REMOVE_RETURN_BOOLEAN = 8 | VALUE_MATCH_ALWAYS; private static final int REMOVE_IF_VALUE_EQUALS_RETURN_BOOLEAN = 9 | VALUE_MATCH_EXPECTED; private static final int SET_VALUE_CONSUMER = 10 | VALUE_MATCH_ALWAYS; private static final int REMOVE_CONSUMER = 11 | VALUE_MATCH_ALWAYS; private static final int RETURN_READ_WRITE_FIND = 12 | VALUE_MATCH_ALWAYS; private static final int RETURN_READ_WRITE_GET = 13 | VALUE_MATCH_ALWAYS; private static final int RETURN_READ_WRITE_VIEW = 14 | VALUE_MATCH_ALWAYS; private static final int RETURN_READ_ONLY_FIND_OR_NULL = 15 | VALUE_MATCH_ALWAYS; private static final int RETURN_READ_ONLY_FIND_IS_PRESENT = 16 | VALUE_MATCH_ALWAYS; private static final int IDENTITY = 17 | VALUE_MATCH_ALWAYS; public static final class ConstantLambdaExternalizer implements LambdaExternalizer<Object> { private final IdentityIntMap<Class<?>> numbers = new IdentityIntMap<>(16); public ConstantLambdaExternalizer() { numbers.put(setValueReturnPrevOrNull().getClass(), SET_VALUE_RETURN_PREV_OR_NULL); numbers.put(setValueReturnView().getClass(), SET_VALUE_RETURN_VIEW); numbers.put(setValueIfAbsentReturnPrevOrNull().getClass(), SET_VALUE_IF_ABSENT_RETURN_PREV_OR_NULL); numbers.put(setValueIfAbsentReturnBoolean().getClass(), SET_VALUE_IF_ABSENT_RETURN_BOOLEAN); numbers.put(setValueIfPresentReturnPrevOrNull().getClass(), SET_VALUE_IF_PRESENT_RETURN_PREV_OR_NULL); numbers.put(setValueIfPresentReturnBoolean().getClass(), SET_VALUE_IF_PRESENT_RETURN_BOOLEAN); numbers.put(removeReturnPrevOrNull().getClass(), REMOVE_RETURN_PREV_OR_NULL); numbers.put(removeReturnBoolean().getClass(), REMOVE_RETURN_BOOLEAN); numbers.put(removeIfValueEqualsReturnBoolean().getClass(), REMOVE_IF_VALUE_EQUALS_RETURN_BOOLEAN); numbers.put(setValueConsumer().getClass(), SET_VALUE_CONSUMER); numbers.put(removeConsumer().getClass(), REMOVE_CONSUMER); numbers.put(returnReadWriteFind().getClass(), RETURN_READ_WRITE_FIND); numbers.put(returnReadWriteGet().getClass(), RETURN_READ_WRITE_GET); numbers.put(returnReadWriteView().getClass(), RETURN_READ_WRITE_VIEW); numbers.put(returnReadOnlyFindOrNull().getClass(), RETURN_READ_ONLY_FIND_OR_NULL); numbers.put(returnReadOnlyFindIsPresent().getClass(), RETURN_READ_ONLY_FIND_IS_PRESENT); numbers.put(identity().getClass(), IDENTITY); } @Override public ValueMatcherMode valueMatcher(Object o) { int i = numbers.get(o.getClass(), -1); if (i > 0) { int valueMatcherId = ((i & VALUE_MATCH_MASK) >> 12) - 1; return ValueMatcherMode.valueOf(valueMatcherId); } return ValueMatcherMode.MATCH_ALWAYS; } @Override public Set<Class<?>> getTypeClasses() { return Util.<Class<?>>asSet( setValueReturnPrevOrNull().getClass(), setValueReturnView().getClass(), setValueIfAbsentReturnPrevOrNull().getClass(), setValueIfAbsentReturnBoolean().getClass(), setValueIfPresentReturnPrevOrNull().getClass(), setValueIfPresentReturnBoolean().getClass(), removeReturnPrevOrNull().getClass(), removeReturnBoolean().getClass(), removeIfValueEqualsReturnBoolean().getClass(), setValueConsumer().getClass(), removeConsumer().getClass(), returnReadWriteFind().getClass(), returnReadWriteGet().getClass(), returnReadWriteView().getClass(), returnReadOnlyFindOrNull().getClass(), returnReadOnlyFindIsPresent().getClass(), identity().getClass() ); } @Override public Integer getId() { return Ids.LAMBDA_CONSTANT; } public void writeObject(ObjectOutput oo, Object o) throws IOException { int id = numbers.get(o.getClass(), -1); oo.writeShort(id); } public Object readObject(ObjectInput input) throws IOException { short id = input.readShort(); switch (id) { case SET_VALUE_RETURN_PREV_OR_NULL: return setValueReturnPrevOrNull(); case SET_VALUE_RETURN_VIEW: return setValueReturnView(); case SET_VALUE_IF_ABSENT_RETURN_PREV_OR_NULL: return setValueIfAbsentReturnPrevOrNull(); case SET_VALUE_IF_ABSENT_RETURN_BOOLEAN: return setValueIfAbsentReturnBoolean(); case SET_VALUE_IF_PRESENT_RETURN_PREV_OR_NULL: return setValueIfPresentReturnPrevOrNull(); case SET_VALUE_IF_PRESENT_RETURN_BOOLEAN: return setValueIfPresentReturnBoolean(); case REMOVE_RETURN_PREV_OR_NULL: return removeReturnPrevOrNull(); case REMOVE_RETURN_BOOLEAN: return removeReturnBoolean(); case REMOVE_IF_VALUE_EQUALS_RETURN_BOOLEAN: return removeIfValueEqualsReturnBoolean(); case SET_VALUE_CONSUMER: return setValueConsumer(); case REMOVE_CONSUMER: return removeConsumer(); case RETURN_READ_WRITE_FIND: return returnReadWriteFind(); case RETURN_READ_WRITE_GET: return returnReadWriteGet(); case RETURN_READ_WRITE_VIEW: return returnReadWriteView(); case RETURN_READ_ONLY_FIND_OR_NULL: return returnReadOnlyFindOrNull(); case RETURN_READ_ONLY_FIND_IS_PRESENT: return returnReadOnlyFindIsPresent(); case IDENTITY: return identity(); default: throw new IllegalStateException("Unknown lambda ID: " + id); } } } public static final class LambdaWithMetasExternalizer implements LambdaExternalizer<LambdaWithMetas> { private final IdentityIntMap<Class<?>> numbers = new IdentityIntMap<>(8); public LambdaWithMetasExternalizer() { numbers.put(SetValueMetasReturnPrevOrNull.class, SET_VALUE_RETURN_PREV_OR_NULL); numbers.put(SetValueMetasReturnView.class, SET_VALUE_RETURN_VIEW); numbers.put(SetValueMetasIfAbsentReturnPrevOrNull.class, SET_VALUE_IF_ABSENT_RETURN_PREV_OR_NULL); numbers.put(SetValueMetasIfAbsentReturnBoolean.class, SET_VALUE_IF_ABSENT_RETURN_BOOLEAN); numbers.put(SetValueMetasIfPresentReturnPrevOrNull.class, SET_VALUE_IF_PRESENT_RETURN_PREV_OR_NULL); numbers.put(SetValueMetasIfPresentReturnBoolean.class, SET_VALUE_IF_PRESENT_RETURN_BOOLEAN); numbers.put(SetValueMetas.class, SET_VALUE_CONSUMER); } @Override public ValueMatcherMode valueMatcher(Object o) { // TODO: Code duplication int i = numbers.get(o.getClass(), -1); if (i > 0) { int valueMatcherId = ((i & VALUE_MATCH_MASK) >> 12) - 1; return ValueMatcherMode.valueOf(valueMatcherId); } return ValueMatcherMode.MATCH_ALWAYS; } @Override public Set<Class<? extends LambdaWithMetas>> getTypeClasses() { return Util.<Class<? extends LambdaWithMetas>>asSet( SetValueMetasReturnPrevOrNull.class, SetValueMetasReturnView.class, SetValueMetasIfAbsentReturnPrevOrNull.class, SetValueMetasIfAbsentReturnBoolean.class, SetValueMetasIfPresentReturnPrevOrNull.class, SetValueMetasIfPresentReturnBoolean.class, SetValueMetas.class ); } @Override public Integer getId() { return Ids.LAMBDA_WITH_METAS; } @Override public void writeObject(ObjectOutput oo, LambdaWithMetas o) throws IOException { int id = numbers.get(o.getClass(), -1); oo.writeShort(id); writeMetas(oo, o); } @Override public LambdaWithMetas readObject(ObjectInput input) throws IOException, ClassNotFoundException { short id = input.readShort(); MetaParam.Writable[] metas = readMetas(input); switch (id) { case SET_VALUE_RETURN_PREV_OR_NULL: return new SetValueMetasReturnPrevOrNull<>(metas); case SET_VALUE_IF_ABSENT_RETURN_PREV_OR_NULL: return new SetValueMetasIfAbsentReturnPrevOrNull<>(metas); case SET_VALUE_IF_ABSENT_RETURN_BOOLEAN: return new SetValueMetasIfAbsentReturnBoolean<>(metas); case SET_VALUE_RETURN_VIEW: return new SetValueMetasReturnView<>(metas); case SET_VALUE_IF_PRESENT_RETURN_PREV_OR_NULL: return new SetValueMetasIfPresentReturnPrevOrNull<>(metas); case SET_VALUE_IF_PRESENT_RETURN_BOOLEAN: return new SetValueMetasIfPresentReturnBoolean<>(metas); case SET_VALUE_CONSUMER: return new SetValueMetas<>(metas); default: throw new IllegalStateException("Unknown lambda and meta parameters with ID: " + id); } } } static MetaParam.Writable[] readMetas(ObjectInput input) throws IOException, ClassNotFoundException { int len = input.readInt(); MetaParam.Writable[] metas = new MetaParam.Writable[len]; for(int i = 0; i < len; i++) metas[i] = (MetaParam.Writable) input.readObject(); return metas; } private static void writeMetas(ObjectOutput oo, LambdaWithMetas o) throws IOException { oo.writeInt(o.metas().length); for (MetaParam.Writable meta : o.metas()) oo.writeObject(meta); } public static final class SetValueIfEqualsReturnBooleanExternalizer implements LambdaExternalizer<SetValueIfEqualsReturnBoolean> { public void writeObject(ObjectOutput oo, SetValueIfEqualsReturnBoolean o) throws IOException { oo.writeObject(o.oldValue); writeMetas(oo, o); } public SetValueIfEqualsReturnBoolean readObject(ObjectInput input) throws IOException, ClassNotFoundException { Object oldValue = input.readObject(); MetaParam.Writable[] metas = readMetas(input); return new SetValueIfEqualsReturnBoolean<>(oldValue, metas); } @Override public ValueMatcherMode valueMatcher(Object o) { return ValueMatcherMode.MATCH_EXPECTED; } @Override public Set<Class<? extends SetValueIfEqualsReturnBoolean>> getTypeClasses() { return Util.<Class<? extends SetValueIfEqualsReturnBoolean>>asSet(SetValueIfEqualsReturnBoolean.class); } @Override public Integer getId() { return Ids.LAMBDA_SET_VALUE_IF_EQUALS_RETURN_BOOLEAN; } } }