package org.infinispan.scripting.impl; import java.nio.charset.Charset; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import org.infinispan.commons.CacheException; import org.infinispan.commons.marshall.Marshaller; import org.infinispan.commons.util.Immutables; public enum DataType { UTF8(new Utf8Transformer()), DEFAULT(new DefaultTransformer()); public final Transformer transformer; DataType(Transformer transformer) { this.transformer = transformer; } public static DataType fromMime(String mime) { switch (mime) { case "text/plain; charset=utf-8": return UTF8; default: return DEFAULT; } } interface Transformer { Object toDataType(Object obj, Optional<Marshaller> marshaller); Map<String, ?> toDataType(Map<String, ?> objs, Optional<Marshaller> marshaller); Object fromDataType(Object obj, Optional<Marshaller> marshaller); } static final class Utf8Transformer implements Transformer { public static final Charset CHARSET_UTF8 = Charset.forName("UTF-8"); @Override public Object toDataType(Object obj, Optional<Marshaller> marshaller) { return obj instanceof byte[] ? asString(obj) : obj; } @Override public Map<String, ?> toDataType(Map<String, ?> objs, Optional<Marshaller> marshaller) { return objs.entrySet().stream().map(e -> { Object v = e.getValue(); Object entryValue = v instanceof byte[] ? asString(v) : v; return Immutables.immutableEntry(e.getKey(), entryValue); }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } @Override @SuppressWarnings("unchecked") public Object fromDataType(Object obj, Optional<Marshaller> marshaller) { if (obj instanceof List) { return ((List) obj).stream() .map(x -> x == null ? "" : x.toString()) .collect(Collectors.joining("\", \"", "[\"", "\"]")) .toString().getBytes(CHARSET_UTF8); } else if (obj instanceof byte[]) { return obj; } return Objects.isNull(obj) ? null : obj.toString().getBytes(CHARSET_UTF8); } private static String asString(Object v) { return new String((byte[]) v, CHARSET_UTF8); } } static final class DefaultTransformer implements Transformer { @Override public Object toDataType(Object obj, Optional<Marshaller> marshaller) { return marshaller.map(m -> obj instanceof byte[] ? fromBytes(obj, m) : obj).orElse(obj); } @Override public Map<String, ?> toDataType(Map<String, ?> objs, Optional<Marshaller> marshaller) { if (marshaller.isPresent()) { Marshaller m = marshaller.get(); return objs.entrySet().stream().map(e -> { Object v = e.getValue(); Object entryValue = v instanceof byte[] ? fromBytes(v, m) : v; return Immutables.immutableEntry(e.getKey(), entryValue); }).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); } return objs; } private static Object fromBytes(Object obj, Marshaller marshaller) { try { return marshaller.objectFromByteBuffer((byte[]) obj); } catch (Exception e) { throw new CacheException(e); } } @Override public Object fromDataType(Object obj, Optional<Marshaller> marshaller) { try { return marshaller.map(m -> toBytes(obj, m)).orElse(obj); } catch (Exception e) { throw new CacheException(e); } } private static Object toBytes(Object obj, Marshaller marshaller) { try { return obj instanceof byte[] ? obj : marshaller.objectToByteBuffer(obj); } catch (Exception e) { throw new CacheException(e); } } } }