/* * Copyright 2014-2016 CyberVision, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kaaproject.kaa.server.common.core.algorithms; import static org.kaaproject.kaa.server.common.core.algorithms.CommonConstants.KAA_NAMESPACE; import static org.kaaproject.kaa.server.common.core.algorithms.CommonConstants.UUID_FIELD; import static org.kaaproject.kaa.server.common.core.algorithms.CommonConstants.UUID_SIZE; import static org.kaaproject.kaa.server.common.core.algorithms.CommonConstants.UUID_TYPE; import org.apache.avro.JsonProperties; import org.apache.avro.Schema; import org.apache.avro.Schema.Type; import org.apache.avro.generic.GenericData; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.node.ObjectNode; import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; import java.util.Map; import java.util.UUID; public class AvroUtils { private AvroUtils() { } /** * Generates UUID bytes. * * @return list of generated bytes. */ public static byte[] generateUuidBytes() { UUID uuid = UUID.randomUUID(); ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[UUID_SIZE]); byteBuffer.putLong(uuid.getMostSignificantBits()); byteBuffer.putLong(uuid.getLeastSignificantBits()); return byteBuffer.array(); } public static GenericData.Fixed generateUuidObject() { Schema avroSchema = Schema.createFixed(UUID_TYPE, null, KAA_NAMESPACE, UUID_SIZE); return new GenericData.Fixed(avroSchema, generateUuidBytes()); } /** * Returns schema from container (union or schema itself) by its type. * * @param container schema container * @param type schema type * @return schema with a specified type */ public static Schema getSchemaByType(Schema container, Schema.Type type) { if (container.getType().equals(type)) { return container; } if (container.getType().equals(Type.UNION)) { List<Schema> types = container.getTypes(); if (types != null) { for (Schema typeIter : types) { if (typeIter.getType().equals(type)) { return typeIter; } } } } return null; } /** * Returns whether schema is complex. * * @param schema schema * @return true if schema is complex otherwise false */ public static boolean isComplexSchema(Schema schema) { switch (schema.getType()) { case RECORD: case ARRAY: case MAP: case FIXED: case ENUM: return true; default: return false; } } /** * Copies json properties. * * @param src source * @param dst destination */ public static void copyJsonProperties(JsonProperties src, JsonProperties dst) { for (Map.Entry<String, JsonNode> prop : src.getJsonProps().entrySet()) { dst.addProp(prop.getKey(), prop.getValue()); } } public static String injectUuids(String json, Schema schema) throws IOException { return injectUuids(json.getBytes(), schema); } /** * Inject UUID. * * @param content the uuid * @param schema the schema * @return json content tree */ public static String injectUuids(byte[] content, Schema schema) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); JsonNode root = objectMapper.readTree(content); injectUuidsFromJsonNodes(root, schema); return root.toString(); } public static String injectUuids(JsonNode root, Schema schema) { return injectUuidsFromJsonNodes(root, schema).toString(); } private static JsonNode injectUuidsFromJsonNodes(JsonNode json, Schema schema) { if (json == null) { return json; } switch (schema.getType()) { case RECORD: schema.getFields().stream() .filter(f -> !f.name().equals(UUID_FIELD)) .forEach(f -> injectUuidsFromJsonNodes(json.get(f.name()), f.schema())); boolean addressable = schema.getFields().stream().filter(f -> f.name().equals( UUID_FIELD)).findFirst().isPresent(); if (addressable) { ((ObjectNode) json).put(UUID_FIELD, (Integer) null); } break; case UNION: schema.getTypes() .forEach(s -> injectUuidsFromJsonNodes(json.get(s.getName()), s)); break; case ARRAY: json.getElements().forEachRemaining((elem) -> injectUuids(elem, schema.getElementType())); break; default: return json; } return json; } /** * Removes UUIDs from a json tree. * * @param json json tree node */ public static void removeUuids(JsonNode json) { boolean containerWithId = json.isContainerNode() && json.has(UUID_FIELD); boolean isArray = json.isArray(); boolean childIsNotArray = !(json.size() == 1 && json.getElements().next().isArray()); if (containerWithId && !isArray && childIsNotArray) { ((ObjectNode) json).remove(UUID_FIELD); } for (JsonNode node : json) { if (node.isContainerNode()) { removeUuids(node); } } } }