Search in sources :

Example 1 with NullRequiredAttributeException

use of org.apache.atlas.typesystem.exception.NullRequiredAttributeException in project incubator-atlas by apache.

the class DeleteHandler method deleteEdgeBetweenVertices.

/**
 * Deletes the edge between outvertex and inVertex. The edge is for attribute attributeName of outVertex
 * @param outVertex
 * @param inVertex
 * @param attributeName
 * @throws AtlasException
 */
protected void deleteEdgeBetweenVertices(AtlasVertex outVertex, AtlasVertex inVertex, String attributeName) throws AtlasException {
    if (LOG.isDebugEnabled()) {
        LOG.debug("Removing edge from {} to {} with attribute name {}", string(outVertex), string(inVertex), attributeName);
    }
    String typeName = GraphHelper.getTypeName(outVertex);
    String outId = GraphHelper.getGuid(outVertex);
    Id.EntityState state = GraphHelper.getState(outVertex);
    if ((outId != null && RequestContext.get().isDeletedEntity(outId)) || state == Id.EntityState.DELETED) {
        // If the reference vertex is marked for deletion, skip updating the reference
        return;
    }
    IDataType type = typeSystem.getDataType(IDataType.class, typeName);
    AttributeInfo attributeInfo = getFieldMapping(type).fields.get(attributeName);
    String propertyName = GraphHelper.getQualifiedFieldName(type, attributeName);
    String edgeLabel = EDGE_LABEL_PREFIX + propertyName;
    AtlasEdge edge = null;
    switch(attributeInfo.dataType().getTypeCategory()) {
        case CLASS:
            // If its class attribute, its the only edge between two vertices
            if (attributeInfo.multiplicity.nullAllowed()) {
                edge = graphHelper.getEdgeForLabel(outVertex, edgeLabel);
                if (shouldUpdateReverseAttribute) {
                    GraphHelper.setProperty(outVertex, propertyName, null);
                }
            } else {
                // Cannot unset a required attribute.
                throw new NullRequiredAttributeException("Cannot unset required attribute " + GraphHelper.getQualifiedFieldName(type, attributeName) + " on " + GraphHelper.getVertexDetails(outVertex) + " edge = " + edgeLabel);
            }
            break;
        case ARRAY:
            // If its array attribute, find the right edge between the two vertices and update array property
            List<String> elements = GraphHelper.getListProperty(outVertex, propertyName);
            if (elements != null) {
                // Make a copy, else list.remove reflects on titan.getProperty()
                elements = new ArrayList<>(elements);
                for (String elementEdgeId : elements) {
                    AtlasEdge elementEdge = graphHelper.getEdgeByEdgeId(outVertex, edgeLabel, elementEdgeId);
                    if (elementEdge == null) {
                        continue;
                    }
                    AtlasVertex elementVertex = elementEdge.getInVertex();
                    if (elementVertex.equals(inVertex)) {
                        edge = elementEdge;
                        // TODO element.size includes deleted items as well. should exclude
                        if (!attributeInfo.multiplicity.nullAllowed() && elements.size() <= attributeInfo.multiplicity.lower) {
                            // Deleting this edge would violate the attribute's lower bound.
                            throw new NullRequiredAttributeException("Cannot remove array element from required attribute " + GraphHelper.getQualifiedFieldName(type, attributeName) + " on " + GraphHelper.getVertexDetails(outVertex) + " " + GraphHelper.getEdgeDetails(elementEdge));
                        }
                        if (shouldUpdateReverseAttribute) {
                            // but when column is deleted, table will not reference the deleted column
                            if (LOG.isDebugEnabled()) {
                                LOG.debug("Removing edge {} from the array attribute {}", string(elementEdge), attributeName);
                            }
                            // Remove all occurrences of the edge ID from the list.
                            // This prevents dangling edge IDs (i.e. edge IDs for deleted edges)
                            // from the remaining in the list if there are duplicates.
                            elements.removeAll(Collections.singletonList(elementEdge.getId().toString()));
                            GraphHelper.setProperty(outVertex, propertyName, elements);
                            break;
                        }
                    }
                }
            }
            break;
        case MAP:
            // If its map attribute, find the right edge between two vertices and update map property
            List<String> keys = GraphHelper.getListProperty(outVertex, propertyName);
            if (keys != null) {
                // Make a copy, else list.remove reflects on titan.getProperty()
                keys = new ArrayList<>(keys);
                for (String key : keys) {
                    String keyPropertyName = GraphHelper.getQualifiedNameForMapKey(propertyName, key);
                    String mapEdgeId = GraphHelper.getSingleValuedProperty(outVertex, keyPropertyName, String.class);
                    AtlasEdge mapEdge = graphHelper.getEdgeByEdgeId(outVertex, keyPropertyName, mapEdgeId);
                    if (mapEdge != null) {
                        AtlasVertex mapVertex = mapEdge.getInVertex();
                        if (mapVertex.getId().toString().equals(inVertex.getId().toString())) {
                            // TODO keys.size includes deleted items as well. should exclude
                            if (attributeInfo.multiplicity.nullAllowed() || keys.size() > attributeInfo.multiplicity.lower) {
                                edge = mapEdge;
                            } else {
                                // Deleting this entry would violate the attribute's lower bound.
                                throw new NullRequiredAttributeException("Cannot remove map entry " + keyPropertyName + " from required attribute " + GraphHelper.getQualifiedFieldName(type, attributeName) + " on " + GraphHelper.getVertexDetails(outVertex) + " " + GraphHelper.getEdgeDetails(mapEdge));
                            }
                            if (shouldUpdateReverseAttribute) {
                                // remove this key
                                if (LOG.isDebugEnabled()) {
                                    LOG.debug("Removing edge {}, key {} from the map attribute {}", string(mapEdge), key, attributeName);
                                }
                                keys.remove(key);
                                GraphHelper.setProperty(outVertex, propertyName, keys);
                                GraphHelper.setProperty(outVertex, keyPropertyName, null);
                            }
                            break;
                        }
                    }
                }
            }
            break;
        case STRUCT:
        case TRAIT:
            break;
        default:
            throw new IllegalStateException("There can't be an edge from " + GraphHelper.getVertexDetails(outVertex) + " to " + GraphHelper.getVertexDetails(inVertex) + " with attribute name " + attributeName + " which is not class/array/map attribute");
    }
    if (edge != null) {
        deleteEdge(edge, false);
        RequestContext requestContext = RequestContext.get();
        GraphHelper.setProperty(outVertex, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY, requestContext.getRequestTime());
        GraphHelper.setProperty(outVertex, Constants.MODIFIED_BY_KEY, requestContext.getUser());
        requestContext.recordEntityUpdate(outId);
    }
}
Also used : AttributeInfo(org.apache.atlas.typesystem.types.AttributeInfo) AtlasVertex(org.apache.atlas.repository.graphdb.AtlasVertex) Id(org.apache.atlas.typesystem.persistence.Id) RequestContext(org.apache.atlas.RequestContext) IDataType(org.apache.atlas.typesystem.types.IDataType) AtlasEdge(org.apache.atlas.repository.graphdb.AtlasEdge) NullRequiredAttributeException(org.apache.atlas.typesystem.exception.NullRequiredAttributeException)

