/*
* Copyright 2014-2015 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.avro.ui.converter;
/*
* Copyright 2014-2015 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.
*/
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.avro.Schema;
import org.apache.avro.Schema.Field;
import org.apache.avro.Schema.Type;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericData.Record;
import org.apache.avro.generic.GenericData.StringType;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.generic.GenericRecordBuilder;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.node.ArrayNode;
import org.codehaus.jackson.node.BooleanNode;
import org.codehaus.jackson.node.DoubleNode;
import org.codehaus.jackson.node.IntNode;
import org.codehaus.jackson.node.JsonNodeFactory;
import org.codehaus.jackson.node.LongNode;
import org.codehaus.jackson.node.ObjectNode;
import org.codehaus.jackson.node.TextNode;
import org.kaaproject.avro.ui.shared.Base64Utils;
import org.kaaproject.avro.ui.shared.FieldType;
import org.kaaproject.avro.ui.shared.FormField;
import org.kaaproject.avro.ui.shared.FormField.FieldAccess;
import org.kaaproject.avro.ui.shared.Fqn;
import org.kaaproject.avro.ui.shared.FqnVersion;
import org.kaaproject.avro.ui.shared.NamesValidator;
import org.kaaproject.avro.ui.shared.RecordField;
/**
* The Class SchemaFormAvroConverter.
*/
public class SchemaFormAvroConverter implements ConverterConstants, SchemaFormConstants {
/** The Constant BASE_SCHEMA_FORM_SCHEMA_FILE. */
private static final String BASE_SCHEMA_FORM_SCHEMA_FILE = "schema-record.avsc";
/** The base schema form schema. */
private static Schema baseSchemaFormSchema;
/**
* Gets the base schema form schema.
*
* @return the base schema form schema
* @throws IOException Signals that an I/O exception has occurred.
*/
protected static Schema getBaseSchemaFormSchema() throws IOException {
if (baseSchemaFormSchema == null) {
baseSchemaFormSchema = new Schema.Parser().parse(Thread.currentThread().getContextClassLoader().
getResourceAsStream(BASE_SCHEMA_FORM_SCHEMA_FILE));
}
return baseSchemaFormSchema;
}
/** The schema form schema. */
private Schema schemaFormSchema;
/** The ctl source. */
private CtlSource ctlSource;
/** The has ctl. */
private boolean hasCtl = false;
/**
* Instantiates a new schema form avro converter.
*
* @throws IOException Signals that an I/O exception has occurred.
*/
public SchemaFormAvroConverter() throws IOException {
this(null);
}
/**
* Instantiates a new schema form avro converter.
*
* @param ctlSource the ctl source
* @throws IOException Signals that an I/O exception has occurred.
*/
public SchemaFormAvroConverter(CtlSource ctlSource) throws IOException {
this.ctlSource = ctlSource;
this.hasCtl = this.ctlSource != null;
this.schemaFormSchema = createConverterSchema();
}
/**
* Gets the empty schema form instance.
*
* @return the empty schema form instance
* @throws IOException Signals that an I/O exception has occurred.
*/
public RecordField getEmptySchemaFormInstance() throws IOException {
RecordField schemaForm = FormAvroConverter.createRecordFieldFromSchema(schemaFormSchema, ctlSource);
schemaForm.finalizeMetadata();
return customizeUiForm(customizeUiFormForCtl(schemaForm));
}
/**
* Creates the schema form from schema.
*
* @param schemaString the schema string
* @return the record field
* @throws IOException Signals that an I/O exception has occurred.
*/
public RecordField createSchemaFormFromSchema(String schemaString) throws IOException {
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(schemaString);
Schema.Parser parser = new Schema.Parser();
Set<Fqn> fqns = null;
if (hasCtl) {
JsonNode dependenciesNode = node.get(DEPENDENCIES);
if (dependenciesNode != null && dependenciesNode.isArray()) {
Map<String,Schema> types = new HashMap<>();
fqns = new HashSet<>();
for (int i=0;i<dependenciesNode.size();i++) {
JsonNode dependencyNode = dependenciesNode.get(i);
Fqn fqn = new Fqn(dependencyNode.get(FQN).asText());
types.put(fqn.getFqnString(), Schema.createRecord(fqn.getName(), null, fqn.getNamespace(), false));
fqns.add(fqn);
}
parser.addTypes(types);
}
}
Schema schema = parser.parse(schemaString);
return createSchemaFormFromSchema(schema, fqns);
}
/**
* Creates the schema form from schema.
*
* @param schema the schema
* @return the record field
* @throws IOException Signals that an I/O exception has occurred.
*/
public RecordField createSchemaFormFromSchema(Schema schema) throws IOException {
return createSchemaFormFromSchema(schema, null);
}
/**
* Creates the schema form from schema.
*
* @param schema the schema
* @param fqns the fqns
* @return the record field
* @throws IOException Signals that an I/O exception has occurred.
*/
public RecordField createSchemaFormFromSchema(Schema schema, Set<Fqn> fqns) throws IOException {
String namespace = "";
if (schema.getType() == Schema.Type.RECORD) {
namespace = schema.getNamespace();
}
GenericRecord record = (GenericRecord) createTypeFromSchema(schema, fqns, true, namespace);
RecordField recordField = FormAvroConverter.createRecordFieldFromGenericRecord(record, ctlSource);
customizeUiForm(customizeUiFormForCtl(recordField));
return recordField;
}
/**
* Creates the schema from schema form.
*
* @param field the field
* @return the schema
* @throws IOException Signals that an I/O exception has occurred.
* @throws ParseException the parse exception
*/
public Schema createSchemaFromSchemaForm(RecordField field) throws IOException, ParseException {
field.orderSchemaTypes();
GenericRecord record = FormAvroConverter.createGenericRecordFromRecordField(field);
Map<Fqn, Schema> namedSchemas = null;
if (hasCtl) {
namedSchemas = new HashMap<>();
List<FqnVersion> dependencies = field.getContext().getCtlDependenciesList();
for (FqnVersion fqnVersion : dependencies) {
Fqn fqn = fqnVersion.getFqn();
Schema emptyRecordSchema = Schema.createRecord(fqnVersion.getName(), null, fqnVersion.getNamespace(), false);
emptyRecordSchema.setFields(Collections.<Field>emptyList());
namedSchemas.put(fqn, emptyRecordSchema);
}
}
String rootNamespace = "";
if (field.getContext().getRootRecord().getDeclaredFqn() != null) {
rootNamespace = field.getContext().getRootRecord().getDeclaredFqn().getNamespace();
}
Schema schema = createFieldSchema(record, namedSchemas, rootNamespace);
return schema;
}
/**
* Creates the schema string.
*
* @param schema the schema
* @param pretty the pretty
* @return the string
* @throws IOException Signals that an I/O exception has occurred.
*/
public static String createSchemaString(Schema schema, boolean pretty) throws IOException {
Schema holderSchema = Schema.createRecord(SchemaFormAvroConverter.class.getSimpleName(),
null, SchemaFormAvroConverter.class.getPackage().getName(), false);
List<Field> fields = new ArrayList<Field>();
JsonNode dependenciesNode = schema.getJsonProp(DEPENDENCIES);
if (dependenciesNode != null && dependenciesNode.isArray()) {
for (int i=0;i<dependenciesNode.size();i++) {
JsonNode dependencyNode = dependenciesNode.get(i);
String fqn = dependencyNode.get(FQN).asText();
Schema fieldType = findType(schema, fqn, null);
if (fieldType != null) {
Field tempField = new Field(fqn.replaceAll("\\.", "_"), fieldType, null, null);
fields.add(tempField);
}
}
}
Field holdedField = new Field(HOLDED_SCHEMA_FIELD, schema, null, null);
fields.add(holdedField);
holderSchema.setFields(fields);
String schemaString = holderSchema.toString();
ObjectMapper mapper = new ObjectMapper();
JsonNode node = mapper.readTree(schemaString);
ArrayNode fieldsNode = (ArrayNode)node.get(FIELDS);
JsonNode fieldNode = fieldsNode.get(fields.size()-1);
JsonNode typeNode = fieldNode.get(TYPE);
if (pretty) {
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(typeNode);
} else {
return mapper.writeValueAsString(typeNode);
}
}
/**
* Find type.
*
* @param schema the schema
* @param fqn the fqn
* @param fqns the fqns
* @return the schema
*/
private static Schema findType(Schema schema, String fqn, Set<String> fqns) {
if (fqns == null) {
fqns = new HashSet<>();
}
Schema type = null;
switch (schema.getType()) {
case ARRAY:
type = findType(schema.getElementType(), fqn, fqns);
break;
case RECORD:
type = findTypeFromRecordSchema(schema, fqn, fqns);
break;
case UNION:
for (Schema schemaType : schema.getTypes()) {
type = findType(schemaType, fqn, fqns);
if (type != null) {
return type;
}
}
break;
default:
break;
}
return type;
}
/**
* Find type from record schema.
*
* @param recordSchema the record schema
* @param fqn the fqn
* @param fqns the fqns
* @return the schema
*/
private static Schema findTypeFromRecordSchema (Schema recordSchema, String fqn, Set<String> fqns) {
if (recordSchema.getFullName().equals(fqn)) {
return recordSchema;
}
if (fqns.contains(recordSchema.getFullName())) {
return null;
} else {
Schema type = null;
fqns.add(recordSchema.getFullName());
for (Field field : recordSchema.getFields()) {
type = findType(field.schema(), fqn, fqns);
if (type != null) {
return type;
}
}
return type;
}
}
/**
* Creates the converter schema.
*
* @return the schema
* @throws IOException Signals that an I/O exception has occurred.
*/
protected Schema createConverterSchema() throws IOException {
Schema initialSchema = getBaseSchemaFormSchema();
Map<String, Schema> recordSchemaMap = new HashMap<>();
return copySchema(initialSchema, recordSchemaMap);
}
/**
* Customize type.
*
* @param record the record
* @param fieldTypeSchema the field type schema
*/
protected void customizeType(Record record, Schema fieldTypeSchema) {
}
/**
* Customize form field.
*
* @param fieldType the field type
* @param field the field
*/
protected void customizeFormField(Record fieldType, Field field) {
}
/**
* Customize field schema.
*
* @param fieldSchema the field schema
* @param fieldType the field type
*/
protected void customizeFieldSchema(Schema fieldSchema, GenericRecord fieldType) {
}
/**
* Customize schema field.
*
* @param avroField the avro field
* @param fieldType the field type
*/
protected void customizeSchemaField(Field avroField, Record fieldType) {
}
/**
* Customize record fields.
*
* @param recordSchema the record schema
* @param fields the fields
*/
protected void customizeRecordFields(Schema recordSchema, List<Field> fields) {
}
/**
* Creates the version field.
*
* @return the field
*/
private Field createVersionField() {
Field versionField = new Field(VERSION, Schema.createUnion(Arrays.asList(
Schema.create(Type.INT), Schema.create(Type.NULL))), null, null);
versionField.addProp(DISPLAY_NAME, "Version");
versionField.addProp(DISPLAY_PROMPT, "Enter type version");
versionField.addProp(TYPE_VERSION, BooleanNode.valueOf(true));
versionField.addProp(FIELD_ACCESS, FieldAccess.HIDDEN.name().toLowerCase());
return versionField;
}
/**
* Creates the dependencies field.
*
* @return the field
*/
private Field createDependenciesField() {
Schema dependencyType = Schema.createRecord(DEPENDENCY_FIELD_TYPE, null, BASE_SCHEMA_FORM_NAMESPACE, false);
Field fqnField = new Field(FQN, Schema.create(Type.STRING), null, null);
Field versionField = new Field(VERSION, Schema.create(Type.INT), null, null);
dependencyType.setFields(Arrays.asList(fqnField, versionField));
Schema dependenciesArray = Schema.createArray(dependencyType);
Field dependenciesField = new Field(DEPENDENCIES, Schema.createUnion(Arrays.asList(
dependenciesArray, Schema.create(Type.NULL))), null, null);
dependenciesField.addProp(DISPLAY_NAME, "Dependencies");
dependenciesField.addProp(TYPE_DEPENDENCIES, BooleanNode.valueOf(true));
dependenciesField.addProp(FIELD_ACCESS, FieldAccess.HIDDEN.name().toLowerCase());
return dependenciesField;
}
/**
* Customize ui form.
*
* @param field the field
* @return the record field
*/
protected RecordField customizeUiForm(RecordField field) {
field.setDisplayName(SCHEMA);
return field;
}
/**
* Customize ui form for ctl.
*
* @param field the field
* @return the record field
*/
private RecordField customizeUiFormForCtl(RecordField field) {
if (hasCtl) {
FormField versionField = field.getFieldByName(VERSION);
if (versionField != null) {
versionField.setFieldAccess(FieldAccess.EDITABLE);
versionField.setOptional(false);
}
FormField dependenciesField = field.getFieldByName(DEPENDENCIES);
if (dependenciesField != null) {
dependenciesField.setFieldAccess(FieldAccess.EDITABLE);
}
}
return field;
}
/**
* Gets the field index.
*
* @param fields the fields
* @param name the name
* @return the field index
*/
protected int getFieldIndex(List<Field> fields, String name) {
int index = -1;
for (int i=0; i<fields.size();i++) {
if (fields.get(i).name().equals(name)) {
index = i;
break;
}
}
return index;
}
/**
* Copy schema.
*
* @param schema the schema
* @param recordSchemaMap the record schema map
* @return the schema
*/
protected Schema copySchema(Schema schema, Map<String, Schema> recordSchemaMap) {
Schema schemaCopy = null;
switch (schema.getType()) {
case ARRAY:
schemaCopy = Schema.createArray(copySchema(schema.getElementType(), recordSchemaMap));
break;
case BOOLEAN:
schemaCopy = Schema.create(Type.BOOLEAN);
break;
case BYTES:
schemaCopy = Schema.create(Type.BYTES);
break;
case DOUBLE:
schemaCopy = Schema.create(Type.DOUBLE);
break;
case ENUM:
schemaCopy = Schema.createEnum(schema.getName(), null,
schema.getNamespace(), schema.getEnumSymbols());
break;
case FIXED:
schemaCopy = Schema.createFixed(schema.getName(), null,
schema.getNamespace(), schema.getFixedSize());
break;
case FLOAT:
schemaCopy = Schema.create(Type.FLOAT);
break;
case INT:
schemaCopy = Schema.create(Type.INT);
break;
case LONG:
schemaCopy = Schema.create(Type.LONG);
break;
case NULL:
schemaCopy = Schema.create(Type.NULL);
break;
case RECORD:
schemaCopy = copyRecordSchema(schema, recordSchemaMap);
break;
case STRING:
schemaCopy = Schema.create(Type.STRING);
break;
case UNION:
List<Schema> types = new ArrayList<>();
for (Schema type : schema.getTypes()) {
types.add(copySchema(type, recordSchemaMap));
}
schemaCopy = Schema.createUnion(types);
break;
default:
throw new UnsupportedOperationException("Unsupported avro type: " + schema.getType());
}
return schemaCopy;
}
/**
* Copy record schema.
*
* @param recordSchema the record schema
* @param recordSchemaMap the record schema map
* @return the schema
*/
private Schema copyRecordSchema(Schema recordSchema, Map<String, Schema> recordSchemaMap) {
if (recordSchemaMap.containsKey(recordSchema.getFullName())) {
return recordSchemaMap.get(recordSchema.getFullName());
} else {
Schema recordSchemaCopy = Schema.createRecord(recordSchema.getName(), null, recordSchema.getNamespace(), false);
recordSchemaMap.put(recordSchemaCopy.getFullName(), recordSchemaCopy);
Map<String, JsonNode> props = recordSchema.getJsonProps();
for (String key : props.keySet()) {
recordSchemaCopy.addProp(key, props.get(key));
}
List<Field> recordFieldsCopy = new ArrayList<>();
for (Field field : recordSchema.getFields()) {
recordFieldsCopy.add(copySchemaField(field, recordSchemaMap));
}
if (hasCtl) {
if (recordSchema.getName().equals(RECORD_FIELD_TYPE)) {
int index = getFieldIndex(recordFieldsCopy, RECORD_NAMESPACE);
if (index > -1) {
recordFieldsCopy.add(index+1, createVersionField());
}
index = getFieldIndex(recordFieldsCopy, FIELDS);
if (index > -1) {
recordFieldsCopy.add(index, createDependenciesField());
}
}
}
customizeRecordFields(recordSchema, recordFieldsCopy);
recordSchemaCopy.setFields(recordFieldsCopy);
return recordSchemaCopy;
}
}
/**
* Copy schema field.
*
* @param field the field
* @param recordSchemaMap the record schema map
* @return the field
*/
private Field copySchemaField(Field field, Map<String, Schema> recordSchemaMap) {
Field fieldCopy = new Field(field.name(), copySchema(field.schema(), recordSchemaMap), null, null);
Map<String, JsonNode> props = field.getJsonProps();
for (String key : props.keySet()) {
fieldCopy.addProp(key, props.get(key));
}
return fieldCopy;
}
/**
* Find type schema.
*
* @param rootSchema the root schema
* @param typeName the type name
* @return the schema
*/
private Schema findTypeSchema(Schema rootSchema, String typeName) {
List<Schema> types = null;
if (rootSchema.getName().equals(RECORD_FIELD_TYPE)) {
types = rootSchema.getField(FIELDS).schema().getElementType().getField(FIELD_TYPE).schema().getTypes();
} else if (rootSchema.getName().equals(UNION_FIELD_TYPE)) {
types = rootSchema.getField(ACCEPTABLE_VALUES).schema().getElementType().getTypes();
} else {
throw new IllegalArgumentException("Ivalid schema form conversion schema: " + rootSchema);
}
for (Schema type : types) {
if (type.getName().equals(typeName)) {
return type;
}
}
throw new IllegalArgumentException("Invalid type name: " + typeName);
}
/**
* Creates the type from schema.
*
* @param schema the schema
* @param namedFqns the named fqns
* @return the record
*/
private Record createTypeFromSchema(Schema schema, Set<Fqn> namedFqns, boolean isRoot, String rootNamespace) {
if (namedFqns == null) {
namedFqns = new HashSet<>();
}
Schema fieldTypeSchema = FormAvroConverter.getFieldTypeSchema(schema);
Type type = fieldTypeSchema.getType();
Record record;
switch (type) {
case STRING:
record = new Record(findTypeSchema(schemaFormSchema, STRING_FIELD_TYPE));
break;
case INT:
record = new Record(findTypeSchema(schemaFormSchema, INTEGER_FIELD_TYPE));
break;
case LONG:
record = new Record(findTypeSchema(schemaFormSchema, LONG_FIELD_TYPE));
break;
case FLOAT:
record = new Record(findTypeSchema(schemaFormSchema, FLOAT_FIELD_TYPE));
break;
case DOUBLE:
record = new Record(findTypeSchema(schemaFormSchema, DOUBLE_FIELD_TYPE));
break;
case BOOLEAN:
record = new Record(findTypeSchema(schemaFormSchema, BOOLEAN_FIELD_TYPE));
break;
case BYTES:
record = new Record(findTypeSchema(schemaFormSchema, BYTES_FIELD_TYPE));
break;
case FIXED:
case ENUM:
case RECORD:
Fqn fqn = new Fqn(fieldTypeSchema.getNamespace(), fieldTypeSchema.getName());
if (namedFqns.contains(fqn)) {
Schema namedReferenceTypeSchema = findTypeSchema(schemaFormSchema, NAMED_REFERENCE_FIELD_TYPE);
record = new Record(namedReferenceTypeSchema);
record.put(FQN, fqn.getFqnString());
} else {
NamesValidator.validateFqnOrThrowException(fqn);
namedFqns.add(fqn);
if (type == Type.FIXED) {
Schema fixedTypeSchema = findTypeSchema(schemaFormSchema, FIXED_FIELD_TYPE);
record = new Record(fixedTypeSchema);
record.put(FIXED_SIZE, fieldTypeSchema.getFixedSize());
} else if (type == Type.ENUM) {
Schema enumTypeSchema = findTypeSchema(schemaFormSchema, ENUM_FIELD_TYPE);
record = new Record(enumTypeSchema);
Field symbolsField = enumTypeSchema.getField(SYMBOLS);
List<String> symbols = fieldTypeSchema.getEnumSymbols();
GenericData.Array<Record> symbolsArray = new GenericData.Array<>(symbols.size(), symbolsField.schema());
Schema enumSymbolSchema = symbolsField.schema().getElementType();
for (String symbol : symbols) {
NamesValidator.validateEnumSymbolOrThrowException(symbol);
Record enumSymbolRecord = new Record(enumSymbolSchema);
enumSymbolRecord.put(SYMBOL, symbol);
symbolsArray.add(enumSymbolRecord);
}
record.put(SYMBOLS, symbolsArray);
} else {
Schema recordTypeSchema = findTypeSchema(schemaFormSchema, RECORD_FIELD_TYPE);
record = new Record(recordTypeSchema);
Field fieldsField = recordTypeSchema.getField(FIELDS);
List<Field> fields = fieldTypeSchema.getFields();
GenericData.Array<Object> fieldsArrayData = new GenericData.Array<>(fields.size(), fieldsField.schema());
Schema fieldSchema = fieldsField.schema().getElementType();
java.util.Set<String> fieldNames = new java.util.HashSet<>();
for (Field field : fields) {
String fieldName = field.name().toLowerCase();
if (!fieldNames.contains(fieldName)) {
fieldNames.add(fieldName);
} else {
throw new IllegalArgumentException("Duplicate field name: " + fieldName);
}
fieldsArrayData.add(createFormFieldFromSchemaField(fieldSchema, field, namedFqns, rootNamespace));
}
record.put(FIELDS, fieldsArrayData);
if (record.getSchema().getField(DISPLAY_NAME) != null) {
JsonNode displayNameNode = fieldTypeSchema.getJsonProp(DISPLAY_NAME);
if (displayNameNode != null && displayNameNode.isTextual()) {
record.put(DISPLAY_NAME, displayNameNode.asText());
}
}
if (record.getSchema().getField(DESCRIPTION) != null) {
JsonNode descriptionNode = fieldTypeSchema.getJsonProp(DESCRIPTION);
if (descriptionNode != null && descriptionNode.isTextual()) {
record.put(DESCRIPTION, descriptionNode.asText());
}
}
if (hasCtl) {
JsonNode versionNode = fieldTypeSchema.getJsonProp(VERSION);
if (versionNode != null && versionNode.isInt()) {
record.put(VERSION, versionNode.asInt());
}
JsonNode dependenciesNode = fieldTypeSchema.getJsonProp(DEPENDENCIES);
if (dependenciesNode != null && dependenciesNode.isArray()) {
Field dependenciesField = recordTypeSchema.getField(DEPENDENCIES);
Schema dependenciesFieldSchema = dependenciesField.schema();
int index = dependenciesFieldSchema.getIndexNamed(FieldType.ARRAY.getName());
Schema dependenciesSchema = dependenciesFieldSchema.getTypes().get(index);
GenericData.Array<Record> dependenciesArrayData =
new GenericData.Array<>(dependenciesNode.size(), dependenciesSchema);
Schema dependencySchema = dependenciesSchema.getElementType();
for (int i=0; i<dependenciesNode.size();i++) {
JsonNode dependencyNode = dependenciesNode.get(i);
GenericRecordBuilder builder = new GenericRecordBuilder(dependencySchema);
Field field = dependencySchema.getField(FQN);
builder.set(field, dependencyNode.get(FQN).asText());
field = dependencySchema.getField(VERSION);
builder.set(field, dependencyNode.get(VERSION).asInt());
dependenciesArrayData.add(builder.build());
}
record.put(DEPENDENCIES, dependenciesArrayData);
}
}
}
record.put(RECORD_NAME, fieldTypeSchema.getName());
String namespace = fieldTypeSchema.getNamespace();
if (!isRoot && rootNamespace.equals(namespace)) {
namespace = null;
}
record.put(RECORD_NAMESPACE, namespace);
}
break;
case ARRAY:
Schema arrayTypeSchema = findTypeSchema(schemaFormSchema, ARRAY_FIELD_TYPE);
record = new Record(arrayTypeSchema);
Record arrayItemRecord = createTypeFromSchema(fieldTypeSchema.getElementType(), namedFqns, false, rootNamespace);
record.put(ARRAY_ITEM, arrayItemRecord);
break;
case UNION:
Schema unionTypeSchema = findTypeSchema(schemaFormSchema, UNION_FIELD_TYPE);
record = new Record(unionTypeSchema);
Field acceptableValuesField = unionTypeSchema.getField(ACCEPTABLE_VALUES);
List<Schema> types = fieldTypeSchema.getTypes();
GenericData.Array<Record> acceptableValuesArrayData = new GenericData.Array<>(types.size(), acceptableValuesField.schema());
for (Schema typeSchema : types) {
if (typeSchema.getType() != Schema.Type.NULL) {
Record fieldTypeRecord = createTypeFromSchema(typeSchema, namedFqns, false, rootNamespace);
acceptableValuesArrayData.add(fieldTypeRecord);
}
}
record.put(ACCEPTABLE_VALUES, acceptableValuesArrayData);
break;
case NULL:
record = null;
break;
default:
throw new UnsupportedOperationException("Unsupported avro field type: " + type);
}
customizeType(record, fieldTypeSchema);
return record;
}
/**
* Creates the form field from schema field.
*
* @param recordTypeFieldSchema the record type field schema
* @param field the field
* @param namedFqns the named fqns
* @return the record
*/
private Record createFormFieldFromSchemaField(Schema recordTypeFieldSchema, Field field, Set<Fqn> namedFqns, String rootNamespace) {
Record fieldRecord = new Record(recordTypeFieldSchema);
Schema fieldSchema = field.schema();
if (fieldRecord.getSchema().getField(OPTIONAL) != null) {
fieldRecord.put(OPTIONAL, FormAvroConverter.isNullTypeSchema(fieldSchema));
}
if (fieldRecord.getSchema().getField(FIELD_NAME) != null) {
fieldRecord.put(FIELD_NAME, field.name());
}
if (fieldRecord.getSchema().getField(DISPLAY_NAME) != null) {
JsonNode displayNameNode = field.getJsonProp(DISPLAY_NAME);
if (displayNameNode != null && displayNameNode.isTextual()) {
fieldRecord.put(DISPLAY_NAME, displayNameNode.asText());
}
}
if (fieldRecord.getSchema().getField(DESCRIPTION) != null) {
JsonNode descriptionNode = field.getJsonProp(DESCRIPTION);
if (descriptionNode != null && descriptionNode.isTextual()) {
fieldRecord.put(DESCRIPTION, descriptionNode.asText());
}
}
if (fieldRecord.getSchema().getField(DISPLAY_PROMPT) != null) {
JsonNode displayPromptNode = field.getJsonProp(DISPLAY_PROMPT);
if (displayPromptNode != null && displayPromptNode.isTextual()) {
fieldRecord.put(DISPLAY_PROMPT, displayPromptNode.asText());
}
}
if (fieldRecord.getSchema().getField(WEIGHT) != null) {
JsonNode weightNode = field.getJsonProp(WEIGHT);
if (weightNode != null && weightNode.isFloatingPointNumber()) {
fieldRecord.put(WEIGHT, new Float(weightNode.asDouble()));
}
}
if (fieldRecord.getSchema().getField(KEY_INDEX) != null) {
JsonNode keyIndexNode = field.getJsonProp(KEY_INDEX);
if (keyIndexNode != null && keyIndexNode.isInt()) {
fieldRecord.put(KEY_INDEX, keyIndexNode.asInt());
}
}
Record fieldType = createTypeFromSchema(field.schema(), namedFqns, false, rootNamespace);
if (fieldType.getSchema().getField(DEFAULT_VALUE) != null) {
JsonNode defaultValueNode = field.getJsonProp(BY_DEFAULT);
if (defaultValueNode != null) {
setDefaultValueFromJsonNode(fieldType, defaultValueNode);
}
}
String fieldTypeName = fieldType.getSchema().getName();
if (fieldTypeName.equals(STRING_FIELD_TYPE)) {
if (fieldType.getSchema().getField(MAX_LENGTH) != null) {
JsonNode maxLengthNode = field.getJsonProp(MAX_LENGTH);
if (maxLengthNode != null && maxLengthNode.isInt()) {
fieldType.put(MAX_LENGTH, maxLengthNode.asInt());
}
}
if (fieldType.getSchema().getField(INPUT_TYPE) != null) {
JsonNode inputTypeNode = field.getJsonProp(INPUT_TYPE);
if (inputTypeNode != null && inputTypeNode.isTextual()) {
Schema inputTypeSchema = fieldType.getSchema().getField(INPUT_TYPE).schema();
fieldType.put(INPUT_TYPE,
new GenericData.EnumSymbol(inputTypeSchema, inputTypeNode.asText().toUpperCase()));
}
}
} else if (fieldTypeName.equals(ENUM_FIELD_TYPE)) {
JsonNode displayNamesNode = field.getJsonProp(DISPLAY_NAMES);
@SuppressWarnings("unchecked")
GenericData.Array<Record> genericArrayData =
(GenericData.Array<Record>) fieldType.get(SYMBOLS);
if (displayNamesNode != null && displayNamesNode.isArray() &&
displayNamesNode.size() == genericArrayData.size()) {
for (int i=0; i<genericArrayData.size();i++) {
if (genericArrayData.get(i).getSchema().getField(DISPLAY_NAME) != null) {
String displayName = displayNamesNode.get(i).asText();
genericArrayData.get(i).put(DISPLAY_NAME, displayName);
}
}
}
} else if (fieldTypeName.equals(ARRAY_FIELD_TYPE)) {
if (fieldType.getSchema().getField(MIN_ROW_COUNT) != null) {
JsonNode minRowCountNode = field.getJsonProp(MIN_ROW_COUNT);
if (minRowCountNode != null && minRowCountNode.isInt()) {
fieldType.put(MIN_ROW_COUNT, minRowCountNode.asInt());
}
}
}
customizeFormField(fieldType, field);
fieldRecord.put(FIELD_TYPE, fieldType);
return fieldRecord;
}
/**
* Sets the default value from json node.
*
* @param fieldType the field type
* @param defaultValueNode the default value node
*/
private static void setDefaultValueFromJsonNode(Record fieldType, JsonNode defaultValueNode) {
if (fieldType.getSchema().getName().equals(STRING_FIELD_TYPE)) {
if (defaultValueNode.isTextual()) {
fieldType.put(DEFAULT_VALUE, defaultValueNode.asText());
}
} else if (fieldType.getSchema().getName().equals(INTEGER_FIELD_TYPE)) {
if (defaultValueNode.isNumber()) {
fieldType.put(DEFAULT_VALUE, defaultValueNode.asInt());
}
} else if (fieldType.getSchema().getName().equals(LONG_FIELD_TYPE)) {
if (defaultValueNode.isNumber()) {
fieldType.put(DEFAULT_VALUE, defaultValueNode.asLong());
}
} else if (fieldType.getSchema().getName().equals(FLOAT_FIELD_TYPE)) {
if (defaultValueNode.isFloatingPointNumber()) {
fieldType.put(DEFAULT_VALUE, new Float(defaultValueNode.asDouble()));
}
} else if (fieldType.getSchema().getName().equals(DOUBLE_FIELD_TYPE)) {
if (defaultValueNode.isFloatingPointNumber()) {
fieldType.put(DEFAULT_VALUE, defaultValueNode.asDouble());
}
} else if (fieldType.getSchema().getName().equals(BOOLEAN_FIELD_TYPE)) {
if (defaultValueNode.isBoolean()) {
fieldType.put(DEFAULT_VALUE, defaultValueNode.asBoolean());
}
} else if (fieldType.getSchema().getName().equals(BYTES_FIELD_TYPE)) {
String val = parseBytesJsonValue(defaultValueNode);
fieldType.put(DEFAULT_VALUE, val);
} else if (fieldType.getSchema().getName().equals(FIXED_FIELD_TYPE)) {
String val = parseBytesJsonValue(defaultValueNode);
fieldType.put(DEFAULT_VALUE, val);
} else if (fieldType.getSchema().getName().equals(ENUM_FIELD_TYPE)) {
if (defaultValueNode.isTextual()) {
fieldType.put(DEFAULT_VALUE, defaultValueNode.asText());
}
} else if (fieldType.getSchema().getName().equals(UNION_FIELD_TYPE)) {
if (defaultValueNode != null) {
@SuppressWarnings("unchecked")
GenericData.Array<Record> acceptableValuesArray =
(GenericData.Array<Record>) fieldType.get(ACCEPTABLE_VALUES);
Object val = convertUnionDefaultValueFromJson(acceptableValuesArray, defaultValueNode);
fieldType.put(DEFAULT_VALUE, val);
}
}
}
/**
* Parses the bytes json value.
*
* @param jsonValue the json value
* @return the string
*/
private static String parseBytesJsonValue(JsonNode jsonValue) {
if (jsonValue.isTextual() || jsonValue.isBinary()) {
return jsonValue.asText();
} else if (jsonValue.isArray()) {
byte[] data = new byte[jsonValue.size()];
for (int i=0;i<jsonValue.size();i++) {
int val = jsonValue.get(i).asInt();
data[i] = (byte) val;
}
return Base64Utils.toBase64(data);
} else {
return null;
}
}
/**
* Convert union default value from json.
*
* @param acceptableValuesArray the acceptable values array
* @param jsonValue the json value
* @return the record
*/
private static Record convertUnionDefaultValueFromJson(GenericData.Array<Record> acceptableValuesArray, JsonNode jsonValue) {
if (jsonValue == null) {
return null;
}
for (Record type : acceptableValuesArray) {
if (matchesType(type, jsonValue)) {
if (type.getSchema().getName().equals(ENUM_FIELD_TYPE)) {
String val = jsonValue.asText();
@SuppressWarnings("unchecked")
GenericData.Array<Record> symbolsArray = (GenericData.Array<Record>) type.get(SYMBOLS);
boolean found = false;
for (Record enumSymbol : symbolsArray) {
String symbol = (String) enumSymbol.get(SYMBOL);
if (symbol.equals(val)) {
found = true;
break;
}
}
if (!found) {
continue;
}
}
if (type.getSchema().getField(DEFAULT_VALUE) != null) {
setDefaultValueFromJsonNode(type, jsonValue);
}
return type;
}
}
return null;
}
/**
* Matches type.
*
* @param type the type
* @param jsonValue the json value
* @return true, if successful
*/
private static boolean matchesType(Record type, JsonNode jsonValue) {
if (type.getSchema().getName().equals(BOOLEAN_FIELD_TYPE)) {
return jsonValue.isBoolean();
} else if (type.getSchema().getName().equals(INTEGER_FIELD_TYPE)) {
return jsonValue.isInt();
} else if (type.getSchema().getName().equals(LONG_FIELD_TYPE)) {
return jsonValue.isIntegralNumber();
} else if (type.getSchema().getName().equals(FLOAT_FIELD_TYPE)) {
return jsonValue.isDouble();
} else if (type.getSchema().getName().equals(DOUBLE_FIELD_TYPE)) {
return jsonValue.isFloatingPointNumber();
} else if (type.getSchema().getName().equals(STRING_FIELD_TYPE) ||
type.getSchema().getName().equals(ENUM_FIELD_TYPE)) {
return jsonValue.isTextual();
} else if (type.getSchema().getName().equals(BYTES_FIELD_TYPE) ||
type.getSchema().getName().equals(FIXED_FIELD_TYPE)) {
return jsonValue.isBinary() || jsonValue.isArray();
} else {
return false;
}
}
/**
* Creates the field schema.
*
* @param fieldType the field type
* @param namedSchemas the named schemas
* @param rootNamespace the root namespace
* @return the schema
* @throws ParseException the parse exception
*/
private Schema createFieldSchema(GenericRecord fieldType, Map<Fqn, Schema> namedSchemas, String rootNamespace) throws ParseException {
if (namedSchemas == null) {
namedSchemas = new HashMap<>();
}
Schema fieldSchema = null;
String fieldTypeName = null;
if (fieldType != null) {
fieldTypeName = fieldType.getSchema().getName();
}
if (fieldTypeName == null) {
fieldSchema = Schema.create(Type.NULL);
} else if (fieldTypeName.equals(STRING_FIELD_TYPE)) {
fieldSchema = Schema.create(Type.STRING);
GenericData.setStringType(fieldSchema, StringType.String);
} else if (fieldTypeName.equals(INTEGER_FIELD_TYPE)) {
fieldSchema = Schema.create(Type.INT);
} else if (fieldTypeName.equals(LONG_FIELD_TYPE)) {
fieldSchema = Schema.create(Type.LONG);
} else if (fieldTypeName.equals(FLOAT_FIELD_TYPE)) {
fieldSchema = Schema.create(Type.FLOAT);
} else if (fieldTypeName.equals(DOUBLE_FIELD_TYPE)) {
fieldSchema = Schema.create(Type.DOUBLE);
} else if (fieldTypeName.equals(BOOLEAN_FIELD_TYPE)) {
fieldSchema = Schema.create(Type.BOOLEAN);
} else if (fieldTypeName.equals(BYTES_FIELD_TYPE)) {
fieldSchema = Schema.create(Type.BYTES);
} else if (fieldTypeName.equals(FIXED_FIELD_TYPE) ||
fieldTypeName.equals(ENUM_FIELD_TYPE) ||
fieldTypeName.equals(RECORD_FIELD_TYPE)) {
String recordNamespace = (String) fieldType.get(RECORD_NAMESPACE);
if (recordNamespace == null || recordNamespace.isEmpty()) {
recordNamespace = rootNamespace;
}
String recordName = (String) fieldType.get(RECORD_NAME);
Fqn fqn = new Fqn(recordNamespace, recordName);
NamesValidator.validateFqnOrThrowException(fqn);
if (fieldTypeName.equals(FIXED_FIELD_TYPE)) {
int fixedSize = (int) fieldType.get(FIXED_SIZE);
fieldSchema = Schema.createFixed(recordName, null,
recordNamespace, fixedSize);
namedSchemas.put(fqn, fieldSchema);
} else if (fieldTypeName.equals(ENUM_FIELD_TYPE)) {
@SuppressWarnings("unchecked")
GenericData.Array<Record> symbolsArray = (GenericData.Array<Record>) fieldType.get(SYMBOLS);
List<String> values = new ArrayList<>();
for (Record symbol : symbolsArray) {
String enumSymbol = (String)symbol.get(SYMBOL);
NamesValidator.validateEnumSymbolOrThrowException(enumSymbol);
values.add(enumSymbol);
}
fieldSchema = Schema.createEnum(recordName, null,
recordNamespace, values);
namedSchemas.put(fqn, fieldSchema);
} else if (fieldTypeName.equals(RECORD_FIELD_TYPE)) {
fieldSchema = Schema.createRecord(recordName, null, recordNamespace, false);
namedSchemas.put(fqn, fieldSchema);
if (hasCtl) {
Integer version = (Integer) fieldType.get(VERSION);
if (version != null) {
fieldSchema.addProp(VERSION, IntNode.valueOf(version));
}
@SuppressWarnings("unchecked")
GenericData.Array<Record> dependenciesArray = (GenericData.Array<Record>) fieldType.get(DEPENDENCIES);
if (dependenciesArray != null) {
JsonNodeFactory jsonFactory = JsonNodeFactory.instance;
ArrayNode dependenciesNode = jsonFactory.arrayNode();
for (Record dependency : dependenciesArray) {
String dependencyFqn = (String) dependency.get(FQN);
Integer dependencyVersion = (Integer) dependency.get(VERSION);
ObjectNode dependencyNode = jsonFactory.objectNode();
dependencyNode.put(FQN, dependencyFqn);
dependencyNode.put(VERSION, dependencyVersion);
dependenciesNode.add(dependencyNode);
}
fieldSchema.addProp(DEPENDENCIES, dependenciesNode);
}
}
String displayName = (String) fieldType.get(DISPLAY_NAME);
if (displayName != null) {
fieldSchema.addProp(DISPLAY_NAME, displayName);
}
String description = (String) fieldType.get(DESCRIPTION);
if (description != null) {
fieldSchema.addProp(DESCRIPTION, description);
}
@SuppressWarnings("unchecked")
GenericData.Array<Record> fieldsArray = (GenericData.Array<Record>)fieldType.get(FIELDS);
List<Field> recordFields = new ArrayList<Field>();
if (fieldsArray != null) {
for (Record field : fieldsArray) {
recordFields.add(createSchemaFieldFromForm(field, namedSchemas, rootNamespace));
}
}
fieldSchema.setFields(recordFields);
}
} else if (fieldTypeName.equals(NAMED_REFERENCE_FIELD_TYPE)) {
Fqn fqn = new Fqn((String) fieldType.get(FQN));
fieldSchema = namedSchemas.get(fqn);
if (fieldSchema == null) {
throw new IllegalArgumentException("Type with FQN '" +
fqn + "' is not defined in schema.");
}
} else if (fieldTypeName.equals(ARRAY_FIELD_TYPE)) {
Record arrayItem = (Record) fieldType.get(ARRAY_ITEM);
Schema elementTypeSchema = createFieldSchema(arrayItem, namedSchemas, rootNamespace);
fieldSchema = Schema.createArray(elementTypeSchema);
} else if (fieldTypeName.equals(UNION_FIELD_TYPE)) {
List<Schema> unionTypes = new ArrayList<>();
@SuppressWarnings("unchecked")
GenericData.Array<Record> acceptableValuesArray =
(GenericData.Array<Record>)fieldType.get(ACCEPTABLE_VALUES);
for (Record acceptableValue : acceptableValuesArray) {
unionTypes.add(createFieldSchema(acceptableValue, namedSchemas, rootNamespace));
}
fieldSchema = Schema.createUnion(unionTypes);
}
customizeFieldSchema(fieldSchema, fieldType);
return fieldSchema;
}
/**
* Creates the schema field from form.
*
* @param field the field
* @param recordSchemas the record schemas
* @return the field
* @throws ParseException the parse exception
*/
private Field createSchemaFieldFromForm(Record field, Map<Fqn, Schema> recordSchemas, String rootNamespace) throws ParseException {
Record fieldType = (Record)field.get(FIELD_TYPE);
Schema fieldSchema = createFieldSchema(fieldType, recordSchemas, rootNamespace);
Boolean optional = (Boolean)field.get(OPTIONAL);
if (optional != null && optional &&
!FormAvroConverter.isNullTypeSchema(fieldSchema)) {
if (fieldSchema.getType() == Type.UNION) {
List<Schema> unionTypes = fieldSchema.getTypes();
unionTypes = new ArrayList<>(unionTypes);
unionTypes.add(Schema.create(Type.NULL));
fieldSchema = Schema.createUnion(unionTypes);
} else {
fieldSchema = Schema.createUnion(Arrays.asList(fieldSchema, Schema.create(Type.NULL)));
}
}
String fieldName = (String)field.get(FIELD_NAME);
Field avroField = new Field(fieldName, fieldSchema, null, null);
String displayName = (String)field.get(DISPLAY_NAME);
if (displayName != null) {
avroField.addProp(DISPLAY_NAME, displayName);
}
String displayPrompt = (String)field.get(DISPLAY_PROMPT);
if (displayPrompt != null) {
avroField.addProp(DISPLAY_PROMPT, displayPrompt);
}
Float weight = (Float)field.get(WEIGHT);
if (weight != null) {
avroField.addProp(WEIGHT, DoubleNode.valueOf(weight));
}
Integer keyIndex = (Integer)field.get(KEY_INDEX);
if (keyIndex != null) {
avroField.addProp(KEY_INDEX, IntNode.valueOf(keyIndex));
}
setDefaultValueFromFieldType(avroField, fieldType);
if (fieldType.getSchema().getName().equals(STRING_FIELD_TYPE)) {
Integer maxLength = (Integer)fieldType.get(MAX_LENGTH);
if (maxLength != null) {
avroField.addProp(MAX_LENGTH, IntNode.valueOf(maxLength));
}
GenericData.EnumSymbol inputType =
(GenericData.EnumSymbol)fieldType.get(INPUT_TYPE);
if (inputType != null) {
avroField.addProp(INPUT_TYPE, inputType.toString().toLowerCase());
}
} else if (fieldType.getSchema().getName().equals(INTEGER_FIELD_TYPE)) {
Integer maxLength = (Integer)fieldType.get(MAX_LENGTH);
if (maxLength != null) {
avroField.addProp(MAX_LENGTH, IntNode.valueOf(maxLength));
}
} else if (fieldType.getSchema().getName().equals(LONG_FIELD_TYPE)) {
Integer maxLength = (Integer)fieldType.get(MAX_LENGTH);
if (maxLength != null) {
avroField.addProp(MAX_LENGTH, IntNode.valueOf(maxLength));
}
} else if (fieldType.getSchema().getName().equals(FLOAT_FIELD_TYPE)) {
Integer maxLength = (Integer)fieldType.get(MAX_LENGTH);
if (maxLength != null) {
avroField.addProp(MAX_LENGTH, IntNode.valueOf(maxLength));
}
} else if (fieldType.getSchema().getName().equals(DOUBLE_FIELD_TYPE)) {
Integer maxLength = (Integer)fieldType.get(MAX_LENGTH);
if (maxLength != null) {
avroField.addProp(MAX_LENGTH, IntNode.valueOf(maxLength));
}
} else if (fieldType.getSchema().getName().equals(ENUM_FIELD_TYPE)) {
@SuppressWarnings("unchecked")
GenericData.Array<Record> symbolsArray =
(GenericData.Array<Record>) fieldType.get(SYMBOLS);
JsonNodeFactory jsonFactory = JsonNodeFactory.instance;
ArrayNode displayNamesNode = jsonFactory.arrayNode();
for (Record enumSymbol : symbolsArray) {
String enumDisplayName = (String)enumSymbol.get("displayName");
if (enumDisplayName != null) {
displayNamesNode.add(enumDisplayName);
}
}
if (displayNamesNode.size() == symbolsArray.size()) {
avroField.addProp(DISPLAY_NAMES, displayNamesNode);
}
} else if (fieldType.getSchema().getName().equals(ARRAY_FIELD_TYPE)) {
Integer minRowCount = (Integer) fieldType.get(MIN_ROW_COUNT);
if (minRowCount != null) {
avroField.addProp(MIN_ROW_COUNT, IntNode.valueOf(minRowCount));
}
}
customizeSchemaField(avroField, fieldType);
return avroField;
}
/**
* Sets the default value from field type.
*
* @param avroField the avro field
* @param fieldType the field type
* @throws ParseException the parse exception
*/
private static void setDefaultValueFromFieldType(Field avroField, Record fieldType) throws ParseException {
if (fieldType.getSchema().getName().equals(STRING_FIELD_TYPE)) {
String defaultValue = (String)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
avroField.addProp(BY_DEFAULT, defaultValue);
}
} else if (fieldType.getSchema().getName().equals(INTEGER_FIELD_TYPE)) {
Integer defaultValue = (Integer)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
avroField.addProp(BY_DEFAULT, IntNode.valueOf(defaultValue));
}
} else if (fieldType.getSchema().getName().equals(LONG_FIELD_TYPE)) {
Long defaultValue = (Long)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
long longVal = defaultValue;
if (longVal < Integer.MIN_VALUE || longVal > Integer.MAX_VALUE) {
avroField.addProp(BY_DEFAULT, LongNode.valueOf(longVal));
} else {
avroField.addProp(BY_DEFAULT, IntNode.valueOf(defaultValue.intValue()));
}
}
} else if (fieldType.getSchema().getName().equals(FLOAT_FIELD_TYPE)) {
Float defaultValue = (Float)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
avroField.addProp(BY_DEFAULT, DoubleNode.valueOf(defaultValue));
}
} else if (fieldType.getSchema().getName().equals(DOUBLE_FIELD_TYPE)) {
Double defaultValue = (Double)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
avroField.addProp(BY_DEFAULT, DoubleNode.valueOf(defaultValue));
}
} else if (fieldType.getSchema().getName().equals(BOOLEAN_FIELD_TYPE)) {
Boolean defaultValue = (Boolean)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
avroField.addProp(BY_DEFAULT, BooleanNode.valueOf(defaultValue));
}
} else if (fieldType.getSchema().getName().equals(BYTES_FIELD_TYPE)) {
String defaultValue = (String)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
avroField.addProp(BY_DEFAULT, createBytesJsonValue(defaultValue));
}
} else if (fieldType.getSchema().getName().equals(FIXED_FIELD_TYPE)) {
String defaultValue = (String)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
avroField.addProp(BY_DEFAULT, createBytesJsonValue(defaultValue));
}
} else if (fieldType.getSchema().getName().equals(ENUM_FIELD_TYPE)) {
String defaultValue = (String)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
avroField.addProp(BY_DEFAULT, defaultValue);
}
} else if (fieldType.getSchema().getName().equals(UNION_FIELD_TYPE)) {
Record defaultValue = (Record)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
JsonNode node = getUnionDefaultValue(defaultValue);
if (node != null) {
avroField.addProp(BY_DEFAULT, node);
}
}
}
}
/**
* Creates the bytes json value.
*
* @param value the value
* @return the array node
* @throws ParseException the parse exception
*/
private static ArrayNode createBytesJsonValue(String value) throws ParseException {
if (value != null) {
JsonNodeFactory jsonFactory = JsonNodeFactory.instance;
ArrayNode bytesNode = jsonFactory.arrayNode();
byte[] data = Base64Utils.fromBase64(value);
for (int i=0;i<data.length;i++) {
bytesNode.add(data[i]);
}
return bytesNode;
} else {
return null;
}
}
/**
* Gets the union default value.
*
* @param fieldType the field type
* @return the union default value
*/
private static JsonNode getUnionDefaultValue(Record fieldType) {
if (fieldType.getSchema().getName().equals(STRING_FIELD_TYPE)) {
String defaultValue = (String)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
return TextNode.valueOf(defaultValue);
}
} else if (fieldType.getSchema().getName().equals(INTEGER_FIELD_TYPE)) {
Integer defaultValue = (Integer)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
return IntNode.valueOf(defaultValue);
}
} else if (fieldType.getSchema().getName().equals(LONG_FIELD_TYPE)) {
Long defaultValue = (Long)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
long longVal = defaultValue;
if (longVal < Integer.MIN_VALUE || longVal > Integer.MAX_VALUE) {
return LongNode.valueOf(longVal);
} else {
return IntNode.valueOf(defaultValue.intValue());
}
}
} else if (fieldType.getSchema().getName().equals(FLOAT_FIELD_TYPE)) {
Float defaultValue = (Float)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
return DoubleNode.valueOf(defaultValue);
}
} else if (fieldType.getSchema().getName().equals(DOUBLE_FIELD_TYPE)) {
Double defaultValue = (Double)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
return DoubleNode.valueOf(defaultValue);
}
} else if (fieldType.getSchema().getName().equals(BOOLEAN_FIELD_TYPE)) {
Boolean defaultValue = (Boolean)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
return BooleanNode.valueOf(defaultValue);
}
} else if (fieldType.getSchema().getName().equals(BYTES_FIELD_TYPE)) {
String defaultValue = (String)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
return TextNode.valueOf(defaultValue);
}
} else if (fieldType.getSchema().getName().equals(FIXED_FIELD_TYPE)) {
String defaultValue = (String)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
return TextNode.valueOf(defaultValue);
}
} else if (fieldType.getSchema().getName().equals(ENUM_FIELD_TYPE)) {
String defaultValue = (String)fieldType.get(DEFAULT_VALUE);
if (defaultValue != null) {
return TextNode.valueOf(defaultValue);
}
}
return null;
}
}