diff --git a/ChangeLog b/ChangeLog index 4aa3c15..834f813 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,5 @@ +* Fri Mar 07 17:00:00 PDT 2014 Vikram Kadi 1.5.0 +Changes to emit a json form of the lwes event. * Tue Aug 07 08:00:00 PDT 2013 Robert Wong 1.4.1 Fix bug where sampleRate was not correctly set. * Tue Jul 30 08:00:00 PDT 2013 Robert Wong 1.4.0 diff --git a/pom.xml b/pom.xml index abf34fd..6d88bf3 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ org.lwes lwes-java jar - 1.4.3-SNAPSHOT + 1.5.0-SNAPSHOT lwes-java Lightweight event system, java implementation http://lwes.org @@ -48,6 +48,13 @@ + + + com.google.code.gson + gson + 2.2.4 + + junit junit diff --git a/src/main/java/org/lwes/ArrayEvent.java b/src/main/java/org/lwes/ArrayEvent.java index 74d68f6..76ee39b 100644 --- a/src/main/java/org/lwes/ArrayEvent.java +++ b/src/main/java/org/lwes/ArrayEvent.java @@ -18,6 +18,7 @@ import java.util.EnumMap; import java.util.Enumeration; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.SortedSet; @@ -26,8 +27,10 @@ import org.apache.commons.lang3.mutable.MutableInt; import org.lwes.serializer.Deserializer; import org.lwes.serializer.DeserializerState; +import org.lwes.serializer.JsonSerializer; import org.lwes.serializer.Serializer; import org.lwes.util.EncodedString; +import org.lwes.util.EventTranslator; public final class ArrayEvent extends DefaultEvent { @@ -679,4 +682,16 @@ public Object getValue() { return value; } } + + public String json() { + return EventTranslator.arrayToMapEvent(this).json(); + } + + public String unTypedJson() { + return EventTranslator.arrayToMapEvent(this).unTypedJson(); + } + + public Map getAttributeNameTypeValues(){ + return EventTranslator.arrayToMapEvent(this).getAttributeNameTypeValues(); + } } diff --git a/src/main/java/org/lwes/BaseType.java b/src/main/java/org/lwes/BaseType.java index db1fd71..88d0c4f 100644 --- a/src/main/java/org/lwes/BaseType.java +++ b/src/main/java/org/lwes/BaseType.java @@ -13,9 +13,12 @@ package org.lwes; import java.lang.reflect.Array; +import java.math.BigInteger; +import org.lwes.serializer.StringConverter; import org.lwes.serializer.StringParser; import org.lwes.util.EncodedString; +import org.lwes.util.IPAddress; /** * This class provides a base type for the base types in the event system. acts @@ -366,6 +369,84 @@ public BaseType cloneBaseType() { public String toString() { return typeObject.toString(); } + + /** + * This method returns the correct string representation of the underlying data, + * + * e.g. for cases where the data is an array of integers, the default toString will just print out + * the internal java representation of array class type, but this method would convert the + * individual elements into strings and return a string array + * @return + */ + + public Object stringyfy(){ + + if(typeObject == null) + return null; + + switch (type) { + case BOOLEAN: + case BYTE: + case DOUBLE: + case FLOAT: + case INT16: + case INT32: + case INT64: + case UINT16: + case UINT32: + case UINT64: + case STRING: + case IPADDR: + return typeObject.toString(); + case BOOLEAN_ARRAY: + return StringConverter.strArray((boolean[]) typeObject); + case BYTE_ARRAY: + return StringConverter.strArray((byte[]) typeObject); + case DOUBLE_ARRAY: + return StringConverter.strArray((double[]) typeObject); + case FLOAT_ARRAY: + return StringConverter.strArray((float[]) typeObject); + case INT16_ARRAY: + return StringConverter.strArray((short[]) typeObject); + case INT32_ARRAY: + return StringConverter.strArray((int[]) typeObject); + case INT64_ARRAY: + return StringConverter.strArray((long[]) typeObject); + case IP_ADDR_ARRAY: + return StringConverter.strArray((IPAddress[]) typeObject); + case STRING_ARRAY: + return StringConverter.strArray((String[]) typeObject); + case UINT16_ARRAY: + return StringConverter.strArray((int[]) typeObject); + case UINT32_ARRAY: + return StringConverter.strArray((long[]) typeObject); + case UINT64_ARRAY: + return StringConverter.strArray((BigInteger[]) typeObject); + case NBOOLEAN_ARRAY: + return StringConverter.strArray((Boolean[]) typeObject); + case NBYTE_ARRAY: + return StringConverter.strArray((Byte[]) typeObject); + case NDOUBLE_ARRAY: + return StringConverter.strArray((Double[]) typeObject); + case NFLOAT_ARRAY: + return StringConverter.strArray((Float[]) typeObject); + case NINT16_ARRAY: + return StringConverter.strArray((Short[]) typeObject); + case NINT32_ARRAY: + return StringConverter.strArray((Integer[]) typeObject); + case NINT64_ARRAY: + return StringConverter.strArray((Long[]) typeObject); + case NSTRING_ARRAY: + return StringConverter.strArray((String[]) typeObject); + case NUINT16_ARRAY: + return StringConverter.strArray((Integer[]) typeObject); + case NUINT32_ARRAY: + return StringConverter.strArray((Long[]) typeObject); + case NUINT64_ARRAY: + return StringConverter.strArray((BigInteger[]) typeObject); + } + return null; + } public String getComment() { return comment; diff --git a/src/main/java/org/lwes/Event.java b/src/main/java/org/lwes/Event.java index 704b306..abf18d2 100644 --- a/src/main/java/org/lwes/Event.java +++ b/src/main/java/org/lwes/Event.java @@ -19,6 +19,7 @@ import java.net.InetAddress; import java.util.Enumeration; import java.util.Iterator; +import java.util.Map; import java.util.Set; import org.lwes.util.CharacterEncoding; @@ -226,7 +227,13 @@ public interface Event extends Iterable { void deserialize(DataInput stream, int length) throws IOException; int getBytesSize(); - + + String json(); + + String unTypedJson(); + + Map getAttributeNameTypeValues(); + // MISCELLANEOUS Event copy(); diff --git a/src/main/java/org/lwes/EventFactory.java b/src/main/java/org/lwes/EventFactory.java index 3c0e711..4dee32b 100644 --- a/src/main/java/org/lwes/EventFactory.java +++ b/src/main/java/org/lwes/EventFactory.java @@ -13,6 +13,7 @@ package org.lwes; import org.lwes.db.EventTemplateDB; +import org.lwes.serializer.JsonDeserializer; import java.io.File; import java.io.InputStream; @@ -189,5 +190,22 @@ public Event createEvent(byte[] bytes, boolean validate) throws EventSystemExcep } return new MapEvent(bytes, validate, eventTemplateDB); } + + /** + * Create an event from its json representation + * @param json + * @param type + * @return + */ + public Event createEventFromJson(String json, EventImplementation type){ + JsonDeserializer deSerializer = JsonDeserializer.getInstance(); + switch (type) { + case MAP_EVENT: + return deSerializer.fromJson(json, new MapEvent()); + case ARRAY_EVENT: + return deSerializer.fromJson(json, new ArrayEvent()); + } + return null; + } } diff --git a/src/main/java/org/lwes/EventImplementation.java b/src/main/java/org/lwes/EventImplementation.java new file mode 100644 index 0000000..07b12e4 --- /dev/null +++ b/src/main/java/org/lwes/EventImplementation.java @@ -0,0 +1,5 @@ +package org.lwes; + +public enum EventImplementation { + MAP_EVENT, ARRAY_EVENT; +} diff --git a/src/main/java/org/lwes/FieldType.java b/src/main/java/org/lwes/FieldType.java index d8d6a29..2ba0a1d 100644 --- a/src/main/java/org/lwes/FieldType.java +++ b/src/main/java/org/lwes/FieldType.java @@ -16,73 +16,78 @@ import org.lwes.util.IPAddress; public enum FieldType { - UINT16(0x01, "uint16", 0), - INT16(0x02, "int16", (short) 0), - UINT32(0x03, "uint32", 0L), - INT32(0x04, "int32", 0), - STRING(0x05, "string", ""), - IPADDR(0x06, "ip_addr", new IPAddress()), - INT64(0x07, "int64", 0L), - UINT64(0x08, "uint64", BigInteger.ZERO), - BOOLEAN(0x09, "boolean", true), - BYTE(0x0A, "byte", (byte) 0), - FLOAT(0x0B, "float", (float) 0.0), - DOUBLE(0x0C, "double", 0.0), + UINT16(0x01, "uint16", 0, "uint16"), + INT16(0x02, "int16", (short) 0, "int16"), + UINT32(0x03, "uint32", 0L, "uint32"), + INT32(0x04, "int32", 0, "int32"), + STRING(0x05, "string", "", "string"), + IPADDR(0x06, "ip_addr", new IPAddress(), "ip_addr"), + INT64(0x07, "int64", 0L, "int64"), + UINT64(0x08, "uint64", BigInteger.ZERO, "uint64"), + BOOLEAN(0x09, "boolean", true, "boolean"), + BYTE(0x0A, "byte", (byte) 0, "byte"), + FLOAT(0x0B, "float", (float) 0.0, "float"), + DOUBLE(0x0C, "double", 0.0, "double"), // Primitive Arrays - UINT16_ARRAY(0x81, "[Luint16", new short[0]), - INT16_ARRAY(0x82, "[Lint16", new int[0]), - UINT32_ARRAY(0x83, "[Luint32", new int[0]), - INT32_ARRAY(0x84, "[Lint32", new long[0]), - STRING_ARRAY(0x85, "[Lstring", new String[0]), - IP_ADDR_ARRAY(0x86, "[Lip_addr", new IPAddress[0]), - INT64_ARRAY(0x87, "[Lint64", new long[0]), - UINT64_ARRAY(0x88, "[Luint64", new BigInteger[0]), - BOOLEAN_ARRAY(0x89, "[Lboolean", new boolean[0]), - BYTE_ARRAY(0x8A, "[Lbyte", new byte[0]), - FLOAT_ARRAY(0x8B, "[Lfloat", new float[0]), - DOUBLE_ARRAY(0x8C, "[Ldouble", new double[0]), + UINT16_ARRAY(0x81, "[Luint16", new short[0], "uint16_array"), + INT16_ARRAY(0x82, "[Lint16", new int[0], "int16_array"), + UINT32_ARRAY(0x83, "[Luint32", new int[0], "uint32_array"), + INT32_ARRAY(0x84, "[Lint32", new long[0], "int32_array"), + STRING_ARRAY(0x85, "[Lstring", new String[0], "string_array"), + IP_ADDR_ARRAY(0x86, "[Lip_addr", new IPAddress[0], "ip_addr_array"), + INT64_ARRAY(0x87, "[Lint64", new long[0], "int64_array"), + UINT64_ARRAY(0x88, "[Luint64", new BigInteger[0], "uint64_array"), + BOOLEAN_ARRAY(0x89, "[Lboolean", new boolean[0], "boolean_array"), + BYTE_ARRAY(0x8A, "[Lbyte", new byte[0], "byte_array"), + FLOAT_ARRAY(0x8B, "[Lfloat", new float[0], "float_array"), + DOUBLE_ARRAY(0x8C, "[Ldouble", new double[0], "double_array"), // Nullable, object backed arrays - NUINT16_ARRAY(0x8D, "[LNuint16", new Short[0]), - NINT16_ARRAY(0x8E, "[LNint16", new Integer[0]), - NUINT32_ARRAY(0x8F, "[LNuint32", new Integer[0]), - NINT32_ARRAY(0x90, "[LNint32", new Long[0]), - NSTRING_ARRAY(0x91, "[LString", new String[0]), + NUINT16_ARRAY(0x8D, "[LNuint16", new Short[0], "nullable_uint16_array"), + NINT16_ARRAY(0x8E, "[LNint16", new Integer[0], "nullable_int16_array"), + NUINT32_ARRAY(0x8F, "[LNuint32", new Integer[0], "nullable_uint32_array"), + NINT32_ARRAY(0x90, "[LNint32", new Long[0], "nullable_int32_array"), + NSTRING_ARRAY(0x91, "[LString", new String[0], "nullable_string_array"), // N_IP_ADDR_ARRAY not implemented... 0x92 - NINT64_ARRAY(0x93, "[LNint64", new Long[0]), - NUINT64_ARRAY(0x94, "[LNuint64", new BigInteger[0]), - NBOOLEAN_ARRAY(0x95, "[LBoolean", new Boolean[0]), - NBYTE_ARRAY(0x96, "[LByte", new Byte[0]), - NFLOAT_ARRAY(0x97, "[LFloat", new Float[0]), - NDOUBLE_ARRAY(0x98, "[LDouble", new Double[0]); + NINT64_ARRAY(0x93, "[LNint64", new Long[0], "nullable_int64_array"), + NUINT64_ARRAY(0x94, "[LNuint64", new BigInteger[0], "nullable_uint64_array"), + NBOOLEAN_ARRAY(0x95, "[LBoolean", new Boolean[0], "nullable_boolean_array"), + NBYTE_ARRAY(0x96, "[LByte", new Byte[0], "nullable_byte_array"), + NFLOAT_ARRAY(0x97, "[LFloat", new Float[0], "nullable_float_array"), + NDOUBLE_ARRAY(0x98, "[LDouble", new Double[0], "nullable_double_array"); public final byte token; public final String name; + public final String typeDesc; private Integer constantSize; private final boolean array, nullableArray; private FieldType componentType, arrayType, nullableArrayType; private final Object defaultValue; private static final FieldType[] TYPES_BY_TOKEN = new FieldType[256]; private static final Map TYPES_BY_NAME; + private static final Map TYPES_BY_DESC; private FieldType(int token, String name) { - this(token, name, null); + this(token, name, null, null); } - private FieldType(int token, String name, Object defaultValue) { + private FieldType(int token, String name, Object defaultValue, String typeDesc) { this.token = (byte) token; this.name = name; this.array = name.startsWith("[L"); this.nullableArray = this.array && name().startsWith("N"); this.defaultValue = defaultValue; + this.typeDesc = typeDesc; } static { TYPES_BY_NAME = new HashMap(); + TYPES_BY_DESC = new HashMap(); for (FieldType type : values()) { TYPES_BY_TOKEN[type.token & 0xff] = type; TYPES_BY_NAME.put(type.name, type); + TYPES_BY_DESC.put(type.typeDesc, type); if (type.isArray()) { // This will fail if our naming becomes inconsistent or a type starts with N. @@ -128,6 +133,14 @@ public static FieldType byName(String name) { return type; } + public static FieldType byTypeDesc(String typeDesc) { + final FieldType type = TYPES_BY_DESC.get(typeDesc); + if (type == null) { + throw new IllegalArgumentException("Bad type description: " + typeDesc); + } + return type; + } + @Override public String toString() { return name; diff --git a/src/main/java/org/lwes/MapEvent.java b/src/main/java/org/lwes/MapEvent.java index 0db5336..4500d04 100644 --- a/src/main/java/org/lwes/MapEvent.java +++ b/src/main/java/org/lwes/MapEvent.java @@ -13,6 +13,8 @@ import java.io.DataOutput; import java.io.IOException; import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; import java.util.Map.Entry; import java.util.SortedSet; import java.util.TreeSet; @@ -23,6 +25,7 @@ import org.lwes.db.EventTemplateDB; import org.lwes.serializer.Deserializer; import org.lwes.serializer.DeserializerState; +import org.lwes.serializer.JsonSerializer; import org.lwes.serializer.Serializer; public class MapEvent extends DefaultEvent { @@ -606,4 +609,16 @@ public FieldType getType(String field) { public int getBytesSize() { return bytesStoreSize; } + + public String json() { + return JsonSerializer.getInstance().json(name, attributes); + } + + public String unTypedJson() { + return JsonSerializer.getInstance().unTypedJson(name, attributes); + } + + public Map getAttributeNameTypeValues(){ + return attributes; + } } diff --git a/src/main/java/org/lwes/TypeValue.java b/src/main/java/org/lwes/TypeValue.java new file mode 100644 index 0000000..5fc0ac8 --- /dev/null +++ b/src/main/java/org/lwes/TypeValue.java @@ -0,0 +1,19 @@ +package org.lwes; + +public class TypeValue { + + private String type; + private Object value; + public String getType() { + return type; + } + public Object getValue() { + return value; + } + public TypeValue(String type, Object value) { + super(); + this.type = type; + this.value = value; + } + +} diff --git a/src/main/java/org/lwes/serializer/JsonDeserializer.java b/src/main/java/org/lwes/serializer/JsonDeserializer.java new file mode 100644 index 0000000..283dc20 --- /dev/null +++ b/src/main/java/org/lwes/serializer/JsonDeserializer.java @@ -0,0 +1,187 @@ +package org.lwes.serializer; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.lwes.Event; +import org.lwes.FieldType; +import org.lwes.TypeValue; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonNull; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +public class JsonDeserializer { + +private static JsonDeserializer instance; + + private JsonParser parser; + + public static JsonDeserializer getInstance(){ + if(instance == null){ + synchronized (JsonSerializer.class) { + //Double-checked locking + if(instance == null) + instance = new JsonDeserializer(); + } + } + return instance; + } + + private JsonDeserializer(){ + parser = new JsonParser(); + } + + public Event fromJson(String json, Event e) throws UnsupportedOperationException{ + try{ + Map typedElems; + JsonObject root = parser.parse(json).getAsJsonObject(); + String name = root.getAsJsonPrimitive("name").getAsString(); + e.setEventName(name); + if(StringUtils.isEmpty(name)) + return null; + JsonObject typedContainer = root.getAsJsonObject("typed"); + JsonObject attributeContainer = root.getAsJsonObject("attributes"); + if(attributeContainer == null && typedContainer == null) + return null; + else if(typedContainer != null){ + typedElems = parseTyped(typedContainer); + for(Entry element : typedElems.entrySet()){ + TypeValue tv = element.getValue(); + FieldType ft = FieldType.byTypeDesc(tv.getType()); + if (ft==null) + continue; + + if(tv.getValue() instanceof String) + e.set(element.getKey(), + ft,getObjectForType(ft, (String)tv.getValue(), null)); + else if (tv.getValue() instanceof String[]) + e.set(element.getKey(), ft, getObjectForType(ft, null, (String[])tv.getValue())); + } + }else + throw new UnsupportedOperationException("Cannot construct the event without the type information for attributes."); + + }catch(Exception ex){ + if (ex instanceof UnsupportedOperationException) + throw (UnsupportedOperationException)ex; + else + return null; + } + return e; + } + + Map parseTyped(JsonObject typedContainer){ + Set> typedElements = typedContainer.entrySet(); + Map typedValues = new HashMap(); + for(Entry element : typedElements){ + String key = element.getKey(); + if(key==null || element.getValue()==null) + continue; + JsonObject tv = (JsonObject)element.getValue(); + String type = tv.get("type").getAsString(); + JsonElement jsonValue = tv.get("value"); + + if(jsonValue instanceof JsonArray){ + typedValues.put(element.getKey(), new TypeValue(type, parseJSONArray((JsonArray)jsonValue))); + }else{ + typedValues.put(element.getKey(), new TypeValue(type, jsonValue.getAsString())); + } + } + return typedValues; + } + + private String[] parseJSONArray(JsonArray json){ + String[] strArr = new String[json.size()]; + for(int i=0;i attrs){ + return gson.toJson(typedContainer(eventName, attrs)); + } + + public String unTypedJson(String eventName, Map attrs){ + return gson.toJson(unTypedContainer(eventName, attrs)); + } + + private Map basicContainer(String eventName){ + Map container = new HashMap(); + container.put("name", eventName); + container.put("version", JSON_SERIALIZER_VERSION); + return container; + } + + private Map unTypedContainer(String eventName, Map attrs){ + Map container = basicContainer(eventName); + container.put("attributes", getUnTypedAttributes(eventName, attrs)); + return container; + } + + private Map typedContainer(String eventName, Map attrs){ + Map container = basicContainer(eventName); + container.put("typed", getTypedAttributes(attrs)); + return container; + } + + public Object getTypedAttributes(Map attrs) { + Map typedAttrs = new HashMap(); + for(Entry attr : attrs.entrySet()) + typedAttrs.put(attr.getKey(), new TypeValue(attr.getValue().getType().typeDesc, attr.getValue().stringyfy())); + + return typedAttrs; + } + + public Object getUnTypedAttributes(String eventName, Map attributes) { + Map unTypedAttributes = new HashMap(); + unTypedAttributes.put("EventName", eventName); + for(Entry attr : attributes.entrySet()) + unTypedAttributes.put(attr.getKey(),attr.getValue().getTypeObject()); + + return unTypedAttributes; + } +} diff --git a/src/main/java/org/lwes/serializer/StringConverter.java b/src/main/java/org/lwes/serializer/StringConverter.java new file mode 100644 index 0000000..baa7520 --- /dev/null +++ b/src/main/java/org/lwes/serializer/StringConverter.java @@ -0,0 +1,69 @@ +package org.lwes.serializer; + +public class StringConverter { + + public static String[] strArray(T[] arr){ + String[] sArr = new String[arr.length]; + for(int i=0; i