atlas-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From venkat...@apache.org
Subject [16/58] [abbrv] incubator-atlas git commit: Refactor packages and scripts to Atlas (cherry picked from commit 414beba)
Date Tue, 16 Jun 2015 23:04:50 GMT
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;
+        }
+    }
+}


Mime
View raw message