// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.data.access.simple; import com.yahoo.data.access.ArrayTraverser; import com.yahoo.data.access.Inspector; import com.yahoo.data.access.ObjectTraverser; import com.yahoo.data.access.Type; import java.util.Collections; import java.util.Map; import java.util.LinkedHashMap; import java.util.List; import java.util.ArrayList; import java.nio.charset.StandardCharsets; public class Value implements Inspector { private static final Value empty = new EmptyValue(); private static final Value invalid = new Value(); private static final byte[] empty_array = new byte[0]; public static Inspector empty() { return empty; } public static Inspector invalid() { return invalid; } public Inspector inspect() { return this; } public boolean valid() { return false; } public Type type() { return Type.EMPTY; } public int entryCount() { return 0; } public int fieldCount() { return 0; } public boolean asBool() { throw new IllegalStateException("invalid data access!"); } public long asLong() { throw new IllegalStateException("invalid data access!"); } public double asDouble() { throw new IllegalStateException("invalid data access!"); } public java.lang.String asString() { throw new IllegalStateException("invalid data access!"); } public byte[] asUtf8() { throw new IllegalStateException("invalid data access!"); } public byte[] asData() { throw new IllegalStateException("invalid data access!"); } public boolean asBool(boolean defaultValue) { return defaultValue; } public long asLong(long defaultValue) { return defaultValue; } public double asDouble(double defaultValue) { return defaultValue; } public java.lang.String asString(java.lang.String defaultValue) { return defaultValue; } public byte[] asUtf8(byte[] defaultValue) { return defaultValue; } public byte[] asData(byte[] defaultValue) { return defaultValue; } public void traverse(ArrayTraverser at) {} public void traverse(ObjectTraverser ot) {} public Inspector entry(int idx) { return invalid; } public Inspector field(java.lang.String name) { return invalid; } public Iterable entries() { return Collections.emptyList(); } public Iterable> fields() { return Collections.emptyList(); } public StringBuilder writeJson(StringBuilder target) { return JsonRender.render(this, target, true); } public String toJson() { return writeJson(new StringBuilder()).toString(); } public String toString() { return toJson(); } static public class EmptyValue extends Value { public boolean valid() { return true; } public boolean asBool() { return false; } public long asLong() { return 0L; } public double asDouble() { return 0.0; } public java.lang.String asString() { return ""; } public byte[] asUtf8() { return empty_array; } public byte[] asData() { return empty_array; } } static public class BoolValue extends Value { private final boolean value; public BoolValue(boolean v) { value = v; } public boolean valid() { return true; } public Type type() { return Type.BOOL; } public boolean asBool() { return value; } public boolean asBool(boolean x) { return value; } } static public class LongValue extends Value { private final long value; public LongValue(long v) { value = v; } public boolean valid() { return true; } public Type type() { return Type.LONG; } public long asLong() { return value; } public double asDouble() { return (double)value; } public long asLong(long x) { return value; } public double asDouble(double x) { return (double)value; } } static public class DoubleValue extends Value { private final double value; public DoubleValue(double v) { value = v; } public boolean valid() { return true; } public Type type() { return Type.DOUBLE; } public double asDouble() { return value; } public long asLong() { return (long)value; } public double asDouble(double x) { return value; } public long asLong(long x) { return (long)value; } } static public class StringValue extends Value { private java.lang.String string_value = null; private byte[] utf8_value = null; private void handle_null() { if (string_value == null && utf8_value == null) { string_value = ""; utf8_value = empty_array; } } public StringValue(java.lang.String v) { string_value = v; handle_null(); } public StringValue(byte[] v) { utf8_value = v; handle_null(); } public boolean valid() { return true; } public Type type() { return Type.STRING; } public java.lang.String asString() { if (string_value == null) { string_value = new java.lang.String(utf8_value, StandardCharsets.UTF_8); } return string_value; } public java.lang.String asString(java.lang.String x) { return asString(); } public byte[] asUtf8() { if (utf8_value == null) { utf8_value = string_value.getBytes(StandardCharsets.UTF_8); } return utf8_value; } public byte[] asUtf8(byte[] x) { return asUtf8(); } } static public class DataValue extends Value { private byte[] value; public DataValue(byte[] v) { value = v; if (v == null) { value = empty_array; } } public boolean valid() { return true; } public Type type() { return Type.DATA; } public byte[] asData() { return value; } public byte[] asData(byte[] x) { return value; } } static public class ArrayValue extends Value { private final List values; public ArrayValue() { values = new ArrayList<>(); } public ArrayValue(int capacity) { values = new ArrayList<>(capacity); } public boolean valid() { return true; } public Type type() { return Type.ARRAY; } public int entryCount() { return values.size(); } public Inspector entry(int idx) { if (idx < 0 || idx >= values.size()) { return invalid; } return values.get(idx); } public void traverse(ArrayTraverser at) { int idx = 0; for (Inspector i: values) { at.entry(idx++, i); } } public Iterable entries() { return Collections.unmodifiableList(values); } public ArrayValue add(Inspector v) { if (v == null || !v.valid()) { throw new IllegalArgumentException("tried to add an invalid value to an array"); } values.add(v); return this; } public ArrayValue add(java.lang.String value) { return add(new Value.StringValue(value)); } public ArrayValue add(long value) { return add(new Value.LongValue(value)); } public ArrayValue add(int value) { return add(new Value.LongValue(value)); } public ArrayValue add(double value) { return add(new Value.DoubleValue(value)); } } static public class ObjectValue extends Value { private final Map values = new LinkedHashMap<>(); public boolean valid() { return true; } public Type type() { return Type.OBJECT; } public int fieldCount() { return values.size(); } public Inspector field(java.lang.String name) { Inspector v = values.get(name); if (v == null) { return invalid; } return v; } public void traverse(ObjectTraverser ot) { for (Map.Entry i: values.entrySet()) { ot.field(i.getKey(), i.getValue()); } } public Iterable> fields() { return Collections.unmodifiableMap(values).entrySet(); } public ObjectValue put(java.lang.String name, Inspector v) { if (name == null) { throw new IllegalArgumentException("field name was "); } if (v == null || !v.valid()) { throw new IllegalArgumentException("tried to put an invalid value into an object"); } values.put(name, v); return this; } public ObjectValue put(java.lang.String name, java.lang.String value) { return put(name, new Value.StringValue(value)); } public ObjectValue put(java.lang.String name, long value) { return put(name, new Value.LongValue(value)); } public ObjectValue put(java.lang.String name, int value) { return put(name, new Value.LongValue(value)); } public ObjectValue put(java.lang.String name, double value) { return put(name, new Value.DoubleValue(value)); } } }