Example 2 with NullRequiredAttributeException

use of org.apache.atlas.typesystem.exception.NullRequiredAttributeException in project incubator-atlas by apache.

the class GraphBackedMetadataRepositoryDeleteTestBase method testDeleteTargetOfRequiredMapReference.

@Test
public void testDeleteTargetOfRequiredMapReference() throws Exception {
    // Define type for map value.
    HierarchicalTypeDefinition<ClassType> mapValueDef = TypesUtil.createClassTypeDef("RequiredMapValue", ImmutableSet.<String>of());
    // Define type with required map references where the map value is a class reference to RequiredMapValue.
    HierarchicalTypeDefinition<ClassType> mapOwnerDef = TypesUtil.createClassTypeDef("RequiredMapOwner", ImmutableSet.<String>of(), new AttributeDefinition("map", DataTypes.mapTypeName(DataTypes.STRING_TYPE.getName(), "RequiredMapValue"), Multiplicity.REQUIRED, false, null));
    TypesDef typesDef = TypesUtil.getTypesDef(ImmutableList.<EnumTypeDefinition>of(), ImmutableList.<StructTypeDefinition>of(), ImmutableList.<HierarchicalTypeDefinition<TraitType>>of(), ImmutableList.of(mapOwnerDef, mapValueDef));
    typeSystem.defineTypes(typesDef);
    ClassType mapOwnerType = typeSystem.getDataType(ClassType.class, "RequiredMapOwner");
    ClassType mapValueType = typeSystem.getDataType(ClassType.class, "RequiredMapValue");
    // Create instances of RequiredMapOwner and RequiredMapValue.
    // Set RequiredMapOwner.map with one entry that references RequiredMapValue instance.
    ITypedReferenceableInstance mapOwnerInstance = mapOwnerType.createInstance();
    ITypedReferenceableInstance mapValueInstance = mapValueType.createInstance();
    mapOwnerInstance.set("map", Collections.singletonMap("value1", mapValueInstance));
    List<String> createEntitiesResult = repositoryService.createEntities(mapOwnerInstance, mapValueInstance).getCreatedEntities();
    Assert.assertEquals(createEntitiesResult.size(), 2);
    List<String> guids = repositoryService.getEntityList("RequiredMapOwner");
    Assert.assertEquals(guids.size(), 1);
    String mapOwnerGuid = guids.get(0);
    guids = repositoryService.getEntityList("RequiredMapValue");
    Assert.assertEquals(guids.size(), 1);
    String mapValueGuid = guids.get(0);
    // Verify MapOwner.map attribute has expected value.
    mapOwnerInstance = repositoryService.getEntityDefinition(mapOwnerGuid);
    Object object = mapOwnerInstance.get("map");
    Assert.assertNotNull(object);
    Assert.assertTrue(object instanceof Map);
    Map<String, ITypedReferenceableInstance> map = (Map<String, ITypedReferenceableInstance>) object;
    Assert.assertEquals(map.size(), 1);
    mapValueInstance = map.get("value1");
    Assert.assertNotNull(mapValueInstance);
    Assert.assertEquals(mapValueInstance.getId()._getId(), mapValueGuid);
    String edgeLabel = GraphHelper.getEdgeLabel(mapOwnerType, mapOwnerType.fieldMapping.fields.get("map"));
    String mapEntryLabel = edgeLabel + "." + "value1";
    AtlasEdgeLabel atlasEdgeLabel = new AtlasEdgeLabel(mapEntryLabel);
    AtlasVertex mapOwnerVertex = GraphHelper.getInstance().getVertexForGUID(mapOwnerGuid);
    object = mapOwnerVertex.getProperty(atlasEdgeLabel.getQualifiedMapKey(), Object.class);
    Assert.assertNotNull(object);
    // Verify deleting the target of required map attribute throws a NullRequiredAttributeException.
    try {
        deleteEntities(mapValueGuid);
        Assert.fail(NullRequiredAttributeException.class.getSimpleName() + " was expected but none thrown.");
    } catch (Exception e) {
        verifyExceptionThrown(e, NullRequiredAttributeException.class);
    }
}
Also used : ITypedReferenceableInstance(org.apache.atlas.typesystem.ITypedReferenceableInstance) NullRequiredAttributeException(org.apache.atlas.typesystem.exception.NullRequiredAttributeException) RepositoryException(org.apache.atlas.repository.RepositoryException) EntityExistsException(org.apache.atlas.typesystem.exception.EntityExistsException) EntityNotFoundException(org.apache.atlas.typesystem.exception.EntityNotFoundException) AtlasException(org.apache.atlas.AtlasException) TypesDef(org.apache.atlas.typesystem.TypesDef) AtlasVertex(org.apache.atlas.repository.graphdb.AtlasVertex) HashMap(java.util.HashMap) Map(java.util.Map) NullRequiredAttributeException(org.apache.atlas.typesystem.exception.NullRequiredAttributeException) Test(org.testng.annotations.Test)

