You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by sa...@apache.org on 2019/07/16 03:36:10 UTC
[atlas] branch master updated: ATLAS-3286: Populate the dynamic
attribute flag for each AtlasAttribute in each AltasEntityType
This is an automated email from the ASF dual-hosted git repository.
sarath 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 85f9b50 ATLAS-3286: Populate the dynamic attribute flag for each AtlasAttribute in each AltasEntityType
85f9b50 is described below
commit 85f9b502e883d3d4870dd201c98aee257a3efa1a
Author: Merryle Wang <me...@cloudera.com>
AuthorDate: Mon Jul 15 20:34:24 2019 -0700
ATLAS-3286: Populate the dynamic attribute flag for each AtlasAttribute in each AltasEntityType
Signed-off-by: Sarath Subramanian <sa...@apache.org>
---
.../org/apache/atlas/type/AtlasEntityType.java | 150 ++++++++++++++++++++-
.../org/apache/atlas/type/AtlasStructType.java | 18 ++-
.../java/org/apache/atlas/type/AttributeToken.java | 43 ++++++
.../java/org/apache/atlas/type/ConstantToken.java | 38 ++++++
.../java/org/apache/atlas/type/DependentToken.java | 52 +++++++
.../java/org/apache/atlas/type/TemplateToken.java | 27 ++++
.../org/apache/atlas/type/TestAtlasEntityType.java | 57 ++++++++
.../graph/v2/AtlasEntityGraphDiscoveryV2.java | 36 +++++
.../notification/NotificationHookConsumerIT.java | 79 ++++++-----
.../web/integration/EntityJerseyResourceIT.java | 14 +-
10 files changed, 466 insertions(+), 48 deletions(-)
diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java b/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
index d9ae9e3..23eaa0a 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
@@ -30,6 +30,7 @@ import org.apache.atlas.utils.AtlasEntityUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
+import org.apache.curator.shaded.com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,16 +43,21 @@ import java.util.Map;
import java.util.Set;
+
/**
* class that implements behaviour of an entity-type.
*/
public class AtlasEntityType extends AtlasStructType {
private static final Logger LOG = LoggerFactory.getLogger(AtlasEntityType.class);
- private static final String NAME = "name";
- private static final String DESCRIPTION = "description";
- private static final String OWNER = "owner";
- private static final String CREATE_TIME = "createTime";
+ private static final String NAME = "name";
+ private static final String DESCRIPTION = "description";
+ private static final String OWNER = "owner";
+ private static final String CREATE_TIME = "createTime";
+ private static final String DYN_ATTRIBUTE_PREFIX = "dynAttribute:";
+ private static final char DYN_ATTRIBUTE_NAME_SEPARATOR = '.';
+ private static final char DYN_ATTRIBUTE_OPEN_DELIM = '{';
+ private static final char DYN_ATTRIBUTE_CLOSE_DELIM = '}';
private static final String[] ENTITY_HEADER_ATTRIBUTES = new String[]{NAME, DESCRIPTION, OWNER, CREATE_TIME};
private static final String OPTION_SCHEMA_ATTRIBUTES = "schemaAttributes";
@@ -73,6 +79,9 @@ public class AtlasEntityType extends AtlasStructType {
private boolean isInternalType = false;
private Map<String, AtlasAttribute> headerAttributes = Collections.emptyMap();
private Map<String, AtlasAttribute> minInfoAttributes = Collections.emptyMap();
+ private List<AtlasAttribute> dynAttributes = Collections.emptyList();
+ private List<AtlasAttribute> dynEvalTriggerAttributes = Collections.emptyList();
+ private Map<String,List<TemplateToken>> parsedTemplates = Collections.emptyMap();
public AtlasEntityType(AtlasEntityDef entityDef) {
@@ -256,6 +265,10 @@ public class AtlasEntityType extends AtlasStructType {
}
entityDef.setRelationshipAttributeDefs(Collections.unmodifiableList(relationshipAttrDefs));
+
+ this.parsedTemplates = parseDynAttributeTemplates();
+
+ populateDynFlagsInfo();
}
public Set<String> getSuperTypes() {
@@ -318,6 +331,18 @@ public class AtlasEntityType extends AtlasStructType {
return ownedRefAttributes;
}
+ public List<AtlasAttribute> getDynEvalAttributes() { return dynAttributes; }
+
+ @VisibleForTesting
+ public void setDynEvalAttributes(List<AtlasAttribute> dynAttributes) { this.dynAttributes = dynAttributes; }
+
+ public List<AtlasAttribute> getDynEvalTriggerAttributes() { return dynEvalTriggerAttributes; }
+
+ @VisibleForTesting
+ public void setDynEvalTriggerAttributes(List<AtlasAttribute> dynEvalTriggerAttributes) { this.dynEvalTriggerAttributes = dynEvalTriggerAttributes; }
+
+ public Map<String,List<TemplateToken>> getParsedTemplates() { return parsedTemplates; }
+
public AtlasAttribute getRelationshipAttribute(String attributeName, String relationshipType) {
final AtlasAttribute ret;
Map<String, AtlasAttribute> attributes = relationshipAttributes.get(attributeName);
@@ -651,6 +676,123 @@ public class AtlasEntityType extends AtlasStructType {
}
}
+ private void populateDynFlagsInfo() {
+ dynAttributes = new ArrayList<>();
+ dynEvalTriggerAttributes = new ArrayList<>();
+
+ for (String attributeName : parsedTemplates.keySet()) {
+ AtlasAttribute attribute = getAttribute(attributeName);
+ if (attribute != null) {
+ dynAttributes.add(attribute);
+ }
+ }
+
+ for (List<TemplateToken> parsedTemplate : parsedTemplates.values()) {
+ for (TemplateToken token : parsedTemplate) {
+ // If token is an instance of AttributeToken means that the attribute is of this entity type
+ // so it must be added to the dynEvalTriggerAttributes list
+ if (token instanceof AttributeToken) {
+ AtlasAttribute attribute = getAttribute(token.getValue());
+
+ if (attribute != null) {
+ dynEvalTriggerAttributes.add(attribute);
+ }
+ }
+ }
+ }
+
+ dynAttributes = Collections.unmodifiableList(dynAttributes);
+ dynEvalTriggerAttributes = Collections.unmodifiableList(dynEvalTriggerAttributes);
+
+ for (AtlasAttribute attribute : dynAttributes) {
+ attribute.setIsDynAttribute(true);
+ }
+
+ for (AtlasAttribute attribute : dynEvalTriggerAttributes) {
+ attribute.setIsDynAttributeEvalTrigger(true);
+ }
+ }
+
+ private Map<String, List<TemplateToken>> parseDynAttributeTemplates(){
+ Map<String, List<TemplateToken>> ret = new HashMap<>();
+ Map<String, String> options = entityDef.getOptions();
+ if (options == null || options.size() == 0) {
+ return ret;
+ }
+
+ for (String key : options.keySet()) {
+ if (key.startsWith(DYN_ATTRIBUTE_PREFIX)) {
+ String attributeName = key.substring(DYN_ATTRIBUTE_PREFIX.length());
+ AtlasAttribute attribute = getAttribute(attributeName);
+
+ if (attribute == null) {
+ LOG.warn("Ignoring {} attribute of {} type as dynamic attribute because attribute does not exist", attributeName, this.getTypeName());
+ continue;
+ }
+
+ if (!(attribute.getAttributeType() instanceof AtlasBuiltInTypes.AtlasStringType)) {
+ LOG.warn("Ignoring {} attribute of {} type as dynamic attribute because attribute isn't a string type", attributeName, this.getTypeName());
+ continue;
+ }
+
+ String template = options.get(key);
+ List<TemplateToken> splitTemplate = templateSplit(template);
+
+ ret.put(attributeName,splitTemplate);
+ }
+ }
+
+ return Collections.unmodifiableMap(ret);
+ }
+
+ // own split function that also designates the right subclass for each token
+ private List<TemplateToken> templateSplit(String template) {
+ List<TemplateToken> ret = new ArrayList<>();
+ StringBuilder token = new StringBuilder();
+ boolean isInAttrName = false;
+
+ for (int i = 0; i < template.length(); i++) {
+ char c = template.charAt(i);
+
+ switch (c) {
+ case DYN_ATTRIBUTE_OPEN_DELIM:
+ isInAttrName = true;
+
+ if (token.length() > 0) {
+ ret.add(new ConstantToken(token.toString()));
+ token.setLength(0);
+ }
+ break;
+
+ case DYN_ATTRIBUTE_CLOSE_DELIM:
+ if (isInAttrName) {
+ isInAttrName = false;
+
+ if (token.length() > 0) {
+ String attrName = token.toString();
+
+ if (attrName.indexOf(DYN_ATTRIBUTE_NAME_SEPARATOR) != -1) {
+ ret.add(new DependentToken(token.toString()));
+ } else {
+ ret.add(new AttributeToken(token.toString()));
+ }
+
+ token.setLength(0);
+ }
+ } else {
+ token.append(c);
+ }
+ break;
+
+ default:
+ token.append(c);
+ break;
+ }
+ }
+
+ return ret;
+ }
+
boolean isAssignableFrom(AtlasObjectId objId) {
boolean ret = AtlasTypeUtil.isValid(objId) && (StringUtils.equals(objId.getTypeName(), getTypeName()) || isSuperTypeOf(objId.getTypeName()));
diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java b/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java
index 0fe47bd..e7ec3d8 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java
@@ -710,6 +710,9 @@ public class AtlasStructType extends AtlasType {
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;
@@ -746,23 +749,23 @@ public class AtlasStructType extends AtlasType {
switch (this.attributeType.getTypeCategory()) {
case OBJECT_ID_TYPE:
isObjectRef = true;
- break;
+ break;
case MAP:
AtlasMapType mapType = (AtlasMapType) this.attributeType;
isObjectRef = mapType.getValueType().getTypeCategory() == OBJECT_ID_TYPE;
- break;
+ break;
case ARRAY:
AtlasArrayType arrayType = (AtlasArrayType) this.attributeType;
isObjectRef = arrayType.getElementType().getTypeCategory() == OBJECT_ID_TYPE;
- break;
+ break;
default:
isObjectRef = false;
- break;
+ break;
}
}
@@ -826,6 +829,13 @@ public class AtlasStructType extends AtlasType {
public int getSearchWeight() { return attributeDef.getSearchWeight(); }
+ 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 static String getEdgeLabel(String property) {
return "__" + property;
diff --git a/intg/src/main/java/org/apache/atlas/type/AttributeToken.java b/intg/src/main/java/org/apache/atlas/type/AttributeToken.java
new file mode 100644
index 0000000..658cf86
--- /dev/null
+++ b/intg/src/main/java/org/apache/atlas/type/AttributeToken.java
@@ -0,0 +1,43 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntity;
+
+public class AttributeToken implements TemplateToken {
+ private final String attrName;
+
+ public AttributeToken(String attrName){
+ this.attrName = attrName;
+ }
+
+ @Override
+ public String eval(AtlasEntity entity) throws AtlasBaseException {
+ Object ret = entity.getAttribute(attrName);
+ if (ret == null) {
+ return null;
+ }
+ return ret.toString();
+ }
+
+ @Override
+ public String getValue() {
+ return attrName;
+ }
+}
diff --git a/intg/src/main/java/org/apache/atlas/type/ConstantToken.java b/intg/src/main/java/org/apache/atlas/type/ConstantToken.java
new file mode 100644
index 0000000..5ba54ae
--- /dev/null
+++ b/intg/src/main/java/org/apache/atlas/type/ConstantToken.java
@@ -0,0 +1,38 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.model.instance.AtlasEntity;
+
+public class ConstantToken implements TemplateToken {
+ private final String constant;
+
+ public ConstantToken(String constant){
+ this.constant = constant;
+ }
+
+ @Override
+ public String eval(AtlasEntity entity) {
+ return constant;
+ }
+
+ @Override
+ public String getValue() {
+ return constant;
+ }
+}
diff --git a/intg/src/main/java/org/apache/atlas/type/DependentToken.java b/intg/src/main/java/org/apache/atlas/type/DependentToken.java
new file mode 100644
index 0000000..c1c7d3d
--- /dev/null
+++ b/intg/src/main/java/org/apache/atlas/type/DependentToken.java
@@ -0,0 +1,52 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntity;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class DependentToken implements TemplateToken {
+ private final String path;
+ private final List<String> objectPath;
+ private final String attrName;
+
+ private static final String DYN_ATTRIBUTE_NAME_SEPARATOR = "\\.";
+
+ public DependentToken(String path){
+ List<String> objectPath = new ArrayList<>(Arrays.asList(path.split(DYN_ATTRIBUTE_NAME_SEPARATOR)));
+
+ this.path = path;
+ this.attrName = objectPath.remove(objectPath.size() - 1);
+ this.objectPath = Collections.unmodifiableList(objectPath);
+ }
+
+ @Override
+ public String eval(AtlasEntity entity) throws AtlasBaseException {
+ return "TEMP";
+ }
+
+ @Override
+ public String getValue() {
+ return path;
+ }
+}
diff --git a/intg/src/main/java/org/apache/atlas/type/TemplateToken.java b/intg/src/main/java/org/apache/atlas/type/TemplateToken.java
new file mode 100644
index 0000000..fffbc2a
--- /dev/null
+++ b/intg/src/main/java/org/apache/atlas/type/TemplateToken.java
@@ -0,0 +1,27 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntity;
+
+public interface TemplateToken {
+ String eval(AtlasEntity entity) throws AtlasBaseException;
+
+ String getValue();
+}
diff --git a/intg/src/test/java/org/apache/atlas/type/TestAtlasEntityType.java b/intg/src/test/java/org/apache/atlas/type/TestAtlasEntityType.java
index 3c53c02..c114bdf 100644
--- a/intg/src/test/java/org/apache/atlas/type/TestAtlasEntityType.java
+++ b/intg/src/test/java/org/apache/atlas/type/TestAtlasEntityType.java
@@ -42,6 +42,7 @@ public class TestAtlasEntityType {
private static final String TYPE_COLUMN = "my_column";
private static final String ATTR_TABLE = "table";
private static final String ATTR_COLUMNS = "columns";
+ private static final String ATTR_OWNER = "owner";
private static final String ATTR_NAME = "name";
private final AtlasEntityType entityType;
@@ -164,6 +165,39 @@ public class TestAtlasEntityType {
}
@Test
+ public void testDynAttributeFlags() {
+ AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry();
+ AtlasTransientTypeRegistry ttr = null;
+ boolean commit = false;
+ List<AtlasEntityDef> entityDefs = new ArrayList<>();
+ String failureMsg = null;
+
+ entityDefs.add(createTableEntityDefWithOptions());
+ entityDefs.add(createColumnEntityDef());
+
+ try {
+ ttr = typeRegistry.lockTypeRegistryForUpdate();
+
+ ttr.addTypes(entityDefs);
+ //options are read in the table,
+ AtlasEntityType typeTable = ttr.getEntityTypeByName(TYPE_TABLE);
+ AtlasEntityType typeColumn = ttr.getEntityTypeByName(TYPE_COLUMN);
+
+ assertTrue(typeTable.getAttribute(ATTR_NAME).getIsDynAttributeEvalTrigger());
+ assertFalse(typeTable.getAttribute(ATTR_NAME).getIsDynAttribute());
+ assertFalse(typeTable.getAttribute(ATTR_OWNER).getIsDynAttributeEvalTrigger());
+ assertTrue(typeTable.getAttribute(ATTR_OWNER).getIsDynAttribute());
+
+ commit = true;
+ } catch (AtlasBaseException excp) {
+ failureMsg = excp.getMessage();
+ } finally {
+ typeRegistry.releaseTypeRegistryForUpdate(ttr, commit);
+ }
+ assertNull(failureMsg, "failed to create types " + TYPE_TABLE + " and " + TYPE_COLUMN);
+ }
+
+ @Test
public void testConstraintInvalidOwnedRef_InvalidAttributeType() {
AtlasTypeRegistry typeRegistry = new AtlasTypeRegistry();
AtlasTransientTypeRegistry ttr = null;
@@ -314,6 +348,29 @@ public class TestAtlasEntityType {
return table;
}
+ private AtlasEntityDef createTableEntityDefWithOptions() {
+ AtlasEntityDef table = new AtlasEntityDef(TYPE_TABLE);
+ AtlasAttributeDef attrName = new AtlasAttributeDef(ATTR_NAME, AtlasBaseTypeDef.ATLAS_TYPE_STRING);
+ AtlasAttributeDef attrColumns = new AtlasAttributeDef(ATTR_COLUMNS, AtlasBaseTypeDef.getArrayTypeName(TYPE_COLUMN));
+ AtlasAttributeDef attrOwner = new AtlasAttributeDef(ATTR_OWNER, AtlasBaseTypeDef.ATLAS_TYPE_STRING);
+
+ attrColumns.addConstraint(new AtlasConstraintDef(AtlasConstraintDef.CONSTRAINT_TYPE_OWNED_REF));
+
+ table.addAttribute(attrName);
+ table.addAttribute(attrColumns);
+ table.addAttribute(attrOwner);
+
+ Map<String,String> options = new HashMap<>();
+ String key = "dynAttribute:" + ATTR_OWNER;
+ String value = "{" + ATTR_NAME + "}";
+
+ options.put(key,value);
+
+ table.setOptions(options);
+
+ return table;
+ }
+
private AtlasEntityDef createTableEntityDefWithOwnedRefOnInvalidType() {
AtlasEntityDef table = new AtlasEntityDef(TYPE_TABLE);
AtlasAttributeDef attrName = new AtlasAttributeDef(ATTR_NAME, AtlasBaseTypeDef.ATLAS_TYPE_STRING);
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityGraphDiscoveryV2.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityGraphDiscoveryV2.java
index 4ff4206..84bb2a3 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityGraphDiscoveryV2.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityGraphDiscoveryV2.java
@@ -36,6 +36,7 @@ import org.apache.atlas.type.AtlasStructType.AtlasAttribute;
import org.apache.atlas.type.AtlasType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.type.AtlasTypeUtil;
+import org.apache.atlas.type.TemplateToken;
import org.apache.atlas.utils.AtlasEntityUtil;
import org.apache.atlas.utils.AtlasPerfMetrics.MetricRecorder;
import org.slf4j.Logger;
@@ -144,6 +145,8 @@ public class AtlasEntityGraphDiscoveryV2 implements EntityGraphDiscovery {
throw new AtlasBaseException(AtlasErrorCode.INVALID_PARAMETERS, "found null entity");
}
+ processDynamicAttributes(entity);
+
walkEntityGraph(entity);
walkedEntities.add(entity.getGuid());
@@ -395,4 +398,37 @@ public class AtlasEntityGraphDiscoveryV2 implements EntityGraphDiscovery {
discoveryContext.addReferencedByUniqAttribs(objId);
}
}
+
+ private void processDynamicAttributes(AtlasEntity entity) throws AtlasBaseException {
+ AtlasEntityType entityType = typeRegistry.getEntityTypeByName(entity.getTypeName());
+
+ for (AtlasAttribute attribute : entityType.getDynEvalAttributes()) {
+ String attributeName = attribute.getName();
+ List<TemplateToken> tokens = entityType.getParsedTemplates().get(attributeName);
+
+ if (tokens == null) {
+ continue;
+ }
+
+ StringBuilder dynAttributeValue = new StringBuilder();
+
+ boolean set = true;
+
+ for (TemplateToken token : tokens) {
+ String evaluated = token.eval(entity);
+ if (evaluated != null) {
+ dynAttributeValue.append(evaluated);
+ } else {
+ set = false;
+ LOG.warn("Attribute {} for {} unable to be generated because of dynamic attribute token {}", attributeName, entityType, token.getValue());
+ break;
+ }
+
+ }
+
+ if (set) {
+ entity.setAttribute(attributeName,dynAttributeValue.toString());
+ }
+ }
+ }
}
diff --git a/webapp/src/test/java/org/apache/atlas/notification/NotificationHookConsumerIT.java b/webapp/src/test/java/org/apache/atlas/notification/NotificationHookConsumerIT.java
index bf7e182..6e24f52 100644
--- a/webapp/src/test/java/org/apache/atlas/notification/NotificationHookConsumerIT.java
+++ b/webapp/src/test/java/org/apache/atlas/notification/NotificationHookConsumerIT.java
@@ -93,13 +93,15 @@ public class NotificationHookConsumerIT extends BaseResourceIT {
@Test
public void testCreateEntity() throws Exception {
- final Referenceable entity = new Referenceable(DATABASE_TYPE_BUILTIN);
- final String dbName = "db" + randomString();
+ final Referenceable entity = new Referenceable(DATABASE_TYPE_BUILTIN);
+ final String dbName = "db" + randomString();
+ final String clusterName = randomString();
+ final String qualifiedName = dbName + "@" + clusterName;
entity.set(NAME, dbName);
entity.set(DESCRIPTION, randomString());
- entity.set(QUALIFIED_NAME, dbName);
- entity.set(CLUSTER_NAME, randomString());
+ entity.set(QUALIFIED_NAME, qualifiedName);
+ entity.set(CLUSTER_NAME, clusterName);
sendHookMessage(new EntityCreateRequest(TEST_USER, entity));
@@ -122,13 +124,15 @@ public class NotificationHookConsumerIT extends BaseResourceIT {
@Test
public void testUpdateEntityPartial() throws Exception {
- final Referenceable entity = new Referenceable(DATABASE_TYPE_BUILTIN);
- final String dbName = "db" + randomString();
+ final Referenceable entity = new Referenceable(DATABASE_TYPE_BUILTIN);
+ final String dbName = "db" + randomString();
+ final String clusterName = randomString();
+ final String qualifiedName = dbName + "@" + clusterName;
entity.set(NAME, dbName);
entity.set(DESCRIPTION, randomString());
- entity.set(QUALIFIED_NAME, dbName);
- entity.set(CLUSTER_NAME, randomString());
+ entity.set(QUALIFIED_NAME, qualifiedName);
+ entity.set(CLUSTER_NAME, clusterName);
atlasClientV1.createEntity(entity);
@@ -136,70 +140,75 @@ public class NotificationHookConsumerIT extends BaseResourceIT {
newEntity.set("owner", randomString());
- sendHookMessage(new EntityPartialUpdateRequest(TEST_USER, DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, dbName, newEntity));
+ sendHookMessage(new EntityPartialUpdateRequest(TEST_USER, DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, (String) entity.get(QUALIFIED_NAME), newEntity));
waitFor(MAX_WAIT_TIME, new Predicate() {
@Override
public boolean evaluate() throws Exception {
- Referenceable localEntity = atlasClientV1.getEntity(DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, dbName);
+ Referenceable localEntity = atlasClientV1.getEntity(DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, qualifiedName);
return (localEntity.get("owner") != null && localEntity.get("owner").equals(newEntity.get("owner")));
}
});
//Its partial update and un-set fields are not updated
- Referenceable actualEntity = atlasClientV1.getEntity(DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, dbName);
+ Referenceable actualEntity = atlasClientV1.getEntity(DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, (String) entity.get(QUALIFIED_NAME));
assertEquals(actualEntity.get(DESCRIPTION), entity.get(DESCRIPTION));
}
@Test
public void testUpdatePartialUpdatingQualifiedName() throws Exception {
- final Referenceable entity = new Referenceable(DATABASE_TYPE_BUILTIN);
- final String dbName = "db" + randomString();
+ final Referenceable entity = new Referenceable(DATABASE_TYPE_BUILTIN);
+ final String dbName = "db" + randomString();
+ final String clusterName = randomString();
+ final String qualifiedName = dbName + "@" + clusterName;
entity.set(NAME, dbName);
entity.set(DESCRIPTION, randomString());
- entity.set(QUALIFIED_NAME, dbName);
- entity.set(CLUSTER_NAME, randomString());
+ entity.set(QUALIFIED_NAME, qualifiedName);
+ entity.set(CLUSTER_NAME, clusterName);
atlasClientV1.createEntity(entity);
- final Referenceable newEntity = new Referenceable(DATABASE_TYPE_BUILTIN);
- final String newName = "db" + randomString();
+ final Referenceable newEntity = new Referenceable(DATABASE_TYPE_BUILTIN);
+ final String newName = "db" + randomString();
+ final String newQualifiedName = newName + "@" + clusterName;
- newEntity.set(QUALIFIED_NAME, newName);
+ newEntity.set(QUALIFIED_NAME, newQualifiedName);
- sendHookMessage(new EntityPartialUpdateRequest(TEST_USER, DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, dbName, newEntity));
+ sendHookMessage(new EntityPartialUpdateRequest(TEST_USER, DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, qualifiedName, newEntity));
waitFor(MAX_WAIT_TIME, new Predicate() {
@Override
public boolean evaluate() throws Exception {
- ArrayNode results = searchByDSL(String.format("%s where qualifiedName='%s'", DATABASE_TYPE_BUILTIN, newName));
+ ArrayNode results = searchByDSL(String.format("%s where qualifiedName='%s'", DATABASE_TYPE_BUILTIN, newQualifiedName));
return results.size() == 1;
}
});
//no entity with the old qualified name
- ArrayNode results = searchByDSL(String.format("%s where qualifiedName='%s'", DATABASE_TYPE_BUILTIN, dbName));
+ ArrayNode results = searchByDSL(String.format("%s where qualifiedName='%s'", DATABASE_TYPE_BUILTIN, qualifiedName));
assertEquals(results.size(), 0);
}
@Test
public void testDeleteByQualifiedName() throws Exception {
- final Referenceable entity = new Referenceable(DATABASE_TYPE_BUILTIN);
- final String dbName = "db" + randomString();
+ final Referenceable entity = new Referenceable(DATABASE_TYPE_BUILTIN);
+ final String dbName = "db" + randomString();
+ final String clusterName = randomString();
+ final String qualifiedName = dbName + "@" + clusterName;
entity.set(NAME, dbName);
entity.set(DESCRIPTION, randomString());
- entity.set(QUALIFIED_NAME, dbName);
- entity.set(CLUSTER_NAME, randomString());
+ entity.set(QUALIFIED_NAME, qualifiedName);
+ entity.set(CLUSTER_NAME, clusterName);
final String dbId = atlasClientV1.createEntity(entity).get(0);
- sendHookMessage(new EntityDeleteRequest(TEST_USER, DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, dbName));
+ sendHookMessage(new EntityDeleteRequest(TEST_USER, DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, qualifiedName));
waitFor(MAX_WAIT_TIME, new Predicate() {
@Override
@@ -213,23 +222,25 @@ public class NotificationHookConsumerIT extends BaseResourceIT {
@Test
public void testUpdateEntityFullUpdate() throws Exception {
- final Referenceable entity = new Referenceable(DATABASE_TYPE_BUILTIN);
- final String dbName = "db" + randomString();
+ final Referenceable entity = new Referenceable(DATABASE_TYPE_BUILTIN);
+ final String dbName = "db" + randomString();
+ final String clusterName = randomString();
+ final String qualifiedName = dbName + "@" + clusterName;
entity.set(NAME, dbName);
entity.set(DESCRIPTION, randomString());
- entity.set(QUALIFIED_NAME, dbName);
- entity.set(CLUSTER_NAME, randomString());
+ entity.set(QUALIFIED_NAME, qualifiedName);
+ entity.set(CLUSTER_NAME, clusterName);
atlasClientV1.createEntity(entity);
final Referenceable newEntity = new Referenceable(DATABASE_TYPE_BUILTIN);
- newEntity.set(NAME, randomString());
+ newEntity.set(NAME, dbName);
newEntity.set(DESCRIPTION, randomString());
newEntity.set("owner", randomString());
- newEntity.set(QUALIFIED_NAME, dbName);
- newEntity.set(CLUSTER_NAME, randomString());
+ newEntity.set(QUALIFIED_NAME, qualifiedName);
+ newEntity.set(CLUSTER_NAME, clusterName);
//updating unique attribute
sendHookMessage(new EntityUpdateRequest(TEST_USER, newEntity));
@@ -243,7 +254,7 @@ public class NotificationHookConsumerIT extends BaseResourceIT {
}
});
- Referenceable actualEntity = atlasClientV1.getEntity(DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, dbName);
+ Referenceable actualEntity = atlasClientV1.getEntity(DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, qualifiedName);
assertEquals(actualEntity.get(DESCRIPTION), newEntity.get(DESCRIPTION));
assertEquals(actualEntity.get("owner"), newEntity.get("owner"));
diff --git a/webapp/src/test/java/org/apache/atlas/web/integration/EntityJerseyResourceIT.java b/webapp/src/test/java/org/apache/atlas/web/integration/EntityJerseyResourceIT.java
index edb4568..70775b3 100755
--- a/webapp/src/test/java/org/apache/atlas/web/integration/EntityJerseyResourceIT.java
+++ b/webapp/src/test/java/org/apache/atlas/web/integration/EntityJerseyResourceIT.java
@@ -277,9 +277,10 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
public void testGetEntityByAttribute() throws Exception {
Referenceable db1 = new Referenceable(DATABASE_TYPE_BUILTIN);
String dbName = randomString();
+ String qualifiedName = dbName + "@cl1";
db1.set(NAME, dbName);
db1.set(DESCRIPTION, randomString());
- db1.set(AtlasClient.REFERENCEABLE_ATTRIBUTE_NAME, dbName);
+ db1.set(AtlasClient.REFERENCEABLE_ATTRIBUTE_NAME, qualifiedName);
db1.set("owner", "user1");
db1.set(CLUSTER_NAME, "cl1");
db1.set("parameters", Collections.EMPTY_MAP);
@@ -287,9 +288,9 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
createInstance(db1);
//get entity by attribute
- Referenceable referenceable = atlasClientV1.getEntity(DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, dbName);
+ Referenceable referenceable = atlasClientV1.getEntity(DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, qualifiedName);
Assert.assertEquals(referenceable.getTypeName(), DATABASE_TYPE_BUILTIN);
- Assert.assertEquals(referenceable.get(QUALIFIED_NAME), dbName);
+ Assert.assertEquals(referenceable.get(QUALIFIED_NAME), dbName + "@" + "cl1");
}
@Test
@@ -1096,11 +1097,12 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
// Create database entity
Referenceable db1 = new Referenceable(DATABASE_TYPE_BUILTIN);
String dbName = randomString();
+ String qualifiedName = dbName + "@cl1";
db1.set(NAME, dbName);
- db1.set(QUALIFIED_NAME, dbName);
+ db1.set(QUALIFIED_NAME, qualifiedName);
db1.set(CLUSTER_NAME, randomString());
db1.set(DESCRIPTION, randomString());
- db1.set(AtlasClient.REFERENCEABLE_ATTRIBUTE_NAME, dbName);
+ db1.set(AtlasClient.REFERENCEABLE_ATTRIBUTE_NAME, qualifiedName);
db1.set("owner", "user1");
db1.set(CLUSTER_NAME, "cl1");
db1.set("parameters", Collections.EMPTY_MAP);
@@ -1108,7 +1110,7 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
Id db1Id = createInstance(db1);
// Delete the database entity
- List<String> deletedGuidsList = atlasClientV1.deleteEntity(DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, dbName).getDeletedEntities();
+ List<String> deletedGuidsList = atlasClientV1.deleteEntity(DATABASE_TYPE_BUILTIN, QUALIFIED_NAME, qualifiedName).getDeletedEntities();
// Verify that deleteEntities() response has database entity guids
Assert.assertEquals(deletedGuidsList.size(), 1);