/*
* 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.common.avro;
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericArray;
import org.apache.avro.generic.GenericFixed;
import org.apache.avro.generic.GenericRecord;
import java.util.Collections;
/**
* Class containing algorithms for canonization Avro data.
*/
public class AvroDataCanonizationUtils {
private static final String UUIDT = "org.kaaproject.configuration.uuidT";
private static final AvroDataComparator COMPARATOR = new AvroDataComparator();
private AvroDataCanonizationUtils() {
}
/**
* Performs canonization of records in array if they are present.
*
* @param baseArray the array to be canonized.
*/
private static void canonizeArray(GenericArray baseArray) {
for (Object obj : baseArray) {
if (obj instanceof GenericRecord) {
canonizeRecord((GenericRecord) obj);
} else if (obj instanceof GenericArray) {
canonizeArray((GenericArray) obj);
}
}
}
/**
* Check if the field contains UUID and returns value which should be on its place.
*
* @param uuidField GenericFixed field which is supposed to contain UUID.
* @param fieldSchema Schema of given field.
* @return null if field is assumed as an UUID or field without changes otherwise
*/
private static GenericFixed clearUuid(GenericFixed uuidField, Schema.Field fieldSchema) {
if (fieldSchema.schema().getType() == Schema.Type.UNION) {
for (Schema unionedSchema : fieldSchema.schema().getTypes()) {
if (unionedSchema.getFullName().equalsIgnoreCase(UUIDT)) {
return null;
}
}
} else {
if (uuidField.getSchema().getFullName().equalsIgnoreCase(UUIDT)) {
return null;
}
}
return uuidField;
}
/**
* Recursively removes UUIDs from the record.
*
* @param baseRecord The record containing UUID fields.
*/
public static void removeUuid(GenericRecord baseRecord) {
Schema recordSchema = baseRecord.getSchema();
for (Schema.Field fieldSchema : recordSchema.getFields()) {
if (baseRecord.get(fieldSchema.name()) != null) {
Object field = baseRecord.get(fieldSchema.name());
if (field instanceof GenericFixed) {
baseRecord.put(fieldSchema.name(), clearUuid((GenericFixed) field, fieldSchema));
} else if (field instanceof GenericRecord) {
removeUuid((GenericRecord) field);
} else if (field instanceof GenericArray) {
GenericArray arrayField = (GenericArray) field;
for (Object obj : arrayField) {
if (obj instanceof GenericRecord) {
removeUuid((GenericRecord) obj);
}
}
}
}
}
}
/**
* Performs canonization of the given record.
*
* @param baseRecord The record to be canonized.
*/
public static void canonizeRecord(GenericRecord baseRecord) {
Schema recordSchema = baseRecord.getSchema();
for (Schema.Field fieldSchema : recordSchema.getFields()) {
if (baseRecord.get(fieldSchema.name()) != null) {
Object field = baseRecord.get(fieldSchema.name());
if (field instanceof GenericArray) {
if (fieldSchema.schema().getType() == Schema.Type.UNION) {
for (Schema unoinedSchema : fieldSchema.schema().getTypes()) {
if (unoinedSchema.getType() == Schema.Type.ARRAY) {
COMPARATOR.setSchema(unoinedSchema.getElementType());
break;
}
}
} else {
COMPARATOR.setSchema(fieldSchema.schema().getElementType());
}
GenericArray arrayField = (GenericArray) baseRecord.get(fieldSchema.name());
canonizeArray(arrayField);
Collections.sort(arrayField, COMPARATOR);
} else if (field instanceof GenericRecord) {
canonizeRecord((GenericRecord) field);
}
}
}
}
}