Repository: incubator-atlas Updated Branches: refs/heads/master 758b3d4df -> 33d60746a
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/33d60746/webapp/src/main/java/org/apache/atlas/web/rest/EntitiesREST.java ---------------------------------------------------------------------- diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/EntitiesREST.java b/webapp/src/main/java/org/apache/atlas/web/rest/EntitiesREST.java index 543cbe2..768ef12 100644 --- a/webapp/src/main/java/org/apache/atlas/web/rest/EntitiesREST.java +++ b/webapp/src/main/java/org/apache/atlas/web/rest/EntitiesREST.java @@ -18,19 +18,29 @@ package org.apache.atlas.web.rest; import com.google.inject.Inject; +import org.apache.atlas.AtlasClient; +import org.apache.atlas.AtlasErrorCode; +import org.apache.atlas.AtlasException; import org.apache.atlas.exception.AtlasBaseException; -import org.apache.atlas.model.SearchFilter; -import org.apache.atlas.model.instance.AtlasClassification; import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasEntityHeader; +import org.apache.atlas.model.instance.AtlasEntityWithAssociations; import org.apache.atlas.model.instance.EntityMutationResponse; import org.apache.atlas.repository.store.graph.AtlasEntityStore; import org.apache.atlas.services.MetadataService; import org.apache.atlas.type.AtlasTypeRegistry; -import org.apache.atlas.typesystem.types.TypeSystem; +import org.apache.atlas.typesystem.ITypedReferenceableInstance; +import org.apache.atlas.web.adapters.AtlasFormatConverters; +import org.apache.atlas.web.adapters.AtlasInstanceRestAdapters; import org.apache.atlas.web.util.Servlets; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static org.apache.atlas.web.adapters.AtlasInstanceRestAdapters.toAtlasBaseException; +import static org.apache.atlas.web.adapters.AtlasInstanceRestAdapters.toEntityMutationResponse; + import javax.inject.Singleton; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; @@ -42,6 +52,8 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; @@ -58,14 +70,16 @@ public class EntitiesREST { @Inject private MetadataService metadataService; - private TypeSystem typeSystem = TypeSystem.getInstance(); - + private AtlasTypeRegistry typeRegistry; + @Inject + AtlasInstanceRestAdapters restAdapters; @Inject public EntitiesREST(AtlasEntityStore entitiesStore, AtlasTypeRegistry atlasTypeRegistry) { LOG.info("EntitiesRest Init"); this.entitiesStore = entitiesStore; + this.typeRegistry = atlasTypeRegistry; } /******* @@ -78,7 +92,17 @@ public class EntitiesREST { @Consumes(Servlets.JSON_MEDIA_TYPE) @Produces(Servlets.JSON_MEDIA_TYPE) public EntityMutationResponse createOrUpdate(List<AtlasEntity> entities) throws AtlasBaseException { - return null; + EntityMutationResponse response = null; + ITypedReferenceableInstance[] entitiesInOldFormat = restAdapters.getITypedReferenceables(entities); + + try { + final AtlasClient.EntityResult result = metadataService.updateEntities(entitiesInOldFormat); + response = toEntityMutationResponse(result); + } catch (AtlasException e) { + LOG.error("Exception while getting a typed reference for the entity ", e); + throw AtlasInstanceRestAdapters.toAtlasBaseException(e); + } + return response; } /******* @@ -90,15 +114,35 @@ public class EntitiesREST { @Consumes(Servlets.JSON_MEDIA_TYPE) @Produces(Servlets.JSON_MEDIA_TYPE) public EntityMutationResponse update(List<AtlasEntity> entities) throws AtlasBaseException { - return null; + return createOrUpdate(entities); } @GET @Path("/guids") @Consumes(Servlets.JSON_MEDIA_TYPE) @Produces(Servlets.JSON_MEDIA_TYPE) - public EntityMutationResponse getById(@QueryParam("guid") List<String> guids) throws AtlasBaseException { - return null; + public AtlasEntity.AtlasEntities getById(@QueryParam("guid") List<String> guids) throws AtlasBaseException { + + if (CollectionUtils.isEmpty(guids)) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guids); + } + + AtlasEntity.AtlasEntities entities = new AtlasEntity.AtlasEntities(); + + List<AtlasEntity> entityList = new ArrayList<>(); + + for (String guid : guids) { + try { + ITypedReferenceableInstance ref = metadataService.getEntityDefinition(guid); + AtlasEntity entity = restAdapters.getAtlasEntity(ref); + entityList.add(entity); + } catch (AtlasException e) { + throw toAtlasBaseException(e); + } + } + + entities.setList(entityList); + return entities; } /******* @@ -109,8 +153,17 @@ public class EntitiesREST { @Path("/guids") @Consumes(Servlets.JSON_MEDIA_TYPE) @Produces(Servlets.JSON_MEDIA_TYPE) - public EntityMutationResponse deleteById(@QueryParam("guid") List<String> guids) throws AtlasBaseException { - return null; + public EntityMutationResponse deleteById(@QueryParam("guid") final List<String> guids) throws AtlasBaseException { + + if (CollectionUtils.isEmpty(guids)) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guids); + } + try { + AtlasClient.EntityResult result = metadataService.deleteEntities(guids); + return toEntityMutationResponse(result); + } catch (AtlasException e) { + throw toAtlasBaseException(e); + } } /** @@ -120,8 +173,9 @@ public class EntitiesREST { */ @GET @Produces(Servlets.JSON_MEDIA_TYPE) - public AtlasEntity.AtlasEntities searchEntities() throws AtlasBaseException { + public AtlasEntityHeader.AtlasEntityHeaders searchEntities() throws AtlasBaseException { //SearchFilter searchFilter + //TODO: Need to handle getEntitiesByType for older API return null; } http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/33d60746/webapp/src/main/java/org/apache/atlas/web/rest/EntityRest.java ---------------------------------------------------------------------- diff --git a/webapp/src/main/java/org/apache/atlas/web/rest/EntityRest.java b/webapp/src/main/java/org/apache/atlas/web/rest/EntityRest.java index df5138e..6bbc69c 100644 --- a/webapp/src/main/java/org/apache/atlas/web/rest/EntityRest.java +++ b/webapp/src/main/java/org/apache/atlas/web/rest/EntityRest.java @@ -17,10 +17,30 @@ */ package org.apache.atlas.web.rest; +import com.google.inject.Inject; +import org.apache.atlas.AtlasClient; +import org.apache.atlas.AtlasErrorCode; +import org.apache.atlas.AtlasException; +import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.TypeCategory; import org.apache.atlas.model.instance.AtlasClassification; import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasEntityWithAssociations; import org.apache.atlas.model.instance.EntityMutationResponse; +import org.apache.atlas.model.typedef.AtlasStructDef; +import org.apache.atlas.services.MetadataService; +import org.apache.atlas.type.AtlasEntityType; +import org.apache.atlas.type.AtlasType; +import org.apache.atlas.type.AtlasTypeRegistry; +import org.apache.atlas.typesystem.IStruct; +import org.apache.atlas.typesystem.ITypedReferenceableInstance; +import org.apache.atlas.typesystem.ITypedStruct; +import org.apache.atlas.typesystem.Referenceable; +import org.apache.atlas.web.adapters.AtlasInstanceRestAdapters; import org.apache.atlas.web.util.Servlets; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.inject.Singleton; import javax.ws.rs.Consumes; @@ -33,17 +53,30 @@ import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; +import java.util.ArrayList; import java.util.List; +import static org.apache.atlas.web.adapters.AtlasInstanceRestAdapters.toAtlasBaseException; +import static org.apache.atlas.web.adapters.AtlasInstanceRestAdapters.toEntityMutationResponse; + /** * REST for a single entity */ @Path("v2/entity") @Singleton -public class EntityRest { +public class EntityREST { + + private static final Logger LOG = LoggerFactory.getLogger(EntityREST.class); + + @Inject + AtlasTypeRegistry typeRegistry; + @Inject + AtlasInstanceRestAdapters restAdapters; + + @Inject + private MetadataService metadataService; /** * Create or Update an entity if it already exists * @@ -53,8 +86,18 @@ public class EntityRest { @POST @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON}) @Produces(Servlets.JSON_MEDIA_TYPE) - public EntityMutationResponse createOrUpdate(AtlasEntity entity) { - return null; + public EntityMutationResponse createOrUpdate(final AtlasEntity entity) throws AtlasBaseException { + EntityMutationResponse response = null; + ITypedReferenceableInstance[] entitiesInOldFormat = restAdapters.getITypedReferenceables(new ArrayList<AtlasEntity>() {{ add(entity); }}); + + try { + final AtlasClient.EntityResult result = metadataService.updateEntities(entitiesInOldFormat); + response = toEntityMutationResponse(result); + } catch (AtlasException e) { + LOG.error("Exception while getting a typed reference for the entity ", e); + throw AtlasInstanceRestAdapters.toAtlasBaseException(e); + } + return response; } /** @@ -68,8 +111,8 @@ public class EntityRest { @Path("guid/{guid}") @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON}) @Produces(Servlets.JSON_MEDIA_TYPE) - public EntityMutationResponse updateByGuid(@PathParam("guid") String guid, AtlasEntity entity, @DefaultValue("false") @QueryParam("partialUpdate") boolean partialUpdate) { - return null; + public EntityMutationResponse updateByGuid(@PathParam("guid") String guid, AtlasEntity entity, @DefaultValue("false") @QueryParam("partialUpdate") boolean partialUpdate) throws AtlasBaseException { + return createOrUpdate(entity); } @@ -81,11 +124,35 @@ public class EntityRest { @GET @Path("/guid/{guid}") @Produces(Servlets.JSON_MEDIA_TYPE) - public AtlasEntity getByGuid(@PathParam("guid") String guid) { - return null; + public AtlasEntity getById(@PathParam("guid") String guid) throws AtlasBaseException { + try { + ITypedReferenceableInstance ref = metadataService.getEntityDefinition(guid); + return restAdapters.getAtlasEntity(ref); + } catch (AtlasException e) { + throw toAtlasBaseException(e); + } + } + + /** + * Fetch the complete definition of an entity given its GUID including its associations + * like classifications, terms etc. + * + * @param guid GUID for the entity + */ + @GET + @Path("/guid/{guid}/associations") + @Produces(Servlets.JSON_MEDIA_TYPE) + public AtlasEntityWithAssociations getWithAssociationsByGuid(@PathParam("guid") String guid) throws AtlasBaseException { + try { + ITypedReferenceableInstance ref = metadataService.getEntityDefinition(guid); + return restAdapters.getAtlasEntity(ref); + } catch (AtlasException e) { + throw toAtlasBaseException(e); + } } + /** * Delete an entity identified by its GUID * @@ -96,8 +163,16 @@ public class EntityRest { @Path("guid/{guid}") @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON}) @Produces(Servlets.JSON_MEDIA_TYPE) - public EntityMutationResponse deleteByGuid(@PathParam("guid") String guid) { - return null; + public EntityMutationResponse deleteByGuid(@PathParam("guid") final String guid) throws AtlasBaseException { + if (StringUtils.isEmpty(guid)) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); + } + try { + AtlasClient.EntityResult result = metadataService.deleteEntities(new ArrayList<String>() {{ add(guid); }}); + return toEntityMutationResponse(result); + } catch (AtlasException e) { + throw toAtlasBaseException(e); + } } @@ -115,7 +190,13 @@ public class EntityRest { public EntityMutationResponse partialUpdateByUniqueAttribute(@PathParam("typeName") String entityType, @PathParam("attrName") String attribute, @QueryParam("value") String value, AtlasEntity entity) throws Exception { - return null; + + AtlasEntityType type = (AtlasEntityType) validateType(entityType, TypeCategory.ENTITY); + validateUniqueAttribute(type, attribute); + + Referenceable ref = restAdapters.getReferenceable(entity); + AtlasClient.EntityResult result = metadataService.updateEntityByUniqueAttribute(entityType, attribute, value, ref); + return toEntityMutationResponse(result); } @Deprecated @@ -126,7 +207,12 @@ public class EntityRest { public EntityMutationResponse deleteByUniqueAttribute(@PathParam("typeName") String entityType, @PathParam("attrName") String attribute, @QueryParam("value") String value) throws Exception { - return null; + + AtlasEntityType type = (AtlasEntityType) validateType(entityType, TypeCategory.ENTITY); + validateUniqueAttribute(type, attribute); + + final AtlasClient.EntityResult result = metadataService.deleteEntityByUniqueAttribute(entityType, attribute, value); + return toEntityMutationResponse(result); } /** @@ -140,8 +226,17 @@ public class EntityRest { @Path("/uniqueAttribute/type/{typeName}/attribute/{attrName}") public AtlasEntity getByUniqueAttribute(@PathParam("typeName") String entityType, @PathParam("attrName") String attribute, - @QueryParam("value") String value) { - return null; + @QueryParam("value") String value) throws AtlasBaseException { + + AtlasEntityType type = (AtlasEntityType) validateType(entityType, TypeCategory.ENTITY); + validateUniqueAttribute(type, attribute); + + try { + final ITypedReferenceableInstance entityDefinitionReference = metadataService.getEntityDefinitionReference(entityType, attribute, value); + return restAdapters.getAtlasEntity(entityDefinitionReference); + } catch (AtlasException e) { + throw toAtlasBaseException(e); + } } @@ -154,8 +249,21 @@ public class EntityRest { @GET @Path("/guid/{guid}/classification/{classificationName}") @Produces(Servlets.JSON_MEDIA_TYPE) - public AtlasClassification.AtlasClassifications getClassification(@PathParam("guid") String guid, @PathParam("classificationName") String classificationName) { - return null; + public AtlasClassification getClassification(@PathParam("guid") String guid, @PathParam("classificationName") String classificationName) throws AtlasBaseException { + + if (StringUtils.isEmpty(guid)) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); + } + + validateType(classificationName, TypeCategory.CLASSIFICATION); + + try { + IStruct trait = metadataService.getTraitDefinition(guid, classificationName); + return restAdapters.getClassification(trait); + + } catch (AtlasException e) { + throw toAtlasBaseException(e); + } } @@ -168,8 +276,28 @@ public class EntityRest { @GET @Path("/guid/{guid}/classifications") @Produces(Servlets.JSON_MEDIA_TYPE) - public AtlasClassification.AtlasClassifications getClassifications(@PathParam("guid") String guid) { - return null; + public AtlasClassification.AtlasClassifications getClassifications(@PathParam("guid") String guid) throws AtlasBaseException { + + if (StringUtils.isEmpty(guid)) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); + } + + AtlasClassification.AtlasClassifications clss = new AtlasClassification.AtlasClassifications(); + + try { + List<AtlasClassification> clsList = new ArrayList<>(); + for ( String traitName : metadataService.getTraitNames(guid) ) { + IStruct trait = metadataService.getTraitDefinition(guid, traitName); + AtlasClassification cls = restAdapters.getClassification(trait); + clsList.add(cls); + } + + clss.setList(clsList); + + } catch (AtlasException e) { + throw toAtlasBaseException(e); + } + return clss; } /** @@ -185,7 +313,20 @@ public class EntityRest { @Path("/guid/{guid}/classifications") @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON}) @Produces(Servlets.JSON_MEDIA_TYPE) - public void addClassifications(@PathParam("guid") final String guid, List<AtlasClassification> classifications) { + public void addClassifications(@PathParam("guid") final String guid, List<AtlasClassification> classifications) throws AtlasBaseException { + + if (StringUtils.isEmpty(guid)) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); + } + + for (AtlasClassification classification: classifications) { + final ITypedStruct trait = restAdapters.getTrait(classification); + try { + metadataService.addTrait(guid, trait); + } catch (AtlasException e) { + throw toAtlasBaseException(e); + } + } } /** @@ -198,7 +339,12 @@ public class EntityRest { @Path("/guid/{guid}/classifications") @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON}) @Produces(Servlets.JSON_MEDIA_TYPE) - public void updateClassifications(@PathParam("guid") final String guid, List<AtlasClassification> classifications) { + public void updateClassifications(@PathParam("guid") final String guid, List<AtlasClassification> classifications) throws AtlasBaseException { + //Not supported in old API + + if (StringUtils.isEmpty(guid)) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); + } } /** @@ -212,6 +358,43 @@ public class EntityRest { @Consumes({Servlets.JSON_MEDIA_TYPE, MediaType.APPLICATION_JSON}) @Produces(Servlets.JSON_MEDIA_TYPE) public void deleteClassification(@PathParam("guid") String guid, - @PathParam("classificationName") String classificationName) { + @PathParam("classificationName") String classificationName) throws AtlasBaseException { + + if (StringUtils.isEmpty(guid)) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, guid); + } + + validateType(classificationName, TypeCategory.CLASSIFICATION); + + try { + metadataService.deleteTrait(guid, classificationName); + } catch (AtlasException e) { + throw toAtlasBaseException(e); + } + } + + private AtlasType validateType(String entityType, TypeCategory expectedCategory) throws AtlasBaseException { + if ( StringUtils.isEmpty(entityType) ) { + throw new AtlasBaseException(AtlasErrorCode.TYPE_NAME_INVALID, entityType); + } + + AtlasType type = typeRegistry.getType(entityType); + if (type.getTypeCategory() != expectedCategory) { + throw new AtlasBaseException(AtlasErrorCode.TYPE_CATEGORY_INVALID, type.getTypeCategory().name(), expectedCategory.name()); + } + + return type; + } + + /** + * Validate that attribute is unique attribute + * @param entityType the entity type + * @param attributeName the name of the attribute + */ + private void validateUniqueAttribute(AtlasEntityType entityType, String attributeName) throws AtlasBaseException { + AtlasStructDef.AtlasAttributeDef attribute = entityType.getAttributeDef(attributeName); + if (!attribute.getIsUnique()) { + throw new AtlasBaseException(AtlasErrorCode.ATTRIBUTE_UNIQUE_INVALID, entityType.getTypeName(), attributeName); + } } } http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/33d60746/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java ---------------------------------------------------------------------- diff --git a/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java b/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java new file mode 100644 index 0000000..f8e18bf --- /dev/null +++ b/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java @@ -0,0 +1,216 @@ +/** + * 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.web.adapters; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.atlas.AtlasClient; +import org.apache.atlas.RepositoryMetadataModule; +import org.apache.atlas.RequestContext; +import org.apache.atlas.TestUtilsV2; +import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasEntityHeader; +import org.apache.atlas.model.instance.AtlasStruct; +import org.apache.atlas.model.instance.EntityMutationResponse; +import org.apache.atlas.model.instance.EntityMutations; +import org.apache.atlas.model.typedef.AtlasTypesDef; +import org.apache.atlas.repository.graph.AtlasGraphProvider; +import org.apache.atlas.store.AtlasTypeDefStore; +import org.apache.atlas.web.rest.EntitiesREST; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; + +import javax.inject.Inject; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +@Guice(modules = {AtlasFormatConvertersModule.class, RepositoryMetadataModule.class}) +public class TestEntitiesREST { + + private static final Logger LOG = LoggerFactory.getLogger(TestEntitiesREST.class); + + @Inject + private AtlasTypeDefStore typeStore; + + @Inject + private EntitiesREST entitiesREST; + + private List<String> createdGuids = new ArrayList<>(); + + private AtlasEntity dbEntity; + + private AtlasEntity tableEntity; + + private List<AtlasEntity> columns; + + @BeforeClass + public void setUp() throws Exception { + AtlasTypesDef typesDef = TestUtilsV2.defineHiveTypes(); + typeStore.createTypesDef(typesDef); + dbEntity = TestUtilsV2.createDBEntity(); + + tableEntity = TestUtilsV2.createTableEntity(dbEntity.getGuid()); + final AtlasEntity colEntity = TestUtilsV2.createColumnEntity(); + columns = new ArrayList<AtlasEntity>() {{ add(colEntity); }}; + tableEntity.setAttribute("columns", columns); + } + + @AfterMethod + public void cleanup() throws Exception { + RequestContext.clear(); + } + + @AfterClass + public void tearDown() throws Exception { + AtlasGraphProvider.cleanup(); + } + + @Test + public void testCreateOrUpdateEntities() throws Exception { + List<AtlasEntity> entities = new ArrayList<AtlasEntity>(); + entities.add(dbEntity); + entities.add(tableEntity); + + EntityMutationResponse response = entitiesREST.createOrUpdate(entities); + List<AtlasEntityHeader> guids = response.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE); + + Assert.assertNotNull(guids); + Assert.assertEquals(guids.size(), 3); + + for (AtlasEntityHeader header : guids) { + createdGuids.add(header.getGuid()); + } + } + + @Test + public void testUpdateWithSerializedEntities() throws Exception { + //Check with serialization and deserialization of entity attributes for the case + // where attributes which are de-serialized into a map + AtlasEntity dbEntity = TestUtilsV2.createDBEntity(); + + AtlasEntity tableEntity = TestUtilsV2.createTableEntity(dbEntity.getGuid()); + final AtlasEntity colEntity = TestUtilsV2.createColumnEntity(); + List<AtlasEntity> columns = new ArrayList<AtlasEntity>() {{ add(colEntity); }}; + tableEntity.setAttribute("columns", columns); + + AtlasEntity newDBEntity = serDeserEntity(dbEntity); + AtlasEntity newTableEntity = serDeserEntity(tableEntity); + + List<AtlasEntity> newEntities = new ArrayList<AtlasEntity>(); + newEntities.add(newDBEntity); + newEntities.add(newTableEntity); + EntityMutationResponse response2 = entitiesREST.createOrUpdate(newEntities); + + List<AtlasEntityHeader> newGuids = response2.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE); + Assert.assertNotNull(newGuids); + Assert.assertEquals(newGuids.size(), 3); + } + + @Test(dependsOnMethods = "testCreateOrUpdateEntities") + public void testGetEntities() throws Exception { + + final AtlasEntity.AtlasEntities response = entitiesREST.getById(createdGuids); + final List<AtlasEntity> entities = response.getList(); + + Assert.assertNotNull(entities); + Assert.assertEquals(entities.size(), 3); + verifyAttributes(entities); + } + + @Test(dependsOnMethods = "testGetEntities") + public void testDeleteEntities() throws Exception { + + final EntityMutationResponse response = entitiesREST.deleteById(createdGuids); + final List<AtlasEntityHeader> entities = response.getEntitiesByOperation(EntityMutations.EntityOperation.DELETE); + + Assert.assertNotNull(entities); + Assert.assertEquals(entities.size(), 3); + } + + private void verifyAttributes(List<AtlasEntity> retrievedEntities) throws Exception { + AtlasEntity retrievedDBEntity = null; + AtlasEntity retrievedTableEntity = null; + AtlasEntity retrievedColumnEntity = null; + for (AtlasEntity entity: retrievedEntities ) { + if ( entity.getTypeName().equals(TestUtilsV2.DATABASE_TYPE)) { + retrievedDBEntity = entity; + } + + if ( entity.getTypeName().equals(TestUtilsV2.TABLE_TYPE)) { + retrievedTableEntity = entity; + } + + if ( entity.getTypeName().equals(TestUtilsV2.COLUMN_TYPE)) { + retrievedColumnEntity = entity; + } + } + + if ( retrievedDBEntity != null) { + LOG.info("verifying entity of type {} ", dbEntity.getTypeName()); + verifyAttributes(dbEntity.getAttributes(), retrievedDBEntity.getAttributes()); + } + + if ( retrievedColumnEntity != null) { + LOG.info("verifying entity of type {} ", columns.get(0).getTypeName()); + verifyAttributes(columns.get(0).getAttributes(), retrievedColumnEntity.getAttributes()); + } + + if ( retrievedTableEntity != null) { + LOG.info("verifying entity of type {} ", tableEntity.getTypeName()); + + //String + Assert.assertEquals(tableEntity.getAttribute(AtlasClient.NAME), retrievedTableEntity.getAttribute(AtlasClient.NAME)); + //Map + Assert.assertEquals(tableEntity.getAttribute("parametersMap"), retrievedTableEntity.getAttribute("parametersMap")); + //enum + Assert.assertEquals(tableEntity.getAttribute("tableType"), retrievedTableEntity.getAttribute("tableType")); + //date + Assert.assertEquals(tableEntity.getAttribute("created"), retrievedTableEntity.getAttribute("created")); + //array of Ids + Assert.assertEquals(((List<AtlasEntity>) retrievedTableEntity.getAttribute("columns")).get(0).getGuid(), retrievedColumnEntity.getGuid()); + //array of structs + Assert.assertEquals(((List<AtlasStruct>) retrievedTableEntity.getAttribute("partitions")), tableEntity.getAttribute("partitions")); + } + } + + public static void verifyAttributes(Map<String, Object> sourceAttrs, Map<String, Object> targetAttributes) throws Exception { + for (String name : sourceAttrs.keySet() ) { + LOG.info("verifying attribute {} ", name); + Assert.assertEquals(targetAttributes.get(name), sourceAttrs.get(name)); + } + } + + AtlasEntity serDeserEntity(AtlasEntity entity) throws IOException { + //Convert from json to object and back to trigger the case where it gets translated to a map for attributes instead of AtlasEntity + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + String entityJson = mapper.writeValueAsString(entity); + //JSON from String to Object + AtlasEntity newEntity = mapper.readValue(entityJson, AtlasEntity.class); + return newEntity; + } +} http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/33d60746/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntityREST.java ---------------------------------------------------------------------- diff --git a/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntityREST.java b/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntityREST.java new file mode 100644 index 0000000..6dd21d1 --- /dev/null +++ b/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntityREST.java @@ -0,0 +1,181 @@ +/** + * 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.web.adapters; + +import org.apache.atlas.RepositoryMetadataModule; +import org.apache.atlas.RequestContext; +import org.apache.atlas.TestUtilsV2; +import org.apache.atlas.model.instance.AtlasClassification; +import org.apache.atlas.model.instance.AtlasEntity; +import org.apache.atlas.model.instance.AtlasEntityHeader; +import org.apache.atlas.model.instance.AtlasEntityWithAssociations; +import org.apache.atlas.model.instance.EntityMutationResponse; +import org.apache.atlas.model.instance.EntityMutations; +import org.apache.atlas.model.typedef.AtlasTypesDef; +import org.apache.atlas.repository.graph.AtlasGraphProvider; +import org.apache.atlas.store.AtlasTypeDefStore; +import org.apache.atlas.web.rest.EntityREST; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.AfterClass; +import org.testng.annotations.Guice; +import org.testng.annotations.Test; +import org.testng.internal.Invoker; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +@Guice(modules = {AtlasFormatConvertersModule.class, RepositoryMetadataModule.class}) +public class TestEntityREST { + + @Inject + private AtlasTypeDefStore typeStore; + + @Inject + private EntityREST entityREST; + + private AtlasEntity dbEntity; + + private String dbGuid; + + private AtlasClassification testClassification; + + @BeforeClass + public void setUp() throws Exception { + AtlasTypesDef typesDef = TestUtilsV2.defineHiveTypes(); + typeStore.createTypesDef(typesDef); + dbEntity = TestUtilsV2.createDBEntity(); + } + + @AfterClass + public void tearDown() throws Exception { + AtlasGraphProvider.cleanup(); + } + + @AfterMethod + public void cleanup() throws Exception { + RequestContext.clear(); + } + + @Test + public void testCreateOrUpdateEntity() throws Exception { + final EntityMutationResponse response = entityREST.createOrUpdate(dbEntity); + + Assert.assertNotNull(response); + List<AtlasEntityHeader> entitiesMutated = response.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE); + + Assert.assertNotNull(entitiesMutated); + Assert.assertEquals(entitiesMutated.size(), 1); + Assert.assertNotNull(entitiesMutated.get(0)); + dbGuid = entitiesMutated.get(0).getGuid(); + Assert.assertEquals(entitiesMutated.size(), 1); + } + + @Test(dependsOnMethods = "testCreateOrUpdateEntity") + public void testGetEntityById() throws Exception { + + final AtlasEntity response = entityREST.getById(dbGuid); + + Assert.assertNotNull(response); + TestEntitiesREST.verifyAttributes(response.getAttributes(), dbEntity.getAttributes()); + } + + @Test(dependsOnMethods = "testCreateOrUpdateEntity") + public void testAddAndGetClassification() throws Exception { + + List<AtlasClassification> classifications = new ArrayList<>(); + testClassification = new AtlasClassification(TestUtilsV2.CLASSIFICATION, new HashMap<String, Object>() {{ put("tag", "tagName"); }}); + classifications.add(testClassification); + entityREST.addClassifications(dbGuid, classifications); + + final AtlasClassification.AtlasClassifications retrievedClassifications = entityREST.getClassifications(dbGuid); + Assert.assertNotNull(retrievedClassifications); + final List<AtlasClassification> retrievedClassificationsList = retrievedClassifications.getList(); + Assert.assertNotNull(retrievedClassificationsList); + + Assert.assertEquals(classifications, retrievedClassificationsList); + + final AtlasClassification retrievedClassification = entityREST.getClassification(dbGuid, TestUtilsV2.CLASSIFICATION); + + Assert.assertNotNull(retrievedClassification); + Assert.assertEquals(retrievedClassification, testClassification); + + } + + @Test(dependsOnMethods = "testAddAndGetClassification") + public void testGetEntityWithAssociations() throws Exception { + + AtlasEntityWithAssociations entity = entityREST.getWithAssociationsByGuid(dbGuid); + final List<AtlasClassification> retrievedClassifications = entity.getClassifications(); + + Assert.assertNotNull(retrievedClassifications); + Assert.assertEquals(new ArrayList<AtlasClassification>() {{ add(testClassification); }}, retrievedClassifications); + } + + @Test(dependsOnMethods = "testGetEntityWithAssociations") + public void testDeleteClassification() throws Exception { + + entityREST.deleteClassification(dbGuid, TestUtilsV2.CLASSIFICATION); + final AtlasClassification.AtlasClassifications retrievedClassifications = entityREST.getClassifications(dbGuid); + + Assert.assertNotNull(retrievedClassifications); + Assert.assertEquals(retrievedClassifications.getList().size(), 0); + } + + @Test(dependsOnMethods = "testDeleteClassification") + public void testDeleteEntityById() throws Exception { + + EntityMutationResponse response = entityREST.deleteByGuid(dbGuid); + List<AtlasEntityHeader> entitiesMutated = response.getEntitiesByOperation(EntityMutations.EntityOperation.DELETE); + Assert.assertNotNull(entitiesMutated); + Assert.assertEquals(entitiesMutated.get(0).getGuid(), dbGuid); + } + + @Test + public void testUpdateGetDeleteEntityByUniqueAttribute() throws Exception { + + AtlasEntity dbEntity = TestUtilsV2.createDBEntity(); + entityREST.createOrUpdate(dbEntity); + + final String prevDBName = (String) dbEntity.getAttribute(TestUtilsV2.NAME); + final String updatedDBName = "updatedDBName"; + + dbEntity.setAttribute(TestUtilsV2.NAME, updatedDBName); + + final EntityMutationResponse response = entityREST.partialUpdateByUniqueAttribute(TestUtilsV2.DATABASE_TYPE, TestUtilsV2.NAME, prevDBName, dbEntity); + String dbGuid = response.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE).get(0).getGuid(); + Assert.assertTrue(AtlasEntity.isAssigned(dbGuid)); + + //Get By unique attribute + AtlasEntity entity = entityREST.getByUniqueAttribute(TestUtilsV2.DATABASE_TYPE, TestUtilsV2.NAME, updatedDBName); + Assert.assertNotNull(entity); + Assert.assertNotNull(entity.getGuid()); + Assert.assertEquals(entity.getGuid(), dbGuid); + TestEntitiesREST.verifyAttributes(entity.getAttributes(), dbEntity.getAttributes()); + + final EntityMutationResponse deleteResponse = entityREST.deleteByUniqueAttribute(TestUtilsV2.DATABASE_TYPE, TestUtilsV2.NAME, (String) dbEntity.getAttribute(TestUtilsV2.NAME)); + + Assert.assertNotNull(deleteResponse.getEntitiesByOperation(EntityMutations.EntityOperation.DELETE)); + Assert.assertEquals(deleteResponse.getEntitiesByOperation(EntityMutations.EntityOperation.DELETE).size(), 1); + Assert.assertEquals(deleteResponse.getEntitiesByOperation(EntityMutations.EntityOperation.DELETE).get(0).getGuid(), dbGuid); + } + +}
