summaryrefslogtreecommitdiffstats
path: root/vespajlib/src/main/java/com/yahoo/data
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
committerJon Bratseth <bratseth@yahoo-inc.com>2016-06-15 23:09:44 +0200
commit72231250ed81e10d66bfe70701e64fa5fe50f712 (patch)
tree2728bba1131a6f6e5bdf95afec7d7ff9358dac50 /vespajlib/src/main/java/com/yahoo/data
Publish
Diffstat (limited to 'vespajlib/src/main/java/com/yahoo/data')
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/ArrayTraverser.java16
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/Inspectable.java12
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/Inspector.java128
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/ObjectTraverser.java16
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/Type.java19
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/package-info.java7
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/simple/JsonRender.java166
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/simple/Value.java215
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/simple/package-info.java7
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/slime/SlimeAdapter.java156
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/access/slime/package-info.java5
-rw-r--r--vespajlib/src/main/java/com/yahoo/data/inspect/slime/.gitignore0
12 files changed, 747 insertions, 0 deletions
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/ArrayTraverser.java b/vespajlib/src/main/java/com/yahoo/data/access/ArrayTraverser.java
new file mode 100644
index 00000000000..99d79dd8eb5
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/ArrayTraverser.java
@@ -0,0 +1,16 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.data.access;
+
+/**
+ * Callback interface for traversing arrays.
+ * Implement this and call Inspector.traverse()
+ * and you will get one callback for each array entry.
+ **/
+public interface ArrayTraverser {
+ /**
+ * Callback function to implement.
+ * @param idx array index for the current array entry.
+ * @param inspector accessor for the current array entry's value.
+ **/
+ public void entry(int idx, Inspector inspector);
+}
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/Inspectable.java b/vespajlib/src/main/java/com/yahoo/data/access/Inspectable.java
new file mode 100644
index 00000000000..bf3344a0fe9
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/Inspectable.java
@@ -0,0 +1,12 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.data.access;
+
+/**
+ * Minimal API to implement for objects containing or exposing
+ * structured, generic, schemaless data. Use this when it's
+ * impractical to implement the Inspector interface directly.
+ **/
+public interface Inspectable {
+ /** get an Inspector exposing this object's structured data. */
+ public Inspector inspect();
+}
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/Inspector.java b/vespajlib/src/main/java/com/yahoo/data/access/Inspector.java
new file mode 100644
index 00000000000..0b0061792bd
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/Inspector.java
@@ -0,0 +1,128 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.data.access;
+
+
+import java.util.Map;
+
+/**
+ * This is a generic API for accessing structured, generic, schemaless data.
+ * An inspector is a handle to a value that has one of 8 specific types:
+ * EMPTY, the 5 scalar types BOOL, LONG, DOUBLE, STRING, or DATA, the
+ * simple list-like ARRAY container and the struct-like OBJECT container.
+ * Instrospection methods are available, but you can also use accessors
+ * with a default value if you expect a certain type and just want your
+ * default value if some field doesn't exist or was of the wrong type.
+ **/
+public interface Inspector extends Inspectable {
+
+ /**
+ * Check if the inspector is valid.
+ * If you try to access a field or array entry that does not exist,
+ * you will get an invalid Inspector returned.
+ */
+ public boolean valid();
+
+ /** Get the type of an inspector */
+ public Type type();
+
+ /** Get the number of entries in an ARRAY (always returns 0 for non-arrays) */
+ public int entryCount();
+
+ /** Get the number of fields in an OBJECT (always returns 0 for non-objects) */
+ public int fieldCount();
+
+ /** Access the inspector's value if it's a BOOLEAN; otherwise throws exception */
+ public boolean asBool();
+
+ /** Access the inspector's value if it's a LONG (or DOUBLE); otherwise throws exception */
+ public long asLong();
+
+ /** Access the inspector's value if it's a DOUBLE (or LONG); otherwise throws exception */
+ public double asDouble();
+
+ /** Access the inspector's value if it's a STRING; otherwise throws exception */
+ public String asString();
+
+ /**
+ * Access the inspector's value (in utf-8 representation) if it's
+ * a STRING; otherwise throws exception
+ **/
+ public byte[] asUtf8();
+
+ /** Access the inspector's value if it's DATA; otherwise throws exception */
+ public byte[] asData();
+
+ /** Get the inspector's value (or the supplied default), never throws */
+ public boolean asBool(boolean defaultValue);
+
+ /** Get the inspector's value (or the supplied default), never throws */
+ public long asLong(long defaultValue);
+
+ /** Get the inspector's value (or the supplied default), never throws */
+ public double asDouble(double defaultValue);
+
+ /** Get the inspector's value (or the supplied default), never throws */
+ public String asString(String defaultValue);
+
+ /** Get the inspector's value (or the supplied default), never throws */
+ public byte[] asUtf8(byte[] defaultValue);
+
+ /** Get the inspector's value (or the supplied default), never throws */
+ public byte[] asData(byte[] defaultValue);
+
+ /**
+ * Traverse an array value, performing callbacks for each entry.
+ *
+ * If the current Inspector is connected to an array value,
+ * perform callbacks to the given traverser for each entry
+ * contained in the array. Otherwise a no-op.
+ * @param at traverser callback object.
+ **/
+ @SuppressWarnings("overloads")
+ public void traverse(ArrayTraverser at);
+
+ /**
+ * Traverse an object value, performing callbacks for each field.
+ *
+ * If the current Inspector is connected to an object value,
+ * perform callbacks to the given traverser for each field
+ * contained in the object. Otherwise a no-op.
+ * @param ot traverser callback object.
+ **/
+ @SuppressWarnings("overloads")
+ public void traverse(ObjectTraverser ot);
+
+ /**
+ * Access an array entry.
+ *
+ * If the current Inspector doesn't connect to an array value,
+ * or the given array index is out of bounds, the returned
+ * Inspector will be invalid.
+ * @param idx array index.
+ * @return a new Inspector for the entry value.
+ **/
+ public Inspector entry(int idx);
+
+ /**
+ * Access an field in an object.
+ *
+ * If the current Inspector doesn't connect to an object value, or
+ * the object value does not contain a field with the given symbol
+ * name, the returned Inspector will be invalid.
+ * @param name symbol name.
+ * @return a new Inspector for the field value.
+ **/
+ public Inspector field(String name);
+
+ /**
+ * Convert an array to an iterable list. Other types will just
+ * return an empty list.
+ **/
+ public Iterable<Inspector> entries();
+
+ /**
+ * Convert an object to an iterable list of (name, value) pairs.
+ * Other types will just return an empty list.
+ **/
+ public Iterable<Map.Entry<String,Inspector>> fields();
+}
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/ObjectTraverser.java b/vespajlib/src/main/java/com/yahoo/data/access/ObjectTraverser.java
new file mode 100644
index 00000000000..90ff360d63d
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/ObjectTraverser.java
@@ -0,0 +1,16 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.data.access;
+
+/**
+ * Callback interface for traversing objects.
+ * Implement this and call Inspector.traverse()
+ * and you will get one callback for each field in an object.
+ **/
+public interface ObjectTraverser {
+ /**
+ * Callback function to implement.
+ * @param name the name of the current field.
+ * @param inspector accessor for the current field's value.
+ **/
+ public void field(String name, Inspector inspector);
+}
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/Type.java b/vespajlib/src/main/java/com/yahoo/data/access/Type.java
new file mode 100644
index 00000000000..e09b0ba9adc
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/Type.java
@@ -0,0 +1,19 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.data.access;
+
+/**
+ * Enumeration of all possible types accessed by the Inspector API.
+ * Note that:
+ * - the EMPTY type is used as a placeholder where data is missing.
+ * - all integers are put into LONGs; the encoding takes care of
+ * packing small integers compactly so this is also efficient.
+ * - likeweise DOUBLE is the only floating-point type, but "simple"
+ * numbers (like 0.0 or 1.0) are packed compactly anyway.
+ * - DATA can be used anything for wrapping anything else serialized
+ * as an array of bytes.
+ * - maps should be represented as an ARRAY of OBJECTs where each
+ * object has the fields "key" and "value".
+ **/
+public enum Type {
+ EMPTY, BOOL, LONG, DOUBLE, STRING, DATA, ARRAY, OBJECT;
+}
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/package-info.java b/vespajlib/src/main/java/com/yahoo/data/access/package-info.java
new file mode 100644
index 00000000000..904686c5d78
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/package-info.java
@@ -0,0 +1,7 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+@ExportPackage
+@PublicApi
+package com.yahoo.data.access;
+
+import com.yahoo.api.annotations.PublicApi;
+import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/simple/JsonRender.java b/vespajlib/src/main/java/com/yahoo/data/access/simple/JsonRender.java
new file mode 100644
index 00000000000..6acc43c2198
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/simple/JsonRender.java
@@ -0,0 +1,166 @@
+// Copyright 2016 Yahoo Inc. 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.text.DoubleFormatter;
+import com.yahoo.data.access.*;
+
+/**
+ * Encodes json from an inspectable object.
+ *
+ * @author arnej27959
+ */
+public final class JsonRender
+{
+ public static StringBuilder render(Inspectable value,
+ StringBuilder target,
+ boolean compact)
+ {
+ StringEncoder enc = new StringEncoder(target, compact);
+ enc.encode(value.inspect());
+ return target;
+ }
+
+ public static final class StringEncoder implements ArrayTraverser, ObjectTraverser
+ {
+ private final StringBuilder out;
+ private boolean head = true;
+ private boolean compact;
+ private int level = 0;
+
+ public StringEncoder(StringBuilder out, boolean compact) {
+ this.out = out;
+ this.compact = compact;
+ }
+
+ public void encode(Inspector top) {
+ encodeValue(top);
+ if (!compact) {
+ out.append('\n');
+ }
+ }
+
+ private void encodeEMPTY() {
+ out.append("null");
+ }
+
+ private void encodeBOOL(boolean value) {
+ out.append(value ? "true" : "false");
+ }
+
+ private void encodeLONG(long value) {
+ out.append(String.valueOf(value));
+ }
+
+ private void encodeDOUBLE(double value) {
+ if (Double.isNaN(value) || Double.isInfinite(value)) {
+ out.append("null");
+ } else {
+ out.append(DoubleFormatter.stringValue(value));
+ }
+ }
+
+ static final char[] hex = "0123456789ABCDEF".toCharArray();
+
+ private void encodeSTRING(String value) {
+ out.append('"');
+ for (char c : value.toCharArray()) {
+ switch (c) {
+ case '"': out.append('\\').append('"'); break;
+ case '\\': out.append('\\').append('\\'); break;
+ case '\b': out.append('\\').append('b'); break;
+ case '\f': out.append('\\').append('f'); break;
+ case '\n': out.append('\\').append('n'); break;
+ case '\r': out.append('\\').append('r'); break;
+ case '\t': out.append('\\').append('t'); break;
+ default:
+ if (c > 0x1f && c < 127) {
+ out.append(c);
+ } else { // requires escaping according to RFC 4627
+ out.append('\\').append('u');
+ out.append(hex[(c >> 12) & 0xf]);
+ out.append(hex[(c >> 8) & 0xf]);
+ out.append(hex[(c >> 4) & 0xf]);
+ out.append(hex[c & 0xf]);
+ }
+ }
+ }
+ out.append('"');
+ }
+
+ private void encodeDATA(byte[] value) {
+ out.append('"');
+ out.append("0x");
+ for (int pos = 0; pos < value.length; pos++) {
+ out.append(hex[(value[pos] >> 4) & 0xf]);
+ out.append(hex[value[pos] & 0xf]);
+ }
+ out.append('"');
+ }
+
+ private void encodeARRAY(Inspector inspector) {
+ openScope("[");
+ ArrayTraverser at = this;
+ inspector.traverse(at);
+ closeScope("]");
+ }
+
+ private void encodeOBJECT(Inspector inspector) {
+ openScope("{");
+ ObjectTraverser ot = this;
+ inspector.traverse(ot);
+ closeScope("}");
+ }
+
+ private void openScope(String opener) {
+ out.append(opener);
+ level++;
+ head = true;
+ }
+
+ private void closeScope(String closer) {
+ level--;
+ separate(false);
+ out.append(closer);
+ }
+
+ private void encodeValue(Inspector inspector) {
+ switch(inspector.type()) {
+ case EMPTY: encodeEMPTY(); return;
+ case BOOL: encodeBOOL(inspector.asBool()); return;
+ case LONG: encodeLONG(inspector.asLong()); return;
+ case DOUBLE: encodeDOUBLE(inspector.asDouble()); return;
+ case STRING: encodeSTRING(inspector.asString()); return;
+ case DATA: encodeDATA(inspector.asData()); return;
+ case ARRAY: encodeARRAY(inspector); return;
+ case OBJECT: encodeOBJECT(inspector); return;
+ }
+ assert false : "Should not be reached";
+ }
+
+ private void separate(boolean useComma) {
+ if (!head && useComma) {
+ out.append(',');
+ } else {
+ head = false;
+ }
+ if (!compact) {
+ out.append("\n");
+ for (int lvl = 0; lvl < level; lvl++) { out.append(" "); }
+ }
+ }
+
+ public void entry(int idx, Inspector inspector) {
+ separate(true);
+ encodeValue(inspector);
+ }
+
+ public void field(String name, Inspector inspector) {
+ separate(true);
+ encodeSTRING(name);
+ out.append(':');
+ if (!compact)
+ out.append(' ');
+ encodeValue(inspector);
+ }
+ }
+}
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/simple/Value.java b/vespajlib/src/main/java/com/yahoo/data/access/simple/Value.java
new file mode 100644
index 00000000000..baf5ce3cc54
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/simple/Value.java
@@ -0,0 +1,215 @@
+// Copyright 2016 Yahoo Inc. 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.*;
+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 Value empty = new EmptyValue();
+ private static Value invalid = new Value();
+ private static 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<Inspector> entries() { return Collections.emptyList(); }
+ public Iterable<Map.Entry<java.lang.String,Inspector>> 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 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 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 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 List<Inspector> values = new ArrayList<>();
+ 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<Inspector> 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 Map<java.lang.String,Inspector> 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<java.lang.String,Inspector> i: values.entrySet()) {
+ ot.field(i.getKey(), i.getValue());
+ }
+ }
+ public Iterable<Map.Entry<java.lang.String,Inspector>> fields() {
+ return Collections.<java.lang.String,Inspector>unmodifiableMap(values).entrySet();
+ }
+ public ObjectValue put(java.lang.String name, Inspector v) {
+ if (name == null) {
+ throw new IllegalArgumentException("field name was <null>");
+ }
+ 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));
+ }
+ }
+}
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/simple/package-info.java b/vespajlib/src/main/java/com/yahoo/data/access/simple/package-info.java
new file mode 100644
index 00000000000..730dc508b21
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/simple/package-info.java
@@ -0,0 +1,7 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+@ExportPackage
+@PublicApi
+package com.yahoo.data.access.simple;
+
+import com.yahoo.api.annotations.PublicApi;
+import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/slime/SlimeAdapter.java b/vespajlib/src/main/java/com/yahoo/data/access/slime/SlimeAdapter.java
new file mode 100644
index 00000000000..adfadfe8bb8
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/slime/SlimeAdapter.java
@@ -0,0 +1,156 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.data.access.slime;
+
+
+import java.util.Map;
+import java.util.AbstractMap;
+import java.util.List;
+import java.util.ArrayList;
+
+
+public final class SlimeAdapter implements com.yahoo.data.access.Inspector {
+ private com.yahoo.slime.Inspector inspector;
+ public SlimeAdapter(com.yahoo.slime.Inspector inspector) { this.inspector = inspector; }
+ @Override public boolean equals(Object rhs) {
+ if (!(rhs instanceof SlimeAdapter)) {
+ return false;
+ }
+ return inspector.equals(((SlimeAdapter)rhs).inspector);
+ }
+ @Override public int hashCode() { return inspector.hashCode(); }
+ @Override public String toString() { return inspector.toString(); }
+ public com.yahoo.data.access.Inspector inspect() { return this; }
+ public boolean valid() { return inspector.valid(); }
+ public com.yahoo.data.access.Type type() {
+ switch(inspector.type()) {
+ case NIX: return com.yahoo.data.access.Type.EMPTY;
+ case BOOL: return com.yahoo.data.access.Type.BOOL;
+ case LONG: return com.yahoo.data.access.Type.LONG;
+ case DOUBLE: return com.yahoo.data.access.Type.DOUBLE;
+ case STRING: return com.yahoo.data.access.Type.STRING;
+ case DATA: return com.yahoo.data.access.Type.DATA;
+ case ARRAY: return com.yahoo.data.access.Type.ARRAY;
+ case OBJECT: return com.yahoo.data.access.Type.OBJECT;
+ }
+ return com.yahoo.data.access.Type.EMPTY;
+ }
+ private boolean verify(com.yahoo.slime.Type ok_type_a) {
+ com.yahoo.slime.Type my_type = inspector.type();
+ return (valid() && (my_type == ok_type_a));
+ }
+ private boolean verify(com.yahoo.slime.Type ok_type_a,
+ com.yahoo.slime.Type ok_type_b)
+ {
+ com.yahoo.slime.Type my_type = inspector.type();
+ return (valid() && (my_type == ok_type_a || my_type == ok_type_b));
+ }
+ private boolean verify(com.yahoo.slime.Type ok_type_a,
+ com.yahoo.slime.Type ok_type_b,
+ com.yahoo.slime.Type ok_type_c)
+ {
+ com.yahoo.slime.Type my_type = inspector.type();
+ return (valid() && (my_type == ok_type_a || my_type == ok_type_b || my_type == ok_type_c));
+ }
+ public int entryCount() { return inspector.entries(); }
+ public int fieldCount() { return inspector.fields(); }
+ public boolean asBool() {
+ if (!verify(com.yahoo.slime.Type.NIX, com.yahoo.slime.Type.BOOL)) {
+ throw new IllegalStateException("invalid data extraction!");
+ }
+ return inspector.asBool();
+ }
+ public long asLong() {
+ if (!verify(com.yahoo.slime.Type.NIX, com.yahoo.slime.Type.LONG, com.yahoo.slime.Type.DOUBLE)) {
+ throw new IllegalStateException("invalid data extraction!");
+ }
+ return inspector.asLong();
+ }
+ public double asDouble() {
+ if (!verify(com.yahoo.slime.Type.NIX, com.yahoo.slime.Type.DOUBLE, com.yahoo.slime.Type.LONG)) {
+ throw new IllegalStateException("invalid data extraction!");
+ }
+ return inspector.asDouble();
+ }
+ public String asString() {
+ if (!verify(com.yahoo.slime.Type.NIX, com.yahoo.slime.Type.STRING)) {
+ throw new IllegalStateException("invalid data extraction!");
+ }
+ return inspector.asString();
+ }
+ public byte[] asUtf8() {
+ if (!verify(com.yahoo.slime.Type.NIX, com.yahoo.slime.Type.STRING)) {
+ throw new IllegalStateException("invalid data extraction!");
+ }
+ return inspector.asUtf8();
+ }
+ public byte[] asData() {
+ if (!verify(com.yahoo.slime.Type.NIX, com.yahoo.slime.Type.DATA)) {
+ throw new IllegalStateException("invalid data extraction!");
+ }
+ return inspector.asData();
+ }
+ public boolean asBool(boolean defaultValue) {
+ if (!verify(com.yahoo.slime.Type.BOOL)) {
+ return defaultValue;
+ }
+ return inspector.asBool();
+ }
+ public long asLong(long defaultValue) {
+ if (!verify(com.yahoo.slime.Type.LONG, com.yahoo.slime.Type.DOUBLE)) {
+ return defaultValue;
+ }
+ return inspector.asLong();
+ }
+ public double asDouble(double defaultValue) {
+ if (!verify(com.yahoo.slime.Type.DOUBLE, com.yahoo.slime.Type.LONG)) {
+ return defaultValue;
+ }
+ return inspector.asDouble();
+ }
+ public String asString(String defaultValue) {
+ if (!verify(com.yahoo.slime.Type.STRING)) {
+ return defaultValue;
+ }
+ return inspector.asString();
+ }
+ public byte[] asUtf8(byte[] defaultValue) {
+ if (!verify(com.yahoo.slime.Type.STRING)) {
+ return defaultValue;
+ }
+ return inspector.asUtf8();
+ }
+ public byte[] asData(byte[] defaultValue) {
+ if (!verify(com.yahoo.slime.Type.DATA)) {
+ return defaultValue;
+ }
+ return inspector.asData();
+ }
+ public void traverse(final com.yahoo.data.access.ArrayTraverser at) {
+ inspector.traverse(new com.yahoo.slime.ArrayTraverser() {
+ public void entry(int idx, com.yahoo.slime.Inspector inspector) { at.entry(idx, new SlimeAdapter(inspector)); }
+ });
+ }
+ public void traverse(final com.yahoo.data.access.ObjectTraverser ot) {
+ inspector.traverse(new com.yahoo.slime.ObjectTraverser() {
+ public void field(String name, com.yahoo.slime.Inspector inspector) { ot.field(name, new SlimeAdapter(inspector)); }
+ });
+ }
+ public com.yahoo.data.access.Inspector entry(int idx) { return new SlimeAdapter(inspector.entry(idx)); }
+ public com.yahoo.data.access.Inspector field(String name) { return new SlimeAdapter(inspector.field(name)); }
+ public Iterable<com.yahoo.data.access.Inspector> entries() {
+ final List<com.yahoo.data.access.Inspector> list = new ArrayList<>();
+ inspector.traverse(new com.yahoo.slime.ArrayTraverser() {
+ public void entry(int idx, com.yahoo.slime.Inspector inspector) { list.add(new SlimeAdapter(inspector)); }
+ });
+ return list;
+ }
+ public Iterable<Map.Entry<String,com.yahoo.data.access.Inspector>> fields() {
+ final List<Map.Entry<String,com.yahoo.data.access.Inspector>> list = new ArrayList<>();
+ inspector.traverse(new com.yahoo.slime.ObjectTraverser() {
+ public void field(String name, com.yahoo.slime.Inspector inspector) {
+ list.add(new AbstractMap.SimpleImmutableEntry<String,com.yahoo.data.access.Inspector>(name, new SlimeAdapter(inspector)));
+ }
+ });
+ return list;
+ }
+}
diff --git a/vespajlib/src/main/java/com/yahoo/data/access/slime/package-info.java b/vespajlib/src/main/java/com/yahoo/data/access/slime/package-info.java
new file mode 100644
index 00000000000..bf6ae26baee
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/access/slime/package-info.java
@@ -0,0 +1,5 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+@ExportPackage
+package com.yahoo.data.access.slime;
+
+import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/vespajlib/src/main/java/com/yahoo/data/inspect/slime/.gitignore b/vespajlib/src/main/java/com/yahoo/data/inspect/slime/.gitignore
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/data/inspect/slime/.gitignore