package org.infinispan.stream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import org.infinispan.commons.marshall.AdvancedExternalizer;
import org.infinispan.commons.util.Util;
import org.infinispan.marshall.core.Ids;
/**
* Static factory class containing methods that will provide marshallable instances for very common use cases.
* Every instance returned from the various static methods uses the Infinispan marshalling to reduce payload sizes
* considerably and should be used whenever possible.
*/
public class StreamMarshalling {
private StreamMarshalling() { }
/**
* Provides a predicate that returns true when the object is equal.
* @param object the instance to test equality on
* @return the predicate
*/
public static Predicate<Object> equalityPredicate(Object object) {
return new EqualityPredicate(object);
}
/**
* Predicate that returns true if the object passed to it is not null.
* @return the predicate
*/
public static Predicate<Object> nonNullPredicate() {
return NonNullPredicate.getInstance();
}
/**
* Predicate taht always returns true irrespective of the value provided
* @return the predicate
*/
public static Predicate<Object> alwaysTruePredicate() {
return AlwaysTruePredicate.getInstance();
}
/**
* Provides a function that returns the key of the entry when invoked.
* @param <K> key type of the entry
* @param <V> value type of the entry
* @return a function that when applied to a given entry will return the key
*/
public static <K, V> Function<Map.Entry<K, V>, K> entryToKeyFunction() {
return EntryToKeyFunction.getInstance();
}
/**
* Provides a function that returns the value of the entry when invoked.
* @param <K> key type of the entry
* @param <V> value type of the entry
* @return a function that when applied to a given entry will return the value
*/
public static <K, V> Function<Map.Entry<K, V>, V> entryToValueFunction() {
return EntryToValueFunction.getInstance();
}
private static final class EqualityPredicate implements Predicate<Object> {
private final Object object;
private EqualityPredicate(Object object) {
Objects.nonNull(object);
this.object = object;
}
@Override
public boolean test(Object t) {
return object.equals(t);
}
}
private static final class NonNullPredicate implements Predicate<Object> {
private static final NonNullPredicate INSTANCE = new NonNullPredicate();
public static NonNullPredicate getInstance() {
return INSTANCE;
}
@Override
public boolean test(Object t) {
return t != null;
}
}
private static final class AlwaysTruePredicate implements Predicate<Object> {
private static final AlwaysTruePredicate INSTANCE = new AlwaysTruePredicate();
public static AlwaysTruePredicate getInstance() {
return INSTANCE;
}
@Override
public boolean test(Object t) {
return true;
}
}
private static final class EntryToKeyFunction<K, V> implements Function<Map.Entry<K, V>, K> {
private static final EntryToKeyFunction<?, ?> FUNCTION = new EntryToKeyFunction<>();
public static <K, V> EntryToKeyFunction<K, V> getInstance() {
return (EntryToKeyFunction<K, V>) FUNCTION;
}
@Override
public K apply(Map.Entry<K, V> kvEntry) {
return kvEntry.getKey();
}
}
private static final class EntryToValueFunction<K, V> implements Function<Map.Entry<K, V>, V> {
private static final EntryToValueFunction<?, ?> FUNCTION = new EntryToValueFunction<>();
public static <K, V> EntryToValueFunction<K, V> getInstance() {
return (EntryToValueFunction<K, V>) FUNCTION;
}
@Override
public V apply(Map.Entry<K, V> kvEntry) {
return kvEntry.getValue();
}
}
public static final class StreamMarshallingExternalizer implements AdvancedExternalizer<Object> {
enum ExternalizerId {
EQUALITY_PREDICATE(EqualityPredicate.class),
ENTRY_KEY_FUNCTION(EntryToKeyFunction.class),
ENTRY_VALUE_FUNCTION(EntryToValueFunction.class),
NON_NULL_PREDICATE(NonNullPredicate.class),
ALWAYS_TRUE_PREDICATE(AlwaysTruePredicate.class);
private final Class<? extends Object> marshalledClass;
ExternalizerId(Class<? extends Object> marshalledClass) {
this.marshalledClass = marshalledClass;
}
}
private final Map<Class<? extends Object>, ExternalizerId> objects = new HashMap<>();
public StreamMarshallingExternalizer() {
for (ExternalizerId id : ExternalizerId.values()) {
objects.put(id.marshalledClass, id);
}
}
@Override
public Set<Class<?>> getTypeClasses() {
return Util.<Class<? extends Object>>asSet(EqualityPredicate.class, EntryToKeyFunction.class,
EntryToValueFunction.class, NonNullPredicate.class, AlwaysTruePredicate.class);
}
@Override
public Integer getId() {
return Ids.STREAM_MARSHALLING;
}
@Override
public void writeObject(ObjectOutput output, Object object) throws IOException {
ExternalizerId id = objects.get(object.getClass());
if (id == null) {
throw new IllegalArgumentException("Unsupported class " + object.getClass() + " was provided!");
}
output.writeByte(id.ordinal());
switch (id) {
case EQUALITY_PREDICATE:
output.writeObject(((EqualityPredicate) object).object);
break;
}
}
@Override
public Object readObject(ObjectInput input) throws IOException, ClassNotFoundException {
int number = input.readUnsignedByte();
ExternalizerId[] ids = ExternalizerId.values();
if (number < 0 || number >= ids.length) {
throw new IllegalArgumentException("Found invalid number " + number);
}
ExternalizerId id = ids[number];
switch (id) {
case EQUALITY_PREDICATE:
return new EqualityPredicate(input.readObject());
case ENTRY_KEY_FUNCTION:
return EntryToKeyFunction.getInstance();
case ENTRY_VALUE_FUNCTION:
return EntryToValueFunction.getInstance();
case NON_NULL_PREDICATE:
return NonNullPredicate.getInstance();
case ALWAYS_TRUE_PREDICATE:
return AlwaysTruePredicate.getInstance();
default:
throw new IllegalArgumentException("ExternalizerId not supported: " + id);
}
}
}
}