http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/DataTypes.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/DataTypes.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/DataTypes.java new file mode 100755 index 0000000..f6b6a3e --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/DataTypes.java @@ -0,0 +1,660 @@ +/** + * 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.atlas.typesystem.types; + +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import org.apache.atlas.MetadataException; +import org.apache.atlas.typesystem.IReferenceableInstance; +import org.apache.atlas.typesystem.persistence.Id; +import org.apache.commons.lang3.StringUtils; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.ParseException; +import java.util.Collection; +import java.util.Date; +import java.util.Iterator; +import java.util.Map; + +public class DataTypes { + + public static BooleanType BOOLEAN_TYPE = new BooleanType(); + public static ByteType BYTE_TYPE = new ByteType(); + public static ShortType SHORT_TYPE = new ShortType(); + public static IntType INT_TYPE = new IntType(); + public static LongType LONG_TYPE = new LongType(); + public static FloatType FLOAT_TYPE = new FloatType(); + public static DoubleType DOUBLE_TYPE = new DoubleType(); + public static BigIntegerType BIGINTEGER_TYPE = new BigIntegerType(); + public static BigDecimalType BIGDECIMAL_TYPE = new BigDecimalType(); + public static DateType DATE_TYPE = new DateType(); + public static StringType STRING_TYPE = new StringType(); + static String ARRAY_TYPE_PREFIX = "array<"; + static String ARRAY_TYPE_SUFFIX = ">"; + static String MAP_TYPE_PREFIX = "map<"; + static String MAP_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 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 enum TypeCategory { + PRIMITIVE, + ENUM, + ARRAY, + MAP, + STRUCT, + TRAIT, + CLASS + } + + public static abstract class PrimitiveType<T> extends AbstractDataType<T> { + @Override + public TypeCategory getTypeCategory() { + return TypeCategory.PRIMITIVE; + } + + public abstract T nullValue(); + + } + + public static class BooleanType extends PrimitiveType<Boolean> { + + private static final String name = "boolean".intern(); + + private BooleanType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public Boolean convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + if (val instanceof Boolean) { + return (Boolean) val; + } else if (val instanceof String) { + return Boolean.parseBoolean((String) val); + } else if (val instanceof Number) { + return ((Number) val).intValue() != 0; + } else { + throw new ValueConversionException(this, val); + } + } + return convertNull(m); + } + + public Boolean nullValue() { + return Boolean.FALSE; + } + } + + public static class ByteType extends PrimitiveType<Byte> { + + private static final String name = "byte".intern(); + + private ByteType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public Byte convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + if (val instanceof Byte) { + return (Byte) val; + } else if (val instanceof String) { + return Byte.parseByte((String) val); + } else if (val instanceof Number) { + return ((Number) val).byteValue(); + } else { + throw new ValueConversionException(this, val); + } + } + return convertNull(m); + } + + public Byte nullValue() { + return 0; + } + } + + public static class ShortType extends PrimitiveType<Short> { + + private static final String name = "short".intern(); + + private ShortType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public Short convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + if (val instanceof Short) { + return (Short) val; + } else if (val instanceof String) { + return Short.parseShort((String) val); + } else if (val instanceof Number) { + return ((Number) val).shortValue(); + } else { + throw new ValueConversionException(this, val); + } + } + return convertNull(m); + } + + public Short nullValue() { + return 0; + } + } + + public static class IntType extends PrimitiveType<Integer> { + + private static final String name = "int".intern(); + + private IntType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public Integer convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + if (val instanceof Integer) { + return (Integer) val; + } else if (val instanceof String) { + return Integer.parseInt((String) val); + } else if (val instanceof Number) { + return ((Number) val).intValue(); + } else { + throw new ValueConversionException(this, val); + } + } + return convertNull(m); + } + + public Integer nullValue() { + return 0; + } + } + + public static class LongType extends PrimitiveType<Long> { + + private static final String name = "long".intern(); + + private LongType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public Long convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + if (val instanceof Long) { + return (Long) val; + } else if (val instanceof String) { + return Long.parseLong((String) val); + } else if (val instanceof Number) { + return ((Number) val).longValue(); + } else { + throw new ValueConversionException(this, val); + } + } + return convertNull(m); + } + + public Long nullValue() { + return 0l; + } + } + + public static class FloatType extends PrimitiveType<Float> { + + private static final String name = "float".intern(); + + private FloatType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public Float convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + if (val instanceof Float) { + return (Float) val; + } else if (val instanceof String) { + return Float.parseFloat((String) val); + } else if (val instanceof Number) { + return ((Number) val).floatValue(); + } else { + throw new ValueConversionException(this, val); + } + } + return convertNull(m); + } + + public Float nullValue() { + return 0.0f; + } + } + + public static class DoubleType extends PrimitiveType<Double> { + + private static final String name = "double".intern(); + + private DoubleType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public Double convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + if (val instanceof Double) { + return (Double) val; + } else if (val instanceof String) { + return Double.parseDouble((String) val); + } else if (val instanceof Number) { + return ((Number) val).doubleValue(); + } else { + throw new ValueConversionException(this, val); + } + } + return convertNull(m); + } + + public Double nullValue() { + return 0.0; + } + } + + public static class BigIntegerType extends PrimitiveType<BigInteger> { + + private static final String name = "biginteger".intern(); + + private BigIntegerType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public BigInteger convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + if (val instanceof BigInteger) { + return (BigInteger) val; + } else if (val instanceof String) { + try { + return new BigInteger((String) val); + } catch (NumberFormatException ne) { + throw new ValueConversionException(this, val, ne); + } + } else if (val instanceof Number) { + return BigInteger.valueOf(((Number) val).longValue()); + } else if (val instanceof BigDecimal) { + return ((BigDecimal) val).toBigInteger(); + } else { + throw new ValueConversionException(this, val); + } + } + return convertNull(m); + } + + public BigInteger nullValue() { + return null; + } + } + + public static class BigDecimalType extends PrimitiveType<BigDecimal> { + + private static final String name = "bigdecimal".intern(); + + private BigDecimalType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public BigDecimal convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + if (val instanceof BigDecimal) { + return (BigDecimal) val; + } else if (val instanceof String) { + try { + return new BigDecimal((String) val); + } catch (NumberFormatException ne) { + throw new ValueConversionException(this, val, ne); + } + } else if (val instanceof Number) { + return new BigDecimal(((Number) val).doubleValue()); + } else if (val instanceof BigInteger) { + return new BigDecimal((BigInteger) val); + } else { + throw new ValueConversionException(this, val); + } + } + return convertNull(m); + } + + public BigDecimal nullValue() { + return null; + } + } + + public static class DateType extends PrimitiveType<Date> { + + private static final String name = "date".intern(); + + private DateType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public Date convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + if (val instanceof Date) { + return (Date) val; + } else if (val instanceof String) { + try { + return TypeSystem.getInstance().getDateFormat().parse((String) val); + } catch (ParseException ne) { + throw new ValueConversionException(this, val, ne); + } + } else if (val instanceof Number) { + return new Date(((Number) val).longValue()); + } else { + throw new ValueConversionException(this, val); + } + } + return convertNull(m); + } + + @Override + public void output(Date val, Appendable buf, String prefix) throws MetadataException { + TypeUtils.outputVal(val == null ? "<null>" : + TypeSystem.getInstance().getDateFormat().format(val), buf, prefix); + } + + public Date nullValue() { + return null; + } + } + + public static class StringType extends PrimitiveType<String> { + + private static final String name = "string".intern(); + + private StringType() { + } + + @Override + public String getName() { + return name; + } + + @Override + public String convert(Object val, Multiplicity m) throws MetadataException { + if (StringUtils.isNotBlank((CharSequence) val)) { + return val.toString(); + } + return convertNull(m); + } + + public String nullValue() { + return null; + } + } + + public static class ArrayType extends AbstractDataType<ImmutableCollection<?>> { + private final String nm; + private IDataType elemType; + + public ArrayType(IDataType elemType) { + assert elemType != null; + this.elemType = elemType; + this.nm = arrayTypeName(elemType); + } + + public IDataType getElemType() { + return elemType; + } + + protected void setElemType(IDataType elemType) { + this.elemType = elemType; + } + + @Override + public String getName() { + return nm; + } + + @Override + public ImmutableCollection<?> convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + Iterator it = null; + if (val instanceof Collection) { + it = ((Collection) val).iterator(); + } else if (val instanceof Iterable) { + it = ((Iterable) val).iterator(); + } else if (val instanceof Iterator) { + it = (Iterator) val; + } + if (it != null) { + ImmutableCollection.Builder b = m.isUnique ? ImmutableSet.builder() + : ImmutableList.builder(); + while (it.hasNext()) { + b.add(elemType.convert(it.next(), + TypeSystem.getInstance().allowNullsInCollections() + ? Multiplicity.OPTIONAL : Multiplicity.REQUIRED)); + } + return m.isUnique ? b.build().asList() : b.build(); + } else { + try { + return ImmutableList.of(elemType.convert(val, + TypeSystem.getInstance().allowNullsInCollections() + ? Multiplicity.OPTIONAL : Multiplicity.REQUIRED)); + } catch (Exception e) { + throw new ValueConversionException(this, val, e); + } + } + } + if (!m.nullAllowed()) { + throw new ValueConversionException.NullConversionException(m); + } + return null; + } + + public ImmutableCollection<?> mapIds(ImmutableCollection<?> val, Multiplicity m, + Map<Id, Id> transientToNewIds) + throws MetadataException { + + if (val == null || elemType.getTypeCategory() != TypeCategory.CLASS) { + return val; + } + ImmutableCollection.Builder b = m.isUnique ? ImmutableSet.builder() + : ImmutableList.builder(); + Iterator it = val.iterator(); + while (it.hasNext()) { + Object elem = it.next(); + if (elem instanceof IReferenceableInstance) { + Id oldId = ((IReferenceableInstance) elem).getId(); + Id newId = transientToNewIds.get(oldId); + b.add(newId == null ? oldId : newId); + } else { + b.add(elem); + } + } + return b.build(); + } + + @Override + public TypeCategory getTypeCategory() { + return TypeCategory.ARRAY; + } + } + + public static class MapType extends AbstractDataType<ImmutableMap<?, ?>> { + + private final String nm; + private IDataType keyType; + private IDataType valueType; + + public MapType(IDataType keyType, IDataType valueType) { + assert keyType != null; + assert valueType != null; + this.keyType = keyType; + this.valueType = valueType; + this.nm = mapTypeName(keyType, valueType); + } + + public IDataType getKeyType() { + return keyType; + } + + protected void setKeyType(IDataType keyType) { + this.keyType = keyType; + } + + public IDataType getValueType() { + return valueType; + } + + protected void setValueType(IDataType valueType) { + this.keyType = valueType; + } + + @Override + public String getName() { + return nm; + } + + @Override + public ImmutableMap<?, ?> convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + Iterator<Map.Entry> it = null; + if (Map.class.isAssignableFrom(val.getClass())) { + it = ((Map) val).entrySet().iterator(); + ImmutableMap.Builder b = ImmutableMap.builder(); + while (it.hasNext()) { + Map.Entry e = it.next(); + b.put(keyType.convert(e.getKey(), + TypeSystem.getInstance().allowNullsInCollections() + ? Multiplicity.OPTIONAL : Multiplicity.REQUIRED), + valueType.convert(e.getValue(), + TypeSystem.getInstance().allowNullsInCollections() + ? Multiplicity.OPTIONAL : Multiplicity.REQUIRED)); + } + return b.build(); + } else { + throw new ValueConversionException(this, val); + } + } + if (!m.nullAllowed()) { + throw new ValueConversionException.NullConversionException(m); + } + return null; + } + + public ImmutableMap<?, ?> mapIds(ImmutableMap val, Multiplicity m, + Map<Id, Id> transientToNewIds) + throws MetadataException { + + if (val == null || (keyType.getTypeCategory() != TypeCategory.CLASS && + valueType.getTypeCategory() != TypeCategory.CLASS)) { + return val; + } + ImmutableMap.Builder b = ImmutableMap.builder(); + Iterator<Map.Entry> it = val.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry elem = it.next(); + Object oldKey = elem.getKey(); + Object oldValue = elem.getValue(); + Object newKey = oldKey; + Object newValue = oldValue; + + if (oldKey instanceof IReferenceableInstance) { + Id oldId = ((IReferenceableInstance) oldKey).getId(); + Id newId = transientToNewIds.get(oldId); + newKey = newId == null ? oldId : newId; + } + + if (oldValue instanceof IReferenceableInstance) { + Id oldId = ((IReferenceableInstance) oldValue).getId(); + Id newId = transientToNewIds.get(oldId); + newValue = newId == null ? oldId : newId; + } + + b.put(newKey, newValue); + } + return b.build(); + } + + @Override + public TypeCategory getTypeCategory() { + return TypeCategory.MAP; + } + } + +}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/DownCastFieldMapping.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/DownCastFieldMapping.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/DownCastFieldMapping.java new file mode 100755 index 0000000..0129b4b --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/DownCastFieldMapping.java @@ -0,0 +1,53 @@ +/** + * 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.atlas.typesystem.types; + +import com.google.common.collect.ImmutableMap; +import org.apache.atlas.MetadataException; +import org.apache.atlas.typesystem.persistence.DownCastStructInstance; + +public class DownCastFieldMapping { + + public final ImmutableMap<String, String> fieldNameMap; + + protected DownCastFieldMapping(ImmutableMap<String, String> fieldNameMap) { + this.fieldNameMap = fieldNameMap; + } + + public void set(DownCastStructInstance s, String attrName, Object val) + throws MetadataException { + + String mappedNm = fieldNameMap.get(attrName); + if (mappedNm == null) { + throw new ValueConversionException(s.getTypeName(), val, "Unknown field " + attrName); + } + + s.backingInstance.set(mappedNm, val); + } + + public Object get(DownCastStructInstance s, String attrName) throws MetadataException { + + String mappedNm = fieldNameMap.get(attrName); + if (mappedNm == null) { + throw new ValueConversionException( + String.format("Unknown field %s for Struct %s", attrName, s.getTypeName())); + } + return s.backingInstance.get(mappedNm); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumType.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumType.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumType.java new file mode 100755 index 0000000..299f78c --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumType.java @@ -0,0 +1,90 @@ +/** + * 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.atlas.typesystem.types; + +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableMap; +import org.apache.atlas.MetadataException; +import scala.math.BigInt; + +public class EnumType extends AbstractDataType<EnumValue> { + + public final TypeSystem typeSystem; + public final String name; + public final ImmutableMap<String, EnumValue> valueMap; + public final ImmutableMap<Integer, EnumValue> ordinalMap; + + protected EnumType(TypeSystem typeSystem, String name, EnumValue... values) { + this.typeSystem = typeSystem; + this.name = name; + ImmutableMap.Builder<String, EnumValue> b1 = new ImmutableMap.Builder(); + ImmutableMap.Builder<Integer, EnumValue> b2 = new ImmutableMap.Builder(); + for (EnumValue v : values) { + b1.put(v.value, v); + b2.put(v.ordinal, v); + } + valueMap = b1.build(); + ordinalMap = b2.build(); + } + + + @Override + public String getName() { + return name; + } + + @Override + public EnumValue convert(Object val, Multiplicity m) throws MetadataException { + if (val != null) { + EnumValue e = null; + if (val instanceof EnumValue) { + e = valueMap.get(((EnumValue)val).value); + } else if ( val instanceof Integer || val instanceof BigInt) { + e = ordinalMap.get(val); + } else if ( val instanceof String) { + e = valueMap.get(val); + } else if ( val instanceof Number ) { + e = ordinalMap.get(((Number)val).intValue()); + } + + if (e == null) { + throw new ValueConversionException(this, val); + } + return e; + } + return convertNull(m); + } + + @Override + public DataTypes.TypeCategory getTypeCategory() { + return DataTypes.TypeCategory.ENUM; + } + + public EnumValue fromOrdinal(int o) { + return ordinalMap.get(o); + } + + public EnumValue fromValue(String val) { + return valueMap.get(val.trim()); + } + + public ImmutableCollection<EnumValue> values() { + return valueMap.values(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumTypeDefinition.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumTypeDefinition.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumTypeDefinition.java new file mode 100755 index 0000000..15be1db --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumTypeDefinition.java @@ -0,0 +1,54 @@ +/** + * 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.atlas.typesystem.types; + +import org.apache.atlas.ParamChecker; + +import java.util.Arrays; + +public final class EnumTypeDefinition { + + public final String name; + public final EnumValue[] enumValues; + + public EnumTypeDefinition(String name, EnumValue... enumValues) { + this.name = ParamChecker.notEmpty(name, "Enum type name"); + this.enumValues = ParamChecker.notNullElements(enumValues, "Enum values"); + } + + @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; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumValue.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumValue.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumValue.java new file mode 100755 index 0000000..309257c --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/EnumValue.java @@ -0,0 +1,57 @@ +/** + * 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.atlas.typesystem.types; + +import org.apache.atlas.ParamChecker; + +public class EnumValue { + + public final String value; + public final int ordinal; + + public EnumValue(String value, int ordinal) { + this.value = ParamChecker.notEmpty(value, "Enum value"); + this.ordinal = ordinal; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + EnumValue enumValue = (EnumValue) o; + + if (ordinal != enumValue.ordinal) return false; + if (!value.equals(enumValue.value)) return false; + + return true; + } + + @Override + public int hashCode() { + int result = value.hashCode(); + result = 31 * result + ordinal; + return result; + } + + @Override + public String toString() { + return value; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/FieldMapping.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/FieldMapping.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/FieldMapping.java new file mode 100755 index 0000000..dba4600 --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/FieldMapping.java @@ -0,0 +1,135 @@ +/** + * 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.atlas.typesystem.types; + +import org.apache.atlas.MetadataException; +import org.apache.atlas.typesystem.IReferenceableInstance; +import org.apache.atlas.typesystem.IStruct; +import org.apache.atlas.typesystem.persistence.Id; + +import java.util.Map; + +public class FieldMapping { + + public final Map<String, AttributeInfo> fields; + public final Map<String, Integer> fieldPos; + public final Map<String, Integer> fieldNullPos; + public final int numBools; + public final int numBytes; + public final int numShorts; + public final int numInts; + public final int numLongs; + public final int numFloats; + public final int numDoubles; + public final int numBigInts; + public final int numBigDecimals; + public final int numDates; + public final int numStrings; + public final int numArrays; + public final int numMaps; + public final int numStructs; + public final int numReferenceables; + + public FieldMapping(Map<String, AttributeInfo> fields, Map<String, Integer> fieldPos, + Map<String, Integer> fieldNullPos, int numBools, int numBytes, + int numShorts, + int numInts, int numLongs, int numFloats, int numDoubles, int numBigInts, + int numBigDecimals, + int numDates, int numStrings, int numArrays, int numMaps, int numStructs, + int numReferenceables) { + this.fields = fields; + this.fieldPos = fieldPos; + this.fieldNullPos = fieldNullPos; + this.numBools = numBools; + this.numBytes = numBytes; + this.numShorts = numShorts; + this.numInts = numInts; + this.numLongs = numLongs; + this.numFloats = numFloats; + this.numDoubles = numDoubles; + this.numBigInts = numBigInts; + this.numBigDecimals = numBigDecimals; + this.numDates = numDates; + this.numStrings = numStrings; + this.numArrays = numArrays; + this.numMaps = numMaps; + this.numStructs = numStructs; + this.numReferenceables = numReferenceables; + } + + protected void outputFields(IStruct s, Appendable buf, String fieldPrefix) + throws MetadataException { + for (Map.Entry<String, AttributeInfo> e : fields.entrySet()) { + String attrName = e.getKey(); + AttributeInfo i = e.getValue(); + Object aVal = s.get(attrName); + TypeUtils.outputVal(attrName + " : ", buf, fieldPrefix); + if (aVal != null && aVal instanceof Id) { + TypeUtils.outputVal(aVal.toString(), buf, ""); + } else { + i.dataType().output(aVal, buf, fieldPrefix); + } + TypeUtils.outputVal("\n", buf, ""); + } + } + + public void output(IStruct s, Appendable buf, String prefix) throws MetadataException { + if (s == null) { + TypeUtils.outputVal("<null>\n", buf, ""); + return; + } + TypeUtils.outputVal("{", buf, prefix); + + TypeUtils.outputVal("\n", buf, ""); + String fieldPrefix = prefix + "\t"; + + outputFields(s, buf, fieldPrefix); + + TypeUtils.outputVal("}", buf, prefix); + } + + public void output(IReferenceableInstance s, Appendable buf, String prefix) + throws MetadataException { + if (s == null) { + TypeUtils.outputVal("<null>\n", buf, ""); + return; + } + TypeUtils.outputVal("{", buf, prefix); + + TypeUtils.outputVal("\n", buf, ""); + String fieldPrefix = prefix + "\t"; + + TypeUtils.outputVal("id : ", buf, fieldPrefix); + TypeUtils.outputVal(s.getId().toString(), buf, ""); + TypeUtils.outputVal("\n", buf, ""); + + outputFields(s, buf, fieldPrefix); + + TypeSystem ts = TypeSystem.getInstance(); + + for (String sT : s.getTraits()) { + TraitType tt = ts.getDataType(TraitType.class, sT); + TypeUtils.outputVal(sT + " : ", buf, fieldPrefix); + tt.output(s.getTrait(sT), buf, fieldPrefix); + } + + TypeUtils.outputVal("}", buf, prefix); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/HierarchicalType.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/HierarchicalType.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/HierarchicalType.java new file mode 100755 index 0000000..6eb5b16 --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/HierarchicalType.java @@ -0,0 +1,499 @@ +/** + * 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.atlas.typesystem.types; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.apache.atlas.MetadataException; +import org.apache.atlas.typesystem.IStruct; +import org.apache.atlas.typesystem.persistence.DownCastStructInstance; +import org.apache.atlas.typesystem.types.TypeUtils.Pair; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +/** + * Represents a Type that can have SuperTypes. An Instance of the HierarchicalType can be + * downcast to a SuperType. + * @param <ST> the Type of the SuperType. TraitTypes have TraitTypes as SuperTypes, ClassTypes + * have ClassTypes + * as SuperTypes. + * @param <T> the class of the Instance of this DataType. + */ +public abstract class HierarchicalType<ST extends HierarchicalType, T> extends AbstractDataType<T> + implements Comparable<ST> { + + public final TypeSystem typeSystem; + public final Class<ST> superTypeClass; + public final String name; + public final FieldMapping fieldMapping; + public final int numFields; + public final ImmutableList<String> superTypes; + public final ImmutableList<AttributeInfo> immediateAttrs; + public final ImmutableMap<String, String> attributeNameToType; + protected ImmutableMap<String, List<Path>> superTypePaths; + protected ImmutableMap<String, Path> pathNameToPathMap; + + /** + * Used when creating a Type, to support recursive Structs. + */ + HierarchicalType(TypeSystem typeSystem, Class<ST> superTypeClass, + String name, ImmutableList<String> superTypes, int numFields) { + this.typeSystem = typeSystem; + this.superTypeClass = superTypeClass; + this.name = name; + this.fieldMapping = null; + this.numFields = numFields; + this.superTypes = superTypes; + this.immediateAttrs = ImmutableList.of(); + this.attributeNameToType = null; + } + + HierarchicalType(TypeSystem typeSystem, Class<ST> superTypeClass, + String name, ImmutableList<String> superTypes, AttributeInfo... fields) + throws MetadataException { + this.typeSystem = typeSystem; + this.superTypeClass = superTypeClass; + this.name = name; + Pair<FieldMapping, ImmutableMap<String, String>> p = constructFieldMapping(superTypes, + fields); + this.fieldMapping = p.left; + this.attributeNameToType = p.right; + this.numFields = this.fieldMapping.fields.size(); + this.superTypes = superTypes == null ? ImmutableList.<String>of() : superTypes; + this.immediateAttrs = ImmutableList.copyOf(fields); + } + + @Override + public String getName() { + return name; + } + + public FieldMapping fieldMapping() { + return fieldMapping; + } + + /** + * Given type must be a SubType of this type. + * @param typeName + * @throws MetadataException + */ + public boolean isSubType(String typeName) throws MetadataException { + HierarchicalType cType = typeSystem.getDataType(HierarchicalType.class, typeName); + return (cType == this || cType.superTypePaths.containsKey(getName())); + } + + protected void setupSuperTypesGraph() + throws MetadataException { + setupSuperTypesGraph(superTypes); + } + + private void setupSuperTypesGraph(ImmutableList<String> superTypes) + throws MetadataException { + Map<String, List<Path>> superTypePaths = new HashMap<String, List<Path>>(); + Map<String, Path> pathNameToPathMap = new HashMap<String, Path>(); + Queue<Path> queue = new LinkedList<Path>(); + queue.add(new Node(getName())); + while (!queue.isEmpty()) { + Path currentPath = queue.poll(); + + ST superType = currentPath.typeName == getName() ? (ST) this : + (ST) typeSystem.getDataType(superTypeClass, currentPath.typeName); + + pathNameToPathMap.put(currentPath.pathName, currentPath); + if (superType != this) { + List<Path> typePaths = superTypePaths.get(superType.getName()); + if (typePaths == null) { + typePaths = new ArrayList<Path>(); + superTypePaths.put(superType.getName(), typePaths); + } + typePaths.add(currentPath); + } + + ImmutableList<String> sTs = superType == this ? superTypes : superType.superTypes; + + if (sTs != null) { + for (String sT : sTs) { + queue.add(new Path(sT, currentPath)); + } + } + } + + this.superTypePaths = ImmutableMap.copyOf(superTypePaths); + this.pathNameToPathMap = ImmutableMap.copyOf(pathNameToPathMap); + + } + + protected Pair<FieldMapping, ImmutableMap<String, String>> constructFieldMapping(ImmutableList<String> superTypes, + AttributeInfo... fields) + throws MetadataException { + + Map<String, AttributeInfo> fieldsMap = new LinkedHashMap<String, AttributeInfo>(); + Map<String, Integer> fieldPos = new HashMap<String, Integer>(); + Map<String, Integer> fieldNullPos = new HashMap<String, Integer>(); + Map<String, String> attributeNameToType = new HashMap<>(); + + int numBools = 0; + int numBytes = 0; + int numShorts = 0; + int numInts = 0; + int numLongs = 0; + int numFloats = 0; + int numDoubles = 0; + int numBigInts = 0; + int numBigDecimals = 0; + int numDates = 0; + int numStrings = 0; + int numArrays = 0; + int numMaps = 0; + int numStructs = 0; + int numReferenceables = 0; + + setupSuperTypesGraph(superTypes); + + Iterator<Path> pathItr = pathIterator(); + while (pathItr.hasNext()) { + Path currentPath = pathItr.next(); + + ST superType = currentPath.typeName == getName() ? (ST) this : + (ST) typeSystem.getDataType(superTypeClass, currentPath.typeName); + + ImmutableList<AttributeInfo> superTypeFields = superType == this ? + ImmutableList.copyOf(fields) : superType.immediateAttrs; + + Set<String> immediateFields = new HashSet<String>(); + + for (AttributeInfo i : superTypeFields) { + if (superType == this) { + if (immediateFields.contains(i.name)) { + throw new MetadataException( + String.format( + "Struct defintion cannot contain multiple fields with the" + + " same name %s", + i.name)); + } + immediateFields.add(i.name); + } + + String attrName = i.name; + if (fieldsMap.containsKey(attrName)) { + attrName = currentPath.addOverrideAttr(attrName); + } + attributeNameToType.put(attrName, superType.getName()); + + fieldsMap.put(attrName, i); + fieldNullPos.put(attrName, fieldNullPos.size()); + if (i.dataType() == DataTypes.BOOLEAN_TYPE) { + fieldPos.put(attrName, numBools); + numBools++; + } else if (i.dataType() == DataTypes.BYTE_TYPE) { + fieldPos.put(attrName, numBytes); + numBytes++; + } else if (i.dataType() == DataTypes.SHORT_TYPE) { + fieldPos.put(attrName, numShorts); + numShorts++; + } else if (i.dataType() == DataTypes.INT_TYPE) { + fieldPos.put(attrName, numInts); + numInts++; + } else if (i.dataType() == DataTypes.LONG_TYPE) { + fieldPos.put(attrName, numLongs); + numLongs++; + } else if (i.dataType() == DataTypes.FLOAT_TYPE) { + fieldPos.put(attrName, numFloats); + numFloats++; + } else if (i.dataType() == DataTypes.DOUBLE_TYPE) { + fieldPos.put(attrName, numDoubles); + numDoubles++; + } else if (i.dataType() == DataTypes.BIGINTEGER_TYPE) { + fieldPos.put(attrName, numBigInts); + numBigInts++; + } else if (i.dataType() == DataTypes.BIGDECIMAL_TYPE) { + fieldPos.put(attrName, numBigDecimals); + numBigDecimals++; + } else if (i.dataType() == DataTypes.DATE_TYPE) { + fieldPos.put(attrName, numDates); + numDates++; + } else if (i.dataType() == DataTypes.STRING_TYPE) { + fieldPos.put(attrName, numStrings); + numStrings++; + } else if (i.dataType().getTypeCategory() == DataTypes.TypeCategory.ENUM) { + fieldPos.put(i.name, numInts); + numInts++; + } else if (i.dataType().getTypeCategory() == DataTypes.TypeCategory.ARRAY) { + fieldPos.put(attrName, numArrays); + numArrays++; + } else if (i.dataType().getTypeCategory() == DataTypes.TypeCategory.MAP) { + fieldPos.put(attrName, numMaps); + numMaps++; + } else if (i.dataType().getTypeCategory() == DataTypes.TypeCategory.STRUCT || + i.dataType().getTypeCategory() == DataTypes.TypeCategory.TRAIT) { + fieldPos.put(attrName, numStructs); + numStructs++; + } else if (i.dataType().getTypeCategory() == DataTypes.TypeCategory.CLASS) { + fieldPos.put(attrName, numReferenceables); + numReferenceables++; + } else { + throw new MetadataException(String.format("Unknown datatype %s", i.dataType())); + } + } + } + + this.superTypePaths = ImmutableMap.copyOf(superTypePaths); + this.pathNameToPathMap = ImmutableMap.copyOf(pathNameToPathMap); + + FieldMapping fm = new FieldMapping(fieldsMap, + fieldPos, + fieldNullPos, + numBools, + numBytes, + numShorts, + numInts, + numLongs, + numFloats, + numDoubles, + numBigInts, + numBigDecimals, + numDates, + numStrings, + numArrays, + numMaps, + numStructs, + numReferenceables); + + return new Pair(fm, ImmutableMap.copyOf(attributeNameToType)); + } + + public IStruct castAs(IStruct s, String superTypeName) throws MetadataException { + + if (!superTypePaths.containsKey(superTypeName)) { + throw new MetadataException( + String.format("Cannot downcast to %s from type %s", superTypeName, getName())); + } + + if (s != null) { + if (s.getTypeName() != getName()) { + throw new MetadataException( + String.format("Downcast called on wrong type %s, instance type is %s", + getName(), s.getTypeName())); + } + + List<Path> pathToSuper = superTypePaths.get(superTypeName); + if (pathToSuper.size() > 1) { + throw new MetadataException( + String.format( + "Cannot downcast called to %s, from %s: there are multiple paths " + + "to SuperType", + superTypeName, getName())); + } + + ST superType = (ST) typeSystem.getDataType(superTypeClass, superTypeName); + Map<String, String> downCastMap = superType + .constructDowncastFieldMap(this, pathToSuper.get(0)); + return new DownCastStructInstance(superTypeName, + new DownCastFieldMapping(ImmutableMap.copyOf(downCastMap)), + s); + } + + return null; + } + + public ST getDefinedType(String attrName) throws MetadataException { + if (!attributeNameToType.containsKey(attrName)) { + throw new MetadataException(String.format("Unknown attribute %s in type %s", attrName, getName())); + } + return typeSystem.getDataType(superTypeClass, attributeNameToType.get(attrName)); + } + + public String getDefinedTypeName(String attrName) throws MetadataException { + return getDefinedType(attrName).getName(); + } + + public String getQualifiedName(String attrName) throws MetadataException { + String attrTypeName = getDefinedTypeName(attrName); + return attrName.contains(".") ? attrName : String.format("%s.%s", attrTypeName, attrName); + } + + protected Map<String, String> constructDowncastFieldMap(ST subType, Path pathToSubType) { + + String pathToSubTypeName = pathToSubType.pathAfterThis; + /* + * the downcastMap; + */ + Map<String, String> dCMap = new HashMap<String, String>(); + Iterator<Path> itr = pathIterator(); + while (itr.hasNext()) { + Path p = itr.next(); + Path pInSubType = (Path) subType.pathNameToPathMap + .get(p.pathName + "." + pathToSubTypeName); + + if (pInSubType.hiddenAttributeMap != null) { + for (Map.Entry<String, String> e : pInSubType.hiddenAttributeMap.entrySet()) { + String mappedInThisType = + p.hiddenAttributeMap != null ? p.hiddenAttributeMap.get(e.getKey()) + : null; + if (mappedInThisType == null) { + dCMap.put(e.getKey(), e.getValue()); + } else { + dCMap.put(mappedInThisType, e.getValue()); + } + } + } + } + return dCMap; + } + + @Override + public int compareTo(ST o) { + String oName = o.getName(); + if (superTypes.contains(oName)) { + return 1; + } else if (o.superTypes.contains(getName())) { + return -1; + } else { + return getName().compareTo(oName); + } + } + + public Set<String> getAllSuperTypeNames() { + return superTypePaths.keySet(); + } + + public Iterator<Path> pathIterator() { + return new PathItr(); + } + + static class Path { + public final String typeName; + public final String pathName; + public final String pathAfterThis; + private final Path subTypePath; + /* + * name mapping for attributes hidden by a SubType. + */ + Map<String, String> hiddenAttributeMap; + + Path(String typeName, Path childPath) throws MetadataException { + this.typeName = typeName; + this.subTypePath = childPath; + if (childPath.contains(typeName)) { + throw new CyclicTypeDefinition(this); + } + pathName = String.format("%s.%s", typeName, childPath.pathName); + pathAfterThis = childPath.pathName; + } + + Path(String typeName) { + assert getClass() == Node.class; + this.typeName = typeName; + this.subTypePath = null; + pathName = typeName; + pathAfterThis = null; + } + + public boolean contains(String typeName) { + return this.typeName.equals(typeName) || + (subTypePath != null && subTypePath.contains(typeName)); + } + + public String pathString(String nodeSep) { + + StringBuilder b = new StringBuilder(); + Path p = this; + + while (p != null) { + b.append(p.typeName); + p = p.subTypePath; + if (p != null) { + b.append(nodeSep); + } + } + return b.toString(); + } + + String addOverrideAttr(String name) { + hiddenAttributeMap = hiddenAttributeMap == null ? new HashMap<String, String>() + : hiddenAttributeMap; + String oName = pathName + "." + name; + hiddenAttributeMap.put(name, oName); + return oName; + } + } + + static class Node extends Path { + Node(String typeName) { + super(typeName); + } + } + + static class CyclicTypeDefinition extends MetadataException { + + CyclicTypeDefinition(Path p) { + super(String.format("Cycle in Type Definition %s", p.pathString(" -> "))); + } + } + + class PathItr implements Iterator<Path> { + + Queue<Path> pathQueue; + + PathItr() { + pathQueue = new LinkedList<Path>(); + pathQueue.add(pathNameToPathMap.get(getName())); + } + + @Override + public boolean hasNext() { + return !pathQueue.isEmpty(); + } + + @Override + public Path next() { + Path p = pathQueue.poll(); + ST t = null; + try { + t = (ST) typeSystem.getDataType(superTypeClass, p.typeName); + } catch (MetadataException me) { + throw new RuntimeException(me); + } + if (t.superTypes != null) { + ImmutableList<String> sTs = t.superTypes; + for (String sT : sTs) { + String nm = sT + "." + p.pathName; + pathQueue.add(pathNameToPathMap.get(nm)); + } + } + return p; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } + + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/HierarchicalTypeDefinition.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/HierarchicalTypeDefinition.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/HierarchicalTypeDefinition.java new file mode 100755 index 0000000..20569f1 --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/HierarchicalTypeDefinition.java @@ -0,0 +1,76 @@ +/** + * 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.atlas.typesystem.types; + +import com.google.common.collect.ImmutableList; +import org.apache.atlas.classification.InterfaceAudience; + +public class HierarchicalTypeDefinition<T extends HierarchicalType> extends StructTypeDefinition { + + public final ImmutableList<String> superTypes; + public final String hierarchicalMetaTypeName; + + /** + * Used for json deserialization only. + * not intended public consumption + * @param hierarchicalMetaTypeName + * @param typeName + * @param superTypes + * @param attributeDefinitions + * @throws ClassNotFoundException + */ + @InterfaceAudience.Private + 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, false, 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; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/IConstructableType.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/IConstructableType.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/IConstructableType.java new file mode 100755 index 0000000..6b9bd4c --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/IConstructableType.java @@ -0,0 +1,34 @@ +/** + * 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.atlas.typesystem.types; + + +import org.apache.atlas.MetadataException; +import org.apache.atlas.typesystem.ITypedInstance; + +import java.util.List; + +public interface IConstructableType<U, T extends ITypedInstance> extends IDataType<U> { + + T createInstance() throws MetadataException; + + FieldMapping fieldMapping(); + + List<String> getNames(AttributeInfo info); +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/IDataType.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/IDataType.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/IDataType.java new file mode 100755 index 0000000..e976362 --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/IDataType.java @@ -0,0 +1,31 @@ +/** + * 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.atlas.typesystem.types; + +import org.apache.atlas.MetadataException; + +public interface IDataType<T> { + String getName(); + + T convert(Object val, Multiplicity m) throws MetadataException; + + DataTypes.TypeCategory getTypeCategory(); + + void output(T val, Appendable buf, String prefix) throws MetadataException; +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/Multiplicity.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/Multiplicity.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/Multiplicity.java new file mode 100755 index 0000000..210c945 --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/Multiplicity.java @@ -0,0 +1,90 @@ +/** + * 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.atlas.typesystem.types; + +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; + +public final class Multiplicity { + + public static final Multiplicity OPTIONAL = new Multiplicity(0, 1, false); + public static final Multiplicity REQUIRED = new Multiplicity(1, 1, false); + public static final Multiplicity COLLECTION = new Multiplicity(1, Integer.MAX_VALUE, false); + public static final Multiplicity SET = new Multiplicity(1, Integer.MAX_VALUE, true); + + public final int lower; + public final int upper; + public final boolean isUnique; + public Multiplicity(int lower, int upper, boolean isUnique) { + assert lower >= 0; + assert upper >= 1; + assert upper >= lower; + this.lower = lower; + this.upper = upper; + this.isUnique = isUnique; + } + + public boolean nullAllowed() { + return lower == 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Multiplicity that = (Multiplicity) o; + + if (isUnique != that.isUnique) return false; + if (lower != that.lower) return false; + if (upper != that.upper) return false; + + return true; + } + + @Override + public int hashCode() { + int result = lower; + result = 31 * result + upper; + result = 31 * result + (isUnique ? 1 : 0); + return result; + } + + @Override + public String toString() { + return "Multiplicity{" + + "lower=" + lower + + ", upper=" + upper + + ", isUnique=" + isUnique + + '}'; + } + + public String toJson() throws JSONException { + JSONObject json = new JSONObject(); + json.put("lower", lower); + json.put("upper", upper); + json.put("isUnique", isUnique); + return json.toString(); + } + + public static Multiplicity fromJson(String jsonStr) throws JSONException { + JSONObject json = new JSONObject(jsonStr); + return new Multiplicity(json.getInt("lower"), json.getInt("upper"), json.getBoolean("isUnique")); + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/ObjectGraphTraversal.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/ObjectGraphTraversal.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/ObjectGraphTraversal.java new file mode 100755 index 0000000..5a302ed --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/ObjectGraphTraversal.java @@ -0,0 +1,198 @@ +/** + * 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.atlas.typesystem.types; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.apache.atlas.MetadataException; +import org.apache.atlas.typesystem.IReferenceableInstance; +import org.apache.atlas.typesystem.IStruct; +import org.apache.atlas.typesystem.persistence.Id; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +public class ObjectGraphTraversal implements Iterator<ObjectGraphTraversal.InstanceTuple> { + + final Queue<InstanceTuple> queue; + final TypeSystem typeSystem; + Set<Id> processedIds; + + public ObjectGraphTraversal(TypeSystem typeSystem, IReferenceableInstance start) + throws MetadataException { + this.typeSystem = typeSystem; + queue = new LinkedList<InstanceTuple>(); + processedIds = new HashSet<Id>(); + processReferenceableInstance(start); + } + + void processValue(IDataType dT, Object val) throws MetadataException { + if (val != null) { + if (dT.getTypeCategory() == DataTypes.TypeCategory.ARRAY) { + IDataType elemType = ((DataTypes.ArrayType) dT).getElemType(); + processCollection(elemType, val); + } else if (dT.getTypeCategory() == DataTypes.TypeCategory.MAP) { + IDataType keyType = ((DataTypes.MapType) dT).getKeyType(); + IDataType valueType = ((DataTypes.MapType) dT).getKeyType(); + processMap(keyType, valueType, val); + } else if (dT.getTypeCategory() == DataTypes.TypeCategory.STRUCT || + dT.getTypeCategory() == DataTypes.TypeCategory.TRAIT) { + processStruct(val); + } else if (dT.getTypeCategory() == DataTypes.TypeCategory.CLASS) { + processReferenceableInstance(val); + } + } + } + + void processMap(IDataType keyType, IDataType valueType, Object val) throws MetadataException { + if (keyType.getTypeCategory() == DataTypes.TypeCategory.PRIMITIVE && + valueType.getTypeCategory() == DataTypes.TypeCategory.PRIMITIVE) { + return; + } + + if (val != null) { + Iterator<Map.Entry> it = null; + if (Map.class.isAssignableFrom(val.getClass())) { + it = ((Map) val).entrySet().iterator(); + ImmutableMap.Builder b = ImmutableMap.builder(); + while (it.hasNext()) { + Map.Entry e = it.next(); + processValue(keyType, e.getKey()); + processValue(valueType, e.getValue()); + } + } + } + } + + void processCollection(IDataType elemType, Object val) throws MetadataException { + + if (elemType.getTypeCategory() == DataTypes.TypeCategory.PRIMITIVE) { + return; + } + + if (val != null) { + Iterator it = null; + if (val instanceof Collection) { + it = ((Collection) val).iterator(); + } else if (val instanceof Iterable) { + it = ((Iterable) val).iterator(); + } else if (val instanceof Iterator) { + it = (Iterator) val; + } + if (it != null) { + DataTypes.TypeCategory elemCategory = elemType.getTypeCategory(); + while (it.hasNext()) { + Object elem = it.next(); + processValue(elemType, elem); + } + } + } + } + + void processStruct(Object val) throws MetadataException { + + if (val == null || !(val instanceof IStruct)) { + return; + } + + IStruct i = (IStruct) val; + + IConstructableType type = typeSystem.getDataType(IConstructableType.class, i.getTypeName()); + + for (Map.Entry<String, AttributeInfo> e : type.fieldMapping().fields.entrySet()) { + AttributeInfo aInfo = e.getValue(); + String attrName = e.getKey(); + if (aInfo.dataType().getTypeCategory() != DataTypes.TypeCategory.PRIMITIVE) { + processValue(aInfo.dataType(), i.get(attrName)); + } + } + } + + void processReferenceableInstance(Object val) throws MetadataException { + + if (val == null || !(val instanceof IReferenceableInstance || val instanceof Id)) { + return; + } + + if (val instanceof Id) { + Id id = (Id) val; + if (id.isUnassigned()) { + add(id, null); + } + return; + } + + IReferenceableInstance ref = (IReferenceableInstance) val; + Id id = ref.getId(); + if (id.isUnassigned()) { + add(id, ref); + if (!processedIds.contains(id)) { + processedIds.add(id); + processStruct(val); + + ImmutableList<String> traits = ref.getTraits(); + for (String trait : traits) { + processStruct(ref.getTrait(trait)); + } + } + } + } + + void add(Id id, IReferenceableInstance ref) { + queue.add(new InstanceTuple(id, ref)); + } + + + @Override + public boolean hasNext() { + return !queue.isEmpty(); + } + + @Override + public InstanceTuple next() { + try { + InstanceTuple t = queue.poll(); + processReferenceableInstance(t.instance); + return t; + } catch (MetadataException me) { + throw new RuntimeException(me); + } + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + public static class InstanceTuple { + public final Id id; + public final IReferenceableInstance instance; + + public InstanceTuple(Id id, IReferenceableInstance instance) { + this.id = id; + this.instance = instance; + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/30711973/typesystem/src/main/java/org/apache/atlas/typesystem/types/ObjectGraphWalker.java ---------------------------------------------------------------------- diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/types/ObjectGraphWalker.java b/typesystem/src/main/java/org/apache/atlas/typesystem/types/ObjectGraphWalker.java new file mode 100755 index 0000000..7d51ae2 --- /dev/null +++ b/typesystem/src/main/java/org/apache/atlas/typesystem/types/ObjectGraphWalker.java @@ -0,0 +1,221 @@ +/** + * 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.atlas.typesystem.types; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.apache.atlas.MetadataException; +import org.apache.atlas.typesystem.IReferenceableInstance; +import org.apache.atlas.typesystem.IStruct; +import org.apache.atlas.typesystem.persistence.Id; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; + +/** + * Given a IReferenceableInstance, a Walker will traverse the Object Graph + * reachable form the instance. It will invoke the process call on the provided NodeProcessor + * for each non-primitive attribute (Structs, Traits, References, Arrays of Non-Primitives, Maps + * of Non-Primitives) + */ +public class ObjectGraphWalker { + + final Queue<IReferenceableInstance> queue; + final TypeSystem typeSystem; + final NodeProcessor nodeProcessor; + Set<Id> processedIds; + + public ObjectGraphWalker(TypeSystem typeSystem, NodeProcessor nodeProcessor) + throws MetadataException { + this(typeSystem, nodeProcessor, (IReferenceableInstance) null); + } + + public ObjectGraphWalker(TypeSystem typeSystem, NodeProcessor nodeProcessor, + IReferenceableInstance start) + throws MetadataException { + this.typeSystem = typeSystem; + this.nodeProcessor = nodeProcessor; + queue = new LinkedList<IReferenceableInstance>(); + processedIds = new HashSet<Id>(); + if (start != null) { + visitReferenceableInstance(start); + } + } + + public ObjectGraphWalker(TypeSystem typeSystem, NodeProcessor nodeProcessor, + List<? extends IReferenceableInstance> roots) + throws MetadataException { + this.typeSystem = typeSystem; + this.nodeProcessor = nodeProcessor; + queue = new LinkedList<IReferenceableInstance>(); + processedIds = new HashSet<Id>(); + for (IReferenceableInstance r : roots) { + visitReferenceableInstance(r); + } + } + + public void walk() throws MetadataException { + while (!queue.isEmpty()) { + IReferenceableInstance r = queue.poll(); + processReferenceableInstance(r); + } + } + + public void addRoot(IReferenceableInstance root) { + visitReferenceableInstance(root); + } + + void traverseValue(IDataType dT, Object val) throws MetadataException { + if (val != null) { + if (dT.getTypeCategory() == DataTypes.TypeCategory.ARRAY) { + IDataType elemType = ((DataTypes.ArrayType) dT).getElemType(); + visitCollection(elemType, val); + } else if (dT.getTypeCategory() == DataTypes.TypeCategory.MAP) { + IDataType keyType = ((DataTypes.MapType) dT).getKeyType(); + IDataType valueType = ((DataTypes.MapType) dT).getKeyType(); + visitMap(keyType, valueType, val); + } else if (dT.getTypeCategory() == DataTypes.TypeCategory.STRUCT || + dT.getTypeCategory() == DataTypes.TypeCategory.TRAIT) { + visitStruct(val); + } else if (dT.getTypeCategory() == DataTypes.TypeCategory.CLASS) { + visitReferenceableInstance(val); + } + } + } + + void visitMap(IDataType keyType, IDataType valueType, Object val) throws MetadataException { + if (keyType.getTypeCategory() == DataTypes.TypeCategory.PRIMITIVE && + valueType.getTypeCategory() == DataTypes.TypeCategory.PRIMITIVE) { + return; + } + + if (val != null) { + Iterator<Map.Entry> it = null; + if (Map.class.isAssignableFrom(val.getClass())) { + it = ((Map) val).entrySet().iterator(); + ImmutableMap.Builder b = ImmutableMap.builder(); + while (it.hasNext()) { + Map.Entry e = it.next(); + traverseValue(keyType, e.getKey()); + traverseValue(valueType, e.getValue()); + } + } + } + } + + void visitCollection(IDataType elemType, Object val) throws MetadataException { + + if (elemType.getTypeCategory() == DataTypes.TypeCategory.PRIMITIVE) { + return; + } + + if (val != null) { + Iterator it = null; + if (val instanceof Collection) { + it = ((Collection) val).iterator(); + } else if (val instanceof Iterable) { + it = ((Iterable) val).iterator(); + } else if (val instanceof Iterator) { + it = (Iterator) val; + } + if (it != null) { + DataTypes.TypeCategory elemCategory = elemType.getTypeCategory(); + while (it.hasNext()) { + Object elem = it.next(); + traverseValue(elemType, elem); + } + } + } + } + + void visitStruct(Object val) throws MetadataException { + + if (val == null || !(val instanceof IStruct)) { + return; + } + + IStruct i = (IStruct) val; + + IConstructableType type = typeSystem.getDataType(IConstructableType.class, i.getTypeName()); + + for (Map.Entry<String, AttributeInfo> e : type.fieldMapping().fields.entrySet()) { + AttributeInfo aInfo = e.getValue(); + String attrName = e.getKey(); + if (aInfo.dataType().getTypeCategory() != DataTypes.TypeCategory.PRIMITIVE) { + Object aVal = i.get(attrName); + nodeProcessor.processNode(new Node(i, attrName, aInfo, aVal)); + traverseValue(aInfo.dataType(), aVal); + } + } + } + + void visitReferenceableInstance(Object val) { + + if (val == null || !(val instanceof IReferenceableInstance)) { + return; + } + + IReferenceableInstance ref = (IReferenceableInstance) val; + + if (!processedIds.contains(ref.getId())) { + processedIds.add(ref.getId()); + if (!(ref instanceof Id)) { + queue.add(ref); + } + } + } + + void processReferenceableInstance(IReferenceableInstance ref) throws MetadataException { + + nodeProcessor.processNode(new Node(ref, null, null, null)); + visitStruct(ref); + ImmutableList<String> traits = ref.getTraits(); + for (String trait : traits) { + visitStruct(ref.getTrait(trait)); + } + } + + public static interface NodeProcessor { + + void processNode(Node nd) throws MetadataException; + } + + /** + * Represents a non-primitive value of an instance. + */ + public static class Node { + public final IStruct instance; + public final String attributeName; + public final AttributeInfo aInfo; + public final Object value; + + public Node(IStruct instance, String attributeName, AttributeInfo aInfo, Object value) { + this.instance = instance; + this.attributeName = attributeName; + this.aInfo = aInfo; + this.value = value; + } + } +}