Example 3 with NullRequiredAttributeException

use of org.apache.atlas.typesystem.exception.NullRequiredAttributeException in project incubator-atlas by apache.

the class GraphBackedMetadataRepositoryDeleteTestBase method testDeleteTargetOfMultiplicityOneRequiredReference.

@Test
public void testDeleteTargetOfMultiplicityOneRequiredReference() throws Exception {
    createDbTableGraph("db1", "table1");
    ITypedReferenceableInstance db = repositoryService.getEntityDefinition(TestUtils.DATABASE_TYPE, "name", "db1");
    try {
        // table1 references db1 through the required reference hive_table.database.
        // Attempt to delete db1 should cause a NullRequiredAttributeException,
        // as that would violate the lower bound on table1's database attribute.
        deleteEntities(db.getId()._getId());
        Assert.fail("Lower bound on attribute hive_table.database was not enforced - " + NullRequiredAttributeException.class.getSimpleName() + " was expected but none thrown");
    } catch (Exception e) {
        verifyExceptionThrown(e, NullRequiredAttributeException.class);
    }
    // Delete table1.
    ITypedReferenceableInstance table1 = repositoryService.getEntityDefinition(TestUtils.TABLE_TYPE, "name", "table1");
    Assert.assertNotNull(table1);
    deleteEntities(table1.getId()._getId());
    // Now delete of db1 should succeed, since it is no longer the target
    // of the required reference from the deleted table1.
    deleteEntities(db.getId()._getId());
}
Also used : ITypedReferenceableInstance(org.apache.atlas.typesystem.ITypedReferenceableInstance) NullRequiredAttributeException(org.apache.atlas.typesystem.exception.NullRequiredAttributeException) NullRequiredAttributeException(org.apache.atlas.typesystem.exception.NullRequiredAttributeException) RepositoryException(org.apache.atlas.repository.RepositoryException) EntityExistsException(org.apache.atlas.typesystem.exception.EntityExistsException) EntityNotFoundException(org.apache.atlas.typesystem.exception.EntityNotFoundException) AtlasException(org.apache.atlas.AtlasException) Test(org.testng.annotations.Test)

Aggregations

NullRequiredAttributeException (org.apache.atlas.typesystem.exception.NullRequiredAttributeException)3 AtlasException (org.apache.atlas.AtlasException)2 RepositoryException (org.apache.atlas.repository.RepositoryException)2 AtlasVertex (org.apache.atlas.repository.graphdb.AtlasVertex)2 ITypedReferenceableInstance (org.apache.atlas.typesystem.ITypedReferenceableInstance)2 EntityExistsException (org.apache.atlas.typesystem.exception.EntityExistsException)2 EntityNotFoundException (org.apache.atlas.typesystem.exception.EntityNotFoundException)2 Test (org.testng.annotations.Test)2 HashMap (java.util.HashMap)1 Map (java.util.Map)1 RequestContext (org.apache.atlas.RequestContext)1 AtlasEdge (org.apache.atlas.repository.graphdb.AtlasEdge)1 TypesDef (org.apache.atlas.typesystem.TypesDef)1 Id (org.apache.atlas.typesystem.persistence.Id)1 AttributeInfo (org.apache.atlas.typesystem.types.AttributeInfo)1 IDataType (org.apache.atlas.typesystem.types.IDataType)1