| /** |
| * 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.AtlasException; |
| import org.apache.atlas.typesystem.IReferenceableInstance; |
| import org.apache.atlas.typesystem.persistence.Id; |
| import org.apache.commons.lang3.StringUtils; |
| import org.joda.time.DateTime; |
| import org.joda.time.DateTimeZone; |
| import org.joda.time.format.DateTimeFormatter; |
| import org.joda.time.format.ISODateTimeFormat; |
| |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| import java.nio.charset.Charset; |
| import java.security.MessageDigest; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| 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(); |
| public static String ARRAY_TYPE_PREFIX = "array<"; |
| static String ARRAY_TYPE_SUFFIX = ">"; |
| public static String MAP_TYPE_PREFIX = "map<"; |
| static String MAP_TYPE_SUFFIX = ">"; |
| |
| public static String arrayTypeName(String elemTypeName) { |
| assert elemTypeName != null; |
| 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) { |
| assert keyType != null; |
| assert valueType != null; |
| return mapTypeName(keyType.getName(), valueType.getName()); |
| } |
| |
| public enum TypeCategory { |
| PRIMITIVE, |
| ENUM, |
| ARRAY, |
| MAP, |
| STRUCT, |
| TRAIT, |
| CLASS |
| } |
| |
| public static abstract class PrimitiveType<T> extends AbstractDataType<T> { |
| public PrimitiveType(String name, String description) { |
| super(name, description); |
| } |
| |
| @Override |
| public TypeCategory getTypeCategory() { |
| return TypeCategory.PRIMITIVE; |
| } |
| |
| public abstract T nullValue(); |
| |
| @Override |
| protected T convertNull(Multiplicity m) throws AtlasException { |
| if (!m.nullAllowed()) { |
| throw new ValueConversionException.NullConversionException(m); |
| } |
| |
| return nullValue(); |
| } |
| |
| @Override |
| public void updateSignatureHash(MessageDigest digester, Object val) throws AtlasException { |
| if ( val != null ) { |
| digester.update(val.toString().getBytes(Charset.forName("UTF-8"))); |
| } |
| } |
| |
| } |
| |
| public static class BooleanType extends PrimitiveType<Boolean> { |
| |
| private static final String name = "boolean".intern(); |
| |
| private BooleanType() { |
| super(name, null); |
| } |
| |
| @Override |
| public Boolean convert(Object val, Multiplicity m) throws AtlasException { |
| 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() { |
| super(name, null); |
| } |
| |
| @Override |
| public Byte convert(Object val, Multiplicity m) throws AtlasException { |
| 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; |
| } |
| |
| @Override |
| public void updateSignatureHash(MessageDigest digester, Object val) throws AtlasException { |
| if ( val != null ) { |
| digester.update((Byte) val); |
| } |
| } |
| } |
| |
| public static class ShortType extends PrimitiveType<Short> { |
| |
| private static final String name = "short".intern(); |
| |
| private ShortType() { |
| super(name, null); |
| } |
| |
| @Override |
| public Short convert(Object val, Multiplicity m) throws AtlasException { |
| 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() { |
| super(name, null); |
| } |
| |
| @Override |
| public Integer convert(Object val, Multiplicity m) throws AtlasException { |
| 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() { |
| super(name, null); |
| } |
| |
| @Override |
| public Long convert(Object val, Multiplicity m) throws AtlasException { |
| 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() { |
| super(name, null); |
| } |
| |
| @Override |
| public Float convert(Object val, Multiplicity m) throws AtlasException { |
| 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() { |
| super(name, null); |
| } |
| |
| @Override |
| public Double convert(Object val, Multiplicity m) throws AtlasException { |
| 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() { |
| super(name, null); |
| } |
| |
| @Override |
| public BigInteger convert(Object val, Multiplicity m) throws AtlasException { |
| 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() { |
| super(name, null); |
| } |
| |
| @Override |
| public BigDecimal convert(Object val, Multiplicity m) throws AtlasException { |
| 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() { |
| super(name, null); |
| } |
| |
| private static final DateTimeFormatter utcDateFormat = ISODateTimeFormat.dateTime(); |
| |
| @Override |
| public Date convert(Object val, Multiplicity m) throws AtlasException { |
| if (val != null) { |
| if (val instanceof Date) { |
| return (Date) val; |
| } else if (val instanceof String) { |
| try { |
| return utcDateFormat.parseDateTime((String)val).toDate(); |
| } catch (Exception 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, Set<Date> inProcess) throws AtlasException { |
| TypeUtils.outputVal(val == null ? "<null>" : utcDateFormat.print(new DateTime(val).withZone(DateTimeZone.UTC)), buf, |
| prefix); |
| } |
| |
| public Date nullValue() { |
| return null; |
| } |
| } |
| |
| public static class StringType extends PrimitiveType<String> { |
| |
| private static final String name = "string".intern(); |
| |
| private StringType() { |
| super(name, null); |
| } |
| |
| @Override |
| public String convert(Object val, Multiplicity m) throws AtlasException { |
| if (val != null && (!(val instanceof String) || StringUtils.isNotEmpty((CharSequence) val))) { |
| return val.toString(); |
| } |
| |
| if (m.nullAllowed() && val != null){ |
| return val.toString(); |
| } |
| return convertNull(m); |
| } |
| |
| public String nullValue() { |
| return null; |
| } |
| } |
| |
| public static class ArrayType extends AbstractDataType<ImmutableCollection<?>> { |
| private IDataType elemType; |
| |
| public ArrayType(IDataType elemType) { |
| super(arrayTypeName(elemType), null); |
| this.elemType = elemType; |
| } |
| |
| public IDataType getElemType() { |
| return elemType; |
| } |
| |
| protected void setElemType(IDataType elemType) { |
| this.elemType = elemType; |
| } |
| |
| @Override |
| public ImmutableCollection<?> convert(Object val, Multiplicity m) throws AtlasException { |
| 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 AtlasException { |
| |
| if (val == null || elemType.getTypeCategory() != TypeCategory.CLASS) { |
| return val; |
| } |
| ImmutableCollection.Builder b = m.isUnique ? ImmutableSet.builder() : ImmutableList.builder(); |
| for (Object elem : val) { |
| 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; |
| } |
| |
| @Override |
| public void updateSignatureHash(MessageDigest digester, Object val) throws AtlasException { |
| IDataType elemType = getElemType(); |
| List vals = (List) val; |
| for (Object listElem : vals) { |
| elemType.updateSignatureHash(digester, listElem); |
| } |
| } |
| } |
| |
| public static class MapType extends AbstractDataType<ImmutableMap<?, ?>> { |
| |
| private IDataType keyType; |
| private IDataType valueType; |
| |
| public MapType(IDataType keyType, IDataType valueType) { |
| super(mapTypeName(keyType, valueType), null); |
| this.keyType = keyType; |
| this.valueType = 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.valueType = valueType; |
| } |
| |
| @Override |
| public ImmutableMap<?, ?> convert(Object val, Multiplicity m) throws AtlasException { |
| 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(), Multiplicity.OPTIONAL)); |
| } |
| 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 AtlasException { |
| |
| if (val == null || (keyType.getTypeCategory() != TypeCategory.CLASS |
| && valueType.getTypeCategory() != TypeCategory.CLASS)) { |
| return val; |
| } |
| ImmutableMap.Builder b = ImmutableMap.builder(); |
| for (Map.Entry elem : (Iterable<Map.Entry>) val.entrySet()) { |
| 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; |
| } |
| |
| @Override |
| public void updateSignatureHash(MessageDigest digester, Object val) throws AtlasException { |
| IDataType keyType = getKeyType(); |
| IDataType valueType = getValueType(); |
| Map vals = (Map) val; |
| for (Object key : vals.keySet()) { |
| keyType.updateSignatureHash(digester, key); |
| valueType.updateSignatureHash(digester, vals.get(key)); |
| } |
| } |
| } |
| |
| } |