blob: d89aca2b330aaf8a5ff5a028eb60caeb8ffecb96 [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.type;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasStruct;
import org.apache.atlas.model.typedef.AtlasStructDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef.Cardinality;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import static org.apache.atlas.model.TypeCategory.OBJECT_ID_TYPE;
import static org.apache.atlas.model.typedef.AtlasBaseTypeDef.ATLAS_TYPE_STRING;
import static org.apache.atlas.model.typedef.AtlasStructDef.AtlasConstraintDef.*;
/**
* class that implements behaviour of a struct-type.
*/
public class AtlasStructType extends AtlasType {
private static final Logger LOG = LoggerFactory.getLogger(AtlasStructType.class);
public static final String UNIQUE_ATTRIBUTE_SHADE_PROPERTY_PREFIX = "__u_";
private final AtlasStructDef structDef;
protected Map<String, AtlasAttribute> allAttributes = Collections.emptyMap();
protected Map<String, AtlasAttribute> uniqAttributes = Collections.emptyMap();
public AtlasStructType(AtlasStructDef structDef) {
super(structDef);
this.structDef = structDef;
}
public AtlasStructType(AtlasStructDef structDef, AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
super(structDef);
this.structDef = structDef;
this.resolveReferences(typeRegistry);
}
public AtlasStructDef getStructDef() { return structDef; }
public AtlasType getAttributeType(String attributeName) {
AtlasAttribute attribute = getAttribute(attributeName);
return attribute != null ? attribute.getAttributeType() : null;
}
public AtlasAttributeDef getAttributeDef(String attributeName) {
AtlasAttribute attribute = getAttribute(attributeName);
return attribute != null ? attribute.getAttributeDef() : null;
}
@Override
void resolveReferences(AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
Map<String, AtlasAttribute> a = new HashMap<>();
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
AtlasType attrType = typeRegistry.getType(attributeDef.getTypeName());
AtlasAttribute attribute = new AtlasAttribute(this, attributeDef, attrType);
Cardinality cardinality = attributeDef.getCardinality();
if (cardinality == Cardinality.LIST || cardinality == Cardinality.SET) {
if (!(attrType instanceof AtlasArrayType)) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_ATTRIBUTE_TYPE_FOR_CARDINALITY,
getTypeName(), attributeDef.getName());
}
AtlasArrayType arrayType = (AtlasArrayType)attrType;
arrayType.setMinCount(attributeDef.getValuesMinCount());
arrayType.setMaxCount(attributeDef.getValuesMaxCount());
arrayType.setCardinality(cardinality);
}
//check if attribute type is not classification
if (attrType instanceof AtlasArrayType) {
attrType = ((AtlasArrayType) attrType).getElementType();
} else if (attrType instanceof AtlasMapType) {
attrType = ((AtlasMapType) attrType).getValueType();
}
if (attrType instanceof AtlasClassificationType) {
throw new AtlasBaseException(AtlasErrorCode.ATTRIBUTE_TYPE_INVALID, getTypeName(), attributeDef.getName());
}
if (attrType instanceof AtlasBusinessMetadataType) {
throw new AtlasBaseException(AtlasErrorCode.ATTRIBUTE_TYPE_INVALID, getTypeName(), attributeDef.getName());
}
a.put(attributeDef.getName(), attribute);
}
resolveConstraints(typeRegistry);
this.allAttributes = Collections.unmodifiableMap(a);
this.uniqAttributes = getUniqueAttributes(this.allAttributes);
}
private void resolveConstraints(AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
for (AtlasAttributeDef attributeDef : getStructDef().getAttributeDefs()) {
if (CollectionUtils.isEmpty(attributeDef.getConstraints())) {
continue;
}
for (AtlasConstraintDef constraint : attributeDef.getConstraints()) {
if (constraint.isConstraintType(CONSTRAINT_TYPE_OWNED_REF)) {
AtlasEntityType attrType = getReferencedEntityType(typeRegistry.getType(attributeDef.getTypeName()));
if (attrType == null) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_OWNED_REF_ATTRIBUTE_INVALID_TYPE,
getTypeName(), attributeDef.getName(), CONSTRAINT_TYPE_OWNED_REF, attributeDef.getTypeName());
}
} else if (constraint.isConstraintType(CONSTRAINT_TYPE_INVERSE_REF)) {
AtlasEntityType attrType = getReferencedEntityType(typeRegistry.getType(attributeDef.getTypeName()));
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 (StringUtils.isBlank(inverseRefAttrName)) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_MISSING_PARAMS,
getTypeName(), attributeDef.getName(),
CONSTRAINT_PARAM_ATTRIBUTE, CONSTRAINT_TYPE_INVERSE_REF,
String.valueOf(constraint.getParams()));
}
AtlasAttributeDef inverseRefAttrDef = attrType.getStructDef().getAttribute(inverseRefAttrName);
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
void resolveReferencesPhase2(AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
super.resolveReferencesPhase2(typeRegistry);
for (AtlasAttribute attribute : allAttributes.values()) {
if (attribute.getInverseRefAttributeName() == null) {
continue;
}
// Set the inverse reference attribute.
AtlasType referencedType = typeRegistry.getType(attribute.getAttributeDef().getTypeName());
AtlasEntityType referencedEntityType = getReferencedEntityType(referencedType);
AtlasAttribute inverseReference = referencedEntityType.getAttribute(attribute.getInverseRefAttributeName());
attribute.setInverseRefAttribute(inverseReference);
}
}
@Override
public AtlasStruct createDefaultValue() {
AtlasStruct ret = new AtlasStruct(structDef.getName());
populateDefaultValues(ret);
return ret;
}
@Override
public Object createDefaultValue(Object defaultValue) {
AtlasStruct ret = new AtlasStruct(structDef.getName());
populateDefaultValues(ret);
return ret;
}
public Map<String, AtlasAttribute> getAllAttributes() {
return allAttributes;
}
public Map<String, AtlasAttribute> getUniqAttributes() {
return uniqAttributes;
}
public AtlasAttribute getAttribute(String attributeName) {
AtlasAttribute ret = allAttributes.get(attributeName);
if (ret == null) {
ret = getSystemAttribute(attributeName);
}
if (ret == null) {
ret = getBusinesAAttribute(attributeName);
}
return ret;
}
public AtlasAttribute getSystemAttribute(String attributeName) {
return null;
}
public AtlasAttribute getBusinesAAttribute(String attributeName) {
return null;
}
@Override
public boolean isValidValue(Object obj) {
if (obj != null) {
if (obj instanceof AtlasStruct) {
AtlasStruct structObj = (AtlasStruct) obj;
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
if (!isAssignableValue(structObj.getAttribute(attributeDef.getName()), attributeDef)) {
return false;
}
}
} else if (obj instanceof Map) {
Map map = AtlasTypeUtil.toStructAttributes((Map) obj);
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
if (!isAssignableValue(map.get(attributeDef.getName()), attributeDef)) {
return false; // no value for non-optinal attribute
}
}
} else {
return false;
}
}
return true;
}
@Override
public boolean areEqualValues(Object val1, Object val2, Map<String, String> guidAssignments) {
boolean ret = true;
if (val1 == null) {
ret = val2 == null;
} else if (val2 == null) {
ret = false;
} else {
AtlasStruct structVal1 = getStructFromValue(val1);
if (structVal1 == null) {
ret = false;
} else {
AtlasStruct structVal2 = getStructFromValue(val2);
if (structVal2 == null) {
ret = false;
} else if (!StringUtils.equalsIgnoreCase(structVal1.getTypeName(), structVal2.getTypeName())) {
ret = false;
} else {
for (AtlasAttribute attribute : getAllAttributes().values()) {
Object attrValue1 = structVal1.getAttribute(attribute.getName());
Object attrValue2 = structVal2.getAttribute(attribute.getName());
if (!attribute.getAttributeType().areEqualValues(attrValue1, attrValue2, guidAssignments)) {
ret = false;
break;
}
}
}
}
}
return ret;
}
@Override
public boolean isValidValueForUpdate(Object obj) {
if (obj != null) {
Map<String, Object> attributes;
if (obj instanceof AtlasStruct) {
AtlasStruct structObj = (AtlasStruct) obj;
attributes = structObj.getAttributes();
} else if (obj instanceof Map) {
attributes = AtlasTypeUtil.toStructAttributes((Map) obj);
} else {
return false;
}
if (MapUtils.isNotEmpty(attributes)) {
for (Map.Entry<String, Object> e : attributes.entrySet()) {
String attrName = e.getKey();
Object attrValue = e.getValue();
AtlasAttributeDef attrDef = structDef.getAttribute(attrName);
if (attrValue == null || attrDef == null) {
continue;
}
if (!isAssignableValueForUpdate(attrValue, attrDef)) {
return false;
}
}
}
}
return true;
}
@Override
public Object getNormalizedValue(Object obj) {
Object ret = null;
if (obj != null) {
if (isValidValue(obj)) {
if (obj instanceof AtlasStruct) {
normalizeAttributeValues((AtlasStruct) obj);
ret = obj;
} else if (obj instanceof Map) {
normalizeAttributeValues((Map) obj);
ret = obj;
}
}
}
return ret;
}
@Override
public Object getNormalizedValueForUpdate(Object obj) {
Object ret = null;
if (obj != null) {
if (isValidValueForUpdate(obj)) {
if (obj instanceof AtlasStruct) {
normalizeAttributeValuesForUpdate((AtlasStruct) obj);
ret = obj;
} else if (obj instanceof Map) {
normalizeAttributeValuesForUpdate((Map) obj);
ret = obj;
}
}
}
return ret;
}
@Override
public boolean validateValue(Object obj, String objName, List<String> messages) {
boolean ret = true;
if (obj != null) {
if (obj instanceof AtlasStruct) {
AtlasStruct structObj = (AtlasStruct) obj;
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
String attrName = attributeDef.getName();
AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
if (attribute != null) {
AtlasType dataType = attribute.getAttributeType();
Object value = structObj.getAttribute(attrName);
String fieldName = objName + "." + attrName;
if (value != null) {
ret = dataType.validateValue(value, fieldName, messages) && ret;
} else if (!attributeDef.getIsOptional()) {
// if required attribute is null, check if attribute value specified in relationship
if (structObj instanceof AtlasEntity) {
AtlasEntity entityObj = (AtlasEntity) structObj;
if (entityObj.getRelationshipAttribute(attrName) == null) {
ret = false;
messages.add(fieldName + ": mandatory attribute value missing in type " + getTypeName());
}
} else {
ret = false;
messages.add(fieldName + ": mandatory attribute value missing in type " + getTypeName());
}
}
}
}
} else if (obj instanceof Map) {
Map attributes = AtlasTypeUtil.toStructAttributes((Map)obj);
Map relationshipAttributes = AtlasTypeUtil.toRelationshipAttributes((Map)obj);
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
String attrName = attributeDef.getName();
AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
if (attribute != null) {
AtlasType dataType = attribute.getAttributeType();
Object value = attributes.get(attrName);
String fieldName = objName + "." + attrName;
if (value != null) {
ret = dataType.validateValue(value, fieldName, messages) && ret;
} else if (!attributeDef.getIsOptional()) {
// if required attribute is null, check if attribute value specified in relationship
if (MapUtils.isEmpty(relationshipAttributes) || !relationshipAttributes.containsKey(attrName)) {
ret = false;
messages.add(fieldName + ": mandatory attribute value missing in type " + getTypeName());
}
}
}
}
} else {
ret = false;
messages.add(objName + "=" + obj + ": invalid value for type " + getTypeName());
}
}
return ret;
}
@Override
public boolean validateValueForUpdate(Object obj, String objName, List<String> messages) {
boolean ret = true;
Map<String, Object> attributes = null;
if (obj != null) {
if (obj instanceof AtlasStruct) {
AtlasStruct structObj = (AtlasStruct) obj;
attributes = structObj.getAttributes();
} else if (obj instanceof Map) {
attributes = AtlasTypeUtil.toStructAttributes((Map) obj);
} else {
ret = false;
messages.add(objName + "=" + obj + ": invalid value for type " + getTypeName());
}
if (MapUtils.isNotEmpty(attributes)) {
for (Map.Entry<String, Object> e : attributes.entrySet()) {
String attrName = e.getKey();
Object attrValue = e.getValue();
AtlasAttribute attribute = allAttributes.get(attrName);
if (attrValue == null) {
continue;
}
if (attribute != null) {
AtlasType dataType = attribute.getAttributeType();
String fieldName = objName + "." + attrName;
ret = dataType.validateValueForUpdate(attrValue, fieldName, messages) && ret;
}
}
}
}
return ret;
}
public void normalizeAttributeValues(AtlasStruct obj) {
if (obj != null) {
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
String attributeName = attributeDef.getName();
if (obj.hasAttribute(attributeName)) {
Object attributeValue = getNormalizedValue(obj.getAttribute(attributeName), attributeDef);
obj.setAttribute(attributeName, attributeValue);
} else if (!attributeDef.getIsOptional()) {
obj.setAttribute(attributeName, createDefaultValue(attributeDef));
}
}
}
}
public void normalizeAttributeValuesForUpdate(AtlasStruct obj) {
if (obj != null) {
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
String attributeName = attributeDef.getName();
if (obj.hasAttribute(attributeName)) {
Object attributeValue = getNormalizedValueForUpdate(obj.getAttribute(attributeName), attributeDef);
obj.setAttribute(attributeName, attributeValue);
}
}
}
}
public void normalizeAttributeValues(Map<String, Object> obj) {
if (obj != null) {
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
String attributeName = attributeDef.getName();
if (obj.containsKey(attributeName)) {
Object attributeValue = getNormalizedValue(obj.get(attributeName), attributeDef);
obj.put(attributeName, attributeValue);
} else if (!attributeDef.getIsOptional()) {
obj.put(attributeName, createDefaultValue(attributeDef));
}
}
}
}
public void normalizeAttributeValuesForUpdate(Map<String, Object> obj) {
if (obj != null) {
for (AtlasAttributeDef attrDef : structDef.getAttributeDefs()) {
String attrName = attrDef.getName();
Object attrValue = obj.get(attrName);
if (obj.containsKey(attrName)) {
attrValue = getNormalizedValueForUpdate(attrValue, attrDef);
obj.put(attrName, attrValue);
}
}
}
}
public void populateDefaultValues(AtlasStruct obj) {
if (obj != null) {
Map<String, Object> attributes = obj.getAttributes();
if (attributes == null) {
attributes = new HashMap<>();
}
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
if (!attributeDef.getIsOptional()) {
attributes.put(attributeDef.getName(), createDefaultValue(attributeDef));
}
}
obj.setAttributes(attributes);
}
}
private Object createDefaultValue(AtlasAttributeDef attributeDef) {
Object ret = null;
if (attributeDef != null) {
AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
if (attribute != null) {
AtlasType dataType = attribute.getAttributeType();
ret = dataType.createDefaultValue(attributeDef.getDefaultValue());
}
}
return ret;
}
private boolean isAssignableValue(Object value, AtlasAttributeDef attributeDef) {
boolean ret = true;
if (value != null) {
AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
if (attribute != null) {
AtlasType attrType = attribute.getAttributeType();
if (!attrType.isValidValue(value)) {
ret = false; // invalid value
}
}
} else if (!attributeDef.getIsOptional()) {
ret = false; // mandatory attribute not present
}
return ret;
}
private boolean isAssignableValueForUpdate(Object value, AtlasAttributeDef attributeDef) {
boolean ret = true;
if (value != null) {
AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
if (attribute != null) {
AtlasType attrType = attribute.getAttributeType();
if (!attrType.isValidValueForUpdate(value)) {
ret = false; // invalid value
}
}
}
return ret;
}
private Object getNormalizedValue(Object value, AtlasAttributeDef attributeDef) {
AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
if (attribute != null) {
AtlasType attrType = attribute.getAttributeType();
if (value == null) {
if (!attributeDef.getIsOptional()) {
return attrType.createDefaultValue();
}
} else {
return attrType.getNormalizedValue(value);
}
}
return null;
}
private Object getNormalizedValueForUpdate(Object value, AtlasAttributeDef attributeDef) {
AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
if (attribute != null) {
AtlasType attrType = attribute.getAttributeType();
if (value != null) {
return attrType.getNormalizedValueForUpdate(value);
}
}
return null;
}
public String getVertexPropertyName(String attrName) throws AtlasBaseException {
AtlasAttribute attribute = getAttribute(attrName);
if (attribute != null) {
return attribute.getVertexPropertyName();
}
throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_ATTRIBUTE, attrName, structDef.getName());
}
public String getQualifiedAttributePropertyKey(String attrName) throws AtlasBaseException {
if ( allAttributes.containsKey(attrName)) {
return allAttributes.get(attrName).getVertexPropertyName();
}
throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_ATTRIBUTE, attrName, structDef.getName());
}
static AtlasEntityType getReferencedEntityType(AtlasType type) {
if (type instanceof AtlasArrayType) {
type = ((AtlasArrayType)type).getElementType();
}
if (type instanceof AtlasMapType) {
type = ((AtlasMapType)type).getValueType();
}
return type instanceof AtlasEntityType ? (AtlasEntityType)type : null;
}
protected Map<String, AtlasAttribute> getUniqueAttributes(Map<String, AtlasAttribute> attributes) {
Map<String, AtlasAttribute> ret = new HashMap<>();
if (MapUtils.isNotEmpty(attributes)) {
for (AtlasAttribute attribute : attributes.values()) {
if (attribute.getAttributeDef().getIsUnique()) {
ret.put(attribute.getName(), attribute);
}
}
}
return Collections.unmodifiableMap(ret);
}
private AtlasStruct getStructFromValue(Object val) {
final AtlasStruct ret;
if (val instanceof AtlasStruct) {
ret = (AtlasStruct) val;
} else if (val instanceof Map) {
ret = new AtlasStruct((Map) val);
} else if (val instanceof String) {
Map map = AtlasType.fromJson(val.toString(), Map.class);
if (map == null) {
ret = null;
} else {
ret = new AtlasStruct((Map) val);
}
} else {
ret = null;
}
return ret;
}
public static class AtlasAttribute {
public static final Object VERTEX_PROPERTY_PREFIX_STRING_INDEX_TYPE = "__s_";
private final AtlasStructType definedInType;
private final AtlasType attributeType;
private final AtlasAttributeDef attributeDef;
private final String qualifiedName;
private final String vertexPropertyName;
private final String vertexUniquePropertyName;
private final boolean isOwnedRef;
private final boolean isObjectRef;
private final String inverseRefAttributeName;
private AtlasAttribute inverseRefAttribute;
private String relationshipName;
private String relationshipEdgeLabel;
private AtlasRelationshipEdgeDirection relationshipEdgeDirection;
private boolean isLegacyAttribute;
private String indexFieldName;
private boolean isDynAttribute = false;
private boolean isDynAttributeEvalTrigger = false;
public AtlasAttribute(AtlasStructType definedInType, AtlasAttributeDef attrDef, AtlasType attributeType, String relationshipName, String relationshipLabel) {
this.definedInType = definedInType;
this.attributeDef = attrDef;
this.attributeType = attributeType.getTypeForAttribute();
this.qualifiedName = getQualifiedAttributeName(definedInType.getStructDef(), attributeDef.getName());
this.vertexPropertyName = generateVertexPropertyName(definedInType.getStructDef(), attributeDef, qualifiedName);
this.vertexUniquePropertyName = attrDef.getIsUnique() ? encodePropertyKey(getQualifiedAttributeName(definedInType.getStructDef(), UNIQUE_ATTRIBUTE_SHADE_PROPERTY_PREFIX + attributeDef.getName())) : null;
this.relationshipName = relationshipName;
this.relationshipEdgeLabel = getRelationshipEdgeLabel(relationshipLabel);
boolean isOwnedRef = false;
String inverseRefAttribute = null;
LOG.debug("Attribute {} will use the vertext property name {}.", qualifiedName, vertexPropertyName);
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.inverseRefAttributeName = inverseRefAttribute;
this.relationshipEdgeDirection = AtlasRelationshipEdgeDirection.OUT;
switch (this.attributeType.getTypeCategory()) {
case OBJECT_ID_TYPE:
isObjectRef = true;
break;
case MAP:
AtlasMapType mapType = (AtlasMapType) this.attributeType;
isObjectRef = mapType.getValueType().getTypeCategory() == OBJECT_ID_TYPE;
break;
case ARRAY:
AtlasArrayType arrayType = (AtlasArrayType) this.attributeType;
isObjectRef = arrayType.getElementType().getTypeCategory() == OBJECT_ID_TYPE;
break;
default:
isObjectRef = false;
break;
}
}
public AtlasAttribute(AtlasStructType definedInType, AtlasAttributeDef attrDef, AtlasType attributeType) {
this(definedInType, attrDef, attributeType, null, null);
}
public AtlasAttribute(AtlasAttribute other) {
this.definedInType = other.definedInType;
this.attributeType = other.attributeType;
this.attributeDef = other.attributeDef;
this.qualifiedName = other.qualifiedName;
this.vertexPropertyName = other.vertexPropertyName;
this.vertexUniquePropertyName = other.vertexUniquePropertyName;
this.isOwnedRef = other.isOwnedRef;
this.isObjectRef = other.isObjectRef;
this.inverseRefAttributeName = other.inverseRefAttributeName;
this.inverseRefAttribute = other.inverseRefAttribute;
this.relationshipName = other.relationshipName;
this.relationshipEdgeLabel = other.relationshipEdgeLabel;
this.relationshipEdgeDirection = other.relationshipEdgeDirection;
this.isLegacyAttribute = other.isLegacyAttribute;
this.indexFieldName = other.indexFieldName;
this.isDynAttribute = false;
this.isDynAttributeEvalTrigger = false;
}
public AtlasStructType getDefinedInType() { return definedInType; }
public AtlasStructDef getDefinedInDef() { return definedInType.getStructDef(); }
public AtlasType getAttributeType() {
return attributeType;
}
public AtlasAttributeDef getAttributeDef() {
return attributeDef;
}
public String getName() { return attributeDef.getName(); }
public String getTypeName() { return attributeDef.getTypeName(); }
public String getQualifiedName() { return qualifiedName; }
public String getVertexPropertyName() { return vertexPropertyName; }
public String getVertexUniquePropertyName() { return vertexUniquePropertyName; }
public boolean isOwnedRef() { return isOwnedRef; }
public boolean isObjectRef() { return isObjectRef; }
public String getInverseRefAttributeName() { return inverseRefAttributeName; }
public AtlasAttribute getInverseRefAttribute() { return inverseRefAttribute; }
public void setInverseRefAttribute(AtlasAttribute inverseAttr) { inverseRefAttribute = inverseAttr; }
public String getRelationshipName() { return relationshipName; }
public void setRelationshipName(String relationshipName) { this.relationshipName = relationshipName; }
public String getRelationshipEdgeLabel() { return relationshipEdgeLabel; }
public void setRelationshipEdgeLabel(String relationshipEdgeLabel) { this.relationshipEdgeLabel = relationshipEdgeLabel; }
public AtlasRelationshipEdgeDirection getRelationshipEdgeDirection() { return relationshipEdgeDirection; }
public void setRelationshipEdgeDirection(AtlasRelationshipEdgeDirection relationshipEdgeDirection) {
this.relationshipEdgeDirection = relationshipEdgeDirection;
}
public boolean isLegacyAttribute() { return isLegacyAttribute; }
public void setLegacyAttribute(boolean legacyAttribute) { isLegacyAttribute = legacyAttribute; }
public String getIndexFieldName() { return indexFieldName; }
public void setIndexFieldName(String indexFieldName) { this.indexFieldName = indexFieldName; }
public int getSearchWeight() { return attributeDef.getSearchWeight(); }
public AtlasAttributeDef.IndexType getIndexType() { return attributeDef.getIndexType();}
public boolean getIsDynAttribute() { return isDynAttribute; }
public void setIsDynAttribute(boolean isDynAttribute){ this.isDynAttribute = isDynAttribute; }
public boolean getIsDynAttributeEvalTrigger() { return isDynAttributeEvalTrigger; }
public void setIsDynAttributeEvalTrigger(boolean isDynAttributeEvalTrigger) { this.isDynAttributeEvalTrigger = isDynAttributeEvalTrigger; }
public Set<String> getOptionSet(String optionName) {
String strValue = attributeDef.getOption(optionName);
Set<String> ret = StringUtils.isBlank(strValue) ? null : AtlasType.fromJson(strValue, Set.class);
return ret;
}
public Integer getOptionInt(String optionName) {
String strValue = attributeDef.getOption(optionName);
Integer ret = StringUtils.isBlank(strValue) ? null : Integer.parseInt(strValue);
return ret;
}
public String getOptionString(String optionName) {
String strValue = attributeDef.getOption(optionName);
String ret = StringUtils.isBlank(strValue) ? null : strValue;
return ret;
}
public static String getEdgeLabel(String property) {
return "__" + property;
}
public static String encodePropertyKey(String key) {
if (StringUtils.isBlank(key)) {
return key;
}
for (String[] strMap : RESERVED_CHAR_ENCODE_MAP) {
key = key.replace(strMap[0], strMap[1]);
}
return key;
}
public static String decodePropertyKey(String key) {
if (StringUtils.isBlank(key)) {
return key;
}
for (String[] strMap : RESERVED_CHAR_ENCODE_MAP) {
key = key.replace(strMap[1], strMap[0]);
}
return key;
}
public static String escapeIndexQueryValue(Collection<String> values) {
return escapeIndexQueryValue(values, false);
}
public static String escapeIndexQueryValue(Collection<String> values, boolean allowWildcard) {
StringBuilder sb = new StringBuilder();
sb.append(BRACE_OPEN_CHAR);
if (CollectionUtils.isNotEmpty(values)) {
Iterator<String> iter = values.iterator();
sb.append(escapeIndexQueryValue(iter.next(), allowWildcard));
while (iter.hasNext()) {
sb.append(SPACE_CHAR).append(escapeIndexQueryValue(iter.next(), allowWildcard));
}
}
sb.append(BRACE_CLOSE_CHAR);
return sb.toString();
}
public static String escapeIndexQueryValue(String value) {
return escapeIndexQueryValue(value, false, true);
}
public static String escapeIndexQueryValue(String value, boolean allowWildcard) {
return escapeIndexQueryValue(value, allowWildcard, true);
}
public static String escapeIndexQueryValue(String value, boolean allowWildcard, boolean shouldQuote) {
String ret = value;
boolean quoteValue = false;
if (hasIndexQueryEscapeChar(value)) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < value.length(); i++) {
char c = value.charAt(i);
if (!(allowWildcard && c == '*') && isIndexQueryEscapeChar(c)) {
sb.append('\\');
}
if (shouldQuote && !quoteValue) {
quoteValue = shouldQuoteIndexQueryForChar(c);
}
sb.append(c);
}
ret = sb.toString();
} else if (value != null) {
for (int i = 0; i < value.length(); i++) {
if (shouldQuote && shouldQuoteIndexQueryForChar(value.charAt(i))) {
quoteValue = true;
break;
}
}
}
if (quoteValue) {
boolean isQuoteAtStart = ret.charAt(0) == DOUBLE_QUOTE_CHAR;
boolean isQuoteAtEnd = ret.charAt(ret.length() - 1) == DOUBLE_QUOTE_CHAR;
if (!isQuoteAtStart) {
if (!isQuoteAtEnd) {
ret = DOUBLE_QUOTE_CHAR + ret + DOUBLE_QUOTE_CHAR;
} else {
ret = DOUBLE_QUOTE_CHAR + ret;
}
} else if (!isQuoteAtEnd) {
ret = ret + DOUBLE_QUOTE_CHAR;
}
}
return ret;
}
private static boolean hasIndexQueryEscapeChar(String value) {
if (value != null) {
for (int i = 0; i < value.length(); i++) {
if (isIndexQueryEscapeChar(value.charAt(i))) {
return true;
}
}
}
return false;
}
private static boolean isIndexQueryEscapeChar(char c) {
switch (c) {
case '+':
case '-':
case '&':
case '|':
case '!':
case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
case '^':
case '"':
case '~':
case '*':
case '?':
case ':':
case '\\':
case '/':
case ' ':
return true;
}
return false;
}
public static boolean hastokenizeChar(String value) {
if (value != null) {
for (int i = 0; i < value.length(); i++) {
if (hastokenizeChar(value, i)) {
return true;
}
}
}
return false;
}
private static boolean hastokenizeChar(String value, int i) {
char c = value.charAt(i);
if (!Character.isLetterOrDigit(c)) {
switch (c) {
case '_':
return false;
case '.':
case ':':
case '\'':
if (i > 0 && !Character.isAlphabetic(value.charAt(i - 1))) {
return true;
}
if (i < value.length() - 1 && !Character.isAlphabetic(value.charAt(i + 1))) {
return true;
}
return false;
}
return true;
}
return false;
}
private static boolean shouldQuoteIndexQueryForChar(char c) {
switch (c) {
case '@':
case ' ':
case '+':
case '-':
case '&':
case '|':
case '!':
case '(':
case ')':
case '{':
case '}':
case '[':
case ']':
case '^':
case '"':
case '~':
case '?':
case ':':
case '\\':
case '/':
return true;
}
return false;
}
private String getRelationshipEdgeLabel(String relationshipLabel) {
return (relationshipLabel == null) ? getEdgeLabel(qualifiedName) : relationshipLabel;
}
public AtlasEntityType getReferencedEntityType(AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
AtlasType type = typeRegistry.getType(attributeDef.getTypeName());
return AtlasStructType.getReferencedEntityType(type);
}
public static String getQualifiedAttributeName(AtlasStructDef structDef, String attrName) {
if (isRootType(structDef)) {
return attrName;
} else {
return attrName.contains(".") ? attrName : String.format("%s.%s", structDef.getName(), attrName);
}
}
public static String generateVertexPropertyName(AtlasStructDef structDef, AtlasAttributeDef attrDef, String qualifiedName) {
String vertexPropertyName = qualifiedName;
String attrName = attrDef.getName();
if (isRootType(structDef)) {
return attrName;
} else {
if(!attrDef.getName().contains(".") &&
AtlasAttributeDef.IndexType.STRING.equals(attrDef.getIndexType()) &&
ATLAS_TYPE_STRING.equalsIgnoreCase(attrDef.getTypeName())) {
vertexPropertyName = String.format("%s.%s%s", structDef.getName(), VERTEX_PROPERTY_PREFIX_STRING_INDEX_TYPE, attrDef.getName());
}
}
return encodePropertyKey(vertexPropertyName);
}
private static boolean isRootType(AtlasStructDef structDef) {
return StringUtils.equals(structDef.getName(), AtlasEntityType.ENTITY_ROOT.getTypeName()) ||
StringUtils.equals(structDef.getName(), AtlasClassificationType.CLASSIFICATION_ROOT.getTypeName());
}
// Keys copied from org.janusgraph.graphdb.types.system.SystemTypeManager.RESERVED_CHARS
// JanusGraph checks that these chars are not part of any keys hence encoding
// also including Titan reserved characters to support migrated property keys
private static String[][] RESERVED_CHAR_ENCODE_MAP = new String[][]{
new String[] {"{", "_o"},
new String[] {"}", "_c"},
new String[] {"\"", "_q"},
new String[] {"$", "_d"}, //titan reserved character
new String[] {"%", "_p"}, //titan reserved characters
};
private static final char BRACE_OPEN_CHAR = '(';
private static final char BRACE_CLOSE_CHAR = ')';
private static final char DOUBLE_QUOTE_CHAR = '"';
private static final char SPACE_CHAR = ' ';
public enum AtlasRelationshipEdgeDirection { IN, OUT, BOTH }
}
}