http://git-wip-us.apache.org/repos/asf/atlas/blob/4823c8ed/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreSoftDeleteV2Test.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreSoftDeleteV2Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreSoftDeleteV2Test.java new file mode 100644 index 0000000..82b75da --- /dev/null +++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreSoftDeleteV2Test.java @@ -0,0 +1,117 @@ +/** + * 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.repository.store.graph.v2; + +import com.google.common.collect.ImmutableList; +import org.apache.atlas.TestModules; +import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasObjectId; +import org.apache.atlas.repository.store.graph.v1.SoftDeleteHandlerV1; +import org.testng.annotations.Guice; + +import java.util.List; + +import static org.apache.atlas.type.AtlasTypeUtil.getAtlasObjectId; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + + +/** + * Inverse reference update test with {@link SoftDeleteHandlerV1} + */ +@Guice(modules = TestModules.SoftDeleteModule.class) +public class AtlasRelationshipStoreSoftDeleteV2Test extends AtlasRelationshipStoreV2Test { + + @Override + protected void verifyRelationshipAttributeUpdate_NonComposite_OneToMany(AtlasEntity jane) throws Exception { + // Max is still in the subordinates list, as the edge still exists with state DELETED + verifyRelationshipAttributeList(jane, "subordinates", ImmutableList.of(employeeNameIdMap.get("John"), employeeNameIdMap.get("Max"))); + } + + @Override + protected void verifyRelationshipAttributeUpdate_NonComposite_ManyToOne(AtlasEntity a1, AtlasEntity a2, + AtlasEntity a3, AtlasEntity b) { + + verifyRelationshipAttributeValue(a1, "oneB", b.getGuid()); + + verifyRelationshipAttributeValue(a2, "oneB", b.getGuid()); + + verifyRelationshipAttributeList(b, "manyA", ImmutableList.of(getAtlasObjectId(a1), getAtlasObjectId(a2), getAtlasObjectId(a3))); + } + + @Override + protected void verifyRelationshipAttributeUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b) { + verifyRelationshipAttributeValue(a1, "b", b.getGuid()); + } + + @Override + protected void verifyRelationshipAttributeUpdate_ManyToMany_Friends(AtlasEntity max, AtlasEntity julius, AtlasEntity mike, AtlasEntity john) throws Exception { + AtlasObjectId johnId = employeeNameIdMap.get("John"); + AtlasObjectId mikeId = employeeNameIdMap.get("Mike"); + AtlasObjectId juliusId = employeeNameIdMap.get("Julius"); + AtlasObjectId maxId = employeeNameIdMap.get("Max"); + + // Max's updated friends: [Julius, John, Mike(soft deleted)] + List<AtlasObjectId> maxFriendsIds = toAtlasObjectIds(max.getRelationshipAttribute("friends")); + assertNotNull(maxFriendsIds); + assertEquals(maxFriendsIds.size(), 3); + assertObjectIdsContains(maxFriendsIds, johnId); + assertObjectIdsContains(maxFriendsIds, juliusId); + assertObjectIdsContains(maxFriendsIds, mikeId); + + // Julius's updated friends: [Max] + List<AtlasObjectId> juliusFriendsIds = toAtlasObjectIds(julius.getRelationshipAttribute("friends")); + assertNotNull(juliusFriendsIds); + assertEquals(juliusFriendsIds.size(), 1); + assertObjectIdsContains(juliusFriendsIds, maxId); + + // Mike's updated friends: [John, Max(soft deleted)] + List<AtlasObjectId> mikeFriendsIds = toAtlasObjectIds(mike.getRelationshipAttribute("friends")); + assertNotNull(mikeFriendsIds); + assertEquals(mikeFriendsIds.size(), 2); + assertObjectIdsContains(mikeFriendsIds, johnId); + assertObjectIdsContains(mikeFriendsIds, maxId); + + // John's updated friends: [Max, Mike] + List<AtlasObjectId> johnFriendsIds = toAtlasObjectIds(john.getRelationshipAttribute("friends")); + assertNotNull(johnFriendsIds); + assertEquals(johnFriendsIds.size(), 2); + assertObjectIdsContains(johnFriendsIds, maxId); + assertObjectIdsContains(johnFriendsIds, mikeId); + } + + protected void verifyRelationshipAttributeUpdate_OneToOne_Sibling(AtlasEntity julius, AtlasEntity jane, AtlasEntity mike) throws Exception { + AtlasObjectId juliusId = employeeNameIdMap.get("Julius"); + AtlasObjectId mikeId = employeeNameIdMap.get("Mike"); + + // Julius sibling updated to Mike + AtlasObjectId juliusSiblingId = toAtlasObjectId(julius.getRelationshipAttribute("sibling")); + assertNotNull(juliusSiblingId); + assertObjectIdEquals(juliusSiblingId, mikeId); + + // Mike's sibling is Julius + AtlasObjectId mikeSiblingId = toAtlasObjectId(mike.getRelationshipAttribute("sibling")); + assertNotNull(mikeSiblingId); + assertObjectIdEquals(mikeSiblingId, juliusId); + + // Jane's sibling is still Julius (soft delete) + AtlasObjectId janeSiblingId = toAtlasObjectId(jane.getRelationshipAttribute("sibling")); + assertNotNull(janeSiblingId); + assertObjectIdEquals(janeSiblingId, juliusId); + } +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/atlas/blob/4823c8ed/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2Test.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2Test.java new file mode 100644 index 0000000..cd1d727 --- /dev/null +++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasRelationshipStoreV2Test.java @@ -0,0 +1,633 @@ +/** + * 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.repository.store.graph.v2; + +import com.google.common.collect.ImmutableList; +import org.apache.atlas.RequestContext; +import org.apache.atlas.TestModules; +import org.apache.atlas.TestUtilsV2; +import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasEntity.AtlasEntitiesWithExtInfo; +import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo; +import org.apache.atlas.model.instance.AtlasEntityHeader; +import org.apache.atlas.model.instance.AtlasObjectId; +import org.apache.atlas.model.instance.AtlasRelatedObjectId; +import org.apache.atlas.model.instance.EntityMutationResponse; +import org.apache.atlas.model.typedef.AtlasTypesDef; +import org.apache.atlas.repository.graph.AtlasGraphProvider; +import org.apache.atlas.repository.graph.GraphBackedSearchIndexer; +import org.apache.atlas.repository.store.bootstrap.AtlasTypeDefStoreInitializer; +import org.apache.atlas.repository.store.graph.AtlasEntityStore; +import org.apache.atlas.repository.store.graph.AtlasRelationshipStore; +import org.apache.atlas.repository.store.graph.v1.DeleteHandlerV1; +import org.apache.atlas.runner.LocalSolrRunner; +import org.apache.atlas.store.AtlasTypeDefStore; +import org.apache.atlas.type.AtlasEntityType; +import org.apache.atlas.type.AtlasTypeRegistry; +import org.apache.commons.collections.CollectionUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.apache.atlas.TestRelationshipUtilsV2.EMPLOYEE_TYPE; +import static org.apache.atlas.TestRelationshipUtilsV2.getDepartmentEmployeeInstances; +import static org.apache.atlas.TestRelationshipUtilsV2.getDepartmentEmployeeTypes; +import static org.apache.atlas.TestRelationshipUtilsV2.getInverseReferenceTestTypes; +import static org.apache.atlas.TestUtilsV2.NAME; +import static org.apache.atlas.graph.GraphSandboxUtil.useLocalSolr; +import static org.apache.atlas.type.AtlasTypeUtil.getAtlasObjectId; +import static org.mockito.Mockito.mock; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +@Guice(modules = TestModules.TestOnlyModule.class) +public abstract class AtlasRelationshipStoreV2Test { + + @Inject + AtlasTypeRegistry typeRegistry; + + @Inject + AtlasTypeDefStore typeDefStore; + + @Inject + DeleteHandlerV1 deleteHandler; + + @Inject + EntityGraphMapper graphMapper; + + @Inject + AtlasEntityChangeNotifier entityNotifier; + + AtlasEntityStore entityStore; + AtlasRelationshipStore relationshipStore; + AtlasEntityChangeNotifier mockChangeNotifier = mock(AtlasEntityChangeNotifier.class); + + protected Map<String, AtlasObjectId> employeeNameIdMap = new HashMap<>(); + + @BeforeClass + public void setUp() throws Exception { + new GraphBackedSearchIndexer(typeRegistry); + + // create employee relationship types + AtlasTypesDef employeeTypes = getDepartmentEmployeeTypes(); + typeDefStore.createTypesDef(employeeTypes); + + AtlasEntitiesWithExtInfo employeeInstances = getDepartmentEmployeeInstances(); + EntityMutationResponse response = entityStore.createOrUpdate(new AtlasEntityStream(employeeInstances), false); + + for (AtlasEntityHeader entityHeader : response.getCreatedEntities()) { + employeeNameIdMap.put((String) entityHeader.getAttribute(NAME), getAtlasObjectId(entityHeader)); + } + + init(); + AtlasTypesDef typesDef = getInverseReferenceTestTypes(); + + AtlasTypesDef typesToCreate = AtlasTypeDefStoreInitializer.getTypesToCreate(typesDef, typeRegistry); + + if (!typesToCreate.isEmpty()) { + typeDefStore.createTypesDef(typesToCreate); + } + } + + @BeforeTest + public void init() throws Exception { + entityStore = new AtlasEntityStoreV2(deleteHandler, typeRegistry, mockChangeNotifier, graphMapper); + relationshipStore = new AtlasRelationshipStoreV2(typeRegistry, deleteHandler, entityNotifier); + + RequestContext.clear(); + RequestContext.get().setUser(TestUtilsV2.TEST_USER, null); + } + + @AfterClass + public void clear() throws Exception { + AtlasGraphProvider.cleanup(); + + if (useLocalSolr()) { + LocalSolrRunner.stop(); + } + } + + @Test + public void testDepartmentEmployeeEntitiesUsingRelationship() throws Exception { + AtlasObjectId hrId = employeeNameIdMap.get("hr"); + AtlasObjectId maxId = employeeNameIdMap.get("Max"); + AtlasObjectId johnId = employeeNameIdMap.get("John"); + AtlasObjectId juliusId = employeeNameIdMap.get("Julius"); + AtlasObjectId janeId = employeeNameIdMap.get("Jane"); + AtlasObjectId mikeId = employeeNameIdMap.get("Mike"); + + AtlasEntity hrDept = getEntityFromStore(hrId.getGuid()); + AtlasEntity max = getEntityFromStore(maxId.getGuid()); + AtlasEntity john = getEntityFromStore(johnId.getGuid()); + AtlasEntity julius = getEntityFromStore(juliusId.getGuid()); + AtlasEntity jane = getEntityFromStore(janeId.getGuid()); + AtlasEntity mike = getEntityFromStore(mikeId.getGuid()); + + // Department relationship attributes + List<AtlasObjectId> deptEmployees = toAtlasObjectIds(hrDept.getRelationshipAttribute("employees")); + assertNotNull(deptEmployees); + assertEquals(deptEmployees.size(), 5); + assertObjectIdsContains(deptEmployees, maxId); + assertObjectIdsContains(deptEmployees, johnId); + assertObjectIdsContains(deptEmployees, juliusId); + assertObjectIdsContains(deptEmployees, janeId); + assertObjectIdsContains(deptEmployees, mikeId); + + // Max employee validation + AtlasObjectId maxDepartmentId = toAtlasObjectId(max.getRelationshipAttribute("department")); + assertNotNull(maxDepartmentId); + assertObjectIdEquals(maxDepartmentId, hrId); + + AtlasObjectId maxManagerId = toAtlasObjectId(max.getRelationshipAttribute("manager")); + assertNotNull(maxManagerId); + assertObjectIdEquals(maxManagerId, janeId); + + List<AtlasObjectId> maxMentorsId = toAtlasObjectIds(max.getRelationshipAttribute("mentors")); + assertNotNull(maxMentorsId); + assertEquals(maxMentorsId.size(), 1); + assertObjectIdEquals(maxMentorsId.get(0), juliusId); + + List<AtlasObjectId> maxMenteesId = toAtlasObjectIds(max.getRelationshipAttribute("mentees")); + assertNotNull(maxMenteesId); + assertEquals(maxMenteesId.size(), 1); + assertObjectIdEquals(maxMenteesId.get(0), johnId); + + List<AtlasObjectId> maxFriendsIds = toAtlasObjectIds(max.getRelationshipAttribute("friends")); + assertNotNull(maxFriendsIds); + assertEquals(maxFriendsIds.size(), 2); + assertObjectIdsContains(maxFriendsIds, mikeId); + assertObjectIdsContains(maxFriendsIds, johnId); + + // John Employee validation + AtlasObjectId johnDepartmentId = toAtlasObjectId(john.getRelationshipAttribute("department")); + assertNotNull(johnDepartmentId); + assertObjectIdEquals(johnDepartmentId, hrId); + + AtlasObjectId johnManagerId = toAtlasObjectId(john.getRelationshipAttribute("manager")); + assertNotNull(johnManagerId); + assertObjectIdEquals(johnManagerId, janeId); + + List<AtlasObjectId> johnMentorIds = toAtlasObjectIds(john.getRelationshipAttribute("mentors")); + assertNotNull(johnMentorIds); + assertEquals(johnMentorIds.size(), 2); + assertObjectIdsContains(johnMentorIds, maxId); + assertObjectIdsContains(johnMentorIds, juliusId); + + List<AtlasObjectId> johnMenteesId = toAtlasObjectIds(john.getRelationshipAttribute("mentees")); + assertEmpty(johnMenteesId); + + List<AtlasObjectId> johnFriendsIds = toAtlasObjectIds(john.getRelationshipAttribute("friends")); + assertNotNull(johnFriendsIds); + assertEquals(johnFriendsIds.size(), 2); + assertObjectIdsContains(johnFriendsIds, mikeId); + assertObjectIdsContains(johnFriendsIds, maxId); + + // Mike Employee validation + AtlasObjectId mikeDepartmentId = toAtlasObjectId(mike.getRelationshipAttribute("department")); + assertNotNull(mikeDepartmentId); + assertObjectIdEquals(mikeDepartmentId, hrId); + + AtlasObjectId mikeManagerId = toAtlasObjectId(mike.getRelationshipAttribute("manager")); + assertNotNull(mikeManagerId); + assertObjectIdEquals(mikeManagerId, juliusId); + + List<AtlasObjectId> mikeMentorIds = toAtlasObjectIds(mike.getRelationshipAttribute("mentors")); + assertEmpty(mikeMentorIds); + + List<AtlasObjectId> mikeMenteesId = toAtlasObjectIds(mike.getRelationshipAttribute("mentees")); + assertEmpty(mikeMenteesId); + + List<AtlasObjectId> mikeFriendsIds = toAtlasObjectIds(mike.getRelationshipAttribute("friends")); + assertNotNull(mikeFriendsIds); + assertEquals(mikeFriendsIds.size(), 2); + assertObjectIdsContains(mikeFriendsIds, maxId); + assertObjectIdsContains(mikeFriendsIds, johnId); + + // Jane Manager validation + AtlasObjectId janeDepartmentId = toAtlasObjectId(jane.getRelationshipAttribute("department")); + assertNotNull(janeDepartmentId); + assertObjectIdEquals(janeDepartmentId, hrId); + + AtlasObjectId janeManagerId = toAtlasObjectId(jane.getRelationshipAttribute("manager")); + assertNull(janeManagerId); + + List<AtlasObjectId> janeMentorIds = toAtlasObjectIds(jane.getRelationshipAttribute("mentors")); + assertEmpty(janeMentorIds); + + List<AtlasObjectId> janeMenteesId = toAtlasObjectIds(jane.getRelationshipAttribute("mentees")); + assertEmpty(janeMenteesId); + + List<AtlasObjectId> janeSubordinateIds = toAtlasObjectIds(jane.getRelationshipAttribute("subordinates")); + assertNotNull(janeSubordinateIds); + assertEquals(janeSubordinateIds.size(), 2); + assertObjectIdsContains(janeSubordinateIds, maxId); + assertObjectIdsContains(janeSubordinateIds, johnId); + + List<AtlasObjectId> janeFriendsIds = toAtlasObjectIds(jane.getRelationshipAttribute("friends")); + assertEmpty(janeFriendsIds); + + AtlasObjectId janeSiblingId = toAtlasObjectId(jane.getRelationshipAttribute("sibling")); + assertNotNull(janeSiblingId); + assertObjectIdEquals(janeSiblingId, juliusId); + + // Julius Manager validation + AtlasObjectId juliusDepartmentId = toAtlasObjectId(julius.getRelationshipAttribute("department")); + assertNotNull(juliusDepartmentId); + assertObjectIdEquals(juliusDepartmentId, hrId); + + AtlasObjectId juliusManagerId = toAtlasObjectId(julius.getRelationshipAttribute("manager")); + assertNull(juliusManagerId); + + List<AtlasObjectId> juliusMentorIds = toAtlasObjectIds(julius.getRelationshipAttribute("mentors")); + assertEmpty(juliusMentorIds); + + List<AtlasObjectId> juliusMenteesId = toAtlasObjectIds(julius.getRelationshipAttribute("mentees")); + assertNotNull(juliusMenteesId); + assertEquals(juliusMenteesId.size(), 2); + assertObjectIdsContains(juliusMenteesId, maxId); + assertObjectIdsContains(juliusMenteesId, johnId); + + List<AtlasObjectId> juliusSubordinateIds = toAtlasObjectIds(julius.getRelationshipAttribute("subordinates")); + assertNotNull(juliusSubordinateIds); + assertEquals(juliusSubordinateIds.size(), 1); + assertObjectIdsContains(juliusSubordinateIds, mikeId); + + List<AtlasObjectId> juliusFriendsIds = toAtlasObjectIds(julius.getRelationshipAttribute("friends")); + assertEmpty(juliusFriendsIds); + + AtlasObjectId juliusSiblingId = toAtlasObjectId(julius.getRelationshipAttribute("sibling")); + assertNotNull(juliusSiblingId); + assertObjectIdEquals(juliusSiblingId, janeId); + } + + // Seeing intermittent failures with janus profile, disabling it until its fixed. + @Test(enabled = false) + public void testRelationshipAttributeUpdate_NonComposite_OneToMany() throws Exception { + AtlasObjectId maxId = employeeNameIdMap.get("Max"); + AtlasObjectId juliusId = employeeNameIdMap.get("Julius"); + AtlasObjectId janeId = employeeNameIdMap.get("Jane"); + AtlasObjectId mikeId = employeeNameIdMap.get("Mike"); + AtlasObjectId johnId = employeeNameIdMap.get("John"); + + // Change Max's Employee.manager reference to Julius and apply the change as a partial update. + // This should also update Julius to add Max to the inverse Manager.subordinates reference. + AtlasEntity maxEntityForUpdate = new AtlasEntity(EMPLOYEE_TYPE); + maxEntityForUpdate.setRelationshipAttribute("manager", juliusId); + + AtlasEntityType employeeType = typeRegistry.getEntityTypeByName(EMPLOYEE_TYPE); + Map<String, Object> uniqAttributes = Collections.<String, Object>singletonMap("name", "Max"); + EntityMutationResponse updateResponse = entityStore.updateByUniqueAttributes(employeeType, uniqAttributes , new AtlasEntityWithExtInfo(maxEntityForUpdate)); + + List<AtlasEntityHeader> partialUpdatedEntities = updateResponse.getPartialUpdatedEntities(); + assertEquals(partialUpdatedEntities.size(), 3); + // 3 entities should have been updated: + // * Max to change the Employee.manager reference + // * Julius to add Max to Manager.subordinates + // * Jane to remove Max from Manager.subordinates + + AtlasEntitiesWithExtInfo updatedEntities = entityStore.getByIds(ImmutableList.of(maxId.getGuid(), juliusId.getGuid(), janeId.getGuid())); + + // Max's manager updated as Julius + AtlasEntity maxEntity = updatedEntities.getEntity(maxId.getGuid()); + verifyRelationshipAttributeValue(maxEntity, "manager", juliusId.getGuid()); + + // Max added to the subordinate list of Julius, existing subordinate is Mike + AtlasEntity juliusEntity = updatedEntities.getEntity(juliusId.getGuid()); + verifyRelationshipAttributeList(juliusEntity, "subordinates", ImmutableList.of(maxId, mikeId)); + + // Max removed from the subordinate list of Julius + AtlasEntity janeEntity = updatedEntities.getEntity(janeId.getGuid()); + + // Jane's subordinates list includes John and Max for soft delete + // Jane's subordinates list includes only John for hard delete + verifyRelationshipAttributeUpdate_NonComposite_OneToMany(janeEntity); + + // Remove Mike from Max's friends list + // Max's current friends: [Mike, John] + // Max's updated friends: [Julius, John] + maxEntityForUpdate = new AtlasEntity(EMPLOYEE_TYPE); + maxEntityForUpdate.setRelationshipAttribute("friends", ImmutableList.of(johnId, juliusId)); + + init(); + updateResponse = entityStore.updateByUniqueAttributes(employeeType, uniqAttributes , new AtlasEntityWithExtInfo(maxEntityForUpdate)); + + partialUpdatedEntities = updateResponse.getPartialUpdatedEntities(); + assertEquals(partialUpdatedEntities.size(), 3); + // 3 entities should have been updated: + // * Max added Julius and removed Mike from Employee.friends + // * Mike removed Max from Employee.friends + // * Julius added Max in Employee.friends + + updatedEntities = entityStore.getByIds(ImmutableList.of(maxId.getGuid(), mikeId.getGuid(), johnId.getGuid(), juliusId.getGuid())); + + maxEntity = updatedEntities.getEntity(maxId.getGuid()); + juliusEntity = updatedEntities.getEntity(juliusId.getGuid()); + AtlasEntity mikeEntity = updatedEntities.getEntity(mikeId.getGuid()); + AtlasEntity johnEntity = updatedEntities.getEntity(johnId.getGuid()); + + verifyRelationshipAttributeUpdate_ManyToMany_Friends(maxEntity, juliusEntity, mikeEntity, johnEntity); + + // Remove Julius from Jane's sibling and add Mike as new sibling + AtlasEntity juliusEntityForUpdate = new AtlasEntity(EMPLOYEE_TYPE); + juliusEntityForUpdate.setRelationshipAttribute("sibling", mikeId); + + init(); + updateResponse = entityStore.updateByUniqueAttributes(employeeType, Collections.<String, Object>singletonMap("name", "Julius") , new AtlasEntityWithExtInfo(juliusEntityForUpdate)); + partialUpdatedEntities = updateResponse.getPartialUpdatedEntities(); + assertEquals(partialUpdatedEntities.size(), 3); + + updatedEntities = entityStore.getByIds(ImmutableList.of(juliusId.getGuid(), janeId.getGuid(), mikeId.getGuid())); + + juliusEntity = updatedEntities.getEntity(juliusId.getGuid()); + janeEntity = updatedEntities.getEntity(janeId.getGuid()); + mikeEntity = updatedEntities.getEntity(mikeId.getGuid()); + + verifyRelationshipAttributeUpdate_OneToOne_Sibling(juliusEntity, janeEntity, mikeEntity); + } + + @Test + public void testRelationshipAttributeUpdate_NonComposite_ManyToOne() throws Exception { + AtlasEntity a1 = new AtlasEntity("A"); + a1.setAttribute(NAME, "a1_name"); + + AtlasEntity a2 = new AtlasEntity("A"); + a2.setAttribute(NAME, "a2_name"); + + AtlasEntity a3 = new AtlasEntity("A"); + a3.setAttribute(NAME, "a3_name"); + + AtlasEntity b = new AtlasEntity("B"); + b.setAttribute(NAME, "b_name"); + + AtlasEntitiesWithExtInfo entitiesWithExtInfo = new AtlasEntitiesWithExtInfo(); + entitiesWithExtInfo.addEntity(a1); + entitiesWithExtInfo.addEntity(a2); + entitiesWithExtInfo.addEntity(a3); + entitiesWithExtInfo.addEntity(b); + entityStore.createOrUpdate(new AtlasEntityStream(entitiesWithExtInfo) , false); + + AtlasEntity bPartialUpdate = new AtlasEntity("B"); + bPartialUpdate.setRelationshipAttribute("manyA", ImmutableList.of(getAtlasObjectId(a1), getAtlasObjectId(a2))); + + init(); + EntityMutationResponse response = entityStore.updateByUniqueAttributes(typeRegistry.getEntityTypeByName("B"), + Collections.singletonMap(NAME, b.getAttribute(NAME)), + new AtlasEntityWithExtInfo(bPartialUpdate)); + // Verify 3 entities were updated: + // * set b.manyA reference to a1 and a2 + // * set inverse a1.oneB reference to b + // * set inverse a2.oneB reference to b + assertEquals(response.getPartialUpdatedEntities().size(), 3); + AtlasEntitiesWithExtInfo updatedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b.getGuid())); + + AtlasEntity a1Entity = updatedEntities.getEntity(a1.getGuid()); + verifyRelationshipAttributeValue(a1Entity, "oneB", b.getGuid()); + + AtlasEntity a2Entity = updatedEntities.getEntity(a2.getGuid()); + verifyRelationshipAttributeValue(a2Entity, "oneB", b.getGuid()); + + AtlasEntity bEntity = updatedEntities.getEntity(b.getGuid()); + verifyRelationshipAttributeList(bEntity, "manyA", ImmutableList.of(getAtlasObjectId(a1), getAtlasObjectId(a2))); + + + bPartialUpdate.setRelationshipAttribute("manyA", ImmutableList.of(getAtlasObjectId(a3))); + init(); + response = entityStore.updateByUniqueAttributes(typeRegistry.getEntityTypeByName("B"), + Collections.singletonMap(NAME, b.getAttribute(NAME)), + new AtlasEntityWithExtInfo(bPartialUpdate)); + // Verify 4 entities were updated: + // * set b.manyA reference to a3 + // * set inverse a3.oneB reference to b + // * disconnect inverse a1.oneB reference to b + // * disconnect inverse a2.oneB reference to b + assertEquals(response.getPartialUpdatedEntities().size(), 4); + init(); + + updatedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), a3.getGuid(), b.getGuid())); + a1Entity = updatedEntities.getEntity(a1.getGuid()); + a2Entity = updatedEntities.getEntity(a2.getGuid()); + bEntity = updatedEntities.getEntity(b.getGuid()); + + AtlasEntity a3Entity = updatedEntities.getEntity(a3.getGuid()); + verifyRelationshipAttributeValue(a3Entity, "oneB", b.getGuid()); + + verifyRelationshipAttributeUpdate_NonComposite_ManyToOne(a1Entity, a2Entity, a3Entity, bEntity); + } + + @Test + public void testRelationshipAttributeUpdate_NonComposite_OneToOne() throws Exception { + AtlasEntity a1 = new AtlasEntity("A"); + a1.setAttribute(NAME, "a1_name"); + + AtlasEntity a2 = new AtlasEntity("A"); + a2.setAttribute(NAME, "a2_name"); + + AtlasEntity b = new AtlasEntity("B"); + b.setAttribute(NAME, "b_name"); + + AtlasEntitiesWithExtInfo entitiesWithExtInfo = new AtlasEntitiesWithExtInfo(); + entitiesWithExtInfo.addEntity(a1); + entitiesWithExtInfo.addEntity(a2); + entitiesWithExtInfo.addEntity(b); + + EntityMutationResponse response = entityStore.createOrUpdate(new AtlasEntityStream(entitiesWithExtInfo) , false); + + AtlasEntity partialUpdateB = new AtlasEntity("B"); + partialUpdateB.setRelationshipAttribute("a", getAtlasObjectId(a1)); + + init(); + AtlasEntityType bType = typeRegistry.getEntityTypeByName("B"); + + response = entityStore.updateByUniqueAttributes(bType, Collections.singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(partialUpdateB)); + List<AtlasEntityHeader> partialUpdatedEntitiesHeader = response.getPartialUpdatedEntities(); + // Verify 2 entities were updated: + // * set b.a reference to a1 + // * set inverse a1.b reference to b + assertEquals(partialUpdatedEntitiesHeader.size(), 2); + AtlasEntitiesWithExtInfo partialUpdatedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), b.getGuid())); + + AtlasEntity a1Entity = partialUpdatedEntities.getEntity(a1.getGuid()); + verifyRelationshipAttributeValue(a1Entity, "b", b.getGuid()); + + AtlasEntity bEntity = partialUpdatedEntities.getEntity(b.getGuid()); + verifyRelationshipAttributeValue(bEntity, "a", a1.getGuid()); + + init(); + + // Update b.a to reference a2. + partialUpdateB.setRelationshipAttribute("a", getAtlasObjectId(a2)); + response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(partialUpdateB)); + partialUpdatedEntitiesHeader = response.getPartialUpdatedEntities(); + // Verify 3 entities were updated: + // * set b.a reference to a2 + // * set a2.b reference to b + // * disconnect a1.b reference + assertEquals(partialUpdatedEntitiesHeader.size(), 3); + partialUpdatedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b.getGuid())); + + bEntity = partialUpdatedEntities.getEntity(b.getGuid()); + verifyRelationshipAttributeValue(bEntity, "a", a2.getGuid()); + + AtlasEntity a2Entity = partialUpdatedEntities.getEntity(a2.getGuid()); + verifyRelationshipAttributeValue(a2Entity, "b", b.getGuid()); + + a1Entity = partialUpdatedEntities.getEntity(a1.getGuid()); + verifyRelationshipAttributeUpdate_NonComposite_OneToOne(a1Entity, bEntity); + } + + @Test + public void testRelationshipAttributeUpdate_NonComposite_ManyToMany() throws Exception { + AtlasEntity a1 = new AtlasEntity("A"); + a1.setAttribute(NAME, "a1_name"); + + AtlasEntity a2 = new AtlasEntity("A"); + a2.setAttribute(NAME, "a2_name"); + + AtlasEntity a3 = new AtlasEntity("A"); + a3.setAttribute(NAME, "a3_name"); + + AtlasEntity b1 = new AtlasEntity("B"); + b1.setAttribute(NAME, "b1_name"); + + AtlasEntity b2 = new AtlasEntity("B"); + b2.setAttribute(NAME, "b2_name"); + + AtlasEntitiesWithExtInfo entitiesWithExtInfo = new AtlasEntitiesWithExtInfo(); + entitiesWithExtInfo.addEntity(a1); + entitiesWithExtInfo.addEntity(a2); + entitiesWithExtInfo.addEntity(a3); + entitiesWithExtInfo.addEntity(b1); + entitiesWithExtInfo.addEntity(b2); + entityStore.createOrUpdate(new AtlasEntityStream(entitiesWithExtInfo) , false); + + AtlasEntity b1PartialUpdate = new AtlasEntity("B"); + b1PartialUpdate.setRelationshipAttribute("manyToManyA", ImmutableList.of(getAtlasObjectId(a1), getAtlasObjectId(a2))); + + init(); + EntityMutationResponse response = entityStore.updateByUniqueAttributes(typeRegistry.getEntityTypeByName("B"), + Collections.singletonMap(NAME, b1.getAttribute(NAME)), + new AtlasEntityWithExtInfo(b1PartialUpdate)); + + List<AtlasEntityHeader> updatedEntityHeaders = response.getPartialUpdatedEntities(); + assertEquals(updatedEntityHeaders.size(), 3); + + AtlasEntitiesWithExtInfo updatedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b1.getGuid())); + + AtlasEntity b1Entity = updatedEntities.getEntity(b1.getGuid()); + verifyRelationshipAttributeList(b1Entity, "manyToManyA", ImmutableList.of(getAtlasObjectId(a1), getAtlasObjectId(a2))); + + AtlasEntity a1Entity = updatedEntities.getEntity(a1.getGuid()); + verifyRelationshipAttributeList(a1Entity, "manyB", ImmutableList.of(getAtlasObjectId(b1))); + + AtlasEntity a2Entity = updatedEntities.getEntity(a2.getGuid()); + verifyRelationshipAttributeList(a2Entity, "manyB", ImmutableList.of(getAtlasObjectId(b1))); + } + + protected abstract void verifyRelationshipAttributeUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b); + + protected abstract void verifyRelationshipAttributeUpdate_NonComposite_OneToMany(AtlasEntity entity) throws Exception; + + protected abstract void verifyRelationshipAttributeUpdate_NonComposite_ManyToOne(AtlasEntity a1, AtlasEntity a2, AtlasEntity a3, AtlasEntity b); + + protected abstract void verifyRelationshipAttributeUpdate_ManyToMany_Friends(AtlasEntity e1, AtlasEntity e2, AtlasEntity e3, AtlasEntity e4) throws Exception; + + protected abstract void verifyRelationshipAttributeUpdate_OneToOne_Sibling(AtlasEntity e1, AtlasEntity e2, AtlasEntity e3) throws Exception; + + protected static void assertObjectIdsContains(List<AtlasObjectId> objectIds, AtlasObjectId objectId) { + assertTrue(CollectionUtils.isNotEmpty(objectIds)); + assertTrue(objectIds.contains(objectId)); + } + + protected static void assertObjectIdEquals(AtlasObjectId objId1, AtlasObjectId objId2) { + assertTrue(objId1.equals(objId2)); + } + + private static void assertEmpty(List collection) { + assertTrue(collection != null && collection.isEmpty()); + } + + protected static List<AtlasObjectId> toAtlasObjectIds(Object object) { + List<AtlasObjectId> ret = new ArrayList<>(); + + if (object instanceof List) { + List<?> objectIds = (List) object; + + if (CollectionUtils.isNotEmpty(objectIds)) { + for (Object obj : objectIds) { + if (obj instanceof AtlasRelatedObjectId) { + AtlasRelatedObjectId relatedObjectId = (AtlasRelatedObjectId) obj; + ret.add(new AtlasObjectId(relatedObjectId.getGuid(), relatedObjectId.getTypeName(), relatedObjectId.getUniqueAttributes())); + } + } + } + } + + return ret; + } + + protected static AtlasObjectId toAtlasObjectId(Object object) { + if (object instanceof AtlasRelatedObjectId) { + AtlasRelatedObjectId relatedObjectId = (AtlasRelatedObjectId) object; + return new AtlasObjectId(relatedObjectId.getGuid(), relatedObjectId.getTypeName(), relatedObjectId.getUniqueAttributes()); + } + + return null; + } + + private AtlasEntity getEntityFromStore(String guid) throws AtlasBaseException { + AtlasEntityWithExtInfo entity = guid != null ? entityStore.getById(guid) : null; + + return entity != null ? entity.getEntity() : null; + } + + protected static void verifyRelationshipAttributeList(AtlasEntity entity, String relationshipAttrName, List<AtlasObjectId> expectedValues) { + Object refValue = entity.getRelationshipAttribute(relationshipAttrName); + assertTrue(refValue instanceof List); + + List<AtlasObjectId> refList = toAtlasObjectIds(refValue); + assertEquals(refList.size(), expectedValues.size()); + + if (expectedValues.size() > 0) { + assertTrue(refList.containsAll(expectedValues)); + } + } + + protected static void verifyRelationshipAttributeValue(AtlasEntity entity, String relationshipAttrName, String expectedGuid) { + Object refValue = entity.getRelationshipAttribute(relationshipAttrName); + if (expectedGuid == null) { + assertNull(refValue); + } + else { + assertTrue(refValue instanceof AtlasObjectId); + AtlasObjectId referencedObjectId = (AtlasObjectId) refValue; + assertEquals(referencedObjectId.getGuid(), expectedGuid); + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/atlas/blob/4823c8ed/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateHardDeleteV2Test.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateHardDeleteV2Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateHardDeleteV2Test.java new file mode 100644 index 0000000..5d45908 --- /dev/null +++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateHardDeleteV2Test.java @@ -0,0 +1,76 @@ +/** + * 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.repository.store.graph.v2; + +import com.google.common.collect.ImmutableList; +import org.apache.atlas.TestModules; +import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasObjectId; +import org.apache.atlas.repository.store.graph.v1.HardDeleteHandlerV1; +import org.apache.atlas.type.AtlasTypeUtil; +import org.testng.annotations.Guice; + +import java.util.Map; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +/** + * Inverse reference update test with {@link HardDeleteHandlerV1} + */ +@Guice(modules = TestModules.HardDeleteModule.class) +public class InverseReferenceUpdateHardDeleteV2Test extends InverseReferenceUpdateV2Test { + + @Override + protected void verify_testInverseReferenceAutoUpdate_NonComposite_OneToMany(AtlasEntity jane) throws Exception { + + // Max should have been removed from the subordinates list, leaving only John. + verifyReferenceList(jane, "subordinates", ImmutableList.of(nameIdMap.get("John"))); + } + + @Override + protected void verify_testInverseReferenceAutoUpdate_NonCompositeManyToOne(AtlasEntity a1, AtlasEntity a2, AtlasEntity a3, AtlasEntity b) { + + verifyReferenceValue(a1, "oneB", null); + + verifyReferenceValue(a2, "oneB", null); + + verifyReferenceList(b, "manyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a3))); + } + + @Override + protected void verify_testInverseReferenceAutoUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b) { + + verifyReferenceValue(a1, "b", null); + } + + @Override + protected void verify_testInverseReferenceAutoUpdate_Map(AtlasEntity a1, AtlasEntity b1, + AtlasEntity b2, AtlasEntity b3) { + + Object value = a1.getAttribute("mapToB"); + assertTrue(value instanceof Map); + Map<String, AtlasObjectId> refMap = (Map<String, AtlasObjectId>) value; + assertEquals(refMap.size(), 1); + AtlasObjectId referencedEntityId = refMap.get("b3"); + assertEquals(referencedEntityId, AtlasTypeUtil.getAtlasObjectId(b3)); + verifyReferenceValue(b1, "mappedFromA", null); + verifyReferenceValue(b2, "mappedFromA", null); + } + +} http://git-wip-us.apache.org/repos/asf/atlas/blob/4823c8ed/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateSoftDeleteV2Test.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateSoftDeleteV2Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateSoftDeleteV2Test.java new file mode 100644 index 0000000..76d6b7d --- /dev/null +++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateSoftDeleteV2Test.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 + * + * 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.repository.store.graph.v2; + +import com.google.common.collect.ImmutableList; +import org.apache.atlas.TestModules; +import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasObjectId; +import org.apache.atlas.repository.store.graph.v1.SoftDeleteHandlerV1; +import org.apache.atlas.type.AtlasTypeUtil; +import org.testng.annotations.Guice; + +import java.util.Map; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + + +/** + * Inverse reference update test with {@link SoftDeleteHandlerV1} + */ +@Guice(modules = TestModules.SoftDeleteModule.class) +public class InverseReferenceUpdateSoftDeleteV2Test extends InverseReferenceUpdateV2Test { + + @Override + protected void verify_testInverseReferenceAutoUpdate_NonComposite_OneToMany(AtlasEntity jane) + throws Exception { + + // Max is still in the subordinates list, as the edge still exists with state DELETED + verifyReferenceList(jane, "subordinates", ImmutableList.of(nameIdMap.get("John"), nameIdMap.get("Max"))); + } + + @Override + protected void verify_testInverseReferenceAutoUpdate_NonCompositeManyToOne(AtlasEntity a1, + AtlasEntity a2, AtlasEntity a3, AtlasEntity b) { + + verifyReferenceValue(a1, "oneB", b.getGuid()); + + verifyReferenceValue(a2, "oneB", b.getGuid()); + + verifyReferenceList(b, "manyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a1), AtlasTypeUtil.getAtlasObjectId(a2), AtlasTypeUtil.getAtlasObjectId(a3))); + } + + @Override + protected void verify_testInverseReferenceAutoUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b) { + + verifyReferenceValue(a1, "b", b.getGuid()); + } + + @Override + protected void verify_testInverseReferenceAutoUpdate_Map(AtlasEntity a1, AtlasEntity b1, + AtlasEntity b2, AtlasEntity b3) { + + Object value = a1.getAttribute("mapToB"); + assertTrue(value instanceof Map); + Map<String, AtlasObjectId> refMap = (Map<String, AtlasObjectId>) value; + assertEquals(refMap.size(), 3); + AtlasObjectId referencedEntityId = refMap.get("b3"); + assertEquals(referencedEntityId, AtlasTypeUtil.getAtlasObjectId(b3)); + verifyReferenceValue(b1, "mappedFromA", a1.getGuid()); + verifyReferenceValue(b2, "mappedFromA", a1.getGuid()); + } + +} http://git-wip-us.apache.org/repos/asf/atlas/blob/4823c8ed/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateV2Test.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateV2Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateV2Test.java new file mode 100644 index 0000000..ea647ec --- /dev/null +++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/InverseReferenceUpdateV2Test.java @@ -0,0 +1,380 @@ +/** + * 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.repository.store.graph.v2; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.apache.atlas.RequestContext; +import org.apache.atlas.TestUtilsV2; +import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasEntity.AtlasEntitiesWithExtInfo; +import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo; +import org.apache.atlas.model.instance.AtlasEntityHeader; +import org.apache.atlas.model.instance.AtlasObjectId; +import org.apache.atlas.model.instance.EntityMutationResponse; +import org.apache.atlas.model.typedef.AtlasTypesDef; +import org.apache.atlas.repository.graph.AtlasGraphProvider; +import org.apache.atlas.repository.store.bootstrap.AtlasTypeDefStoreInitializer; +import org.apache.atlas.repository.store.graph.AtlasEntityStore; +import org.apache.atlas.runner.LocalSolrRunner; +import org.apache.atlas.store.AtlasTypeDefStore; +import org.apache.atlas.type.AtlasEntityType; +import org.apache.atlas.type.AtlasTypeRegistry; +import org.apache.atlas.type.AtlasTypeUtil; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import javax.inject.Inject; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.apache.atlas.graph.GraphSandboxUtil.useLocalSolr; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; + +import static org.apache.atlas.TestUtilsV2.NAME; + +/** + * Test automatic inverse reference updating in V1 (V2?) code path. + * + */ +public abstract class InverseReferenceUpdateV2Test { + @Inject + AtlasTypeRegistry typeRegistry; + + @Inject + AtlasTypeDefStore typeDefStore; + + @Inject + AtlasEntityStore entityStore; + + private AtlasEntitiesWithExtInfo deptEntity; + + protected Map<String, AtlasObjectId> nameIdMap = new HashMap<>(); + + @BeforeClass + public void setUp() throws Exception { + RequestContext.clear(); + RequestContext.get().setUser(TestUtilsV2.TEST_USER, null); + + AtlasTypesDef[] testTypesDefs = new AtlasTypesDef[] { TestUtilsV2.defineDeptEmployeeTypes(), + TestUtilsV2.defineInverseReferenceTestTypes() + }; + + for (AtlasTypesDef typesDef : testTypesDefs) { + AtlasTypesDef typesToCreate = AtlasTypeDefStoreInitializer.getTypesToCreate(typesDef, typeRegistry); + + if (!typesToCreate.isEmpty()) { + typeDefStore.createTypesDef(typesToCreate); + } + } + + deptEntity = TestUtilsV2.createDeptEg2(); + init(); + EntityMutationResponse response = entityStore.createOrUpdate(new AtlasEntityStream(deptEntity), false); + for (AtlasEntityHeader entityHeader : response.getCreatedEntities()) { + nameIdMap.put((String)entityHeader.getAttribute(NAME), AtlasTypeUtil.getAtlasObjectId(entityHeader)); + } + } + + @AfterClass + public void clear() throws Exception { + AtlasGraphProvider.cleanup(); + + if (useLocalSolr()) { + LocalSolrRunner.stop(); + } + } + + @BeforeMethod + public void init() throws Exception { + RequestContext.clear(); + RequestContext.get().setUser(TestUtilsV2.TEST_USER, null); + } + + @Test + public void testInverseReferenceAutoUpdate_NonComposite_OneToMany() throws Exception { + AtlasObjectId juliusId = nameIdMap.get("Julius"); + + // Change Max's Employee.manager reference to Julius and apply the change as a partial update. + // This should also update Julius to add Max to the inverse Manager.subordinates reference. + AtlasEntity maxEntityForUpdate = new AtlasEntity(TestUtilsV2.EMPLOYEE_TYPE); + maxEntityForUpdate.setAttribute("manager", juliusId); + AtlasEntityType employeeType = typeRegistry.getEntityTypeByName(TestUtilsV2.EMPLOYEE_TYPE); + Map<String, Object> uniqAttributes = Collections.<String, Object>singletonMap("name", "Max"); + EntityMutationResponse updateResponse = entityStore.updateByUniqueAttributes(employeeType, uniqAttributes , new AtlasEntityWithExtInfo(maxEntityForUpdate)); + List<AtlasEntityHeader> partialUpdatedEntities = updateResponse.getPartialUpdatedEntities(); + // 3 entities should have been updated: + // * Max to change the Employee.manager reference + // * Julius to add Max to Manager.subordinates + // * Jane to remove Max from Manager.subordinates + assertEquals(partialUpdatedEntities.size(), 3); + + AtlasObjectId maxId = nameIdMap.get("Max"); + String janeGuid = nameIdMap.get("Jane").getGuid(); + AtlasEntitiesWithExtInfo storedEntities = entityStore.getByIds(ImmutableList.of(maxId.getGuid(), juliusId.getGuid(), janeGuid)); + AtlasEntity storedEntity = storedEntities.getEntity(maxId.getGuid()); + verifyReferenceValue(storedEntity, "manager", juliusId.getGuid()); + storedEntity = storedEntities.getEntity(juliusId.getGuid()); + verifyReferenceList(storedEntity, "subordinates", ImmutableList.of(maxId)); + storedEntity = storedEntities.getEntity(janeGuid); + verify_testInverseReferenceAutoUpdate_NonComposite_OneToMany(storedEntity); + } + + protected abstract void verify_testInverseReferenceAutoUpdate_NonComposite_OneToMany(AtlasEntity jane) throws Exception; + + @Test + public void testInverseReferenceAutoUpdate_NonCompositeManyToOne() throws Exception { + AtlasEntityType bType = typeRegistry.getEntityTypeByName("B"); + AtlasEntity a1 = new AtlasEntity("A"); + a1.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity a2 = new AtlasEntity("A"); + a2.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity a3 = new AtlasEntity("A"); + a3.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity b = new AtlasEntity("B"); + + b.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntitiesWithExtInfo atlasEntitiesWithExtInfo = new AtlasEntitiesWithExtInfo(); + atlasEntitiesWithExtInfo.addEntity(a1); + atlasEntitiesWithExtInfo.addEntity(a2); + atlasEntitiesWithExtInfo.addEntity(a3); + atlasEntitiesWithExtInfo.addEntity(b); + AtlasEntityStream entityStream = new AtlasEntityStream(atlasEntitiesWithExtInfo); + EntityMutationResponse response = entityStore.createOrUpdate(entityStream , false); + + AtlasEntity bForPartialUpdate = new AtlasEntity("B"); + bForPartialUpdate.setAttribute("manyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a1), AtlasTypeUtil.getAtlasObjectId(a2))); + init(); + response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(bForPartialUpdate)); + List<AtlasEntityHeader> partialUpdatedEntities = response.getPartialUpdatedEntities(); + // Verify 3 entities were updated: + // * set b.manyA reference to a1 and a2 + // * set inverse a1.oneB reference to b + // * set inverse a2.oneB reference to b + assertEquals(partialUpdatedEntities.size(), 3); + AtlasEntitiesWithExtInfo storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b.getGuid())); + AtlasEntity storedEntity = storedEntities.getEntity(a1.getGuid()); + verifyReferenceValue(storedEntity, "oneB", b.getGuid()); + + storedEntity = storedEntities.getEntity(a2.getGuid()); + verifyReferenceValue(storedEntity, "oneB", b.getGuid()); + + storedEntity = storedEntities.getEntity(b.getGuid()); + verifyReferenceList(storedEntity, "manyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a1), AtlasTypeUtil.getAtlasObjectId(a2))); + + bForPartialUpdate.setAttribute("manyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a3))); + init(); + response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(bForPartialUpdate)); + partialUpdatedEntities = response.getPartialUpdatedEntities(); + // Verify 4 entities were updated: + // * set b.manyA reference to a3 + // * set inverse a3.oneB reference to b + // * disconnect inverse a1.oneB reference to b + // * disconnect inverse a2.oneB reference to b + assertEquals(partialUpdatedEntities.size(), 4); + + init(); + storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), a3.getGuid(), b.getGuid())); + verifyReferenceValue(storedEntities.getEntity(a3.getGuid()), "oneB", b.getGuid()); + + verify_testInverseReferenceAutoUpdate_NonCompositeManyToOne(storedEntities.getEntity(a1.getGuid()), storedEntities.getEntity(a2.getGuid()), + storedEntities.getEntity(a3.getGuid()), storedEntities.getEntity(b.getGuid())); + } + + protected abstract void verify_testInverseReferenceAutoUpdate_NonCompositeManyToOne(AtlasEntity a1, AtlasEntity a2, AtlasEntity a3, AtlasEntity b); + + @Test + public void testInverseReferenceAutoUpdate_NonComposite_OneToOne() throws Exception { + AtlasEntityType bType = typeRegistry.getEntityTypeByName("B"); + AtlasEntity a1 = new AtlasEntity("A"); + a1.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity a2 = new AtlasEntity("A"); + a2.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity b = new AtlasEntity("B"); + b.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntitiesWithExtInfo atlasEntitiesWithExtInfo = new AtlasEntitiesWithExtInfo(); + atlasEntitiesWithExtInfo.addEntity(a1); + atlasEntitiesWithExtInfo.addEntity(a2); + atlasEntitiesWithExtInfo.addEntity(b); + AtlasEntityStream entityStream = new AtlasEntityStream(atlasEntitiesWithExtInfo); + EntityMutationResponse response = entityStore.createOrUpdate(entityStream , false); + + AtlasEntity bForPartialUpdate = new AtlasEntity("B"); + bForPartialUpdate.setAttribute("a", AtlasTypeUtil.getAtlasObjectId(a1)); + init(); + response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(bForPartialUpdate)); + List<AtlasEntityHeader> partialUpdatedEntities = response.getPartialUpdatedEntities(); + // Verify 2 entities were updated: + // * set b.a reference to a1 + // * set inverse a1.b reference to b + assertEquals(partialUpdatedEntities.size(), 2); + AtlasEntitiesWithExtInfo storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), b.getGuid())); + AtlasEntity storedEntity = storedEntities.getEntity(a1.getGuid()); + verifyReferenceValue(storedEntity, "b", b.getGuid()); + storedEntity = storedEntities.getEntity(b.getGuid()); + verifyReferenceValue(storedEntity, "a", a1.getGuid()); + + // Update b.a to reference a2. + bForPartialUpdate.setAttribute("a", AtlasTypeUtil.getAtlasObjectId(a2)); + init(); + response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(bForPartialUpdate)); + partialUpdatedEntities = response.getPartialUpdatedEntities(); + // Verify 3 entities were updated: + // * set b.a reference to a2 + // * set a2.b reference to b + // * disconnect a1.b reference + assertEquals(partialUpdatedEntities.size(), 3); + storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b.getGuid())); + storedEntity = storedEntities.getEntity(a2.getGuid()); + verifyReferenceValue(storedEntity, "b", b.getGuid()); + storedEntity = storedEntities.getEntity(b.getGuid()); + verifyReferenceValue(storedEntity, "a", a2.getGuid()); + storedEntity = storedEntities.getEntity(a1.getGuid()); + Object refValue = storedEntity.getAttribute("b"); + verify_testInverseReferenceAutoUpdate_NonComposite_OneToOne(storedEntities.getEntity(a1.getGuid()), storedEntities.getEntity(b.getGuid())); + } + + protected abstract void verify_testInverseReferenceAutoUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b); + + @Test + public void testInverseReferenceAutoUpdate_NonComposite_ManyToMany() throws Exception { + AtlasEntityType bType = typeRegistry.getEntityTypeByName("B"); + AtlasEntity a1 = new AtlasEntity("A"); + a1.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity a2 = new AtlasEntity("A"); + a2.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity a3 = new AtlasEntity("A"); + a3.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity b1 = new AtlasEntity("B"); + b1.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity b2 = new AtlasEntity("B"); + b2.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntitiesWithExtInfo atlasEntitiesWithExtInfo = new AtlasEntitiesWithExtInfo(); + atlasEntitiesWithExtInfo.addEntity(a1); + atlasEntitiesWithExtInfo.addEntity(a2); + atlasEntitiesWithExtInfo.addEntity(a3); + atlasEntitiesWithExtInfo.addEntity(b1); + atlasEntitiesWithExtInfo.addEntity(b2); + AtlasEntityStream entityStream = new AtlasEntityStream(atlasEntitiesWithExtInfo); + EntityMutationResponse response = entityStore.createOrUpdate(entityStream , false); + + AtlasEntity b1ForPartialUpdate = new AtlasEntity("B"); + b1ForPartialUpdate.setAttribute("manyToManyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a1), AtlasTypeUtil.getAtlasObjectId(a2))); + init(); + response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b1.getAttribute(NAME)), new AtlasEntityWithExtInfo(b1ForPartialUpdate)); + List<AtlasEntityHeader> partialUpdatedEntities = response.getPartialUpdatedEntities(); + assertEquals(partialUpdatedEntities.size(), 3); + AtlasEntitiesWithExtInfo storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b1.getGuid())); + AtlasEntity storedEntity = storedEntities.getEntity(b1.getGuid()); + verifyReferenceList(storedEntity, "manyToManyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a1), AtlasTypeUtil.getAtlasObjectId(a2))); + storedEntity = storedEntities.getEntity(a1.getGuid()); + verifyReferenceList(storedEntity, "manyB", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(b1))); + storedEntity = storedEntities.getEntity(a2.getGuid()); + verifyReferenceList(storedEntity, "manyB", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(b1))); + } + + @Test + public void testInverseReferenceAutoUpdate_Map() throws Exception { + AtlasEntity a1 = new AtlasEntity("A"); + a1.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity b1 = new AtlasEntity("B"); + b1.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity b2 = new AtlasEntity("B"); + b2.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntity b3 = new AtlasEntity("B"); + b3.setAttribute(NAME, TestUtilsV2.randomString()); + AtlasEntitiesWithExtInfo atlasEntitiesWithExtInfo = new AtlasEntitiesWithExtInfo(); + atlasEntitiesWithExtInfo.addEntity(a1); + atlasEntitiesWithExtInfo.addEntity(b1); + atlasEntitiesWithExtInfo.addEntity(b2); + atlasEntitiesWithExtInfo.addEntity(b3); + AtlasEntityStream entityStream = new AtlasEntityStream(atlasEntitiesWithExtInfo); + EntityMutationResponse response = entityStore.createOrUpdate(entityStream , false); + + AtlasEntityType aType = typeRegistry.getEntityTypeByName("A"); + AtlasEntity aForPartialUpdate = new AtlasEntity("A"); + aForPartialUpdate.setAttribute("mapToB", ImmutableMap.<String, AtlasObjectId>of("b1", AtlasTypeUtil.getAtlasObjectId(b1), "b2", AtlasTypeUtil.getAtlasObjectId(b2))); + init(); + response = entityStore.updateByUniqueAttributes(aType, Collections.<String, Object>singletonMap(NAME, a1.getAttribute(NAME)), new AtlasEntityWithExtInfo(aForPartialUpdate)); + List<AtlasEntityHeader> partialUpdatedEntities = response.getPartialUpdatedEntities(); + // Verify 3 entities were updated: + // * set a1.mapToB to "b1"->b1, "b2"->b2 + // * set b1.mappedFromA to a1 + // * set b2.mappedFromA to a1 + assertEquals(partialUpdatedEntities.size(), 3); + AtlasEntitiesWithExtInfo storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), b2.getGuid(), b1.getGuid())); + AtlasEntity storedEntity = storedEntities.getEntity(a1.getGuid()); + Object value = storedEntity.getAttribute("mapToB"); + assertTrue(value instanceof Map); + Map<String, AtlasObjectId> refMap = (Map<String, AtlasObjectId>) value; + assertEquals(refMap.size(), 2); + AtlasObjectId referencedEntityId = refMap.get("b1"); + assertEquals(referencedEntityId, AtlasTypeUtil.getAtlasObjectId(b1)); + referencedEntityId = refMap.get("b2"); + assertEquals(referencedEntityId, AtlasTypeUtil.getAtlasObjectId(b2)); + storedEntity = storedEntities.getEntity(b1.getGuid()); + verifyReferenceValue(storedEntity, "mappedFromA", a1.getGuid()); + storedEntity = storedEntities.getEntity(b2.getGuid()); + verifyReferenceValue(storedEntity, "mappedFromA", a1.getGuid()); + + aForPartialUpdate.setAttribute("mapToB", ImmutableMap.<String, AtlasObjectId>of("b3", AtlasTypeUtil.getAtlasObjectId(b3))); + init(); + response = entityStore.updateByUniqueAttributes(aType, Collections.<String, Object>singletonMap(NAME, a1.getAttribute(NAME)), new AtlasEntityWithExtInfo(aForPartialUpdate)); + partialUpdatedEntities = response.getPartialUpdatedEntities(); + // Verify 4 entities were updated: + // * set a1.mapToB to "b3"->b3 + // * set b3.mappedFromA to a1 + // * disconnect b1.mappedFromA + // * disconnect b2.mappedFromA + assertEquals(partialUpdatedEntities.size(), 4); + storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), b2.getGuid(), b1.getGuid(), b3.getGuid())); + AtlasEntity storedB3 = storedEntities.getEntity(b3.getGuid()); + verifyReferenceValue(storedB3, "mappedFromA", a1.getGuid()); + verify_testInverseReferenceAutoUpdate_Map(storedEntities.getEntity(a1.getGuid()), storedEntities.getEntity(b1.getGuid()), storedEntities.getEntity(b2.getGuid()), storedB3); + } + + protected abstract void verify_testInverseReferenceAutoUpdate_Map(AtlasEntity a1, AtlasEntity b1, AtlasEntity b2, AtlasEntity b3); + + protected void verifyReferenceValue(AtlasEntity entity, String refName, String expectedGuid) { + Object refValue = entity.getAttribute(refName); + if (expectedGuid == null) { + assertNull(refValue); + } + else { + assertTrue(refValue instanceof AtlasObjectId); + AtlasObjectId referencedObjectId = (AtlasObjectId) refValue; + assertEquals(referencedObjectId.getGuid(), expectedGuid); + } + } + + protected void verifyReferenceList(AtlasEntity entity, String refName, List<AtlasObjectId> expectedValues) { + Object refValue = entity.getAttribute(refName); + assertTrue(refValue instanceof List); + List<AtlasObjectId> refList = (List<AtlasObjectId>) refValue; + assertEquals(refList.size(), expectedValues.size()); + if (expectedValues.size() > 0) { + assertTrue(refList.containsAll(expectedValues)); + } + } +} http://git-wip-us.apache.org/repos/asf/atlas/blob/4823c8ed/repository/src/test/java/org/apache/atlas/repository/tagpropagation/ClassificationPropagationTest.java ---------------------------------------------------------------------- diff --git a/repository/src/test/java/org/apache/atlas/repository/tagpropagation/ClassificationPropagationTest.java b/repository/src/test/java/org/apache/atlas/repository/tagpropagation/ClassificationPropagationTest.java index 151211e..8ceeedb 100644 --- a/repository/src/test/java/org/apache/atlas/repository/tagpropagation/ClassificationPropagationTest.java +++ b/repository/src/test/java/org/apache/atlas/repository/tagpropagation/ClassificationPropagationTest.java @@ -17,7 +17,7 @@ */ package org.apache.atlas.repository.tagpropagation; -import org.apache.atlas.RequestContextV1; +import org.apache.atlas.RequestContext; import org.apache.atlas.TestModules; import org.apache.atlas.discovery.AtlasLineageService; import org.apache.atlas.exception.AtlasBaseException; @@ -104,7 +104,7 @@ public class ClassificationPropagationTest { @BeforeClass public void setup() { - RequestContextV1.clear(); + RequestContext.clear(); loadModelFilesAndImportTestData(); } http://git-wip-us.apache.org/repos/asf/atlas/blob/4823c8ed/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 new file mode 100644 index 0000000..b4ff98a --- /dev/null +++ b/server-api/src/main/java/org/apache/atlas/RequestContext.java @@ -0,0 +1,186 @@ +/** + * 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 org.apache.atlas.model.instance.AtlasClassification; +import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo; +import org.apache.atlas.model.instance.AtlasObjectId; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +public class RequestContext { + private static final Logger LOG = LoggerFactory.getLogger(RequestContext.class); + + private static final ThreadLocal<RequestContext> CURRENT_CONTEXT = new ThreadLocal<>(); + + private final Map<String, AtlasObjectId> updatedEntities = new HashMap<>(); + private final Map<String, AtlasObjectId> deletedEntities = new HashMap<>(); + private final Map<String, AtlasEntityWithExtInfo> entityCacheV2 = new HashMap<>(); + private final Map<String, List<AtlasClassification>> addedPropagations = new HashMap<>(); + private final Map<String, List<AtlasClassification>> removedPropagations = new HashMap<>(); + private final long requestTime = System.currentTimeMillis(); + + private String user; + private Set<String> userGroups; + private String clientIPAddress; + + + 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() { + RequestContext ret = CURRENT_CONTEXT.get(); + + if (ret == null) { + ret = new RequestContext(); + CURRENT_CONTEXT.set(ret); + } + + return ret; + } + + public static void clear() { + RequestContext instance = CURRENT_CONTEXT.get(); + + if (instance != null) { + instance.updatedEntities.clear(); + instance.deletedEntities.clear(); + instance.entityCacheV2.clear(); + instance.addedPropagations.clear(); + instance.removedPropagations.clear(); + } + + CURRENT_CONTEXT.remove(); + } + + public String getUser() { + return user; + } + + public Set<String> getUserGroups() { + return userGroups; + } + + public void setUser(String user, Set<String> userGroups) { + this.user = user; + this.userGroups = userGroups; + } + + public String getClientIPAddress() { + return clientIPAddress; + } + + public void setClientIPAddress(String clientIPAddress) { + this.clientIPAddress = clientIPAddress; + } + + public void recordEntityUpdate(AtlasObjectId entity) { + if (entity != null && entity.getGuid() != null) { + updatedEntities.put(entity.getGuid(), entity); + } + } + + public void recordEntityDelete(AtlasObjectId entity) { + if (entity != null && entity.getGuid() != null) { + deletedEntities.put(entity.getGuid(), entity); + } + } + + public void recordAddedPropagation(String guid, AtlasClassification classification) { + if (StringUtils.isNotEmpty(guid) && classification != null) { + List<AtlasClassification> classifications = addedPropagations.get(guid); + + if (classifications == null) { + classifications = new ArrayList<>(); + } + + classifications.add(classification); + + addedPropagations.put(guid, classifications); + } + } + + public void recordRemovedPropagation(String guid, AtlasClassification classification) { + if (StringUtils.isNotEmpty(guid) && classification != null) { + List<AtlasClassification> classifications = removedPropagations.get(guid); + + if (classifications == null) { + classifications = new ArrayList<>(); + } + + classifications.add(classification); + + removedPropagations.put(guid, classifications); + } + } + + public Map<String, List<AtlasClassification>> getAddedPropagations() { + return addedPropagations; + } + + public Map<String, List<AtlasClassification>> getRemovedPropagations() { + return removedPropagations; + } + + /** + * Adds the specified instance to the cache + * + */ + public void cache(AtlasEntityWithExtInfo entity) { + if (entity != null && entity.getEntity() != null && entity.getEntity().getGuid() != null) { + entityCacheV2.put(entity.getEntity().getGuid(), entity); + } + } + + public Collection<AtlasObjectId> getUpdatedEntities() { + return updatedEntities.values(); + } + + public Collection<AtlasObjectId> getDeletedEntities() { + return deletedEntities.values(); + } + + /** + * Checks if an instance with the given guid is in the cache for this request. Either returns the instance + * or null if it is not in the cache. + * + * @param guid the guid to find + * @return Either the instance or null if it is not in the cache. + */ + public AtlasEntityWithExtInfo getInstanceV2(String guid) { + return entityCacheV2.get(guid); + } + + public long getRequestTime() { + return requestTime; + } + + public boolean isUpdatedEntity(String guid) { + return updatedEntities.containsKey(guid); + } + + public boolean isDeletedEntity(String guid) { + return deletedEntities.containsKey(guid); + } +} http://git-wip-us.apache.org/repos/asf/atlas/blob/4823c8ed/server-api/src/main/java/org/apache/atlas/RequestContextV1.java ---------------------------------------------------------------------- diff --git a/server-api/src/main/java/org/apache/atlas/RequestContextV1.java b/server-api/src/main/java/org/apache/atlas/RequestContextV1.java deleted file mode 100644 index 0fc15e8..0000000 --- a/server-api/src/main/java/org/apache/atlas/RequestContextV1.java +++ /dev/null @@ -1,186 +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 - * <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 org.apache.atlas.model.instance.AtlasClassification; -import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo; -import org.apache.atlas.model.instance.AtlasObjectId; -import org.apache.commons.lang.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; - -public class RequestContextV1 { - private static final Logger LOG = LoggerFactory.getLogger(RequestContextV1.class); - - private static final ThreadLocal<RequestContextV1> CURRENT_CONTEXT = new ThreadLocal<>(); - - private final Map<String, AtlasObjectId> updatedEntities = new HashMap<>(); - private final Map<String, AtlasObjectId> deletedEntities = new HashMap<>(); - private final Map<String, AtlasEntityWithExtInfo> entityCacheV2 = new HashMap<>(); - private final Map<String, List<AtlasClassification>> addedPropagations = new HashMap<>(); - private final Map<String, List<AtlasClassification>> removedPropagations = new HashMap<>(); - private final long requestTime = System.currentTimeMillis(); - - private String user; - private Set<String> userGroups; - private String clientIPAddress; - - - private RequestContextV1() { - } - - //To handle gets from background threads where createContext() is not called - //createContext called for every request in the filter - public static RequestContextV1 get() { - RequestContextV1 ret = CURRENT_CONTEXT.get(); - - if (ret == null) { - ret = new RequestContextV1(); - CURRENT_CONTEXT.set(ret); - } - - return ret; - } - - public static void clear() { - RequestContextV1 instance = CURRENT_CONTEXT.get(); - - if (instance != null) { - instance.updatedEntities.clear(); - instance.deletedEntities.clear(); - instance.entityCacheV2.clear(); - instance.addedPropagations.clear(); - instance.removedPropagations.clear(); - } - - CURRENT_CONTEXT.remove(); - } - - public String getUser() { - return user; - } - - public Set<String> getUserGroups() { - return userGroups; - } - - public void setUser(String user, Set<String> userGroups) { - this.user = user; - this.userGroups = userGroups; - } - - public String getClientIPAddress() { - return clientIPAddress; - } - - public void setClientIPAddress(String clientIPAddress) { - this.clientIPAddress = clientIPAddress; - } - - public void recordEntityUpdate(AtlasObjectId entity) { - if (entity != null && entity.getGuid() != null) { - updatedEntities.put(entity.getGuid(), entity); - } - } - - public void recordEntityDelete(AtlasObjectId entity) { - if (entity != null && entity.getGuid() != null) { - deletedEntities.put(entity.getGuid(), entity); - } - } - - public void recordAddedPropagation(String guid, AtlasClassification classification) { - if (StringUtils.isNotEmpty(guid) && classification != null) { - List<AtlasClassification> classifications = addedPropagations.get(guid); - - if (classifications == null) { - classifications = new ArrayList<>(); - } - - classifications.add(classification); - - addedPropagations.put(guid, classifications); - } - } - - public void recordRemovedPropagation(String guid, AtlasClassification classification) { - if (StringUtils.isNotEmpty(guid) && classification != null) { - List<AtlasClassification> classifications = removedPropagations.get(guid); - - if (classifications == null) { - classifications = new ArrayList<>(); - } - - classifications.add(classification); - - removedPropagations.put(guid, classifications); - } - } - - public Map<String, List<AtlasClassification>> getAddedPropagations() { - return addedPropagations; - } - - public Map<String, List<AtlasClassification>> getRemovedPropagations() { - return removedPropagations; - } - - /** - * Adds the specified instance to the cache - * - */ - public void cache(AtlasEntityWithExtInfo entity) { - if (entity != null && entity.getEntity() != null && entity.getEntity().getGuid() != null) { - entityCacheV2.put(entity.getEntity().getGuid(), entity); - } - } - - public Collection<AtlasObjectId> getUpdatedEntities() { - return updatedEntities.values(); - } - - public Collection<AtlasObjectId> getDeletedEntities() { - return deletedEntities.values(); - } - - /** - * Checks if an instance with the given guid is in the cache for this request. Either returns the instance - * or null if it is not in the cache. - * - * @param guid the guid to find - * @return Either the instance or null if it is not in the cache. - */ - public AtlasEntityWithExtInfo getInstanceV2(String guid) { - return entityCacheV2.get(guid); - } - - public long getRequestTime() { - return requestTime; - } - - public boolean isUpdatedEntity(String guid) { - return updatedEntities.containsKey(guid); - } - - public boolean isDeletedEntity(String guid) { - return deletedEntities.containsKey(guid); - } -} http://git-wip-us.apache.org/repos/asf/atlas/blob/4823c8ed/webapp/src/main/java/org/apache/atlas/notification/EntityNotificationListenerV2.java ---------------------------------------------------------------------- diff --git a/webapp/src/main/java/org/apache/atlas/notification/EntityNotificationListenerV2.java b/webapp/src/main/java/org/apache/atlas/notification/EntityNotificationListenerV2.java index 017de99..c70011f 100644 --- a/webapp/src/main/java/org/apache/atlas/notification/EntityNotificationListenerV2.java +++ b/webapp/src/main/java/org/apache/atlas/notification/EntityNotificationListenerV2.java @@ -18,7 +18,7 @@ package org.apache.atlas.notification; import org.apache.atlas.AtlasErrorCode; -import org.apache.atlas.RequestContextV1; +import org.apache.atlas.RequestContext; import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.listener.EntityChangeListenerV2; import org.apache.atlas.model.glossary.AtlasGlossaryTerm; @@ -48,11 +48,11 @@ import java.util.Set; import static org.apache.atlas.notification.NotificationInterface.NotificationType.ENTITIES; import static org.apache.atlas.repository.graph.GraphHelper.isInternalType; import static org.apache.atlas.model.notification.EntityNotification.EntityNotificationV2.OperationType.*; -import static org.apache.atlas.repository.store.graph.v1.EntityGraphRetriever.CREATE_TIME; -import static org.apache.atlas.repository.store.graph.v1.EntityGraphRetriever.DESCRIPTION; -import static org.apache.atlas.repository.store.graph.v1.EntityGraphRetriever.NAME; -import static org.apache.atlas.repository.store.graph.v1.EntityGraphRetriever.OWNER; -import static org.apache.atlas.repository.store.graph.v1.EntityGraphRetriever.QUALIFIED_NAME; +import static org.apache.atlas.repository.store.graph.v2.EntityGraphRetriever.CREATE_TIME; +import static org.apache.atlas.repository.store.graph.v2.EntityGraphRetriever.DESCRIPTION; +import static org.apache.atlas.repository.store.graph.v2.EntityGraphRetriever.NAME; +import static org.apache.atlas.repository.store.graph.v2.EntityGraphRetriever.OWNER; +import static org.apache.atlas.repository.store.graph.v2.EntityGraphRetriever.QUALIFIED_NAME; @Component public class EntityNotificationListenerV2 implements EntityChangeListenerV2 { @@ -89,8 +89,8 @@ public class EntityNotificationListenerV2 implements EntityChangeListenerV2 { @Override public void onClassificationsUpdated(AtlasEntity entity, List<AtlasClassification> classifications) throws AtlasBaseException { - Map<String, List<AtlasClassification>> addedPropagations = RequestContextV1.get().getAddedPropagations(); - Map<String, List<AtlasClassification>> removedPropagations = RequestContextV1.get().getRemovedPropagations(); + Map<String, List<AtlasClassification>> addedPropagations = RequestContext.get().getAddedPropagations(); + Map<String, List<AtlasClassification>> removedPropagations = RequestContext.get().getRemovedPropagations(); if (addedPropagations.containsKey(entity.getGuid())) { notifyEntityEvents(Collections.singletonList(entity), CLASSIFICATION_ADD);