This is an automated email from the ASF dual-hosted git repository. sarath pushed a commit to branch branch-2.0 in repository https://gitbox.apache.org/repos/asf/atlas.git
commit fceafbc75f5b5af52a095612620cbe0d51a84cd6 Author: Merryle Wang <merryle.w...@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 <sar...@apache.org> (cherry picked from commit 85f9b502e883d3d4870dd201c98aee257a3efa1a) --- .../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);