diff --git a/typesystem/src/main/java/org/apache/hadoop/metadata/types/AttributeDefinition.java b/typesystem/src/main/java/org/apache/hadoop/metadata/types/AttributeDefinition.java index f409465..4c1ce96 100644 --- a/typesystem/src/main/java/org/apache/hadoop/metadata/types/AttributeDefinition.java +++ b/typesystem/src/main/java/org/apache/hadoop/metadata/types/AttributeDefinition.java @@ -15,6 +15,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.apache.hadoop.metadata.types; public final class AttributeDefinition { @@ -37,4 +38,32 @@ public final class AttributeDefinition { this.isComposite = isComposite; this.reverseAttributeName = reverseAttributeName; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + AttributeDefinition that = (AttributeDefinition) o; + + if (isComposite != that.isComposite) return false; + if (!dataTypeName.equals(that.dataTypeName)) return false; + if (!multiplicity.equals(that.multiplicity)) return false; + if (!name.equals(that.name)) return false; + if (reverseAttributeName != null ? !reverseAttributeName.equals(that.reverseAttributeName) : that + .reverseAttributeName != null) + return false; + + return true; + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + dataTypeName.hashCode(); + result = 31 * result + multiplicity.hashCode(); + result = 31 * result + (isComposite ? 1 : 0); + result = 31 * result + (reverseAttributeName != null ? reverseAttributeName.hashCode() : 0); + return result; + } } diff --git a/typesystem/src/main/java/org/apache/hadoop/metadata/types/DataTypes.java b/typesystem/src/main/java/org/apache/hadoop/metadata/types/DataTypes.java index ad83f41..6be122f 100644 --- a/typesystem/src/main/java/org/apache/hadoop/metadata/types/DataTypes.java +++ b/typesystem/src/main/java/org/apache/hadoop/metadata/types/DataTypes.java @@ -433,6 +433,15 @@ public class DataTypes { static String ARRAY_TYPE_PREFIX = "array<"; static String ARRAY_TYPE_SUFFIX = ">"; + + public static String arrayTypeName(String elemTypeName) { + return String.format("%s%s%s", ARRAY_TYPE_PREFIX, elemTypeName, ARRAY_TYPE_SUFFIX); + } + + public static String arrayTypeName(IDataType elemType) { + return arrayTypeName(elemType.getName()); + } + public static class ArrayType extends AbstractDataType<ImmutableCollection<?>> { private IDataType elemType; @@ -441,7 +450,7 @@ public class DataTypes { public ArrayType(IDataType elemType) { assert elemType != null; this.elemType = elemType; - this.nm = String.format("%s%s%s", ARRAY_TYPE_PREFIX, elemType.getName(), ARRAY_TYPE_SUFFIX); + this.nm = arrayTypeName(elemType); } public IDataType getElemType() { @@ -521,6 +530,16 @@ public class DataTypes { static String MAP_TYPE_PREFIX = "map<"; static String MAP_TYPE_SUFFIX = ">"; + + public static String mapTypeName(String keyTypeName, String valueTypeName) { + return String.format("%s%s,%s%s", MAP_TYPE_PREFIX, + keyTypeName, valueTypeName, MAP_TYPE_SUFFIX); + } + + public static String mapTypeName(IDataType keyType, IDataType valueType) { + return mapTypeName(keyType.getName(), valueType.getName()); + } + public static class MapType extends AbstractDataType<ImmutableMap<?, ?>> { private IDataType keyType; @@ -532,8 +551,7 @@ public class DataTypes { assert valueType != null; this.keyType = keyType; this.valueType = valueType; - this.nm = String.format("%s%s,%s%s", MAP_TYPE_PREFIX, - keyType.getName(), valueType.getName(), MAP_TYPE_SUFFIX); + this.nm = mapTypeName(keyType, valueType); } public IDataType getKeyType() { diff --git a/typesystem/src/main/java/org/apache/hadoop/metadata/types/EnumTypeDefinition.java b/typesystem/src/main/java/org/apache/hadoop/metadata/types/EnumTypeDefinition.java new file mode 100644 index 0000000..e8bd548 --- /dev/null +++ b/typesystem/src/main/java/org/apache/hadoop/metadata/types/EnumTypeDefinition.java @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.hadoop.metadata.types; + +import java.util.Arrays; + +public final class EnumTypeDefinition { + + public final String name; + public final EnumValue[] enumValues; + + public EnumTypeDefinition(String name, EnumValue...enumValues) { + this.name = name; + this.enumValues = enumValues; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + EnumTypeDefinition that = (EnumTypeDefinition) o; + + if (!Arrays.equals(enumValues, that.enumValues)) return false; + if (!name.equals(that.name)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = name.hashCode(); + result = 31 * result + Arrays.hashCode(enumValues); + return result; + } +} diff --git a/typesystem/src/main/java/org/apache/hadoop/metadata/types/HierarchicalTypeDefinition.java b/typesystem/src/main/java/org/apache/hadoop/metadata/types/HierarchicalTypeDefinition.java index 0092db7..058ffc4 100644 --- a/typesystem/src/main/java/org/apache/hadoop/metadata/types/HierarchicalTypeDefinition.java +++ b/typesystem/src/main/java/org/apache/hadoop/metadata/types/HierarchicalTypeDefinition.java @@ -20,14 +20,56 @@ package org.apache.hadoop.metadata.types; import com.google.common.collect.ImmutableList; +import java.util.Collection; + public class HierarchicalTypeDefinition<T extends HierarchicalType> extends StructTypeDefinition { public final ImmutableList<String> superTypes; + public final String hierarchicalMetaTypeName; + + /** + * Used for json deserialization only + * @nopublic + * @param hierarchicalMetaTypeName + * @param typeName + * @param superTypes + * @param attributeDefinitions + * @throws ClassNotFoundException + */ + public HierarchicalTypeDefinition(String hierarchicalMetaTypeName, + String typeName, String[] superTypes, + AttributeDefinition[] attributeDefinitions) throws ClassNotFoundException { + this((Class<T>) Class.forName(hierarchicalMetaTypeName), + typeName, ImmutableList.copyOf(superTypes), attributeDefinitions); + } public HierarchicalTypeDefinition(Class<T> hierarchicalMetaType, String typeName, ImmutableList<String> superTypes, AttributeDefinition[] attributeDefinitions) { super(typeName, attributeDefinitions); + hierarchicalMetaTypeName = hierarchicalMetaType.getName(); this.superTypes = superTypes == null ? ImmutableList.<String>of() : superTypes; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + if (!super.equals(o)) return false; + + HierarchicalTypeDefinition that = (HierarchicalTypeDefinition) o; + + if (!hierarchicalMetaTypeName.equals(that.hierarchicalMetaTypeName)) return false; + if (!superTypes.equals(that.superTypes)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + superTypes.hashCode(); + result = 31 * result + hierarchicalMetaTypeName.hashCode(); + return result; + } } diff --git a/typesystem/src/main/java/org/apache/hadoop/metadata/types/StructTypeDefinition.java b/typesystem/src/main/java/org/apache/hadoop/metadata/types/StructTypeDefinition.java index 5200b8e..3806786 100644 --- a/typesystem/src/main/java/org/apache/hadoop/metadata/types/StructTypeDefinition.java +++ b/typesystem/src/main/java/org/apache/hadoop/metadata/types/StructTypeDefinition.java @@ -1,6 +1,24 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.hadoop.metadata.types; -import com.google.common.collect.ImmutableList; +import java.util.Arrays; public class StructTypeDefinition { @@ -12,4 +30,24 @@ public class StructTypeDefinition { this.typeName = typeName; this.attributeDefinitions = attributeDefinitions; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + StructTypeDefinition that = (StructTypeDefinition) o; + + if (!Arrays.equals(attributeDefinitions, that.attributeDefinitions)) return false; + if (!typeName.equals(that.typeName)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = typeName.hashCode(); + result = 31 * result + Arrays.hashCode(attributeDefinitions); + return result; + } } diff --git a/typesystem/src/main/java/org/apache/hadoop/metadata/types/TypeSystem.java b/typesystem/src/main/java/org/apache/hadoop/metadata/types/TypeSystem.java index 35465d3..773397c 100644 --- a/typesystem/src/main/java/org/apache/hadoop/metadata/types/TypeSystem.java +++ b/typesystem/src/main/java/org/apache/hadoop/metadata/types/TypeSystem.java @@ -111,7 +111,7 @@ public class TypeSystem { return getDataType(ClassType.class, classDef.typeName); } - public Map<String, IDataType> defineTraitTypes(HierarchicalTypeDefinition<TraitType>... traitDefs) + public Map<String, IDataType> defineTraitTypes(HierarchicalTypeDefinition<TraitType>...traitDefs) throws MetadataException { TransientTypeSystem transientTypes = new TransientTypeSystem(ImmutableList.<StructTypeDefinition>of(), ImmutableList.<HierarchicalTypeDefinition<TraitType>>copyOf(traitDefs), @@ -145,12 +145,16 @@ public class TypeSystem { } public EnumType defineEnumType(String name, EnumValue...values) throws MetadataException { - assert name != null; - if (types.containsKey(name)) { - throw new MetadataException(String.format("Redefinition of type %s not supported", name)); + return defineEnumType(new EnumTypeDefinition(name, values)); + } + + public EnumType defineEnumType(EnumTypeDefinition eDef) throws MetadataException { + assert eDef.name != null; + if (types.containsKey(eDef.name)) { + throw new MetadataException(String.format("Redefinition of type %s not supported", eDef.name)); } - EnumType eT = new EnumType(this, name, values); - types.put(name, eT); + EnumType eT = new EnumType(this, eDef.name, eDef.enumValues); + types.put(eDef.name, eT); return eT; } diff --git a/typesystem/src/main/scala/org/apache/hadoop/metadata/json/TypesSerialization.scala b/typesystem/src/main/scala/org/apache/hadoop/metadata/json/TypesSerialization.scala new file mode 100644 index 0000000..0ea5668 --- /dev/null +++ b/typesystem/src/main/scala/org/apache/hadoop/metadata/json/TypesSerialization.scala @@ -0,0 +1,200 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.hadoop.metadata.json + +import com.google.common.collect.ImmutableList +import org.apache.hadoop.metadata.MetadataException +import org.apache.hadoop.metadata.types.DataTypes.{ArrayType, MapType, TypeCategory} +import org.apache.hadoop.metadata.types._ +import org.json4s.JsonAST.JString +import org.json4s._ +import org.json4s.native.Serialization._ + +case class TypesDef(enumTypes: Seq[EnumTypeDefinition], + structTypes: Seq[StructTypeDefinition], + traitTypes: Seq[HierarchicalTypeDefinition[TraitType]], + classTypes: Seq[HierarchicalTypeDefinition[ClassType]]) + +/** + * Module for serializing to/from Json. + * + * @example {{{ + * val j = TypesSerialization.toJson(typeSystem, "Employee", "Person", "Department", "SecurityClearance") + * + * val typesDef = TypesSerialization.fromJson(jsonStr) + * typesDef.enumTypes.foreach( typeSystem.defineEnumType(_)) + + typeSystem.defineTypes(ImmutableList.copyOf(typesDef.structTypes.toArray), + ImmutableList.copyOf(typesDef.traitTypes.toArray), + ImmutableList.copyOf(typesDef.classTypes.toArray) + ) + * }}} + * + * @todo doesn't traverse includes directives. Includes are parsed into + * [[org.apache.hadoop.metadata.tools.thrift.IncludeDef IncludeDef]] structures + * but are not traversed. + * @todo mixing in [[scala.util.parsing.combinator.PackratParsers PackratParsers]] is a placeholder. Need to + * change specific grammar rules to `lazy val` and `Parser[Elem]` to `PackratParser[Elem]`. Will do based on + * performance analysis. + * @todo Error reporting + */ +object TypesSerialization { + + def toJson(ts : TypeSystem, typNames : String*) : String = { + toJson(ts, (typ : IDataType[_]) => typNames.contains(typ.getName)) + } + + def toJson(ts : TypeSystem, export : IDataType[_] => Boolean) : String = { + implicit val formats = org.json4s.native.Serialization.formats(NoTypeHints) + new MultiplicitySerializer + + val typsDef = convertToTypesDef(ts, export) + + writePretty(typsDef) + } + + def fromJson(jsonStr : String) : TypesDef = { + implicit val formats = org.json4s.native.Serialization.formats(NoTypeHints) + new MultiplicitySerializer + + read[TypesDef](jsonStr) + } + + private def convertAttributeInfoToAttributeDef(aInfo : AttributeInfo) = { + new AttributeDefinition(aInfo.name, aInfo.dataType().getName, aInfo.multiplicity, + aInfo.isComposite, aInfo.reverseAttributeName) + } + + private def convertEnumTypeToEnumTypeDef(et : EnumType) = { + import scala.collection.JavaConversions._ + val eVals :Seq[EnumValue] = et.valueMap.values().toSeq + new EnumTypeDefinition(et.name, eVals:_*) + } + + private def convertStructTypeToStructDef(st : StructType) : StructTypeDefinition = { + import scala.collection.JavaConversions._ + + val aDefs : Iterable[AttributeDefinition] = + st.fieldMapping.fields.values().map(convertAttributeInfoToAttributeDef(_)) + new StructTypeDefinition(st.name, aDefs.toArray) + } + + private def convertTraitTypeToHierarchicalTypeDefintion(tt : TraitType) : HierarchicalTypeDefinition[TraitType] = { + import scala.collection.JavaConversions._ + + val aDefs : Iterable[AttributeDefinition] = + tt.immediateAttrs.map(convertAttributeInfoToAttributeDef(_)) + new HierarchicalTypeDefinition[TraitType](classOf[TraitType], tt.name, tt.superTypes, aDefs.toArray) + } + + private def convertClassTypeToHierarchicalTypeDefintion(tt : ClassType) : HierarchicalTypeDefinition[ClassType] = { + import scala.collection.JavaConversions._ + + val aDefs : Iterable[AttributeDefinition] = + tt.immediateAttrs.map(convertAttributeInfoToAttributeDef(_)) + new HierarchicalTypeDefinition[ClassType](classOf[ClassType], tt.name, tt.superTypes, aDefs.toArray) + } + + def convertToTypesDef(ts: TypeSystem, export : IDataType[_] => Boolean) : TypesDef = { + + import scala.collection.JavaConversions._ + + var enumTypes : Seq[EnumTypeDefinition] = Nil + var structTypes : Seq[StructTypeDefinition] = Nil + var traitTypes : Seq[HierarchicalTypeDefinition[TraitType]] = Nil + var classTypes : Seq[HierarchicalTypeDefinition[ClassType]] = Nil + + def toTyp(nm : String) = ts.getDataType(classOf[IDataType[_]], nm) + + val typs : Iterable[IDataType[_]] = ts.getTypeNames.map(toTyp(_)).filter {(typ : IDataType[_]) => + !(typ.getTypeCategory eq TypeCategory.PRIMITIVE) && export(typ) + } + + typs.foreach { + case typ : ArrayType => () + case typ : MapType => () + case typ : EnumType => enumTypes = enumTypes :+ convertEnumTypeToEnumTypeDef(typ) + case typ : StructType => structTypes = structTypes :+ convertStructTypeToStructDef(typ) + case typ : TraitType => traitTypes = traitTypes :+ convertTraitTypeToHierarchicalTypeDefintion(typ) + case typ : ClassType => classTypes = classTypes :+ convertClassTypeToHierarchicalTypeDefintion(typ) + } + + TypesDef(enumTypes, structTypes, traitTypes, classTypes) + } + +} + +class MultiplicitySerializer extends CustomSerializer[Multiplicity](format => ( { + case JString(m) => m match { + case "optional" => Multiplicity.OPTIONAL + case "required" => Multiplicity.REQUIRED + case "collection" => Multiplicity.COLLECTION + case "set" => Multiplicity.SET + } +}, { + case m : Multiplicity => JString( m match { + case Multiplicity.OPTIONAL => "optional" + case Multiplicity.REQUIRED => "required" + case Multiplicity.COLLECTION => "collection" + case Multiplicity.SET => "set" + } + + ) +} + )) + +trait TypeHelpers { + def requiredAttr(name: String, dataType: IDataType[_]) = + new AttributeDefinition(name, dataType.getName, Multiplicity.REQUIRED, false, null) + + def optionalAttr(name: String, dataTypeName: String) = + new AttributeDefinition(name, dataTypeName, Multiplicity.OPTIONAL, false, null) + + + def optionalAttr(name: String, dataType: IDataType[_]) = + new AttributeDefinition(name, dataType.getName, Multiplicity.OPTIONAL, false, null) + + def structDef(name : String, attrs : AttributeDefinition*) = { + new StructTypeDefinition(name, attrs.toArray) + } + + def defineTraits(ts: TypeSystem, tDefs: HierarchicalTypeDefinition[TraitType]*) = { + ts.defineTraitTypes(tDefs:_*) + } + + def createTraitTypeDef(name: String, superTypes: Seq[String], attrDefs: AttributeDefinition*): + HierarchicalTypeDefinition[TraitType] = { + val sts = ImmutableList.copyOf(superTypes.toArray) + return new HierarchicalTypeDefinition[TraitType](classOf[TraitType], name, + sts, attrDefs.toArray) + } + + def createClassTypeDef(name: String, superTypes: Seq[String], attrDefs: AttributeDefinition*): + HierarchicalTypeDefinition[ClassType] = { + val sts = ImmutableList.copyOf(superTypes.toArray) + return new HierarchicalTypeDefinition[ClassType](classOf[ClassType], name, + sts, attrDefs.toArray) + } + + @throws(classOf[MetadataException]) + def defineClassType(ts : TypeSystem, classDef: HierarchicalTypeDefinition[ClassType]): ClassType = { + ts.defineTypes(ImmutableList.of[StructTypeDefinition], + ImmutableList.of[HierarchicalTypeDefinition[TraitType]], + ImmutableList.of[HierarchicalTypeDefinition[ClassType]](classDef)) + return ts.getDataType(classOf[ClassType], classDef.typeName) + } +} diff --git a/typesystem/src/test/scala/org/apache/hadoop/metadata/json/TypesSerializationTest.scala b/typesystem/src/test/scala/org/apache/hadoop/metadata/json/TypesSerializationTest.scala new file mode 100644 index 0000000..077ce3a --- /dev/null +++ b/typesystem/src/test/scala/org/apache/hadoop/metadata/json/TypesSerializationTest.scala @@ -0,0 +1,190 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.apache.hadoop.metadata.json + +import com.google.common.collect.ImmutableList +import org.apache.hadoop.metadata.{MetadataException, BaseTest} +import org.apache.hadoop.metadata.types._ +import org.junit.{Assert, Test} + +class TypesSerializationTest extends BaseTest with TypeHelpers { + + @Test def test1: Unit = { + + val ts = ms.getTypeSystem + + val sDef = structDef("ts1", requiredAttr("a", DataTypes.INT_TYPE), + optionalAttr("b", DataTypes.BOOLEAN_TYPE), + optionalAttr("c", DataTypes.BYTE_TYPE), + optionalAttr("d", DataTypes.SHORT_TYPE), + optionalAttr("e", DataTypes.INT_TYPE), + optionalAttr("f", DataTypes.INT_TYPE), + optionalAttr("g", DataTypes.LONG_TYPE), + optionalAttr("h", DataTypes.FLOAT_TYPE), + optionalAttr("i", DataTypes.DOUBLE_TYPE), + optionalAttr("j", DataTypes.BIGINTEGER_TYPE), + optionalAttr("k", DataTypes.BIGDECIMAL_TYPE), + optionalAttr("l", DataTypes.DATE_TYPE), + optionalAttr("m", DataTypes.arrayTypeName(DataTypes.INT_TYPE)), + optionalAttr("n", DataTypes.arrayTypeName(DataTypes.BIGDECIMAL_TYPE)), + optionalAttr("o", DataTypes.mapTypeName(DataTypes.STRING_TYPE, DataTypes.DOUBLE_TYPE))) + + + ts.defineTypes(ImmutableList.of[StructTypeDefinition](sDef), + ImmutableList.of[HierarchicalTypeDefinition[TraitType]], + ImmutableList.of[HierarchicalTypeDefinition[ClassType]] + ) + + val A: HierarchicalTypeDefinition[TraitType] = createTraitTypeDef("A", List(), + requiredAttr("a", DataTypes.INT_TYPE), + optionalAttr("b", DataTypes.BOOLEAN_TYPE), + optionalAttr("c", DataTypes.BYTE_TYPE), + optionalAttr("d", DataTypes.SHORT_TYPE)) + val B: HierarchicalTypeDefinition[TraitType] = + createTraitTypeDef("B", Seq("A"), optionalAttr("b", DataTypes.BOOLEAN_TYPE)) + val C: HierarchicalTypeDefinition[TraitType] = + createTraitTypeDef("C", Seq("A"), optionalAttr("c", DataTypes.BYTE_TYPE)) + val D: HierarchicalTypeDefinition[TraitType] = + createTraitTypeDef("D", Seq("B", "C"), optionalAttr("d", DataTypes.SHORT_TYPE)) + + defineTraits(ts, A, B, C, D) + + ts.defineEnumType("HiveObjectType", + new EnumValue("GLOBAL", 1), + new EnumValue("DATABASE", 2), + new EnumValue("TABLE", 3), + new EnumValue("PARTITION", 4), + new EnumValue("COLUMN", 5)) + + ts.defineEnumType("PrincipalType", + new EnumValue("USER", 1), + new EnumValue("ROLE", 2), + new EnumValue("GROUP", 3)) + + ts.defineEnumType("TxnState", + new EnumValue("COMMITTED", 1), + new EnumValue("ABORTED", 2), + new EnumValue("OPEN", 3)) + + ts.defineEnumType("LockLevel", + new EnumValue("DB", 1), + new EnumValue("TABLE", 2), + new EnumValue("PARTITION", 3)) + + defineClassType(ts, createClassTypeDef("t4", List(), + requiredAttr("a", DataTypes.INT_TYPE), + optionalAttr("b", DataTypes.BOOLEAN_TYPE), + optionalAttr("c", DataTypes.BYTE_TYPE), + optionalAttr("d", DataTypes.SHORT_TYPE), + optionalAttr("enum1", ts.getDataType(classOf[EnumType], "HiveObjectType")), + optionalAttr("e", DataTypes.INT_TYPE), + optionalAttr("f", DataTypes.INT_TYPE), + optionalAttr("g", DataTypes.LONG_TYPE), + optionalAttr("enum2", ts.getDataType(classOf[EnumType], "PrincipalType")), + optionalAttr("h", DataTypes.FLOAT_TYPE), + optionalAttr("i", DataTypes.DOUBLE_TYPE), + optionalAttr("j", DataTypes.BIGINTEGER_TYPE), + optionalAttr("k", DataTypes.BIGDECIMAL_TYPE), + optionalAttr("enum3", ts.getDataType(classOf[EnumType], "TxnState")), + optionalAttr("l", DataTypes.DATE_TYPE), + optionalAttr("m", ts.defineArrayType(DataTypes.INT_TYPE)), + optionalAttr("n", ts.defineArrayType(DataTypes.BIGDECIMAL_TYPE)), + optionalAttr("o", ts.defineMapType(DataTypes.STRING_TYPE, DataTypes.DOUBLE_TYPE)), + optionalAttr("enum4", ts.getDataType(classOf[EnumType], "LockLevel")))) + + val deptTypeDef: HierarchicalTypeDefinition[ClassType] = createClassTypeDef("Department", List(), + requiredAttr("name", DataTypes.STRING_TYPE), + new AttributeDefinition("employees", String.format("array<%s>", "Person"), + Multiplicity.COLLECTION, true, "department")) + val personTypeDef: HierarchicalTypeDefinition[ClassType] = createClassTypeDef("Person", List(), + requiredAttr("name", DataTypes.STRING_TYPE), + new AttributeDefinition("department", "Department", Multiplicity.REQUIRED, false, "employees"), + new AttributeDefinition("manager", "Manager", Multiplicity.OPTIONAL, false, "subordinates") + ) + val managerTypeDef: HierarchicalTypeDefinition[ClassType] = createClassTypeDef("Manager", List("Person"), + new AttributeDefinition("subordinates", String.format("array<%s>", "Person"), + Multiplicity.COLLECTION, false, "manager") + ) + val securityClearanceTypeDef: HierarchicalTypeDefinition[TraitType] = createTraitTypeDef("SecurityClearance", List(), + requiredAttr("level", DataTypes.INT_TYPE) + ) + ts.defineTypes(ImmutableList.of[StructTypeDefinition], + ImmutableList.of[HierarchicalTypeDefinition[TraitType]](securityClearanceTypeDef), + ImmutableList.of[HierarchicalTypeDefinition[ClassType]](deptTypeDef, personTypeDef, managerTypeDef)) + + val ser = TypesSerialization.toJson(ts, _ => true) + + val typesDef1 = TypesSerialization.fromJson(ser) + + val ts1 = new TypeSystem() + + typesDef1.enumTypes.foreach( ts1.defineEnumType(_)) + + ts1.defineTypes(ImmutableList.copyOf(typesDef1.structTypes.toArray), + ImmutableList.copyOf(typesDef1.traitTypes.toArray), + ImmutableList.copyOf(typesDef1.classTypes.toArray) + ) + val ser2 = TypesSerialization.toJson(ts1, _ => true) + val typesDef2 = TypesSerialization.fromJson(ser2) + + Assert.assertEquals(typesDef1, typesDef2) + } +} + +trait TypeHelpers { + def requiredAttr(name: String, dataType: IDataType[_]) = + new AttributeDefinition(name, dataType.getName, Multiplicity.REQUIRED, false, null) + + def optionalAttr(name: String, dataTypeName: String) = + new AttributeDefinition(name, dataTypeName, Multiplicity.OPTIONAL, false, null) + + + def optionalAttr(name: String, dataType: IDataType[_]) = + new AttributeDefinition(name, dataType.getName, Multiplicity.OPTIONAL, false, null) + + def structDef(name : String, attrs : AttributeDefinition*) = { + new StructTypeDefinition(name, attrs.toArray) + } + + def defineTraits(ts: TypeSystem, tDefs: HierarchicalTypeDefinition[TraitType]*) = { + ts.defineTraitTypes(tDefs:_*) + } + + def createTraitTypeDef(name: String, superTypes: Seq[String], attrDefs: AttributeDefinition*): + HierarchicalTypeDefinition[TraitType] = { + val sts = ImmutableList.copyOf(superTypes.toArray) + return new HierarchicalTypeDefinition[TraitType](classOf[TraitType], name, + sts, attrDefs.toArray) + } + + def createClassTypeDef(name: String, superTypes: Seq[String], attrDefs: AttributeDefinition*): + HierarchicalTypeDefinition[ClassType] = { + val sts = ImmutableList.copyOf(superTypes.toArray) + return new HierarchicalTypeDefinition[ClassType](classOf[ClassType], name, + sts, attrDefs.toArray) + } + + @throws(classOf[MetadataException]) + def defineClassType(ts : TypeSystem, classDef: HierarchicalTypeDefinition[ClassType]): ClassType = { + ts.defineTypes(ImmutableList.of[StructTypeDefinition], + ImmutableList.of[HierarchicalTypeDefinition[TraitType]], + ImmutableList.of[HierarchicalTypeDefinition[ClassType]](classDef)) + return ts.getDataType(classOf[ClassType], classDef.typeName) + } +}