Commit 14037eed by lma Committed by Sarath Subramanian

ATLAS-3031: UI : Allow user to export the lineage in PNG or JPEG format

parent 8dc4041c
......@@ -109,7 +109,14 @@ public class AtlasJanusElement<T extends Element> implements AtlasElement {
@Override
public void setProperty(String propertyName, Object value) {
try {
getWrappedElement().property(propertyName, value);
if (value == null) {
Object existingVal = getProperty(propertyName, Object.class);
if (existingVal != null) {
removeProperty(propertyName);
}
} else {
getWrappedElement().property(propertyName, value);
}
} catch(SchemaViolationException e) {
throw new AtlasSchemaViolationException(e);
}
......@@ -157,9 +164,6 @@ public class AtlasJanusElement<T extends Element> implements AtlasElement {
@Override
public List<String> getListProperty(String propertyName) {
List<String> value = getProperty(propertyName, List.class);
if (value == null) {
return Collections.emptyList();
}
return value;
}
......@@ -200,7 +204,7 @@ public class AtlasJanusElement<T extends Element> implements AtlasElement {
List<String> value = getListProperty(propertyName);
if (value.isEmpty()) {
if (value == null || value.isEmpty()) {
return (List<V>)value;
}
......
......@@ -154,9 +154,9 @@ public class AtlasArrayType extends AtlasType {
boolean ret = true;
if (val1 == null) {
ret = isEmptyArrayValue(val2);
ret = val2 == null;
} else if (val2 == null) {
ret = isEmptyArrayValue(val1);
ret = false;
} else {
if (val1.getClass().isArray() && val2.getClass().isArray()) {
int len = Array.getLength(val1);
......@@ -510,9 +510,7 @@ public class AtlasArrayType extends AtlasType {
}
private boolean isEmptyArrayValue(Object val) {
if (val == null) {
return true;
} else if (val instanceof Collection) {
if (val instanceof Collection) {
return ((Collection) val).isEmpty();
} else if (val.getClass().isArray()) {
return Array.getLength(val) == 0;
......
......@@ -553,6 +553,7 @@ public final class TestUtilsV2 {
public static final String SERDE_TYPE = "serdeType";
public static final String COLUMNS_MAP = "columnsMap";
public static final String COLUMNS_ATTR_NAME = "columns";
public static final String ENTITY_TYPE_WITH_SIMPLE_ATTR = "entity_with_simple_attr";
public static final String ENTITY_TYPE_WITH_NESTED_COLLECTION_ATTR = "entity_with_nested_collection_attr";
public static final String ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR = "entity_with_complex_collection_attr";
public static final String ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR_DELETE = "entity_with_complex_collection_attr_delete";
......@@ -621,6 +622,42 @@ public final class TestUtilsV2 {
return ret;
}
public static AtlasTypesDef defineSimpleAttrType() {
AtlasEntityDef simpleAttributesEntityType =
createClassTypeDef(ENTITY_TYPE_WITH_SIMPLE_ATTR, ENTITY_TYPE_WITH_SIMPLE_ATTR + "_description", null,
createUniqueRequiredAttrDef("name", "string"),
new AtlasAttributeDef("stringAtrr", "string",
true,
SINGLE, 1, 1,
false, false, false, null),
new AtlasAttributeDef("arrayOfStrings",
"array<string>", true, SINGLE, 1, 1,
false, false, false, null),
new AtlasAttributeDef("mapOfStrings", "map<string,string>",
true, SINGLE, 1,1, false, false, false, null)
);
AtlasTypesDef ret = AtlasTypeUtil.getTypesDef(Collections.<AtlasEnumDef>emptyList(),
Collections.<AtlasStructDef>emptyList(),
Collections.<AtlasClassificationDef>emptyList(),
Collections.singletonList(simpleAttributesEntityType));
return ret;
}
public static AtlasEntityWithExtInfo createSimpleAttrTypeEntity() {
AtlasEntity entity = new AtlasEntity(ENTITY_TYPE_WITH_SIMPLE_ATTR);
entity.setAttribute(NAME, ENTITY_TYPE_WITH_SIMPLE_ATTR);
entity.setAttribute("stringAtrr", "DummyThree");
entity.setAttribute("arrayOfStrings", Arrays.asList("DummyOne", "DummyTwo"));
entity.setAttribute("mapOfStrings", Collections.singletonMap("one", "DummyString"));
return new AtlasEntityWithExtInfo(entity);
}
public static AtlasTypesDef defineHiveTypes() {
String _description = "_description";
......
......@@ -1587,10 +1587,6 @@ public final class GraphHelper {
public static Map<String, Object> getPrimitiveMap(AtlasVertex instanceVertex, String propertyName) {
Map<String, Object> ret = instanceVertex.getProperty(AtlasGraphUtilsV2.encodePropertyKey(propertyName), Map.class);
if (ret == null) {
ret = new HashMap<>();
}
return ret;
}
......
......@@ -228,12 +228,11 @@ public class AtlasGraphUtilsV2 {
Object existingValue = element.getProperty(propertyName, Object.class);
if (value == null || (value instanceof Collection && ((Collection)value).isEmpty())) {
if (value == null) {
if (existingValue != null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Removing property {} from {}", propertyName, toString(element));
}
element.removeProperty(propertyName);
}
} else {
......@@ -242,7 +241,7 @@ public class AtlasGraphUtilsV2 {
LOG.debug("Setting property {} in {}", propertyName, toString(element));
}
if ( value instanceof Date) {
if (value instanceof Date) {
Long encodedValue = ((Date) value).getTime();
element.setProperty(propertyName, encodedValue);
} else {
......
......@@ -947,52 +947,63 @@ public class EntityGraphMapper {
boolean isReference = isReference(mapType.getValueType());
boolean isSoftReference = ctx.getAttribute().getAttributeDef().isSoftReferenced();
if (MapUtils.isNotEmpty(newVal)) {
String propertyName = ctx.getVertexProperty();
boolean isNewValNull = newVal == null;
if (isReference) {
for (Map.Entry<Object, Object> entry : newVal.entrySet()) {
String key = entry.getKey().toString();
AtlasEdge existingEdge = isSoftReference ? null : getEdgeIfExists(mapType, currentMap, key);
if (isNewValNull) {
newVal = new HashMap<>();
}
AttributeMutationContext mapCtx = new AttributeMutationContext(ctx.getOp(), ctx.getReferringVertex(), attribute, entry.getValue(),
propertyName, mapType.getValueType(), existingEdge);
// Add/Update/Remove property value
Object newEntry = mapCollectionElementsToVertex(mapCtx, context);
String propertyName = ctx.getVertexProperty();
if (!isSoftReference && newEntry instanceof AtlasEdge) {
AtlasEdge edge = (AtlasEdge) newEntry;
if (isReference) {
for (Map.Entry<Object, Object> entry : newVal.entrySet()) {
String key = entry.getKey().toString();
AtlasEdge existingEdge = isSoftReference ? null : getEdgeIfExists(mapType, currentMap, key);
edge.setProperty(ATTRIBUTE_KEY_PROPERTY_KEY, key);
AttributeMutationContext mapCtx = new AttributeMutationContext(ctx.getOp(), ctx.getReferringVertex(), attribute, entry.getValue(),
propertyName, mapType.getValueType(), existingEdge);
// Add/Update/Remove property value
Object newEntry = mapCollectionElementsToVertex(mapCtx, context);
// If value type indicates this attribute is a reference, and the attribute has an inverse reference attribute,
// update the inverse reference value.
AtlasAttribute inverseRefAttribute = attribute.getInverseRefAttribute();
if (!isSoftReference && newEntry instanceof AtlasEdge) {
AtlasEdge edge = (AtlasEdge) newEntry;
if (inverseRefAttribute != null) {
addInverseReference(context, inverseRefAttribute, edge, getRelationshipAttributes(ctx.getValue()));
}
edge.setProperty(ATTRIBUTE_KEY_PROPERTY_KEY, key);
updateInConsistentOwnedMapVertices(ctx, mapType, newEntry);
// If value type indicates this attribute is a reference, and the attribute has an inverse reference attribute,
// update the inverse reference value.
AtlasAttribute inverseRefAttribute = attribute.getInverseRefAttribute();
newMap.put(key, newEntry);
if (inverseRefAttribute != null) {
addInverseReference(context, inverseRefAttribute, edge, getRelationshipAttributes(ctx.getValue()));
}
if (isSoftReference) {
newMap.put(key, newEntry);
}
updateInConsistentOwnedMapVertices(ctx, mapType, newEntry);
newMap.put(key, newEntry);
}
if (isSoftReference) {
newMap.put(key, newEntry);
}
}
Map<String, Object> finalMap = removeUnusedMapEntries(attribute, ctx.getReferringVertex(), currentMap, newMap);
newMap.putAll(finalMap);
Map<String, Object> finalMap = removeUnusedMapEntries(attribute, ctx.getReferringVertex(), currentMap, newMap);
newMap.putAll(finalMap);
} else {
// primitive type map
if (isNewValNull) {
ctx.getReferringVertex().setProperty(propertyName, null);
} else {
// primitive type map
ctx.getReferringVertex().setProperty(propertyName, new HashMap<>(newVal));
newVal.forEach((key, value) -> newMap.put(key.toString(), value));
}
newVal.forEach((key, value) -> newMap.put(key.toString(), value));
}
if (isSoftReference) {
if (isSoftReference) {
if (isNewValNull) {
ctx.getReferringVertex().setProperty(propertyName,null);
} else {
ctx.getReferringVertex().setProperty(propertyName, new HashMap<>(newMap));
}
}
......@@ -1019,6 +1030,7 @@ public class EntityGraphMapper {
Cardinality cardinality = attribute.getAttributeDef().getCardinality();
List<Object> newElementsCreated = new ArrayList<>();
List<Object> currentElements;
boolean isNewElementsNull = newElements == null;
if (isReference && !isSoftReference) {
currentElements = (List) getCollectionElementsUsingRelationship(ctx.getReferringVertex(), attribute);
......@@ -1026,28 +1038,30 @@ public class EntityGraphMapper {
currentElements = (List) getArrayElementsProperty(elementType, isSoftReference, ctx.getReferringVertex(), ctx.getVertexProperty());
}
if (CollectionUtils.isNotEmpty(newElements)) {
if (cardinality == SET) {
newElements = (List) newElements.stream().distinct().collect(Collectors.toList());
}
if (isNewElementsNull) {
newElements = new ArrayList();
}
for (int index = 0; index < newElements.size(); index++) {
AtlasEdge existingEdge = (isSoftReference) ? null : getEdgeAt(currentElements, index, elementType);
AttributeMutationContext arrCtx = new AttributeMutationContext(ctx.getOp(), ctx.getReferringVertex(), ctx.getAttribute(), newElements.get(index),
ctx.getVertexProperty(), elementType, existingEdge);
if (cardinality == SET) {
newElements = (List) newElements.stream().distinct().collect(Collectors.toList());
}
Object newEntry = mapCollectionElementsToVertex(arrCtx, context);
for (int index = 0; index < newElements.size(); index++) {
AtlasEdge existingEdge = (isSoftReference) ? null : getEdgeAt(currentElements, index, elementType);
AttributeMutationContext arrCtx = new AttributeMutationContext(ctx.getOp(), ctx.getReferringVertex(), ctx.getAttribute(), newElements.get(index),
ctx.getVertexProperty(), elementType, existingEdge);
if (isReference && newEntry != null && newEntry instanceof AtlasEdge && inverseRefAttribute != null) {
// Update the inverse reference value.
AtlasEdge newEdge = (AtlasEdge) newEntry;
Object newEntry = mapCollectionElementsToVertex(arrCtx, context);
addInverseReference(context, inverseRefAttribute, newEdge, getRelationshipAttributes(ctx.getValue()));
}
if (isReference && newEntry != null && newEntry instanceof AtlasEdge && inverseRefAttribute != null) {
// Update the inverse reference value.
AtlasEdge newEdge = (AtlasEdge) newEntry;
if(newEntry != null) {
newElementsCreated.add(newEntry);
}
addInverseReference(context, inverseRefAttribute, newEdge, getRelationshipAttributes(ctx.getValue()));
}
if(newEntry != null) {
newElementsCreated.add(newEntry);
}
}
......@@ -1065,8 +1079,11 @@ public class EntityGraphMapper {
}
}
// for dereference on way out
setArrayElementsProperty(elementType, isSoftReference, ctx.getReferringVertex(), ctx.getVertexProperty(), newElementsCreated);
if (isNewElementsNull) {
setArrayElementsProperty(elementType, isSoftReference, ctx.getReferringVertex(), ctx.getVertexProperty(), null);
} else {
setArrayElementsProperty(elementType, isSoftReference, ctx.getReferringVertex(), ctx.getVertexProperty(), newElementsCreated);
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== mapArrayValue({})", ctx);
......
......@@ -74,6 +74,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
......@@ -740,7 +741,9 @@ public class EntityGraphRetriever {
Map<String, AtlasObjectId> ret = null;
Map softRefVal = entityVertex.getProperty(attribute.getVertexPropertyName(), Map.class);
if (MapUtils.isNotEmpty(softRefVal)) {
if (MapUtils.isEmpty(softRefVal)) {
return softRefVal;
} else {
ret = new HashMap<>();
for (Object mapKey : softRefVal.keySet()) {
......@@ -751,7 +754,6 @@ public class EntityGraphRetriever {
}
}
}
return ret;
}
......@@ -759,7 +761,9 @@ public class EntityGraphRetriever {
List<AtlasObjectId> ret = null;
List softRefVal = entityVertex.getListProperty(attribute.getVertexPropertyName(), List.class);
if (CollectionUtils.isNotEmpty(softRefVal)) {
if (CollectionUtils.isEmpty(softRefVal)) {
return softRefVal;
} else {
ret = new ArrayList<>();
for (Object o : softRefVal) {
......@@ -841,10 +845,6 @@ public class EntityGraphRetriever {
ret = getPrimitiveMap(entityVertex, attribute.getVertexPropertyName());
}
if (MapUtils.isEmpty(ret)) {
ret = null;
}
return ret;
}
......@@ -855,14 +855,14 @@ public class EntityGraphRetriever {
AtlasType arrayElementType = arrayType.getElementType();
List<Object> arrayElements = getArrayElementsProperty(arrayElementType, entityVertex, attribute);
if (CollectionUtils.isEmpty(arrayElements)) {
return null;
}
if (LOG.isDebugEnabled()) {
LOG.debug("Mapping array attribute {} for vertex {}", arrayElementType.getTypeName(), entityVertex);
}
if (CollectionUtils.isEmpty(arrayElements)) {
return arrayElements;
}
List arrValues = new ArrayList(arrayElements.size());
String edgeLabel = attribute.getRelationshipEdgeLabel();
AtlasRelationshipEdgeDirection edgeDirection = attribute.getRelationshipEdgeDirection();
......
......@@ -38,6 +38,7 @@ import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
......@@ -48,6 +49,7 @@ import static org.apache.atlas.TestUtilsV2.ENTITY_TYPE;
import static org.apache.atlas.TestUtilsV2.ENTITY_TYPE_MAP;
import static org.apache.atlas.TestUtilsV2.ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR;
import static org.apache.atlas.TestUtilsV2.ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR_DELETE;
import static org.apache.atlas.TestUtilsV2.ENTITY_TYPE_WITH_SIMPLE_ATTR;
import static org.apache.atlas.TestUtilsV2.NAME;
import static org.apache.atlas.repository.graph.GraphHelper.getStatus;
import static org.apache.atlas.type.AtlasTypeUtil.getAtlasObjectId;
......@@ -66,7 +68,8 @@ public class AtlasComplexAttributesTest extends AtlasEntityTestBase {
// create typeDefs
AtlasTypesDef[] testTypesDefs = new AtlasTypesDef[] { TestUtilsV2.defineTypeWithComplexCollectionAttributes(),
TestUtilsV2.defineTypeWithMapAttributes() };
TestUtilsV2.defineTypeWithMapAttributes(),
TestUtilsV2.defineSimpleAttrType()};
createTypesDef(testTypesDefs);
// create entity
......@@ -195,6 +198,51 @@ public class AtlasComplexAttributesTest extends AtlasEntityTestBase {
attrEntity.setAttribute("mapAttr5", map5);
}
@Test
public void testArrayAttribute() throws Exception {
init();
AtlasEntityWithExtInfo simpleEntity = TestUtilsV2.createSimpleAttrTypeEntity();
EntityMutationResponse response = entityStore.createOrUpdate(new AtlasEntityStream(simpleEntity), false);
AtlasEntityHeader simpleEntityHeader = response.getFirstCreatedEntityByTypeName(ENTITY_TYPE_WITH_SIMPLE_ATTR);
AtlasEntity createdSimpleEntity = getEntityFromStore(simpleEntityHeader);
validateEntity(simpleEntity, createdSimpleEntity);
createdSimpleEntity.setAttribute("stringAtrr", null);
createdSimpleEntity.setAttribute("mapOfStrings", Collections.emptyMap());
createdSimpleEntity.setAttribute("arrayOfStrings", Collections.emptyList());
EntityMutationResponse responseUpdated = entityStore.createOrUpdate(new AtlasEntityStream(createdSimpleEntity), false);
AtlasEntityHeader simpleEntityUpdatedHeader = responseUpdated.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_SIMPLE_ATTR);
AtlasEntity updatedSimpleEntity = getEntityFromStore(simpleEntityUpdatedHeader);
assertNull(updatedSimpleEntity.getAttribute("stringAtrr"));
assertEquals(updatedSimpleEntity.getAttribute("mapOfStrings"), Collections.emptyMap());
assertEquals(updatedSimpleEntity.getAttribute("arrayOfStrings"), Collections.emptyList());
updatedSimpleEntity.setAttribute("stringAtrr", "");
updatedSimpleEntity.setAttribute("mapOfStrings", null);
updatedSimpleEntity.setAttribute("arrayOfStrings", null);
EntityMutationResponse responseUpdatedAgain = entityStore.createOrUpdate(new AtlasEntityStream(updatedSimpleEntity), false);
AtlasEntityHeader simpleEntityUpdatedAgainHeader = responseUpdatedAgain.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_SIMPLE_ATTR);
AtlasEntity updatedAgainSimpleEntity = getEntityFromStore(simpleEntityUpdatedAgainHeader);
assertEquals(updatedAgainSimpleEntity.getAttribute("stringAtrr"), "");
assertNull(updatedAgainSimpleEntity.getAttribute("arrayOfStrings"));
assertNull(updatedAgainSimpleEntity.getAttribute("mapOfStrings"));
updatedAgainSimpleEntity.setAttribute("stringAtrr", "Dummy String Test 3");
updatedAgainSimpleEntity.setAttribute("mapOfStrings", Collections.singletonMap("key1", "val1"));
updatedAgainSimpleEntity.setAttribute("arrayOfStrings", Arrays.asList("DummyTest3", "DummyTest4"));
EntityMutationResponse updateRes = entityStore.createOrUpdate(new AtlasEntityStream(updatedAgainSimpleEntity), false);
AtlasEntityHeader updateHeader = updateRes.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_SIMPLE_ATTR);
AtlasEntity updateEntity = getEntityFromStore(updateHeader);
assertEquals(updateEntity.getAttribute("stringAtrr"), "Dummy String Test 3");
assertEquals(updateEntity.getAttribute("arrayOfStrings"), Arrays.asList("DummyTest3", "DummyTest4"));
assertEquals(updateEntity.getAttribute("mapOfStrings"), Collections.singletonMap("key1", "val1"));
}
@Test(dependsOnMethods = "testCreateComplexAttributeEntity")
public void testStructArray() throws Exception {
init();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment