| /** |
| * 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.ImmutableSet; |
| import org.apache.atlas.AtlasException; |
| import org.apache.atlas.classification.InterfaceAudience; |
| import org.apache.atlas.typesystem.TypesDef; |
| import org.apache.atlas.typesystem.exception.TypeExistsException; |
| import org.apache.atlas.typesystem.exception.TypeNotFoundException; |
| import org.apache.atlas.typesystem.types.cache.DefaultTypeCache; |
| import org.apache.atlas.typesystem.types.cache.TypeCache; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import javax.inject.Singleton; |
| import java.lang.reflect.Constructor; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TimeZone; |
| import java.util.concurrent.ConcurrentHashMap; |
| |
| @Singleton |
| @InterfaceAudience.Private |
| public class TypeSystem { |
| private static final Logger LOG = LoggerFactory.getLogger(TypeSystem.class); |
| |
| private static final TypeSystem INSTANCE = new TypeSystem(); |
| private static ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>() { |
| @Override |
| public SimpleDateFormat initialValue() { |
| SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); |
| dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); |
| return dateFormat; |
| } |
| }; |
| |
| private TypeCache typeCache = new DefaultTypeCache(); |
| private IdType idType; |
| private Map<String, IDataType> coreTypes; |
| |
| public TypeSystem() { |
| initialize(); |
| } |
| |
| public static TypeSystem getInstance() { |
| return INSTANCE; |
| } |
| |
| /** |
| * This is only used for testing purposes. Not intended for public use. |
| */ |
| @InterfaceAudience.Private |
| public TypeSystem reset() { |
| |
| typeCache.clear(); // clear all entries in cache |
| initialize(); |
| |
| return this; |
| } |
| |
| public void setTypeCache(TypeCache typeCache) { |
| this.typeCache = typeCache; |
| } |
| |
| private void initialize() { |
| |
| coreTypes = new ConcurrentHashMap<>(); |
| |
| registerPrimitiveTypes(); |
| registerCoreTypes(); |
| } |
| |
| public ImmutableList<String> getCoreTypes() { |
| return ImmutableList.copyOf(coreTypes.keySet()); |
| } |
| |
| public ImmutableList<String> getTypeNames() throws AtlasException { |
| List<String> typeNames = new ArrayList<>(typeCache.getAllTypeNames()); |
| return ImmutableList.copyOf(typeNames); |
| } |
| |
| public ImmutableList<String> getTypeNamesByCategory(final DataTypes.TypeCategory typeCategory) throws AtlasException { |
| return getTypeNames(new HashMap<TypeCache.TYPE_FILTER, String>() {{ |
| put(TypeCache.TYPE_FILTER.CATEGORY, typeCategory.name()); |
| }}); |
| } |
| |
| public ImmutableList<String> getTypeNames(Map<TypeCache.TYPE_FILTER, String> filterMap) throws AtlasException { |
| return ImmutableList.copyOf(typeCache.getTypeNames(filterMap)); |
| } |
| |
| private void registerPrimitiveTypes() { |
| coreTypes.put(DataTypes.BOOLEAN_TYPE.getName(), DataTypes.BOOLEAN_TYPE); |
| coreTypes.put(DataTypes.BYTE_TYPE.getName(), DataTypes.BYTE_TYPE); |
| coreTypes.put(DataTypes.SHORT_TYPE.getName(), DataTypes.SHORT_TYPE); |
| coreTypes.put(DataTypes.INT_TYPE.getName(), DataTypes.INT_TYPE); |
| coreTypes.put(DataTypes.LONG_TYPE.getName(), DataTypes.LONG_TYPE); |
| coreTypes.put(DataTypes.FLOAT_TYPE.getName(), DataTypes.FLOAT_TYPE); |
| coreTypes.put(DataTypes.DOUBLE_TYPE.getName(), DataTypes.DOUBLE_TYPE); |
| coreTypes.put(DataTypes.BIGINTEGER_TYPE.getName(), DataTypes.BIGINTEGER_TYPE); |
| coreTypes.put(DataTypes.BIGDECIMAL_TYPE.getName(), DataTypes.BIGDECIMAL_TYPE); |
| coreTypes.put(DataTypes.DATE_TYPE.getName(), DataTypes.DATE_TYPE); |
| coreTypes.put(DataTypes.STRING_TYPE.getName(), DataTypes.STRING_TYPE); |
| } |
| |
| /* |
| * The only core OOB type we will define is the Struct to represent the Identity of an Instance. |
| */ |
| private void registerCoreTypes() { |
| |
| idType = new IdType(); |
| coreTypes.put(idType.getStructType().getName(), idType.getStructType()); |
| } |
| |
| public IdType getIdType() { |
| return idType; |
| } |
| |
| public boolean isRegistered(String typeName) throws AtlasException { |
| return isCoreType(typeName) || typeCache.has(typeName); |
| } |
| |
| protected boolean isCoreType(String typeName) { |
| |
| return coreTypes.containsKey(typeName); |
| } |
| |
| public <T> T getDataType(Class<T> cls, String name) throws AtlasException { |
| if (isCoreType(name)) { |
| return cls.cast(coreTypes.get(name)); |
| } |
| |
| if (typeCache.has(name)) { |
| try { |
| return cls.cast(typeCache.get(name)); |
| } catch (ClassCastException cce) { |
| throw new AtlasException(cce); |
| } |
| } |
| |
| /* |
| * is this an Array Type? |
| */ |
| String arrElemType = TypeUtils.parseAsArrayType(name); |
| if (arrElemType != null) { |
| IDataType dT = defineArrayType(getDataType(IDataType.class, arrElemType)); |
| return cls.cast(dT); |
| } |
| |
| /* |
| * is this a Map Type? |
| */ |
| String[] mapType = TypeUtils.parseAsMapType(name); |
| if (mapType != null) { |
| IDataType dT = |
| defineMapType(getDataType(IDataType.class, mapType[0]), getDataType(IDataType.class, mapType[1])); |
| return cls.cast(dT); |
| } |
| |
| /* |
| * Invoke cache callback to possibly obtain type from other storage. |
| */ |
| IDataType dT = typeCache.onTypeFault(name); |
| if (dT != null) { |
| return cls.cast(dT); |
| } |
| |
| throw new TypeNotFoundException(String.format("Unknown datatype: %s", name)); |
| } |
| |
| public StructType defineStructType(String name, boolean errorIfExists, AttributeDefinition... attrDefs) |
| throws AtlasException { |
| return defineStructType(name, null, errorIfExists, attrDefs); |
| } |
| |
| public StructType defineStructType(String name, String description, boolean errorIfExists, AttributeDefinition... attrDefs) |
| throws AtlasException { |
| StructTypeDefinition structDef = new StructTypeDefinition(name, description, attrDefs); |
| defineTypes(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.of(structDef), |
| ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(), |
| ImmutableList.<HierarchicalTypeDefinition<ClassType>>of()); |
| return getDataType(StructType.class, structDef.typeName); |
| } |
| |
| /** |
| * construct a temporary StructType for a Query Result. This is not registered in the |
| * typeSystem. |
| * The attributes in the typeDefinition can only reference permanent types. |
| * @param name struct type name |
| * @param attrDefs struct type definition |
| * @return temporary struct type |
| * @throws AtlasException |
| */ |
| public StructType defineQueryResultType(String name, Map<String, IDataType> tempTypes, |
| AttributeDefinition... attrDefs) throws AtlasException { |
| |
| AttributeInfo[] infos = new AttributeInfo[attrDefs.length]; |
| for (int i = 0; i < attrDefs.length; i++) { |
| infos[i] = new AttributeInfo(this, attrDefs[i], tempTypes); |
| } |
| |
| return new StructType(this, name, null, infos); |
| } |
| |
| public TraitType defineTraitType(HierarchicalTypeDefinition<TraitType> traitDef) throws AtlasException { |
| defineTypes(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(), |
| ImmutableList.of(traitDef), ImmutableList.<HierarchicalTypeDefinition<ClassType>>of()); |
| return getDataType(TraitType.class, traitDef.typeName); |
| } |
| |
| public ClassType defineClassType(HierarchicalTypeDefinition<ClassType> classDef) throws AtlasException { |
| defineTypes(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(), |
| ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(), ImmutableList.of(classDef)); |
| return getDataType(ClassType.class, classDef.typeName); |
| } |
| |
| public Map<String, IDataType> defineTraitTypes(HierarchicalTypeDefinition<TraitType>... traitDefs) |
| throws AtlasException { |
| TransientTypeSystem transientTypes = |
| new TransientTypeSystem(ImmutableList.<EnumTypeDefinition>of(), |
| ImmutableList.<StructTypeDefinition>of(), ImmutableList.copyOf(traitDefs), |
| ImmutableList.<HierarchicalTypeDefinition<ClassType>>of()); |
| return transientTypes.defineTypes(false); |
| } |
| |
| public Map<String, IDataType> defineClassTypes(HierarchicalTypeDefinition<ClassType>... classDefs) |
| throws AtlasException { |
| TransientTypeSystem transientTypes = new TransientTypeSystem(ImmutableList.<EnumTypeDefinition>of(), |
| ImmutableList.<StructTypeDefinition>of(), ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(), |
| ImmutableList.copyOf(classDefs)); |
| return transientTypes.defineTypes(false); |
| } |
| |
| public Map<String, IDataType> updateTypes(TypesDef typesDef) throws AtlasException { |
| ImmutableList<EnumTypeDefinition> enumDefs = ImmutableList.copyOf(typesDef.enumTypesAsJavaList()); |
| ImmutableList<StructTypeDefinition> structDefs = ImmutableList.copyOf(typesDef.structTypesAsJavaList()); |
| ImmutableList<HierarchicalTypeDefinition<TraitType>> traitDefs = |
| ImmutableList.copyOf(typesDef.traitTypesAsJavaList()); |
| ImmutableList<HierarchicalTypeDefinition<ClassType>> classDefs = |
| ImmutableList.copyOf(typesDef.classTypesAsJavaList()); |
| |
| TransientTypeSystem transientTypes = new TransientTypeSystem(enumDefs, structDefs, traitDefs, classDefs); |
| return transientTypes.defineTypes(true); |
| } |
| |
| public Map<String, IDataType> defineTypes(TypesDef typesDef) throws AtlasException { |
| ImmutableList<EnumTypeDefinition> enumDefs = ImmutableList.copyOf(typesDef.enumTypesAsJavaList()); |
| ImmutableList<StructTypeDefinition> structDefs = ImmutableList.copyOf(typesDef.structTypesAsJavaList()); |
| ImmutableList<HierarchicalTypeDefinition<TraitType>> traitDefs = |
| ImmutableList.copyOf(typesDef.traitTypesAsJavaList()); |
| ImmutableList<HierarchicalTypeDefinition<ClassType>> classDefs = |
| ImmutableList.copyOf(typesDef.classTypesAsJavaList()); |
| |
| return defineTypes(enumDefs, structDefs, traitDefs, classDefs); |
| } |
| |
| public Map<String, IDataType> defineTypes(ImmutableList<EnumTypeDefinition> enumDefs, |
| ImmutableList<StructTypeDefinition> structDefs, |
| ImmutableList<HierarchicalTypeDefinition<TraitType>> traitDefs, |
| ImmutableList<HierarchicalTypeDefinition<ClassType>> classDefs) throws AtlasException { |
| TransientTypeSystem transientTypes = new TransientTypeSystem(enumDefs, structDefs, traitDefs, classDefs); |
| return transientTypes.defineTypes(false); |
| } |
| |
| public DataTypes.ArrayType defineArrayType(IDataType elemType) throws AtlasException { |
| assert elemType != null; |
| DataTypes.ArrayType dT = new DataTypes.ArrayType(elemType); |
| return dT; |
| } |
| |
| public DataTypes.MapType defineMapType(IDataType keyType, IDataType valueType) throws AtlasException { |
| assert keyType != null; |
| assert valueType != null; |
| DataTypes.MapType dT = new DataTypes.MapType(keyType, valueType); |
| return dT; |
| } |
| |
| public EnumType defineEnumType(String name, EnumValue... values) throws AtlasException { |
| return defineEnumType(new EnumTypeDefinition(name, values)); |
| } |
| |
| public EnumType defineEnumType(String name, String description, EnumValue... values) throws AtlasException { |
| return defineEnumType(new EnumTypeDefinition(name, description, values)); |
| } |
| |
| public EnumType defineEnumType(EnumTypeDefinition eDef) throws AtlasException { |
| assert eDef.name != null; |
| if (isRegistered(eDef.name)) { |
| throw new AtlasException(String.format("Redefinition of type %s not supported", eDef.name)); |
| } |
| |
| EnumType eT = new EnumType(this, eDef.name, eDef.description, eDef.enumValues); |
| typeCache.put(eT); |
| return eT; |
| } |
| |
| public SimpleDateFormat getDateFormat() { |
| return dateFormat.get(); |
| } |
| |
| public boolean allowNullsInCollections() { |
| return false; |
| } |
| |
| /** |
| * Create an instance of {@link TransientTypeSystem} with the types defined in the {@link TypesDef}. |
| * |
| * As part of this, a set of verifications are run on the types defined. |
| * @param typesDef The new list of types to be created or updated. |
| * @param isUpdate True, if types are updated, false otherwise. |
| * @return {@link TransientTypeSystem} that holds the newly added types. |
| * @throws AtlasException |
| */ |
| public TransientTypeSystem createTransientTypeSystem(TypesDef typesDef, boolean isUpdate) throws AtlasException { |
| ImmutableList<EnumTypeDefinition> enumDefs = ImmutableList.copyOf(typesDef.enumTypesAsJavaList()); |
| ImmutableList<StructTypeDefinition> structDefs = ImmutableList.copyOf(typesDef.structTypesAsJavaList()); |
| ImmutableList<HierarchicalTypeDefinition<TraitType>> traitDefs = |
| ImmutableList.copyOf(typesDef.traitTypesAsJavaList()); |
| ImmutableList<HierarchicalTypeDefinition<ClassType>> classDefs = |
| ImmutableList.copyOf(typesDef.classTypesAsJavaList()); |
| TransientTypeSystem transientTypeSystem = new TransientTypeSystem(enumDefs, structDefs, traitDefs, classDefs); |
| transientTypeSystem.verifyTypes(isUpdate); |
| return transientTypeSystem; |
| } |
| |
| /** |
| * Commit the given types to this {@link TypeSystem} instance. |
| * |
| * This step should be called only after the types have been committed to the backend stores successfully. |
| * @param typesAdded newly added types. |
| * @throws AtlasException |
| */ |
| public void commitTypes(Map<String, IDataType> typesAdded) throws AtlasException { |
| for (Map.Entry<String, IDataType> typeEntry : typesAdded.entrySet()) { |
| IDataType type = typeEntry.getValue(); |
| //Add/replace the new type in the typesystem |
| typeCache.put(type); |
| } |
| } |
| |
| public class TransientTypeSystem extends TypeSystem { |
| |
| final ImmutableList<StructTypeDefinition> structDefs; |
| final ImmutableList<HierarchicalTypeDefinition<TraitType>> traitDefs; |
| final ImmutableList<HierarchicalTypeDefinition<ClassType>> classDefs; |
| private final ImmutableList<EnumTypeDefinition> enumDefs; |
| |
| Map<String, StructTypeDefinition> structNameToDefMap = new HashMap<>(); |
| Map<String, HierarchicalTypeDefinition<TraitType>> traitNameToDefMap = new HashMap<>(); |
| Map<String, HierarchicalTypeDefinition<ClassType>> classNameToDefMap = new HashMap<>(); |
| |
| Map<String, IDataType> transientTypes = null; |
| |
| List<AttributeInfo> recursiveRefs = new ArrayList<>(); |
| List<DataTypes.ArrayType> recursiveArrayTypes = new ArrayList<>(); |
| List<DataTypes.MapType> recursiveMapTypes = new ArrayList<>(); |
| |
| |
| TransientTypeSystem(ImmutableList<EnumTypeDefinition> enumDefs, ImmutableList<StructTypeDefinition> structDefs, |
| ImmutableList<HierarchicalTypeDefinition<TraitType>> traitDefs, |
| ImmutableList<HierarchicalTypeDefinition<ClassType>> classDefs) { |
| this.enumDefs = enumDefs; |
| this.structDefs = structDefs; |
| this.traitDefs = traitDefs; |
| this.classDefs = classDefs; |
| transientTypes = new HashMap<>(); |
| } |
| |
| private IDataType dataType(String name) throws AtlasException { |
| if (transientTypes.containsKey(name)) { |
| return transientTypes.get(name); |
| } |
| |
| return TypeSystem.this.getDataType(IDataType.class, name); |
| } |
| |
| /* |
| * Step 1: |
| * - validate cannot redefine types |
| * - setup shallow Type instances to facilitate recursive type graphs |
| */ |
| private void validateAndSetupShallowTypes(boolean update) throws AtlasException { |
| for (EnumTypeDefinition eDef : enumDefs) { |
| assert eDef.name != null; |
| if (!update && isRegistered(eDef.name)) { |
| LOG.warn("Found duplicate definition of type {}. Ignoring..", eDef.name); |
| continue; |
| } |
| |
| EnumType eT = new EnumType(this, eDef.name, eDef.description, eDef.enumValues); |
| transientTypes.put(eDef.name, eT); |
| } |
| |
| for (StructTypeDefinition sDef : structDefs) { |
| assert sDef.typeName != null; |
| if (!update && isRegistered(sDef.typeName)) { |
| LOG.warn("Found duplicate definition of type {}. Ignoring..", sDef.typeName); |
| continue; |
| } |
| StructType sT = new StructType(this, sDef.typeName, sDef.typeDescription, sDef.attributeDefinitions.length); |
| structNameToDefMap.put(sDef.typeName, sDef); |
| transientTypes.put(sDef.typeName, sT); |
| } |
| |
| for (HierarchicalTypeDefinition<TraitType> traitDef : traitDefs) { |
| assert traitDef.typeName != null; |
| if (!update && isRegistered(traitDef.typeName)) { |
| LOG.warn("Found duplicate definition of type {}. Ignoring..", traitDef.typeName); |
| continue; |
| } |
| TraitType tT = new TraitType(this, traitDef.typeName, traitDef.typeDescription, traitDef.superTypes, |
| traitDef.attributeDefinitions.length); |
| traitNameToDefMap.put(traitDef.typeName, traitDef); |
| transientTypes.put(traitDef.typeName, tT); |
| } |
| |
| for (HierarchicalTypeDefinition<ClassType> classDef : classDefs) { |
| assert classDef.typeName != null; |
| if (!update && isRegistered(classDef.typeName)) { |
| LOG.warn("Found duplicate definition of type {}. Ignoring..", classDef.typeName); |
| continue; |
| } |
| |
| ClassType cT = new ClassType(this, classDef.typeName, classDef.typeDescription, classDef.superTypes, |
| classDef.attributeDefinitions.length); |
| classNameToDefMap.put(classDef.typeName, classDef); |
| transientTypes.put(classDef.typeName, cT); |
| } |
| } |
| |
| @Override |
| public boolean isRegistered(String typeName) throws AtlasException { |
| return transientTypes.containsKey(typeName) || TypeSystem.this.isRegistered(typeName); |
| } |
| |
| private <U extends HierarchicalType> void validateSuperTypes(Class<U> cls, HierarchicalTypeDefinition<U> def) |
| throws AtlasException { |
| for (String superTypeName : def.superTypes) { |
| |
| IDataType dT = dataType(superTypeName); |
| |
| if (dT == null) { |
| throw new AtlasException( |
| String.format("Unknown superType %s in definition of type %s", superTypeName, |
| def.typeName)); |
| } |
| |
| if (!cls.isAssignableFrom(dT.getClass())) { |
| throw new AtlasException( |
| String.format("SuperType %s must be a %s, in definition of type %s", superTypeName, |
| cls.getName(), def.typeName)); |
| } |
| } |
| } |
| |
| /* |
| * Step 2: |
| * - for Hierarchical Types, validate SuperTypes. |
| * - for each Hierarchical Type setup their SuperTypes Graph |
| */ |
| private void validateAndSetupSuperTypes() throws AtlasException { |
| for (HierarchicalTypeDefinition<TraitType> traitDef : traitDefs) { |
| validateSuperTypes(TraitType.class, traitDef); |
| TraitType traitType = getDataType(TraitType.class, traitDef.typeName); |
| traitType.setupSuperTypesGraph(); |
| } |
| |
| for (HierarchicalTypeDefinition<ClassType> classDef : classDefs) { |
| validateSuperTypes(ClassType.class, classDef); |
| ClassType classType = getDataType(ClassType.class, classDef.typeName); |
| classType.setupSuperTypesGraph(); |
| } |
| } |
| |
| private AttributeInfo constructAttributeInfo(AttributeDefinition attrDef) throws AtlasException { |
| AttributeInfo info = new AttributeInfo(this, attrDef, null); |
| if (transientTypes.keySet().contains(attrDef.dataTypeName)) { |
| recursiveRefs.add(info); |
| } |
| if (info.dataType().getTypeCategory() == DataTypes.TypeCategory.ARRAY) { |
| DataTypes.ArrayType arrType = (DataTypes.ArrayType) info.dataType(); |
| if (transientTypes.keySet().contains(arrType.getElemType().getName())) { |
| recursiveArrayTypes.add(arrType); |
| } |
| } |
| if (info.dataType().getTypeCategory() == DataTypes.TypeCategory.MAP) { |
| DataTypes.MapType mapType = (DataTypes.MapType) info.dataType(); |
| if (transientTypes.keySet().contains(mapType.getKeyType().getName())) { |
| recursiveMapTypes.add(mapType); |
| } else if (transientTypes.keySet().contains(mapType.getValueType().getName())) { |
| recursiveMapTypes.add(mapType); |
| } |
| } |
| |
| if (info.multiplicity.upper > 1 && !(info.dataType().getTypeCategory() == DataTypes.TypeCategory.MAP |
| || info.dataType().getTypeCategory() == DataTypes.TypeCategory.ARRAY)) { |
| throw new AtlasException( |
| String.format("A multiplicty of more than one requires a collection type for attribute '%s'", |
| info.name)); |
| } |
| |
| return info; |
| } |
| |
| private StructType constructStructureType(StructTypeDefinition def) throws AtlasException { |
| AttributeInfo[] infos = new AttributeInfo[def.attributeDefinitions.length]; |
| for (int i = 0; i < def.attributeDefinitions.length; i++) { |
| infos[i] = constructAttributeInfo(def.attributeDefinitions[i]); |
| } |
| |
| StructType type = new StructType(this, def.typeName, def.typeDescription, infos); |
| transientTypes.put(def.typeName, type); |
| return type; |
| } |
| |
| private <U extends HierarchicalType> U constructHierarchicalType(Class<U> cls, |
| HierarchicalTypeDefinition<U> def) throws AtlasException { |
| AttributeInfo[] infos = new AttributeInfo[def.attributeDefinitions.length]; |
| for (int i = 0; i < def.attributeDefinitions.length; i++) { |
| infos[i] = constructAttributeInfo(def.attributeDefinitions[i]); |
| } |
| |
| try { |
| Constructor<U> cons = cls.getDeclaredConstructor(TypeSystem.class, String.class, String.class, ImmutableSet.class, |
| AttributeInfo[].class); |
| U type = cons.newInstance(this, def.typeName, def.typeDescription, def.superTypes, infos); |
| transientTypes.put(def.typeName, type); |
| return type; |
| } catch (Exception e) { |
| e.printStackTrace(); |
| throw new AtlasException(String.format("Cannot construct Type of MetaType %s - %s", cls.getName(), def.typeName), e); |
| } |
| } |
| |
| /* |
| * Step 3: |
| * - Order Hierarchical Types in order of SuperType before SubType. |
| * - Construct all the Types |
| */ |
| private void orderAndConstructTypes() throws AtlasException { |
| |
| List<TraitType> traitTypes = new ArrayList<>(); |
| for (String traitTypeName : traitNameToDefMap.keySet()) { |
| traitTypes.add(getDataType(TraitType.class, traitTypeName)); |
| } |
| traitTypes = HierarchicalTypeDependencySorter.sortTypes(traitTypes); |
| |
| List<ClassType> classTypes = new ArrayList<>(); |
| for (String classTypeName : classNameToDefMap.keySet()) { |
| classTypes.add(getDataType(ClassType.class, classTypeName)); |
| } |
| classTypes = HierarchicalTypeDependencySorter.sortTypes(classTypes); |
| |
| for (StructTypeDefinition structDef : structDefs) { |
| constructStructureType(structDef); |
| } |
| |
| for (TraitType traitType : traitTypes) { |
| constructHierarchicalType(TraitType.class, traitNameToDefMap.get(traitType.getName())); |
| } |
| |
| for (ClassType classType : classTypes) { |
| constructHierarchicalType(ClassType.class, classNameToDefMap.get(classType.getName())); |
| } |
| } |
| |
| /* |
| * Step 4: |
| * - fix up references in recursive AttrInfo and recursive Collection Types. |
| */ |
| private void setupRecursiveTypes() throws AtlasException { |
| for (AttributeInfo info : recursiveRefs) { |
| info.setDataType(dataType(info.dataType().getName())); |
| } |
| for (DataTypes.ArrayType arrType : recursiveArrayTypes) { |
| arrType.setElemType(dataType(arrType.getElemType().getName())); |
| } |
| for (DataTypes.MapType mapType : recursiveMapTypes) { |
| mapType.setKeyType(dataType(mapType.getKeyType().getName())); |
| mapType.setValueType(dataType(mapType.getValueType().getName())); |
| } |
| } |
| |
| /** |
| * Step 5: |
| * - Validate that the update can be done |
| */ |
| private void validateUpdateIsPossible() throws TypeUpdateException, AtlasException { |
| //If the type is modified, validate that update can be done |
| for (IDataType newType : transientTypes.values()) { |
| IDataType oldType = null; |
| try { |
| oldType = TypeSystem.this.getDataType(IDataType.class, newType.getName()); |
| } catch (TypeNotFoundException e) { |
| LOG.debug("No existing type %s found - update OK", newType.getName()); |
| } |
| if (oldType != null) { |
| oldType.validateUpdate(newType); |
| } |
| } |
| } |
| |
| Map<String, IDataType> defineTypes(boolean update) throws AtlasException { |
| verifyTypes(update); |
| Map<String, IDataType> typesAdded = getTypesAdded(); |
| commitTypes(typesAdded); |
| return typesAdded; |
| } |
| |
| @Override |
| public ImmutableList<String> getTypeNames() throws AtlasException { |
| Set<String> typeNames = transientTypes.keySet(); |
| typeNames.addAll(TypeSystem.this.getTypeNames()); |
| return ImmutableList.copyOf(typeNames); |
| } |
| |
| //get from transient types. Else, from main type system |
| @Override |
| public <T> T getDataType(Class<T> cls, String name) throws AtlasException { |
| if (transientTypes != null) { |
| if (transientTypes.containsKey(name)) { |
| try { |
| return cls.cast(transientTypes.get(name)); |
| } catch (ClassCastException cce) { |
| throw new AtlasException(cce); |
| } |
| } |
| |
| /* |
| * is this an Array Type? |
| */ |
| String arrElemType = TypeUtils.parseAsArrayType(name); |
| if (arrElemType != null) { |
| IDataType dT = defineArrayType(getDataType(IDataType.class, arrElemType)); |
| return cls.cast(dT); |
| } |
| |
| /* |
| * is this a Map Type? |
| */ |
| String[] mapType = TypeUtils.parseAsMapType(name); |
| if (mapType != null) { |
| IDataType dT = |
| defineMapType(getDataType(IDataType.class, mapType[0]), getDataType(IDataType.class, mapType[1])); |
| return cls.cast(dT); |
| } |
| } |
| |
| return TypeSystem.this.getDataType(cls, name); |
| } |
| |
| @Override |
| public StructType defineStructType(String name, boolean errorIfExists, AttributeDefinition... attrDefs) |
| throws AtlasException { |
| throw new AtlasException("Internal Error: define type called on TransientTypeSystem"); |
| } |
| |
| @Override |
| public TraitType defineTraitType(HierarchicalTypeDefinition traitDef) throws AtlasException { |
| throw new AtlasException("Internal Error: define type called on TransientTypeSystem"); |
| } |
| |
| @Override |
| public ClassType defineClassType(HierarchicalTypeDefinition<ClassType> classDef) throws AtlasException { |
| throw new AtlasException("Internal Error: define type called on TransientTypeSystem"); |
| } |
| |
| @Override |
| public Map<String, IDataType> defineTypes(ImmutableList<EnumTypeDefinition> enumDefs, |
| ImmutableList<StructTypeDefinition> structDefs, |
| ImmutableList<HierarchicalTypeDefinition<TraitType>> traitDefs, |
| ImmutableList<HierarchicalTypeDefinition<ClassType>> classDefs) throws AtlasException { |
| throw new AtlasException("Internal Error: define type called on TransientTypeSystem"); |
| } |
| |
| @Override |
| public DataTypes.ArrayType defineArrayType(IDataType elemType) throws AtlasException { |
| return super.defineArrayType(elemType); |
| } |
| |
| @Override |
| public DataTypes.MapType defineMapType(IDataType keyType, IDataType valueType) throws AtlasException { |
| return super.defineMapType(keyType, valueType); |
| } |
| |
| void verifyTypes(boolean isUpdate) throws AtlasException { |
| validateAndSetupShallowTypes(isUpdate); |
| validateAndSetupSuperTypes(); |
| orderAndConstructTypes(); |
| setupRecursiveTypes(); |
| if (isUpdate) { |
| validateUpdateIsPossible(); |
| } |
| } |
| |
| @Override |
| public void commitTypes(Map<String, IDataType> typesAdded) throws AtlasException { |
| TypeSystem.this.commitTypes(typesAdded); |
| } |
| |
| public Map<String, IDataType> getTypesAdded() { |
| return new HashMap<>(transientTypes); |
| } |
| |
| /** |
| * The core types do not change and they are registered |
| * once in the main type system. |
| */ |
| @Override |
| public ImmutableList<String> getCoreTypes() { |
| return TypeSystem.this.getCoreTypes(); |
| } |
| } |
| |
| public class IdType { |
| private static final String ID_ATTRNAME = "guid"; |
| private static final String TYPENAME_ATTRNAME = "typeName"; |
| private static final String STATE_ATTRNAME = "state"; |
| private static final String TYP_NAME = "__IdType"; |
| |
| private StructType type; |
| |
| private IdType() { |
| AttributeDefinition idAttr = |
| new AttributeDefinition(ID_ATTRNAME, DataTypes.STRING_TYPE.getName(), Multiplicity.REQUIRED, false, |
| null); |
| AttributeDefinition typNmAttr = |
| new AttributeDefinition(TYPENAME_ATTRNAME, DataTypes.STRING_TYPE.getName(), Multiplicity.REQUIRED, |
| false, null); |
| AttributeDefinition stateAttr = |
| new AttributeDefinition(STATE_ATTRNAME, DataTypes.STRING_TYPE.getName(), Multiplicity.REQUIRED, |
| false, null); |
| try { |
| AttributeInfo[] infos = new AttributeInfo[3]; |
| infos[0] = new AttributeInfo(TypeSystem.this, idAttr, null); |
| infos[1] = new AttributeInfo(TypeSystem.this, typNmAttr, null); |
| infos[2] = new AttributeInfo(TypeSystem.this, stateAttr, null); |
| |
| type = new StructType(TypeSystem.this, TYP_NAME, null, infos); |
| } catch (AtlasException me) { |
| throw new RuntimeException(me); |
| } |
| } |
| |
| public StructType getStructType() { |
| return type; |
| } |
| |
| public String getName() { |
| return TYP_NAME; |
| } |
| |
| public String idAttrName() { |
| return ID_ATTRNAME; |
| } |
| |
| public String typeNameAttrName() { |
| return TYPENAME_ATTRNAME; |
| } |
| |
| public String stateAttrName() { |
| return STATE_ATTRNAME; |
| } |
| } |
| |
| public static final String ID_STRUCT_ID_ATTRNAME = IdType.ID_ATTRNAME; |
| public static final String ID_STRUCT_TYP_NAME = IdType.TYP_NAME; |
| } |