You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by sh...@apache.org on 2016/05/25 18:34:34 UTC
[1/3] incubator-atlas git commit: ATLAS-716 Entity update/delete
notifications (shwethags)
Repository: incubator-atlas
Updated Branches:
refs/heads/master 153fc3623 -> 705014eb3
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/test/java/org/apache/atlas/service/DefaultMetadataServiceTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/service/DefaultMetadataServiceTest.java b/repository/src/test/java/org/apache/atlas/service/DefaultMetadataServiceTest.java
index 1f906ed..e6dd230 100644
--- a/repository/src/test/java/org/apache/atlas/service/DefaultMetadataServiceTest.java
+++ b/repository/src/test/java/org/apache/atlas/service/DefaultMetadataServiceTest.java
@@ -73,6 +73,7 @@ import java.util.Map;
import static org.apache.atlas.TestUtils.COLUMNS_ATTR_NAME;
import static org.apache.atlas.TestUtils.COLUMN_TYPE;
+import static org.apache.atlas.TestUtils.PII;
import static org.apache.atlas.TestUtils.TABLE_TYPE;
import static org.apache.atlas.TestUtils.createColumnEntity;
import static org.apache.atlas.TestUtils.createDBEntity;
@@ -80,6 +81,7 @@ import static org.apache.atlas.TestUtils.createTableEntity;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
@Guice(modules = RepositoryMetadataModule.class)
@@ -154,23 +156,21 @@ public class DefaultMetadataServiceTest {
String entityjson = InstanceSerialization.toJson(entity, true);
JSONArray entitiesJson = new JSONArray();
entitiesJson.put(entityjson);
- String response = metadataService.createEntities(entitiesJson.toString());
- JSONArray guids = new JSONArray(response);
- if (guids != null && guids.length() > 0) {
- return guids.getString(guids.length() - 1);
+ List<String> guids = metadataService.createEntities(entitiesJson.toString());
+ if (guids != null && guids.size() > 0) {
+ return guids.get(guids.size() - 1);
}
return null;
}
- private String updateInstance(Referenceable entity) throws Exception {
+ private AtlasClient.EntityResult updateInstance(Referenceable entity) throws Exception {
RequestContext.createContext();
ParamChecker.notNull(entity, "Entity");
ParamChecker.notNull(entity.getId(), "Entity");
String entityjson = InstanceSerialization.toJson(entity, true);
JSONArray entitiesJson = new JSONArray();
entitiesJson.put(entityjson);
- String response = metadataService.updateEntities(entitiesJson.toString());
- return new JSONArray(response).getString(0);
+ return metadataService.updateEntities(entitiesJson.toString());
}
@Test(expectedExceptions = TypeNotFoundException.class)
@@ -201,6 +201,32 @@ public class DefaultMetadataServiceTest {
}
@Test
+ public void testAddDeleteTrait() throws Exception {
+ Referenceable entity = createDBEntity();
+ String id = createInstance(entity);
+
+ //add trait
+ Struct tag = new Struct(TestUtils.PII);
+ metadataService.addTrait(id, InstanceSerialization.toJson(tag, true));
+
+ List<String> traits = metadataService.getTraitNames(id);
+ assertEquals(traits.size(), 1);
+ assertEquals(traits.get(0), PII);
+
+ //delete trait
+ metadataService.deleteTrait(id, PII);
+ traits = metadataService.getTraitNames(id);
+ assertEquals(traits.size(), 0);
+
+ //add trait again
+ metadataService.addTrait(id, InstanceSerialization.toJson(tag, true));
+
+ traits = metadataService.getTraitNames(id);
+ assertEquals(traits.size(), 1);
+ assertEquals(traits.get(0), PII);
+ }
+
+ @Test
public void testEntityAudit() throws Exception {
//create entity
Referenceable entity = createDBEntity();
@@ -221,7 +247,7 @@ public class DefaultMetadataServiceTest {
assertAuditEvents(id, EntityAuditEvent.EntityAuditAction.ENTITY_DELETE);
}
- private List<String> deleteEntities(String... guids) throws AtlasException {
+ private AtlasClient.EntityResult deleteEntities(String... guids) throws AtlasException {
RequestContext.createContext();
return metadataService.deleteEntities(Arrays.asList(guids));
}
@@ -350,7 +376,7 @@ public class DefaultMetadataServiceTest {
Assert.assertTrue(partsMap.get("part2").equalsContents(((Map<String, Struct>)tableDefinition.get("partitionsMap")).get("part2")));
//Test map pointing to a class
- final Map<String, Struct> columnsMap = new HashMap<>();
+ final Map<String, Referenceable> columnsMap = new HashMap<>();
Referenceable col0Type = new Referenceable(TestUtils.COLUMN_TYPE,
new HashMap<String, Object>() {{
put(NAME, "test1");
@@ -393,17 +419,33 @@ public class DefaultMetadataServiceTest {
verifyMapUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), null, TestUtils.COLUMNS_MAP);
}
- private void verifyMapUpdates(String typeName, String uniqAttrName, String uniqAttrValue, Map<String, Struct> expectedMap, String mapAttrName) throws AtlasException {
+ private void verifyMapUpdates(String typeName, String uniqAttrName, String uniqAttrValue,
+ Map<String, Referenceable> expectedMap, String mapAttrName) throws AtlasException {
String json =
metadataService.getEntityDefinition(typeName, uniqAttrName, uniqAttrValue);
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(json, true);
+ Map<String, Referenceable> actualMap = (Map<String, Referenceable>) tableDefinition.get(mapAttrName);
- if(expectedMap == null) {
- Assert.assertNull(tableDefinition.get(TestUtils.COLUMNS_MAP));
+ if (expectedMap == null && actualMap != null) {
+ //all are marked as deleted in case of soft delete
+ for (String key : actualMap.keySet()) {
+ assertEquals(actualMap.get(key).getId().state, Id.EntityState.DELETED);
+ }
+ } else if(expectedMap == null) {
+ //hard delete case
+ assertNull(actualMap);
} else {
- Assert.assertEquals(((Map<String, Referenceable>)tableDefinition.get(mapAttrName)).size(), expectedMap.size());
+ assertTrue(actualMap.size() >= expectedMap.size());
+
for (String key : expectedMap.keySet()) {
- Assert.assertTrue(((Map<String, Referenceable>) tableDefinition.get(mapAttrName)).get(key).equalsContents(expectedMap.get(key)));
+ assertTrue(actualMap.get(key).equalsContents(expectedMap.get(key)));
+ }
+
+ //rest of the keys are marked as deleted
+ List<String> extraKeys = new ArrayList<>(actualMap.keySet());
+ extraKeys.removeAll(expectedMap.keySet());
+ for (String key : extraKeys) {
+ assertEquals(actualMap.get(key).getId().getState(), Id.EntityState.DELETED);
}
}
}
@@ -438,14 +480,13 @@ public class DefaultMetadataServiceTest {
Assert.assertEquals(actualColumns, updatedColNameList);
}
- private void updateEntityPartial(String guid, Referenceable entity) throws AtlasException {
+ private AtlasClient.EntityResult updateEntityPartial(String guid, Referenceable entity) throws AtlasException {
RequestContext.createContext();
- metadataService.updateEntityPartialByGuid(guid, entity);
+ return metadataService.updateEntityPartialByGuid(guid, entity);
}
@Test
public void testUpdateEntityArrayOfClass() throws Exception {
-
//test array of class with id
final List<Referenceable> columns = new ArrayList<>();
Map<String, Object> values = new HashMap<>();
@@ -456,63 +497,67 @@ public class DefaultMetadataServiceTest {
Referenceable tableUpdated = new Referenceable(TestUtils.TABLE_TYPE, new HashMap<String, Object>() {{
put(COLUMNS_ATTR_NAME, columns);
}});
- updateEntityPartial(tableId._getId(), tableUpdated);
+ AtlasClient.EntityResult entityResult = updateEntityPartial(tableId._getId(), tableUpdated);
+ assertEquals(entityResult.getCreatedEntities().size(), 1); //col1 created
+ assertEquals(entityResult.getUpdateEntities().size(), 1); //table updated
+ assertEquals(entityResult.getUpdateEntities().get(0), tableId._getId());
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
- //Partial update. Add col5 But also update col1
+ //Partial update. Add col2 But also update col1
Map<String, Object> valuesCol5 = new HashMap<>();
- valuesCol5.put(NAME, "col5");
+ valuesCol5.put(NAME, "col2");
valuesCol5.put("type", "type");
Referenceable col2 = new Referenceable(TestUtils.COLUMN_TYPE, valuesCol5);
//update col1
col1.set("type", "type1");
-
- //add col5
- final List<Referenceable> updateColumns = Arrays.asList(col1, col2);
+ columns.add(col2);
tableUpdated = new Referenceable(TestUtils.TABLE_TYPE, new HashMap<String, Object>() {{
- put(COLUMNS_ATTR_NAME, updateColumns);
+ put(COLUMNS_ATTR_NAME, columns);
}});
- updateEntityPartial(tableId._getId(), tableUpdated);
+ entityResult = updateEntityPartial(tableId._getId(), tableUpdated);
+ assertEquals(entityResult.getCreatedEntities().size(), 1); //col2 created
+ assertEquals(entityResult.getUpdateEntities().size(), 2); //table, col1 updated
- verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), updateColumns, COLUMNS_ATTR_NAME);
+ verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
- //Complete update. Add array elements - col3,4
+ //Complete update. Add array elements - col3,col4
Map<String, Object> values1 = new HashMap<>();
values1.put(NAME, "col3");
values1.put("type", "type");
- Referenceable ref1 = new Referenceable(TestUtils.COLUMN_TYPE, values1);
- columns.add(ref1);
+ Referenceable col3 = new Referenceable(TestUtils.COLUMN_TYPE, values1);
+ columns.add(col3);
Map<String, Object> values2 = new HashMap<>();
values2.put(NAME, "col4");
values2.put("type", "type");
- Referenceable ref2 = new Referenceable(TestUtils.COLUMN_TYPE, values2);
- columns.add(ref2);
+ Referenceable col4 = new Referenceable(TestUtils.COLUMN_TYPE, values2);
+ columns.add(col4);
table.set(COLUMNS_ATTR_NAME, columns);
- updateInstance(table);
+ entityResult = updateInstance(table);
+ assertEquals(entityResult.getCreatedEntities().size(), 2); //col3, col4 created
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
//Swap elements
columns.clear();
- columns.add(ref2);
- columns.add(ref1);
+ columns.add(col4);
+ columns.add(col3);
table.set(COLUMNS_ATTR_NAME, columns);
- updateInstance(table);
-
+ entityResult = updateInstance(table);
+ assertEquals(entityResult.getDeletedEntities().size(), 2); //col1, col2 are deleted
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
//drop a single column
columns.clear();
- columns.add(ref1);
+ columns.add(col3);
table.set(COLUMNS_ATTR_NAME, columns);
- updateInstance(table);
-
+ entityResult = updateInstance(table);
+ assertEquals(entityResult.getDeletedEntities().size(), 1); //col4 deleted
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
//Remove a class reference/Id and insert another reference
@@ -520,34 +565,46 @@ public class DefaultMetadataServiceTest {
values.clear();
columns.clear();
- values.put(NAME, "col2");
+ values.put(NAME, "col5");
values.put("type", "type");
- col1 = new Referenceable(TestUtils.COLUMN_TYPE, values);
- columns.add(col1);
+ Referenceable col5 = new Referenceable(TestUtils.COLUMN_TYPE, values);
+ columns.add(col5);
table.set(COLUMNS_ATTR_NAME, columns);
- updateInstance(table);
+ entityResult = updateInstance(table);
+ assertEquals(entityResult.getCreatedEntities().size(), 1); //col5 created
+ assertEquals(entityResult.getDeletedEntities().size(), 1); //col3 deleted
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), columns, COLUMNS_ATTR_NAME);
//Update array column to null
table.setNull(COLUMNS_ATTR_NAME);
- String newtableId = updateInstance(table);
- Assert.assertEquals(newtableId, tableId._getId());
-
+ entityResult = updateInstance(table);
+ assertEquals(entityResult.getDeletedEntities().size(), 1);
verifyArrayUpdates(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME), null, COLUMNS_ATTR_NAME);
}
- private void verifyArrayUpdates(String typeName, String uniqAttrName, String uniqAttrValue, List<? extends Struct> expectedArray, String arrAttrName) throws AtlasException {
- String json =
- metadataService.getEntityDefinition(typeName, uniqAttrName, uniqAttrValue);
+ private void verifyArrayUpdates(String typeName, String uniqAttrName, String uniqAttrValue,
+ List<Referenceable> expectedArray, String arrAttrName) throws AtlasException {
+ String json = metadataService.getEntityDefinition(typeName, uniqAttrName, uniqAttrValue);
Referenceable entityDefinition = InstanceSerialization.fromJsonReferenceable(json, true);
-
- if (expectedArray == null) {
- Assert.assertNull(entityDefinition.get(arrAttrName));
+ List<Referenceable> actualArray = (List<Referenceable>) entityDefinition.get(arrAttrName);
+ if (expectedArray == null && actualArray != null) {
+ //all are marked as deleted in case of soft delete
+ for (int index = 0; index < actualArray.size(); index++) {
+ assertEquals(actualArray.get(index).getId().state, Id.EntityState.DELETED);
+ }
+ } else if(expectedArray == null) {
+ //hard delete case
+ assertNull(actualArray);
} else {
- Assert.assertEquals(((List<Referenceable>)entityDefinition.get(arrAttrName)).size(), expectedArray.size());
- for (int index = 0; index < expectedArray.size(); index++) {
- Assert.assertTrue(((List<Referenceable>) entityDefinition.get(arrAttrName)).get(index).equalsContents(expectedArray.get(index)));
+ int index;
+ for (index = 0; index < expectedArray.size(); index++) {
+ Assert.assertTrue(actualArray.get(index).equalsContents(expectedArray.get(index)));
+ }
+
+ //Rest of the entities in the list are marked as deleted
+ for (; index < actualArray.size(); index++) {
+ assertEquals(actualArray.get(index).getId().state, Id.EntityState.DELETED);
}
}
}
@@ -560,7 +617,7 @@ public class DefaultMetadataServiceTest {
serdeInstance.set("description", "testDesc");
table.set("serde1", serdeInstance);
- String newtableId = updateInstance(table);
+ String newtableId = updateInstance(table).getUpdateEntities().get(0);
Assert.assertEquals(newtableId, tableId._getId());
String tableDefinitionJson =
@@ -664,7 +721,7 @@ public class DefaultMetadataServiceTest {
List<Struct> partitions = new ArrayList<Struct>(){{ add(partition1); add(partition2); }};
table.set("partitions", partitions);
- String newtableId = updateInstance(table);
+ String newtableId = updateInstance(table).getUpdateEntities().get(0);
Assert.assertEquals(newtableId, tableId._getId());
String tableDefinitionJson =
@@ -673,15 +730,14 @@ public class DefaultMetadataServiceTest {
Assert.assertNotNull(tableDefinition.get("partitions"));
List<Struct> partitionsActual = (List<Struct>) tableDefinition.get("partitions");
- Assert.assertEquals(partitionsActual.size(), 2);
- Assert.assertTrue(partitions.get(0).equalsContents(partitionsActual.get(0)));
+ assertPartitions(partitionsActual, partitions);
//add a new element to array of struct
final Struct partition3 = new Struct(TestUtils.PARTITION_STRUCT_TYPE);
partition3.set(NAME, "part3");
partitions.add(partition3);
table.set("partitions", partitions);
- newtableId = updateInstance(table);
+ newtableId = updateInstance(table).getUpdateEntities().get(0);
Assert.assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
@@ -690,13 +746,12 @@ public class DefaultMetadataServiceTest {
Assert.assertNotNull(tableDefinition.get("partitions"));
partitionsActual = (List<Struct>) tableDefinition.get("partitions");
- Assert.assertEquals(partitionsActual.size(), 3);
- Assert.assertTrue(partitions.get(2).equalsContents(partitionsActual.get(2)));
+ assertPartitions(partitionsActual, partitions);
//remove one of the struct values
partitions.remove(1);
table.set("partitions", partitions);
- newtableId = updateInstance(table);
+ newtableId = updateInstance(table).getUpdateEntities().get(0);
Assert.assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
@@ -705,13 +760,11 @@ public class DefaultMetadataServiceTest {
Assert.assertNotNull(tableDefinition.get("partitions"));
partitionsActual = (List<Struct>) tableDefinition.get("partitions");
- Assert.assertEquals(partitionsActual.size(), 2);
- Assert.assertTrue(partitions.get(0).equalsContents(partitionsActual.get(0)));
- Assert.assertTrue(partitions.get(1).equalsContents(partitionsActual.get(1)));
+ assertPartitions(partitionsActual, partitions);
//Update struct value within array of struct
- partition1.set(NAME, "part4");
- newtableId = updateInstance(table);
+ partitions.get(0).set(NAME, "part4");
+ newtableId = updateInstance(table).getUpdateEntities().get(0);
Assert.assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
@@ -720,15 +773,14 @@ public class DefaultMetadataServiceTest {
Assert.assertNotNull(tableDefinition.get("partitions"));
partitionsActual = (List<Struct>) tableDefinition.get("partitions");
- Assert.assertEquals(partitionsActual.size(), 2);
- Assert.assertTrue(partitions.get(0).equalsContents(partitionsActual.get(0)));
+ assertPartitions(partitionsActual, partitions);
//add a repeated element to array of struct
final Struct partition4 = new Struct(TestUtils.PARTITION_STRUCT_TYPE);
partition4.set(NAME, "part4");
partitions.add(partition4);
table.set("partitions", partitions);
- newtableId = updateInstance(table);
+ newtableId = updateInstance(table).getUpdateEntities().get(0);
Assert.assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
@@ -737,15 +789,12 @@ public class DefaultMetadataServiceTest {
Assert.assertNotNull(tableDefinition.get("partitions"));
partitionsActual = (List<Struct>) tableDefinition.get("partitions");
- Assert.assertEquals(partitionsActual.size(), 3);
- Assert.assertEquals(partitionsActual.get(2).get(NAME), "part4");
- Assert.assertEquals(partitionsActual.get(0).get(NAME), "part4");
- Assert.assertTrue(partitions.get(2).equalsContents(partitionsActual.get(2)));
+ assertPartitions(partitionsActual, partitions);
// Remove all elements. Should set array attribute to null
partitions.clear();
- newtableId = updateInstance(table);
+ newtableId = updateInstance(table).getUpdateEntities().get(0);
Assert.assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
@@ -755,6 +804,13 @@ public class DefaultMetadataServiceTest {
Assert.assertNull(tableDefinition.get("partitions"));
}
+ private void assertPartitions(List<Struct> partitionsActual, List<Struct> partitions) {
+ assertEquals(partitionsActual.size(), partitions.size());
+ for (int index = 0; index < partitions.size(); index++) {
+ assertTrue(partitionsActual.get(index).equalsContents(partitions.get(index)));
+ }
+ }
+
@Test(expectedExceptions = ValueConversionException.class)
public void testUpdateRequiredAttrToNull() throws Exception {
@@ -772,7 +828,6 @@ public class DefaultMetadataServiceTest {
@Test
public void testUpdateOptionalAttrToNull() throws Exception {
-
String tableDefinitionJson =
metadataService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, (String) table.get(NAME));
Referenceable tableDefinition = InstanceSerialization.fromJsonReferenceable(tableDefinitionJson, true);
@@ -782,7 +837,7 @@ public class DefaultMetadataServiceTest {
//Update optional attribute
table.setNull("created");
- String newtableId = updateInstance(table);
+ String newtableId = updateInstance(table).getUpdateEntities().get(0);
Assert.assertEquals(newtableId, tableId._getId());
tableDefinitionJson =
@@ -853,35 +908,39 @@ public class DefaultMetadataServiceTest {
// Register an EntityChangeListener to verify the notification mechanism
// is working for deleteEntities().
- DeleteEntitiesChangeListener listener = new DeleteEntitiesChangeListener();
+ EntitiesChangeListener listener = new EntitiesChangeListener();
metadataService.registerListener(listener);
+ //Delete one column
+ String columnId = table1Columns.get(0).getId()._getId();
+ AtlasClient.EntityResult entityResult = deleteEntities(columnId);
+ //column is deleted and table is updated
+ assertEquals(entityResult.getDeletedEntities().get(0), columnId);
+ assertEquals(entityResult.getUpdateEntities().get(0), table1Entity.getId()._getId());
+
+ //verify listener was called for updates and deletes
+ assertEquals(entityResult.getDeletedEntities(), listener.getDeletedEntities());
+ assertEquals(entityResult.getUpdateEntities(), listener.getUpdatedEntities());
+
// Delete the table entities. The deletion should cascade
// to their composite columns.
- List<String> deletedGuids = deleteEntities(table1Entity.getId()._getId());
+ entityResult = deleteEntities(table1Entity.getId()._getId());
// Verify that deleteEntities() response has guids for tables and their composite columns.
- Assert.assertTrue(deletedGuids.contains(table1Entity.getId()._getId()));
- for (IReferenceableInstance column : table1Columns) {
- Assert.assertTrue(deletedGuids.contains(column.getId()._getId()));
- }
+ Assert.assertTrue(entityResult.getDeletedEntities().contains(table1Entity.getId()._getId()));
+ Assert.assertTrue(entityResult.getDeletedEntities().contains(table1Columns.get(1).getId()._getId()));
+ Assert.assertTrue(entityResult.getDeletedEntities().contains(table1Columns.get(2).getId()._getId()));
// Verify that tables and their composite columns have been deleted from the repository.
assertEntityDeleted(TABLE_TYPE, NAME, table1Entity.get(NAME));
- assertEntityDeleted(COLUMN_TYPE, NAME, col1.get(NAME));
assertEntityDeleted(COLUMN_TYPE, NAME, col2.get(NAME));
assertEntityDeleted(COLUMN_TYPE, NAME, col3.get(NAME));
// Verify that the listener was notified about the deleted entities.
- Collection<ITypedReferenceableInstance> deletedEntitiesFromListener = listener.getDeletedEntities();
+ List<String> deletedEntitiesFromListener = listener.getDeletedEntities();
Assert.assertNotNull(deletedEntitiesFromListener);
- Assert.assertEquals(deletedEntitiesFromListener.size(), deletedGuids.size());
- List<String> deletedGuidsFromListener = new ArrayList<>(deletedGuids.size());
- for (ITypedReferenceableInstance deletedEntity : deletedEntitiesFromListener) {
- deletedGuidsFromListener.add(deletedEntity.getId()._getId());
- }
- Assert.assertEquals(deletedGuidsFromListener.size(), deletedGuids.size());
- Assert.assertTrue(deletedGuidsFromListener.containsAll(deletedGuids));
+ Assert.assertEquals(deletedEntitiesFromListener.size(), entityResult.getDeletedEntities().size());
+ Assert.assertTrue(deletedEntitiesFromListener.containsAll(entityResult.getDeletedEntities()));
}
private void assertEntityDeleted(String typeName, String attributeName, Object attributeValue)
@@ -915,12 +974,13 @@ public class DefaultMetadataServiceTest {
// Register an EntityChangeListener to verify the notification mechanism
// is working for deleteEntityByUniqueAttribute().
- DeleteEntitiesChangeListener listener = new DeleteEntitiesChangeListener();
+ EntitiesChangeListener listener = new EntitiesChangeListener();
metadataService.registerListener(listener);
// Delete the table entities. The deletion should cascade
// to their composite columns.
- List<String> deletedGuids = metadataService.deleteEntityByUniqueAttribute(TestUtils.TABLE_TYPE, NAME, (String) table1Entity.get(NAME));
+ List<String> deletedGuids = metadataService.deleteEntityByUniqueAttribute(TestUtils.TABLE_TYPE, NAME,
+ (String) table1Entity.get(NAME)).getDeletedEntities();
// Verify that deleteEntities() response has guids for tables and their composite columns.
Assert.assertTrue(deletedGuids.contains(table1Entity.getId()._getId()));
@@ -936,15 +996,10 @@ public class DefaultMetadataServiceTest {
assertEntityDeleted(COLUMN_TYPE, NAME, col3.get(NAME));
// Verify that the listener was notified about the deleted entities.
- Collection<ITypedReferenceableInstance> deletedEntitiesFromListener = listener.getDeletedEntities();
+ List<String> deletedEntitiesFromListener = listener.getDeletedEntities();
Assert.assertNotNull(deletedEntitiesFromListener);
Assert.assertEquals(deletedEntitiesFromListener.size(), deletedGuids.size());
- List<String> deletedGuidsFromListener = new ArrayList<>(deletedGuids.size());
- for (ITypedReferenceableInstance deletedEntity : deletedEntitiesFromListener) {
- deletedGuidsFromListener.add(deletedEntity.getId()._getId());
- }
- Assert.assertEquals(deletedGuidsFromListener.size(), deletedGuids.size());
- Assert.assertTrue(deletedGuidsFromListener.containsAll(deletedGuids));
+ Assert.assertTrue(deletedEntitiesFromListener.containsAll(deletedGuids));
}
@Test
@@ -1024,10 +1079,10 @@ public class DefaultMetadataServiceTest {
}
}
- private static class DeleteEntitiesChangeListener implements EntityChangeListener {
-
- private Collection<ITypedReferenceableInstance> deletedEntities_;
-
+ private static class EntitiesChangeListener implements EntityChangeListener {
+ private List<String> deletedEntities = new ArrayList<>();
+ private List<String> updatedEntities = new ArrayList<>();
+
@Override
public void onEntitiesAdded(Collection<ITypedReferenceableInstance> entities)
throws AtlasException {
@@ -1036,6 +1091,10 @@ public class DefaultMetadataServiceTest {
@Override
public void onEntitiesUpdated(Collection<ITypedReferenceableInstance> entities)
throws AtlasException {
+ updatedEntities.clear();
+ for (ITypedReferenceableInstance entity : entities) {
+ updatedEntities.add(entity.getId()._getId());
+ }
}
@Override
@@ -1051,11 +1110,18 @@ public class DefaultMetadataServiceTest {
@Override
public void onEntitiesDeleted(Collection<ITypedReferenceableInstance> entities)
throws AtlasException {
- deletedEntities_ = entities;
+ deletedEntities.clear();
+ for (ITypedReferenceableInstance entity : entities) {
+ deletedEntities.add(entity.getId()._getId());
+ }
}
- public Collection<ITypedReferenceableInstance> getDeletedEntities() {
- return deletedEntities_;
+ public List<String> getDeletedEntities() {
+ return deletedEntities;
+ }
+
+ public List<String> getUpdatedEntities() {
+ return updatedEntities;
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/server-api/src/main/java/org/apache/atlas/RequestContext.java
----------------------------------------------------------------------
diff --git a/server-api/src/main/java/org/apache/atlas/RequestContext.java b/server-api/src/main/java/org/apache/atlas/RequestContext.java
index b1d87ea..ec38c11 100644
--- a/server-api/src/main/java/org/apache/atlas/RequestContext.java
+++ b/server-api/src/main/java/org/apache/atlas/RequestContext.java
@@ -49,7 +49,16 @@ public class RequestContext {
private RequestContext() {
}
+ //To handle gets from background threads where createContext() is not called
+ //createContext called for every request in the filter
public static RequestContext get() {
+ if (CURRENT_CONTEXT.get() == null) {
+ synchronized (RequestContext.class) {
+ if (CURRENT_CONTEXT.get() == null) {
+ createContext();
+ }
+ }
+ }
return CURRENT_CONTEXT.get();
}
@@ -72,15 +81,19 @@ public class RequestContext {
this.user = user;
}
- public void recordCreatedEntities(Collection<String> createdEntityIds) {
+ public void recordEntityCreate(Collection<String> createdEntityIds) {
this.createdEntityIds.addAll(createdEntityIds);
}
- public void recordUpdatedEntities(Collection<String> updatedEntityIds) {
+ public void recordEntityUpdate(Collection<String> updatedEntityIds) {
this.updatedEntityIds.addAll(updatedEntityIds);
}
- public void recordDeletedEntity(String entityId, String typeName) throws AtlasException {
+ public void recordEntityUpdate(String entityId) {
+ this.updatedEntityIds.add(entityId);
+ }
+
+ public void recordEntityDelete(String entityId, String typeName) throws AtlasException {
ClassType type = typeSystem.getDataType(ClassType.class, typeName);
ITypedReferenceableInstance entity = type.createInstance(new Id(entityId, 0, typeName));
if (deletedEntityIds.add(entityId)) {
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/server-api/src/main/java/org/apache/atlas/services/MetadataService.java
----------------------------------------------------------------------
diff --git a/server-api/src/main/java/org/apache/atlas/services/MetadataService.java b/server-api/src/main/java/org/apache/atlas/services/MetadataService.java
index c8c1067..6bca3df 100644
--- a/server-api/src/main/java/org/apache/atlas/services/MetadataService.java
+++ b/server-api/src/main/java/org/apache/atlas/services/MetadataService.java
@@ -18,6 +18,7 @@
package org.apache.atlas.services;
+import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasException;
import org.apache.atlas.EntityAuditEvent;
import org.apache.atlas.listener.EntityChangeListener;
@@ -80,7 +81,7 @@ public interface MetadataService {
* @param entityDefinition definition
* @return json array of guids of entities created
*/
- String createEntities(String entityDefinition) throws AtlasException;
+ List<String> createEntities(String entityDefinition) throws AtlasException;
/**
* Get a typed entity instance.
@@ -136,7 +137,7 @@ public interface MetadataService {
* @param value property value
* @return json array of guids of entities created/updated
*/
- String updateEntityAttributeByGuid(String guid, String attribute, String value) throws AtlasException;
+ AtlasClient.EntityResult updateEntityAttributeByGuid(String guid, String attribute, String value) throws AtlasException;
/**
* Supports Partial updates of an entity. Users can update a subset of attributes for an entity identified by its guid
@@ -146,7 +147,7 @@ public interface MetadataService {
* @return json array of guids of entities created/updated
* @throws AtlasException
*/
- String updateEntityPartialByGuid(String guid, Referenceable entity) throws AtlasException;
+ AtlasClient.EntityResult updateEntityPartialByGuid(String guid, Referenceable entity) throws AtlasException;
/**
* Batch API - Adds/Updates the given entity id(guid).
@@ -154,7 +155,7 @@ public interface MetadataService {
* @param entityJson entity json
* @return json array of guids of entities created/updated
*/
- String updateEntities(String entityJson) throws AtlasException;
+ AtlasClient.EntityResult updateEntities(String entityJson) throws AtlasException;
// Trait management functions
@@ -168,8 +169,9 @@ public interface MetadataService {
* @return Guid of updated entity
* @throws AtlasException
*/
- String updateEntityByUniqueAttribute(String typeName, String uniqueAttributeName, String attrValue,
- Referenceable updatedEntity) throws AtlasException;
+ AtlasClient.EntityResult updateEntityByUniqueAttribute(String typeName, String uniqueAttributeName,
+ String attrValue,
+ Referenceable updatedEntity) throws AtlasException;
/**
* Gets the list of trait names for a given entity represented by a guid.
@@ -207,10 +209,10 @@ public interface MetadataService {
* Delete the specified entities from the repository
*
* @param guids entity guids to be deleted
- * @return List of guids for deleted entities
+ * @return List of guids for deleted entities
* @throws AtlasException
*/
- List<String> deleteEntities(List<String> guids) throws AtlasException;
+ AtlasClient.EntityResult deleteEntities(List<String> guids) throws AtlasException;
/**
* Register a listener for entity change.
@@ -235,7 +237,8 @@ public interface MetadataService {
* @return List of guids for deleted entities (including their composite references)
* @throws AtlasException
*/
- List<String> deleteEntityByUniqueAttribute(String typeName, String uniqueAttributeName, String attrValue) throws AtlasException;
+ AtlasClient.EntityResult deleteEntityByUniqueAttribute(String typeName, String uniqueAttributeName,
+ String attrValue) throws AtlasException;
/**
* Returns entity audit events for entity id in the decreasing order of timestamp
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/typesystem/src/main/java/org/apache/atlas/typesystem/Referenceable.java
----------------------------------------------------------------------
diff --git a/typesystem/src/main/java/org/apache/atlas/typesystem/Referenceable.java b/typesystem/src/main/java/org/apache/atlas/typesystem/Referenceable.java
index 31f157e..5b8e157 100755
--- a/typesystem/src/main/java/org/apache/atlas/typesystem/Referenceable.java
+++ b/typesystem/src/main/java/org/apache/atlas/typesystem/Referenceable.java
@@ -100,7 +100,7 @@ public class Referenceable extends Struct implements IReferenceableInstance {
* @throws AtlasException if the referenceable can not be created
*/
public Referenceable(IReferenceableInstance instance) throws AtlasException {
- this(instance.getId()._getId(), instance.getTypeName(), instance.getValuesMap(), instance.getTraits(),
+ this(instance.getId(), instance.getTypeName(), instance.getValuesMap(), instance.getTraits(),
getTraits(instance));
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/webapp/src/main/java/org/apache/atlas/LocalAtlasClient.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/LocalAtlasClient.java b/webapp/src/main/java/org/apache/atlas/LocalAtlasClient.java
index c6ed85d..7173d4d 100644
--- a/webapp/src/main/java/org/apache/atlas/LocalAtlasClient.java
+++ b/webapp/src/main/java/org/apache/atlas/LocalAtlasClient.java
@@ -83,13 +83,13 @@ public class LocalAtlasClient extends AtlasClient {
}
};
JSONObject response = entityOperation.run();
- List<String> results = extractResults(response, GUID, new ExtractOperation<String, String>());
+ EntityResult results = extractEntityResult(response);
LOG.debug("Create entities returned results: {}", results);
- return results;
+ return results.getCreatedEntities();
}
@Override
- protected List<String> updateEntities(final JSONArray entities) throws AtlasServiceException {
+ protected EntityResult updateEntities(final JSONArray entities) throws AtlasServiceException {
LOG.debug("Updating entities: {}", entities);
EntityOperation entityOperation = new EntityOperation(API.UPDATE_ENTITY) {
@Override
@@ -98,7 +98,7 @@ public class LocalAtlasClient extends AtlasClient {
}
};
JSONObject response = entityOperation.run();
- List<String> results = extractResults(response, GUID, new ExtractOperation<String, String>());
+ EntityResult results = extractEntityResult(response);
LOG.debug("Update entities returned results: {}", results);
return results;
}
@@ -130,7 +130,7 @@ public class LocalAtlasClient extends AtlasClient {
}
@Override
- public String updateEntity(final String entityType, final String uniqueAttributeName,
+ public EntityResult updateEntity(final String entityType, final String uniqueAttributeName,
final String uniqueAttributeValue, Referenceable entity) throws AtlasServiceException {
final String entityJson = InstanceSerialization.toJson(entity, true);
LOG.debug("Updating entity type: {}, attributeName: {}, attributeValue: {}, entity: {}", entityType,
@@ -143,13 +143,13 @@ public class LocalAtlasClient extends AtlasClient {
}
};
JSONObject response = entityOperation.run();
- String result = getString(response, GUID);
+ EntityResult result = extractEntityResult(response);
LOG.debug("Update entity returned result: {}", result);
return result;
}
@Override
- public List<String> deleteEntity(final String entityType, final String uniqueAttributeName,
+ public EntityResult deleteEntity(final String entityType, final String uniqueAttributeName,
final String uniqueAttributeValue) throws AtlasServiceException {
LOG.debug("Deleting entity type: {}, attributeName: {}, attributeValue: {}", entityType, uniqueAttributeName,
uniqueAttributeValue);
@@ -160,7 +160,7 @@ public class LocalAtlasClient extends AtlasClient {
}
};
JSONObject response = entityOperation.run();
- List<String> results = extractResults(response, GUID, new ExtractOperation<String, String>());
+ EntityResult results = extractEntityResult(response);
LOG.debug("Delete entities returned results: {}", results);
return results;
}
@@ -191,18 +191,18 @@ public class LocalAtlasClient extends AtlasClient {
}
@Override
- public void updateEntityAttribute(final String guid, final String attribute, String value) throws AtlasServiceException {
+ public EntityResult updateEntityAttribute(final String guid, final String attribute, String value) throws AtlasServiceException {
throw new IllegalStateException("Not supported in LocalAtlasClient");
}
@Override
- public void updateEntity(String guid, Referenceable entity) throws AtlasServiceException {
+ public EntityResult updateEntity(String guid, Referenceable entity) throws AtlasServiceException {
throw new IllegalStateException("Not supported in LocalAtlasClient");
}
@Override
- public List<String> deleteEntities(final String ... guids) throws AtlasServiceException {
+ public EntityResult deleteEntities(final String ... guids) throws AtlasServiceException {
throw new IllegalStateException("Not supported in LocalAtlasClient");
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/webapp/src/main/java/org/apache/atlas/notification/NotificationEntityChangeListener.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/notification/NotificationEntityChangeListener.java b/webapp/src/main/java/org/apache/atlas/notification/NotificationEntityChangeListener.java
new file mode 100644
index 0000000..d10194d
--- /dev/null
+++ b/webapp/src/main/java/org/apache/atlas/notification/NotificationEntityChangeListener.java
@@ -0,0 +1,161 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.notification;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.inject.Inject;
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.listener.EntityChangeListener;
+import org.apache.atlas.notification.entity.EntityNotification;
+import org.apache.atlas.notification.entity.EntityNotificationImpl;
+import org.apache.atlas.typesystem.IReferenceableInstance;
+import org.apache.atlas.typesystem.IStruct;
+import org.apache.atlas.typesystem.ITypedReferenceableInstance;
+import org.apache.atlas.typesystem.Referenceable;
+import org.apache.atlas.typesystem.Struct;
+import org.apache.atlas.typesystem.types.FieldMapping;
+import org.apache.atlas.typesystem.types.TraitType;
+import org.apache.atlas.typesystem.types.TypeSystem;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Listen to the repository for entity changes and produce entity change notifications.
+ */
+public class NotificationEntityChangeListener implements EntityChangeListener {
+
+ private final NotificationInterface notificationInterface;
+ private final TypeSystem typeSystem;
+
+
+ // ----- Constructors ------------------------------------------------------
+
+ /**
+ * Construct a NotificationEntityChangeListener.
+ *
+ * @param notificationInterface the notification framework interface
+ * @param typeSystem the Atlas type system
+ */
+ @Inject
+ public NotificationEntityChangeListener(NotificationInterface notificationInterface, TypeSystem typeSystem) {
+ this.notificationInterface = notificationInterface;
+ this.typeSystem = typeSystem;
+ }
+
+
+ // ----- EntityChangeListener ----------------------------------------------
+
+ @Override
+ public void onEntitiesAdded(Collection<ITypedReferenceableInstance> entities) throws AtlasException {
+ notifyOfEntityEvent(entities, EntityNotification.OperationType.ENTITY_CREATE);
+ }
+
+ @Override
+ public void onEntitiesUpdated(Collection<ITypedReferenceableInstance> entities) throws AtlasException {
+ notifyOfEntityEvent(entities, EntityNotification.OperationType.ENTITY_UPDATE);
+ }
+
+ @Override
+ public void onTraitAdded(ITypedReferenceableInstance entity, IStruct trait) throws AtlasException {
+ notifyOfEntityEvent(Collections.singleton(entity), EntityNotification.OperationType.TRAIT_ADD);
+ }
+
+ @Override
+ public void onTraitDeleted(ITypedReferenceableInstance entity, String traitName) throws AtlasException {
+ notifyOfEntityEvent(Collections.singleton(entity), EntityNotification.OperationType.TRAIT_DELETE);
+ }
+
+ @Override
+ public void onEntitiesDeleted(Collection<ITypedReferenceableInstance> entities) throws AtlasException {
+ notifyOfEntityEvent(entities, EntityNotification.OperationType.ENTITY_DELETE);
+ }
+
+
+ // ----- helper methods -------------------------------------------------
+
+
+ // ----- helper methods ----------------------------------------------------
+ @VisibleForTesting
+ public static List<IStruct> getAllTraits(IReferenceableInstance entityDefinition,
+ TypeSystem typeSystem) throws AtlasException {
+ List<IStruct> traitInfo = new LinkedList<>();
+ for (String traitName : entityDefinition.getTraits()) {
+ IStruct trait = entityDefinition.getTrait(traitName);
+ String typeName = trait.getTypeName();
+ Map<String, Object> valuesMap = trait.getValuesMap();
+ traitInfo.add(new Struct(typeName, valuesMap));
+ traitInfo.addAll(getSuperTraits(typeName, valuesMap, typeSystem));
+ }
+ return traitInfo;
+ }
+
+ private static List<IStruct> getSuperTraits(
+ String typeName, Map<String, Object> values, TypeSystem typeSystem) throws AtlasException {
+
+ List<IStruct> superTypes = new LinkedList<>();
+
+ TraitType traitDef = typeSystem.getDataType(TraitType.class, typeName);
+ Set<String> superTypeNames = traitDef.getAllSuperTypeNames();
+
+ for (String superTypeName : superTypeNames) {
+ TraitType superTraitDef = typeSystem.getDataType(TraitType.class, superTypeName);
+
+ Map<String, Object> superTypeValues = new HashMap<>();
+
+ FieldMapping fieldMapping = superTraitDef.fieldMapping();
+
+ if (fieldMapping != null) {
+ Set<String> superTypeAttributeNames = fieldMapping.fields.keySet();
+
+ for (String superTypeAttributeName : superTypeAttributeNames) {
+ if (values.containsKey(superTypeAttributeName)) {
+ superTypeValues.put(superTypeAttributeName, values.get(superTypeAttributeName));
+ }
+ }
+ }
+ IStruct superTrait = new Struct(superTypeName, superTypeValues);
+ superTypes.add(superTrait);
+ superTypes.addAll(getSuperTraits(superTypeName, values, typeSystem));
+ }
+
+ return superTypes;
+ }
+
+ // send notification of entity change
+ private void notifyOfEntityEvent(Collection<ITypedReferenceableInstance> entityDefinitions,
+ EntityNotification.OperationType operationType) throws AtlasException {
+ List<EntityNotification> messages = new LinkedList<>();
+
+ for (IReferenceableInstance entityDefinition : entityDefinitions) {
+ Referenceable entity = new Referenceable(entityDefinition);
+
+ EntityNotificationImpl notification =
+ new EntityNotificationImpl(entity, operationType, getAllTraits(entity, typeSystem));
+
+ messages.add(notification);
+ }
+
+ notificationInterface.send(NotificationInterface.NotificationType.ENTITIES, messages);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java b/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
index 709fec5..487270d 100755
--- a/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
+++ b/webapp/src/main/java/org/apache/atlas/web/resources/EntityResource.java
@@ -19,7 +19,6 @@
package org.apache.atlas.web.resources;
import com.google.common.base.Preconditions;
-
import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasException;
import org.apache.atlas.EntityAuditEvent;
@@ -59,9 +58,7 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
-
import java.net.URI;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -119,19 +116,11 @@ public class EntityResource {
LOG.debug("submitting entities {} ", AtlasClient.toString(new JSONArray(entities)));
- final String guids = metadataService.createEntities(entities);
+ final List<String> guids = metadataService.createEntities(entities);
+ JSONObject response = getResponse(new AtlasClient.EntityResult(guids, null, null));
UriBuilder ub = uriInfo.getAbsolutePathBuilder();
- URI locationURI = ub.path(guids).build();
-
- JSONObject response = new JSONObject();
- response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
- JSONArray guidArray = new JSONArray(guids);
- response.put(AtlasClient.GUID, guidArray);
- if (guidArray.length() > 0) {
- response.put(AtlasClient.DEFINITION,
- new JSONObject(metadataService.getEntityDefinition(new JSONArray(guids).getString(0))));
- }
+ URI locationURI = guids.isEmpty() ? null : ub.path(guids.get(0)).build();
return Response.created(locationURI).entity(response).build();
@@ -150,6 +139,18 @@ public class EntityResource {
}
}
+ private JSONObject getResponse(AtlasClient.EntityResult entityResult) throws AtlasException, JSONException {
+ JSONObject response = new JSONObject();
+ response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
+ response.put(AtlasClient.ENTITIES, new JSONObject(entityResult.toString()).get(AtlasClient.ENTITIES));
+ String sampleEntityId = getSample(entityResult);
+ if (sampleEntityId != null) {
+ String entityDefinition = metadataService.getEntityDefinition(sampleEntityId);
+ response.put(AtlasClient.DEFINITION, new JSONObject(entityDefinition));
+ }
+ return response;
+ }
+
/**
* Complete update of a set of entities - the values not specified will be replaced with null/removed
* Adds/Updates given entities identified by its GUID or unique attribute
@@ -163,14 +164,8 @@ public class EntityResource {
final String entities = Servlets.getRequestPayload(request);
LOG.debug("updating entities {} ", AtlasClient.toString(new JSONArray(entities)));
- final String guids = metadataService.updateEntities(entities);
-
- JSONObject response = new JSONObject();
- response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
- JSONArray guidsArray = new JSONArray(guids);
- response.put(AtlasClient.GUID, guidsArray);
- String entityDefinition = metadataService.getEntityDefinition(guidsArray.getString(0));
- response.put(AtlasClient.DEFINITION, new JSONObject(entityDefinition));
+ AtlasClient.EntityResult entityResult = metadataService.updateEntities(entities);
+ JSONObject response = getResponse(entityResult);
return Response.ok(response).build();
} catch(EntityExistsException e) {
LOG.error("Unique constraint violation", e);
@@ -187,6 +182,25 @@ public class EntityResource {
}
}
+ private String getSample(AtlasClient.EntityResult entityResult) {
+ String sample = getSample(entityResult.getCreatedEntities());
+ if (sample == null) {
+ sample = getSample(entityResult.getUpdateEntities());
+ }
+ if (sample == null) {
+ sample = getSample(entityResult.getDeletedEntities());
+ }
+ return sample;
+ }
+
+
+ private String getSample(List<String> list) {
+ if (list != null && list.size() > 0) {
+ return list.get(0);
+ }
+ return null;
+ }
+
/**
* Adds/Updates given entity identified by its unique attribute( entityType, attributeName and value)
* Updates support only partial update of an entity - Adds/updates any new values specified
@@ -214,11 +228,10 @@ public class EntityResource {
Referenceable updatedEntity =
InstanceSerialization.fromJsonReferenceable(entities, true);
- final String guid = metadataService.updateEntityByUniqueAttribute(entityType, attribute, value, updatedEntity);
+ AtlasClient.EntityResult entityResult =
+ metadataService.updateEntityByUniqueAttribute(entityType, attribute, value, updatedEntity);
- JSONObject response = new JSONObject();
- response.put(AtlasClient.REQUEST_ID, Thread.currentThread().getName());
- response.put(AtlasClient.GUID, guid);
+ JSONObject response = getResponse(entityResult);
return Response.ok(response).build();
} catch (ValueConversionException ve) {
LOG.error("Unable to persist entity instance due to a desrialization error ", ve);
@@ -268,10 +281,8 @@ public class EntityResource {
Referenceable updatedEntity =
InstanceSerialization.fromJsonReferenceable(entityJson, true);
- metadataService.updateEntityPartialByGuid(guid, updatedEntity);
-
- JSONObject response = new JSONObject();
- response.put(AtlasClient.REQUEST_ID, Thread.currentThread().getName());
+ AtlasClient.EntityResult entityResult = metadataService.updateEntityPartialByGuid(guid, updatedEntity);
+ JSONObject response = getResponse(entityResult);
return Response.ok(response).build();
} catch (EntityNotFoundException e) {
LOG.error("An entity with GUID={} does not exist", guid, e);
@@ -301,12 +312,8 @@ public class EntityResource {
String value = Servlets.getRequestPayload(request);
Preconditions.checkNotNull(value, "Entity value cannot be null");
- metadataService.updateEntityAttributeByGuid(guid, property, value);
-
- JSONObject response = new JSONObject();
- response.put(AtlasClient.REQUEST_ID, Thread.currentThread().getName());
- response.put(AtlasClient.GUID, guid);
-
+ AtlasClient.EntityResult entityResult = metadataService.updateEntityAttributeByGuid(guid, property, value);
+ JSONObject response = getResponse(entityResult);
return Response.ok(response).build();
} catch (EntityNotFoundException e) {
LOG.error("An entity with GUID={} does not exist", guid, e);
@@ -340,19 +347,13 @@ public class EntityResource {
@QueryParam("value") String value) {
try {
- List<String> deletedGuids = new ArrayList<>();
+ AtlasClient.EntityResult entityResult;
if (guids != null && !guids.isEmpty()) {
- deletedGuids = metadataService.deleteEntities(guids);
+ entityResult = metadataService.deleteEntities(guids);
} else {
- deletedGuids = metadataService.deleteEntityByUniqueAttribute(entityType, attribute, value);
- }
- JSONObject response = new JSONObject();
- response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
- JSONArray guidArray = new JSONArray(deletedGuids.size());
- for (String guid : deletedGuids) {
- guidArray.put(guid);
+ entityResult = metadataService.deleteEntityByUniqueAttribute(entityType, attribute, value);
}
- response.put(AtlasClient.GUID, guidArray);
+ JSONObject response = getResponse(entityResult);
return Response.ok(response).build();
} catch (EntityNotFoundException e) {
if(guids != null || !guids.isEmpty()) {
@@ -386,7 +387,6 @@ public class EntityResource {
JSONObject response = new JSONObject();
response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
- response.put(AtlasClient.GUID, guid);
Response.Status status = Response.Status.NOT_FOUND;
if (entityDefinition != null) {
@@ -518,7 +518,6 @@ public class EntityResource {
JSONObject response = new JSONObject();
response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
- response.put(AtlasClient.GUID, guid);
response.put(AtlasClient.RESULTS, new JSONArray(traitNames));
response.put(AtlasClient.COUNT, traitNames.size());
@@ -555,7 +554,6 @@ public class EntityResource {
JSONObject response = new JSONObject();
response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
- response.put(AtlasClient.GUID, guid);
return Response.created(locationURI).entity(response).build();
} catch (EntityNotFoundException | TypeNotFoundException e) {
@@ -588,7 +586,6 @@ public class EntityResource {
JSONObject response = new JSONObject();
response.put(AtlasClient.REQUEST_ID, Servlets.getRequestId());
- response.put(AtlasClient.GUID, guid);
response.put(TRAIT_NAME, traitName);
return Response.ok(response).build();
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/webapp/src/main/java/org/apache/atlas/web/service/ServiceModule.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/service/ServiceModule.java b/webapp/src/main/java/org/apache/atlas/web/service/ServiceModule.java
index 0f8bcb1..2128b7c 100644
--- a/webapp/src/main/java/org/apache/atlas/web/service/ServiceModule.java
+++ b/webapp/src/main/java/org/apache/atlas/web/service/ServiceModule.java
@@ -23,7 +23,7 @@ import com.google.inject.multibindings.Multibinder;
import org.apache.atlas.kafka.KafkaNotification;
import org.apache.atlas.listener.EntityChangeListener;
import org.apache.atlas.notification.NotificationHookConsumer;
-import org.apache.atlas.notification.entity.NotificationEntityChangeListener;
+import org.apache.atlas.notification.NotificationEntityChangeListener;
import org.apache.atlas.service.Service;
public class ServiceModule extends AbstractModule {
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/webapp/src/test/java/org/apache/atlas/LocalAtlasClientTest.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/atlas/LocalAtlasClientTest.java b/webapp/src/test/java/org/apache/atlas/LocalAtlasClientTest.java
index 7f20652..e774399 100644
--- a/webapp/src/test/java/org/apache/atlas/LocalAtlasClientTest.java
+++ b/webapp/src/test/java/org/apache/atlas/LocalAtlasClientTest.java
@@ -23,7 +23,6 @@ import org.apache.atlas.typesystem.Referenceable;
import org.apache.atlas.web.resources.EntityResource;
import org.apache.atlas.web.service.ServiceState;
import org.apache.commons.lang.RandomStringUtils;
-import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONObject;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -36,6 +35,7 @@ import javax.ws.rs.core.Response;
import java.util.Arrays;
import java.util.List;
+import static org.apache.atlas.AtlasClient.ENTITIES;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Matchers.anyString;
@@ -64,7 +64,8 @@ public class LocalAtlasClientTest {
when(entityResource.submit(any(HttpServletRequest.class))).thenReturn(response);
final String guid = random();
when(response.getEntity()).thenReturn(new JSONObject() {{
- put(AtlasClient.GUID, new JSONArray(Arrays.asList(guid)));
+ put(ENTITIES, new JSONObject(
+ new AtlasClient.EntityResult(Arrays.asList(guid), null, null).toString()).get(ENTITIES));
}});
LocalAtlasClient atlasClient = new LocalAtlasClient(serviceState, entityResource);
@@ -119,12 +120,14 @@ public class LocalAtlasClientTest {
when(entityResource.updateByUniqueAttribute(anyString(), anyString(), anyString(),
any(HttpServletRequest.class))).thenReturn(response);
when(response.getEntity()).thenReturn(new JSONObject() {{
- put(AtlasClient.GUID, guid);
+ put(ENTITIES, new JSONObject(
+ new AtlasClient.EntityResult(null, Arrays.asList(guid), null).toString()).get(ENTITIES));
}});
LocalAtlasClient atlasClient = new LocalAtlasClient(serviceState, entityResource);
- String actualId = atlasClient.updateEntity(random(), random(), random(), new Referenceable(random()));
- assertEquals(actualId, guid);
+ AtlasClient.EntityResult
+ entityResult = atlasClient.updateEntity(random(), random(), random(), new Referenceable(random()));
+ assertEquals(entityResult.getUpdateEntities(), Arrays.asList(guid));
}
@Test
@@ -132,14 +135,14 @@ public class LocalAtlasClientTest {
final String guid = random();
Response response = mock(Response.class);
when(response.getEntity()).thenReturn(new JSONObject() {{
- put(AtlasClient.GUID, new JSONArray(Arrays.asList(guid)));
+ put(ENTITIES, new JSONObject(
+ new AtlasClient.EntityResult(null, null, Arrays.asList(guid)).toString()).get(ENTITIES));
}});
when(entityResource.deleteEntities(anyListOf(String.class), anyString(), anyString(), anyString())).thenReturn(response);
LocalAtlasClient atlasClient = new LocalAtlasClient(serviceState, entityResource);
- List<String> results = atlasClient.deleteEntity(random(), random(), random());
- assertEquals(results.size(), 1);
- assertEquals(results.get(0), guid);
+ AtlasClient.EntityResult entityResult = atlasClient.deleteEntity(random(), random(), random());
+ assertEquals(entityResult.getDeletedEntities(), Arrays.asList(guid));
}
private String random() {
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/webapp/src/test/java/org/apache/atlas/notification/EntityNotificationIT.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/atlas/notification/EntityNotificationIT.java b/webapp/src/test/java/org/apache/atlas/notification/EntityNotificationIT.java
index 6985152..52f5b83 100644
--- a/webapp/src/test/java/org/apache/atlas/notification/EntityNotificationIT.java
+++ b/webapp/src/test/java/org/apache/atlas/notification/EntityNotificationIT.java
@@ -22,7 +22,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.inject.Inject;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
-
import org.apache.atlas.notification.entity.EntityNotification;
import org.apache.atlas.typesystem.IReferenceableInstance;
import org.apache.atlas.typesystem.IStruct;
@@ -43,7 +42,6 @@ import org.testng.annotations.Test;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.Response;
-
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/webapp/src/test/java/org/apache/atlas/notification/NotificationEntityChangeListenerTest.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/atlas/notification/NotificationEntityChangeListenerTest.java b/webapp/src/test/java/org/apache/atlas/notification/NotificationEntityChangeListenerTest.java
new file mode 100644
index 0000000..a988915
--- /dev/null
+++ b/webapp/src/test/java/org/apache/atlas/notification/NotificationEntityChangeListenerTest.java
@@ -0,0 +1,90 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.atlas.notification;
+
+import org.apache.atlas.typesystem.IStruct;
+import org.apache.atlas.typesystem.Referenceable;
+import org.apache.atlas.typesystem.Struct;
+import org.apache.atlas.typesystem.types.TraitType;
+import org.apache.atlas.typesystem.types.TypeSystem;
+import org.testng.annotations.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class NotificationEntityChangeListenerTest {
+ @Test
+ public void testGetAllTraitsSuperTraits() throws Exception {
+
+ TypeSystem typeSystem = mock(TypeSystem.class);
+
+ String traitName = "MyTrait";
+ IStruct myTrait = new Struct(traitName);
+
+ String superTraitName = "MySuperTrait";
+
+ TraitType traitDef = mock(TraitType.class);
+ Set<String> superTypeNames = Collections.singleton(superTraitName);
+
+ TraitType superTraitDef = mock(TraitType.class);
+ Set<String> superSuperTypeNames = Collections.emptySet();
+
+ Referenceable entity = getEntity("id", myTrait);
+
+ when(typeSystem.getDataType(TraitType.class, traitName)).thenReturn(traitDef);
+ when(typeSystem.getDataType(TraitType.class, superTraitName)).thenReturn(superTraitDef);
+
+ when(traitDef.getAllSuperTypeNames()).thenReturn(superTypeNames);
+ when(superTraitDef.getAllSuperTypeNames()).thenReturn(superSuperTypeNames);
+
+ List<IStruct> allTraits = NotificationEntityChangeListener.getAllTraits(entity, typeSystem);
+
+ assertEquals(2, allTraits.size());
+
+ for (IStruct trait : allTraits) {
+ String typeName = trait.getTypeName();
+ assertTrue(typeName.equals(traitName) || typeName.equals(superTraitName));
+ }
+ }
+
+ private Referenceable getEntity(String id, IStruct... traits) {
+ String typeName = "typeName";
+ Map<String, Object> values = new HashMap<>();
+
+ List<String> traitNames = new LinkedList<>();
+ Map<String, IStruct> traitMap = new HashMap<>();
+
+ for (IStruct trait : traits) {
+ String traitName = trait.getTypeName();
+
+ traitNames.add(traitName);
+ traitMap.put(traitName, trait);
+ }
+ return new Referenceable(id, typeName, values, traitNames, traitMap);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java b/webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java
index aa92bc0..36db646 100755
--- a/webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java
+++ b/webapp/src/test/java/org/apache/atlas/web/resources/EntityJerseyResourceIT.java
@@ -71,6 +71,7 @@ import java.util.Map;
import java.util.UUID;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.fail;
@@ -154,7 +155,10 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
JSONObject response = new JSONObject(responseAsString);
Assert.assertNotNull(response.get(AtlasClient.REQUEST_ID));
- Assert.assertNotNull(response.get(AtlasClient.GUID));
+
+ AtlasClient.EntityResult entityResult = AtlasClient.EntityResult.fromString(response.toString());
+ assertEquals(entityResult.getCreatedEntities().size(), 1);
+ assertNotNull(entityResult.getCreatedEntities().get(0));
}
@Test
@@ -376,7 +380,9 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
}
private void addProperty(String guid, String property, String value) throws AtlasServiceException {
- serviceClient.updateEntityAttribute(guid, property, value);
+ AtlasClient.EntityResult entityResult = serviceClient.updateEntityAttribute(guid, property, value);
+ assertEquals(entityResult.getUpdateEntities().size(), 1);
+ assertEquals(entityResult.getUpdateEntities().get(0), guid);
}
private ClientResponse getEntityDefinition(String guid) {
@@ -482,7 +488,6 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
JSONObject response = new JSONObject(responseAsString);
Assert.assertNotNull(response.get(AtlasClient.REQUEST_ID));
- Assert.assertNotNull(response.get("GUID"));
final JSONArray list = response.getJSONArray(AtlasClient.RESULTS);
Assert.assertEquals(list.length(), 7);
@@ -513,7 +518,6 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
JSONObject response = new JSONObject(responseAsString);
Assert.assertNotNull(response.get(AtlasClient.REQUEST_ID));
- Assert.assertNotNull(response.get(AtlasClient.GUID));
assertEntityAudit(guid, EntityAuditEvent.EntityAuditAction.TAG_ADD);
}
@@ -561,7 +565,6 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
JSONObject response = new JSONObject(responseAsString);
Assert.assertNotNull(response.get(AtlasClient.REQUEST_ID));
- Assert.assertNotNull(response.get(AtlasClient.GUID));
// verify the response
clientResponse = getEntityDefinition(guid);
@@ -612,7 +615,6 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
JSONObject response = new JSONObject(responseAsString);
Assert.assertNotNull(response.get(AtlasClient.REQUEST_ID));
- Assert.assertNotNull(response.get("GUID"));
Assert.assertNotNull(response.get("traitName"));
assertEntityAudit(guid, EntityAuditEvent.EntityAuditAction.TAG_DELETE);
}
@@ -635,7 +637,8 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
"trait=" + traitName + " should be defined in type system before it can be deleted");
Assert.assertNotNull(response.get(AtlasClient.STACKTRACE));
}
-@Test(dependsOnMethods = "testSubmitEntity()")
+
+ @Test(dependsOnMethods = "testSubmitEntity()")
public void testDeleteExistentTraitNonExistentForEntity() throws Exception {
final String guid = tableId._getId();
@@ -704,7 +707,9 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
}});
LOG.debug("Updating entity= " + tableUpdated);
- serviceClient.updateEntity(tableId._getId(), tableUpdated);
+ AtlasClient.EntityResult entityResult = serviceClient.updateEntity(tableId._getId(), tableUpdated);
+ assertEquals(entityResult.getUpdateEntities().size(), 1);
+ assertEquals(entityResult.getUpdateEntities().get(0), tableId._getId());
ClientResponse response = getEntityDefinition(tableId._getId());
String definition = getEntityDefinition(response);
@@ -722,8 +727,10 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
}});
LOG.debug("Updating entity= " + tableUpdated);
- serviceClient.updateEntity(BaseResourceIT.HIVE_TABLE_TYPE, "name", (String) tableInstance.get("name"),
- tableUpdated);
+ entityResult = serviceClient.updateEntity(BaseResourceIT.HIVE_TABLE_TYPE, "name",
+ (String) tableInstance.get("name"), tableUpdated);
+ assertEquals(entityResult.getUpdateEntities().size(), 1);
+ assertEquals(entityResult.getUpdateEntities().get(0), tableId._getId());
response = getEntityDefinition(tableId._getId());
definition = getEntityDefinition(response);
@@ -732,7 +739,6 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
Assert.assertTrue(refs.get(0).equalsContents(columns.get(0)));
Assert.assertEquals(refs.get(0).get("dataType"), "int");
-
}
@Test(dependsOnMethods = "testSubmitEntity")
@@ -765,9 +771,8 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
// ATLAS-586: verify response entity can be parsed by GSON.
String entity = clientResponse.getEntity(String.class);
Gson gson = new Gson();
- UpdateEntitiesResponse updateEntitiesResponse = null;
try {
- updateEntitiesResponse = gson.fromJson(entity, UpdateEntitiesResponse.class);
+ UpdateEntitiesResponse updateEntitiesResponse = gson.fromJson(entity, UpdateEntitiesResponse.class);
}
catch (JsonSyntaxException e) {
Assert.fail("Response entity from " + service.path(ENTITIES).getURI() + " not parseable by GSON", e);
@@ -785,7 +790,7 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
private static class UpdateEntitiesResponse {
String requestId;
- String[] GUID;
+ AtlasClient.EntityResult entities;
AtlasEntity definition;
}
@@ -811,15 +816,9 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
queryParam(AtlasClient.GUID.toLowerCase(), db1Id._getId()).
queryParam(AtlasClient.GUID.toLowerCase(), db2Id._getId()).
accept(Servlets.JSON_MEDIA_TYPE).type(Servlets.JSON_MEDIA_TYPE).method(HttpMethod.DELETE, ClientResponse.class);
+
JSONObject response = getEntity(clientResponse);
- final String deletedGuidsJson = response.getString(AtlasClient.GUID);
- Assert.assertNotNull(deletedGuidsJson);
- JSONArray guidsArray = new JSONArray(deletedGuidsJson);
- Assert.assertEquals(guidsArray.length(), 2);
- List<String> deletedGuidsList = new ArrayList<>(2);
- for (int index = 0; index < guidsArray.length(); index++) {
- deletedGuidsList.add(guidsArray.getString(index));
- }
+ List<String> deletedGuidsList = AtlasClient.EntityResult.fromString(response.toString()).getDeletedEntities();
Assert.assertTrue(deletedGuidsList.contains(db1Id._getId()));
Assert.assertTrue(deletedGuidsList.contains(db2Id._getId()));
@@ -843,7 +842,8 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
Id db2Id = createInstance(db2);
// Delete the database entities
- List<String> deletedGuidsList = serviceClient.deleteEntities(db1Id._getId(), db2Id._getId());
+ List<String> deletedGuidsList =
+ serviceClient.deleteEntities(db1Id._getId(), db2Id._getId()).getDeletedEntities();
// Verify that deleteEntities() response has database entity guids
Assert.assertEquals(deletedGuidsList.size(), 2);
@@ -867,7 +867,7 @@ public class EntityJerseyResourceIT extends BaseResourceIT {
Id db1Id = createInstance(db1);
// Delete the database entity
- List<String> deletedGuidsList = serviceClient.deleteEntity(DATABASE_TYPE, "name", dbName);
+ List<String> deletedGuidsList = serviceClient.deleteEntity(DATABASE_TYPE, "name", dbName).getDeletedEntities();
// Verify that deleteEntities() response has database entity guids
Assert.assertEquals(deletedGuidsList.size(), 1);
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/webapp/src/test/java/org/apache/atlas/web/service/CuratorFactoryTest.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/atlas/web/service/CuratorFactoryTest.java b/webapp/src/test/java/org/apache/atlas/web/service/CuratorFactoryTest.java
index 2d510a0..0e48509 100644
--- a/webapp/src/test/java/org/apache/atlas/web/service/CuratorFactoryTest.java
+++ b/webapp/src/test/java/org/apache/atlas/web/service/CuratorFactoryTest.java
@@ -23,21 +23,16 @@ import org.apache.atlas.ha.HAConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.ACLProvider;
-import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.ACL;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
-import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
-import static junit.framework.TestCase.assertEquals;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
[2/3] incubator-atlas git commit: ATLAS-716 Entity update/delete
notifications (shwethags)
Posted by sh...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/graph/GraphToTypedInstanceMapper.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/GraphToTypedInstanceMapper.java b/repository/src/main/java/org/apache/atlas/repository/graph/GraphToTypedInstanceMapper.java
index df28ab3..e240fb6 100644
--- a/repository/src/main/java/org/apache/atlas/repository/graph/GraphToTypedInstanceMapper.java
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/GraphToTypedInstanceMapper.java
@@ -68,9 +68,9 @@ public final class GraphToTypedInstanceMapper {
LOG.debug("Mapping graph root vertex {} to typed instance for guid {}", instanceVertex, guid);
String typeName = instanceVertex.getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY);
List<String> traits = GraphHelper.getTraitNames(instanceVertex);
+ String state = GraphHelper.getStateAsString(instanceVertex);
- Id id = new Id(guid, instanceVertex.<Integer>getProperty(Constants.VERSION_PROPERTY_KEY), typeName,
- instanceVertex.<String>getProperty(Constants.STATE_PROPERTY_KEY));
+ Id id = new Id(guid, instanceVertex.<Integer>getProperty(Constants.VERSION_PROPERTY_KEY), typeName, state);
LOG.debug("Created id {} for instance type {}", id, typeName);
ClassType classType = typeSystem.getDataType(ClassType.class, typeName);
@@ -161,9 +161,9 @@ public final class GraphToTypedInstanceMapper {
Edge edge;
if (edgeId == null) {
- edge = GraphHelper.getEdgeForLabel(instanceVertex, relationshipLabel);;
+ edge = GraphHelper.getEdgeForLabel(instanceVertex, relationshipLabel);
} else {
- edge = graphHelper.getEdgeById(edgeId);
+ edge = graphHelper.getEdgeByEdgeId(instanceVertex, relationshipLabel, edgeId);
}
if (edge != null) {
@@ -175,9 +175,10 @@ public final class GraphToTypedInstanceMapper {
LOG.debug("Found composite, mapping vertex to instance");
return mapGraphToTypedInstance(guid, referenceVertex);
} else {
+ String state = GraphHelper.getStateAsString(referenceVertex);
Id referenceId =
new Id(guid, referenceVertex.<Integer>getProperty(Constants.VERSION_PROPERTY_KEY),
- dataType.getName());
+ dataType.getName(), state);
LOG.debug("Found non-composite, adding id {} ", referenceId);
return referenceId;
}
@@ -271,7 +272,7 @@ public final class GraphToTypedInstanceMapper {
if (edgeId == null) {
edge = GraphHelper.getEdgeForLabel(instanceVertex, relationshipLabel);
} else {
- edge = graphHelper.getEdgeById(edgeId);
+ edge = graphHelper.getEdgeByEdgeId(instanceVertex, relationshipLabel, edgeId);
}
if (edge != null) {
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/graph/HardDeleteHandler.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/HardDeleteHandler.java b/repository/src/main/java/org/apache/atlas/repository/graph/HardDeleteHandler.java
index f8bbf73..3636791 100644
--- a/repository/src/main/java/org/apache/atlas/repository/graph/HardDeleteHandler.java
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/HardDeleteHandler.java
@@ -26,20 +26,18 @@ import org.apache.atlas.typesystem.types.TypeSystem;
public class HardDeleteHandler extends DeleteHandler {
- private static final GraphHelper graphHelper = GraphHelper.getInstance();
-
@Inject
public HardDeleteHandler(TypeSystem typeSystem) {
- super(typeSystem, true);
+ super(typeSystem, true, false);
}
@Override
- protected void _deleteVertex(Vertex instanceVertex) {
+ protected void _deleteVertex(Vertex instanceVertex, boolean force) {
graphHelper.removeVertex(instanceVertex);
}
@Override
- protected void deleteEdge(Edge edge) throws AtlasException {
+ protected void deleteEdge(Edge edge, boolean force) throws AtlasException {
graphHelper.removeEdge(edge);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/graph/SoftDeleteHandler.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/SoftDeleteHandler.java b/repository/src/main/java/org/apache/atlas/repository/graph/SoftDeleteHandler.java
index aa78582..25aa7c5 100644
--- a/repository/src/main/java/org/apache/atlas/repository/graph/SoftDeleteHandler.java
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/SoftDeleteHandler.java
@@ -32,24 +32,34 @@ import static org.apache.atlas.repository.Constants.STATE_PROPERTY_KEY;
public class SoftDeleteHandler extends DeleteHandler {
@Inject
public SoftDeleteHandler(TypeSystem typeSystem) {
- super(typeSystem, false);
+ super(typeSystem, false, true);
}
@Override
- protected void _deleteVertex(Vertex instanceVertex) {
- Id.EntityState state = Id.EntityState.valueOf((String) instanceVertex.getProperty(STATE_PROPERTY_KEY));
- if (state != Id.EntityState.DELETED) {
- GraphHelper.setProperty(instanceVertex, STATE_PROPERTY_KEY, Id.EntityState.DELETED.name());
- GraphHelper.setProperty(instanceVertex, MODIFICATION_TIMESTAMP_PROPERTY_KEY, RequestContext.get().getRequestTime());
+ protected void _deleteVertex(Vertex instanceVertex, boolean force) {
+ if (force) {
+ graphHelper.removeVertex(instanceVertex);
+ } else {
+ Id.EntityState state = GraphHelper.getState(instanceVertex);
+ if (state != Id.EntityState.DELETED) {
+ GraphHelper.setProperty(instanceVertex, STATE_PROPERTY_KEY, Id.EntityState.DELETED.name());
+ GraphHelper.setProperty(instanceVertex, MODIFICATION_TIMESTAMP_PROPERTY_KEY,
+ RequestContext.get().getRequestTime());
+ }
}
}
@Override
- protected void deleteEdge(Edge edge) throws AtlasException {
- Id.EntityState state = Id.EntityState.valueOf((String) edge.getProperty(STATE_PROPERTY_KEY));
- if (state != Id.EntityState.DELETED) {
- GraphHelper.setProperty(edge, STATE_PROPERTY_KEY, Id.EntityState.DELETED.name());
- GraphHelper.setProperty(edge, MODIFICATION_TIMESTAMP_PROPERTY_KEY, RequestContext.get().getRequestTime());
+ protected void deleteEdge(Edge edge, boolean force) throws AtlasException {
+ if (force) {
+ graphHelper.removeEdge(edge);
+ } else {
+ Id.EntityState state = GraphHelper.getState(edge);
+ if (state != Id.EntityState.DELETED) {
+ GraphHelper.setProperty(edge, STATE_PROPERTY_KEY, Id.EntityState.DELETED.name());
+ GraphHelper
+ .setProperty(edge, MODIFICATION_TIMESTAMP_PROPERTY_KEY, RequestContext.get().getRequestTime());
+ }
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/graph/TypedInstanceToGraphMapper.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/TypedInstanceToGraphMapper.java b/repository/src/main/java/org/apache/atlas/repository/graph/TypedInstanceToGraphMapper.java
index a017536..4c1f559 100644
--- a/repository/src/main/java/org/apache/atlas/repository/graph/TypedInstanceToGraphMapper.java
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/TypedInstanceToGraphMapper.java
@@ -101,15 +101,15 @@ public final class TypedInstanceToGraphMapper {
case CREATE:
List<String> ids = addOrUpdateAttributesAndTraits(operation, entitiesToCreate);
addFullTextProperty(entitiesToCreate, fulltextMapper);
- requestContext.recordCreatedEntities(ids);
+ requestContext.recordEntityCreate(ids);
break;
case UPDATE_FULL:
case UPDATE_PARTIAL:
ids = addOrUpdateAttributesAndTraits(Operation.CREATE, entitiesToCreate);
- requestContext.recordCreatedEntities(ids);
+ requestContext.recordEntityCreate(ids);
ids = addOrUpdateAttributesAndTraits(operation, entitiesToUpdate);
- requestContext.recordUpdatedEntities(ids);
+ requestContext.recordEntityUpdate(ids);
addFullTextProperty(entitiesToCreate, fulltextMapper);
addFullTextProperty(entitiesToUpdate, fulltextMapper);
@@ -218,8 +218,8 @@ public final class TypedInstanceToGraphMapper {
attrValue, currentEdge, edgeLabel, operation);
if (currentEdge != null && !currentEdge.getId().toString().equals(newEdgeId)) {
- deleteHandler.deleteReference(currentEdge, attributeInfo.dataType().getTypeCategory(),
- attributeInfo.isComposite);
+ deleteHandler.deleteEdgeReference(currentEdge, attributeInfo.dataType().getTypeCategory(),
+ attributeInfo.isComposite, true);
}
break;
@@ -326,7 +326,7 @@ public final class TypedInstanceToGraphMapper {
String propertyName = GraphHelper.getQualifiedFieldName(typedInstance, attributeInfo);
List<String> currentElements = instanceVertex.getProperty(propertyName);
IDataType elementType = ((DataTypes.ArrayType) attributeInfo.dataType()).getElemType();
- List<String> newElementsCreated = new ArrayList<>();
+ List<Object> newElementsCreated = new ArrayList<>();
if (!newAttributeEmpty) {
if (newElements != null && !newElements.isEmpty()) {
@@ -336,75 +336,53 @@ public final class TypedInstanceToGraphMapper {
currentElements.get(index) : null;
LOG.debug("Adding/updating element at position {}, current element {}, new element {}", index,
currentElement, newElements.get(index));
- String newEntry = addOrUpdateCollectionEntry(instanceVertex, attributeInfo, elementType,
+ Object newEntry = addOrUpdateCollectionEntry(instanceVertex, attributeInfo, elementType,
newElements.get(index), currentElement, propertyName, operation);
newElementsCreated.add(newEntry);
}
}
}
+ List<String> additionalEdges = removeUnusedEntries(instanceVertex, propertyName, currentElements,
+ newElementsCreated, elementType, attributeInfo);
+ newElementsCreated.addAll(additionalEdges);
+
// for dereference on way out
GraphHelper.setProperty(instanceVertex, propertyName, newElementsCreated);
-
- removeUnusedEntries(currentElements, newElementsCreated, elementType, attributeInfo);
}
- private void removeUnusedEntries(List<String> currentEntries, List<String> newEntries, IDataType entryType,
- AttributeInfo attributeInfo) throws AtlasException {
- if (currentEntries == null || currentEntries.isEmpty()) {
- return;
- }
-
- LOG.debug("Removing unused entries from the old collection");
- if (entryType.getTypeCategory() == DataTypes.TypeCategory.STRUCT
- || entryType.getTypeCategory() == DataTypes.TypeCategory.CLASS) {
-
- //Get map of edge id to edge
- Map<String, Edge> edgeMap = new HashMap<>();
- getEdges(currentEntries, edgeMap);
- getEdges(newEntries, edgeMap);
-
- //Get final set of in vertices
- Set<String> newInVertices = new HashSet<>();
- for (String edgeId : newEntries) {
- Vertex inVertex = edgeMap.get(edgeId).getVertex(Direction.IN);
- newInVertices.add(inVertex.getId().toString());
- }
-
- //Remove the edges for (current edges - new edges)
- List<String> cloneElements = new ArrayList<>(currentEntries);
- cloneElements.removeAll(newEntries);
- LOG.debug("Removing unused entries from the old collection - {}", cloneElements);
-
- if (!cloneElements.isEmpty()) {
- for (String edgeIdForDelete : cloneElements) {
- Edge edge = edgeMap.get(edgeIdForDelete);
- Vertex inVertex = edge.getVertex(Direction.IN);
- if (newInVertices.contains(inVertex.getId().toString())) {
- //If the edge.inVertex is in the new set of in vertices, just delete the edge
- deleteHandler.deleteEdge(edge, true);
- } else {
- //else delete the edge + vertex
- deleteHandler.deleteReference(edge, entryType.getTypeCategory(), attributeInfo.isComposite);
+ //Removes unused edges from the old collection, compared to the new collection
+ private List<String> removeUnusedEntries(Vertex instanceVertex, String edgeLabel,
+ Collection<String> currentEntries,
+ Collection<Object> newEntries,
+ IDataType entryType, AttributeInfo attributeInfo) throws AtlasException {
+ if (currentEntries != null && !currentEntries.isEmpty()) {
+ LOG.debug("Removing unused entries from the old collection");
+ if (entryType.getTypeCategory() == DataTypes.TypeCategory.STRUCT
+ || entryType.getTypeCategory() == DataTypes.TypeCategory.CLASS) {
+
+ //Remove the edges for (current edges - new edges)
+ List<String> cloneElements = new ArrayList<>(currentEntries);
+ cloneElements.removeAll(newEntries);
+ List<String> additionalElements = new ArrayList<>();
+ LOG.debug("Removing unused entries from the old collection - {}", cloneElements);
+
+ if (!cloneElements.isEmpty()) {
+ for (String edgeIdForDelete : cloneElements) {
+ Edge edge = graphHelper.getEdgeByEdgeId(instanceVertex, edgeLabel, edgeIdForDelete);
+ boolean deleted = deleteHandler.deleteEdgeReference(edge, entryType.getTypeCategory(),
+ attributeInfo.isComposite, true);
+ if (!deleted) {
+ additionalElements.add(edgeIdForDelete);
+ }
}
}
+ return additionalElements;
}
}
+ return new ArrayList<>();
}
- private void getEdges(List<String> edgeIds, Map<String, Edge> edgeMap) {
- if (edgeIds == null) {
- return;
- }
-
- for (String edgeId : edgeIds) {
- if (!edgeMap.containsKey(edgeId)) {
- edgeMap.put(edgeId, graphHelper.getEdgeById(edgeId));
- }
- }
- }
-
-
/******************************************** MAP **************************************************/
private void mapMapCollectionToVertex(ITypedInstance typedInstance, Vertex instanceVertex,
@@ -421,38 +399,81 @@ public final class TypedInstanceToGraphMapper {
IDataType elementType = ((DataTypes.MapType) attributeInfo.dataType()).getValueType();
String propertyName = GraphHelper.getQualifiedFieldName(typedInstance, attributeInfo);
- List<String> currentElements = new ArrayList<>();
- List<String> newElementsCreated = new ArrayList<>();
- List<String> newKeysCreated = new ArrayList<>();
+
+ Map<String, String> currentMap = new HashMap<>();
+ Map<String, Object> newMap = new HashMap<>();
+
+ List<String> currentKeys = instanceVertex.getProperty(propertyName);
+ if (currentKeys != null && !currentKeys.isEmpty()) {
+ for (String key : currentKeys) {
+ String propertyNameForKey = GraphHelper.getQualifiedNameForMapKey(propertyName, key);
+ String propertyValueForKey = instanceVertex.getProperty(propertyNameForKey).toString();
+ currentMap.put(key, propertyValueForKey);
+ }
+ }
if (!newAttributeEmpty) {
for (Map.Entry entry : newAttribute.entrySet()) {
- String propertyNameForKey = GraphHelper.getQualifiedNameForMapKey(propertyName, entry.getKey().toString());
- newKeysCreated.add(entry.getKey().toString());
+ String keyStr = entry.getKey().toString();
+ String propertyNameForKey = GraphHelper.getQualifiedNameForMapKey(propertyName, keyStr);
- String currentEntry = instanceVertex.getProperty(propertyNameForKey);
- if (currentEntry != null) {
- currentElements.add(currentEntry);
- }
-
- String newEntry = addOrUpdateCollectionEntry(instanceVertex, attributeInfo, elementType,
- entry.getValue(), currentEntry, propertyNameForKey, operation);
+ Object newEntry = addOrUpdateCollectionEntry(instanceVertex, attributeInfo, elementType,
+ entry.getValue(), currentMap.get(keyStr), propertyNameForKey, operation);
//Add/Update/Remove property value
GraphHelper.setProperty(instanceVertex, propertyNameForKey, newEntry);
- newElementsCreated.add(newEntry);
+ newMap.put(keyStr, newEntry);
}
}
+ Map<String, String> additionalMap =
+ removeUnusedMapEntries(instanceVertex, propertyName, currentMap, newMap, elementType, attributeInfo);
+
+ Set<String> newKeys = new HashSet<>(newMap.keySet());
+ newKeys.addAll(additionalMap.keySet());
+
// for dereference on way out
- GraphHelper.setProperty(instanceVertex, propertyName, newKeysCreated);
+ GraphHelper.setProperty(instanceVertex, propertyName, new ArrayList<>(newKeys));
+ }
+
+ //Remove unused entries from map
+ private Map<String, String> removeUnusedMapEntries(Vertex instanceVertex, String propertyName,
+ Map<String, String> currentMap,
+ Map<String, Object> newMap, IDataType elementType,
+ AttributeInfo attributeInfo)
+ throws AtlasException {
+ boolean reference = (elementType.getTypeCategory() == DataTypes.TypeCategory.STRUCT
+ || elementType.getTypeCategory() == DataTypes.TypeCategory.CLASS);
+ Map<String, String> additionalMap = new HashMap<>();
+
+ for (String currentKey : currentMap.keySet()) {
+ boolean shouldDeleteKey = !newMap.containsKey(currentKey);
+ if (reference) {
+ String currentEdge = currentMap.get(currentKey);
+ //Delete the edge reference if its not part of new edges created/updated
+ if (!newMap.values().contains(currentEdge)) {
+ String edgeLabel = GraphHelper.getQualifiedNameForMapKey(propertyName, currentKey);
+ Edge edge = graphHelper.getEdgeByEdgeId(instanceVertex, edgeLabel, currentMap.get(currentKey));
+ boolean deleted =
+ deleteHandler.deleteEdgeReference(edge, elementType.getTypeCategory(), attributeInfo.isComposite, true);
+ if (!deleted) {
+ additionalMap.put(currentKey, currentEdge);
+ shouldDeleteKey = false;
+ }
+ }
+ }
- removeUnusedEntries(currentElements, newElementsCreated, elementType, attributeInfo);
+ if (shouldDeleteKey) {
+ String propertyNameForKey = GraphHelper.getQualifiedNameForMapKey(propertyName, currentKey);
+ graphHelper.setProperty(instanceVertex, propertyNameForKey, null);
+ }
+ }
+ return additionalMap;
}
/******************************************** ARRAY & MAP **************************************************/
- private String addOrUpdateCollectionEntry(Vertex instanceVertex, AttributeInfo attributeInfo,
+ private Object addOrUpdateCollectionEntry(Vertex instanceVertex, AttributeInfo attributeInfo,
IDataType elementType, Object newAttributeValue, String currentValue,
String propertyName, Operation operation)
throws AtlasException {
@@ -460,7 +481,7 @@ public final class TypedInstanceToGraphMapper {
switch (elementType.getTypeCategory()) {
case PRIMITIVE:
case ENUM:
- return newAttributeValue != null ? newAttributeValue.toString() : null;
+ return newAttributeValue != null ? newAttributeValue : null;
case ARRAY:
case MAP:
@@ -471,7 +492,7 @@ public final class TypedInstanceToGraphMapper {
case STRUCT:
case CLASS:
final String edgeLabel = GraphHelper.EDGE_LABEL_PREFIX + propertyName;
- Edge currentEdge = graphHelper.getEdgeById(currentValue);
+ Edge currentEdge = graphHelper.getEdgeByEdgeId(instanceVertex, edgeLabel, currentValue);
return addOrUpdateReference(instanceVertex, attributeInfo, elementType, newAttributeValue, currentEdge,
edgeLabel, operation);
@@ -526,7 +547,7 @@ public final class TypedInstanceToGraphMapper {
mapInstanceToVertex(structInstance, structInstanceVertex, structInstance.fieldMapping().fields, false,
Operation.CREATE);
// add an edge to the newly created vertex from the parent
- Edge newEdge = graphHelper.addEdge(instanceVertex, structInstanceVertex, edgeLabel);
+ Edge newEdge = graphHelper.getOrCreateEdge(instanceVertex, structInstanceVertex, edgeLabel);
return newEdge;
}
@@ -575,7 +596,7 @@ public final class TypedInstanceToGraphMapper {
private Edge addClassEdge(Vertex instanceVertex, Vertex toVertex, String edgeLabel) throws AtlasException {
// add an edge to the class vertex from the instance
- return graphHelper.addEdge(instanceVertex, toVertex, edgeLabel);
+ return graphHelper.getOrCreateEdge(instanceVertex, toVertex, edgeLabel);
}
private Vertex getClassVertex(ITypedReferenceableInstance typedReference) throws EntityNotFoundException {
@@ -644,7 +665,7 @@ public final class TypedInstanceToGraphMapper {
// add an edge to the newly created vertex from the parent
String relationshipLabel = GraphHelper.getTraitLabel(entityType.getName(), traitName);
- graphHelper.addEdge(parentInstanceVertex, traitInstanceVertex, relationshipLabel);
+ graphHelper.getOrCreateEdge(parentInstanceVertex, traitInstanceVertex, relationshipLabel);
}
/******************************************** PRIMITIVES **************************************************/
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/typestore/GraphBackedTypeStore.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/typestore/GraphBackedTypeStore.java b/repository/src/main/java/org/apache/atlas/repository/typestore/GraphBackedTypeStore.java
index 3fb128c..5ed9e02 100755
--- a/repository/src/main/java/org/apache/atlas/repository/typestore/GraphBackedTypeStore.java
+++ b/repository/src/main/java/org/apache/atlas/repository/typestore/GraphBackedTypeStore.java
@@ -69,6 +69,8 @@ public class GraphBackedTypeStore implements ITypeStore {
private final TitanGraph titanGraph;
+ private GraphHelper graphHelper = GraphHelper.getInstance();
+
@Inject
public GraphBackedTypeStore(GraphProvider<TitanGraph> graphProvider) {
titanGraph = graphProvider.get();
@@ -155,7 +157,7 @@ public class GraphBackedTypeStore implements ITypeStore {
for (String superTypeName : superTypes) {
HierarchicalType superType = typeSystem.getDataType(HierarchicalType.class, superTypeName);
Vertex superVertex = createVertex(superType.getTypeCategory(), superTypeName, superType.getDescription());
- addEdge(vertex, superVertex, SUPERTYPE_EDGE_LABEL);
+ graphHelper.getOrCreateEdge(vertex, superVertex, SUPERTYPE_EDGE_LABEL);
}
}
}
@@ -200,26 +202,11 @@ public class GraphBackedTypeStore implements ITypeStore {
if (!coreTypes.contains(attrType.getName())) {
Vertex attrVertex = createVertex(attrType.getTypeCategory(), attrType.getName(), attrType.getDescription());
String label = getEdgeLabel(vertexTypeName, attribute.name);
- addEdge(vertex, attrVertex, label);
+ graphHelper.getOrCreateEdge(vertex, attrVertex, label);
}
}
}
- private void addEdge(Vertex fromVertex, Vertex toVertex, String label) {
- Iterator<Edge> edges = GraphHelper.getOutGoingEdgesByLabel(fromVertex, label);
- // ATLAS-474: Check if this type system edge already exists, to avoid duplicates.
- while (edges.hasNext()) {
- Edge edge = edges.next();
- if (edge.getVertex(Direction.IN).equals(toVertex)) {
- LOG.debug("Edge from {} to {} with label {} already exists",
- toString(fromVertex), toString(toVertex), label);
- return;
- }
- }
- LOG.debug("Adding edge from {} to {} with label {}", toString(fromVertex), toString(toVertex), label);
- titanGraph.addEdge(null, fromVertex, toVertex, label);
- }
-
@Override
@GraphTransaction
public TypesDef restore() throws AtlasException {
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java b/repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java
index 7cd83f8..c1af0f6 100755
--- a/repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java
+++ b/repository/src/main/java/org/apache/atlas/services/DefaultMetadataService.java
@@ -26,6 +26,7 @@ import org.apache.atlas.ApplicationProperties;
import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasException;
import org.apache.atlas.EntityAuditEvent;
+import org.apache.atlas.RequestContext;
import org.apache.atlas.classification.InterfaceAudience;
import org.apache.atlas.ha.HAConfiguration;
import org.apache.atlas.listener.ActiveStateChangeHandler;
@@ -58,8 +59,6 @@ import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeSystem;
-import org.apache.atlas.typesystem.types.TypeUtils;
-import org.apache.atlas.typesystem.types.TypeUtils.Pair;
import org.apache.atlas.typesystem.types.ValueConversionException;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.apache.atlas.utils.ParamChecker;
@@ -305,16 +304,15 @@ public class DefaultMetadataService implements MetadataService, ActiveStateChang
* Creates an entity, instance of the type.
*
* @param entityInstanceDefinition json array of entity definitions
- * @return guids - json array of guids
+ * @return guids - list of guids
*/
@Override
- public String createEntities(String entityInstanceDefinition) throws AtlasException {
+ public List<String> createEntities(String entityInstanceDefinition) throws AtlasException {
ParamChecker.notEmpty(entityInstanceDefinition, "Entity instance definition");
ITypedReferenceableInstance[] typedInstances = deserializeClassInstances(entityInstanceDefinition);
- List<String> guids = createEntities(typedInstances);
- return new JSONArray(guids).toString();
+ return createEntities(typedInstances);
}
public List<String> createEntities(ITypedReferenceableInstance[] typedInstances) throws AtlasException {
@@ -422,25 +420,26 @@ public class DefaultMetadataService implements MetadataService, ActiveStateChang
* @return guids - json array of guids
*/
@Override
- public String updateEntities(String entityInstanceDefinition) throws AtlasException {
+ public AtlasClient.EntityResult updateEntities(String entityInstanceDefinition) throws AtlasException {
ParamChecker.notEmpty(entityInstanceDefinition, "Entity instance definition");
ITypedReferenceableInstance[] typedInstances = deserializeClassInstances(entityInstanceDefinition);
- TypeUtils.Pair<List<String>, List<String>> guids = repository.updateEntities(typedInstances);
- return onEntitiesAddedUpdated(guids);
+ AtlasClient.EntityResult entityResult = repository.updateEntities(typedInstances);
+ onEntitiesAddedUpdated(entityResult);
+ return entityResult;
}
- private String onEntitiesAddedUpdated(TypeUtils.Pair<List<String>, List<String>> guids) throws AtlasException {
- onEntitiesAdded(guids.left);
- onEntitiesUpdated(guids.right);
-
- guids.left.addAll(guids.right);
- return new JSONArray(guids.left).toString();
+ private void onEntitiesAddedUpdated(AtlasClient.EntityResult entityResult) throws AtlasException {
+ onEntitiesAdded(entityResult.getCreatedEntities());
+ onEntitiesUpdated(entityResult.getUpdateEntities());
+ //Note: doesn't access deletedEntities from entityResult
+ onEntitiesDeleted(RequestContext.get().getDeletedEntities());
}
@Override
- public String updateEntityAttributeByGuid(final String guid, String attributeName, String value) throws AtlasException {
+ public AtlasClient.EntityResult updateEntityAttributeByGuid(final String guid, String attributeName,
+ String value) throws AtlasException {
ParamChecker.notEmpty(guid, "entity id");
ParamChecker.notEmpty(attributeName, "attribute name");
ParamChecker.notEmpty(value, "attribute value");
@@ -469,8 +468,9 @@ public class DefaultMetadataService implements MetadataService, ActiveStateChang
}
((ReferenceableInstance)newInstance).replaceWithNewId(new Id(guid, 0, newInstance.getTypeName()));
- TypeUtils.Pair<List<String>, List<String>> guids = repository.updatePartial(newInstance);
- return onEntitiesAddedUpdated(guids);
+ AtlasClient.EntityResult entityResult = repository.updatePartial(newInstance);
+ onEntitiesAddedUpdated(entityResult);
+ return entityResult;
}
private ITypedReferenceableInstance validateEntityExists(String guid)
@@ -483,7 +483,8 @@ public class DefaultMetadataService implements MetadataService, ActiveStateChang
}
@Override
- public String updateEntityPartialByGuid(final String guid, Referenceable newEntity) throws AtlasException {
+ public AtlasClient.EntityResult updateEntityPartialByGuid(final String guid, Referenceable newEntity)
+ throws AtlasException {
ParamChecker.notEmpty(guid, "guid cannot be null");
ParamChecker.notNull(newEntity, "updatedEntity cannot be null");
ITypedReferenceableInstance existInstance = validateEntityExists(guid);
@@ -491,11 +492,13 @@ public class DefaultMetadataService implements MetadataService, ActiveStateChang
ITypedReferenceableInstance newInstance = convertToTypedInstance(newEntity, existInstance.getTypeName());
((ReferenceableInstance)newInstance).replaceWithNewId(new Id(guid, 0, newInstance.getTypeName()));
- TypeUtils.Pair<List<String>, List<String>> guids = repository.updatePartial(newInstance);
- return onEntitiesAddedUpdated(guids);
+ AtlasClient.EntityResult entityResult = repository.updatePartial(newInstance);
+ onEntitiesAddedUpdated(entityResult);
+ return entityResult;
}
- private ITypedReferenceableInstance convertToTypedInstance(Referenceable updatedEntity, String typeName) throws AtlasException {
+ private ITypedReferenceableInstance convertToTypedInstance(Referenceable updatedEntity, String typeName)
+ throws AtlasException {
ClassType type = typeSystem.getDataType(ClassType.class, typeName);
ITypedReferenceableInstance newInstance = type.createInstance();
@@ -538,8 +541,9 @@ public class DefaultMetadataService implements MetadataService, ActiveStateChang
}
@Override
- public String updateEntityByUniqueAttribute(String typeName, String uniqueAttributeName, String attrValue,
- Referenceable updatedEntity) throws AtlasException {
+ public AtlasClient.EntityResult updateEntityByUniqueAttribute(String typeName, String uniqueAttributeName,
+ String attrValue,
+ Referenceable updatedEntity) throws AtlasException {
ParamChecker.notEmpty(typeName, "typeName");
ParamChecker.notEmpty(uniqueAttributeName, "uniqueAttributeName");
ParamChecker.notNull(attrValue, "unique attribute value");
@@ -550,8 +554,9 @@ public class DefaultMetadataService implements MetadataService, ActiveStateChang
final ITypedReferenceableInstance newInstance = convertToTypedInstance(updatedEntity, typeName);
((ReferenceableInstance)newInstance).replaceWithNewId(oldInstance.getId());
- TypeUtils.Pair<List<String>, List<String>> guids = repository.updatePartial(newInstance);
- return onEntitiesAddedUpdated(guids);
+ AtlasClient.EntityResult entityResult = repository.updatePartial(newInstance);
+ onEntitiesAddedUpdated(entityResult);
+ return entityResult;
}
private void validateTypeExists(String entityType) throws AtlasException {
@@ -726,13 +731,14 @@ public class DefaultMetadataService implements MetadataService, ActiveStateChang
* @see org.apache.atlas.services.MetadataService#deleteEntities(java.lang.String)
*/
@Override
- public List<String> deleteEntities(List<String> deleteCandidateGuids) throws AtlasException {
+ public AtlasClient.EntityResult deleteEntities(List<String> deleteCandidateGuids) throws AtlasException {
ParamChecker.notEmpty(deleteCandidateGuids, "delete candidate guids");
return deleteGuids(deleteCandidateGuids);
}
@Override
- public List<String> deleteEntityByUniqueAttribute(String typeName, String uniqueAttributeName, String attrValue) throws AtlasException {
+ public AtlasClient.EntityResult deleteEntityByUniqueAttribute(String typeName, String uniqueAttributeName,
+ String attrValue) throws AtlasException {
ParamChecker.notEmpty(typeName, "delete candidate typeName");
ParamChecker.notEmpty(uniqueAttributeName, "delete candidate unique attribute name");
ParamChecker.notEmpty(attrValue, "delete candidate unique attribute value");
@@ -745,12 +751,10 @@ public class DefaultMetadataService implements MetadataService, ActiveStateChang
return deleteGuids(deleteCandidateGuids);
}
- private List<String> deleteGuids(List<String> deleteCandidateGuids) throws AtlasException {
- Pair<List<String>, List<ITypedReferenceableInstance>> deleteEntitiesResult = repository.deleteEntities(deleteCandidateGuids);
- if (deleteEntitiesResult.right.size() > 0) {
- onEntitiesDeleted(deleteEntitiesResult.right);
- }
- return deleteEntitiesResult.left;
+ private AtlasClient.EntityResult deleteGuids(List<String> deleteCandidateGuids) throws AtlasException {
+ AtlasClient.EntityResult entityResult = repository.deleteEntities(deleteCandidateGuids);
+ onEntitiesAddedUpdated(entityResult);
+ return entityResult;
}
private void onEntitiesDeleted(List<ITypedReferenceableInstance> entities) throws AtlasException {
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/test/java/org/apache/atlas/repository/audit/AuditRepositoryTestBase.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/audit/AuditRepositoryTestBase.java b/repository/src/test/java/org/apache/atlas/repository/audit/AuditRepositoryTestBase.java
index be407a5..f699404 100644
--- a/repository/src/test/java/org/apache/atlas/repository/audit/AuditRepositoryTestBase.java
+++ b/repository/src/test/java/org/apache/atlas/repository/audit/AuditRepositoryTestBase.java
@@ -19,6 +19,7 @@
package org.apache.atlas.repository.audit;
import org.apache.atlas.EntityAuditEvent;
+import org.apache.atlas.typesystem.Referenceable;
import org.apache.commons.lang.RandomStringUtils;
import org.testng.annotations.Test;
@@ -38,7 +39,7 @@ public class AuditRepositoryTestBase {
@Test
public void testAddEvents() throws Exception {
EntityAuditEvent event = new EntityAuditEvent(rand(), System.currentTimeMillis(), "u1",
- EntityAuditEvent.EntityAuditAction.ENTITY_CREATE, "d1");
+ EntityAuditEvent.EntityAuditAction.ENTITY_CREATE, "d1", new Referenceable(rand()));
eventRepository.putEvents(event);
@@ -54,17 +55,18 @@ public class AuditRepositoryTestBase {
String id2 = "id2" + rand();
String id3 = "id3" + rand();
long ts = System.currentTimeMillis();
+ Referenceable entity = new Referenceable(rand());
List<EntityAuditEvent> expectedEvents = new ArrayList<>(3);
for (int i = 0; i < 3; i++) {
//Add events for both ids
EntityAuditEvent event = new EntityAuditEvent(id2, ts - i, "user" + i,
- EntityAuditEvent.EntityAuditAction.ENTITY_UPDATE, "details" + i);
+ EntityAuditEvent.EntityAuditAction.ENTITY_UPDATE, "details" + i, entity);
eventRepository.putEvents(event);
expectedEvents.add(event);
eventRepository.putEvents(new EntityAuditEvent(id1, ts - i, "user" + i,
- EntityAuditEvent.EntityAuditAction.TAG_DELETE, "details" + i));
+ EntityAuditEvent.EntityAuditAction.TAG_DELETE, "details" + i, entity));
eventRepository.putEvents(new EntityAuditEvent(id3, ts - i, "user" + i,
- EntityAuditEvent.EntityAuditAction.TAG_ADD, "details" + i));
+ EntityAuditEvent.EntityAuditAction.TAG_ADD, "details" + i, entity));
}
//Use ts for which there is no event - ts + 2
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepositoryDeleteTestBase.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepositoryDeleteTestBase.java b/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepositoryDeleteTestBase.java
index 1aeedb5..449e066 100644
--- a/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepositoryDeleteTestBase.java
+++ b/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepositoryDeleteTestBase.java
@@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableSet;
import com.thinkaurelius.titan.core.TitanGraph;
import com.thinkaurelius.titan.core.util.TitanCleanup;
import com.tinkerpop.blueprints.Vertex;
-
import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasException;
import org.apache.atlas.RepositoryMetadataModule;
@@ -50,7 +49,6 @@ import org.apache.atlas.typesystem.types.Multiplicity;
import org.apache.atlas.typesystem.types.StructTypeDefinition;
import org.apache.atlas.typesystem.types.TraitType;
import org.apache.atlas.typesystem.types.TypeSystem;
-import org.apache.atlas.typesystem.types.TypeUtils;
import org.apache.atlas.typesystem.types.utils.TypesUtil;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
@@ -60,7 +58,6 @@ import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import javax.inject.Inject;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -71,6 +68,7 @@ import java.util.Map;
import static org.apache.atlas.TestUtils.COLUMNS_ATTR_NAME;
import static org.apache.atlas.TestUtils.COLUMN_TYPE;
import static org.apache.atlas.TestUtils.NAME;
+import static org.apache.atlas.TestUtils.PII;
import static org.apache.atlas.TestUtils.PROCESS_TYPE;
import static org.apache.atlas.TestUtils.TABLE_TYPE;
import static org.apache.atlas.TestUtils.createColumnEntity;
@@ -78,8 +76,6 @@ import static org.apache.atlas.TestUtils.createDBEntity;
import static org.apache.atlas.TestUtils.createTableEntity;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotEquals;
-import static org.testng.Assert.assertNotNull;
-import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
import static org.testng.Assert.fail;
@@ -145,7 +141,7 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
assertEquals(instance.getId()._getId(), id);
//delete entity should mark it as deleted
- List<String> results = deleteEntities(id);
+ List<String> results = deleteEntities(id).getDeletedEntities();
assertEquals(results.get(0), id);
assertEntityDeleted(id);
@@ -167,6 +163,26 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
}
@Test
+ public void testDeleteEntityWithTraits() throws Exception {
+ Referenceable entity = createDBEntity();
+ String id = createInstance(entity);
+
+ TraitType dataType = typeSystem.getDataType(TraitType.class, PII);
+ ITypedStruct trait = dataType.convert(new Struct(TestUtils.PII), Multiplicity.REQUIRED);
+ repositoryService.addTrait(id, trait);
+
+ ITypedReferenceableInstance instance = repositoryService.getEntityDefinition(id);
+ assertTrue(instance.getTraits().contains(PII));
+
+ deleteEntities(id);
+ assertEntityDeleted(id);
+ assertTestDeleteEntityWithTraits(id);
+ }
+
+ protected abstract void assertTestDeleteEntityWithTraits(String guid)
+ throws EntityNotFoundException, RepositoryException, Exception;
+
+ @Test
public void testDeleteReference() throws Exception {
//Deleting column should update table
Referenceable db = createDBEntity();
@@ -179,13 +195,16 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
table.set(COLUMNS_ATTR_NAME, Arrays.asList(new Id(colId, 0, COLUMN_TYPE)));
String tableId = createInstance(table);
- deleteEntities(colId);
+ AtlasClient.EntityResult entityResult = deleteEntities(colId);
+ assertEquals(entityResult.getDeletedEntities().size(), 1);
+ assertEquals(entityResult.getDeletedEntities().get(0), colId);
+ assertEquals(entityResult.getUpdateEntities().size(), 1);
+ assertEquals(entityResult.getUpdateEntities().get(0), tableId);
+
assertEntityDeleted(colId);
ITypedReferenceableInstance tableInstance = repositoryService.getEntityDefinition(tableId);
- List<ITypedReferenceableInstance> columns =
- (List<ITypedReferenceableInstance>) tableInstance.get(COLUMNS_ATTR_NAME);
- assertNull(columns);
+ assertColumnForTestDeleteReference(tableInstance);
//Deleting table should update process
Referenceable process = new Referenceable(PROCESS_TYPE);
@@ -195,18 +214,23 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
deleteEntities(tableId);
assertEntityDeleted(tableId);
- assertTestDeleteReference(processInstance);
+
+ assertTableForTestDeleteReference(tableId);
+ assertProcessForTestDeleteReference(processInstance);
}
- protected abstract void assertTestDeleteReference(ITypedReferenceableInstance processInstance) throws Exception;
+ protected abstract void assertTableForTestDeleteReference(String tableId) throws Exception;
+
+ protected abstract void assertColumnForTestDeleteReference(ITypedReferenceableInstance tableInstance)
+ throws AtlasException;
+
+ protected abstract void assertProcessForTestDeleteReference(ITypedReferenceableInstance processInstance) throws Exception;
protected abstract void assertEntityDeleted(String id) throws Exception;
- private List<String> deleteEntities(String... id) throws Exception {
+ private AtlasClient.EntityResult deleteEntities(String... id) throws Exception {
RequestContext.createContext();
- List<String> response = repositoryService.deleteEntities(Arrays.asList(id)).left;
- assertNotNull(response);
- return response;
+ return repositoryService.deleteEntities(Arrays.asList(id));
}
private String createInstance(Referenceable entity) throws Exception {
@@ -228,21 +252,41 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
table1Entity.set(COLUMNS_ATTR_NAME, ImmutableList.of(col1, col2, col3));
createInstance(table1Entity);
- // Retrieve the table entities from the auditRepository,
- // to get their guids and the composite column guids.
+ // Retrieve the table entities from the Repository, to get their guids and the composite column guids.
ITypedReferenceableInstance tableInstance = repositoryService.getEntityDefinition(TestUtils.TABLE_TYPE,
NAME, table1Entity.get(NAME));
- List<IReferenceableInstance> table1Columns = (List<IReferenceableInstance>) tableInstance.get(COLUMNS_ATTR_NAME);
+ List<IReferenceableInstance> columns = (List<IReferenceableInstance>) tableInstance.get(COLUMNS_ATTR_NAME);
+
+ //Delete column
+ String colId = columns.get(0).getId()._getId();
+ String tableId = tableInstance.getId()._getId();
+
+ AtlasClient.EntityResult entityResult = deleteEntities(colId);
+ assertEquals(entityResult.getDeletedEntities().size(), 1);
+ assertEquals(entityResult.getDeletedEntities().get(0), colId);
+ assertEquals(entityResult.getUpdateEntities().size(), 1);
+ assertEquals(entityResult.getUpdateEntities().get(0), tableId);
+ assertEntityDeleted(colId);
+
+ tableInstance = repositoryService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, table1Entity.get(NAME));
+ assertDeletedColumn(tableInstance);
- // Delete the table entities. The deletion should cascade
- // to their composite columns.
- List<String> deletedGuids = deleteEntities(tableInstance.getId()._getId());
+ //update by removing a column
+ tableInstance.set(COLUMNS_ATTR_NAME, ImmutableList.of(col3));
+ entityResult = updatePartial(tableInstance);
+ colId = columns.get(1).getId()._getId();
+ assertEquals(entityResult.getDeletedEntities().size(), 1);
+ assertEquals(entityResult.getDeletedEntities().get(0), colId);
+ assertEntityDeleted(colId);
+
+ // Delete the table entities. The deletion should cascade to their composite columns.
+ tableInstance = repositoryService.getEntityDefinition(TestUtils.TABLE_TYPE, NAME, table1Entity.get(NAME));
+ List<String> deletedGuids = deleteEntities(tableInstance.getId()._getId()).getDeletedEntities();
+ assertEquals(deletedGuids.size(), 2);
// Verify that deleteEntities() response has guids for tables and their composite columns.
Assert.assertTrue(deletedGuids.contains(tableInstance.getId()._getId()));
- for (IReferenceableInstance column : table1Columns) {
- Assert.assertTrue(deletedGuids.contains(column.getId()._getId()));
- }
+ Assert.assertTrue(deletedGuids.contains(columns.get(2).getId()._getId()));
// Verify that tables and their composite columns have been deleted from the graph Repository.
for (String guid : deletedGuids) {
@@ -251,6 +295,8 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
assertTestDeleteEntities(tableInstance);
}
+ protected abstract void assertDeletedColumn(ITypedReferenceableInstance tableInstance) throws AtlasException;
+
protected abstract void assertTestDeleteEntities(ITypedReferenceableInstance tableInstance) throws Exception;
/**
@@ -276,12 +322,13 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
vertexCount = getVertices(Constants.ENTITY_TYPE_PROPERTY_KEY, "SecurityClearance").size();
Assert.assertEquals(vertexCount, 1);
- List<String> deletedEntities = deleteEntities(hrDeptGuid);
+ List<String> deletedEntities = deleteEntities(hrDeptGuid).getDeletedEntities();
assertTrue(deletedEntities.contains(hrDeptGuid));
+ assertEntityDeleted(hrDeptGuid);
// Verify Department entity and its contained Person entities were deleted.
- assertEntityDeleted(hrDeptGuid);
for (String employeeGuid : employeeGuids) {
+ assertTrue(deletedEntities.contains(employeeGuid));
assertEntityDeleted(employeeGuid);
}
@@ -341,15 +388,16 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
object = mapOwnerVertex.getProperty(atlasEdgeLabel.getQualifiedMapKey());
Assert.assertNotNull(object);
- List<String> deletedEntities = deleteEntities(mapOwnerGuid);
+ List<String> deletedEntities = deleteEntities(mapOwnerGuid).getDeletedEntities();
Assert.assertEquals(deletedEntities.size(), 2);
- Assert.assertTrue(deletedEntities.containsAll(guids));
+ Assert.assertTrue(deletedEntities.contains(mapOwnerGuid));
+ Assert.assertTrue(deletedEntities.contains(mapValueGuid));
assertEntityDeleted(mapOwnerGuid);
assertEntityDeleted(mapValueGuid);
}
- private TypeUtils.Pair<List<String>, List<String>> updatePartial(ITypedReferenceableInstance entity) throws RepositoryException {
+ private AtlasClient.EntityResult updatePartial(ITypedReferenceableInstance entity) throws RepositoryException {
RequestContext.createContext();
return repositoryService.updatePartial(entity);
}
@@ -379,7 +427,9 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
ClassType personType = typeSystem.getDataType(ClassType.class, "Person");
ITypedReferenceableInstance maxEntity = personType.createInstance(max.getId());
maxEntity.set("mentor", johnGuid);
- updatePartial(maxEntity);
+ AtlasClient.EntityResult entityResult = updatePartial(maxEntity);
+ assertEquals(entityResult.getUpdateEntities().size(), 1);
+ assertTrue(entityResult.getUpdateEntities().contains(maxGuid));
// Verify the update was applied correctly - john should now be max's mentor.
max = repositoryService.getEntityDefinition(maxGuid);
@@ -394,7 +444,9 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
// Update max's mentor reference to jane.
maxEntity.set("mentor", janeGuid);
- updatePartial(maxEntity);
+ entityResult = updatePartial(maxEntity);
+ assertEquals(entityResult.getUpdateEntities().size(), 1);
+ assertTrue(entityResult.getUpdateEntities().contains(maxGuid));
// Verify the update was applied correctly - jane should now be max's mentor.
max = repositoryService.getEntityDefinition(maxGuid);
@@ -411,7 +463,11 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
Id juliusGuid = julius.getId();
maxEntity = personType.createInstance(max.getId());
maxEntity.set("manager", juliusGuid);
- updatePartial(maxEntity);
+ entityResult = updatePartial(maxEntity);
+ //TODO ATLAS-499 should have updated julius' subordinates
+ assertEquals(entityResult.getUpdateEntities().size(), 2);
+ assertTrue(entityResult.getUpdateEntities().contains(maxGuid));
+ assertTrue(entityResult.getUpdateEntities().contains(janeGuid._getId()));
// Verify the update was applied correctly - julius should now be max's manager.
max = repositoryService.getEntityDefinition(maxGuid);
@@ -456,41 +512,38 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
}
Assert.assertTrue(subordinateIds.contains(maxGuid));
- List<String> deletedEntities = deleteEntities(maxGuid);
- Assert.assertTrue(deletedEntities.contains(maxGuid));
- assertEntityDeleted(maxGuid);
- // Verify that the Department.employees reference to the deleted employee
- // was disconnected.
- hrDept = repositoryService.getEntityDefinition(hrDeptGuid);
- refValue = hrDept.get("employees");
- Assert.assertTrue(refValue instanceof List);
- List<Object> employees = (List<Object>)refValue;
- Assert.assertEquals(employees.size(), 3);
- for (Object listValue : employees) {
- Assert.assertTrue(listValue instanceof ITypedReferenceableInstance);
- ITypedReferenceableInstance employee = (ITypedReferenceableInstance) listValue;
- Assert.assertNotEquals(employee.getId()._getId(), maxGuid);
- }
+ AtlasClient.EntityResult entityResult = deleteEntities(maxGuid);
+ ITypedReferenceableInstance john = repositoryService.getEntityDefinition("Manager", "name", "John");
- // Verify that max's Person.mentor unidirectional reference to john was disconnected.
- ITypedReferenceableInstance john = repositoryService.getEntityDefinition(johnGuid);
- refValue = john.get("mentor");
- Assert.assertNull(refValue);
+ assertEquals(entityResult.getDeletedEntities().size(), 1);
+ assertTrue(entityResult.getDeletedEntities().contains(maxGuid));
+ assertEquals(entityResult.getUpdateEntities().size(), 3);
+ assertTrue(entityResult.getUpdateEntities().containsAll(Arrays.asList(jane.getId()._getId(), hrDeptGuid,
+ john.getId()._getId())));
+ assertEntityDeleted(maxGuid);
- assertTestDisconnectBidirectionalReferences(janeGuid);
+ assertMaxForTestDisconnectBidirectionalReferences(nameGuidMap);
// Now delete jane - this should disconnect the manager reference from her
// subordinate.
- deletedEntities = deleteEntities(janeGuid);
- Assert.assertTrue(deletedEntities.contains(janeGuid));
+ entityResult = deleteEntities(janeGuid);
+ assertEquals(entityResult.getDeletedEntities().size(), 1);
+ assertTrue(entityResult.getDeletedEntities().contains(janeGuid));
+ assertEquals(entityResult.getUpdateEntities().size(), 2);
+ assertTrue(entityResult.getUpdateEntities().containsAll(Arrays.asList(hrDeptGuid, john.getId()._getId())));
+
assertEntityDeleted(janeGuid);
- john = repositoryService.getEntityDefinition(johnGuid);
- Assert.assertNull(john.get("manager"));
+ john = repositoryService.getEntityDefinition("Person", "name", "John");
+ assertJohnForTestDisconnectBidirectionalReferences(john, janeGuid);
}
- protected abstract void assertTestDisconnectBidirectionalReferences(String janeGuid) throws Exception;
+ protected abstract void assertJohnForTestDisconnectBidirectionalReferences(ITypedReferenceableInstance john,
+ String janeGuid) throws Exception;
+
+ protected abstract void assertMaxForTestDisconnectBidirectionalReferences(Map<String, String> nameGuidMap)
+ throws Exception;
/**
* Verify deleting entity that is the target of a unidirectional class array reference
@@ -503,30 +556,27 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
// Get the guid for one of the table's columns.
ITypedReferenceableInstance table = repositoryService.getEntityDefinition(TestUtils.TABLE_TYPE, "name", TestUtils.TABLE_NAME);
String tableGuid = table.getId()._getId();
- Object refValues = table.get("columns");
- Assert.assertTrue(refValues instanceof List);
- List<Object> refList = (List<Object>) refValues;
- Assert.assertEquals(refList.size(), 5);
- Assert.assertTrue(refList.get(0) instanceof ITypedReferenceableInstance);
- ITypedReferenceableInstance column = (ITypedReferenceableInstance) refList.get(0);
- String columnGuid = column.getId()._getId();
+ List<ITypedReferenceableInstance> columns = (List<ITypedReferenceableInstance>) table.get("columns");
+ Assert.assertEquals(columns.size(), 5);
+ String columnGuid = columns.get(0).getId()._getId();
// Delete the column.
- List<String> deletedEntities = deleteEntities(columnGuid);
- Assert.assertTrue(deletedEntities.contains(columnGuid));
+ AtlasClient.EntityResult entityResult = deleteEntities(columnGuid);
+ assertEquals(entityResult.getDeletedEntities().size(), 1);
+ Assert.assertTrue(entityResult.getDeletedEntities().contains(columnGuid));
+ assertEquals(entityResult.getUpdateEntities().size(), 1);
+ Assert.assertTrue(entityResult.getUpdateEntities().contains(tableGuid));
assertEntityDeleted(columnGuid);
// Verify table.columns reference to the deleted column has been disconnected.
table = repositoryService.getEntityDefinition(tableGuid);
- refList = (List<Object>) table.get("columns");
- Assert.assertEquals(refList.size(), 4);
- for (Object refValue : refList) {
- Assert.assertTrue(refValue instanceof ITypedReferenceableInstance);
- column = (ITypedReferenceableInstance)refValue;
- Assert.assertFalse(column.getId()._getId().equals(columnGuid));
- }
+ assertTestDisconnectUnidirectionalArrayReferenceFromClassType(
+ (List<ITypedReferenceableInstance>) table.get("columns"), columnGuid);
}
+ protected abstract void assertTestDisconnectUnidirectionalArrayReferenceFromClassType(
+ List<ITypedReferenceableInstance> columns, String columnGuid);
+
/**
* Verify deleting entities that are the target of a unidirectional class array reference
* from a struct or trait instance.
@@ -559,8 +609,8 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
Referenceable structTargetEntity = new Referenceable("StructTarget");
Referenceable traitTargetEntity = new Referenceable("TraitTarget");
Referenceable structContainerEntity = new Referenceable("StructContainer");
- Referenceable structInstance = new Referenceable("TestStruct");
- Referenceable nestedStructInstance = new Referenceable("NestedStruct");
+ Struct structInstance = new Struct("TestStruct");
+ Struct nestedStructInstance = new Struct("NestedStruct");
Referenceable traitInstance = new Referenceable("TestTrait");
structContainerEntity.set("struct", structInstance);
structInstance.set("target", ImmutableList.of(structTargetEntity));
@@ -623,19 +673,19 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
Assert.assertEquals(refList.get(0).getId()._getId(), traitTargetGuid);
// Delete the entities that are targets of the struct and trait instances.
- List<String> deletedEntities = deleteEntities(structTargetGuid, traitTargetGuid);
+ AtlasClient.EntityResult entityResult = deleteEntities(structTargetGuid, traitTargetGuid);
+ Assert.assertEquals(entityResult.getDeletedEntities().size(), 2);
+ Assert.assertTrue(entityResult.getDeletedEntities().containsAll(Arrays.asList(structTargetGuid, traitTargetGuid)));
assertEntityDeleted(structTargetGuid);
assertEntityDeleted(traitTargetGuid);
- Assert.assertEquals(deletedEntities.size(), 2);
- Assert.assertTrue(deletedEntities.containsAll(Arrays.asList(structTargetGuid, traitTargetGuid)));
assertTestDisconnectUnidirectionalArrayReferenceFromStructAndTraitTypes(structContainerGuid);
// Delete the entity which contains nested structs and has the TestTrait trait.
- deletedEntities = deleteEntities(structContainerGuid);
+ entityResult = deleteEntities(structContainerGuid);
+ Assert.assertEquals(entityResult.getDeletedEntities().size(), 1);
+ Assert.assertTrue(entityResult.getDeletedEntities().contains(structContainerGuid));
assertEntityDeleted(structContainerGuid);
- Assert.assertEquals(deletedEntities.size(), 1);
- Assert.assertTrue(deletedEntities.contains(structContainerGuid));
// Verify all TestStruct struct vertices were removed.
assertVerticesDeleted(getVertices(Constants.ENTITY_TYPE_PROPERTY_KEY, "TestStruct"));
@@ -890,13 +940,14 @@ public abstract class GraphBackedMetadataRepositoryDeleteTestBase {
return list;
}
- private Map<String, String> getEmployeeNameGuidMap(ITypedReferenceableInstance hrDept) throws AtlasException {
-
+ private Map<String, String> getEmployeeNameGuidMap(final ITypedReferenceableInstance hrDept) throws AtlasException {
Object refValue = hrDept.get("employees");
Assert.assertTrue(refValue instanceof List);
List<Object> employees = (List<Object>)refValue;
Assert.assertEquals(employees.size(), 4);
- Map<String, String> nameGuidMap = new HashMap<String, String>();
+ Map<String, String> nameGuidMap = new HashMap<String, String>() {{
+ put("hr", hrDept.getId()._getId());
+ }};
for (Object listValue : employees) {
Assert.assertTrue(listValue instanceof ITypedReferenceableInstance);
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedRepositoryHardDeleteTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedRepositoryHardDeleteTest.java b/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedRepositoryHardDeleteTest.java
index d2109d3..cc60264 100644
--- a/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedRepositoryHardDeleteTest.java
+++ b/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedRepositoryHardDeleteTest.java
@@ -21,8 +21,10 @@ package org.apache.atlas.repository.graph;
import com.tinkerpop.blueprints.Vertex;
import org.apache.atlas.AtlasClient;
+import org.apache.atlas.AtlasException;
import org.apache.atlas.TestUtils;
import org.apache.atlas.repository.Constants;
+import org.apache.atlas.typesystem.IReferenceableInstance;
import org.apache.atlas.typesystem.IStruct;
import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.ITypedStruct;
@@ -32,8 +34,11 @@ import org.apache.atlas.typesystem.types.TypeSystem;
import org.testng.Assert;
import java.util.List;
+import java.util.Map;
+import static org.apache.atlas.TestUtils.COLUMNS_ATTR_NAME;
import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.fail;
import static org.testng.AssertJUnit.assertNotNull;
@@ -45,7 +50,24 @@ public class GraphBackedRepositoryHardDeleteTest extends GraphBackedMetadataRepo
}
@Override
- protected void assertTestDeleteReference(ITypedReferenceableInstance processInstance) throws Exception {
+ protected void assertTestDeleteEntityWithTraits(String guid) {
+ //entity is deleted. So, no assertions
+ }
+
+ @Override
+ protected void assertTableForTestDeleteReference(String tableId) {
+ //entity is deleted. So, no assertions
+ }
+
+ @Override
+ protected void assertColumnForTestDeleteReference(ITypedReferenceableInstance tableInstance) throws AtlasException {
+ List<ITypedReferenceableInstance> columns =
+ (List<ITypedReferenceableInstance>) tableInstance.get(COLUMNS_ATTR_NAME);
+ assertNull(columns);
+ }
+
+ @Override
+ protected void assertProcessForTestDeleteReference(ITypedReferenceableInstance processInstance) throws Exception {
//assert that outputs is empty
ITypedReferenceableInstance newProcess =
repositoryService.getEntityDefinition(processInstance.getId()._getId());
@@ -63,6 +85,11 @@ public class GraphBackedRepositoryHardDeleteTest extends GraphBackedMetadataRepo
}
@Override
+ protected void assertDeletedColumn(ITypedReferenceableInstance tableInstance) throws AtlasException {
+ assertEquals(((List<IReferenceableInstance>) tableInstance.get(COLUMNS_ATTR_NAME)).size(), 2);
+ }
+
+ @Override
protected void assertTestDeleteEntities(ITypedReferenceableInstance tableInstance) {
int vertexCount = getVertices(Constants.ENTITY_TYPE_PROPERTY_KEY, TestUtils.TABLE_TYPE).size();
assertEquals(vertexCount, 0);
@@ -85,12 +112,42 @@ public class GraphBackedRepositoryHardDeleteTest extends GraphBackedMetadataRepo
}
@Override
- protected void assertTestDisconnectBidirectionalReferences(String janeGuid) throws Exception {
+ protected void assertJohnForTestDisconnectBidirectionalReferences(ITypedReferenceableInstance john,
+ String janeGuid) throws Exception {
+ assertNull(john.get("manager"));
+ }
+
+ @Override
+ protected void assertMaxForTestDisconnectBidirectionalReferences(Map<String, String> nameGuidMap)
+ throws Exception {
+ // Verify that the Department.employees reference to the deleted employee
+ // was disconnected.
+ ITypedReferenceableInstance hrDept = repositoryService.getEntityDefinition(nameGuidMap.get("hr"));
+ List<ITypedReferenceableInstance> employees = (List<ITypedReferenceableInstance>) hrDept.get("employees");
+ Assert.assertEquals(employees.size(), 3);
+ String maxGuid = nameGuidMap.get("Max");
+ for (ITypedReferenceableInstance employee : employees) {
+ Assert.assertNotEquals(employee.getId()._getId(), maxGuid);
+ }
+
// Verify that the Manager.subordinates reference to the deleted employee
// Max was disconnected.
- ITypedReferenceableInstance jane = repositoryService.getEntityDefinition(janeGuid);
+ ITypedReferenceableInstance jane = repositoryService.getEntityDefinition(nameGuidMap.get("Jane"));
List<ITypedReferenceableInstance> subordinates = (List<ITypedReferenceableInstance>) jane.get("subordinates");
assertEquals(subordinates.size(), 1);
+
+ // Verify that max's Person.mentor unidirectional reference to john was disconnected.
+ ITypedReferenceableInstance john = repositoryService.getEntityDefinition(nameGuidMap.get("John"));
+ assertNull(john.get("mentor"));
+ }
+
+ @Override
+ protected void assertTestDisconnectUnidirectionalArrayReferenceFromClassType(
+ List<ITypedReferenceableInstance> columns, String columnGuid) {
+ assertEquals(columns.size(), 4);
+ for (ITypedReferenceableInstance column : columns) {
+ assertFalse(column.getId()._getId().equals(columnGuid));
+ }
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedRepositorySoftDeleteTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedRepositorySoftDeleteTest.java b/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedRepositorySoftDeleteTest.java
index d9e3ec9..90bb635 100644
--- a/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedRepositorySoftDeleteTest.java
+++ b/repository/src/test/java/org/apache/atlas/repository/graph/GraphBackedRepositorySoftDeleteTest.java
@@ -19,10 +19,11 @@
package org.apache.atlas.repository.graph;
import com.tinkerpop.blueprints.Vertex;
-
import org.apache.atlas.AtlasClient;
+import org.apache.atlas.AtlasException;
import org.apache.atlas.TestUtils;
import org.apache.atlas.repository.Constants;
+import org.apache.atlas.typesystem.IReferenceableInstance;
import org.apache.atlas.typesystem.IStruct;
import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.ITypedStruct;
@@ -33,8 +34,12 @@ import org.testng.Assert;
import java.util.List;
import java.util.Map;
+import static org.apache.atlas.TestUtils.COLUMNS_ATTR_NAME;
+import static org.apache.atlas.TestUtils.NAME;
+import static org.apache.atlas.TestUtils.PII;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
public class GraphBackedRepositorySoftDeleteTest extends GraphBackedMetadataRepositoryDeleteTestBase {
@Override
@@ -43,7 +48,38 @@ public class GraphBackedRepositorySoftDeleteTest extends GraphBackedMetadataRepo
}
@Override
- protected void assertTestDeleteReference(ITypedReferenceableInstance expected) throws Exception {
+ protected void assertTestDeleteEntityWithTraits(String guid) throws Exception {
+ ITypedReferenceableInstance instance = repositoryService.getEntityDefinition(guid);
+ assertTrue(instance.getTraits().contains(PII));
+ }
+
+ @Override
+ protected void assertTableForTestDeleteReference(String tableId) throws Exception {
+ ITypedReferenceableInstance table = repositoryService.getEntityDefinition(tableId);
+ assertNotNull(table.get(NAME));
+ assertNotNull(table.get("description"));
+ assertNotNull(table.get("type"));
+ assertNotNull(table.get("tableType"));
+ assertNotNull(table.get("created"));
+
+ Id dbId = (Id) table.get("database");
+ assertNotNull(dbId);
+
+ ITypedReferenceableInstance db = repositoryService.getEntityDefinition(dbId.getId()._getId());
+ assertNotNull(db);
+ assertEquals(db.getId().getState(), Id.EntityState.ACTIVE);
+ }
+
+ @Override
+ protected void assertColumnForTestDeleteReference(ITypedReferenceableInstance tableInstance) throws AtlasException {
+ List<ITypedReferenceableInstance> columns =
+ (List<ITypedReferenceableInstance>) tableInstance.get(COLUMNS_ATTR_NAME);
+ assertEquals(columns.size(), 1);
+ assertEquals(columns.get(0).getId().getState(), Id.EntityState.DELETED);
+ }
+
+ @Override
+ protected void assertProcessForTestDeleteReference(ITypedReferenceableInstance expected) throws Exception {
ITypedReferenceableInstance process = repositoryService.getEntityDefinition(expected.getId()._getId());
List<ITypedReferenceableInstance> outputs =
(List<ITypedReferenceableInstance>) process.get(AtlasClient.PROCESS_ATTRIBUTE_OUTPUTS);
@@ -59,6 +95,13 @@ public class GraphBackedRepositorySoftDeleteTest extends GraphBackedMetadataRepo
}
@Override
+ protected void assertDeletedColumn(ITypedReferenceableInstance tableInstance) throws AtlasException {
+ List<IReferenceableInstance> columns = (List<IReferenceableInstance>) tableInstance.get(COLUMNS_ATTR_NAME);
+ assertEquals(columns.size(), 3);
+ assertEquals(columns.get(0).getId().getState(), Id.EntityState.DELETED);
+ }
+
+ @Override
protected void assertTestDeleteEntities(ITypedReferenceableInstance expected) throws Exception {
//Assert that the deleted table can be fully constructed back
ITypedReferenceableInstance table = repositoryService.getEntityDefinition(expected.getId()._getId());
@@ -67,6 +110,7 @@ public class GraphBackedRepositorySoftDeleteTest extends GraphBackedMetadataRepo
List<ITypedReferenceableInstance> expectedColumns =
(List<ITypedReferenceableInstance>) table.get(TestUtils.COLUMNS_ATTR_NAME);
assertEquals(columns.size(), expectedColumns.size());
+ assertNotNull(table.get("database"));
}
@Override
@@ -85,11 +129,57 @@ public class GraphBackedRepositorySoftDeleteTest extends GraphBackedMetadataRepo
}
@Override
- protected void assertTestDisconnectBidirectionalReferences(String janeGuid) throws Exception {
+ protected void assertJohnForTestDisconnectBidirectionalReferences(ITypedReferenceableInstance john, String janeGuid)
+ throws Exception {
+ Id mgr = (Id) john.get("manager");
+ assertNotNull(mgr);
+ assertEquals(mgr._getId(), janeGuid);
+ assertEquals(mgr.getState(), Id.EntityState.DELETED);
+ }
+
+ @Override
+ protected void assertMaxForTestDisconnectBidirectionalReferences(Map<String, String> nameGuidMap) throws Exception {
+ // Verify that the Department.employees reference to the deleted employee
+ // was disconnected.
+ ITypedReferenceableInstance hrDept = repositoryService.getEntityDefinition(nameGuidMap.get("hr"));
+ List<ITypedReferenceableInstance> employees = (List<ITypedReferenceableInstance>) hrDept.get("employees");
+ Assert.assertEquals(employees.size(), 4);
+ String maxGuid = nameGuidMap.get("Max");
+ for (ITypedReferenceableInstance employee : employees) {
+ if (employee.getId()._getId().equals(maxGuid)) {
+ assertEquals(employee.getId().getState(), Id.EntityState.DELETED);
+ }
+ }
+
// Verify that the Manager.subordinates still references deleted employee
- ITypedReferenceableInstance jane = repositoryService.getEntityDefinition(janeGuid);
+ ITypedReferenceableInstance jane = repositoryService.getEntityDefinition(nameGuidMap.get("Jane"));
List<ITypedReferenceableInstance> subordinates = (List<ITypedReferenceableInstance>) jane.get("subordinates");
assertEquals(subordinates.size(), 2);
+ for (ITypedReferenceableInstance subordinate : subordinates) {
+ if (subordinate.getId()._getId().equals(maxGuid)) {
+ assertEquals(subordinate.getId().getState(), Id.EntityState.DELETED);
+ }
+ }
+
+ // Verify that max's Person.mentor unidirectional reference to john was disconnected.
+ ITypedReferenceableInstance john = repositoryService.getEntityDefinition(nameGuidMap.get("John"));
+ Id mentor = (Id) john.get("mentor");
+ assertEquals(mentor._getId(), maxGuid);
+ assertEquals(mentor.getState(), Id.EntityState.DELETED);
+ }
+
+ @Override
+ protected void assertTestDisconnectUnidirectionalArrayReferenceFromClassType(
+ List<ITypedReferenceableInstance> columns, String columnGuid) {
+ Assert.assertEquals(columns.size(), 5);
+ for (ITypedReferenceableInstance column : columns) {
+ if (column.getId()._getId().equals(columnGuid)) {
+ assertEquals(column.getId().getState(), Id.EntityState.DELETED);
+ } else {
+ assertEquals(column.getId().getState(), Id.EntityState.ACTIVE);
+ }
+ }
+
}
@Override
@@ -122,7 +212,6 @@ public class GraphBackedRepositorySoftDeleteTest extends GraphBackedMetadataRepo
@Override
protected void assertTestDeleteTargetOfMultiplicityRequiredReference() throws Exception {
-
// No-op - it's ok that no exception was thrown if soft deletes are enabled.
}
}
[3/3] incubator-atlas git commit: ATLAS-716 Entity update/delete
notifications (shwethags)
Posted by sh...@apache.org.
ATLAS-716 Entity update/delete notifications (shwethags)
Project: http://git-wip-us.apache.org/repos/asf/incubator-atlas/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-atlas/commit/705014eb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/705014eb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/705014eb
Branch: refs/heads/master
Commit: 705014eb3352180ff8f2cac05dbbc0809b421d8c
Parents: 153fc36
Author: Shwetha GS <ss...@hortonworks.com>
Authored: Thu May 26 00:02:32 2016 +0530
Committer: Shwetha GS <ss...@hortonworks.com>
Committed: Thu May 26 00:04:22 2016 +0530
----------------------------------------------------------------------
.../atlas/hive/bridge/HiveMetaStoreBridge.java | 2 +-
.../org/apache/atlas/hive/hook/HiveHookIT.java | 65 +++--
.../main/java/org/apache/atlas/AtlasClient.java | 112 ++++++--
.../java/org/apache/atlas/EntityAuditEvent.java | 40 ++-
.../src/main/java/org/apache/atlas/SerDe.java | 79 ++++++
.../java/org/apache/atlas/AtlasClientTest.java | 26 ++
.../atlas/notification/MessageVersion.java | 5 +
.../notification/NotificationInterface.java | 2 +-
.../VersionedMessageDeserializer.java | 12 +-
.../NotificationEntityChangeListener.java | 106 -------
.../AbstractNotificationConsumerTest.java | 14 +-
release-log.txt | 1 +
.../atlas/repository/MetadataRepository.java | 8 +-
.../repository/audit/EntityAuditListener.java | 5 +-
.../audit/HBaseBasedAuditRepository.java | 3 +
.../atlas/repository/graph/DeleteHandler.java | 136 +++++----
.../graph/GraphBackedMetadataRepository.java | 22 +-
.../atlas/repository/graph/GraphHelper.java | 59 ++--
.../graph/GraphToTypedInstanceMapper.java | 13 +-
.../repository/graph/HardDeleteHandler.java | 8 +-
.../repository/graph/SoftDeleteHandler.java | 32 ++-
.../graph/TypedInstanceToGraphMapper.java | 181 ++++++------
.../typestore/GraphBackedTypeStore.java | 21 +-
.../atlas/services/DefaultMetadataService.java | 72 ++---
.../audit/AuditRepositoryTestBase.java | 10 +-
...hBackedMetadataRepositoryDeleteTestBase.java | 221 +++++++++------
.../GraphBackedRepositoryHardDeleteTest.java | 63 +++-
.../GraphBackedRepositorySoftDeleteTest.java | 99 ++++++-
.../service/DefaultMetadataServiceTest.java | 284 ++++++++++++-------
.../java/org/apache/atlas/RequestContext.java | 19 +-
.../apache/atlas/services/MetadataService.java | 21 +-
.../apache/atlas/typesystem/Referenceable.java | 2 +-
.../java/org/apache/atlas/LocalAtlasClient.java | 22 +-
.../NotificationEntityChangeListener.java | 161 +++++++++++
.../atlas/web/resources/EntityResource.java | 97 +++----
.../apache/atlas/web/service/ServiceModule.java | 2 +-
.../org/apache/atlas/LocalAtlasClientTest.java | 21 +-
.../notification/EntityNotificationIT.java | 2 -
.../NotificationEntityChangeListenerTest.java | 90 ++++++
.../web/resources/EntityJerseyResourceIT.java | 48 ++--
.../atlas/web/service/CuratorFactoryTest.java | 5 -
41 files changed, 1443 insertions(+), 748 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/addons/hive-bridge/src/main/java/org/apache/atlas/hive/bridge/HiveMetaStoreBridge.java
----------------------------------------------------------------------
diff --git a/addons/hive-bridge/src/main/java/org/apache/atlas/hive/bridge/HiveMetaStoreBridge.java b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/bridge/HiveMetaStoreBridge.java
index 254e150..fe07d73 100755
--- a/addons/hive-bridge/src/main/java/org/apache/atlas/hive/bridge/HiveMetaStoreBridge.java
+++ b/addons/hive-bridge/src/main/java/org/apache/atlas/hive/bridge/HiveMetaStoreBridge.java
@@ -188,7 +188,7 @@ public class HiveMetaStoreBridge {
List<String> guids = getAtlasClient().createEntity(entityJSON);
LOG.debug("created instance for type " + typeName + ", guid: " + guids);
- return new Referenceable(guids.get(0), referenceable.getTypeName(), null);
+ return new Referenceable(guids.get(guids.size() - 1), referenceable.getTypeName(), null);
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
----------------------------------------------------------------------
diff --git a/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java b/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
index 70100f1..84d9a52 100755
--- a/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
+++ b/addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/HiveHookIT.java
@@ -29,7 +29,6 @@ import org.apache.atlas.hive.bridge.HiveMetaStoreBridge;
import org.apache.atlas.hive.model.HiveDataModelGenerator;
import org.apache.atlas.hive.model.HiveDataTypes;
import org.apache.atlas.hive.rewrite.HiveASTRewriter;
-import org.apache.atlas.hive.rewrite.RewriteException;
import org.apache.atlas.typesystem.Referenceable;
import org.apache.atlas.typesystem.Struct;
import org.apache.atlas.typesystem.persistence.Id;
@@ -66,6 +65,7 @@ import java.util.Map;
import static org.apache.atlas.hive.hook.HiveHook.lower;
import static org.apache.atlas.hive.hook.HiveHook.normalize;
+import static org.apache.atlas.hive.model.HiveDataModelGenerator.NAME;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.fail;
@@ -197,8 +197,8 @@ public class HiveHookIT {
Assert.assertEquals(tableRef.get(HiveDataModelGenerator.TABLE_TYPE_ATTR), TableType.MANAGED_TABLE.name());
Assert.assertEquals(tableRef.get(HiveDataModelGenerator.COMMENT), "table comment");
String entityName = HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, tableName);
- Assert.assertEquals(tableRef.get(HiveDataModelGenerator.NAME), entityName);
- Assert.assertEquals(tableRef.get(HiveDataModelGenerator.NAME), "default." + tableName.toLowerCase() + "@" + CLUSTER_NAME);
+ Assert.assertEquals(tableRef.get(NAME), entityName);
+ Assert.assertEquals(tableRef.get(NAME), "default." + tableName.toLowerCase() + "@" + CLUSTER_NAME);
Table t = hiveMetaStoreBridge.hiveClient.getTable(DEFAULT_DB, tableName);
long createTime = Long.parseLong(t.getMetadata().getProperty(hive_metastoreConstants.DDL_TIME)) * HiveMetaStoreBridge.MILLIS_CONVERT_FACTOR;
@@ -631,7 +631,7 @@ public class HiveHookIT {
final String newDBName = createDatabase();
assertTableIsRegistered(DEFAULT_DB, tableName);
- String columnGuid = assertColumnIsRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, tableName), HiveDataModelGenerator.NAME));
+ String columnGuid = assertColumnIsRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, tableName), NAME));
String sdGuid = assertSDIsRegistered(HiveMetaStoreBridge.getStorageDescQFName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, tableName)), null);
assertDatabaseIsRegistered(newDBName);
@@ -649,10 +649,10 @@ public class HiveHookIT {
String query = String.format("alter table %s rename to %s", DEFAULT_DB + "." + tableName, newDBName + "." + newTableName);
runCommand(query);
- String newColGuid = assertColumnIsRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, newDBName, newTableName), HiveDataModelGenerator.NAME));
+ String newColGuid = assertColumnIsRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, newDBName, newTableName), NAME));
Assert.assertEquals(newColGuid, columnGuid);
- assertColumnIsNotRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, newDBName, tableName), HiveDataModelGenerator.NAME));
+ assertColumnIsNotRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, newDBName, tableName), NAME));
assertTrait(columnGuid, colTraitDetails);
String newSdGuid = assertSDIsRegistered(HiveMetaStoreBridge.getStorageDescQFName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, newDBName, newTableName)), null);
@@ -676,7 +676,16 @@ public class HiveHookIT {
private List<Referenceable> getColumns(String dbName, String tableName) throws Exception {
String tableId = assertTableIsRegistered(dbName, tableName);
Referenceable tableRef = atlasClient.getEntity(tableId);
- return ((List<Referenceable>)tableRef.get(HiveDataModelGenerator.COLUMNS));
+
+ //with soft delete, the deleted columns are returned as well. So, filter the deleted ones
+ List<Referenceable> columns = ((List<Referenceable>) tableRef.get(HiveDataModelGenerator.COLUMNS));
+ List<Referenceable> activeColumns = new ArrayList<>();
+ for (Referenceable col : columns) {
+ if (col.getId().getState() == Id.EntityState.ACTIVE) {
+ activeColumns.add(col);
+ }
+ }
+ return activeColumns;
}
@@ -723,21 +732,15 @@ public class HiveHookIT {
colDropped));
//Verify the number of columns present in the table
- assertTableIsRegistered(DEFAULT_DB, tableName, new AssertPredicate() {
- @Override
- public void assertOnEntity(Referenceable tableRef) throws Exception {
- List<Referenceable> columns = (List<Referenceable>) tableRef.get(HiveDataModelGenerator.COLUMNS);
- Assert.assertEquals(columns.size(), 1);
- Assert.assertEquals(columns.get(0).get(HiveDataModelGenerator.NAME), HiveDataModelGenerator.NAME);
-
- }
- });
+ List<Referenceable> columns = getColumns(DEFAULT_DB, tableName);
+ assertEquals(columns.size(), 1);
+ assertEquals(columns.get(0).get(NAME), "name");
}
@Test
public void testAlterTableChangeColumn() throws Exception {
//Change name
- String oldColName = HiveDataModelGenerator.NAME;
+ String oldColName = NAME;
String newColName = "name1";
String tableName = createTable();
String query = String.format("alter table %s change %s %s string", tableName, oldColName, newColName);
@@ -818,8 +821,8 @@ public class HiveHookIT {
@Override
public void assertOnEntity(Referenceable entity) throws Exception {
List<Referenceable> columns = (List<Referenceable>) entity.get(HiveDataModelGenerator.COLUMNS);
- assertEquals(columns.get(0).get(HiveDataModelGenerator.NAME), finalNewColName);
- assertEquals(columns.get(1).get(HiveDataModelGenerator.NAME), "id");
+ assertEquals(columns.get(0).get(NAME), finalNewColName);
+ assertEquals(columns.get(1).get(NAME), "id");
}
}
);
@@ -846,8 +849,8 @@ public class HiveHookIT {
@Override
public void assertOnEntity(Referenceable entity) throws Exception {
List<Referenceable> columns = (List<Referenceable>) entity.get(HiveDataModelGenerator.COLUMNS);
- assertEquals(columns.get(1).get(HiveDataModelGenerator.NAME), finalNewColName2);
- assertEquals(columns.get(0).get(HiveDataModelGenerator.NAME), "id");
+ assertEquals(columns.get(1).get(NAME), finalNewColName2);
+ assertEquals(columns.get(0).get(NAME), "id");
}
}
);
@@ -955,7 +958,7 @@ public class HiveHookIT {
Referenceable hdfsPathRef = atlasClient.getEntity(hdfsPathId);
Assert.assertEquals(hdfsPathRef.get("path"), testPathNormed);
- Assert.assertEquals(hdfsPathRef.get(HiveDataModelGenerator.NAME), testPathNormed);
+ Assert.assertEquals(hdfsPathRef.get(NAME), testPathNormed);
// Assert.assertEquals(hdfsPathRef.get("name"), new Path(testPath).getName());
Assert.assertEquals(hdfsPathRef.get(AtlasClient.REFERENCEABLE_ATTRIBUTE_NAME), testPathNormed);
@@ -964,7 +967,7 @@ public class HiveHookIT {
private String assertHDFSPathIsRegistered(String path) throws Exception {
LOG.debug("Searching for hdfs path {}", path);
- return assertEntityIsRegistered(FSDataTypes.HDFS_PATH().toString(), HiveDataModelGenerator.NAME, path, null);
+ return assertEntityIsRegistered(FSDataTypes.HDFS_PATH().toString(), NAME, path, null);
}
@Test
@@ -1014,7 +1017,7 @@ public class HiveHookIT {
ImmutableList<String> cols = ImmutableList.of("id");
runBucketSortQuery(tableName, 5, cols, cols);
- cols = ImmutableList.of("id", HiveDataModelGenerator.NAME);
+ cols = ImmutableList.of("id", NAME);
runBucketSortQuery(tableName, 2, cols, cols);
}
@@ -1077,7 +1080,7 @@ public class HiveHookIT {
assertTableIsRegistered(DEFAULT_DB, tableName);
assertColumnIsRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, tableName), "id"));
- assertColumnIsRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, tableName), HiveDataModelGenerator.NAME));
+ assertColumnIsRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, tableName), NAME));
final String query = String.format("drop table %s ", tableName);
runCommand(query);
@@ -1086,7 +1089,7 @@ public class HiveHookIT {
"id"));
assertColumnIsNotRegistered(HiveMetaStoreBridge
.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, tableName),
- HiveDataModelGenerator.NAME));
+ NAME));
assertTableIsNotRegistered(DEFAULT_DB, tableName);
}
@@ -1110,7 +1113,7 @@ public class HiveHookIT {
HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, dbName, tableNames[0]), "id"));
assertColumnIsNotRegistered(HiveMetaStoreBridge
.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, dbName, tableNames[0]),
- HiveDataModelGenerator.NAME));
+ NAME));
for(int i = 0; i < numTables; i++) {
assertTableIsNotRegistered(dbName, tableNames[i]);
@@ -1175,7 +1178,7 @@ public class HiveHookIT {
assertTableIsRegistered(DEFAULT_DB, viewName);
assertColumnIsRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, viewName), "id"));
- assertColumnIsRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, viewName), HiveDataModelGenerator.NAME));
+ assertColumnIsRegistered(HiveMetaStoreBridge.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, viewName), NAME));
query = String.format("drop view %s ", viewName);
@@ -1185,7 +1188,7 @@ public class HiveHookIT {
"id"));
assertColumnIsNotRegistered(HiveMetaStoreBridge
.getColumnQualifiedName(HiveMetaStoreBridge.getTableQualifiedName(CLUSTER_NAME, DEFAULT_DB, viewName),
- HiveDataModelGenerator.NAME));
+ NAME));
assertTableIsNotRegistered(DEFAULT_DB, viewName);
}
@@ -1349,7 +1352,7 @@ public class HiveHookIT {
if (inputTblName != null) {
Referenceable inputTableRef = new Referenceable(HiveDataTypes.HIVE_TABLE.name(), new HashMap<String, Object>() {{
- put(HiveDataModelGenerator.NAME, inputTblName);
+ put(NAME, inputTblName);
}});
inputs = new ArrayList<Referenceable>();
inputs.add(inputTableRef);
@@ -1357,7 +1360,7 @@ public class HiveHookIT {
List<Referenceable> outputs = null;
if (outputTblName != null) {
Referenceable outputTableRef = new Referenceable(HiveDataTypes.HIVE_TABLE.name(), new HashMap<String, Object>() {{
- put(HiveDataModelGenerator.NAME, outputTblName);
+ put(NAME, outputTblName);
}});
outputs = new ArrayList<Referenceable>();
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/client/src/main/java/org/apache/atlas/AtlasClient.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/atlas/AtlasClient.java b/client/src/main/java/org/apache/atlas/AtlasClient.java
index 7e32cc2..be178dc 100755
--- a/client/src/main/java/org/apache/atlas/AtlasClient.java
+++ b/client/src/main/java/org/apache/atlas/AtlasClient.java
@@ -20,11 +20,14 @@ package org.apache.atlas;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
import org.apache.atlas.security.SecureClientUtils;
import org.apache.atlas.typesystem.Referenceable;
@@ -45,6 +48,7 @@ import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
@@ -54,8 +58,10 @@ import java.net.ConnectException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
-import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
+import java.util.Map;
+
import static org.apache.atlas.security.SecurityProperties.TLS_ENABLED;
/**
@@ -65,9 +71,10 @@ public class AtlasClient {
private static final Logger LOG = LoggerFactory.getLogger(AtlasClient.class);
public static final String NAME = "name";
- public static final String GUID = "GUID";
public static final String TYPE = "type";
public static final String TYPENAME = "typeName";
+ public static final String GUID = "GUID";
+ public static final String ENTITIES = "entities";
public static final String DEFINITION = "definition";
public static final String ERROR = "error";
@@ -340,6 +347,61 @@ public class AtlasClient {
return service;
}
+ public static class EntityResult {
+ private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
+
+ public static final String OP_CREATED = "created";
+ public static final String OP_UPDATED = "updated";
+ public static final String OP_DELETED = "deleted";
+
+ Map<String, List<String>> entities = new HashMap<>();
+
+ public EntityResult() {
+ //For gson
+ }
+
+ public EntityResult(List<String> created, List<String> updated, List<String> deleted) {
+ add(OP_CREATED, created);
+ add(OP_UPDATED, updated);
+ add(OP_DELETED, deleted);
+ }
+
+ private void add(String type, List<String> list) {
+ if (list != null && list.size() > 0) {
+ entities.put(type, list);
+ }
+ }
+
+ private List<String> get(String type) {
+ List<String> list = entities.get(type);
+ if (list == null) {
+ list = new ArrayList<>();
+ }
+ return list;
+ }
+
+ public List<String> getCreatedEntities() {
+ return get(OP_CREATED);
+ }
+
+ public List<String> getUpdateEntities() {
+ return get(OP_UPDATED);
+ }
+
+ public List<String> getDeletedEntities() {
+ return get(OP_DELETED);
+ }
+
+ @Override
+ public String toString() {
+ return gson.toJson(this);
+ }
+
+ public static EntityResult fromString(String json) throws AtlasServiceException {
+ return gson.fromJson(json, EntityResult.class);
+ }
+ }
+
/**
* Return status of the service instance the client is pointing to.
*
@@ -562,11 +624,15 @@ public class AtlasClient {
protected List<String> createEntity(JSONArray entities) throws AtlasServiceException {
LOG.debug("Creating entities: {}", entities);
JSONObject response = callAPI(API.CREATE_ENTITY, entities.toString());
- List<String> results = extractResults(response, GUID, new ExtractOperation<String, String>());
+ List<String> results = extractEntityResult(response).getCreatedEntities();
LOG.debug("Create entities returned results: {}", results);
return results;
}
+ protected EntityResult extractEntityResult(JSONObject response) throws AtlasServiceException {
+ return EntityResult.fromString(response.toString());
+ }
+
/**
* Create the given entity
* @param entitiesAsJson entity(type instance) as json
@@ -601,19 +667,19 @@ public class AtlasClient {
* @return json array of guids which were updated/created
* @throws AtlasServiceException
*/
- public List<String> updateEntities(Referenceable... entities) throws AtlasServiceException {
+ public EntityResult updateEntities(Referenceable... entities) throws AtlasServiceException {
return updateEntities(Arrays.asList(entities));
}
- protected List<String> updateEntities(JSONArray entities) throws AtlasServiceException {
+ protected EntityResult updateEntities(JSONArray entities) throws AtlasServiceException {
LOG.debug("Updating entities: {}", entities);
JSONObject response = callAPI(API.UPDATE_ENTITY, entities.toString());
- List<String> results = extractResults(response, GUID, new ExtractOperation<String, String>());
+ EntityResult results = extractEntityResult(response);
LOG.debug("Update entities returned results: {}", results);
return results;
}
- public List<String> updateEntities(Collection<Referenceable> entities) throws AtlasServiceException {
+ public EntityResult updateEntities(Collection<Referenceable> entities) throws AtlasServiceException {
JSONArray entitiesArray = getEntitiesArray(entities);
return updateEntities(entitiesArray);
}
@@ -625,9 +691,10 @@ public class AtlasClient {
* @param attribute property key
* @param value property value
*/
- public void updateEntityAttribute(final String guid, final String attribute, String value) throws AtlasServiceException {
+ public EntityResult updateEntityAttribute(final String guid, final String attribute, String value)
+ throws AtlasServiceException {
LOG.debug("Updating entity id: {}, attribute name: {}, attribute value: {}", guid, attribute, value);
- callAPIWithRetries(API.UPDATE_ENTITY_PARTIAL, value, new ResourceCreator() {
+ JSONObject response = callAPIWithRetries(API.UPDATE_ENTITY_PARTIAL, value, new ResourceCreator() {
@Override
public WebResource createResource() {
API api = API.UPDATE_ENTITY_PARTIAL;
@@ -636,6 +703,7 @@ public class AtlasClient {
return resource;
}
});
+ return extractEntityResult(response);
}
@VisibleForTesting
@@ -665,10 +733,11 @@ public class AtlasClient {
* @param guid guid
* @param entity entity definition
*/
- public void updateEntity(String guid, Referenceable entity) throws AtlasServiceException {
+ public EntityResult updateEntity(String guid, Referenceable entity) throws AtlasServiceException {
String entityJson = InstanceSerialization.toJson(entity, true);
LOG.debug("Updating entity id {} with {}", guid, entityJson);
- callAPI(API.UPDATE_ENTITY_PARTIAL, entityJson, guid);
+ JSONObject response = callAPI(API.UPDATE_ENTITY_PARTIAL, entityJson, guid);
+ return extractEntityResult(response);
}
/**
@@ -691,8 +760,9 @@ public class AtlasClient {
* @param uniqueAttributeValue Attribute Value that uniquely identifies the entity
* @param entity entity definition
*/
- public String updateEntity(final String entityType, final String uniqueAttributeName, final String uniqueAttributeValue,
- Referenceable entity) throws AtlasServiceException {
+ public EntityResult updateEntity(final String entityType, final String uniqueAttributeName,
+ final String uniqueAttributeValue,
+ Referenceable entity) throws AtlasServiceException {
final API api = API.UPDATE_ENTITY_PARTIAL;
String entityJson = InstanceSerialization.toJson(entity, true);
LOG.debug("Updating entity type: {}, attributeName: {}, attributeValue: {}, entity: {}", entityType,
@@ -707,7 +777,7 @@ public class AtlasClient {
return resource;
}
});
- String result = getString(response, GUID);
+ EntityResult result = extractEntityResult(response);
LOG.debug("Update entity returned result: {}", result);
return result;
}
@@ -724,10 +794,10 @@ public class AtlasClient {
* Delete the specified entities from the repository
*
* @param guids guids of entities to delete
- * @return List of deleted entity guids
+ * @return List of entity ids updated/deleted
* @throws AtlasServiceException
*/
- public List<String> deleteEntities(final String ... guids) throws AtlasServiceException {
+ public EntityResult deleteEntities(final String ... guids) throws AtlasServiceException {
LOG.debug("Deleting entities: {}", guids);
JSONObject jsonResponse = callAPIWithRetries(API.DELETE_ENTITIES, null, new ResourceCreator() {
@Override
@@ -740,7 +810,7 @@ public class AtlasClient {
return resource;
}
});
- List<String> results = extractResults(jsonResponse, GUID, new ExtractOperation<String, String>());
+ EntityResult results = extractEntityResult(jsonResponse);
LOG.debug("Delete entities returned results: {}", results);
return results;
}
@@ -750,9 +820,9 @@ public class AtlasClient {
* @param entityType Type of the entity being deleted
* @param uniqueAttributeName Attribute Name that uniquely identifies the entity
* @param uniqueAttributeValue Attribute Value that uniquely identifies the entity
- * @return List of deleted entity guids(including composite references from that entity)
+ * @return List of entity ids updated/deleted(including composite references from that entity)
*/
- public List<String> deleteEntity(String entityType, String uniqueAttributeName, String uniqueAttributeValue)
+ public EntityResult deleteEntity(String entityType, String uniqueAttributeName, String uniqueAttributeValue)
throws AtlasServiceException {
LOG.debug("Deleting entity type: {}, attributeName: {}, attributeValue: {}", entityType, uniqueAttributeName,
uniqueAttributeValue);
@@ -762,7 +832,7 @@ public class AtlasClient {
resource = resource.queryParam(ATTRIBUTE_NAME, uniqueAttributeName);
resource = resource.queryParam(ATTRIBUTE_VALUE, uniqueAttributeValue);
JSONObject jsonResponse = callAPIWithResource(API.DELETE_ENTITIES, resource, null);
- List<String> results = extractResults(jsonResponse, GUID, new ExtractOperation<String, String>());
+ EntityResult results = extractEntityResult(jsonResponse);
LOG.debug("Delete entities returned results: {}", results);
return results;
}
@@ -901,7 +971,7 @@ public class AtlasClient {
return extractResults(jsonResponse, AtlasClient.EVENTS, new ExtractOperation<EntityAuditEvent, JSONObject>() {
@Override
EntityAuditEvent extractElement(JSONObject element) throws JSONException {
- return EntityAuditEvent.GSON.fromJson(element.toString(), EntityAuditEvent.class);
+ return SerDe.GSON.fromJson(element.toString(), EntityAuditEvent.class);
}
});
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/client/src/main/java/org/apache/atlas/EntityAuditEvent.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/atlas/EntityAuditEvent.java b/client/src/main/java/org/apache/atlas/EntityAuditEvent.java
index 460f708..29a04ab 100644
--- a/client/src/main/java/org/apache/atlas/EntityAuditEvent.java
+++ b/client/src/main/java/org/apache/atlas/EntityAuditEvent.java
@@ -18,16 +18,14 @@
package org.apache.atlas;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
+import org.apache.atlas.typesystem.IReferenceableInstance;
+import org.apache.atlas.typesystem.json.InstanceSerialization;
import org.apache.commons.lang.StringUtils;
/**
* Structure of entity audit event
*/
public class EntityAuditEvent {
- public static final Gson GSON = new GsonBuilder().create();
-
public enum EntityAuditAction {
ENTITY_CREATE, ENTITY_UPDATE, ENTITY_DELETE, TAG_ADD, TAG_DELETE
}
@@ -38,16 +36,19 @@ public class EntityAuditEvent {
private EntityAuditAction action;
private String details;
private String eventKey;
+ private IReferenceableInstance entityDefinition;
public EntityAuditEvent() {
}
- public EntityAuditEvent(String entityId, Long ts, String user, EntityAuditAction action, String details) {
+ public EntityAuditEvent(String entityId, Long ts, String user, EntityAuditAction action, String details,
+ IReferenceableInstance entityDefinition) throws AtlasException {
this.entityId = entityId;
this.timestamp = ts;
this.user = user;
this.action = action;
this.details = details;
+ this.entityDefinition = entityDefinition;
}
@Override
@@ -62,10 +63,12 @@ public class EntityAuditEvent {
EntityAuditEvent otherEvent = (EntityAuditEvent) other;
return StringUtils.equals(entityId, otherEvent.entityId) &&
- (timestamp == otherEvent.timestamp) &&
- StringUtils.equals(user, otherEvent.user) && (action == otherEvent.action) &&
- StringUtils.equals(details, otherEvent.details) &&
- StringUtils.equals(eventKey, otherEvent.eventKey);
+ (timestamp == otherEvent.timestamp) &&
+ StringUtils.equals(user, otherEvent.user) &&
+ (action == otherEvent.action) &&
+ StringUtils.equals(details, otherEvent.details) &&
+ StringUtils.equals(eventKey, otherEvent.eventKey) &&
+ StringUtils.equals(getEntityDefinitionString(), otherEvent.getEntityDefinitionString());
}
@Override
@@ -75,11 +78,11 @@ public class EntityAuditEvent {
@Override
public String toString() {
- return GSON.toJson(this);
+ return SerDe.GSON.toJson(this);
}
public static EntityAuditEvent fromString(String eventString) {
- return GSON.fromJson(eventString, EntityAuditEvent.class);
+ return SerDe.GSON.fromJson(eventString, EntityAuditEvent.class);
}
public String getEntityId() {
@@ -129,4 +132,19 @@ public class EntityAuditEvent {
public void setEventKey(String eventKey) {
this.eventKey = eventKey;
}
+
+ public IReferenceableInstance getEntityDefinition() {
+ return entityDefinition;
+ }
+
+ public String getEntityDefinitionString() {
+ if (entityDefinition != null) {
+ return InstanceSerialization.toJson(entityDefinition, true);
+ }
+ return null;
+ }
+
+ public void setEntityDefinition(String entityDefinition) {
+ this.entityDefinition = InstanceSerialization.fromJsonReferenceable(entityDefinition, true);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/client/src/main/java/org/apache/atlas/SerDe.java
----------------------------------------------------------------------
diff --git a/client/src/main/java/org/apache/atlas/SerDe.java b/client/src/main/java/org/apache/atlas/SerDe.java
new file mode 100644
index 0000000..6b7478a
--- /dev/null
+++ b/client/src/main/java/org/apache/atlas/SerDe.java
@@ -0,0 +1,79 @@
+/**
+ * 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;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import org.apache.atlas.typesystem.IReferenceableInstance;
+import org.apache.atlas.typesystem.IStruct;
+import org.apache.atlas.typesystem.Referenceable;
+import org.apache.atlas.typesystem.Struct;
+import org.apache.atlas.typesystem.json.InstanceSerialization;
+
+import java.lang.reflect.Type;
+
+public class SerDe {
+ public static final Gson GSON = new GsonBuilder().
+ registerTypeAdapter(IStruct.class, new StructDeserializer()).
+ registerTypeAdapter(IReferenceableInstance.class, new ReferenceableSerializerDeserializer()).
+ registerTypeAdapter(Referenceable.class, new ReferenceableSerializerDeserializer()).
+ create();
+
+ /**
+ * Serde for Struct used by AbstractNotificationConsumer.GSON.
+ */
+ public static final class StructDeserializer implements JsonDeserializer<IStruct>, JsonSerializer<IStruct> {
+ @Override
+ public IStruct deserialize(final JsonElement json, final Type type,
+ final JsonDeserializationContext context) {
+ return context.deserialize(json, Struct.class);
+ }
+
+ @Override
+ public JsonElement serialize(IStruct src, Type typeOfSrc, JsonSerializationContext context) {
+ String instanceJson = InstanceSerialization.toJson(src, true);
+ return new JsonParser().parse(instanceJson).getAsJsonObject();
+ }
+ }
+
+ /**
+ * Serde for Referenceable used by AbstractNotificationConsumer.GSON.
+ */
+ public static final class ReferenceableSerializerDeserializer implements JsonDeserializer<IStruct>,
+ JsonSerializer<IReferenceableInstance> {
+ @Override
+ public IReferenceableInstance deserialize(final JsonElement json, final Type type,
+ final JsonDeserializationContext context) {
+
+ return InstanceSerialization.fromJsonReferenceable(json.toString(), true);
+ }
+
+ @Override
+ public JsonElement serialize(IReferenceableInstance src, Type typeOfSrc, JsonSerializationContext context) {
+ String instanceJson = InstanceSerialization.toJson(src, true);
+ return new JsonParser().parse(instanceJson).getAsJsonObject();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/client/src/test/java/org/apache/atlas/AtlasClientTest.java
----------------------------------------------------------------------
diff --git a/client/src/test/java/org/apache/atlas/AtlasClientTest.java b/client/src/test/java/org/apache/atlas/AtlasClientTest.java
index 0e80573..77a387f 100644
--- a/client/src/test/java/org/apache/atlas/AtlasClientTest.java
+++ b/client/src/test/java/org/apache/atlas/AtlasClientTest.java
@@ -21,8 +21,12 @@ import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
+import org.apache.atlas.typesystem.Referenceable;
+import org.apache.atlas.typesystem.json.InstanceSerialization;
import org.apache.commons.configuration.Configuration;
import org.apache.hadoop.security.UserGroupInformation;
+import org.codehaus.jettison.json.JSONObject;
+import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.BeforeMethod;
@@ -33,9 +37,12 @@ import javax.ws.rs.core.UriBuilder;
import java.net.ConnectException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.List;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -76,6 +83,25 @@ public class AtlasClientTest {
assertTrue(atlasClient.isServerReady());
}
+ @Test
+ public void testCreateEntity() throws Exception {
+ setupRetryParams();
+ AtlasClient atlasClient = new AtlasClient(service, configuration);
+
+ WebResource.Builder builder = setupBuilder(AtlasClient.API.CREATE_ENTITY, service);
+ ClientResponse response = mock(ClientResponse.class);
+ when(response.getStatus()).thenReturn(Response.Status.CREATED.getStatusCode());
+
+ JSONObject jsonResponse = new JSONObject(new AtlasClient.EntityResult(Arrays.asList("id"), null, null).toString());
+ when(response.getEntity(String.class)).thenReturn(jsonResponse.toString());
+ String entityJson = InstanceSerialization.toJson(new Referenceable("type"), true);
+ when(builder.method(anyString(), Matchers.<Class>any(), anyString())).thenReturn(response);
+
+ List<String> ids = atlasClient.createEntity(entityJson);
+ assertEquals(ids.size(), 1);
+ assertEquals(ids.get(0), "id");
+ }
+
private WebResource.Builder setupBuilder(AtlasClient.API api, WebResource webResource) {
when(webResource.path(api.getPath())).thenReturn(service);
WebResource.Builder builder = getBuilder(service);
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/notification/src/main/java/org/apache/atlas/notification/MessageVersion.java
----------------------------------------------------------------------
diff --git a/notification/src/main/java/org/apache/atlas/notification/MessageVersion.java b/notification/src/main/java/org/apache/atlas/notification/MessageVersion.java
index 3f16a9a..6ef407a 100644
--- a/notification/src/main/java/org/apache/atlas/notification/MessageVersion.java
+++ b/notification/src/main/java/org/apache/atlas/notification/MessageVersion.java
@@ -97,6 +97,11 @@ public class MessageVersion implements Comparable<MessageVersion> {
}
+ @Override
+ public String toString() {
+ return "MessageVersion[version=" + version + "]";
+ }
+
// ----- helper methods --------------------------------------------------
/**
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/notification/src/main/java/org/apache/atlas/notification/NotificationInterface.java
----------------------------------------------------------------------
diff --git a/notification/src/main/java/org/apache/atlas/notification/NotificationInterface.java b/notification/src/main/java/org/apache/atlas/notification/NotificationInterface.java
index 384f383..ef8ee27 100644
--- a/notification/src/main/java/org/apache/atlas/notification/NotificationInterface.java
+++ b/notification/src/main/java/org/apache/atlas/notification/NotificationInterface.java
@@ -17,11 +17,11 @@
*/
package org.apache.atlas.notification;
+import com.google.gson.reflect.TypeToken;
import org.apache.atlas.notification.entity.EntityMessageDeserializer;
import org.apache.atlas.notification.entity.EntityNotification;
import org.apache.atlas.notification.hook.HookMessageDeserializer;
import org.apache.atlas.notification.hook.HookNotification;
-import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.List;
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/notification/src/main/java/org/apache/atlas/notification/VersionedMessageDeserializer.java
----------------------------------------------------------------------
diff --git a/notification/src/main/java/org/apache/atlas/notification/VersionedMessageDeserializer.java b/notification/src/main/java/org/apache/atlas/notification/VersionedMessageDeserializer.java
index 290be59..cc2099e 100644
--- a/notification/src/main/java/org/apache/atlas/notification/VersionedMessageDeserializer.java
+++ b/notification/src/main/java/org/apache/atlas/notification/VersionedMessageDeserializer.java
@@ -31,7 +31,7 @@ import java.lang.reflect.Type;
public abstract class VersionedMessageDeserializer<T> implements MessageDeserializer<T> {
public static final String VERSION_MISMATCH_MSG =
- "Notification message version mismatch. Expected %s but recieved %s";
+ "Notification message version mismatch. Expected %s but recieved %s. Message %s";
private final Type versionedMessageType;
private final MessageVersion expectedVersion;
@@ -90,18 +90,16 @@ public abstract class VersionedMessageDeserializer<T> implements MessageDeserial
// message has newer version
if (comp > 0) {
- String msg = String.format(VERSION_MISMATCH_MSG, expectedVersion, versionedMessage.getVersion());
+ String msg =
+ String.format(VERSION_MISMATCH_MSG, expectedVersion, versionedMessage.getVersion(), messageJson);
notificationLogger.error(msg);
- notificationLogger.info(messageJson);
throw new IncompatibleVersionException(msg);
}
// message has older version
if (comp < 0) {
- notificationLogger.info(
- String.format(VERSION_MISMATCH_MSG, expectedVersion, versionedMessage.getVersion()));
-
- notificationLogger.info(messageJson);
+ notificationLogger.info(String.format(VERSION_MISMATCH_MSG, expectedVersion, versionedMessage.getVersion(),
+ messageJson));
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/notification/src/main/java/org/apache/atlas/notification/entity/NotificationEntityChangeListener.java
----------------------------------------------------------------------
diff --git a/notification/src/main/java/org/apache/atlas/notification/entity/NotificationEntityChangeListener.java b/notification/src/main/java/org/apache/atlas/notification/entity/NotificationEntityChangeListener.java
deleted file mode 100644
index 300cbb5..0000000
--- a/notification/src/main/java/org/apache/atlas/notification/entity/NotificationEntityChangeListener.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.atlas.notification.entity;
-
-import com.google.inject.Inject;
-import org.apache.atlas.AtlasException;
-import org.apache.atlas.listener.EntityChangeListener;
-import org.apache.atlas.notification.NotificationInterface;
-import org.apache.atlas.typesystem.IReferenceableInstance;
-import org.apache.atlas.typesystem.IStruct;
-import org.apache.atlas.typesystem.ITypedReferenceableInstance;
-import org.apache.atlas.typesystem.Referenceable;
-import org.apache.atlas.typesystem.types.TypeSystem;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Listen to the repository for entity changes and produce entity change notifications.
- */
-public class NotificationEntityChangeListener implements EntityChangeListener {
-
- private final NotificationInterface notificationInterface;
- private final TypeSystem typeSystem;
-
-
- // ----- Constructors ------------------------------------------------------
-
- /**
- * Construct a NotificationEntityChangeListener.
- *
- * @param notificationInterface the notification framework interface
- * @param typeSystem the Atlas type system
- */
- @Inject
- public NotificationEntityChangeListener(NotificationInterface notificationInterface, TypeSystem typeSystem) {
- this.notificationInterface = notificationInterface;
- this.typeSystem = typeSystem;
- }
-
-
- // ----- EntityChangeListener ----------------------------------------------
-
- @Override
- public void onEntitiesAdded(Collection<ITypedReferenceableInstance> entities) throws AtlasException {
- notifyOfEntityEvent(entities, EntityNotification.OperationType.ENTITY_CREATE);
- }
-
- @Override
- public void onEntitiesUpdated(Collection<ITypedReferenceableInstance> entities) throws AtlasException {
- notifyOfEntityEvent(entities, EntityNotification.OperationType.ENTITY_UPDATE);
- }
-
- @Override
- public void onTraitAdded(ITypedReferenceableInstance entity, IStruct trait) throws AtlasException {
- notifyOfEntityEvent(Collections.singleton(entity), EntityNotification.OperationType.TRAIT_ADD);
- }
-
- @Override
- public void onTraitDeleted(ITypedReferenceableInstance entity, String traitName) throws AtlasException {
- notifyOfEntityEvent(Collections.singleton(entity), EntityNotification.OperationType.TRAIT_DELETE);
- }
-
- @Override
- public void onEntitiesDeleted(Collection<ITypedReferenceableInstance> entities) throws AtlasException {
- notifyOfEntityEvent(entities, EntityNotification.OperationType.ENTITY_DELETE);
- }
-
-
- // ----- helper methods -------------------------------------------------
-
-
- // send notification of entity change
- private void notifyOfEntityEvent(Collection<ITypedReferenceableInstance> entityDefinitions,
- EntityNotification.OperationType operationType) throws AtlasException {
- List<EntityNotification> messages = new LinkedList<>();
-
- for (IReferenceableInstance entityDefinition : entityDefinitions) {
- Referenceable entity = new Referenceable(entityDefinition);
-
- EntityNotificationImpl notification =
- new EntityNotificationImpl(entity, operationType, typeSystem);
-
- messages.add(notification);
- }
-
- notificationInterface.send(NotificationInterface.NotificationType.ENTITIES, messages);
- }
-}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/notification/src/test/java/org/apache/atlas/notification/AbstractNotificationConsumerTest.java
----------------------------------------------------------------------
diff --git a/notification/src/test/java/org/apache/atlas/notification/AbstractNotificationConsumerTest.java b/notification/src/test/java/org/apache/atlas/notification/AbstractNotificationConsumerTest.java
index e8b55ef..0c8990f 100644
--- a/notification/src/test/java/org/apache/atlas/notification/AbstractNotificationConsumerTest.java
+++ b/notification/src/test/java/org/apache/atlas/notification/AbstractNotificationConsumerTest.java
@@ -27,9 +27,13 @@ import java.lang.reflect.Type;
import java.util.LinkedList;
import java.util.List;
+import static org.mockito.Matchers.endsWith;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import static org.testng.Assert.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
/**
* AbstractNotificationConsumer tests.
@@ -110,17 +114,17 @@ public class AbstractNotificationConsumerTest {
assertTrue(consumer.hasNext());
assertEquals(new TestMessage("sValue2", 98), consumer.next());
- verify(logger).info(json2);
+ verify(logger).info(endsWith(json2));
assertTrue(consumer.hasNext());
assertEquals(new TestMessage("sValue3", 97), consumer.next());
- verify(logger).info(json3);
+ verify(logger).info(endsWith(json3));
assertTrue(consumer.hasNext());
assertEquals(new TestMessage("sValue4", 96), consumer.next());
- verify(logger).info(json4);
+ verify(logger).info(endsWith(json4));
assertFalse(consumer.hasNext());
}
@@ -154,7 +158,7 @@ public class AbstractNotificationConsumerTest {
consumer.next();
fail("Expected VersionMismatchException!");
} catch (IncompatibleVersionException e) {
- verify(logger).info(json2);
+ verify(logger).error(endsWith(json2));
}
assertFalse(consumer.hasNext());
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/release-log.txt
----------------------------------------------------------------------
diff --git a/release-log.txt b/release-log.txt
index fd17292..0402b49 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -3,6 +3,7 @@ Apache Atlas Release Notes
--trunk - unreleased
INCOMPATIBLE CHANGES:
+ATLAS-716 Entity update/delete notifications (shwethags)
ATLAS-619 Canonicalize hive queries (sumasai)
ATLAS-497 Simple Authorization (saqeeb.s via yhemanth)
ATLAS-661 REST API Authentication (nixonrodrigues via yhemanth)
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java b/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
index 540c308..43e9f85 100755
--- a/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
+++ b/repository/src/main/java/org/apache/atlas/repository/MetadataRepository.java
@@ -18,6 +18,7 @@
package org.apache.atlas.repository;
+import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasException;
import org.apache.atlas.typesystem.ITypedReferenceableInstance;
import org.apache.atlas.typesystem.ITypedStruct;
@@ -26,7 +27,6 @@ import org.apache.atlas.typesystem.exception.EntityNotFoundException;
import org.apache.atlas.typesystem.exception.TraitNotFoundException;
import org.apache.atlas.typesystem.types.AttributeInfo;
import org.apache.atlas.typesystem.types.IDataType;
-import org.apache.atlas.typesystem.types.TypeUtils;
import java.util.List;
@@ -111,7 +111,7 @@ public interface MetadataRepository {
* @return guids of deleted entities
* @throws RepositoryException
*/
- TypeUtils.Pair<List<String>, List<ITypedReferenceableInstance>> deleteEntities(List<String> guids) throws RepositoryException;
+ AtlasClient.EntityResult deleteEntities(List<String> guids) throws RepositoryException;
// Trait management functions
@@ -147,13 +147,13 @@ public interface MetadataRepository {
* Adds/Updates the property to the entity that corresponds to the GUID
* Supports only primitive attribute/Class Id updations.
*/
- TypeUtils.Pair<List<String>, List<String>> updatePartial(ITypedReferenceableInstance entity) throws RepositoryException;
+ AtlasClient.EntityResult updatePartial(ITypedReferenceableInstance entity) throws RepositoryException;
/**
* Adds the property to the entity that corresponds to the GUID
* @param entitiesToBeUpdated The entities to be updated
*/
- TypeUtils.Pair<List<String>, List<String>> updateEntities(ITypedReferenceableInstance... entitiesToBeUpdated) throws RepositoryException;
+ AtlasClient.EntityResult updateEntities(ITypedReferenceableInstance... entitiesToBeUpdated) throws RepositoryException;
/**
* Returns the entity for the given type and qualified name
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/audit/EntityAuditListener.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/audit/EntityAuditListener.java b/repository/src/main/java/org/apache/atlas/repository/audit/EntityAuditListener.java
index 5b4bdbf..958ecaf 100644
--- a/repository/src/main/java/org/apache/atlas/repository/audit/EntityAuditListener.java
+++ b/repository/src/main/java/org/apache/atlas/repository/audit/EntityAuditListener.java
@@ -55,8 +55,9 @@ public class EntityAuditListener implements EntityChangeListener {
}
private EntityAuditEvent createEvent(ITypedReferenceableInstance entity, long ts,
- EntityAuditEvent.EntityAuditAction action, String details) {
- return new EntityAuditEvent(entity.getId()._getId(), ts, RequestContext.get().getUser(), action, details);
+ EntityAuditEvent.EntityAuditAction action, String details)
+ throws AtlasException {
+ return new EntityAuditEvent(entity.getId()._getId(), ts, RequestContext.get().getUser(), action, details, entity);
}
@Override
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/audit/HBaseBasedAuditRepository.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/audit/HBaseBasedAuditRepository.java b/repository/src/main/java/org/apache/atlas/repository/audit/HBaseBasedAuditRepository.java
index 8f11322..22d71df 100644
--- a/repository/src/main/java/org/apache/atlas/repository/audit/HBaseBasedAuditRepository.java
+++ b/repository/src/main/java/org/apache/atlas/repository/audit/HBaseBasedAuditRepository.java
@@ -78,6 +78,7 @@ public class HBaseBasedAuditRepository implements Service, EntityAuditRepository
public static final byte[] COLUMN_ACTION = Bytes.toBytes("action");
public static final byte[] COLUMN_DETAIL = Bytes.toBytes("detail");
public static final byte[] COLUMN_USER = Bytes.toBytes("user");
+ public static final byte[] COLUMN_DEFINITION = Bytes.toBytes("def");
private TableName tableName;
private Connection connection;
@@ -110,6 +111,7 @@ public class HBaseBasedAuditRepository implements Service, EntityAuditRepository
addColumn(put, COLUMN_ACTION, event.getAction());
addColumn(put, COLUMN_USER, event.getUser());
addColumn(put, COLUMN_DETAIL, event.getDetails());
+ addColumn(put, COLUMN_DEFINITION, event.getEntityDefinitionString());
puts.add(put);
}
table.put(puts);
@@ -183,6 +185,7 @@ public class HBaseBasedAuditRepository implements Service, EntityAuditRepository
event.setUser(getResultString(result, COLUMN_USER));
event.setAction(EntityAuditEvent.EntityAuditAction.valueOf(getResultString(result, COLUMN_ACTION)));
event.setDetails(getResultString(result, COLUMN_DETAIL));
+ event.setEntityDefinition(getResultString(result, COLUMN_DEFINITION));
events.add(event);
}
LOG.info("Got events for entity id {}, starting timestamp {}, #records {}", entityId, startKey, events.size());
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/graph/DeleteHandler.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/DeleteHandler.java b/repository/src/main/java/org/apache/atlas/repository/graph/DeleteHandler.java
index a9e4f39..91f9bd0 100644
--- a/repository/src/main/java/org/apache/atlas/repository/graph/DeleteHandler.java
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/DeleteHandler.java
@@ -47,15 +47,16 @@ import static org.apache.atlas.repository.graph.GraphHelper.string;
public abstract class DeleteHandler {
public static final Logger LOG = LoggerFactory.getLogger(DeleteHandler.class);
- private static final GraphHelper graphHelper = GraphHelper.getInstance();
+ protected static final GraphHelper graphHelper = GraphHelper.getInstance();
protected TypeSystem typeSystem;
private boolean shouldUpdateReverseAttribute;
+ private boolean softDelete;
- public DeleteHandler(TypeSystem typeSystem, boolean shouldUpdateReverseAttribute) {
+ public DeleteHandler(TypeSystem typeSystem, boolean shouldUpdateReverseAttribute, boolean softDelete) {
this.typeSystem = typeSystem;
this.shouldUpdateReverseAttribute = shouldUpdateReverseAttribute;
-
+ this.softDelete = softDelete;
}
/**
@@ -64,16 +65,22 @@ public abstract class DeleteHandler {
* @throws AtlasException
*/
public void deleteEntity(Vertex instanceVertex) throws AtlasException {
+ RequestContext requestContext = RequestContext.get();
String guid = GraphHelper.getIdFromVertex(instanceVertex);
+ Id.EntityState state = GraphHelper.getState(instanceVertex);
+ if (requestContext.getDeletedEntityIds().contains(guid) || state == Id.EntityState.DELETED) {
+ LOG.debug("Skipping deleting {} as its already deleted", guid);
+ return;
+ }
String typeName = GraphHelper.getTypeName(instanceVertex);
- RequestContext.get().recordDeletedEntity(guid, typeName);
+ requestContext.recordEntityDelete(guid, typeName);
deleteAllTraits(instanceVertex);
- deleteTypeVertex(instanceVertex);
+ deleteTypeVertex(instanceVertex, false);
}
- protected abstract void deleteEdge(Edge edge) throws AtlasException;
+ protected abstract void deleteEdge(Edge edge, boolean force) throws AtlasException;
/**
* Deletes a type vertex - can be entity(class type) or just vertex(struct/trait type)
@@ -81,11 +88,11 @@ public abstract class DeleteHandler {
* @param typeCategory
* @throws AtlasException
*/
- protected void deleteTypeVertex(Vertex instanceVertex, DataTypes.TypeCategory typeCategory) throws AtlasException {
+ protected void deleteTypeVertex(Vertex instanceVertex, DataTypes.TypeCategory typeCategory, boolean force) throws AtlasException {
switch (typeCategory) {
case STRUCT:
case TRAIT:
- deleteTypeVertex(instanceVertex);
+ deleteTypeVertex(instanceVertex, force);
break;
case CLASS:
@@ -102,7 +109,7 @@ public abstract class DeleteHandler {
* @param instanceVertex
* @throws AtlasException
*/
- protected void deleteTypeVertex(Vertex instanceVertex) throws AtlasException {
+ protected void deleteTypeVertex(Vertex instanceVertex, boolean force) throws AtlasException {
LOG.debug("Deleting {}", string(instanceVertex));
String typeName = GraphHelper.getTypeName(instanceVertex);
IDataType type = typeSystem.getDataType(IDataType.class, typeName);
@@ -115,12 +122,12 @@ public abstract class DeleteHandler {
switch (attributeInfo.dataType().getTypeCategory()) {
case CLASS:
//If its class attribute, delete the reference
- deleteReference(instanceVertex, edgeLabel, DataTypes.TypeCategory.CLASS, attributeInfo.isComposite);
+ deleteEdgeReference(instanceVertex, edgeLabel, DataTypes.TypeCategory.CLASS, attributeInfo.isComposite);
break;
case STRUCT:
//If its struct attribute, delete the reference
- deleteReference(instanceVertex, edgeLabel, DataTypes.TypeCategory.STRUCT);
+ deleteEdgeReference(instanceVertex, edgeLabel, DataTypes.TypeCategory.STRUCT, false);
break;
case ARRAY:
@@ -133,7 +140,7 @@ public abstract class DeleteHandler {
if (edges != null) {
while (edges.hasNext()) {
Edge edge = edges.next();
- deleteReference(edge, elementType, attributeInfo);
+ deleteEdgeReference(edge, elementType.getTypeCategory(), attributeInfo.isComposite, false);
}
}
}
@@ -151,22 +158,31 @@ public abstract class DeleteHandler {
if (keys != null) {
for (String key : keys) {
String mapEdgeLabel = GraphHelper.getQualifiedNameForMapKey(edgeLabel, key);
- deleteReference(instanceVertex, mapEdgeLabel, valueTypeCategory, attributeInfo.isComposite);
+ deleteEdgeReference(instanceVertex, mapEdgeLabel, valueTypeCategory, attributeInfo.isComposite);
}
}
}
}
}
- deleteVertex(instanceVertex, type.getTypeCategory());
+ deleteVertex(instanceVertex, force);
}
- public void deleteReference(Edge edge, IDataType dataType, AttributeInfo attributeInfo) throws AtlasException {
- deleteReference(edge, dataType.getTypeCategory(), attributeInfo.isComposite);
- }
-
- public void deleteReference(Edge edge, DataTypes.TypeCategory typeCategory, boolean isComposite) throws AtlasException {
+ /**
+ * Force delete is used to remove struct/trait in case of entity updates
+ * @param edge
+ * @param typeCategory
+ * @param isComposite
+ * @param forceDeleteStructTrait
+ * @return returns true if the edge reference is hard deleted
+ * @throws AtlasException
+ */
+ public boolean deleteEdgeReference(Edge edge, DataTypes.TypeCategory typeCategory, boolean isComposite,
+ boolean forceDeleteStructTrait) throws AtlasException {
LOG.debug("Deleting {}", string(edge));
+ boolean forceDelete =
+ (typeCategory == DataTypes.TypeCategory.STRUCT || typeCategory == DataTypes.TypeCategory.TRAIT)
+ ? forceDeleteStructTrait : false;
if (typeCategory == DataTypes.TypeCategory.STRUCT || typeCategory == DataTypes.TypeCategory.TRAIT
|| (typeCategory == DataTypes.TypeCategory.CLASS && isComposite)) {
//If the vertex is of type struct/trait, delete the edge and then the reference vertex as the vertex is not shared by any other entities.
@@ -175,32 +191,28 @@ public abstract class DeleteHandler {
Vertex vertexForDelete = edge.getVertex(Direction.IN);
//If deleting the edge and then the in vertex, reverse attribute shouldn't be updated
- deleteEdge(edge, false);
- deleteTypeVertex(vertexForDelete, typeCategory);
+ deleteEdge(edge, false, forceDelete);
+ deleteTypeVertex(vertexForDelete, typeCategory, forceDelete);
} else {
//If the vertex is of type class, and its not a composite attributes, the reference vertex' lifecycle is not controlled
//through this delete. Hence just remove the reference edge. Leave the reference vertex as is
//If deleting just the edge, reverse attribute should be updated for any references
//For example, for the department type system, if the person's manager edge is deleted, subordinates of manager should be updated
- deleteEdge(edge, true);
+ deleteEdge(edge, true, false);
}
+ return !softDelete || forceDelete;
}
- public void deleteReference(Vertex instanceVertex, String edgeLabel, DataTypes.TypeCategory typeCategory)
- throws AtlasException {
- deleteReference(instanceVertex, edgeLabel, typeCategory, false);
- }
-
- public void deleteReference(Vertex instanceVertex, String edgeLabel, DataTypes.TypeCategory typeCategory,
- boolean isComposite) throws AtlasException {
- Edge edge = GraphHelper.getEdgeForLabel(instanceVertex, edgeLabel);
+ public void deleteEdgeReference(Vertex outVertex, String edgeLabel, DataTypes.TypeCategory typeCategory,
+ boolean isComposite) throws AtlasException {
+ Edge edge = GraphHelper.getEdgeForLabel(outVertex, edgeLabel);
if (edge != null) {
- deleteReference(edge, typeCategory, isComposite);
+ deleteEdgeReference(edge, typeCategory, isComposite, false);
}
}
- protected void deleteEdge(Edge edge, boolean updateReverseAttribute) throws AtlasException {
+ protected void deleteEdge(Edge edge, boolean updateReverseAttribute, boolean force) throws AtlasException {
//update reverse attribute
if (updateReverseAttribute) {
AttributeInfo attributeInfo = getAttributeForEdge(edge.getLabel());
@@ -210,28 +222,28 @@ public abstract class DeleteHandler {
}
}
- deleteEdge(edge);
+ deleteEdge(edge, force);
}
- protected void deleteVertex(Vertex instanceVertex, DataTypes.TypeCategory typeCategory) throws AtlasException {
+ protected void deleteVertex(Vertex instanceVertex, boolean force) throws AtlasException {
//Update external references(incoming edges) to this vertex
LOG.debug("Setting the external references to {} to null(removing edges)", string(instanceVertex));
Iterator<Edge> edges = instanceVertex.getEdges(Direction.IN).iterator();
while(edges.hasNext()) {
Edge edge = edges.next();
- String edgeState = edge.getProperty(Constants.STATE_PROPERTY_KEY);
- if (Id.EntityState.ACTIVE.name().equals(edgeState)) {
+ Id.EntityState edgeState = GraphHelper.getState(edge);
+ if (edgeState == Id.EntityState.ACTIVE) {
//Delete only the active edge references
AttributeInfo attribute = getAttributeForEdge(edge.getLabel());
+ //TODO use delete edge instead??
deleteEdgeBetweenVertices(edge.getVertex(Direction.OUT), edge.getVertex(Direction.IN), attribute.name);
- deleteEdge(edge);
}
}
- _deleteVertex(instanceVertex);
+ _deleteVertex(instanceVertex, force);
}
- protected abstract void _deleteVertex(Vertex instanceVertex);
+ protected abstract void _deleteVertex(Vertex instanceVertex, boolean force);
/**
* Deletes the edge between outvertex and inVertex. The edge is for attribute attributeName of outVertex
@@ -245,7 +257,8 @@ public abstract class DeleteHandler {
attributeName);
String typeName = GraphHelper.getTypeName(outVertex);
String outId = GraphHelper.getIdFromVertex(outVertex);
- if (outId != null && RequestContext.get().isDeletedEntity(outId)) {
+ Id.EntityState state = GraphHelper.getState(outVertex);
+ if ((outId != null && RequestContext.get().isDeletedEntity(outId)) || state == Id.EntityState.DELETED) {
//If the reference vertex is marked for deletion, skip updating the reference
return;
}
@@ -261,8 +274,10 @@ public abstract class DeleteHandler {
//If its class attribute, its the only edge between two vertices
if (attributeInfo.multiplicity.nullAllowed()) {
edge = GraphHelper.getEdgeForLabel(outVertex, edgeLabel);
- }
- else {
+ if (shouldUpdateReverseAttribute) {
+ GraphHelper.setProperty(outVertex, propertyName, null);
+ }
+ } else {
// Cannot unset a required attribute.
throw new NullRequiredAttributeException("Cannot unset required attribute " + GraphHelper.getQualifiedFieldName(type, attributeName) +
" on " + string(outVertex) + " edge = " + edgeLabel);
@@ -275,23 +290,26 @@ public abstract class DeleteHandler {
if (elements != null) {
elements = new ArrayList<>(elements); //Make a copy, else list.remove reflects on titan.getProperty()
for (String elementEdgeId : elements) {
- Edge elementEdge = graphHelper.getEdgeById(elementEdgeId);
+ Edge elementEdge = graphHelper.getEdgeByEdgeId(outVertex, edgeLabel, elementEdgeId);
if (elementEdge == null) {
continue;
}
Vertex elementVertex = elementEdge.getVertex(Direction.IN);
if (elementVertex.getId().toString().equals(inVertex.getId().toString())) {
- if (attributeInfo.multiplicity.nullAllowed() || elements.size() > attributeInfo.multiplicity.lower) {
- edge = elementEdge;
- }
- else {
+ edge = elementEdge;
+
+ //TODO element.size includes deleted items as well. should exclude
+ if (!attributeInfo.multiplicity.nullAllowed()
+ && elements.size() <= attributeInfo.multiplicity.lower) {
// Deleting this edge would violate the attribute's lower bound.
throw new NullRequiredAttributeException(
- "Cannot remove array element from required attribute " +
- GraphHelper.getQualifiedFieldName(type, attributeName) + " on " + string(outVertex) + " " + string(elementEdge));
+ "Cannot remove array element from required attribute " +
+ GraphHelper.getQualifiedFieldName(type, attributeName) + " on "
+ + string(outVertex) + " " + string(elementEdge));
}
- if (shouldUpdateReverseAttribute || attributeInfo.isComposite) {
+
+ if (shouldUpdateReverseAttribute) {
//if composite attribute, remove the reference as well. else, just remove the edge
//for example, when table is deleted, process still references the table
//but when column is deleted, table will not reference the deleted column
@@ -299,8 +317,9 @@ public abstract class DeleteHandler {
attributeName);
elements.remove(elementEdge.getId().toString());
GraphHelper.setProperty(outVertex, propertyName, elements);
+ break;
+
}
- break;
}
}
}
@@ -312,11 +331,12 @@ public abstract class DeleteHandler {
if (keys != null) {
keys = new ArrayList<>(keys); //Make a copy, else list.remove reflects on titan.getProperty()
for (String key : keys) {
- String keyPropertyName = propertyName + "." + key;
+ String keyPropertyName = GraphHelper.getQualifiedNameForMapKey(propertyName, key);
String mapEdgeId = outVertex.getProperty(keyPropertyName);
- Edge mapEdge = graphHelper.getEdgeById(mapEdgeId);
+ Edge mapEdge = graphHelper.getEdgeByEdgeId(outVertex, keyPropertyName, mapEdgeId);
Vertex mapVertex = mapEdge.getVertex(Direction.IN);
if (mapVertex.getId().toString().equals(inVertex.getId().toString())) {
+ //TODO keys.size includes deleted items as well. should exclude
if (attributeInfo.multiplicity.nullAllowed() || keys.size() > attributeInfo.multiplicity.lower) {
edge = mapEdge;
}
@@ -327,7 +347,7 @@ public abstract class DeleteHandler {
GraphHelper.getQualifiedFieldName(type, attributeName) + " on " + string(outVertex) + " " + string(mapEdge));
}
- if (shouldUpdateReverseAttribute || attributeInfo.isComposite) {
+ if (shouldUpdateReverseAttribute) {
//remove this key
LOG.debug("Removing edge {}, key {} from the map attribute {}", string(mapEdge), key,
attributeName);
@@ -351,9 +371,11 @@ public abstract class DeleteHandler {
}
if (edge != null) {
- deleteEdge(edge);
+ deleteEdge(edge, false);
+ RequestContext requestContext = RequestContext.get();
GraphHelper.setProperty(outVertex, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY,
- RequestContext.get().getRequestTime());
+ requestContext.getRequestTime());
+ requestContext.recordEntityUpdate(outId);
}
}
@@ -389,7 +411,7 @@ public abstract class DeleteHandler {
for (String traitNameToBeDeleted : traitNames) {
String relationshipLabel = GraphHelper.getTraitLabel(typeName, traitNameToBeDeleted);
- deleteReference(instanceVertex, relationshipLabel, DataTypes.TypeCategory.TRAIT);
+ deleteEdgeReference(instanceVertex, relationshipLabel, DataTypes.TypeCategory.TRAIT, false);
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java b/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java
index 3604277..0d82d90 100755
--- a/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/GraphBackedMetadataRepository.java
@@ -22,8 +22,10 @@ import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.thinkaurelius.titan.core.TitanGraph;
+import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.GraphQuery;
import com.tinkerpop.blueprints.Vertex;
+import org.apache.atlas.AtlasClient;
import org.apache.atlas.AtlasException;
import org.apache.atlas.GraphTransaction;
import org.apache.atlas.RequestContext;
@@ -40,7 +42,6 @@ import org.apache.atlas.typesystem.types.ClassType;
import org.apache.atlas.typesystem.types.DataTypes;
import org.apache.atlas.typesystem.types.IDataType;
import org.apache.atlas.typesystem.types.TypeSystem;
-import org.apache.atlas.typesystem.types.TypeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -258,8 +259,8 @@ public class GraphBackedMetadataRepository implements MetadataRepository {
try {
final String entityTypeName = GraphHelper.getTypeName(instanceVertex);
String relationshipLabel = GraphHelper.getTraitLabel(entityTypeName, traitNameToBeDeleted);
-
- deleteHandler.deleteReference(instanceVertex, relationshipLabel, DataTypes.TypeCategory.TRAIT);
+ Edge edge = GraphHelper.getEdgeForLabel(instanceVertex, relationshipLabel);
+ deleteHandler.deleteEdgeReference(edge, DataTypes.TypeCategory.TRAIT, false, true);
// update the traits in entity once trait removal is successful
traitNames.remove(traitNameToBeDeleted);
@@ -284,14 +285,15 @@ public class GraphBackedMetadataRepository implements MetadataRepository {
@Override
@GraphTransaction
- public TypeUtils.Pair<List<String>, List<String>> updateEntities(ITypedReferenceableInstance... entitiesUpdated) throws RepositoryException {
+ public AtlasClient.EntityResult updateEntities(ITypedReferenceableInstance... entitiesUpdated) throws RepositoryException {
LOG.info("updating entity {}", entitiesUpdated);
try {
TypedInstanceToGraphMapper instanceToGraphMapper = new TypedInstanceToGraphMapper(graphToInstanceMapper, deleteHandler);
instanceToGraphMapper.mapTypedInstanceToGraph(TypedInstanceToGraphMapper.Operation.UPDATE_FULL,
entitiesUpdated);
RequestContext requestContext = RequestContext.get();
- return TypeUtils.Pair.of(requestContext.getCreatedEntityIds(), requestContext.getUpdatedEntityIds());
+ return new AtlasClient.EntityResult(requestContext.getCreatedEntityIds(),
+ requestContext.getUpdatedEntityIds(), requestContext.getDeletedEntityIds());
} catch (AtlasException e) {
throw new RepositoryException(e);
}
@@ -299,13 +301,14 @@ public class GraphBackedMetadataRepository implements MetadataRepository {
@Override
@GraphTransaction
- public TypeUtils.Pair<List<String>, List<String>> updatePartial(ITypedReferenceableInstance entity) throws RepositoryException {
+ public AtlasClient.EntityResult updatePartial(ITypedReferenceableInstance entity) throws RepositoryException {
LOG.info("updating entity {}", entity);
try {
TypedInstanceToGraphMapper instanceToGraphMapper = new TypedInstanceToGraphMapper(graphToInstanceMapper, deleteHandler);
instanceToGraphMapper.mapTypedInstanceToGraph(TypedInstanceToGraphMapper.Operation.UPDATE_PARTIAL, entity);
RequestContext requestContext = RequestContext.get();
- return TypeUtils.Pair.of(requestContext.getCreatedEntityIds(), requestContext.getUpdatedEntityIds());
+ return new AtlasClient.EntityResult(requestContext.getCreatedEntityIds(),
+ requestContext.getUpdatedEntityIds(), requestContext.getDeletedEntityIds());
} catch (AtlasException e) {
throw new RepositoryException(e);
}
@@ -313,7 +316,7 @@ public class GraphBackedMetadataRepository implements MetadataRepository {
@Override
@GraphTransaction
- public TypeUtils.Pair<List<String>, List<ITypedReferenceableInstance>> deleteEntities(List<String> guids) throws RepositoryException {
+ public AtlasClient.EntityResult deleteEntities(List<String> guids) throws RepositoryException {
if (guids == null || guids.size() == 0) {
throw new IllegalArgumentException("guids must be non-null and non-empty");
@@ -337,6 +340,7 @@ public class GraphBackedMetadataRepository implements MetadataRepository {
}
}
RequestContext requestContext = RequestContext.get();
- return new TypeUtils.Pair<>(requestContext.getDeletedEntityIds(), requestContext.getDeletedEntities());
+ return new AtlasClient.EntityResult(requestContext.getCreatedEntityIds(),
+ requestContext.getUpdatedEntityIds(), requestContext.getDeletedEntityIds());
}
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/705014eb/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java b/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java
index cccafc2..4f6d011 100755
--- a/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java
@@ -107,11 +107,13 @@ public final class GraphHelper {
// add timestamp information
setProperty(vertexWithoutIdentity, Constants.TIMESTAMP_PROPERTY_KEY, RequestContext.get().getRequestTime());
+ setProperty(vertexWithoutIdentity, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY,
+ RequestContext.get().getRequestTime());
return vertexWithoutIdentity;
}
- public Edge addEdge(Vertex fromVertex, Vertex toVertex, String edgeLabel) {
+ private Edge addEdge(Vertex fromVertex, Vertex toVertex, String edgeLabel) {
LOG.debug("Adding edge for {} -> label {} -> {}", string(fromVertex), edgeLabel, string(toVertex));
Edge edge = titanGraph.addEdge(null, fromVertex, toVertex, edgeLabel);
@@ -127,12 +129,34 @@ public final class GraphHelper {
Iterable<Edge> edges = inVertex.getEdges(Direction.IN, edgeLabel);
for (Edge edge : edges) {
if (edge.getVertex(Direction.OUT).getId().toString().equals(outVertex.getId().toString())) {
- return edge;
+ Id.EntityState edgeState = getState(edge);
+ if (edgeState == null || edgeState == Id.EntityState.ACTIVE) {
+ return edge;
+ }
}
}
return addEdge(outVertex, inVertex, edgeLabel);
}
+
+ public Edge getEdgeByEdgeId(Vertex outVertex, String edgeLabel, String edgeId) {
+ if (edgeId == null) {
+ return null;
+ }
+ return titanGraph.getEdge(edgeId);
+
+ //TODO get edge id is expensive. Use this logic. But doesn't work for now
+ /**
+ Iterable<Edge> edges = outVertex.getEdges(Direction.OUT, edgeLabel);
+ for (Edge edge : edges) {
+ if (edge.getId().toString().equals(edgeId)) {
+ return edge;
+ }
+ }
+ return null;
+ **/
+ }
+
/**
* Args of the format prop1, key1, prop2, key2...
* Searches for a vertex with prop1=key1 && prop2=key2
@@ -180,15 +204,14 @@ public final class GraphHelper {
* @return
*/
public static Edge getEdgeForLabel(Vertex vertex, String edgeLabel) {
- String vertexState = vertex.getProperty(Constants.STATE_PROPERTY_KEY);
-
Iterator<Edge> iterator = GraphHelper.getOutGoingEdgesByLabel(vertex, edgeLabel);
Edge latestDeletedEdge = null;
long latestDeletedEdgeTime = Long.MIN_VALUE;
+
while (iterator != null && iterator.hasNext()) {
Edge edge = iterator.next();
- String edgeState = edge.getProperty(Constants.STATE_PROPERTY_KEY);
- if (edgeState == null || Id.EntityState.ACTIVE.name().equals(edgeState)) {
+ Id.EntityState edgeState = getState(edge);
+ if (edgeState == null || edgeState == Id.EntityState.ACTIVE) {
LOG.debug("Found {}", string(edge));
return edge;
} else {
@@ -201,19 +224,8 @@ public final class GraphHelper {
}
//If the vertex is deleted, return latest deleted edge
- if (Id.EntityState.DELETED.equals(vertexState)) {
- LOG.debug("Found {}", string(latestDeletedEdge));
- return latestDeletedEdge;
- }
-
- return null;
- }
-
- public Edge getEdgeById(String edgeId) {
- if(edgeId != null) {
- return titanGraph.getEdge(edgeId);
- }
- return null;
+ LOG.debug("Found {}", latestDeletedEdge == null ? "null" : string(latestDeletedEdge));
+ return latestDeletedEdge;
}
public static String vertexString(final Vertex vertex) {
@@ -343,6 +355,15 @@ public final class GraphHelper {
return instanceVertex.getProperty(Constants.ENTITY_TYPE_PROPERTY_KEY);
}
+ public static Id.EntityState getState(Element element) {
+ String state = getStateAsString(element);
+ return state == null ? null : Id.EntityState.valueOf(state);
+ }
+
+ public static String getStateAsString(Element element) {
+ return element.getProperty(Constants.STATE_PROPERTY_KEY);
+ }
+
/**
* For the given type, finds an unique attribute and checks if there is an existing instance with the same
* unique value