All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.bitsensor.lib.entity.util.ProtoUtils Maven / Gradle / Ivy

There is a newer version: 4.11.0
Show newest version
package io.bitsensor.lib.entity.util;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.bitsensor.lib.entity.proto.Detection;
import io.bitsensor.lib.entity.proto.DetectionOrBuilder;
import io.bitsensor.lib.entity.proto.Error;
import io.bitsensor.lib.entity.proto.ErrorOrBuilder;
import io.bitsensor.lib.jackson.protobuf.ProtobufDeserializer;
import io.bitsensor.lib.util.exception.DataModelException;
import io.bitsensor.proto.shaded.com.google.protobuf.InvalidProtocolBufferException;
import io.bitsensor.proto.shaded.com.google.protobuf.MessageOrBuilder;
import io.bitsensor.proto.shaded.com.google.protobuf.util.JsonFormat;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.hash.MurmurHash3;

import java.io.IOException;
import java.util.List;

import static io.bitsensor.lib.entity.Constants.*;
import static io.bitsensor.lib.entity.Constants.Detection.DETECTION_RULE_FIELDS;
import static io.bitsensor.lib.jackson.JacksonConfig.objectMapper;
import static io.bitsensor.lib.util.InputConverter.unflatten;
import static java.util.Arrays.asList;

import io.bitsensor.lib.entity.proto.Error;


/**
 * Utility class for working with proto messages.
 */
public class ProtoUtils {

    /**
     * Fields to exclude when unflattening object.
     * 

* This is necessary for converting json string into protobuf message as message can have nested messages. */ public static final String[] UNFLATTEN_EXCLUDED_FIELDS = {CONTEXT, ENDPOINT, META, INPUT, NON_COMPLIANCE}; private static final ObjectMapper mapper = objectMapper(); public static String getValueForKey(String key, JsonObject dataPoint) { //Get type, typically Context, Endpoint, eg. and update key accordingly String type, path; try { type = key.split("\\.")[0]; path = key.substring(type.length() + 1); } catch (Exception e) { throw new IllegalArgumentException(); } try { return dataPoint.get(type).getAsJsonObject() .get(path).getAsString(); } catch (NullPointerException | IllegalStateException notInDataPointException) { throw new DataModelException(notInDataPointException); } } /** * Returns json string converted from a proto message. * * @param object a proto message * @return json string * @throws DataModelException when a protocol message being parsed is invalid in some way */ public static String proto2String(MessageOrBuilder object) { try { return JsonFormat.printer() .includingDefaultValueFields() .omittingInsignificantWhitespace() .preservingProtoFieldNames() .print(object); } catch (InvalidProtocolBufferException e) { throw new DataModelException("Unable to print MessageOrBuilder object", e); } } /** * Returns json object converted from a proto message. * * @param object a proto message * @return json object * @throws DataModelException when a protocol message being parsed is invalid in some way */ public static JsonObject proto2Json(MessageOrBuilder object) { return new JsonParser().parse(proto2String(object)).getAsJsonObject(); } /** * Returns json object without hashes properties converted from a proto message. * * @param object a proto message * @return json object * @throws DataModelException when a protocol message being parsed is invalid in some way */ public static JsonObject proto2JsonWithoutHashes(MessageOrBuilder object) { JsonObject json = new JsonParser().parse(proto2String(object)).getAsJsonObject(); json.remove("hash"); json.remove("ruleHash"); return json; } /** * Returns json string compatible with elasticsearch converted from a proto message. * * @param object a proto message * @return json string * @throws DataModelException when a protocol message being parsed is invalid in some way */ public static String proto2EsDocument(MessageOrBuilder object) { return unflatten(proto2String(object)).toString(); } /** * Returns a JSON deserialized java object from a given json element. */ public static T convert(JsonElement element, Class type) { return convert(element.toString(), type); } /** * Returns a JSON deserialized java object from given a json string. */ public static T convert(String json, Class type) { try { return mapper.readValue(json, type); } catch (IOException e) { throw new DataModelException("Unable to parse Datapoint from json '" + json + "'", e); } } /** * Returns a proto-compatible json object used for deserializing proto message. * * @see ProtobufDeserializer */ public static JsonObject toProtoJson(String json, String... exludedFields) { JsonObject object = unflatten(json, exludedFields); // Filter out null entry from maps object.entrySet().stream() .filter(entry -> entry.getValue().isJsonObject()) .map(entry -> entry.getValue().getAsJsonObject()) .forEach(map -> map.entrySet() .removeIf(entry -> entry.getValue() == JsonNull.INSTANCE)); return object; } /** * Returns instance of {@code ErrorOrBuilder} with generated hash. */ @SuppressWarnings("unchecked") public static T generateHash(T object) { if (object instanceof Error.Builder) { return (T) ((Error.Builder) object).setHash(createHash(object)); } else if (object instanceof Error) { return (T) generateHash(((Error) object).toBuilder()).build(); } return object; } /** * Returns instance of {@code DetectionOrBuilder} with generated hash. */ @SuppressWarnings("unchecked") public static T generateHash(T object) { if (object instanceof Detection.Builder) { return (T) ((Detection.Builder) object).setHash(createHash(object)); } else if (object instanceof Detection) { return (T) generateHash(((Detection) object).toBuilder()).build(); } return object; } /** * Returns instance of {@code DetectionOrBuilder} with generated rule hash. */ @SuppressWarnings("unchecked") public static T generateRuleHash(T object) { if (object.getRuleHash() != 0) { return object; } if (object instanceof Detection.Builder) { return (T) ((Detection.Builder) object).setRuleHash(createHash(object, DETECTION_RULE_FIELDS)); } else if (object instanceof Detection) { return (T) generateRuleHash(((Detection) object).toBuilder()).build(); } return object; } /** * Returns hash for given message for fields in the {@code onlyFields} array or for all fields if the array is * empty. */ private static long createHash(MessageOrBuilder message, String... onlyFields) { JsonObject json = proto2JsonWithoutHashes(message); final List onlyFieldsList = asList(onlyFields); if (onlyFields.length > 0) json.entrySet().removeIf(entry -> !onlyFieldsList.contains(entry.getKey())); final BytesRef bytes = new BytesRef(json.toString()); return MurmurHash3.hash128(bytes.bytes, bytes.offset, bytes.length, 0, new MurmurHash3.Hash128()).h1; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy