blob: e0d37336318512e5cf204746783e62a47c915803 [file] [log] [blame]
/**
* 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) {
if (TypeSystem.this.isRegistered(eDef.name)) {
throw new TypeExistsException(String.format("Redefinition of type %s is not supported", eDef.name));
} else if (transientTypes.containsKey(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) {
if (TypeSystem.this.isRegistered(sDef.typeName)) {
throw new TypeExistsException(String.format("Redefinition of type %s is not supported", sDef.typeName));
} else if (transientTypes.containsKey(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) {
if (TypeSystem.this.isRegistered(traitDef.typeName)) {
throw new TypeExistsException(String.format("Redefinition of type %s is not supported", traitDef.typeName));
} else if (transientTypes.containsKey(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) {
if (TypeSystem.this.isRegistered(classDef.typeName)) {
throw new TypeExistsException(String.format("Redefinition of type %s is not supported", classDef.typeName));
} else if (transientTypes.containsKey(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;
}