You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2020/02/07 06:15:55 UTC
[atlas] branch master updated: ATLAS-3534: enhancements to support
add/update/delete namespace-attributes on entities
This is an automated email from the ASF dual-hosted git repository.
madhan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/atlas.git
The following commit(s) were added to refs/heads/master by this push:
new d3a08b6 ATLAS-3534: enhancements to support add/update/delete namespace-attributes on entities
d3a08b6 is described below
commit d3a08b6eabcc50536c468db2d1328df54ee27fce
Author: Mandar Ambawane <ma...@freestoneinfotech.com>
AuthorDate: Thu Feb 6 14:45:49 2020 +0530
ATLAS-3534: enhancements to support add/update/delete namespace-attributes on entities
Signed-off-by: Madhan Neethiraj <ma...@apache.org>
---
.../org/apache/atlas/repository/Constants.java | 3 +-
.../main/java/org/apache/atlas/AtlasErrorCode.java | 41 +++---
.../apache/atlas/model/instance/AtlasEntity.java | 56 +++++++-
.../org/apache/atlas/type/AtlasNamespaceType.java | 17 +--
.../org/apache/atlas/type/AtlasTypeRegistry.java | 1 +
.../repository/store/graph/AtlasEntityStore.java | 17 +++
.../store/graph/v2/AtlasEntityStoreV2.java | 122 ++++++++++++++++-
.../store/graph/v2/EntityGraphMapper.java | 146 ++++++++++++++++++++-
.../store/graph/v2/EntityGraphRetriever.java | 23 ++++
.../java/org/apache/atlas/web/rest/EntityREST.java | 73 +++++++++++
10 files changed, 455 insertions(+), 44 deletions(-)
diff --git a/common/src/main/java/org/apache/atlas/repository/Constants.java b/common/src/main/java/org/apache/atlas/repository/Constants.java
index 0b28243..7c0fd56 100644
--- a/common/src/main/java/org/apache/atlas/repository/Constants.java
+++ b/common/src/main/java/org/apache/atlas/repository/Constants.java
@@ -88,14 +88,13 @@ public final class Constants {
public static final String VERSION_PROPERTY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "version");
public static final String STATE_PROPERTY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "state");
public static final String CREATED_BY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "createdBy");
+ public static final String MODIFIED_BY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "modifiedBy");
public static final String CLASSIFICATION_TEXT_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "classificationsText");
public static final String CLASSIFICATION_NAMES_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "classificationNames");
public static final String PROPAGATED_CLASSIFICATION_NAMES_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "propagatedClassificationNames");
public static final String CUSTOM_ATTRIBUTES_PROPERTY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "customAttributes");
public static final String LABELS_PROPERTY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "labels");
- public static final String MODIFIED_BY_KEY = encodePropertyKey(INTERNAL_PROPERTY_KEY_PREFIX + "modifiedBy");
-
/**
* Patch vertices property keys.
*/
diff --git a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
index 2054513..1670bda 100644
--- a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
+++ b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
@@ -147,25 +147,28 @@ public enum AtlasErrorCode {
ATTRIBUTE_TYPE_INVALID(400, "ATLAS-400-00-081", "{0}.{1}: invalid attribute type. Attribute cannot be of type classification"),
MISSING_CATEGORY_DISPLAY_NAME(400, "ATLAS-400-00-082", "Category name is empty/null"),
INVALID_DISPLAY_NAME(400, "ATLAS-400-00-083", "name cannot contain following special chars ('@', '.')"),
- TERM_HAS_ENTITY_ASSOCIATION(400, "ATLAS-400-00-086", "Term (guid={0}) can't be deleted as it has been assigned to {1} entities."),
- INVALID_TIMEBOUNDRY_TIMEZONE(400, "ATLAS-400-00-87A", "Invalid timezone {0}"),
- INVALID_TIMEBOUNDRY_START_TIME(400, "ATLAS-400-00-87B", "Invalid startTime {0}"),
- INVALID_TIMEBOUNDRY_END_TIME(400, "ATLAS-400-00-87C", "Invalid endTime {0}"),
- INVALID_TIMEBOUNDRY_DATERANGE(400, "ATLAS-400-00-87D", "Invalid dateRange: startTime {0} must be before endTime {1}"),
- PROPAGATED_CLASSIFICATION_REMOVAL_NOT_SUPPORTED(400, "ATLAS-400-00-87E", "Removal of classification {0}, which is propagated from entity {1}, is not supported"),
- IMPORT_ATTEMPTING_EMPTY_ZIP(400, "ATLAS-400-00-87F", "Attempting to import empty ZIP file."),
- PATCH_MISSING_RELATIONSHIP_LABEL(400, "ATLAS-400-00-88", "{0} - must include relationship label for type {1}"),
- INVALID_CUSTOM_ATTRIBUTE_KEY_LENGTH(400, "ATLAS-400-00-89", "Invalid key: {0} in custom attribute, key size should not be greater than 50"),
- INVALID_CUSTOM_ATTRIBUTE_KEY_CHARACTERS(400, "ATLAS-400-00-90", "Invalid key: {0} in custom attribute, key should only contain alphanumeric characters, '_' or '-'"),
- INVALID_CUSTOM_ATTRIBUTE_VALUE(400, "ATLAS-400-00-9A", "Invalid value: {0} in custom attribute, value length is greater than {1}"),
- INVALID_LABEL_LENGTH(400, "ATLAS-400-00-9B", "Invalid label: {0}, label size should not be greater than {1}"),
- INVALID_LABEL_CHARACTERS(400, "ATLAS-400-00-9C", "Invalid label: {0}, label should contain alphanumeric characters, '_' or '-'"),
- INVALID_PROPAGATION_TYPE(400, "ATLAS-400-00-9D", "Invalid propagation {0} for relationship-type={1}. Default value is {2}"),
- DUPLICATE_NAMESPACE_ATTRIBUTE(400, "ATLAS-400-00-094", "Duplicate Namespace Attributes: {0} not allowed within the same namespace: {1}"),
- APPLICABLE_ENTITY_TYPES_DELETION_NOT_SUPPORTED(400, "ATLAS-400-00-095", "Cannot remove applicableEntityTypes in Attribute Def: {1}, defined in namespace: {2}"),
- NAMESPACE_DEF_MANDATORY_ATTRIBUTE_NOT_ALLOWED(400, "ATLAS-400-00-096", "{0}.{1} : namespaces can not have mandatory attribute"),
- NAMESPACE_DEF_UNIQUE_ATTRIBUTE_NOT_ALLOWED(400, "ATLAS-400-00-097", "{0}.{1} : namespaces can not have unique attribute"),
- NAMESPACE_DEF_ATTRIBUTE_TYPE_INVALID(400, "ATLAS-400-00-098", "{0}.{1}: invalid attribute type. Namespace attribute cannot be of type entity/classification/struct/namespace"),
+ TERM_HAS_ENTITY_ASSOCIATION(400, "ATLAS-400-00-084", "Term (guid={0}) can't be deleted as it has been assigned to {1} entities."),
+ INVALID_TIMEBOUNDRY_TIMEZONE(400, "ATLAS-400-00-085", "Invalid timezone {0}"),
+ INVALID_TIMEBOUNDRY_START_TIME(400, "ATLAS-400-00-086", "Invalid startTime {0}"),
+ INVALID_TIMEBOUNDRY_END_TIME(400, "ATLAS-400-00-087", "Invalid endTime {0}"),
+ INVALID_TIMEBOUNDRY_DATERANGE(400, "ATLAS-400-00-088", "Invalid dateRange: startTime {0} must be before endTime {1}"),
+ PROPAGATED_CLASSIFICATION_REMOVAL_NOT_SUPPORTED(400, "ATLAS-400-00-089", "Removal of classification {0}, which is propagated from entity {1}, is not supported"),
+ IMPORT_ATTEMPTING_EMPTY_ZIP(400, "ATLAS-400-00-08A", "Attempting to import empty ZIP file."),
+ PATCH_MISSING_RELATIONSHIP_LABEL(400, "ATLAS-400-00-08B", "{0} - must include relationship label for type {1}"),
+ INVALID_CUSTOM_ATTRIBUTE_KEY_LENGTH(400, "ATLAS-400-00-08C", "Invalid key: {0} in custom attribute, key size should not be greater than 50"),
+ INVALID_CUSTOM_ATTRIBUTE_KEY_CHARACTERS(400, "ATLAS-400-00-08D", "Invalid key: {0} in custom attribute, key should only contain alphanumeric characters, '_' or '-'"),
+ INVALID_CUSTOM_ATTRIBUTE_VALUE(400, "ATLAS-400-00-08E", "Invalid value: {0} in custom attribute, value length is greater than {1}"),
+ INVALID_LABEL_LENGTH(400, "ATLAS-400-00-08F", "Invalid label: {0}, label size should not be greater than {1}"),
+ INVALID_LABEL_CHARACTERS(400, "ATLAS-400-00-090", "Invalid label: {0}, label should contain alphanumeric characters, '_' or '-'"),
+ INVALID_PROPAGATION_TYPE(400, "ATLAS-400-00-091", "Invalid propagation {0} for relationship-type={1}. Default value is {2}"),
+ DUPLICATE_NAMESPACE_ATTRIBUTE(400, "ATLAS-400-00-092", "Duplicate Namespace Attributes: {0} not allowed within the same namespace: {1}"),
+ APPLICABLE_ENTITY_TYPES_DELETION_NOT_SUPPORTED(400, "ATLAS-400-00-093", "Cannot remove applicableEntityTypes in Attribute Def: {0}, defined in namespace: {1}"),
+ NAMESPACE_DEF_MANDATORY_ATTRIBUTE_NOT_ALLOWED(400, "ATLAS-400-00-094", "{0}.{1} : namespaces can not have mandatory attribute"),
+ NAMESPACE_DEF_UNIQUE_ATTRIBUTE_NOT_ALLOWED(400, "ATLAS-400-00-095", "{0}.{1} : namespaces can not have unique attribute"),
+ NAMESPACE_DEF_ATTRIBUTE_TYPE_INVALID(400, "ATLAS-400-00-096", "{0}.{1}: invalid attribute type. Namespace attribute cannot be of type entity/classification/struct/namespace"),
+ INVALID_NAMESPACE_NAME_FOR_ENTITY_TYPE(400, "ATLAS-400-00-097", "Invalid Namespace: {0} specified for entity, applicable namespaces: {1}"),
+ NAMESPACE_ATTRIBUTE_DOES_NOT_EXIST(400, "ATLAS-400-00-098", "Namespace attribute does not exist in entity: {0}"),
+ NAMESPACE_ATTRIBUTE_ALREADY_EXISTS(400, "ATLAS-400-00-099", "Namespace attribute already exists in entity: {0}"),
UNAUTHORIZED_ACCESS(403, "ATLAS-403-00-001", "{0} is not authorized to perform {1}"),
diff --git a/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java b/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java
index 1b033b9..2e2e4ee 100644
--- a/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java
+++ b/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java
@@ -89,11 +89,12 @@ public class AtlasEntity extends AtlasStruct implements Serializable {
private Date updateTime = null;
private Long version = 0L;
- private Map<String, Object> relationshipAttributes;
- private List<AtlasClassification> classifications;
- private List<AtlasTermAssignmentHeader> meanings;
- private Map<String, String> customAttributes;
- private Set<String> labels;
+ private Map<String, Object> relationshipAttributes;
+ private List<AtlasClassification> classifications;
+ private List<AtlasTermAssignmentHeader> meanings;
+ private Map<String, String> customAttributes;
+ private Map<String, Map<String, Object>> namespaceAttributes;
+ private Set<String> labels;
@JsonIgnore
private static AtomicLong s_nextId = new AtomicLong(System.nanoTime());
@@ -217,6 +218,7 @@ public class AtlasEntity extends AtlasStruct implements Serializable {
setRelationshipAttributes(other.getRelationshipAttributes());
setMeanings(other.getMeanings());
setCustomAttributes(other.getCustomAttributes());
+ setNamespaceAttributes(other.getNamespaceAttributes());
setLabels(other.getLabels());
}
}
@@ -348,6 +350,41 @@ public class AtlasEntity extends AtlasStruct implements Serializable {
this.customAttributes = customAttributes;
}
+ public Map<String, Map<String, Object>> getNamespaceAttributes() {
+ return namespaceAttributes;
+ }
+
+ public void setNamespaceAttributes(Map<String, Map<String, Object>> namespaceAttributes) {
+ this.namespaceAttributes = namespaceAttributes;
+ }
+
+ public void setNamespaceAttribute(String nsName, String nsAttrName, Object nsValue) {
+ Map<String, Map<String, Object>> namespaceAttributes = this.namespaceAttributes;
+
+ if (namespaceAttributes == null) {
+ namespaceAttributes = new HashMap<>();
+
+ this.namespaceAttributes = namespaceAttributes;
+ }
+
+ Map<String, Object> namespaceAttributeMap = namespaceAttributes.get(nsName);
+
+ if (namespaceAttributeMap == null) {
+ namespaceAttributeMap = new HashMap<>();
+
+ namespaceAttributes.put(nsName, namespaceAttributeMap);
+ }
+
+ namespaceAttributeMap.put(nsAttrName, nsValue);
+ }
+
+ public Object getNamespaceAttribute(String nsName, String nsAttrName) {
+ Map<String, Map<String, Object>> namespaceAttributes = this.namespaceAttributes;
+ Map<String, Object> namespaceAttributeMap = namespaceAttributes == null ? null : namespaceAttributes.get(nsName);
+
+ return namespaceAttributeMap == null ? null : namespaceAttributeMap.get(nsAttrName);
+ }
+
public Set<String> getLabels() {
return labels;
}
@@ -404,6 +441,7 @@ public class AtlasEntity extends AtlasStruct implements Serializable {
setClassifications(null);
setMeanings(null);
setCustomAttributes(null);
+ setNamespaceAttributes(null);
setLabels(null);
}
@@ -442,6 +480,9 @@ public class AtlasEntity extends AtlasStruct implements Serializable {
sb.append(", customAttributes=[");
dumpObjects(customAttributes, sb);
sb.append("]");
+ sb.append(", namespaceAttributes=[");
+ dumpObjects(namespaceAttributes, sb);
+ sb.append("]");
sb.append(", labels=[");
dumpObjects(labels, sb);
sb.append("]");
@@ -470,14 +511,15 @@ public class AtlasEntity extends AtlasStruct implements Serializable {
Objects.equals(version, that.version) &&
Objects.equals(relationshipAttributes, that.relationshipAttributes) &&
Objects.equals(customAttributes, that.customAttributes) &&
+ Objects.equals(namespaceAttributes, that.namespaceAttributes) &&
Objects.equals(labels, that.labels) &&
Objects.equals(classifications, that.classifications);
}
@Override
public int hashCode() {
- return Objects.hash(super.hashCode(), guid, homeId, isProxy, isIncomplete, provenanceType, status, createdBy,
- updatedBy, createTime, updateTime, version, relationshipAttributes, classifications, customAttributes, labels);
+ return Objects.hash(super.hashCode(), guid, homeId, isProxy, isIncomplete, provenanceType, status, createdBy, updatedBy,
+ createTime, updateTime, version, relationshipAttributes, classifications, customAttributes, namespaceAttributes, labels);
}
@Override
diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasNamespaceType.java b/intg/src/main/java/org/apache/atlas/type/AtlasNamespaceType.java
index a141d4a..cfbf2b1 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasNamespaceType.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasNamespaceType.java
@@ -146,21 +146,22 @@ public class AtlasNamespaceType extends AtlasStructType {
public static class AtlasNamespaceAttribute extends AtlasAttribute {
private final Set<AtlasEntityType> applicableEntityTypes;
- private final int maxStringLength;
- private final String validPattern;
+ private final int maxStringLength;
+ private final String validPattern;
public AtlasNamespaceAttribute(AtlasAttribute attribute, Set<AtlasEntityType> applicableEntityTypes) {
super(attribute);
- this.maxStringLength = 0;
- this.validPattern = null;
+
+ this.maxStringLength = 0;
+ this.validPattern = null;
this.applicableEntityTypes = applicableEntityTypes;
}
- public AtlasNamespaceAttribute(AtlasAttribute attribute, Set<AtlasEntityType> applicableEntityTypes,
- int maxStringLength, String validPattern) {
+ public AtlasNamespaceAttribute(AtlasAttribute attribute, Set<AtlasEntityType> applicableEntityTypes, int maxStringLength, String validPattern) {
super(attribute);
- this.maxStringLength = maxStringLength;
- this.validPattern = validPattern;
+
+ this.maxStringLength = maxStringLength;
+ this.validPattern = validPattern;
this.applicableEntityTypes = applicableEntityTypes;
}
diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasTypeRegistry.java b/intg/src/main/java/org/apache/atlas/type/AtlasTypeRegistry.java
index 97e27d0..5b7cbee 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasTypeRegistry.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasTypeRegistry.java
@@ -201,6 +201,7 @@ public class AtlasTypeRegistry {
return registryData.namespaceDefs.getAll();
}
+ public AtlasNamespaceType getNamespaceTypeByName(String name) { return registryData.namespaceDefs.getTypeByName(name); }
public Collection<AtlasRelationshipDef> getAllRelationshipDefs() { return registryData.relationshipDefs.getAll(); }
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java
index 928c70d..39ea3f8 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java
@@ -248,6 +248,23 @@ public interface AtlasEntityStore {
void setLabels(String guid, Set<String> labels) throws AtlasBaseException;
/**
+ *
+ * @param guid
+ * @param namespaceAttributes
+ * @param isOverwrite
+ * @throws AtlasBaseException
+ */
+ void addOrUpdateNamespaceAttributes(String guid, Map<String, Map<String, Object>> namespaceAttributes, boolean isOverwrite) throws AtlasBaseException;
+
+ /**
+ *
+ * @param guid
+ * @param namespaceAttributes
+ * @throws AtlasBaseException
+ */
+ void removeNamespaceAttributes(String guid, Map<String, Map<String, Object>> namespaceAttributes) throws AtlasBaseException;
+
+ /**
* Remove given labels, if labels is null/empty, no labels will be removed. If any labels in
* labels set are non-existing labels, they will be ignored, only existing labels will be removed.
*/
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java
index 25284e9..f511e2f 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2.java
@@ -47,6 +47,7 @@ import org.apache.atlas.repository.store.graph.v1.DeleteHandlerDelegate;
import org.apache.atlas.store.DeleteType;
import org.apache.atlas.type.AtlasClassificationType;
import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasNamespaceType.AtlasNamespaceAttribute;
import org.apache.atlas.type.AtlasStructType.AtlasAttribute;
import org.apache.atlas.type.AtlasType;
import org.apache.atlas.type.AtlasTypeRegistry;
@@ -74,6 +75,7 @@ import static java.lang.Boolean.FALSE;
import static org.apache.atlas.model.instance.EntityMutations.EntityOperation.*;
import static org.apache.atlas.repository.Constants.IS_INCOMPLETE_PROPERTY_KEY;
import static org.apache.atlas.repository.graph.GraphHelper.getCustomAttributes;
+import static org.apache.atlas.repository.graph.GraphHelper.getTypeName;
import static org.apache.atlas.repository.graph.GraphHelper.isEntityIncomplete;
import static org.apache.atlas.repository.store.graph.v2.EntityGraphMapper.validateLabels;
@@ -318,13 +320,13 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore {
@Override
@GraphTransaction
public EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean isPartialUpdate) throws AtlasBaseException {
- return createOrUpdate(entityStream, isPartialUpdate, false);
+ return createOrUpdate(entityStream, isPartialUpdate, false, false);
}
@Override
@GraphTransaction(logRollback = false)
public EntityMutationResponse createOrUpdateForImport(EntityStream entityStream) throws AtlasBaseException {
- return createOrUpdate(entityStream, false, true);
+ return createOrUpdate(entityStream, false, true, true);
}
@Override
@@ -356,7 +358,7 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore {
entity.setGuid(guid);
- return createOrUpdate(new AtlasEntityStream(updatedEntityInfo), isPartialUpdate, false);
+ return createOrUpdate(new AtlasEntityStream(updatedEntityInfo), isPartialUpdate, false, false);
}
@Override
@@ -378,7 +380,7 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore {
AtlasAuthorizationUtils.verifyAccess(new AtlasEntityAccessRequest(typeRegistry, AtlasPrivilege.ENTITY_UPDATE, new AtlasEntityHeader(entity)), "update entity ByUniqueAttributes");
- return createOrUpdate(new AtlasEntityStream(updatedEntityInfo), true, false);
+ return createOrUpdate(new AtlasEntityStream(updatedEntityInfo), true, false, false);
}
@Override
@@ -429,7 +431,7 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore {
throw new AtlasBaseException(AtlasErrorCode.ATTRIBUTE_UPDATE_NOT_SUPPORTED, attrName, attrType.getTypeName());
}
- return createOrUpdate(new AtlasEntityStream(updateEntity), true, false);
+ return createOrUpdate(new AtlasEntityStream(updateEntity), true, false, false);
}
@Override
@@ -823,6 +825,66 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore {
@Override
@GraphTransaction
+ public void addOrUpdateNamespaceAttributes(String guid, Map<String, Map<String, Object>> entityNamespaces, boolean isOverwrite) throws AtlasBaseException {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> addOrUpdateNamespaceAttributes(guid={}, entityNamespaces={}, isOverwrite={})", guid, entityNamespaces, isOverwrite);
+ }
+
+ if (StringUtils.isEmpty(guid)) {
+ throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "guid is null/empty");
+ }
+
+ AtlasVertex entityVertex = AtlasGraphUtilsV2.findByGuid(guid);
+
+ if (entityVertex == null) {
+ throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid);
+ }
+
+ String typeName = getTypeName(entityVertex);
+ AtlasEntityType entityType = typeRegistry.getEntityTypeByName(typeName);
+
+ validateNamespaceAttributes(entityVertex, entityType, entityNamespaces, isOverwrite);
+
+ if (isOverwrite) {
+ entityGraphMapper.setNamespaceAttributes(entityVertex, entityType, entityNamespaces);
+ } else {
+ entityGraphMapper.addOrUpdateNamespaceAttributes(entityVertex, entityType, entityNamespaces);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== addOrUpdateNamespaceAttributes(guid={}, entityNamespaces={}, isOverwrite={})", guid, entityNamespaces, isOverwrite);
+ }
+ }
+
+ @Override
+ @GraphTransaction
+ public void removeNamespaceAttributes(String guid, Map<String, Map<String, Object>> entityNamespaces) throws AtlasBaseException {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> removeNamespaceAttributes(guid={}, entityNamespaces={})", guid, entityNamespaces);
+ }
+
+ if (StringUtils.isEmpty(guid)) {
+ throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "guid is null/empty");
+ }
+
+ AtlasVertex entityVertex = AtlasGraphUtilsV2.findByGuid(guid);
+
+ if (entityVertex == null) {
+ throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid);
+ }
+
+ String typeName = getTypeName(entityVertex);
+ AtlasEntityType entityType = typeRegistry.getEntityTypeByName(typeName);
+
+ entityGraphMapper.removeNamespaceAttributes(entityVertex, entityType, entityNamespaces);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== removeNamespaceAttributes(guid={}, entityNamespaces={})", guid, entityNamespaces);
+ }
+ }
+
+ @Override
+ @GraphTransaction
public void setLabels(String guid, Set<String> labels) throws AtlasBaseException {
if (LOG.isDebugEnabled()) {
LOG.debug("==> setLabels()");
@@ -899,7 +961,7 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore {
}
}
- private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean isPartialUpdate, boolean replaceClassifications) throws AtlasBaseException {
+ private EntityMutationResponse createOrUpdate(EntityStream entityStream, boolean isPartialUpdate, boolean replaceClassifications, boolean replaceNamespaceAttributes) throws AtlasBaseException {
if (LOG.isDebugEnabled()) {
LOG.debug("==> createOrUpdate()");
}
@@ -1040,7 +1102,7 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore {
RequestContext.get().endMetricRecord(checkForUnchangedEntities);
}
- EntityMutationResponse ret = entityGraphMapper.mapAttributesAndClassifications(context, isPartialUpdate, replaceClassifications);
+ EntityMutationResponse ret = entityGraphMapper.mapAttributesAndClassifications(context, isPartialUpdate, replaceClassifications, replaceNamespaceAttributes);
ret.setGuidAssignments(context.getGuidAssignments());
@@ -1311,4 +1373,50 @@ public class AtlasEntityStoreV2 implements AtlasEntityStore {
}
}
}
+
+ private void validateNamespaceAttributes(AtlasVertex entityVertex, AtlasEntityType entityType, Map<String, Map<String, Object>> entityNamespaces, boolean isOverwrite) throws AtlasBaseException {
+ List<String> messages = new ArrayList<>();
+
+ Map<String, List<AtlasNamespaceAttribute>> entityTypeNamespaces = entityType.getNamespaceAttributes();
+
+ for (String nsName : entityNamespaces.keySet()) {
+ if (!entityNamespaces.containsKey(nsName)) {
+ messages.add(nsName + ": invalid namespace for entity type " + entityType.getTypeName());
+
+ continue;
+ }
+
+ List<AtlasNamespaceAttribute> entityTypeNsAttributes = entityTypeNamespaces.get(nsName);
+ Map<String, Object> entityNsAttributes = entityNamespaces.get(nsName);
+
+ for (AtlasNamespaceAttribute nsAttribute : entityTypeNsAttributes) {
+ AtlasType attrType = nsAttribute.getAttributeType();
+ String attrName = nsAttribute.getName();
+ Object attrValue = entityNsAttributes.get(attrName);
+ String fieldName = entityType.getTypeName() + "." + nsName + "." + attrName;
+
+ if (attrValue != null) {
+ attrType.validateValue(attrValue, fieldName, messages);
+ } else if (!nsAttribute.getAttributeDef().getIsOptional()) {
+ final boolean isAttrValuePresent;
+
+ if (isOverwrite) {
+ isAttrValuePresent = false;
+ } else {
+ Object existingValue = AtlasGraphUtilsV2.getEncodedProperty(entityVertex, nsAttribute.getVertexPropertyName(), Object.class);
+
+ isAttrValuePresent = existingValue != null;
+ }
+
+ if (!isAttrValuePresent) {
+ messages.add(fieldName + ": mandatory namespace attribute value missing in type " + entityType.getTypeName());
+ }
+ }
+ }
+ }
+
+ if (!messages.isEmpty()) {
+ throw new AtlasBaseException(AtlasErrorCode.INSTANCE_CRUD_INVALID_PARAMS, messages);
+ }
+ }
}
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphMapper.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphMapper.java
index 3d42d1f..113325d 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphMapper.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphMapper.java
@@ -53,6 +53,7 @@ import org.apache.atlas.type.AtlasBuiltInTypes;
import org.apache.atlas.type.AtlasClassificationType;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasMapType;
+import org.apache.atlas.type.AtlasNamespaceType.AtlasNamespaceAttribute;
import org.apache.atlas.type.AtlasStructType;
import org.apache.atlas.type.AtlasStructType.AtlasAttribute;
import org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection;
@@ -253,7 +254,7 @@ public class EntityGraphMapper {
}
}
- public EntityMutationResponse mapAttributesAndClassifications(EntityMutationContext context, final boolean isPartialUpdate, final boolean replaceClassifications) throws AtlasBaseException {
+ public EntityMutationResponse mapAttributesAndClassifications(EntityMutationContext context, final boolean isPartialUpdate, final boolean replaceClassifications, boolean replaceNamespaceAttributes) throws AtlasBaseException {
MetricRecorder metric = RequestContext.get().startMetricRecord("mapAttributesAndClassifications");
EntityMutationResponse resp = new EntityMutationResponse();
@@ -275,6 +276,8 @@ public class EntityGraphMapper {
resp.addEntity(CREATE, constructHeader(createdEntity, entityType, vertex));
addClassifications(context, guid, createdEntity.getClassifications());
+ addOrUpdateNamespaceAttributes(vertex, entityType, createdEntity.getNamespaceAttributes());
+
reqContext.cache(createdEntity);
}
}
@@ -300,6 +303,10 @@ public class EntityGraphMapper {
addClassifications(context, guid, updatedEntity.getClassifications());
}
+ if (replaceNamespaceAttributes) {
+ setNamespaceAttributes(vertex, entityType, updatedEntity.getNamespaceAttributes());
+ }
+
reqContext.cache(updatedEntity);
}
}
@@ -412,6 +419,143 @@ public class EntityGraphMapper {
return ret;
}
+ /*
+ * reset/overwrite namespace attributes of the entity with given values
+ */
+ public void setNamespaceAttributes(AtlasVertex entityVertex, AtlasEntityType entityType, Map<String, Map<String, Object>> entityNamespaces) throws AtlasBaseException {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> setNamespaceAttributes(entityVertex={}, entityType={}, entityNamespaces={}", entityVertex, entityType.getTypeName(), entityNamespaces);
+ }
+
+ Map<String, List<AtlasNamespaceAttribute>> entityTypeNamespaces = entityType.getNamespaceAttributes();
+
+ for (Map.Entry<String, List<AtlasNamespaceAttribute>> entry : entityTypeNamespaces.entrySet()) {
+ String nsName = entry.getKey();
+ List<AtlasNamespaceAttribute> entityTypeNsAttributes = entry.getValue();
+ Map<String, Object> entityNsAttributes = MapUtils.isEmpty(entityNamespaces) ? null : entityNamespaces.get(nsName);
+
+ for (AtlasNamespaceAttribute nsAttribute : entityTypeNsAttributes) {
+ String nsAttrName = nsAttribute.getName();
+ Object nsAttrExistingValue = entityVertex.getProperty(nsAttribute.getVertexPropertyName(), Object.class);
+ Object nsAttrNewValue = MapUtils.isEmpty(entityNsAttributes) ? null : entityNsAttributes.get(nsAttrName);
+
+ if (nsAttrExistingValue == null) {
+ if (nsAttrNewValue != null) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("setNamespaceAttributes(): adding {}.{}={}", nsName, nsAttribute.getName(), nsAttrNewValue);
+ }
+
+ mapAttribute(nsAttribute, nsAttrNewValue, entityVertex, CREATE, new EntityMutationContext());
+ }
+ } else {
+ if (nsAttrNewValue != null) {
+ if (!Objects.equals(nsAttrExistingValue, nsAttrNewValue)) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("setNamespaceAttributes(): updating {}.{}={}", nsName, nsAttribute.getName(), nsAttrNewValue);
+ }
+
+ mapAttribute(nsAttribute, nsAttrNewValue, entityVertex, UPDATE, new EntityMutationContext());
+ }
+ } else {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("setNamespaceAttributes(): removing {}.{}", nsName, nsAttribute.getName());
+ }
+
+ entityVertex.removeProperty(nsAttribute.getVertexPropertyName());
+ }
+ }
+ }
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== setNamespaceAttributes(entityVertex={}, entityType={}, entityNamespaces={}", entityVertex, entityType.getTypeName(), entityNamespaces);
+ }
+ }
+
+ /*
+ * add or update the given namespace attributes on the entity
+ */
+ public void addOrUpdateNamespaceAttributes(AtlasVertex entityVertex, AtlasEntityType entityType, Map<String, Map<String, Object>> entityNamespaces) throws AtlasBaseException {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> addOrUpdateNamespaceAttributes(entityVertex={}, entityType={}, entityNamespaces={}", entityVertex, entityType.getTypeName(), entityNamespaces);
+ }
+
+ Map<String, List<AtlasNamespaceAttribute>> entityTypeNamespaces = entityType.getNamespaceAttributes();
+
+ if (MapUtils.isNotEmpty(entityTypeNamespaces) && MapUtils.isNotEmpty(entityNamespaces)) {
+ for (Map.Entry<String, List<AtlasNamespaceAttribute>> entry : entityTypeNamespaces.entrySet()) {
+ String nsName = entry.getKey();
+ List<AtlasNamespaceAttribute> entityTypeNsAttributes = entry.getValue();
+ Map<String, Object> entityNsAttributes = entityNamespaces.get(nsName);
+
+ if (MapUtils.isEmpty(entityNsAttributes)) {
+ continue;
+ }
+
+ for (AtlasNamespaceAttribute nsAttribute : entityTypeNsAttributes) {
+ String nsAttrName = nsAttribute.getName();
+
+ if (!entityNsAttributes.containsKey(nsAttrName)) {
+ continue;
+ }
+
+ Object nsAttrValue = entityNsAttributes.get(nsAttrName);
+ Object existingValue = AtlasGraphUtilsV2.getEncodedProperty(entityVertex, nsAttribute.getVertexPropertyName(), Object.class);
+
+ if (existingValue == null) {
+ if (nsAttrValue != null) {
+ mapAttribute(nsAttribute, nsAttrValue, entityVertex, CREATE, new EntityMutationContext());
+ }
+ } else {
+ if (!Objects.equals(existingValue, nsAttrValue)) {
+ mapAttribute(nsAttribute, nsAttrValue, entityVertex, UPDATE, new EntityMutationContext());
+ }
+ }
+ }
+ }
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== addOrUpdateNamespaceAttributes(entityVertex={}, entityType={}, entityNamespaces={}", entityVertex, entityType.getTypeName(), entityNamespaces);
+ }
+ }
+
+ /*
+ * remove the given namespace attributes from the entity
+ */
+ public void removeNamespaceAttributes(AtlasVertex entityVertex, AtlasEntityType entityType, Map<String, Map<String, Object>> entityNamespaces) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> removeNamespaceAttributes(entityVertex={}, entityType={}, entityNamespaces={}", entityVertex, entityType.getTypeName(), entityNamespaces);
+ }
+
+ Map<String, List<AtlasNamespaceAttribute>> entityTypeNamespaces = entityType.getNamespaceAttributes();
+
+ if (MapUtils.isNotEmpty(entityTypeNamespaces) && MapUtils.isNotEmpty(entityNamespaces)) {
+ for (Map.Entry<String, List<AtlasNamespaceAttribute>> entry : entityTypeNamespaces.entrySet()) {
+ String nsName = entry.getKey();
+ List<AtlasNamespaceAttribute> entityTypeNsAttributes = entry.getValue();
+
+ if (!entityNamespaces.containsKey(nsName)) { // nothing to remove for this namespace
+ continue;
+ }
+
+ Map<String, Object> entityNsAttributes = entityNamespaces.get(nsName);
+
+ for (AtlasNamespaceAttribute nsAttribute : entityTypeNsAttributes) {
+ // if (entityNsAttributes is empty) remove all attributes in this namespace
+ // else remove the attribute only if its given in entityNsAttributes
+ if (MapUtils.isEmpty(entityNsAttributes) || entityNsAttributes.containsKey(nsAttribute.getName())) {
+ entityVertex.removeProperty(nsAttribute.getVertexPropertyName());
+ }
+ }
+ }
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== removeNamespaceAttributes(entityVertex={}, entityType={}, entityNamespaces={}", entityVertex, entityType.getTypeName(), entityNamespaces);
+ }
+ }
+
private AtlasVertex createStructVertex(AtlasStruct struct) {
return createStructVertex(struct.getTypeName());
}
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java
index dc4c399..55c1cac 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/EntityGraphRetriever.java
@@ -48,6 +48,7 @@ import org.apache.atlas.type.AtlasArrayType;
import org.apache.atlas.type.AtlasBuiltInTypes.AtlasObjectIdType;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasMapType;
+import org.apache.atlas.type.AtlasNamespaceType.AtlasNamespaceAttribute;
import org.apache.atlas.type.AtlasRelationshipType;
import org.apache.atlas.type.AtlasStructType;
import org.apache.atlas.type.AtlasStructType.AtlasAttribute;
@@ -586,6 +587,8 @@ public class EntityGraphRetriever {
mapSystemAttributes(entityVertex, entity);
+ mapNamespaceAttributes(entityVertex, entity);
+
mapAttributes(entityVertex, entity, entityExtInfo, isMinExtInfo, includeReferences);
if (!ignoreRelationshipAttr) { // only map when really needed
@@ -761,6 +764,26 @@ public class EntityGraphRetriever {
}
}
+ private void mapNamespaceAttributes(AtlasVertex entityVertex, AtlasEntity entity) throws AtlasBaseException {
+ AtlasEntityType entityType = typeRegistry.getEntityTypeByName(entity.getTypeName());
+ Map<String, List<AtlasNamespaceAttribute>> entityTypeNamespaces = entityType != null ? entityType.getNamespaceAttributes() : null;
+
+ if (MapUtils.isNotEmpty(entityTypeNamespaces)) {
+ for (Map.Entry<String, List<AtlasNamespaceAttribute>> entry : entityTypeNamespaces.entrySet()) {
+ String nsName = entry.getKey();
+ List<AtlasNamespaceAttribute> nsAttributes = entry.getValue();
+
+ for (AtlasNamespaceAttribute nsAttribute : nsAttributes) {
+ Object nsAttrValue = mapVertexToAttribute(entityVertex, nsAttribute, null, false, false);
+
+ if (nsAttrValue != null) {
+ entity.setNamespaceAttribute(nsName, nsAttribute.getName(), nsAttrValue);
+ }
+ }
+ }
+ }
+ }
+
public List<AtlasClassification> getAllClassifications(AtlasVertex entityVertex) throws AtlasBaseException {
List<AtlasClassification> ret = new ArrayList<>();
Iterable edges = entityVertex.query().direction(AtlasEdgeDirection.OUT).label(CLASSIFICATION_LABEL).edges();
diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java
index 6845121..fcf7189 100644
--- a/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java
+++ b/webapp/src/main/java/org/apache/atlas/web/rest/EntityREST.java
@@ -64,6 +64,7 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -855,6 +856,78 @@ public class EntityREST {
}
}
+ @POST
+ @Path("/guid/{guid}/namespaces")
+ @Produces(Servlets.JSON_MEDIA_TYPE)
+ @Consumes(Servlets.JSON_MEDIA_TYPE)
+ public void addOrUpdateNamespaceAttributes(@PathParam("guid") final String guid, @QueryParam("isOverwrite") @DefaultValue("false") boolean isOverwrite, Map<String, Map<String, Object>> entityNamespaces) throws AtlasBaseException {
+ AtlasPerfTracer perf = null;
+
+ try {
+ if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+ perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityREST.addOrUpdateNamespaceAttributes(" + guid + ", isOverwrite=" + isOverwrite + ")");
+ }
+
+ entitiesStore.addOrUpdateNamespaceAttributes(guid, entityNamespaces, isOverwrite);
+ } finally {
+ AtlasPerfTracer.log(perf);
+ }
+ }
+
+ @DELETE
+ @Path("/guid/{guid}/namespaces")
+ @Produces(Servlets.JSON_MEDIA_TYPE)
+ @Consumes(Servlets.JSON_MEDIA_TYPE)
+ public void removeNamespaceAttributes(@PathParam("guid") final String guid, Map<String, Map<String, Object>> entityNamespaces) throws AtlasBaseException {
+ AtlasPerfTracer perf = null;
+
+ try {
+ if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+ perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityREST.removeNamespaceAttributes(" + guid + ")");
+ }
+
+ entitiesStore.removeNamespaceAttributes(guid, entityNamespaces);
+ } finally {
+ AtlasPerfTracer.log(perf);
+ }
+ }
+
+ @POST
+ @Path("/guid/{guid}/namespace/{namespace}")
+ @Produces(Servlets.JSON_MEDIA_TYPE)
+ @Consumes(Servlets.JSON_MEDIA_TYPE)
+ public void addOrUpdateNamespaceAttributes(@PathParam("guid") final String guid, @PathParam("namespace") final String namespace, Map<String, Object> entityNsAttributes) throws AtlasBaseException {
+ AtlasPerfTracer perf = null;
+
+ try {
+ if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+ perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityREST.addOrUpdateNamespaceAttributes(" + guid + ", " + namespace + ")");
+ }
+
+ entitiesStore.addOrUpdateNamespaceAttributes(guid, Collections.singletonMap(namespace, entityNsAttributes), false);
+ } finally {
+ AtlasPerfTracer.log(perf);
+ }
+ }
+
+ @DELETE
+ @Path("/guid/{guid}/namespace/{namespace}")
+ @Produces(Servlets.JSON_MEDIA_TYPE)
+ @Consumes(Servlets.JSON_MEDIA_TYPE)
+ public void removeNamespaceAttributes(@PathParam("guid") final String guid, @PathParam("namespace") final String namespace, Map<String, Object> entityNsAttributes) throws AtlasBaseException {
+ AtlasPerfTracer perf = null;
+
+ try {
+ if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) {
+ perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "EntityREST.removeNamespaceAttributes(" + guid + ", " + namespace + ")");
+ }
+
+ entitiesStore.removeNamespaceAttributes(guid, Collections.singletonMap(namespace, entityNsAttributes));
+ } finally {
+ AtlasPerfTracer.log(perf);
+ }
+ }
+
/**
* Set labels to a given entity
* @param guid - Unique entity identifier