Commit 48477e20 by Madhan Neethiraj

ATLAS-1526: removed foreignKey/mappedFromRef constraints and brought back

legacy flags isComposite/reverseAttributeName using constraints ownedRef/inverseRef(attribute=attr1)
parent 5f508c97
...@@ -215,12 +215,9 @@ ...@@ -215,12 +215,9 @@
"name": "sd", "name": "sd",
"typeName": "hive_storagedesc", "typeName": "hive_storagedesc",
"cardinality": "SINGLE", "cardinality": "SINGLE",
"constraintDefs": [ "constraints": [
{ {
"type": "mappedFromRef", "type": "ownedRef"
"params": {
"refAttribute": "table"
}
} }
], ],
"isIndexable": false, "isIndexable": false,
...@@ -231,7 +228,11 @@ ...@@ -231,7 +228,11 @@
"name": "partitionKeys", "name": "partitionKeys",
"typeName": "array<hive_column>", "typeName": "array<hive_column>",
"cardinality": "SINGLE", "cardinality": "SINGLE",
"constraintDefs": [], "constraints": [
{
"type": "ownedRef"
}
],
"isIndexable": false, "isIndexable": false,
"isOptional": true, "isOptional": true,
"isUnique": false "isUnique": false
...@@ -248,7 +249,11 @@ ...@@ -248,7 +249,11 @@
"name": "columns", "name": "columns",
"typeName": "array<hive_column>", "typeName": "array<hive_column>",
"cardinality": "SINGLE", "cardinality": "SINGLE",
"constraintDefs": [], "constraints": [
{
"type": "ownedRef"
}
],
"isIndexable": false, "isIndexable": false,
"isOptional": true, "isOptional": true,
"isUnique": false "isUnique": false
...@@ -306,11 +311,11 @@ ...@@ -306,11 +311,11 @@
"name": "table", "name": "table",
"typeName": "hive_table", "typeName": "hive_table",
"cardinality": "SINGLE", "cardinality": "SINGLE",
"constraintDefs": [ "constraints": [
{ {
"type": "foreignKey", "type": "inverseRef",
"params": { "params": {
"onDelete": "cascade" "attribute": "sd"
} }
} }
], ],
...@@ -469,11 +474,11 @@ ...@@ -469,11 +474,11 @@
"name": "table", "name": "table",
"typeName": "hive_table", "typeName": "hive_table",
"cardinality": "SINGLE", "cardinality": "SINGLE",
"constraintDefs": [ "constraints": [
{ {
"type": "foreignKey", "type": "inverseRef",
"params": { "params": {
"onDelete": "cascade" "attribute": "columns"
} }
} }
], ],
......
...@@ -17,7 +17,20 @@ ...@@ -17,7 +17,20 @@
"isIndexable": false, "isIndexable": false,
"isOptional": false, "isOptional": false,
"isUnique": false "isUnique": false
},
{
"name": "column_families",
"typeName": "array<hbase_column_family>",
"cardinality": "SINGLE",
"constraints": [
{
"type": "ownedRef"
} }
],
"isIndexable": false,
"isOptional": true,
"isUnique": false
},
] ]
}, },
{ {
...@@ -33,14 +46,27 @@ ...@@ -33,14 +46,27 @@
"isIndexable": false, "isIndexable": false,
"isOptional": false, "isOptional": false,
"isUnique": false, "isUnique": false,
"constraintDefs": [ "constraints": [
{ {
"type": "foreignKey", "type": "inverseRef",
"params": { "params": {
"onDelete": "cascade" "attribute": "column_families"
} }
} }
] ]
},
{
"name": "columns",
"typeName": "array<hbase_column>",
"cardinality": "SINGLE",
"constraints": [
{
"type": "ownedRef"
}
],
"isIndexable": false,
"isOptional": true,
"isUnique": false
} }
], ],
"typeVersion": "1.0" "typeVersion": "1.0"
...@@ -58,11 +84,11 @@ ...@@ -58,11 +84,11 @@
"isIndexable": false, "isIndexable": false,
"isOptional": false, "isOptional": false,
"isUnique": false, "isUnique": false,
"constraintDefs": [ "constraints": [
{ {
"type": "foreignKey", "type": "inverseRef",
"params": { "params": {
"onDelete": "cascade" "attribute": "columns"
} }
} }
] ]
......
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
"name": "nodes", "name": "nodes",
"typeName": "array<storm_node>", "typeName": "array<storm_node>",
"cardinality": "LIST", "cardinality": "LIST",
"constraintDefs": [], "constraints": [],
"isIndexable": false, "isIndexable": false,
"isOptional": false, "isOptional": false,
"isUnique": false "isUnique": false
......
...@@ -55,6 +55,10 @@ public enum AtlasErrorCode { ...@@ -55,6 +55,10 @@ public enum AtlasErrorCode {
TYPE_NAME_INVALID_FORMAT(400, "ATLAS40025E", "{0}: invalid name for {1}. Names must consist of a letter followed by a sequence of letter, number, or '_' characters"), TYPE_NAME_INVALID_FORMAT(400, "ATLAS40025E", "{0}: invalid name for {1}. Names must consist of a letter followed by a sequence of letter, number, or '_' characters"),
INVALID_PARAMETERS(400, "ATLAS40025E", "invalid parameters: {0}"), INVALID_PARAMETERS(400, "ATLAS40025E", "invalid parameters: {0}"),
CLASSIFICATION_ALREADY_ASSOCIATED(400, "ATLAS40026E", "instance {0} already is associated with classification {1}"), CLASSIFICATION_ALREADY_ASSOCIATED(400, "ATLAS40026E", "instance {0} already is associated with classification {1}"),
CONSTRAINT_INVERSE_REF_ATTRIBUTE_INVALID_TYPE(400, "ATLAS40027E", "{0}.{1}: invalid {2} constraint. Attribute {3} is not an entity type"),
CONSTRAINT_INVERSE_REF_INVERSE_ATTRIBUTE_NON_EXISTING(400, "ATLAS40028E", "{0}.{1}: invalid {2} constraint. Inverse attribute {3}.{4} does not exist"),
CONSTRAINT_INVERSE_REF_INVERSE_ATTRIBUTE_INVALID_TYPE(400, "ATLAS40029E", "{0}.{1}: invalid {2} constraint. Inverse attribute {3}.{4} is not an entity type"),
CONSTRAINT_OWNED_REF_ATTRIBUTE_INVALID_TYPE(400, "ATLAS40030E", "{0}.{1}: invalid {2} constraint. Attribute {3} is not an entity type"),
// All Not found enums go here // All Not found enums go here
TYPE_NAME_NOT_FOUND(404, "ATLAS4041E", "Given typename {0} was invalid"), TYPE_NAME_NOT_FOUND(404, "ATLAS4041E", "Given typename {0} was invalid"),
......
...@@ -42,6 +42,8 @@ import org.apache.hadoop.util.StringUtils; ...@@ -42,6 +42,8 @@ import org.apache.hadoop.util.StringUtils;
import org.codehaus.jackson.annotate.JsonAutoDetect; import org.codehaus.jackson.annotate.JsonAutoDetect;
import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.PUBLIC_ONLY; import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.PUBLIC_ONLY;
import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE; import static org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.map.annotate.JsonSerialize; import org.codehaus.jackson.map.annotate.JsonSerialize;
...@@ -269,7 +271,7 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable { ...@@ -269,7 +271,7 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
private int valuesMaxCount; private int valuesMaxCount;
private boolean isUnique; private boolean isUnique;
private boolean isIndexable; private boolean isIndexable;
private List<AtlasConstraintDef> constraintDefs; private List<AtlasConstraintDef> constraints;
public AtlasAttributeDef() { this(null, null); } public AtlasAttributeDef() { this(null, null); }
...@@ -279,7 +281,7 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable { ...@@ -279,7 +281,7 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
public AtlasAttributeDef(String name, String typeName, boolean isOptional, Cardinality cardinality, public AtlasAttributeDef(String name, String typeName, boolean isOptional, Cardinality cardinality,
int valuesMinCount, int valuesMaxCount, boolean isUnique, boolean isIndexable, int valuesMinCount, int valuesMaxCount, boolean isUnique, boolean isIndexable,
List<AtlasConstraintDef> constraintDefs) { List<AtlasConstraintDef> constraints) {
setName(name); setName(name);
setTypeName(typeName); setTypeName(typeName);
setIsOptional(isOptional); setIsOptional(isOptional);
...@@ -288,7 +290,7 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable { ...@@ -288,7 +290,7 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
setValuesMaxCount(valuesMaxCount); setValuesMaxCount(valuesMaxCount);
setIsUnique(isUnique); setIsUnique(isUnique);
setIsIndexable(isIndexable); setIsIndexable(isIndexable);
setConstraintDefs(constraintDefs); setConstraints(constraints);
} }
public AtlasAttributeDef(AtlasAttributeDef other) { public AtlasAttributeDef(AtlasAttributeDef other) {
...@@ -301,7 +303,7 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable { ...@@ -301,7 +303,7 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
setValuesMaxCount(other.getValuesMaxCount()); setValuesMaxCount(other.getValuesMaxCount());
setIsUnique(other.getIsUnique()); setIsUnique(other.getIsUnique());
setIsIndexable(other.getIsIndexable()); setIsIndexable(other.getIsIndexable());
setConstraintDefs(other.getConstraintDefs()); setConstraints(other.getConstraints());
} }
} }
...@@ -367,33 +369,34 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable { ...@@ -367,33 +369,34 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
isIndexable = idexable; isIndexable = idexable;
} }
public List<AtlasConstraintDef> getConstraintDefs() { return constraintDefs; } public List<AtlasConstraintDef> getConstraints() { return constraints; }
public void setConstraintDefs(List<AtlasConstraintDef> constraintDefs) { public void setConstraints(List<AtlasConstraintDef> constraints) {
if (this.constraintDefs != null && this.constraintDefs == constraintDefs) { if (this.constraints != null && this.constraints == constraints) {
return; return;
} }
if (CollectionUtils.isEmpty(constraintDefs)) { if (CollectionUtils.isEmpty(constraints)) {
this.constraintDefs = null; this.constraints = null;
} else { } else {
this.constraintDefs = new ArrayList<>(constraintDefs); this.constraints = new ArrayList<>(constraints);
} }
} }
public void addConstraint(AtlasConstraintDef constraintDef) { public void addConstraint(AtlasConstraintDef constraintDef) {
List<AtlasConstraintDef> cDefs = constraintDefs; List<AtlasConstraintDef> cDefs = constraints;
if (cDefs == null) { if (cDefs == null) {
cDefs = new ArrayList<>(); cDefs = new ArrayList<>();
this.constraints = cDefs;
} else { } else {
cDefs = new ArrayList<>(cDefs); cDefs = new ArrayList<>(cDefs);
} }
cDefs.add(constraintDef); cDefs.add(constraintDef);
this.constraintDefs = cDefs;
} }
public StringBuilder toString(StringBuilder sb) { public StringBuilder toString(StringBuilder sb) {
if (sb == null) { if (sb == null) {
sb = new StringBuilder(); sb = new StringBuilder();
...@@ -408,10 +411,10 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable { ...@@ -408,10 +411,10 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
sb.append(", valuesMaxCount=").append(valuesMaxCount); sb.append(", valuesMaxCount=").append(valuesMaxCount);
sb.append(", isUnique=").append(isUnique); sb.append(", isUnique=").append(isUnique);
sb.append(", isIndexable=").append(isIndexable); sb.append(", isIndexable=").append(isIndexable);
sb.append(", constraintDefs=["); sb.append(", constraints=[");
if (CollectionUtils.isNotEmpty(constraintDefs)) { if (CollectionUtils.isNotEmpty(constraints)) {
int i = 0; int i = 0;
for (AtlasConstraintDef constraintDef : constraintDefs) { for (AtlasConstraintDef constraintDef : constraints) {
constraintDef.toString(sb); constraintDef.toString(sb);
if (i > 0) { if (i > 0) {
sb.append(", "); sb.append(", ");
...@@ -438,12 +441,12 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable { ...@@ -438,12 +441,12 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
Objects.equals(name, that.name) && Objects.equals(name, that.name) &&
Objects.equals(typeName, that.typeName) && Objects.equals(typeName, that.typeName) &&
cardinality == that.cardinality && cardinality == that.cardinality &&
Objects.equals(constraintDefs, that.constraintDefs); Objects.equals(constraints, that.constraints);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash(name, typeName, isOptional, cardinality, valuesMinCount, valuesMaxCount, isUnique, isIndexable, constraintDefs); return Objects.hash(name, typeName, isOptional, cardinality, valuesMinCount, valuesMaxCount, isUnique, isIndexable, constraints);
} }
@Override @Override
...@@ -465,11 +468,9 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable { ...@@ -465,11 +468,9 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
public static class AtlasConstraintDef implements Serializable { public static class AtlasConstraintDef implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public static final String CONSTRAINT_TYPE_FOREIGN_KEY = "foreignKey"; public static final String CONSTRAINT_TYPE_OWNED_REF = "ownedRef";
public static final String CONSTRAINT_TYPE_MAPPED_FROM_REF = "mappedFromRef"; public static final String CONSTRAINT_TYPE_INVERSE_REF = "inverseRef";
public static final String CONSTRAINT_PARAM_REF_ATTRIBUTE = "refAttribute"; public static final String CONSTRAINT_PARAM_ATTRIBUTE = "attribute";
public static final String CONSTRAINT_PARAM_ON_DELETE = "onDelete";
public static final String CONSTRAINT_PARAM_VAL_CASCADE = "cascade";
private String type; // foreignKey/mappedFromRef/valueInRange private String type; // foreignKey/mappedFromRef/valueInRange
private Map<String, Object> params; // onDelete=cascade/refAttribute=attr2/min=0,max=23 private Map<String, Object> params; // onDelete=cascade/refAttribute=attr2/min=0,max=23
...@@ -515,6 +516,18 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable { ...@@ -515,6 +516,18 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
this.params = params; this.params = params;
} }
@JsonIgnore
public boolean isConstraintType(String name) {
return StringUtils.equalsIgnoreCase(name, this.type);
}
@JsonIgnore
public Object getParam(String name) {
Map<String, Object> params = this.params;
return params != null ? params.get(name) : null;
}
public StringBuilder toString(StringBuilder sb) { public StringBuilder toString(StringBuilder sb) {
if (sb == null) { if (sb == null) {
sb = new StringBuilder(); sb = new StringBuilder();
......
...@@ -24,15 +24,12 @@ import org.apache.atlas.model.instance.AtlasEntity; ...@@ -24,15 +24,12 @@ import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasObjectId; import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.typedef.AtlasEntityDef; import org.apache.atlas.model.typedef.AtlasEntityDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef; import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
...@@ -40,7 +37,6 @@ import java.util.List; ...@@ -40,7 +37,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.*;
/** /**
* class that implements behaviour of an entity-type. * class that implements behaviour of an entity-type.
...@@ -53,8 +49,6 @@ public class AtlasEntityType extends AtlasStructType { ...@@ -53,8 +49,6 @@ public class AtlasEntityType extends AtlasStructType {
private List<AtlasEntityType> superTypes = Collections.emptyList(); private List<AtlasEntityType> superTypes = Collections.emptyList();
private Set<String> allSuperTypes = Collections.emptySet(); private Set<String> allSuperTypes = Collections.emptySet();
private Set<String> allSubTypes = Collections.emptySet(); private Set<String> allSubTypes = Collections.emptySet();
private Map<String, AtlasAttribute> mappedFromRefAttributes = new HashMap<>();
private List<ForeignKeyReference> foreignKeyReferences = Collections.emptyList();
public AtlasEntityType(AtlasEntityDef entityDef) { public AtlasEntityType(AtlasEntityDef entityDef) {
super(entityDef); super(entityDef);
...@@ -96,15 +90,12 @@ public class AtlasEntityType extends AtlasStructType { ...@@ -96,15 +90,12 @@ public class AtlasEntityType extends AtlasStructType {
this.allSuperTypes = Collections.unmodifiableSet(allS); this.allSuperTypes = Collections.unmodifiableSet(allS);
this.allAttributes = Collections.unmodifiableMap(allA); this.allAttributes = Collections.unmodifiableMap(allA);
this.allSubTypes = new HashSet<>(); // this will be populated in resolveReferencesPhase2() this.allSubTypes = new HashSet<>(); // this will be populated in resolveReferencesPhase2()
this.foreignKeyReferences = new ArrayList<>(); // this will be populated in resolveReferencesPhase2()
} }
@Override @Override
public void resolveReferencesPhase2(AtlasTypeRegistry typeRegistry) throws AtlasBaseException { public void resolveReferencesPhase2(AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
super.resolveReferencesPhase2(typeRegistry); super.resolveReferencesPhase2(typeRegistry);
mappedFromRefAttributes = Collections.unmodifiableMap(resolveMappedFromRefConstraint(allAttributes.values()));
for (String superTypeName : allSuperTypes) { for (String superTypeName : allSuperTypes) {
AtlasEntityType superType = typeRegistry.getEntityTypeByName(superTypeName); AtlasEntityType superType = typeRegistry.getEntityTypeByName(superTypeName);
superType.addSubType(this); superType.addSubType(this);
...@@ -121,47 +112,6 @@ public class AtlasEntityType extends AtlasStructType { ...@@ -121,47 +112,6 @@ public class AtlasEntityType extends AtlasStructType {
public Set<String> getAllSubTypes() { return Collections.unmodifiableSet(allSubTypes); } public Set<String> getAllSubTypes() { return Collections.unmodifiableSet(allSubTypes); }
public Collection<String> getMappedFromRefAttributes() { return mappedFromRefAttributes.keySet(); }
public boolean isMappedFromRefAttribute(String attributeName) {
return mappedFromRefAttributes.containsKey(attributeName);
}
public String getMappedFromRefAttribute(String typeName, String attribName) {
String ret = null;
for (Map.Entry<String, AtlasAttribute> e : mappedFromRefAttributes.entrySet()) {
AtlasAttribute attribute = e.getValue();
if(StringUtils.equals(attribute.getDefinedInType().getTypeName(), typeName) && StringUtils.equals(attribute.getName(), attribName)) {
ret = e.getKey();
break;
}
}
return ret;
}
public List<ForeignKeyReference> getForeignKeyReferences() {
return Collections.unmodifiableList(foreignKeyReferences);
}
public ForeignKeyReference getForeignKeyReference(String fromTypeName, String fromAttributeName) {
ForeignKeyReference ret = null;
for (ForeignKeyReference fkRef : foreignKeyReferences) {
if (StringUtils.equals(fkRef.fromTypeName(), fromTypeName) &&
StringUtils.equals(fkRef.fromAttributeName(), fromAttributeName)) {
ret = fkRef;
break;
}
}
return ret;
}
public boolean isSuperTypeOf(AtlasEntityType entityType) { public boolean isSuperTypeOf(AtlasEntityType entityType) {
return entityType != null && allSubTypes.contains(entityType.getTypeName()); return entityType != null && allSubTypes.contains(entityType.getTypeName());
} }
...@@ -283,10 +233,6 @@ public class AtlasEntityType extends AtlasStructType { ...@@ -283,10 +233,6 @@ public class AtlasEntityType extends AtlasStructType {
} }
} }
void addForeignKeyReference(AtlasAttribute attribute, AtlasConstraintDef refConstraint) {
foreignKeyReferences.add(new ForeignKeyReference(attribute, refConstraint));
}
private void addSubType(AtlasEntityType subType) { private void addSubType(AtlasEntityType subType) {
allSubTypes.add(subType.getTypeName()); allSubTypes.add(subType.getTypeName());
} }
...@@ -334,128 +280,9 @@ public class AtlasEntityType extends AtlasStructType { ...@@ -334,128 +280,9 @@ public class AtlasEntityType extends AtlasStructType {
} }
} }
/*
* valid conditions for mapped-from-ref constraint:
* - supported only in entity-type
* - attribute should be an entity-type or an array of entity-type
* - attribute's entity-type should have a foreign-key constraint to this type
*/
private Map<String, AtlasAttribute> resolveMappedFromRefConstraint(Collection<AtlasAttribute> attributes) throws AtlasBaseException {
Map<String, AtlasAttribute> ret = null;
for (AtlasAttribute attribute : attributes) {
AtlasAttributeDef attribDef = attribute.getAttributeDef();
if (CollectionUtils.isEmpty(attribDef.getConstraintDefs())) {
continue;
}
for (AtlasConstraintDef constraintDef : attribDef.getConstraintDefs()) {
if (!StringUtils.equals(constraintDef.getType(), CONSTRAINT_TYPE_MAPPED_FROM_REF)) {
continue;
}
AtlasType attribType = attribute.getAttributeType();
if (attribType instanceof AtlasArrayType) {
attribType = ((AtlasArrayType)attribType).getElementType();
}
if (!(attribType instanceof AtlasEntityType)) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_NOT_SATISFIED, getTypeName(),
attribDef.getName(), CONSTRAINT_TYPE_MAPPED_FROM_REF,
attribDef.getTypeName());
}
String refAttribName = AtlasTypeUtil.getStringValue(constraintDef.getParams(), CONSTRAINT_PARAM_REF_ATTRIBUTE);
if (StringUtils.isBlank(refAttribName)) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_MISSING_PARAMS,
getTypeName(), attribDef.getName(),
CONSTRAINT_PARAM_REF_ATTRIBUTE, CONSTRAINT_TYPE_MAPPED_FROM_REF,
String.valueOf(constraintDef.getParams()));
}
AtlasEntityType entityType = (AtlasEntityType) attribType;
AtlasAttribute refAttrib = entityType.getAttribute(refAttribName);
if (refAttrib == null) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_NOT_EXIST,
getTypeName(), attribDef.getName(), CONSTRAINT_PARAM_REF_ATTRIBUTE,
entityType.getTypeName(), refAttribName);
}
if (!StringUtils.equals(getTypeName(), refAttrib.getTypeName())) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_NOT_MATCHED,
getTypeName(), attribDef.getName(), CONSTRAINT_PARAM_REF_ATTRIBUTE,
entityType.getTypeName(), refAttribName, getTypeName(),
refAttrib.getTypeName());
}
if (ret == null) {
ret = new HashMap<>();
}
ret.put(attribDef.getName(), refAttrib);
break;
}
}
return ret == null ? Collections.<String, AtlasAttribute>emptyMap() : ret;
}
boolean isAssignableFrom(AtlasObjectId objId) { boolean isAssignableFrom(AtlasObjectId objId) {
boolean ret = objId.isValid() && (StringUtils.equals(objId.getTypeName(), getTypeName()) || isSuperTypeOf(objId.getTypeName())); boolean ret = objId.isValid() && (StringUtils.equals(objId.getTypeName(), getTypeName()) || isSuperTypeOf(objId.getTypeName()));
return ret; return ret;
} }
public static class ForeignKeyReference {
private final AtlasAttribute fromAttribute;
private final AtlasConstraintDef refConstraint;
public ForeignKeyReference(AtlasAttribute fromAttribute, AtlasConstraintDef refConstraint) {
this.fromAttribute = fromAttribute;
this.refConstraint = refConstraint;
}
public String fromTypeName() { return fromType().getTypeName(); }
public String fromAttributeName() { return fromAttribute.getName(); }
public String toTypeName() { return fromAttribute.getTypeName(); }
public AtlasStructType fromType() { return fromAttribute.getDefinedInType(); }
public AtlasAttribute fromAttribute() { return fromAttribute; }
public AtlasEntityType toType() {
AtlasType attrType = fromAttribute.getAttributeType();
if (attrType instanceof AtlasArrayType) {
attrType = ((AtlasArrayType)attrType).getElementType();
}
if (attrType instanceof AtlasEntityType) {
return (AtlasEntityType)attrType;
}
return null;
}
public AtlasConstraintDef getConstraint() { return refConstraint; }
public boolean isOnDeleteCascade() {
return StringUtils.equals(getOnDeleteAction(), CONSTRAINT_PARAM_VAL_CASCADE);
}
private String getOnDeleteAction() {
Map<String, Object> params = refConstraint.getParams();
Object action = MapUtils.isNotEmpty(params) ? params.get(AtlasConstraintDef.CONSTRAINT_PARAM_ON_DELETE) : null;
return (action != null) ? action.toString() : null;
}
}
} }
...@@ -17,26 +17,26 @@ ...@@ -17,26 +17,26 @@
*/ */
package org.apache.atlas.type; package org.apache.atlas.type;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_OWNED_REF;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE;
import org.apache.atlas.AtlasErrorCode; import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.instance.AtlasStruct; import org.apache.atlas.model.instance.AtlasStruct;
import org.apache.atlas.model.typedef.AtlasStructDef; import org.apache.atlas.model.typedef.AtlasStructDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef; import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef.Cardinality; import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef.Cardinality;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef;
import org.apache.atlas.type.AtlasEntityType.ForeignKeyReference;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* class that implements behaviour of a struct-type. * class that implements behaviour of a struct-type.
...@@ -46,7 +46,6 @@ public class AtlasStructType extends AtlasType { ...@@ -46,7 +46,6 @@ public class AtlasStructType extends AtlasType {
private final AtlasStructDef structDef; private final AtlasStructDef structDef;
private Map<String, AtlasConstraintDef> foreignKeyAttributes = Collections.emptyMap();
protected Map<String, AtlasAttribute> allAttributes = Collections.emptyMap(); protected Map<String, AtlasAttribute> allAttributes = Collections.emptyMap();
public AtlasStructType(AtlasStructDef structDef) { public AtlasStructType(AtlasStructDef structDef) {
...@@ -77,37 +76,6 @@ public class AtlasStructType extends AtlasType { ...@@ -77,37 +76,6 @@ public class AtlasStructType extends AtlasType {
return attribute != null ? attribute.getAttributeDef() : null; return attribute != null ? attribute.getAttributeDef() : null;
} }
public Set<String> getForeignKeyAttributes() { return foreignKeyAttributes.keySet(); }
public boolean isForeignKeyAttribute(String attributeName) {
return foreignKeyAttributes.containsKey(attributeName);
}
public AtlasConstraintDef getForeignKeyConstraint(String attributeName) {
return foreignKeyAttributes.get(attributeName);
}
public String getForeignKeyOnDeleteAction(String attributeName) {
String ret = null;
AtlasConstraintDef fkConstraint = getForeignKeyConstraint(attributeName);
if (fkConstraint != null && MapUtils.isNotEmpty(fkConstraint.getParams())) {
Object onDeleteAction = fkConstraint.getParams().get(AtlasConstraintDef.CONSTRAINT_PARAM_ON_DELETE);
if (onDeleteAction != null) {
ret = onDeleteAction.toString();
}
}
return ret;
}
public boolean isForeignKeyOnDeleteActionCascade(String attributeName) {
return StringUtils.equals(getForeignKeyOnDeleteAction(attributeName),
AtlasConstraintDef.CONSTRAINT_PARAM_VAL_CASCADE);
}
@Override @Override
public void resolveReferences(AtlasTypeRegistry typeRegistry) throws AtlasBaseException { public void resolveReferences(AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
Map<String, AtlasAttribute> a = new HashMap<>(); Map<String, AtlasAttribute> a = new HashMap<>();
...@@ -133,33 +101,69 @@ public class AtlasStructType extends AtlasType { ...@@ -133,33 +101,69 @@ public class AtlasStructType extends AtlasType {
a.put(attributeDef.getName(), attribute); a.put(attributeDef.getName(), attribute);
} }
resolveConstraints(typeRegistry);
this.allAttributes = Collections.unmodifiableMap(a); this.allAttributes = Collections.unmodifiableMap(a);
}
foreignKeyAttributes = Collections.unmodifiableMap(resolveForeignKeyConstraints(allAttributes.values())); private void resolveConstraints(AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
for (AtlasAttributeDef attributeDef : getStructDef().getAttributeDefs()) {
if (CollectionUtils.isEmpty(attributeDef.getConstraints())) {
continue;
} }
@Override for (AtlasConstraintDef constraint : attributeDef.getConstraints()) {
public void resolveReferencesPhase2(AtlasTypeRegistry typeRegistry) throws AtlasBaseException { if (constraint.isConstraintType(CONSTRAINT_TYPE_OWNED_REF)) {
super.resolveReferencesPhase2(typeRegistry); AtlasEntityType attrType = getReferencedEntityType(typeRegistry.getType(attributeDef.getTypeName()));
for (Map.Entry<String, AtlasConstraintDef> e : foreignKeyAttributes.entrySet()) { if (attrType == null) {
String attributeName = e.getKey(); throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_OWNED_REF_ATTRIBUTE_INVALID_TYPE,
AtlasAttribute attribute = getAttribute(attributeName); getTypeName(), attributeDef.getName(), CONSTRAINT_TYPE_OWNED_REF, attributeDef.getTypeName());
AtlasConstraintDef constraint = e.getValue(); }
} else if (constraint.isConstraintType(CONSTRAINT_TYPE_INVERSE_REF)) {
AtlasEntityType attrType = getReferencedEntityType(typeRegistry.getType(attributeDef.getTypeName()));
AtlasType attrType = attribute.getAttributeType(); if (attrType == null) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_INVERSE_REF_ATTRIBUTE_INVALID_TYPE,
getTypeName(), attributeDef.getName(), CONSTRAINT_TYPE_INVERSE_REF,
attributeDef.getTypeName());
}
String inverseRefAttrName = AtlasTypeUtil.getStringValue(constraint.getParams(), CONSTRAINT_PARAM_ATTRIBUTE);
if (attrType instanceof AtlasArrayType) { if (StringUtils.isBlank(inverseRefAttrName)) {
attrType = ((AtlasArrayType)attrType).getElementType(); throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_MISSING_PARAMS,
getTypeName(), attributeDef.getName(),
CONSTRAINT_PARAM_ATTRIBUTE, CONSTRAINT_TYPE_INVERSE_REF,
String.valueOf(constraint.getParams()));
} }
if (attrType instanceof AtlasEntityType) { AtlasAttributeDef inverseRefAttrDef = attrType.getStructDef().getAttribute(inverseRefAttrName);
((AtlasEntityType)attrType).addForeignKeyReference(attribute, constraint);
if (inverseRefAttrDef == null) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_INVERSE_REF_INVERSE_ATTRIBUTE_NON_EXISTING,
getTypeName(), attributeDef.getName(),
CONSTRAINT_TYPE_INVERSE_REF, attrType.getTypeName(), inverseRefAttrName);
}
AtlasEntityType inverseRefAttrType = getReferencedEntityType(typeRegistry.getType(inverseRefAttrDef.getTypeName()));
if (inverseRefAttrType == null) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_INVERSE_REF_INVERSE_ATTRIBUTE_INVALID_TYPE,
getTypeName(), attributeDef.getName(),
CONSTRAINT_TYPE_INVERSE_REF, attrType.getTypeName(), inverseRefAttrName);
}
}
} }
} }
} }
@Override @Override
public void resolveReferencesPhase2(AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
super.resolveReferencesPhase2(typeRegistry);
}
@Override
public AtlasStruct createDefaultValue() { public AtlasStruct createDefaultValue() {
AtlasStruct ret = new AtlasStruct(structDef.getName()); AtlasStruct ret = new AtlasStruct(structDef.getName());
...@@ -383,57 +387,6 @@ public class AtlasStructType extends AtlasType { ...@@ -383,57 +387,6 @@ public class AtlasStructType extends AtlasType {
return null; return null;
} }
/*
* valid conditions for foreign-key constraint:
* - supported only in entity-type
* - attribute should be an entity-type or an array of entity-type
*/
private Map<String, AtlasConstraintDef> resolveForeignKeyConstraints(Collection<AtlasAttribute> attributes)
throws AtlasBaseException {
Map<String, AtlasConstraintDef> ret = null;
for (AtlasAttribute attribute : attributes) {
AtlasAttributeDef attribDef = attribute.getAttributeDef();
if (CollectionUtils.isEmpty(attribDef.getConstraintDefs())) {
continue;
}
for (AtlasConstraintDef constraintDef : attribDef.getConstraintDefs()) {
if (!StringUtils.equals(constraintDef.getType(), AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY)) {
continue;
}
if (!(this instanceof AtlasEntityType)) {
throw new AtlasBaseException(AtlasErrorCode.UNSUPPORTED_CONSTRAINT,
AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY, getTypeName(), attribute.getName());
}
AtlasType attrType = attribute.getAttributeType();
if (attrType instanceof AtlasArrayType) {
attrType = ((AtlasArrayType) attrType).getElementType();
}
if (!(attrType instanceof AtlasEntityType)) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_NOT_SATISFIED,
getTypeName(), attribute.getName(), AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY,
attrType.getTypeName());
}
if (ret == null) {
ret = new HashMap<>();
}
ret.put(attribute.getName(), constraintDef);
break;
}
}
return ret == null ? Collections.<String, AtlasConstraintDef>emptyMap() : ret;
}
public String getQualifiedAttributeName(String attrName) throws AtlasBaseException { public String getQualifiedAttributeName(String attrName) throws AtlasBaseException {
if ( allAttributes.containsKey(attrName)) { if ( allAttributes.containsKey(attrName)) {
return allAttributes.get(attrName).getQualifiedName(); return allAttributes.get(attrName).getQualifiedName();
...@@ -442,18 +395,49 @@ public class AtlasStructType extends AtlasType { ...@@ -442,18 +395,49 @@ public class AtlasStructType extends AtlasType {
throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_ATTRIBUTE, attrName, structDef.getName()); throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_ATTRIBUTE, attrName, structDef.getName());
} }
public static class AtlasAttribute { private AtlasEntityType getReferencedEntityType(AtlasType type) {
if (type instanceof AtlasArrayType) {
type = ((AtlasArrayType)type).getElementType();
}
return type instanceof AtlasEntityType ? (AtlasEntityType)type : null;
}
public static class AtlasAttribute {
private final AtlasStructType definedInType; private final AtlasStructType definedInType;
private final AtlasType attributeType; private final AtlasType attributeType;
private final AtlasAttributeDef attributeDef; private final AtlasAttributeDef attributeDef;
private final String qualifiedName; private final String qualifiedName;
private final boolean isOwnedRef;
private final String inverseRefAttribute;
public AtlasAttribute(AtlasStructType definedInType, AtlasAttributeDef attrDef, AtlasType attributeType) { public AtlasAttribute(AtlasStructType definedInType, AtlasAttributeDef attrDef, AtlasType attributeType) {
this.definedInType = definedInType; this.definedInType = definedInType;
this.attributeDef = attrDef; this.attributeDef = attrDef;
this.attributeType = attributeType; this.attributeType = attributeType;
this.qualifiedName = getQualifiedAttributeName(definedInType.getStructDef(), attributeDef.getName()); this.qualifiedName = getQualifiedAttributeName(definedInType.getStructDef(), attributeDef.getName());
boolean isOwnedRef = false;
String inverseRefAttribute = null;
if (CollectionUtils.isNotEmpty(attributeDef.getConstraints())) {
for (AtlasConstraintDef constraint : attributeDef.getConstraints()) {
if (constraint.isConstraintType(CONSTRAINT_TYPE_OWNED_REF)) {
isOwnedRef = true;
}
if (constraint.isConstraintType(CONSTRAINT_TYPE_INVERSE_REF)) {
Object val = constraint.getParam(CONSTRAINT_PARAM_ATTRIBUTE);
if (val != null) {
inverseRefAttribute = val.toString();
}
}
}
}
this.isOwnedRef = isOwnedRef;
this.inverseRefAttribute = inverseRefAttribute;
} }
public AtlasStructType getDefinedInType() { return definedInType; } public AtlasStructType getDefinedInType() { return definedInType; }
...@@ -478,74 +462,9 @@ public class AtlasStructType extends AtlasType { ...@@ -478,74 +462,9 @@ public class AtlasStructType extends AtlasType {
return qualifiedName; return qualifiedName;
} }
public boolean isForeignKeyWithOnDeleteCascade() { public boolean isOwnedRef() { return isOwnedRef; }
return definedInType.isForeignKeyOnDeleteActionCascade(getName());
}
/*
* true - if attribute-type has foreign-key(onDelete=cascade) reference to this type
* false - in all cases
*
* "legacyIsComposite" can not be computed and cached in the constructor - as definedInType is not fully
* populated at the time AtlasAttribute object is constructed.
*/
public boolean legacyIsComposite() {
boolean ret = false;
if (definedInType instanceof AtlasEntityType) {
AtlasEntityType entityType = (AtlasEntityType) definedInType;
AtlasType attrType = attributeType;
if (attrType instanceof AtlasArrayType) {
attrType = ((AtlasArrayType)attrType).getElementType();
}
if (attrType instanceof AtlasEntityType) {
for (ForeignKeyReference fkRef : entityType.getForeignKeyReferences()) {
if (fkRef.isOnDeleteCascade() && StringUtils.equals(fkRef.fromTypeName(), attrType.getTypeName())) {
ret = true;
break;
}
}
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("*** {}.{}: isComposite={} ***", definedInType.getTypeName(), getName(), ret);
}
return ret;
}
/*
* return the name of the attribute in attribute-type that has mappedFromRef constraint on this attribute
*
* "legacyReverseAttribute" can not be computed and cached in the constructor - as definedInType is not fully
* populated at the time AtlasAttribute object is constructed.
*/
public String legacyReverseAttribute() {
String ret = null;
if (definedInType instanceof AtlasEntityType) {
AtlasType attrType = attributeType;
if (attrType instanceof AtlasArrayType) {
attrType = ((AtlasArrayType)attrType).getElementType();
}
if (attrType instanceof AtlasEntityType) {
AtlasEntityType attribEntityType = (AtlasEntityType) attrType;
ret = attribEntityType.getMappedFromRefAttribute(definedInType.getTypeName(), getName()); public String getInverseRefAttribute() { return inverseRefAttribute; }
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("*** {}.{}: reverseAttribute={} ***", definedInType.getTypeName(), getName(), ret);
}
return ret;
}
public static String getQualifiedAttributeName(AtlasStructDef structDef, String attrName) { public static String getQualifiedAttributeName(AtlasStructDef structDef, String attrName) {
final String typeName = structDef.getName(); final String typeName = structDef.getName();
......
...@@ -87,12 +87,6 @@ public final class TestUtilsV2 { ...@@ -87,12 +87,6 @@ public final class TestUtilsV2 {
AtlasAttributeDef.Cardinality.SINGLE, 0, 1, false, false, AtlasAttributeDef.Cardinality.SINGLE, 0, 1, false, false,
new ArrayList<AtlasConstraintDef>())); new ArrayList<AtlasConstraintDef>()));
deptTypeDef.getAttribute("employees").addConstraint(
new AtlasConstraintDef(
AtlasConstraintDef.CONSTRAINT_TYPE_MAPPED_FROM_REF, new HashMap<String, Object>() {{
put(AtlasConstraintDef.CONSTRAINT_PARAM_REF_ATTRIBUTE, "department");
}}));
AtlasEntityDef personTypeDef = AtlasTypeUtil.createClassTypeDef("Person", "Person"+_description, ImmutableSet.<String>of(), AtlasEntityDef personTypeDef = AtlasTypeUtil.createClassTypeDef("Person", "Person"+_description, ImmutableSet.<String>of(),
AtlasTypeUtil.createUniqueRequiredAttrDef("name", "string"), AtlasTypeUtil.createUniqueRequiredAttrDef("name", "string"),
AtlasTypeUtil.createOptionalAttrDef("address", "Address"), AtlasTypeUtil.createOptionalAttrDef("address", "Address"),
...@@ -126,8 +120,8 @@ public final class TestUtilsV2 { ...@@ -126,8 +120,8 @@ public final class TestUtilsV2 {
employeeTypeDef.getAttribute("department").addConstraint( employeeTypeDef.getAttribute("department").addConstraint(
new AtlasConstraintDef( new AtlasConstraintDef(
AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY, new HashMap<String, Object>() {{ AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF, new HashMap<String, Object>() {{
put(AtlasConstraintDef.CONSTRAINT_PARAM_ON_DELETE, AtlasConstraintDef.CONSTRAINT_PARAM_VAL_CASCADE); put(AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE, "employees");
}})); }}));
AtlasEntityDef managerTypeDef = AtlasTypeUtil.createClassTypeDef("Manager", "Manager"+_description, ImmutableSet.of("Employee"), AtlasEntityDef managerTypeDef = AtlasTypeUtil.createClassTypeDef("Manager", "Manager"+_description, ImmutableSet.of("Employee"),
...@@ -480,8 +474,8 @@ public final class TestUtilsV2 { ...@@ -480,8 +474,8 @@ public final class TestUtilsV2 {
false, false, false, false,
new ArrayList<AtlasStructDef.AtlasConstraintDef>() {{ new ArrayList<AtlasStructDef.AtlasConstraintDef>() {{
add(new AtlasStructDef.AtlasConstraintDef( add(new AtlasStructDef.AtlasConstraintDef(
AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY, new HashMap<String, Object>() {{ AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF, new HashMap<String, Object>() {{
put(AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_ON_DELETE, AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_VAL_CASCADE); put(AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE, "columns");
}})); }}));
}}) }})
); );
...@@ -583,11 +577,7 @@ public final class TestUtilsV2 { ...@@ -583,11 +577,7 @@ public final class TestUtilsV2 {
AtlasAttributeDef.Cardinality.SINGLE, 0, 1, AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
false, false, false, false,
new ArrayList<AtlasStructDef.AtlasConstraintDef>() {{ new ArrayList<AtlasStructDef.AtlasConstraintDef>() {{
add(new AtlasStructDef.AtlasConstraintDef( add(new AtlasStructDef.AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_OWNED_REF));
AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_MAPPED_FROM_REF,
new HashMap<String, Object>() {{
put(AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_REF_ATTRIBUTE, "table");
}}));
}}), }}),
// array of structs // array of structs
new AtlasAttributeDef("partitions", String.format("array<%s>", "partition_struct_type"), new AtlasAttributeDef("partitions", String.format("array<%s>", "partition_struct_type"),
......
...@@ -23,6 +23,7 @@ import java.util.HashSet; ...@@ -23,6 +23,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.ModelTestUtil; import org.apache.atlas.model.ModelTestUtil;
import org.apache.atlas.model.instance.AtlasEntity; import org.apache.atlas.model.instance.AtlasEntity;
...@@ -31,7 +32,6 @@ import org.apache.atlas.model.typedef.AtlasEntityDef; ...@@ -31,7 +32,6 @@ import org.apache.atlas.model.typedef.AtlasEntityDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef; import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef; import org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef;
import org.apache.atlas.type.AtlasTypeRegistry.AtlasTransientTypeRegistry; import org.apache.atlas.type.AtlasTypeRegistry.AtlasTransientTypeRegistry;
import org.apache.atlas.type.AtlasEntityType.ForeignKeyReference;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import static org.testng.Assert.*; import static org.testng.Assert.*;
...@@ -42,6 +42,7 @@ public class TestAtlasEntityType { ...@@ -42,6 +42,7 @@ public class TestAtlasEntityType {
private static final String TYPE_COLUMN = "my_column"; private static final String TYPE_COLUMN = "my_column";
private static final String ATTR_TABLE = "table"; private static final String ATTR_TABLE = "table";
private static final String ATTR_COLUMNS = "columns"; private static final String ATTR_COLUMNS = "columns";
private static final String ATTR_NAME = "name";
private final AtlasEntityType entityType; private final AtlasEntityType entityType;
private final List<Object> validValues = new ArrayList<>(); private final List<Object> validValues = new ArrayList<>();
...@@ -129,7 +130,7 @@ public class TestAtlasEntityType { ...@@ -129,7 +130,7 @@ public class TestAtlasEntityType {
} }
@Test @Test
public void testForeignKeyConstraintValid() { public void testValidConstraints() {
AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry(); AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry();
AtlasTransientTypeRegistry ttr = null; AtlasTransientTypeRegistry ttr = null;
boolean commit = false; boolean commit = false;
...@@ -147,42 +148,81 @@ public class TestAtlasEntityType { ...@@ -147,42 +148,81 @@ public class TestAtlasEntityType {
AtlasEntityType typeTable = ttr.getEntityTypeByName(TYPE_TABLE); AtlasEntityType typeTable = ttr.getEntityTypeByName(TYPE_TABLE);
AtlasEntityType typeColumn = ttr.getEntityTypeByName(TYPE_COLUMN); AtlasEntityType typeColumn = ttr.getEntityTypeByName(TYPE_COLUMN);
assertEquals(typeTable.getForeignKeyReferences().size(), 1); assertTrue(typeTable.getAttribute(ATTR_COLUMNS).isOwnedRef());
assertNull(typeTable.getAttribute(ATTR_COLUMNS).getInverseRefAttribute());
assertFalse(typeColumn.getAttribute(ATTR_TABLE).isOwnedRef());
assertEquals(typeColumn.getAttribute(ATTR_TABLE).getInverseRefAttribute(), ATTR_COLUMNS);
ForeignKeyReference fkRef = typeTable.getForeignKeyReferences().get(0); commit = true;
assertEquals(fkRef.fromTypeName(), TYPE_COLUMN); } catch (AtlasBaseException excp) {
assertEquals(fkRef.fromAttributeName(), ATTR_TABLE); failureMsg = excp.getMessage();
assertEquals(fkRef.toTypeName(), TYPE_TABLE); } finally {
assertTrue(fkRef.isOnDeleteCascade()); typeRegistry.releaseTypeRegistryForUpdate(ttr, commit);
}
assertNull(failureMsg, "failed to create types " + TYPE_TABLE + " and " + TYPE_COLUMN);
}
assertEquals(typeTable.getForeignKeyAttributes().size(), 0); @Test
assertEquals(typeTable.getMappedFromRefAttributes().size(), 1); public void testConstraintInvalidOwnedRef_InvalidAttributeType() {
assertTrue(typeTable.getMappedFromRefAttributes().contains(ATTR_COLUMNS)); AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry();
AtlasTransientTypeRegistry ttr = null;
boolean commit = false;
List<AtlasEntityDef> entityDefs = new ArrayList<>();
AtlasErrorCode errorCode = null;
entityDefs.add(createTableEntityDefWithOwnedRefOnInvalidType());
try {
ttr = typeRegistry.lockTypeRegistryForUpdate();
assertEquals(typeColumn.getForeignKeyReferences().size(), 0); ttr.addTypes(entityDefs);
assertEquals(typeColumn.getForeignKeyAttributes().size(), 1);
assertTrue(typeColumn.getForeignKeyAttributes().contains(ATTR_TABLE));
assertEquals(typeColumn.getMappedFromRefAttributes().size(), 0);
commit = true; commit = true;
} catch (AtlasBaseException excp) { } catch (AtlasBaseException excp) {
failureMsg = excp.getMessage(); errorCode = excp.getAtlasErrorCode();
} finally { } finally {
typeRegistry.releaseTypeRegistryForUpdate(ttr, commit); typeRegistry.releaseTypeRegistryForUpdate(ttr, commit);
} }
assertNull(failureMsg, "failed to create types " + TYPE_TABLE + " and " + TYPE_COLUMN); assertEquals(errorCode, AtlasErrorCode.CONSTRAINT_OWNED_REF_ATTRIBUTE_INVALID_TYPE,
"expected invalid constraint failure - missing refAttribute");
} }
@Test @Test
public void testForeignKeyConstraintInValidMappedFromRef() { public void testConstraintInValidInverseRef_MissingParams() {
AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry(); AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry();
AtlasTransientTypeRegistry ttr = null;
boolean commit = false;
List<AtlasEntityDef> entityDefs = new ArrayList<>(); List<AtlasEntityDef> entityDefs = new ArrayList<>();
String failureMsg = null; AtlasErrorCode errorCode = null;
entityDefs.add(createTableEntityDef()); entityDefs.add(createTableEntityDef());
entityDefs.add(createColumnEntityDefWithMissingInverseAttribute());
try {
ttr = typeRegistry.lockTypeRegistryForUpdate();
ttr.addTypes(entityDefs);
commit = true;
} catch (AtlasBaseException excp) {
errorCode = excp.getAtlasErrorCode();
} finally {
typeRegistry.releaseTypeRegistryForUpdate(ttr, commit);
}
assertEquals(errorCode, AtlasErrorCode.CONSTRAINT_MISSING_PARAMS,
"expected invalid constraint failure - missing refAttribute");
}
@Test
public void testConstraintInValidInverseRef_InvalidAttributeTypeForInverseAttribute() {
AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry();
AtlasTransientTypeRegistry ttr = null; AtlasTransientTypeRegistry ttr = null;
boolean commit = false; boolean commit = false;
List<AtlasEntityDef> entityDefs = new ArrayList<>();
AtlasErrorCode errorCode = null;
entityDefs.add(createTableEntityDef());
entityDefs.add(createColumnEntityDefWithInvaidAttributeTypeForInverseAttribute());
try { try {
ttr = typeRegistry.lockTypeRegistryForUpdate(); ttr = typeRegistry.lockTypeRegistryForUpdate();
...@@ -191,23 +231,24 @@ public class TestAtlasEntityType { ...@@ -191,23 +231,24 @@ public class TestAtlasEntityType {
commit = true; commit = true;
} catch (AtlasBaseException excp) { } catch (AtlasBaseException excp) {
failureMsg = excp.getMessage(); errorCode = excp.getAtlasErrorCode();
} finally { } finally {
typeRegistry.releaseTypeRegistryForUpdate(ttr, commit); typeRegistry.releaseTypeRegistryForUpdate(ttr, commit);
} }
assertNotNull(failureMsg, "expected invalid constraint failure - unknown attribute in mappedFromRef"); assertEquals(errorCode, AtlasErrorCode.CONSTRAINT_INVERSE_REF_ATTRIBUTE_INVALID_TYPE,
"expected invalid constraint failure - missing refAttribute");
} }
@Test @Test
public void testForeignKeyConstraintInValidMappedFromRef2() { public void testConstraintInValidInverseRef_InvalidAttributeType() {
AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry(); AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry();
AtlasTransientTypeRegistry ttr = null; AtlasTransientTypeRegistry ttr = null;
boolean commit = false; boolean commit = false;
List<AtlasEntityDef> entityDefs = new ArrayList<>(); List<AtlasEntityDef> entityDefs = new ArrayList<>();
String failureMsg = null; AtlasErrorCode errorCode = null;
entityDefs.add(createTableEntityDefWithMissingRefAttribute()); entityDefs.add(createTableEntityDef());
entityDefs.add(createColumnEntityDef()); entityDefs.add(createColumnEntityDefWithInvalidInverseAttributeType());
try { try {
ttr = typeRegistry.lockTypeRegistryForUpdate(); ttr = typeRegistry.lockTypeRegistryForUpdate();
...@@ -216,22 +257,24 @@ public class TestAtlasEntityType { ...@@ -216,22 +257,24 @@ public class TestAtlasEntityType {
commit = true; commit = true;
} catch (AtlasBaseException excp) { } catch (AtlasBaseException excp) {
failureMsg = excp.getMessage(); errorCode = excp.getAtlasErrorCode();
} finally { } finally {
typeRegistry.releaseTypeRegistryForUpdate(ttr, commit); typeRegistry.releaseTypeRegistryForUpdate(ttr, commit);
} }
assertNotNull(failureMsg, "expected invalid constraint failure - missing refAttribute in mappedFromRef"); assertEquals(errorCode, AtlasErrorCode.CONSTRAINT_INVERSE_REF_INVERSE_ATTRIBUTE_INVALID_TYPE,
"expected invalid constraint failure - invalid refAttribute type");
} }
@Test @Test
public void testForeignKeyConstraintInValidForeignKey() { public void testConstraintInValidInverseRef_NonExistingAttribute() {
AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry(); AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry();
AtlasTransientTypeRegistry ttr = null; AtlasTransientTypeRegistry ttr = null;
boolean commit = false; boolean commit = false;
List<AtlasEntityDef> entityDefs = new ArrayList<>(); List<AtlasEntityDef> entityDefs = new ArrayList<>();
String failureMsg = null; AtlasErrorCode errorCode = null;
entityDefs.add(createColumnEntityDef()); entityDefs.add(createTableEntityDef());
entityDefs.add(createColumnEntityDefWithNonExistingInverseAttribute());
try { try {
ttr = typeRegistry.lockTypeRegistryForUpdate(); ttr = typeRegistry.lockTypeRegistryForUpdate();
...@@ -240,11 +283,12 @@ public class TestAtlasEntityType { ...@@ -240,11 +283,12 @@ public class TestAtlasEntityType {
commit = true; commit = true;
} catch (AtlasBaseException excp) { } catch (AtlasBaseException excp) {
failureMsg = excp.getMessage(); errorCode = excp.getAtlasErrorCode();
} finally { } finally {
typeRegistry.releaseTypeRegistryForUpdate(ttr, commit); typeRegistry.releaseTypeRegistryForUpdate(ttr, commit);
} }
assertNotNull(failureMsg, "expected invalid constraint failure - unknown attribute in foreignKey"); assertEquals(errorCode, AtlasErrorCode.CONSTRAINT_INVERSE_REF_INVERSE_ATTRIBUTE_NON_EXISTING,
"expected invalid constraint failure - non-existing refAttribute");
} }
private static AtlasEntityType getEntityType(AtlasEntityDef entityDef) { private static AtlasEntityType getEntityType(AtlasEntityDef entityDef) {
...@@ -257,37 +301,86 @@ public class TestAtlasEntityType { ...@@ -257,37 +301,86 @@ public class TestAtlasEntityType {
private AtlasEntityDef createTableEntityDef() { private AtlasEntityDef createTableEntityDef() {
AtlasEntityDef table = new AtlasEntityDef(TYPE_TABLE); AtlasEntityDef table = new AtlasEntityDef(TYPE_TABLE);
AtlasAttributeDef attrName = new AtlasAttributeDef(ATTR_NAME, AtlasBaseTypeDef.ATLAS_TYPE_STRING);
AtlasAttributeDef attrColumns = new AtlasAttributeDef(ATTR_COLUMNS, AtlasAttributeDef attrColumns = new AtlasAttributeDef(ATTR_COLUMNS,
AtlasBaseTypeDef.getArrayTypeName(TYPE_COLUMN)); AtlasBaseTypeDef.getArrayTypeName(TYPE_COLUMN));
Map<String, Object> params = new HashMap<>(); attrColumns.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_OWNED_REF));
params.put(AtlasConstraintDef.CONSTRAINT_PARAM_REF_ATTRIBUTE, ATTR_TABLE);
attrColumns.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_MAPPED_FROM_REF, params)); table.addAttribute(attrName);
table.addAttribute(attrColumns); table.addAttribute(attrColumns);
return table; return table;
} }
private AtlasEntityDef createTableEntityDefWithMissingRefAttribute() { private AtlasEntityDef createTableEntityDefWithOwnedRefOnInvalidType() {
AtlasEntityDef table = new AtlasEntityDef(TYPE_TABLE); AtlasEntityDef table = new AtlasEntityDef(TYPE_TABLE);
AtlasAttributeDef attrColumns = new AtlasAttributeDef(ATTR_COLUMNS, AtlasAttributeDef attrName = new AtlasAttributeDef(ATTR_NAME, AtlasBaseTypeDef.ATLAS_TYPE_STRING);
AtlasBaseTypeDef.getArrayTypeName(TYPE_COLUMN));
attrColumns.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_MAPPED_FROM_REF, null)); attrName.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_OWNED_REF));
table.addAttribute(attrColumns);
table.addAttribute(attrName);
return table; return table;
} }
private AtlasEntityDef createColumnEntityDefWithMissingInverseAttribute() {
AtlasEntityDef column = new AtlasEntityDef(TYPE_COLUMN);
AtlasAttributeDef attrTable = new AtlasAttributeDef(ATTR_TABLE, TYPE_TABLE);
attrTable.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF));
column.addAttribute(attrTable);
return column;
}
private AtlasEntityDef createColumnEntityDefWithInvaidAttributeTypeForInverseAttribute() {
AtlasEntityDef column = new AtlasEntityDef(TYPE_COLUMN);
AtlasAttributeDef attrTable = new AtlasAttributeDef(ATTR_NAME, AtlasBaseTypeDef.ATLAS_TYPE_STRING);
Map<String, Object> params = new HashMap<>();
params.put(AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE, ATTR_NAME);
attrTable.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF, params));
column.addAttribute(attrTable);
return column;
}
private AtlasEntityDef createColumnEntityDefWithNonExistingInverseAttribute() {
AtlasEntityDef column = new AtlasEntityDef(TYPE_COLUMN);
AtlasAttributeDef attrTable = new AtlasAttributeDef(ATTR_TABLE, TYPE_TABLE);
Map<String, Object> params = new HashMap<>();
params.put(AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE, "non-existing:" + ATTR_COLUMNS);
attrTable.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF, params));
column.addAttribute(attrTable);
return column;
}
private AtlasEntityDef createColumnEntityDefWithInvalidInverseAttributeType() {
AtlasEntityDef column = new AtlasEntityDef(TYPE_COLUMN);
AtlasAttributeDef attrTable = new AtlasAttributeDef(ATTR_TABLE, TYPE_TABLE);
Map<String, Object> params = new HashMap<>();
params.put(AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE, ATTR_NAME);
attrTable.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF, params));
column.addAttribute(attrTable);
return column;
}
private AtlasEntityDef createColumnEntityDef() { private AtlasEntityDef createColumnEntityDef() {
AtlasEntityDef column = new AtlasEntityDef(TYPE_COLUMN); AtlasEntityDef column = new AtlasEntityDef(TYPE_COLUMN);
AtlasAttributeDef attrTable = new AtlasAttributeDef(ATTR_TABLE, TYPE_TABLE); AtlasAttributeDef attrTable = new AtlasAttributeDef(ATTR_TABLE, TYPE_TABLE);
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put(AtlasConstraintDef.CONSTRAINT_PARAM_ON_DELETE, AtlasConstraintDef.CONSTRAINT_PARAM_VAL_CASCADE); params.put(AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE, ATTR_COLUMNS);
attrTable.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY, params)); attrTable.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF, params));
column.addAttribute(attrTable); column.addAttribute(attrTable);
return column; return column;
......
...@@ -52,11 +52,6 @@ import java.util.List; ...@@ -52,11 +52,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_ON_DELETE;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_VAL_CASCADE;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_MAPPED_FROM_REF;
/** /**
* StructDef store in v1 format. * StructDef store in v1 format.
*/ */
...@@ -503,18 +498,14 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1 implements At ...@@ -503,18 +498,14 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1 implements At
@VisibleForTesting @VisibleForTesting
public static String toJsonFromAttribute(AtlasAttribute attribute) { public static String toJsonFromAttribute(AtlasAttribute attribute) {
AtlasAttributeDef attributeDef = attribute.getAttributeDef(); AtlasAttributeDef attributeDef = attribute.getAttributeDef();
boolean isComposite = attribute.legacyIsComposite();
String reverseAttribName = attribute.legacyReverseAttribute();
Map<String, Object> attribInfo = new HashMap<>(); Map<String, Object> attribInfo = new HashMap<>();
attribInfo.put("name", attributeDef.getName()); attribInfo.put("name", attributeDef.getName());
attribInfo.put("dataType", attributeDef.getTypeName()); attribInfo.put("dataType", attributeDef.getTypeName());
attribInfo.put("isUnique", attributeDef.getIsUnique()); attribInfo.put("isUnique", attributeDef.getIsUnique());
attribInfo.put("isIndexable", attributeDef.getIsIndexable()); attribInfo.put("isIndexable", attributeDef.getIsIndexable());
attribInfo.put("isComposite", isComposite); attribInfo.put("isComposite", attribute.isOwnedRef());
attribInfo.put("reverseAttributeName", reverseAttribName); attribInfo.put("reverseAttributeName", attribute.getInverseRefAttribute());
attribInfo.put("isForeignKeyWithOnDeleteCascade", attribute.isForeignKeyWithOnDeleteCascade());
final int lower; final int lower;
final int upper; final int upper;
...@@ -554,111 +545,16 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1 implements At ...@@ -554,111 +545,16 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1 implements At
ret.setIsUnique((Boolean) attribInfo.get("isUnique")); ret.setIsUnique((Boolean) attribInfo.get("isUnique"));
ret.setIsIndexable((Boolean) attribInfo.get("isIndexable")); ret.setIsIndexable((Boolean) attribInfo.get("isIndexable"));
String attrTypeName = ret.getTypeName(); if ((Boolean)attribInfo.get("isComposite")) {
ret.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_OWNED_REF));
if (AtlasTypeUtil.isArrayType(attrTypeName)) {
Set<String> typeNames = AtlasTypeUtil.getReferencedTypeNames(attrTypeName);
if (typeNames.size() > 0) {
attrTypeName = typeNames.iterator().next();
}
}
if (!AtlasTypeUtil.isBuiltInType(attrTypeName)) {
AtlasVertex attributeType = typeDefStore.findTypeVertexByName(attrTypeName);
/* determine constraints to add to this attribute
- add mappedFromRef if attribute-type has an attribute that refers to this attribute via reverseAttributeName
example: hive_table.sd referenced from hive_storagedesc.table with reverseAttributeName=sd
- add foreignKey(onDelete=cascade) if attribute-type has an attribute that refers to this struct with isComposite=true
example: hive_storagedesc referenced from hive_table.sd with isComposite=true
example: hive_column referenced from hive_table.columns with isComposite=true
*/
if (attributeType != null && typeDefStore.isTypeVertex(attributeType, TypeCategory.CLASS)) {
boolean attributeTypeHasIsCompositeRef = false;
String attributeTypeRevAttribRefFrom = null;
List<String> attrNames = attributeType.getProperty(AtlasGraphUtilsV1.getTypeDefPropertyKey(attrTypeName), List.class);
if (CollectionUtils.isNotEmpty(attrNames)) {
for (String attrName : attrNames) {
String attribJson = attributeType.getProperty(
AtlasGraphUtilsV1.getTypeDefPropertyKey(attrTypeName, attrName), String.class);
if (StringUtils.isBlank(attribJson)) {
continue;
}
Map refAttrInfo = AtlasType.fromJson(attribJson, Map.class);
if (refAttrInfo == null) {
continue;
}
String refAttribType = (String) refAttrInfo.get("dataType");
if (AtlasTypeUtil.isArrayType(refAttribType)) {
Set<String> typeNames = AtlasTypeUtil.getReferencedTypeNames(refAttribType);
if (typeNames.size() > 0) {
refAttribType = typeNames.iterator().next();
}
}
if (!StringUtils.equals(refAttribType, structDef.getName())) {
continue;
} }
if (StringUtils.isBlank(attributeTypeRevAttribRefFrom)) { final String reverseAttributeName = (String) attribInfo.get("reverseAttributeName");
String refAttribRevAttribName = (String) refAttrInfo.get("reverseAttributeName"); if (StringUtils.isNotBlank(reverseAttributeName)) {
ret.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF,
if (StringUtils.equals(refAttribRevAttribName, ret.getName())) { new HashMap<String, Object>() {{
attributeTypeRevAttribRefFrom = (String) refAttrInfo.get("name"); put(AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE, reverseAttributeName);
} }}));
}
if (!attributeTypeHasIsCompositeRef) {
Object val = refAttrInfo.get("isComposite");
if (val instanceof Boolean) {
attributeTypeHasIsCompositeRef = (Boolean) val;
} if (val != null) {
attributeTypeHasIsCompositeRef = Boolean.parseBoolean(val.toString());
}
}
if (StringUtils.isNotBlank(attributeTypeRevAttribRefFrom) && attributeTypeHasIsCompositeRef) {
break;
}
}
}
boolean isForeignKeyWithOnDeleteCascade = attributeTypeHasIsCompositeRef;
if (!isForeignKeyWithOnDeleteCascade) {
Object val = attribInfo.get("isForeignKeyWithOnDeleteCascade");
if (val instanceof Boolean) {
isForeignKeyWithOnDeleteCascade = (Boolean) val;
} else if (val != null) {
isForeignKeyWithOnDeleteCascade = Boolean.parseBoolean(val.toString());
}
}
if (StringUtils.isNotBlank(attributeTypeRevAttribRefFrom)) {
Map<String, Object> params = new HashMap<>();
params.put(AtlasConstraintDef.CONSTRAINT_PARAM_REF_ATTRIBUTE, attributeTypeRevAttribRefFrom);
ret.addConstraint(new AtlasConstraintDef(CONSTRAINT_TYPE_MAPPED_FROM_REF, params));
}
if (isForeignKeyWithOnDeleteCascade) { // ex: hive_column.table
Map<String, Object> params = new HashMap<>();
params.put(CONSTRAINT_PARAM_ON_DELETE, CONSTRAINT_PARAM_VAL_CASCADE);
ret.addConstraint(new AtlasConstraintDef(CONSTRAINT_TYPE_FOREIGN_KEY, params));
}
}
} }
Map multiplicity = AtlasType.fromJson((String) attribInfo.get("multiplicity"), Map.class); Map multiplicity = AtlasType.fromJson((String) attribInfo.get("multiplicity"), Map.class);
......
...@@ -139,7 +139,7 @@ public abstract class DeleteHandlerV1 { ...@@ -139,7 +139,7 @@ public abstract class DeleteHandlerV1 {
} }
for (AtlasStructType.AtlasAttribute attributeInfo : entityType.getAllAttributes().values()) { for (AtlasStructType.AtlasAttribute attributeInfo : entityType.getAllAttributes().values()) {
if (!entityType.isMappedFromRefAttribute(attributeInfo.getName())) { if (! attributeInfo.isOwnedRef()) {
continue; continue;
} }
String edgeLabel = AtlasGraphUtilsV1.getAttributeEdgeLabel(entityType, attributeInfo.getName()); String edgeLabel = AtlasGraphUtilsV1.getAttributeEdgeLabel(entityType, attributeInfo.getName());
...@@ -284,7 +284,7 @@ public abstract class DeleteHandlerV1 { ...@@ -284,7 +284,7 @@ public abstract class DeleteHandlerV1 {
for (AtlasStructType.AtlasAttribute attributeInfo : getAttributes(structType)) { for (AtlasStructType.AtlasAttribute attributeInfo : getAttributes(structType)) {
LOG.debug("Deleting attribute {} for {}", attributeInfo.getName(), string(instanceVertex)); LOG.debug("Deleting attribute {} for {}", attributeInfo.getName(), string(instanceVertex));
boolean isComposite = isEntityType && ((AtlasEntityType)structType).isMappedFromRefAttribute(attributeInfo.getName()); boolean isComposite = isEntityType && attributeInfo.isOwnedRef();
AtlasType attrType = typeRegistry.getType(attributeInfo.getTypeName()); AtlasType attrType = typeRegistry.getType(attributeInfo.getTypeName());
......
...@@ -88,7 +88,9 @@ public class StructVertexMapper implements InstanceGraphMapper<AtlasEdge> { ...@@ -88,7 +88,9 @@ public class StructVertexMapper implements InstanceGraphMapper<AtlasEdge> {
} }
public static boolean shouldManageChildReferences(AtlasStructType type, String attributeName) { public static boolean shouldManageChildReferences(AtlasStructType type, String attributeName) {
return (type instanceof AtlasEntityType) && ((AtlasEntityType)type).isMappedFromRefAttribute(attributeName); AtlasStructType.AtlasAttribute attribute = type.getAttribute(attributeName);
return attribute != null ? attribute.isOwnedRef() : false;
} }
/** /**
......
...@@ -63,11 +63,9 @@ import java.util.List; ...@@ -63,11 +63,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_ON_DELETE; import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_REF_ATTRIBUTE; import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_OWNED_REF;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_VAL_CASCADE; import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_MAPPED_FROM_REF;
/** /**
* A driver that sets up sample types and entities using v2 types and entity model for testing purposes. * A driver that sets up sample types and entities using v2 types and entity model for testing purposes.
...@@ -217,8 +215,8 @@ public class QuickStartV2 { ...@@ -217,8 +215,8 @@ public class QuickStartV2 {
AtlasTypeUtil.createOptionalAttrDef("createTime", "long")); AtlasTypeUtil.createOptionalAttrDef("createTime", "long"));
AtlasEntityDef sdType = AtlasTypeUtil.createClassTypeDef(STORAGE_DESC_TYPE, STORAGE_DESC_TYPE, "1.0", null, AtlasEntityDef sdType = AtlasTypeUtil.createClassTypeDef(STORAGE_DESC_TYPE, STORAGE_DESC_TYPE, "1.0", null,
AtlasTypeUtil.createOptionalAttrDefWithConstraint("table", TABLE_TYPE, CONSTRAINT_TYPE_FOREIGN_KEY, AtlasTypeUtil.createOptionalAttrDefWithConstraint("table", TABLE_TYPE, CONSTRAINT_TYPE_INVERSE_REF,
new HashMap<String, Object>() {{ put(CONSTRAINT_PARAM_ON_DELETE, CONSTRAINT_PARAM_VAL_CASCADE); }}), new HashMap<String, Object>() {{ put(CONSTRAINT_PARAM_ATTRIBUTE, "sd"); }}),
AtlasTypeUtil.createOptionalAttrDef("location", "string"), AtlasTypeUtil.createOptionalAttrDef("location", "string"),
AtlasTypeUtil.createOptionalAttrDef("inputFormat", "string"), AtlasTypeUtil.createOptionalAttrDef("inputFormat", "string"),
AtlasTypeUtil.createOptionalAttrDef("outputFormat", "string"), AtlasTypeUtil.createOptionalAttrDef("outputFormat", "string"),
...@@ -228,15 +226,14 @@ public class QuickStartV2 { ...@@ -228,15 +226,14 @@ public class QuickStartV2 {
AtlasTypeUtil.createOptionalAttrDef("name", "string"), AtlasTypeUtil.createOptionalAttrDef("name", "string"),
AtlasTypeUtil.createOptionalAttrDef("dataType", "string"), AtlasTypeUtil.createOptionalAttrDef("dataType", "string"),
AtlasTypeUtil.createOptionalAttrDef("comment", "string"), AtlasTypeUtil.createOptionalAttrDef("comment", "string"),
AtlasTypeUtil.createOptionalAttrDefWithConstraint("table", TABLE_TYPE, CONSTRAINT_TYPE_FOREIGN_KEY, AtlasTypeUtil.createOptionalAttrDefWithConstraint("table", TABLE_TYPE, CONSTRAINT_TYPE_INVERSE_REF,
new HashMap<String, Object>() {{ put(CONSTRAINT_PARAM_ON_DELETE, CONSTRAINT_PARAM_VAL_CASCADE); }})); new HashMap<String, Object>() {{ put(CONSTRAINT_PARAM_ATTRIBUTE, "table"); }}));
colType.setOptions(new HashMap<String, String>() {{ put("schemaAttributes", "[\"name\", \"description\", \"owner\", \"type\", \"comment\", \"position\"]"); }}); colType.setOptions(new HashMap<String, String>() {{ put("schemaAttributes", "[\"name\", \"description\", \"owner\", \"type\", \"comment\", \"position\"]"); }});
AtlasEntityDef tblType = AtlasTypeUtil.createClassTypeDef(TABLE_TYPE, TABLE_TYPE, "1.0", ImmutableSet.of("DataSet"), AtlasEntityDef tblType = AtlasTypeUtil.createClassTypeDef(TABLE_TYPE, TABLE_TYPE, "1.0", ImmutableSet.of("DataSet"),
AtlasTypeUtil.createRequiredAttrDef("db", DATABASE_TYPE), AtlasTypeUtil.createRequiredAttrDef("db", DATABASE_TYPE),
AtlasTypeUtil.createRequiredAttrDefWithConstraint("sd", STORAGE_DESC_TYPE, CONSTRAINT_TYPE_MAPPED_FROM_REF, AtlasTypeUtil.createRequiredAttrDefWithConstraint("sd", STORAGE_DESC_TYPE, CONSTRAINT_TYPE_OWNED_REF, null),
new HashMap<String, Object>() {{ put(CONSTRAINT_PARAM_REF_ATTRIBUTE, "table"); }}),
AtlasTypeUtil.createOptionalAttrDef("owner", "string"), AtlasTypeUtil.createOptionalAttrDef("owner", "string"),
AtlasTypeUtil.createOptionalAttrDef("createTime", "long"), AtlasTypeUtil.createOptionalAttrDef("createTime", "long"),
AtlasTypeUtil.createOptionalAttrDef("lastAccessTime", "long"), AtlasTypeUtil.createOptionalAttrDef("lastAccessTime", "long"),
...@@ -246,7 +243,7 @@ public class QuickStartV2 { ...@@ -246,7 +243,7 @@ public class QuickStartV2 {
AtlasTypeUtil.createOptionalAttrDef("tableType", "string"), AtlasTypeUtil.createOptionalAttrDef("tableType", "string"),
AtlasTypeUtil.createOptionalAttrDef("temporary", "boolean"), AtlasTypeUtil.createOptionalAttrDef("temporary", "boolean"),
AtlasTypeUtil.createRequiredListAttrDefWithConstraint("columns", AtlasBaseTypeDef.getArrayTypeName(COLUMN_TYPE), AtlasTypeUtil.createRequiredListAttrDefWithConstraint("columns", AtlasBaseTypeDef.getArrayTypeName(COLUMN_TYPE),
CONSTRAINT_TYPE_MAPPED_FROM_REF, new HashMap<String, Object>() {{ put(CONSTRAINT_PARAM_REF_ATTRIBUTE, "table"); }})); CONSTRAINT_TYPE_OWNED_REF, null));
tblType.setOptions(new HashMap<String, String>() {{ put("schemaElementsAttribute", "columns"); }}); tblType.setOptions(new HashMap<String, String>() {{ put("schemaElementsAttribute", "columns"); }});
......
...@@ -19,21 +19,18 @@ ...@@ -19,21 +19,18 @@
package org.apache.atlas.util; package org.apache.atlas.util;
import static org.apache.atlas.AtlasErrorCode.INVALID_TYPE_DEFINITION; import static org.apache.atlas.AtlasErrorCode.INVALID_TYPE_DEFINITION;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_ON_DELETE; import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_OWNED_REF;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_VAL_CASCADE; import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY; import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_MAPPED_FROM_REF;
import static org.apache.atlas.type.AtlasTypeUtil.isArrayType; import static org.apache.atlas.type.AtlasTypeUtil.isArrayType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.TypeCategory; import org.apache.atlas.model.TypeCategory;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.typedef.AtlasClassificationDef; import org.apache.atlas.model.typedef.AtlasClassificationDef;
import org.apache.atlas.model.typedef.AtlasEntityDef; import org.apache.atlas.model.typedef.AtlasEntityDef;
import org.apache.atlas.model.typedef.AtlasEnumDef; import org.apache.atlas.model.typedef.AtlasEnumDef;
...@@ -45,7 +42,6 @@ import org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef; ...@@ -45,7 +42,6 @@ import org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef;
import org.apache.atlas.model.typedef.AtlasTypeDefHeader; import org.apache.atlas.model.typedef.AtlasTypeDefHeader;
import org.apache.atlas.model.typedef.AtlasTypesDef; import org.apache.atlas.model.typedef.AtlasTypesDef;
import org.apache.atlas.repository.store.graph.v1.AtlasStructDefStoreV1; import org.apache.atlas.repository.store.graph.v1.AtlasStructDefStoreV1;
import org.apache.atlas.type.AtlasArrayType;
import org.apache.atlas.type.AtlasClassificationType; import org.apache.atlas.type.AtlasClassificationType;
import org.apache.atlas.type.AtlasEntityType; import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasEnumType; import org.apache.atlas.type.AtlasEnumType;
...@@ -73,6 +69,13 @@ import org.slf4j.LoggerFactory; ...@@ -73,6 +69,13 @@ import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import static org.apache.atlas.AtlasErrorCode.INVALID_TYPE_DEFINITION;
import static org.apache.atlas.type.AtlasTypeUtil.isArrayType;
public final class RestUtils { public final class RestUtils {
...@@ -307,85 +310,6 @@ public final class RestUtils { ...@@ -307,85 +310,6 @@ public final class RestUtils {
AttributeDefinition[] attrDefinitions = classType.attributeDefinitions; AttributeDefinition[] attrDefinitions = classType.attributeDefinitions;
for (AttributeDefinition oldAttr : attrDefinitions) { for (AttributeDefinition oldAttr : attrDefinitions) {
AtlasAttributeDef newAttr = toAtlasAttributeDef(oldAttr); AtlasAttributeDef newAttr = toAtlasAttributeDef(oldAttr);
// isComposite and reverseAttributeName applicable only for entities/classes.
if (oldAttr.isComposite) {
String attrType = oldAttr.dataTypeName;
attrType = isArrayType(attrType) ? getArrayTypeName(attrType) : attrType;
if (!AtlasTypeUtil.isBuiltInType(attrType)) {
String refAttrName = null;
// 1. Check if attribute datatype is present in payload definition, if present get the typeDefinition,
// check all its attributes and find attribute that matches with classTypeDefName and reverseAttributeName
HierarchicalTypeDefinition<ClassType> refType = findClassType(classTypeDefinitions, attrType);
if (refType != null) {
for (AttributeDefinition refAttr : refType.attributeDefinitions) {
String refAttrDataTypeName = refAttr.dataTypeName;
String refAttrRevAttrName = refAttr.reverseAttributeName;
if (StringUtils.equals(refAttrDataTypeName, classTypeDefName) &&
StringUtils.equals(refAttrRevAttrName, oldAttr.name)) {
refAttrName = refAttr.name;
break;
}
}
}
// 2. Check if attribute present in typeRegistry. If present fetch all attributes associated with the type and
// check revAttrName equals base type attr name AND classTypeDefName equals attribute name
else {
if (registry.isRegisteredType(attrType)) {
AtlasType atlasType = registry.getType(attrType);
if (isEntity(atlasType)) {
AtlasEntityType entityType = (AtlasEntityType) atlasType;
List<AtlasAttributeDef> atlasAttrDefs = entityType.getEntityDef().getAttributeDefs();
for (AtlasAttributeDef attrDef : atlasAttrDefs) {
boolean isForeignKey = entityType.isForeignKeyAttribute(attrDef.getName());
if (isForeignKey) {
AtlasType attribType = entityType.getAttributeType(attrDef.getName());
if (attribType != null) {
if (attribType.getTypeCategory() == TypeCategory.ARRAY) {
attribType = ((AtlasArrayType) attribType).getElementType();
}
if (attribType.getTypeCategory() == TypeCategory.ENTITY) {
String revAttrName = ((AtlasEntityType) attribType).
getMappedFromRefAttribute(entityType.getTypeName(), attrDef.getName());
if (StringUtils.equals(classTypeDefName, attrDef.getTypeName()) &&
StringUtils.equals(oldAttr.name, revAttrName)) {
refAttrName = attrDef.getName();
}
}
}
}
}
}
}
}
if (StringUtils.isNotBlank(refAttrName)) { // ex: hive_table.columns, hive_column.table
Map<String, Object> params = new HashMap<>();
params.put(AtlasConstraintDef.CONSTRAINT_PARAM_REF_ATTRIBUTE, refAttrName);
newAttr.addConstraint(new AtlasConstraintDef(CONSTRAINT_TYPE_MAPPED_FROM_REF, params));
} else { // ex: hive_table.partitionKeys, with no reverseAttribute-reference
newAttr.addConstraint(new AtlasConstraintDef(CONSTRAINT_TYPE_FOREIGN_KEY));
}
}
} else if (StringUtils.isNotEmpty(oldAttr.reverseAttributeName)) {
Map<String, Object> params = new HashMap<>();
params.put(CONSTRAINT_PARAM_ON_DELETE, CONSTRAINT_PARAM_VAL_CASCADE);
newAttr.addConstraint(new AtlasConstraintDef(CONSTRAINT_TYPE_FOREIGN_KEY, params));
}
attrDefs.add(newAttr); attrDefs.add(newAttr);
} }
...@@ -432,13 +356,23 @@ public final class RestUtils { ...@@ -432,13 +356,23 @@ public final class RestUtils {
return ret.toArray(new EnumValue[ret.size()]); return ret.toArray(new EnumValue[ret.size()]);
} }
private static AtlasAttributeDef toAtlasAttributeDef(AttributeDefinition attrDefinition) { private static AtlasAttributeDef toAtlasAttributeDef(final AttributeDefinition attrDefinition) {
AtlasAttributeDef ret = new AtlasAttributeDef(); AtlasAttributeDef ret = new AtlasAttributeDef();
ret.setName(attrDefinition.name); ret.setName(attrDefinition.name);
ret.setTypeName(attrDefinition.dataTypeName); ret.setTypeName(attrDefinition.dataTypeName);
ret.setIsIndexable(attrDefinition.isIndexable); ret.setIsIndexable(attrDefinition.isIndexable);
ret.setIsUnique(attrDefinition.isUnique); ret.setIsUnique(attrDefinition.isUnique);
if (attrDefinition.isComposite) {
ret.addConstraint(new AtlasConstraintDef(CONSTRAINT_TYPE_OWNED_REF));
}
if (StringUtils.isNotBlank(attrDefinition.reverseAttributeName)) {
ret.addConstraint(new AtlasConstraintDef(CONSTRAINT_TYPE_INVERSE_REF,
new HashMap<String, Object>() {{
put(CONSTRAINT_PARAM_ATTRIBUTE, attrDefinition.reverseAttributeName);
}}));
}
// Multiplicity attribute mapping // Multiplicity attribute mapping
Multiplicity multiplicity = attrDefinition.multiplicity; Multiplicity multiplicity = attrDefinition.multiplicity;
......
...@@ -136,7 +136,7 @@ public class AtlasStructFormatConverter extends AtlasAbstractFormatConverter { ...@@ -136,7 +136,7 @@ public class AtlasStructFormatConverter extends AtlasAbstractFormatConverter {
Object v1Value = null; Object v1Value = null;
AtlasFormatConverter attrConverter = null; AtlasFormatConverter attrConverter = null;
if (attrType.getTypeCategory() == TypeCategory.ENTITY && !attr.legacyIsComposite()) { if (attrType.getTypeCategory() == TypeCategory.ENTITY && !attr.isOwnedRef()) {
attrConverter = new AtlasObjectIdConverter(converterRegistry, typeRegistry); attrConverter = new AtlasObjectIdConverter(converterRegistry, typeRegistry);
v1Value = attrConverter.fromV2ToV1(v2Value, attrType, context); v1Value = attrConverter.fromV2ToV1(v2Value, attrType, context);
} else { } else {
......
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
package org.apache.atlas.web.resources; package org.apache.atlas.web.resources;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_ON_DELETE; import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_OWNED_REF;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_VAL_CASCADE; import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_INVERSE_REF;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY; import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_ATTRIBUTE;
import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
...@@ -408,11 +408,10 @@ public abstract class BaseResourceIT { ...@@ -408,11 +408,10 @@ public abstract class BaseResourceIT {
protected void createTypeDefinitionsV2() throws Exception { protected void createTypeDefinitionsV2() throws Exception {
AtlasConstraintDef isCompositeSourceConstraint = new AtlasConstraintDef(CONSTRAINT_TYPE_FOREIGN_KEY, AtlasConstraintDef isCompositeSourceConstraint = new AtlasConstraintDef(CONSTRAINT_TYPE_OWNED_REF);
Collections.<String, Object>singletonMap(CONSTRAINT_PARAM_ON_DELETE, CONSTRAINT_PARAM_VAL_CASCADE));
AtlasConstraintDef isCompositeTargetConstraint = new AtlasConstraintDef(CONSTRAINT_TYPE_FOREIGN_KEY, AtlasConstraintDef isCompositeTargetConstraint = new AtlasConstraintDef(CONSTRAINT_TYPE_INVERSE_REF,
Collections.<String, Object>emptyMap()); Collections.<String, Object>singletonMap(CONSTRAINT_PARAM_ATTRIBUTE, "randomTable"));
AtlasEntityDef dbClsTypeDef = AtlasTypeUtil.createClassTypeDef( AtlasEntityDef dbClsTypeDef = AtlasTypeUtil.createClassTypeDef(
DATABASE_TYPE_V2, DATABASE_TYPE_V2,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment