You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2017/01/20 01:59:56 UTC
[1/3] incubator-atlas git commit: ATLAS-1467: instance
create/full-Update implementation
Repository: incubator-atlas
Updated Branches:
refs/heads/master 511c88670 -> 2f1cb57a7
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/InstanceGraphMapper.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/InstanceGraphMapper.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/InstanceGraphMapper.java
new file mode 100644
index 0000000..7e87d39
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/InstanceGraphMapper.java
@@ -0,0 +1,39 @@
+/**
+ * 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.v1;
+
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.type.AtlasEntityType;
+
+public interface InstanceGraphMapper<T> {
+
+ /**
+ * Map the given type instance to the graph
+ *
+ * @param ctx
+ * @return the value that was mapped to the vertex
+ * @throws AtlasBaseException
+ */
+ T toGraph(GraphMutationContext ctx) throws AtlasBaseException;
+
+
+ void cleanUp() throws AtlasBaseException;
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/MapVertexMapper.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/MapVertexMapper.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/MapVertexMapper.java
new file mode 100644
index 0000000..9d219f5
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/MapVertexMapper.java
@@ -0,0 +1,200 @@
+/**
+ * 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.v1;
+
+
+import com.google.common.base.Optional;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+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.typedef.AtlasStructDef;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasMapType;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.atlas.type.AtlasType;
+import org.apache.commons.collections.MapUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Provider;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.atlas.repository.graph.GraphHelper.string;
+
+public class MapVertexMapper implements InstanceGraphMapper<Map> {
+
+ private DeleteHandlerV1 deleteHandler;
+
+ private static final Logger LOG = LoggerFactory.getLogger(MapVertexMapper.class);
+
+ private StructVertexMapper structVertexMapper;
+
+ @Inject
+ public MapVertexMapper(DeleteHandlerV1 deleteHandler) {
+ this.deleteHandler = deleteHandler;
+ }
+
+ void init(StructVertexMapper structVertexMapper) {
+ this.structVertexMapper = structVertexMapper;
+ }
+
+ @Override
+ public Map<String, Object> toGraph(GraphMutationContext ctx) throws AtlasBaseException {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Mapping instance to vertex {} for map type {}", string(ctx.getReferringVertex()), ctx.getAttrType().getTypeName());
+ }
+
+ @SuppressWarnings("unchecked") Map<Object, Object> newVal =
+ (Map<Object, Object>) ctx.getValue();
+
+ boolean newAttributeEmpty = MapUtils.isEmpty(newVal);
+
+ Map<String, Object> currentMap = new HashMap<>();
+ Map<String, Object> newMap = new HashMap<>();
+
+ AtlasMapType mapType = (AtlasMapType) ctx.getAttrType();
+
+ try {
+ List<String> currentKeys = GraphHelper.getListProperty(ctx.getReferringVertex(), ctx.getVertexPropertyKey());
+ if (currentKeys != null && !currentKeys.isEmpty()) {
+ for (String key : currentKeys) {
+ String propertyNameForKey = GraphHelper.getQualifiedNameForMapKey(ctx.getVertexPropertyKey(), key);
+ Object propertyValueForKey = getMapValueProperty(mapType.getValueType(), ctx.getReferringVertex(), propertyNameForKey);
+ currentMap.put(key, propertyValueForKey);
+ }
+ }
+
+ if (!newAttributeEmpty) {
+ for (Map.Entry<Object, Object> entry : newVal.entrySet()) {
+ String keyStr = entry.getKey().toString();
+ String propertyNameForKey = GraphHelper.getQualifiedNameForMapKey(ctx.getVertexPropertyKey(), keyStr);
+ Optional<AtlasEdge> existingEdge = getEdgeIfExists(mapType, currentMap, keyStr);
+
+ GraphMutationContext mapCtx = new GraphMutationContext.Builder(ctx.getAttribute(), mapType.getValueType(), entry.getValue())
+ .referringVertex(ctx.getReferringVertex())
+ .edge(existingEdge)
+ .vertexProperty(propertyNameForKey).build();
+
+
+ Object newEntry = structVertexMapper.mapCollectionElementsToVertex(mapCtx);
+ newMap.put(keyStr, newEntry);
+ }
+ }
+
+ Map<String, Object> finalMap =
+ removeUnusedMapEntries(ctx.getParentType(), mapType, ctx.getAttributeDef(), ctx.getReferringVertex(), ctx.getVertexPropertyKey(), currentMap, newMap);
+
+ Set<String> newKeys = new HashSet<>(newMap.keySet());
+ newKeys.addAll(finalMap.keySet());
+
+ // for dereference on way out
+ GraphHelper.setListProperty(ctx.getReferringVertex(), ctx.getVertexPropertyKey(), new ArrayList<>(newKeys));
+ } catch (AtlasException e) {
+ throw new AtlasBaseException(AtlasErrorCode.INTERNAL_ERROR, e);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Map values set in vertex {} {}", mapType.getTypeName(), newMap);
+ }
+
+ return newMap;
+ }
+
+ @Override
+ public void cleanUp() throws AtlasBaseException {
+ }
+
+
+ public static Object getMapValueProperty(AtlasType elementType, AtlasVertex instanceVertex, String propertyName) {
+ String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
+ if (AtlasGraphUtilsV1.isReference(elementType)) {
+ return instanceVertex.getProperty(actualPropertyName, AtlasEdge.class);
+ }
+ else {
+ return instanceVertex.getProperty(actualPropertyName, String.class).toString();
+ }
+ }
+
+ public static void setMapValueProperty(AtlasType elementType, AtlasVertex instanceVertex, String propertyName, Object value) {
+ String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
+ if (AtlasGraphUtilsV1.isReference(elementType)) {
+ instanceVertex.setPropertyFromElementId(actualPropertyName, (AtlasEdge)value);
+ }
+ else {
+ instanceVertex.setProperty(actualPropertyName, value);
+ }
+ }
+
+ //Remove unused entries from map
+ private Map<String, Object> removeUnusedMapEntries(
+ AtlasStructType entityType,
+ AtlasMapType mapType, AtlasStructDef.AtlasAttributeDef attributeDef,
+ AtlasVertex instanceVertex, String propertyName,
+ Map<String, Object> currentMap,
+ Map<String, Object> newMap)
+ throws AtlasException, AtlasBaseException {
+
+ Map<String, Object> additionalMap = new HashMap<>();
+ for (String currentKey : currentMap.keySet()) {
+
+ boolean shouldDeleteKey = !newMap.containsKey(currentKey);
+ if (AtlasGraphUtilsV1.isReference(mapType.getValueType())) {
+
+ //Delete the edge reference if its not part of new edges created/updated
+ AtlasEdge currentEdge = (AtlasEdge)currentMap.get(currentKey);
+
+ if (!newMap.values().contains(currentEdge)) {
+ boolean deleteChildReferences = StructVertexMapper.shouldManageChildReferences(entityType, attributeDef.getName());
+ boolean deleted =
+ deleteHandler.deleteEdgeReference(currentEdge, mapType.getValueType().getTypeCategory(), deleteChildReferences, true);
+ if (!deleted) {
+ additionalMap.put(currentKey, currentEdge);
+ shouldDeleteKey = false;
+ }
+ }
+ }
+
+ if (shouldDeleteKey) {
+ String propertyNameForKey = GraphHelper.getQualifiedNameForMapKey(propertyName, currentKey);
+ GraphHelper.setProperty(instanceVertex, propertyNameForKey, null);
+ }
+ }
+ return additionalMap;
+ }
+
+ private Optional<AtlasEdge> getEdgeIfExists(AtlasMapType mapType, Map<String, Object> currentMap, String keyStr) {
+ Optional<AtlasEdge> existingEdge = Optional.absent();
+ if ( AtlasGraphUtilsV1.isReference(mapType.getValueType()) ) {
+ existingEdge = Optional.of((AtlasEdge) currentMap.get(keyStr));
+ }
+
+ return existingEdge;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/SoftDeleteHandlerV1.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/SoftDeleteHandlerV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/SoftDeleteHandlerV1.java
new file mode 100644
index 0000000..7e3068b
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/SoftDeleteHandlerV1.java
@@ -0,0 +1,72 @@
+/**
+ * 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.repository.store.graph.v1;
+
+import com.google.inject.Inject;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.RequestContext;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.atlas.typesystem.persistence.Id;
+
+import static org.apache.atlas.repository.Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY;
+import static org.apache.atlas.repository.Constants.MODIFIED_BY_KEY;
+import static org.apache.atlas.repository.Constants.STATE_PROPERTY_KEY;
+
+public class SoftDeleteHandlerV1 extends DeleteHandlerV1 {
+
+ @Inject
+ public SoftDeleteHandlerV1(AtlasTypeRegistry typeRegistry) {
+ super(typeRegistry, false, true);
+ }
+
+ @Override
+ protected void _deleteVertex(AtlasVertex instanceVertex, boolean force) {
+ if (force) {
+ graphHelper.removeVertex(instanceVertex);
+ } else {
+ AtlasEntity.Status state = AtlasGraphUtilsV1.getState(instanceVertex);
+ if (state != AtlasEntity.Status.DELETED) {
+ GraphHelper.setProperty(instanceVertex, STATE_PROPERTY_KEY, Id.EntityState.DELETED.name());
+ GraphHelper.setProperty(instanceVertex, MODIFICATION_TIMESTAMP_PROPERTY_KEY,
+ RequestContext.get().getRequestTime());
+ GraphHelper.setProperty(instanceVertex, MODIFIED_BY_KEY, RequestContext.get().getUser());
+ }
+ }
+ }
+
+ @Override
+ protected void deleteEdge(AtlasEdge edge, boolean force) throws AtlasBaseException {
+ if (force) {
+ graphHelper.removeEdge(edge);
+ } else {
+ Id.EntityState state = GraphHelper.getState(edge);
+ if (state != Id.EntityState.DELETED) {
+ GraphHelper.setProperty(edge, STATE_PROPERTY_KEY, Id.EntityState.DELETED.name());
+ GraphHelper
+ .setProperty(edge, MODIFICATION_TIMESTAMP_PROPERTY_KEY, RequestContext.get().getRequestTime());
+ GraphHelper.setProperty(edge, MODIFIED_BY_KEY, RequestContext.get().getUser());
+ }
+ }
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/StructVertexMapper.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/StructVertexMapper.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/StructVertexMapper.java
new file mode 100644
index 0000000..ae9ecc4
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/StructVertexMapper.java
@@ -0,0 +1,203 @@
+/**
+ * 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.v1;
+
+import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.RequestContextV1;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.TypeCategory;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasStruct;
+import org.apache.atlas.model.typedef.AtlasStructDef;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.repository.RepositoryException;
+import org.apache.atlas.repository.graph.AtlasGraphProvider;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasGraph;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasMapType;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.atlas.type.AtlasType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class StructVertexMapper implements InstanceGraphMapper<AtlasEdge> {
+
+ private final AtlasGraph graph;
+
+ private final GraphHelper graphHelper = GraphHelper.getInstance();
+
+ private final MapVertexMapper mapVertexMapper;
+
+ private final ArrayVertexMapper arrVertexMapper;
+
+ private EntityGraphMapper entityVertexMapper;
+
+ private static final Logger LOG = LoggerFactory.getLogger(StructVertexMapper.class);
+
+ public StructVertexMapper(ArrayVertexMapper arrayVertexMapper, MapVertexMapper mapVertexMapper) {
+ this.graph = AtlasGraphProvider.getGraphInstance();;
+ this.mapVertexMapper = mapVertexMapper;
+ this.arrVertexMapper = arrayVertexMapper;
+ }
+
+ void init(final EntityGraphMapper entityVertexMapper) {
+ this.entityVertexMapper = entityVertexMapper;
+ }
+
+ @Override
+ public AtlasEdge toGraph(GraphMutationContext ctx) throws AtlasBaseException {
+ AtlasEdge result = null;
+
+ String edgeLabel = AtlasGraphUtilsV1.getAttributeEdgeLabel(ctx.getParentType(), ctx.getAttributeDef().getName());
+
+ if ( ctx.getCurrentEdge().isPresent() ) {
+ updateVertex(ctx.getParentType(), (AtlasStructType) ctx.getAttrType(), ctx.getAttributeDef(), (AtlasStruct) ctx.getValue(), ctx.getCurrentEdge().get().getOutVertex());
+ result = ctx.getCurrentEdge().get();
+ } else {
+ result = createVertex(ctx.getParentType(), (AtlasStructType) ctx.getAttrType(), ctx.getAttributeDef(), (AtlasStruct) ctx.getValue(), ctx.getReferringVertex(), edgeLabel);
+ }
+
+ return result;
+ }
+
+ @Override
+ public void cleanUp() throws AtlasBaseException {
+ }
+
+ public static boolean shouldManageChildReferences(AtlasStructType type, String attributeName) {
+ return type.isMappedFromRefAttribute(attributeName);
+ }
+
+ /**
+ * Map attributes for entity, struct or trait
+ * @param structType
+ * @param struct
+ * @param vertex
+ * @return
+ * @throws AtlasBaseException
+ */
+ public AtlasVertex mapAttributestoVertex(AtlasStructType structType, AtlasStruct struct, AtlasVertex vertex) throws AtlasBaseException {
+ if (struct.getAttributes() != null) {
+ for (String attrName : struct.getAttributes().keySet()) {
+ Object value = struct.getAttribute(attrName);
+ AtlasType attributeType = structType.getAttributeType(attrName);
+ if ( attributeType != null) {
+ final AtlasStructType.AtlasAttribute attribute = structType.getAttribute(attrName);
+
+ GraphMutationContext ctx = new GraphMutationContext.Builder(attribute, value)
+ .referringVertex(vertex)
+ .vertexProperty(AtlasGraphUtilsV1.getQualifiedAttributePropertyKey(structType, attrName)).build();
+ mapToVertexByTypeCategory(ctx);
+ }
+ }
+
+ //Set updated timestamp
+ AtlasGraphUtilsV1.setProperty(vertex, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY, RequestContextV1.get().getRequestTime());
+ GraphHelper.setProperty(vertex, Constants.MODIFIED_BY_KEY, RequestContextV1.get().getUser());
+ }
+ return vertex;
+ }
+
+ protected Object mapToVertexByTypeCategory(GraphMutationContext ctx) throws AtlasBaseException {
+ switch(ctx.getAttrType().getTypeCategory()) {
+ case PRIMITIVE:
+ case ENUM:
+ return primitivesToVertex(ctx);
+ case STRUCT:
+ return toGraph(ctx);
+ case ENTITY:
+ AtlasEntityType instanceType = entityVertexMapper.getInstanceType(ctx.getValue());
+ ctx.setElementType(instanceType);
+ return entityVertexMapper.toGraph(ctx);
+ case MAP:
+ return mapVertexMapper.toGraph(ctx);
+ case ARRAY:
+ return arrVertexMapper.toGraph(ctx);
+ default:
+ throw new AtlasBaseException(AtlasErrorCode.TYPE_CATEGORY_INVALID, ctx.getAttrType().getTypeCategory().name());
+ }
+ }
+
+ protected Object primitivesToVertex(GraphMutationContext ctx) {
+ if ( ctx.getAttrType().getTypeCategory() == TypeCategory.MAP ) {
+ MapVertexMapper.setMapValueProperty(((AtlasMapType) ctx.getAttrType()).getValueType(), ctx.getReferringVertex(), ctx.getVertexPropertyKey(), ctx.getValue());
+ } else {
+ AtlasGraphUtilsV1.setProperty(ctx.getReferringVertex(), ctx.getVertexPropertyKey(), ctx.getValue());
+ }
+ return ctx.getValue();
+ }
+
+ private AtlasEdge createVertex(AtlasStructType parentType, AtlasStructType attrType, AtlasStructDef.AtlasAttributeDef attributeDef, AtlasStruct struct, AtlasVertex referringVertex, String edgeLabel) throws AtlasBaseException {
+ AtlasVertex vertex = createVertexTemplate(struct, attrType);
+ mapAttributestoVertex(attrType, struct, vertex);
+
+ try {
+ //TODO - Map directly in AtlasGraphUtilsV1
+ return graphHelper.getOrCreateEdge(referringVertex, vertex, edgeLabel);
+ } catch (RepositoryException e) {
+ throw new AtlasBaseException(AtlasErrorCode.INTERNAL_ERROR, e);
+ }
+ }
+
+ private void updateVertex(AtlasStructType parentType, AtlasStructType structAttributeType, AtlasStructDef.AtlasAttributeDef attributeDef, AtlasStruct value, AtlasVertex structVertex) throws AtlasBaseException {
+ mapAttributestoVertex(structAttributeType, value, structVertex);
+ }
+
+ protected AtlasVertex createVertexTemplate(final AtlasStruct instance, final AtlasStructType structType) {
+ LOG.debug("Creating AtlasVertex for type {}", instance.getTypeName());
+ final AtlasVertex vertexWithoutIdentity = graph.addVertex();
+
+ // add type information
+ AtlasGraphUtilsV1.setProperty(vertexWithoutIdentity, Constants.ENTITY_TYPE_PROPERTY_KEY, instance.getTypeName());
+
+ // add state information
+ AtlasGraphUtilsV1.setProperty(vertexWithoutIdentity, Constants.STATE_PROPERTY_KEY, AtlasEntity.Status.ACTIVE.name());
+
+ // add timestamp information
+ AtlasGraphUtilsV1.setProperty(vertexWithoutIdentity, Constants.TIMESTAMP_PROPERTY_KEY, RequestContextV1.get().getRequestTime());
+ AtlasGraphUtilsV1.setProperty(vertexWithoutIdentity, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY,
+ RequestContextV1.get().getRequestTime());
+
+ AtlasGraphUtilsV1.setProperty(vertexWithoutIdentity, Constants.CREATED_BY_KEY, RequestContextV1.get().getUser());
+
+ GraphHelper.setProperty(vertexWithoutIdentity, Constants.MODIFIED_BY_KEY, RequestContextV1.get().getUser());
+
+ return vertexWithoutIdentity;
+ }
+
+ protected Object mapCollectionElementsToVertex(GraphMutationContext ctx) throws AtlasBaseException {
+ switch(ctx.getAttrType().getTypeCategory()) {
+ case PRIMITIVE:
+ case ENUM:
+ return primitivesToVertex(ctx);
+ case STRUCT:
+ return toGraph(ctx);
+ case ENTITY:
+ AtlasEntityType instanceType = entityVertexMapper.getInstanceType(ctx.getValue());
+ ctx.setElementType(instanceType);
+ return entityVertexMapper.toGraph(ctx);
+ case MAP:
+ case ARRAY:
+ default:
+ throw new AtlasBaseException(AtlasErrorCode.TYPE_CATEGORY_INVALID, ctx.getAttrType().getTypeCategory().name());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/UniqAttrBasedEntityResolver.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/UniqAttrBasedEntityResolver.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/UniqAttrBasedEntityResolver.java
new file mode 100644
index 0000000..8025f1e
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/UniqAttrBasedEntityResolver.java
@@ -0,0 +1,136 @@
+/**
+ * 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.v1;
+
+import com.google.common.base.Optional;
+import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.model.typedef.AtlasStructDef;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.repository.store.graph.EntityGraphDiscoveryContext;
+import org.apache.atlas.repository.store.graph.EntityResolver;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.atlas.typesystem.exception.EntityNotFoundException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.inject.Inject;
+import java.util.ArrayList;
+import java.util.List;
+
+public class UniqAttrBasedEntityResolver implements EntityResolver {
+
+ private static final Logger LOG = LoggerFactory.getLogger(UniqAttrBasedEntityResolver.class);
+
+ private final AtlasTypeRegistry typeRegistry;
+
+ private final GraphHelper graphHelper = GraphHelper.getInstance();
+
+ private EntityGraphDiscoveryContext context;
+
+ @Inject
+ public UniqAttrBasedEntityResolver(AtlasTypeRegistry typeRegistry) {
+ this.typeRegistry = typeRegistry;
+ }
+
+ @Override
+ public void init(EntityGraphDiscoveryContext entities) throws AtlasBaseException {
+ this.context = entities;
+ }
+
+ @Override
+ public EntityGraphDiscoveryContext resolveEntityReferences() throws AtlasBaseException {
+
+ if ( context == null) {
+ throw new AtlasBaseException(AtlasErrorCode.INTERNAL_ERROR, "Unique attribute based entity resolver not initialized");
+ }
+
+ //Resolve attribute references
+ List<AtlasEntity> resolvedReferences = new ArrayList<>();
+
+ for (AtlasEntity entity : context.getUnResolvedEntityReferences()) {
+ //query in graph repo that given unique attribute - check for deleted also?
+ Optional<AtlasVertex> vertex = resolveByUniqueAttribute(entity);
+ if (vertex.isPresent()) {
+ context.addRepositoryResolvedReference(new AtlasObjectId(entity.getTypeName(), entity.getGuid()), vertex.get());
+ resolvedReferences.add(entity);
+ }
+ }
+
+ context.removeUnResolvedEntityReferences(resolvedReferences);
+
+ if (context.getUnResolvedEntityReferences().size() > 0) {
+ throw new AtlasBaseException(AtlasErrorCode.INSTANCE_BY_UNIQUE_ATTRIBUTE_NOT_FOUND, context.getUnResolvedEntityReferences().toString());
+ }
+
+ //Resolve root references
+ for (AtlasEntity entity : context.getRootEntities()) {
+ if ( !context.isResolved(entity.getGuid()) ) {
+ Optional<AtlasVertex> vertex = resolveByUniqueAttribute(entity);
+ if (vertex.isPresent()) {
+ context.addRepositoryResolvedReference(new AtlasObjectId(entity.getTypeName(), entity.getGuid()), vertex.get());
+ }
+ }
+ }
+
+ return context;
+ }
+
+ Optional<AtlasVertex> resolveByUniqueAttribute(AtlasEntity entity) throws AtlasBaseException {
+ AtlasEntityType entityType = (AtlasEntityType) typeRegistry.getType(entity.getTypeName());
+ for (AtlasStructType.AtlasAttribute attr : entityType.getAllAttributes().values()) {
+ if (attr.getAttributeDef().getIsUnique()) {
+ Object attrVal = entity.getAttribute(attr.getAttributeDef().getName());
+ if (attrVal != null) {
+ String qualifiedAttrName = attr.getQualifiedAttributeName();
+ AtlasVertex vertex = null;
+ try {
+ vertex = graphHelper.findVertex(qualifiedAttrName, attrVal,
+ Constants.ENTITY_TYPE_PROPERTY_KEY, entityType.getTypeName(),
+ Constants.STATE_PROPERTY_KEY, AtlasEntity.Status.ACTIVE
+ .name());
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Found vertex by unique attribute : " + qualifiedAttrName + "=" + attrVal);
+ }
+ if (vertex != null) {
+ return Optional.of(vertex);
+ }
+ } catch (EntityNotFoundException e) {
+ //Ignore if not found
+ }
+ }
+ }
+ }
+ return Optional.absent();
+ }
+
+ @Override
+ public void cleanUp() {
+ //Nothing to cleanup
+ this.context = null;
+ }
+
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/util/AtlasRepositoryConfiguration.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/util/AtlasRepositoryConfiguration.java b/repository/src/main/java/org/apache/atlas/util/AtlasRepositoryConfiguration.java
index ea0e670..6655085 100644
--- a/repository/src/main/java/org/apache/atlas/util/AtlasRepositoryConfiguration.java
+++ b/repository/src/main/java/org/apache/atlas/util/AtlasRepositoryConfiguration.java
@@ -27,6 +27,8 @@ import org.apache.atlas.repository.audit.HBaseBasedAuditRepository;
import org.apache.atlas.repository.graph.DeleteHandler;
import org.apache.atlas.repository.graph.SoftDeleteHandler;
import org.apache.atlas.repository.graphdb.GraphDatabase;
+import org.apache.atlas.repository.store.graph.v1.DeleteHandlerV1;
+import org.apache.atlas.repository.store.graph.v1.SoftDeleteHandlerV1;
import org.apache.atlas.typesystem.types.cache.DefaultTypeCache;
import org.apache.atlas.typesystem.types.cache.TypeCache;
import org.apache.commons.configuration.Configuration;
@@ -83,6 +85,16 @@ public class AtlasRepositoryConfiguration {
throw new RuntimeException(e);
}
}
+
+ public static Class<? extends DeleteHandlerV1> getDeleteHandlerV1Impl() {
+ try {
+ Configuration config = ApplicationProperties.get();
+ return ApplicationProperties.getClass(config,
+ DELETE_HANDLER_IMPLEMENTATION_PROPERTY, SoftDeleteHandlerV1.class.getName(), DeleteHandlerV1.class);
+ } catch (AtlasException e) {
+ throw new RuntimeException(e);
+ }
+ }
private static final String GRAPH_DATABASE_IMPLEMENTATION_PROPERTY = "atlas.graphdb.backend";
private static final String DEFAULT_GRAPH_DATABASE_IMPLEMENTATION_CLASS = "org.apache.atlas.repository.graphdb.titan0.Titan0GraphDatabase";
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/test/java/org/apache/atlas/lineage/EntityLineageServiceTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/lineage/EntityLineageServiceTest.java b/repository/src/test/java/org/apache/atlas/lineage/EntityLineageServiceTest.java
index b1dac9d..19124d7 100644
--- a/repository/src/test/java/org/apache/atlas/lineage/EntityLineageServiceTest.java
+++ b/repository/src/test/java/org/apache/atlas/lineage/EntityLineageServiceTest.java
@@ -258,7 +258,7 @@ public class EntityLineageServiceTest extends BaseRepositoryTest {
assertEquals(relationsInput.size(), 2);
AtlasEntityHeader tableEntityInput = entitiesInput.get(entityGuid);
- assertEquals(tableEntityInput.getStatus(), Status.STATUS_ACTIVE);
+ assertEquals(tableEntityInput.getStatus(), Status.ACTIVE);
AtlasLineageInfo outputLineage = getOutputLineageInfo(entityGuid, 5);
assertNotNull(outputLineage);
@@ -273,7 +273,7 @@ public class EntityLineageServiceTest extends BaseRepositoryTest {
assertEquals(relationsOutput.size(), 2);
AtlasEntityHeader tableEntityOutput = entitiesOutput.get(entityGuid);
- assertEquals(tableEntityOutput.getStatus(), Status.STATUS_ACTIVE);
+ assertEquals(tableEntityOutput.getStatus(), Status.ACTIVE);
AtlasLineageInfo bothLineage = getBothLineageInfo(entityGuid, 5);
assertNotNull(bothLineage);
@@ -288,7 +288,7 @@ public class EntityLineageServiceTest extends BaseRepositoryTest {
assertEquals(relationsBoth.size(), 4);
AtlasEntityHeader tableEntityBoth = entitiesBoth.get(entityGuid);
- assertEquals(tableEntityBoth.getStatus(), Status.STATUS_ACTIVE);
+ assertEquals(tableEntityBoth.getStatus(), Status.ACTIVE);
//Delete the table entity. Lineage for entity returns the same results as before.
//Lineage for table name throws EntityNotFoundException
@@ -297,17 +297,17 @@ public class EntityLineageServiceTest extends BaseRepositoryTest {
inputLineage = getInputLineageInfo(entityGuid, 5);
tableEntityInput = inputLineage.getGuidEntityMap().get(entityGuid);
- assertEquals(tableEntityInput.getStatus(), Status.STATUS_DELETED);
+ assertEquals(tableEntityInput.getStatus(), Status.DELETED);
assertEquals(inputLineage.getGuidEntityMap().size(), 3);
outputLineage = getOutputLineageInfo(entityGuid, 5);
tableEntityOutput = outputLineage.getGuidEntityMap().get(entityGuid);
- assertEquals(tableEntityOutput.getStatus(), Status.STATUS_DELETED);
+ assertEquals(tableEntityOutput.getStatus(), Status.DELETED);
assertEquals(outputLineage.getGuidEntityMap().size(), 3);
bothLineage = getBothLineageInfo(entityGuid, 5);
tableEntityBoth = bothLineage.getGuidEntityMap().get(entityGuid);
- assertEquals(tableEntityBoth.getStatus(), Status.STATUS_DELETED);
+ assertEquals(tableEntityBoth.getStatus(), Status.DELETED);
assertEquals(bothLineage.getGuidEntityMap().size(), 5);
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/test/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStoreTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStoreTest.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStoreTest.java
index c7c3286..25bae44 100644
--- a/repository/src/test/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStoreTest.java
+++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/AtlasTypeDefGraphStoreTest.java
@@ -32,6 +32,7 @@ import org.apache.atlas.repository.graph.AtlasGraphProvider;
import org.apache.atlas.store.AtlasTypeDefStore;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Guice;
@@ -215,7 +216,7 @@ public class AtlasTypeDefGraphStoreTest {
assertTrue(createdTypesDef.getEnumDefs().containsAll(atlasTypesDef.getEnumDefs()), "EnumDefs create failed");
assertTrue(createdTypesDef.getClassificationDefs().containsAll(atlasTypesDef.getClassificationDefs()), "ClassificationDef create failed");
assertTrue(createdTypesDef.getStructDefs().containsAll(atlasTypesDef.getStructDefs()), "StructDef creation failed");
- assertTrue(createdTypesDef.getEntityDefs().containsAll(atlasTypesDef.getEntityDefs()), "EntityDef creation failed");
+ Assert.assertEquals(createdTypesDef.getEntityDefs(), atlasTypesDef.getEntityDefs());
} catch (AtlasBaseException e) {
fail("Creation of Types should've been a success", e);
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java
new file mode 100644
index 0000000..0ff33ba
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java
@@ -0,0 +1,236 @@
+/**
+ * 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.v1;
+
+import org.apache.atlas.AtlasClient;
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.RepositoryMetadataModule;
+import org.apache.atlas.TestUtils;
+import org.apache.atlas.TestUtilsV2;
+import org.apache.atlas.exception.AtlasBaseException;
+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.AtlasStructDef;
+import org.apache.atlas.model.typedef.AtlasTypesDef;
+import org.apache.atlas.repository.graph.AtlasGraphProvider;
+import org.apache.atlas.repository.graph.DeleteHandler;
+import org.apache.atlas.repository.graph.GraphBackedSearchIndexer;
+import org.apache.atlas.repository.store.graph.AtlasEntityStore;
+import org.apache.atlas.repository.store.graph.EntityGraphDiscovery;
+import org.apache.atlas.repository.store.graph.EntityResolver;
+import org.apache.atlas.services.MetadataService;
+import org.apache.atlas.store.AtlasTypeDefStore;
+import org.apache.atlas.type.AtlasArrayType;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasMapType;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.atlas.type.AtlasType;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.atlas.typesystem.IInstance;
+import org.apache.atlas.typesystem.ITypedReferenceableInstance;
+import org.apache.atlas.typesystem.ITypedStruct;
+import org.apache.atlas.typesystem.Struct;
+import org.apache.atlas.typesystem.persistence.Id;
+import org.apache.atlas.typesystem.persistence.ReferenceableInstance;
+import org.apache.atlas.typesystem.persistence.StructInstance;
+import org.apache.atlas.util.AtlasRepositoryConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterTest;
+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.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Guice(modules = RepositoryMetadataModule.class)
+public class AtlasEntityStoreV1Test {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AtlasEntityStoreV1Test.class);
+
+ @Inject
+ AtlasTypeRegistry typeRegistry;
+
+ @Inject
+ AtlasTypeDefStore typeDefStore;
+
+ AtlasEntityStore entityStore;
+
+ @Inject
+ MetadataService metadataService;
+
+ private AtlasEntity entityCreated;
+
+ @BeforeClass
+ public void setUp() throws Exception {
+ new GraphBackedSearchIndexer(typeRegistry);
+ final AtlasTypesDef atlasTypesDef = TestUtilsV2.defineDeptEmployeeTypes();
+ typeDefStore.createTypesDef(atlasTypesDef);
+
+ entityCreated = TestUtilsV2.createDeptEg1();
+ }
+
+ @AfterClass
+ public void clear() {
+ AtlasGraphProvider.cleanup();
+ }
+
+ @BeforeTest
+ public void init() throws Exception {
+ final Class<? extends DeleteHandlerV1> deleteHandlerImpl = AtlasRepositoryConfiguration.getDeleteHandlerV1Impl();
+ final Constructor<? extends DeleteHandlerV1> deleteHandlerImplConstructor = deleteHandlerImpl.getConstructor(AtlasTypeRegistry.class);
+ DeleteHandlerV1 deleteHandler = deleteHandlerImplConstructor.newInstance(typeRegistry);
+ ArrayVertexMapper arrVertexMapper = new ArrayVertexMapper(deleteHandler);
+ MapVertexMapper mapVertexMapper = new MapVertexMapper(deleteHandler);
+
+ List<EntityResolver> entityResolvers = new ArrayList<>();
+ entityResolvers.add(new IDBasedEntityResolver());
+ entityResolvers.add(new UniqAttrBasedEntityResolver(typeRegistry));
+
+ EntityGraphDiscovery graphDiscovery = new AtlasEntityGraphDiscoveryV1(typeRegistry, entityResolvers);
+
+ entityStore = new AtlasEntityStoreV1(new EntityGraphMapper(arrVertexMapper, mapVertexMapper));
+ entityStore.init(typeRegistry, graphDiscovery);
+ }
+
+ @Test
+ public void testCreate() throws Exception {
+ EntityMutationResponse response = entityStore.createOrUpdate(entityCreated);
+ List<AtlasEntityHeader> entitiesCreated = response.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE);
+ Assert.assertNotNull(entitiesCreated);
+ Assert.assertEquals(entitiesCreated.size(), 5);
+
+ AtlasEntityHeader deptEntity = entitiesCreated.get(0);
+
+ //TODO : Use the older API for get until new instance API is ready.
+ ITypedReferenceableInstance instance = metadataService.getEntityDefinition(deptEntity.getGuid());
+ assertAttributes(deptEntity, instance);
+
+ }
+
+ private void assertAttributes(AtlasStruct entity, IInstance instance) throws AtlasBaseException, AtlasException {
+ LOG.debug("Asserting type : " + entity.getTypeName());
+ AtlasStructType entityType = (AtlasStructType) typeRegistry.getType(instance.getTypeName());
+ for (String attrName : entity.getAttributes().keySet()) {
+ Object actual = entity.getAttribute(attrName);
+ Object expected = instance.get(attrName);
+
+ AtlasType attrType = entityType.getAttributeType(attrName);
+ assertAttribute(actual, expected, attrType, attrName);
+ }
+ }
+
+ private void assertAttribute(Object actual, Object expected, AtlasType attributeType, String attrName) throws AtlasBaseException, AtlasException {
+ LOG.debug("Asserting attribute : " + attrName);
+
+ switch(attributeType.getTypeCategory()) {
+ case ENTITY:
+ if ( expected instanceof Id) {
+ String guid = ((Id) expected)._getId();
+ Assert.assertTrue(AtlasEntity.isAssigned(guid));
+ } else {
+ ReferenceableInstance expectedInstance = (ReferenceableInstance) expected;
+ AtlasEntity actualInstance = (AtlasEntity) actual;
+ assertAttributes(actualInstance, expectedInstance);
+ }
+ break;
+ case PRIMITIVE:
+ case ENUM:
+ Assert.assertEquals(actual, expected);
+ break;
+ case MAP:
+ AtlasMapType mapType = (AtlasMapType) attributeType;
+ AtlasType keyType = mapType.getKeyType();
+ AtlasType valueType = mapType.getValueType();
+ Map actualMap = (Map) actual;
+ Map expectedMap = (Map) expected;
+
+ Assert.assertEquals(actualMap.size(), expectedMap.size());
+ for (Object key : actualMap.keySet()) {
+ assertAttribute(actualMap.get(key), expectedMap.get(key), valueType, attrName);
+ }
+ break;
+ case ARRAY:
+ AtlasArrayType arrType = (AtlasArrayType) attributeType;
+ AtlasType elemType = arrType.getElementType();
+ List actualList = (List) actual;
+ List expectedList = (List) expected;
+
+ if (!(expected == null && actualList.size() == 0)) {
+ Assert.assertEquals(actualList.size(), expectedList.size());
+ for (int i = 0; i < actualList.size(); i++) {
+ assertAttribute(actualList.get(i), expectedList.get(i), elemType, attrName);
+ }
+ }
+ break;
+ case STRUCT:
+ StructInstance structInstance = (StructInstance) expected;
+ AtlasStruct newStructVal = (AtlasStruct) actual;
+ assertAttributes(newStructVal, structInstance);
+ break;
+ default:
+ Assert.fail("Unknown type category");
+ }
+ }
+
+ @Test(dependsOnMethods = "testCreate")
+ public void testArrayUpdate() throws Exception {
+ //clear state
+ init();
+
+ AtlasEntity entityClone = new AtlasEntity(entityCreated);
+
+ List<AtlasEntity> employees = (List<AtlasEntity>) entityClone.getAttribute("employees");
+
+ List<AtlasEntity> updatedEmployees = new ArrayList<>(employees);
+ clearSubOrdinates(updatedEmployees, 1);
+ entityClone.setAttribute("employees", updatedEmployees);
+
+ EntityMutationResponse response = entityStore.createOrUpdate(entityClone);
+
+ List<AtlasEntityHeader> entitiesUpdated = response.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE);
+ Assert.assertNotNull(entitiesUpdated);
+ Assert.assertEquals(entitiesUpdated.size(), 5);
+
+ AtlasEntityHeader deptEntity = entitiesUpdated.get(0);
+
+ //TODO : Change to new API after new instance GET API is ready.
+ ITypedReferenceableInstance instance = metadataService.getEntityDefinition(deptEntity.getGuid());
+ assertAttributes(deptEntity, instance);
+
+ }
+
+ private void clearSubOrdinates(List<AtlasEntity> updatedEmployees, int index) {
+ List<AtlasEntity> subOrdinates = (List<AtlasEntity>) updatedEmployees.get(index).getAttribute("subordinates");
+ List<AtlasEntity> subOrdClone = new ArrayList<>(subOrdinates);
+ subOrdClone.remove(index);
+
+ updatedEmployees.get(index).setAttribute("subordinates", subOrdClone);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/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
new file mode 100644
index 0000000..1fc11a2
--- /dev/null
+++ b/server-api/src/main/java/org/apache/atlas/RequestContextV1.java
@@ -0,0 +1,122 @@
+/**
+ * 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.metrics.Metrics;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasEntityHeader;
+import org.apache.atlas.typesystem.ITypedReferenceableInstance;
+import org.apache.atlas.typesystem.persistence.Id;
+import org.apache.atlas.typesystem.types.ClassType;
+import org.apache.atlas.typesystem.types.TypeSystem;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+public class RequestContextV1 {
+ private static final Logger LOG = LoggerFactory.getLogger(RequestContextV1.class);
+
+ private static final ThreadLocal<RequestContextV1> CURRENT_CONTEXT = new ThreadLocal<>();
+
+ private Set<String> createdEntityIds = new LinkedHashSet<>();
+ private Set<String> updatedEntityIds = new LinkedHashSet<>();
+ private Set<String> deletedEntityIds = new LinkedHashSet<>();
+
+ private String user;
+ private final long requestTime;
+
+ TypeSystem typeSystem = TypeSystem.getInstance();
+ private Metrics metrics = new Metrics();
+
+ private RequestContextV1() {
+ requestTime = System.currentTimeMillis();
+ }
+
+ //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() {
+ CURRENT_CONTEXT.remove();
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public void setUser(String user) {
+ this.user = user;
+ }
+
+ public void recordEntityCreate(Collection<String> createdEntityIds) {
+ this.createdEntityIds.addAll(createdEntityIds);
+ }
+
+ public void recordEntityCreate(String createdEntityId) {
+ this.createdEntityIds.add(createdEntityId);
+ }
+
+ public void recordEntityUpdate(Collection<String> updatedEntityIds) {
+ this.updatedEntityIds.addAll(updatedEntityIds);
+ }
+
+ public void recordEntityUpdate(String entityId) {
+ this.updatedEntityIds.add(entityId);
+ }
+ public void recordEntityDelete(String entityId) {
+ deletedEntityIds.add(entityId);
+ }
+
+ public Collection<String> getCreatedEntityIds() {
+ return createdEntityIds;
+ }
+
+ public Collection<String> getUpdatedEntityIds() {
+ return updatedEntityIds;
+ }
+
+ public Collection<String> getDeletedEntityIds() {
+ return deletedEntityIds;
+ }
+
+ public long getRequestTime() {
+ return requestTime;
+ }
+
+ public boolean isDeletedEntity(String entityGuid) {
+ return deletedEntityIds.contains(entityGuid);
+ }
+
+ public static Metrics getMetrics() {
+ return get().metrics;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasEntityFormatConverter.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasEntityFormatConverter.java b/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasEntityFormatConverter.java
index c4be236..74ab740 100644
--- a/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasEntityFormatConverter.java
+++ b/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasEntityFormatConverter.java
@@ -109,9 +109,9 @@ public class AtlasEntityFormatConverter extends AtlasStructFormatConverter {
}
private AtlasEntity.Status convertState(EntityState state){
- Status status = Status.STATUS_ACTIVE;
+ Status status = Status.ACTIVE;
if(state != null && state.equals(EntityState.DELETED)){
- status = Status.STATUS_DELETED;
+ status = Status.DELETED;
}
LOG.debug("Setting state to {}", state);
return status;
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasInstanceRestAdapters.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasInstanceRestAdapters.java b/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasInstanceRestAdapters.java
index ad16be7..2b13552 100644
--- a/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasInstanceRestAdapters.java
+++ b/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasInstanceRestAdapters.java
@@ -126,13 +126,13 @@ public class AtlasInstanceRestAdapters {
for (String guid : result.getCreatedEntities()) {
AtlasEntityHeader header = new AtlasEntityHeader();
header.setGuid(guid);
- response.addEntity(EntityMutations.EntityOperation.CREATE_OR_UPDATE, header);
+ response.addEntity(EntityMutations.EntityOperation.CREATE, header);
}
for (String guid : result.getUpdateEntities()) {
AtlasEntityHeader header = new AtlasEntityHeader();
header.setGuid(guid);
- response.addEntity(EntityMutations.EntityOperation.CREATE_OR_UPDATE, header);
+ response.addEntity(EntityMutations.EntityOperation.UPDATE, header);
}
for (String guid : result.getDeletedEntities()) {
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasStructFormatConverter.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasStructFormatConverter.java b/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasStructFormatConverter.java
index 3565ab3..8777510 100644
--- a/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasStructFormatConverter.java
+++ b/webapp/src/main/java/org/apache/atlas/web/adapters/AtlasStructFormatConverter.java
@@ -124,20 +124,20 @@ public class AtlasStructFormatConverter extends AtlasAbstractFormatConverter {
if (MapUtils.isNotEmpty(attributes)) {
ret = new HashMap<>();
- for (AtlasStructDef.AtlasAttributeDef attrDef : getAttributeDefs(structType)) {
- AtlasType attrType = structType.getAttributeType(attrDef.getName());
+ for (AtlasStructType.AtlasAttribute attr : getAttributes(structType)) {
+ AtlasType attrType = structType.getAttributeType(attr.getAttributeDef().getName());
if (attrType == null) {
- LOG.warn("ignored attribute {}.{}: failed to find AtlasType", structType.getTypeName(), attrDef.getName());
+ LOG.warn("ignored attribute {}.{}: failed to find AtlasType", structType.getTypeName(), attr.getAttributeDef().getName());
continue;
}
AtlasFormatConverter attrConverter = converterRegistry.getConverter(attrType.getTypeCategory());
- Object v2Value = attributes.get(attrDef.getName());
+ Object v2Value = attributes.get(attr.getAttributeDef().getName());
Object v1Value = attrConverter.fromV2ToV1(v2Value, attrType);
- ret.put(attrDef.getName(), v1Value);
+ ret.put(attr.getAttributeDef().getName(), v1Value);
}
}
@@ -150,29 +150,27 @@ public class AtlasStructFormatConverter extends AtlasAbstractFormatConverter {
if (MapUtils.isNotEmpty(attributes)) {
ret = new HashMap<>();
- for (AtlasStructDef.AtlasAttributeDef attrDef : getAttributeDefs(structType)) {
- AtlasType attrType = structType.getAttributeType(attrDef.getName());
+ for (AtlasStructType.AtlasAttribute attr : getAttributes(structType)) {
+ AtlasType attrType = structType.getAttributeType(attr.getAttributeDef().getName());
AtlasFormatConverter attrConverter = converterRegistry.getConverter(attrType.getTypeCategory());
- Object v1Value = attributes.get(attrDef.getName());
+ Object v1Value = attributes.get(attr.getAttributeDef().getName());
Object v2Value = attrConverter.fromV1ToV2(v1Value, attrType);
- ret.put(attrDef.getName(), v2Value);
+ ret.put(attr.getAttributeDef().getName(), v2Value);
}
}
return ret;
}
- private Collection<AtlasAttributeDef> getAttributeDefs(AtlasStructType structType) {
- Collection<AtlasAttributeDef> ret = null;
+ private Collection<AtlasStructType.AtlasAttribute> getAttributes(AtlasStructType structType) {
+ Collection<AtlasStructType.AtlasAttribute> ret = null;
- if (structType.getTypeCategory() == TypeCategory.STRUCT) {
- ret = structType.getStructDef().getAttributeDefs();
- } else if (structType.getTypeCategory() == TypeCategory.CLASSIFICATION) {
- ret = ((AtlasClassificationType)structType).getAllAttributeDefs().values();
- } else if (structType.getTypeCategory() == TypeCategory.ENTITY) {
- ret = ((AtlasEntityType)structType).getAllAttributeDefs().values();
+ if (structType.getTypeCategory() == TypeCategory.STRUCT
+ || structType.getTypeCategory() == TypeCategory.CLASSIFICATION
+ || structType.getTypeCategory() == TypeCategory.ENTITY) {
+ ret = structType.getAllAttributes().values();
} else {
ret = Collections.emptyList();
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/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 f6acd07..21f8977 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
@@ -104,7 +104,7 @@ public class EntitiesREST {
/*******
* Entity Updation - Allows full update of the specified entities.
* Any associations like Classifications, Business Terms will have to be handled through the respective APIs
- * Null updates are supported i.e Set an attribute value to Null if its an optional attribute
+ * Null updates are supported i.e Set an attribute value to Null if its an optional attribute
*******/
@PUT
@Consumes(Servlets.JSON_MEDIA_TYPE)
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/webapp/src/main/java/org/apache/atlas/web/util/LineageUtils.java
----------------------------------------------------------------------
diff --git a/webapp/src/main/java/org/apache/atlas/web/util/LineageUtils.java b/webapp/src/main/java/org/apache/atlas/web/util/LineageUtils.java
index 54ca236..58ddf8b 100644
--- a/webapp/src/main/java/org/apache/atlas/web/util/LineageUtils.java
+++ b/webapp/src/main/java/org/apache/atlas/web/util/LineageUtils.java
@@ -69,7 +69,7 @@ public final class LineageUtils {
TypeSystem.IdType idType = TypeSystem.getInstance().getIdType();
vertexIdMap.put(idType.idAttrName(), guid);
- vertexIdMap.put(idType.stateAttrName(), (entityHeader.getStatus() == AtlasEntity.Status.STATUS_ACTIVE) ? "ACTIVE" : "DELETED");
+ vertexIdMap.put(idType.stateAttrName(), (entityHeader.getStatus() == AtlasEntity.Status.ACTIVE) ? "ACTIVE" : "DELETED");
vertexIdMap.put(idType.typeNameAttrName(), entityHeader.getTypeName());
Map<String, Object> values = new HashMap<>();
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/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
index 265b650..90a46f8 100644
--- a/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java
+++ b/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntitiesREST.java
@@ -96,7 +96,7 @@ public class TestEntitiesREST {
entities.add(tableEntity);
EntityMutationResponse response = entitiesREST.createOrUpdate(entities);
- List<AtlasEntityHeader> guids = response.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE);
+ List<AtlasEntityHeader> guids = response.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE);
Assert.assertNotNull(guids);
Assert.assertEquals(guids.size(), 3);
@@ -125,7 +125,7 @@ public class TestEntitiesREST {
newEntities.add(newTableEntity);
EntityMutationResponse response2 = entitiesREST.createOrUpdate(newEntities);
- List<AtlasEntityHeader> newGuids = response2.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE);
+ List<AtlasEntityHeader> newGuids = response2.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE);
Assert.assertNotNull(newGuids);
Assert.assertEquals(newGuids.size(), 3);
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/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
index 2a75773..ee36fdf 100644
--- a/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntityREST.java
+++ b/webapp/src/test/java/org/apache/atlas/web/adapters/TestEntityREST.java
@@ -79,7 +79,7 @@ public class TestEntityREST {
final EntityMutationResponse response = entityREST.createOrUpdate(dbEntity);
Assert.assertNotNull(response);
- List<AtlasEntityHeader> entitiesMutated = response.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE);
+ List<AtlasEntityHeader> entitiesMutated = response.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE);
Assert.assertNotNull(entitiesMutated);
Assert.assertEquals(entitiesMutated.size(), 1);
@@ -160,7 +160,7 @@ public class TestEntityREST {
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();
+ String dbGuid = response.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE).get(0).getGuid();
Assert.assertTrue(AtlasEntity.isAssigned(dbGuid));
//Get By unique attribute
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/webapp/src/test/java/org/apache/atlas/web/resources/BaseResourceIT.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/atlas/web/resources/BaseResourceIT.java b/webapp/src/test/java/org/apache/atlas/web/resources/BaseResourceIT.java
index 44d8a11..51be64c 100755
--- a/webapp/src/test/java/org/apache/atlas/web/resources/BaseResourceIT.java
+++ b/webapp/src/test/java/org/apache/atlas/web/resources/BaseResourceIT.java
@@ -225,9 +225,9 @@ public abstract class BaseResourceIT {
entity = entitiesClientV2.updateEntity(atlasEntity);
}
assertNotNull(entity);
- assertNotNull(entity.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE));
- assertTrue(entity.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE).size() > 0);
- return entity.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE).get(0);
+ assertNotNull(entity.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE));
+ assertTrue(entity.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE).size() > 0);
+ return entity.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE).get(0);
} catch (AtlasServiceException e) {
LOG.error("Entity {} failed", update ? "update" : "creation", entity);
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/webapp/src/test/java/org/apache/atlas/web/resources/EntityDiscoveryJerseyResourceIT.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/atlas/web/resources/EntityDiscoveryJerseyResourceIT.java b/webapp/src/test/java/org/apache/atlas/web/resources/EntityDiscoveryJerseyResourceIT.java
index 2ade5b0..2bbe10a 100755
--- a/webapp/src/test/java/org/apache/atlas/web/resources/EntityDiscoveryJerseyResourceIT.java
+++ b/webapp/src/test/java/org/apache/atlas/web/resources/EntityDiscoveryJerseyResourceIT.java
@@ -75,7 +75,7 @@ public class EntityDiscoveryJerseyResourceIT extends BaseResourceIT {
AtlasEntityHeaderWithAssociations dbEntity = entities.get(0);
assertEquals(dbEntity.getTypeName(), DATABASE_TYPE);
assertEquals(dbEntity.getDisplayText(), dbName);
- assertEquals(dbEntity.getStatus(), Status.STATUS_ACTIVE);
+ assertEquals(dbEntity.getStatus(), Status.ACTIVE);
assertNotNull(dbEntity.getGuid());
assertNull(searchResult.getAttributes());
assertNull(searchResult.getFullTextResult());
@@ -137,7 +137,7 @@ public class EntityDiscoveryJerseyResourceIT extends BaseResourceIT {
AtlasEntityHeaderWithAssociations dbEntity = entities.get(0);
assertEquals(dbEntity.getTypeName(), DATABASE_TYPE);
assertEquals(dbEntity.getDisplayText(), dbName);
- assertEquals(dbEntity.getStatus(), Status.STATUS_ACTIVE);
+ assertEquals(dbEntity.getStatus(), Status.ACTIVE);
assertNotNull(dbEntity.getGuid());
assertNull(searchResult.getAttributes());
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/webapp/src/test/java/org/apache/atlas/web/resources/EntityV2JerseyResourceIT.java
----------------------------------------------------------------------
diff --git a/webapp/src/test/java/org/apache/atlas/web/resources/EntityV2JerseyResourceIT.java b/webapp/src/test/java/org/apache/atlas/web/resources/EntityV2JerseyResourceIT.java
index d7702e2..74338fd 100755
--- a/webapp/src/test/java/org/apache/atlas/web/resources/EntityV2JerseyResourceIT.java
+++ b/webapp/src/test/java/org/apache/atlas/web/resources/EntityV2JerseyResourceIT.java
@@ -138,7 +138,7 @@ public class EntityV2JerseyResourceIT extends BaseResourceIT {
EntityMutationResponse entity = entitiesClientV2.createEntity(hiveTableInstanceV2);
assertNotNull(entity);
- assertNotNull(entity.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE));
+ assertNotNull(entity.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE));
results = searchByDSL(String.format("%s where name='%s'", DATABASE_TYPE, DATABASE_NAME));
assertEquals(results.length(), 1);
}
@@ -175,9 +175,9 @@ public class EntityV2JerseyResourceIT extends BaseResourceIT {
instance.setAttribute("name", randomString());
EntityMutationResponse mutationResponse = entitiesClientV2.createEntity(instance);
assertNotNull(mutationResponse);
- assertNotNull(mutationResponse.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE));
- assertEquals(mutationResponse.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE).size(),1 );
- String guid = mutationResponse.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE).get(0).getGuid();
+ assertNotNull(mutationResponse.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE));
+ assertEquals(mutationResponse.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE).size(),1 );
+ String guid = mutationResponse.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE).get(0).getGuid();
//update type - add attribute
entityDef = AtlasTypeUtil.createClassTypeDef(entityDef.getName(), ImmutableSet.<String>of(),
@@ -352,7 +352,7 @@ public class EntityV2JerseyResourceIT extends BaseResourceIT {
entityByGuid.setAttribute(property, value);
EntityMutationResponse response = entitiesClientV2.updateEntity(entityByGuid);
assertNotNull(response);
- assertNotNull(response.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE));
+ assertNotNull(response.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE));
}
private AtlasEntity createHiveDB() {
@@ -575,8 +575,8 @@ public class EntityV2JerseyResourceIT extends BaseResourceIT {
LOG.debug("Updating entity= " + tableUpdated);
EntityMutationResponse updateResult = entitiesClientV2.updateEntity(tableEntity.getGuid(), tableUpdated);
assertNotNull(updateResult);
- assertNotNull(updateResult.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE));
- assertTrue(updateResult.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE).size() > 0);
+ assertNotNull(updateResult.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE));
+ assertTrue(updateResult.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE).size() > 0);
AtlasEntity entityByGuid = entitiesClientV2.getEntityByGuid(tableEntity.getGuid());
assertNotNull(entityByGuid);
@@ -593,8 +593,8 @@ public class EntityV2JerseyResourceIT extends BaseResourceIT {
EntityMutationResponse updateResponse = entitiesClientV2.updateEntityByAttribute(BaseResourceIT.HIVE_TABLE_TYPE, AtlasClient.REFERENCEABLE_ATTRIBUTE_NAME,
(String) tableEntity.getAttribute("name"), tableUpdated);
assertNotNull(updateResponse);
- assertNotNull(updateResponse.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE));
- assertTrue(updateResponse.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE).size() > 0);
+ assertNotNull(updateResponse.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE));
+ assertTrue(updateResponse.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE).size() > 0);
entityByGuid = entitiesClientV2.getEntityByGuid(tableEntity.getGuid());
assertNotNull(entityByGuid);
@@ -623,8 +623,8 @@ public class EntityV2JerseyResourceIT extends BaseResourceIT {
tableEntity.setAttribute("columns", columns);
EntityMutationResponse updateEntityResult = entitiesClientV2.updateEntity(tableEntity);
assertNotNull(updateEntityResult);
- assertNotNull(updateEntityResult.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE));
- assertEquals(updateEntityResult.getEntitiesByOperation(EntityMutations.EntityOperation.CREATE_OR_UPDATE).size(), 3);
+ assertNotNull(updateEntityResult.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE));
+ assertEquals(updateEntityResult.getEntitiesByOperation(EntityMutations.EntityOperation.UPDATE).size(), 3);
AtlasEntity entityByGuid = entitiesClientV2.getEntityByGuid(tableEntity.getGuid());
List<AtlasEntity> refs = (List<AtlasEntity>) entityByGuid.getAttribute("columns");
[2/3] incubator-atlas git commit: ATLAS-1467: instance
create/full-Update implementation
Posted by ma...@apache.org.
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityGraphDiscoveryV1.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityGraphDiscoveryV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityGraphDiscoveryV1.java
new file mode 100644
index 0000000..b874c5d
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityGraphDiscoveryV1.java
@@ -0,0 +1,244 @@
+/**
+ * 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.v1;
+
+import atlas.shaded.hbase.guava.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Provider;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.TypeCategory;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.model.instance.AtlasStruct;
+import org.apache.atlas.model.typedef.AtlasStructDef;
+import org.apache.atlas.repository.store.graph.EntityGraphDiscoveryContext;
+import org.apache.atlas.repository.store.graph.EntityGraphDiscovery;
+import org.apache.atlas.repository.store.graph.EntityResolver;
+import org.apache.atlas.type.AtlasArrayType;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasMapType;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.atlas.type.AtlasType;
+import org.apache.atlas.type.AtlasTypeRegistry;
+
+import javax.inject.Inject;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+
+public class AtlasEntityGraphDiscoveryV1 implements EntityGraphDiscovery {
+
+ private AtlasTypeRegistry typeRegistry;
+
+ private Set<String> processedIds = new HashSet<>();
+
+ private EntityGraphDiscoveryContext discoveredEntities = new EntityGraphDiscoveryContext();
+
+ private final Collection<EntityResolver> entityResolvers = new LinkedHashSet<>();
+
+ @Inject
+ public AtlasEntityGraphDiscoveryV1(AtlasTypeRegistry typeRegistry, final Collection<Provider<EntityResolver>> entityResolverProviders) {
+ this.typeRegistry = typeRegistry;
+
+ for (Provider<EntityResolver> entityResolverProvider : entityResolverProviders) {
+ entityResolvers.add(entityResolverProvider.get());
+ }
+ }
+
+ @VisibleForTesting
+ public AtlasEntityGraphDiscoveryV1(AtlasTypeRegistry typeRegistry, final List<EntityResolver> entityResolvers) {
+ this.typeRegistry = typeRegistry;
+
+ for (EntityResolver entityResolver : entityResolvers) {
+ this.entityResolvers.add(entityResolver);
+ }
+ }
+
+ @Override
+ public void init() throws AtlasBaseException {
+ //Nothing to do
+ }
+
+ @Override
+ public EntityGraphDiscoveryContext discoverEntities(final List<AtlasEntity> entities) throws AtlasBaseException {
+
+ //walk the graph and discover entity references
+ discover(entities);
+
+ //resolve root and referred entities
+ resolveReferences();
+
+ return discoveredEntities;
+ }
+
+ @Override
+ public void cleanUp() throws AtlasBaseException {
+ processedIds.clear();
+ discoveredEntities.cleanUp();
+ final Collection<EntityResolver> entityResolvers = this.entityResolvers;
+ for (EntityResolver resolver : entityResolvers) {
+ resolver.cleanUp();
+ }
+ }
+
+
+ protected void resolveReferences() throws AtlasBaseException {
+ for (EntityResolver resolver : entityResolvers ) {
+ resolver.init(discoveredEntities);
+ resolver.resolveEntityReferences();
+ }
+ }
+
+
+ protected void discover(final List<AtlasEntity> entities) throws AtlasBaseException {
+ for (AtlasEntity entity : entities) {
+ AtlasType type = typeRegistry.getType(entity.getTypeName());
+
+ discoveredEntities.addRootEntity(entity);
+ walkEntityGraph(type, entity);
+ }
+ }
+
+ private void visitReference(AtlasEntityType type, Object entity, boolean isManagedEntity) throws AtlasBaseException {
+ if ( entity != null) {
+ if ( entity instanceof String ) {
+ String guid = (String) entity;
+ discoveredEntities.addUnResolvedIdReference(type, guid);
+ } else if ( entity instanceof AtlasObjectId ) {
+ final String guid = ((AtlasObjectId) entity).getGuid();
+ discoveredEntities.addUnResolvedIdReference(type, guid);
+ } else if ( entity instanceof AtlasEntity ) {
+ AtlasEntity entityObj = ( AtlasEntity ) entity;
+ if (!processedIds.contains(entityObj.getGuid())) {
+ processedIds.add(entityObj.getGuid());
+
+ if ( isManagedEntity ) {
+ discoveredEntities.addRootEntity(entityObj);
+ visitStruct(type, entityObj);
+ } else if ( entity instanceof AtlasObjectId) {
+ discoveredEntities.addUnResolvedIdReference(type, ((AtlasObjectId) entity).getGuid());
+ } else {
+ discoveredEntities.addUnResolvedEntityReference(entityObj);
+ }
+ }
+ }
+ }
+ }
+
+ void visitAttribute(AtlasStructType parentType, AtlasType attrType, AtlasStructDef.AtlasAttributeDef attrDef, Object val) throws AtlasBaseException {
+ if (val != null) {
+ if ( isPrimitive(attrType.getTypeCategory()) ) {
+ return;
+ }
+ if (attrType.getTypeCategory() == TypeCategory.ARRAY) {
+ AtlasArrayType arrayType = (AtlasArrayType) attrType;
+ AtlasType elemType = arrayType.getElementType();
+ visitCollectionReferences(parentType, attrType, attrDef, elemType, val);
+ } else if (attrType.getTypeCategory() == TypeCategory.MAP) {
+ AtlasType keyType = ((AtlasMapType) attrType).getKeyType();
+ AtlasType valueType = ((AtlasMapType) attrType).getValueType();
+ visitMapReferences(parentType, attrType, attrDef, keyType, valueType, val);
+ } else if (attrType.getTypeCategory() == TypeCategory.STRUCT) {
+ visitStruct(attrType, val);
+ } else if (attrType.getTypeCategory() == TypeCategory.ENTITY) {
+ if ( val instanceof AtlasObjectId || val instanceof String) {
+ visitReference((AtlasEntityType) attrType, val, false);
+ } else if ( val instanceof AtlasEntity ) {
+ //TODO - Change this to foreign key checks after changes in the model
+ if ( parentType.isMappedFromRefAttribute(attrDef.getName())) {
+ visitReference((AtlasEntityType) attrType, val, true);
+ }
+ }
+ }
+ }
+ }
+
+ void visitMapReferences(AtlasStructType parentType, final AtlasType attrType, AtlasStructDef.AtlasAttributeDef attrDef, AtlasType keyType, AtlasType valueType, Object val) throws AtlasBaseException {
+ if (isPrimitive(keyType.getTypeCategory()) && isPrimitive(valueType.getTypeCategory())) {
+ return;
+ }
+
+ if (val != null) {
+ Iterator<Map.Entry> it = null;
+ if (Map.class.isAssignableFrom(val.getClass())) {
+ it = ((Map) val).entrySet().iterator();
+ ImmutableMap.Builder b = ImmutableMap.builder();
+ while (it.hasNext()) {
+ Map.Entry e = it.next();
+ visitAttribute(parentType, keyType, attrDef, e.getKey());
+ visitAttribute(parentType, valueType, attrDef, e.getValue());
+ }
+ }
+ }
+ }
+
+ void visitCollectionReferences(final AtlasStructType parentType, final AtlasType attrType, final AtlasStructDef.AtlasAttributeDef attrDef, AtlasType elemType, Object val) throws AtlasBaseException {
+
+ if (isPrimitive(elemType.getTypeCategory())) {
+ return;
+ }
+
+ if (val != null) {
+ Iterator it = null;
+ if (val instanceof Collection) {
+ it = ((Collection) val).iterator();
+ } else if (val instanceof Iterable) {
+ it = ((Iterable) val).iterator();
+ } else if (val instanceof Iterator) {
+ it = (Iterator) val;
+ }
+ if (it != null) {
+ while (it.hasNext()) {
+ Object elem = it.next();
+ visitAttribute(parentType, elemType, attrDef, elem);
+ }
+ }
+ }
+ }
+
+ void visitStruct(AtlasType type, Object val) throws AtlasBaseException {
+
+ if (val == null || !(val instanceof AtlasStruct)) {
+ return;
+ }
+
+ AtlasStructType structType = (AtlasStructType) type;
+
+ for (AtlasStructDef.AtlasAttributeDef attributeDef : structType.getStructDef().getAttributeDefs()) {
+ String attrName = attributeDef.getName();
+ AtlasType attrType = structType.getAttributeType(attrName);
+ Object attrVal = ((AtlasStruct) val).getAttribute(attrName);
+ visitAttribute(structType, attrType, attributeDef, attrVal);
+ }
+ }
+
+
+ void walkEntityGraph(AtlasType type, AtlasEntity entity) throws AtlasBaseException {
+ visitStruct(type, entity);
+ }
+
+
+ boolean isPrimitive(TypeCategory typeCategory) {
+ return typeCategory == TypeCategory.PRIMITIVE || typeCategory == TypeCategory.ENUM;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1.java
index e731c11..18e397b 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1.java
@@ -18,25 +18,93 @@
package org.apache.atlas.repository.store.graph.v1;
+import atlas.shaded.hbase.guava.common.annotations.VisibleForTesting;
+import com.google.inject.Inject;
+import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.GraphTransaction;
+import org.apache.atlas.RequestContextV1;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.SearchFilter;
+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.AtlasObjectId;
import org.apache.atlas.model.instance.EntityMutationResponse;
import org.apache.atlas.model.instance.EntityMutations;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
import org.apache.atlas.repository.store.graph.AtlasEntityStore;
-
+import org.apache.atlas.repository.store.graph.EntityGraphDiscoveryContext;
+import org.apache.atlas.repository.store.graph.EntityGraphDiscovery;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasType;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
import java.util.List;
public class AtlasEntityStoreV1 implements AtlasEntityStore {
- @Override
- public void init() throws AtlasBaseException {
+
+ protected EntityGraphDiscovery graphDiscoverer;
+ protected AtlasTypeRegistry typeRegistry;
+
+ private EntityGraphMapper graphMapper;
+
+ private static final Logger LOG = LoggerFactory.getLogger(AtlasEntityStoreV1.class);
+
+ @Inject
+ public AtlasEntityStoreV1(EntityGraphMapper vertexMapper) {
+ this.graphMapper = vertexMapper;
+ }
+
+ @Inject
+ public void init(AtlasTypeRegistry typeRegistry, EntityGraphDiscovery graphDiscoverer) throws AtlasBaseException {
+ this.graphDiscoverer = graphDiscoverer;
+ this.typeRegistry = typeRegistry;
}
@Override
- public EntityMutationResponse createOrUpdate(final AtlasEntity entity) {
- return null;
+ public EntityMutationResponse createOrUpdate(final AtlasEntity entity) throws AtlasBaseException {
+ return createOrUpdate(new ArrayList<AtlasEntity>() {{ add(entity); }});
+ }
+
+ public EntityMutationContext preCreateOrUpdate(final List<AtlasEntity> atlasEntities) throws AtlasBaseException {
+
+ EntityGraphDiscoveryContext discoveredEntities = graphDiscoverer.discoverEntities(atlasEntities);
+ EntityMutationContext context = new EntityMutationContext(discoveredEntities);
+ for (AtlasEntity entity : discoveredEntities.getRootEntities()) {
+
+ AtlasVertex vertex = null;
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== AtlasEntityStoreV1.preCreateOrUpdate({}): {}", entity);
+ }
+
+ AtlasEntityType entityType = (AtlasEntityType) typeRegistry.getType(entity.getTypeName());
+
+ if ( discoveredEntities.isResolved(entity.getGuid()) ) {
+ vertex = discoveredEntities.getResolvedReference(entity.getGuid());
+ context.addUpdated(entity, entityType, vertex);
+
+ String guid = AtlasGraphUtilsV1.getIdFromVertex(vertex);
+ RequestContextV1.get().recordEntityUpdate(guid);
+ } else {
+ //Create vertices which do not exist in the repository
+ vertex = graphMapper.createVertexTemplate(entity, entityType);
+ context.addCreated(entity, entityType, vertex);
+ discoveredEntities.addRepositoryResolvedReference(new AtlasObjectId(entityType.getTypeName(), entity.getGuid()), vertex);
+
+ String guid = AtlasGraphUtilsV1.getIdFromVertex(vertex);
+ RequestContextV1.get().recordEntityCreate(guid);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== AtlasEntityStoreV1.preCreateOrUpdate({}): {}", entity, vertex);
+ }
+ }
+
+ return context;
}
@Override
@@ -55,8 +123,24 @@ public class AtlasEntityStoreV1 implements AtlasEntityStore {
}
@Override
+ @GraphTransaction
public EntityMutationResponse createOrUpdate(final List<AtlasEntity> entities) throws AtlasBaseException {
- return null;
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> AtlasEntityStoreV1.createOrUpdate({}, {})", entities);
+ }
+
+ //Validate
+ List<AtlasEntity> normalizedEntities = validateAndNormalize(entities);
+
+ //Discover entities, create vertices
+ EntityMutationContext ctx = preCreateOrUpdate(normalizedEntities);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("<== AtlasStructDefStoreV1.createOrUpdate({}, {}): {}", entities);
+ }
+
+ return graphMapper.mapAttributes(ctx);
}
@Override
@@ -117,7 +201,48 @@ public class AtlasEntityStoreV1 implements AtlasEntityStore {
@Override
public AtlasEntity.AtlasEntities searchEntities(final SearchFilter searchFilter) throws AtlasBaseException {
- // TODO: Add checks here to ensure that typename and supertype are mandatory in the requests
+ // TODO: Add checks here to ensure that typename and supertype are mandatory in the request
return null;
}
+
+ private List<AtlasEntity> validateAndNormalize(final List<AtlasEntity> entities) throws AtlasBaseException {
+
+ List<AtlasEntity> normalizedEntities = new ArrayList<>();
+ List<String> messages = new ArrayList<>();
+
+ for (AtlasEntity entity : entities) {
+ AtlasType type = typeRegistry.getType(entity.getTypeName());
+ if (type.getTypeCategory() != TypeCategory.ENTITY) {
+ throw new AtlasBaseException(AtlasErrorCode.TYPE_MATCH_FAILED, type.getTypeCategory().name(), TypeCategory.ENTITY.name());
+ }
+
+ type.validateValue(entity, entity.getTypeName(), messages);
+
+ if ( !messages.isEmpty()) {
+ throw new AtlasBaseException(AtlasErrorCode.INSTANCE_CRUD_INVALID_PARAMS, messages);
+ }
+ AtlasEntity normalizedEntity = (AtlasEntity) type.getNormalizedValue(entity);
+ if ( normalizedEntity == null) {
+ //TODO - Fix this. Should not come here. Should ideally fail above
+ throw new AtlasBaseException(AtlasErrorCode.INSTANCE_CRUD_INVALID_PARAMS, "Failed to validate entity");
+ }
+ normalizedEntities.add(normalizedEntity);
+ }
+
+ return normalizedEntities;
+ }
+
+ @VisibleForTesting
+ EntityGraphDiscovery getGraphDiscoverer() {
+ return graphDiscoverer;
+ }
+
+ @VisibleForTesting
+ void setGraphDiscoverer(EntityGraphDiscovery discoverer) {
+ this.graphDiscoverer = discoverer;
+ }
+
+ public void cleanUp() throws AtlasBaseException {
+ this.graphDiscoverer.cleanUp();
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEnumDefStoreV1.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEnumDefStoreV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEnumDefStoreV1.java
index fccbeba..3cb10ff 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEnumDefStoreV1.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasEnumDefStoreV1.java
@@ -283,19 +283,19 @@ public class AtlasEnumDefStoreV1 extends AtlasAbstractDefStoreV1 implements Atla
List<String> values = new ArrayList<>(enumDef.getElementDefs().size());
for (AtlasEnumElementDef element : enumDef.getElementDefs()) {
- String elemKey = AtlasGraphUtilsV1.getPropertyKey(enumDef, element.getValue());
+ String elemKey = AtlasGraphUtilsV1.getTypeDefPropertyKey(enumDef, element.getValue());
AtlasGraphUtilsV1.setProperty(vertex, elemKey, element.getOrdinal());
if (StringUtils.isNoneBlank(element.getDescription())) {
- String descKey = AtlasGraphUtilsV1.getPropertyKey(elemKey, "description");
+ String descKey = AtlasGraphUtilsV1.getTypeDefPropertyKey(elemKey, "description");
AtlasGraphUtilsV1.setProperty(vertex, descKey, element.getDescription());
}
values.add(element.getValue());
}
- AtlasGraphUtilsV1.setProperty(vertex, AtlasGraphUtilsV1.getPropertyKey(enumDef), values);
+ AtlasGraphUtilsV1.setProperty(vertex, AtlasGraphUtilsV1.getTypeDefPropertyKey(enumDef), values);
}
private AtlasEnumDef toEnumDef(AtlasVertex vertex) {
@@ -314,10 +314,10 @@ public class AtlasEnumDefStoreV1 extends AtlasAbstractDefStoreV1 implements Atla
typeDefStore.vertexToTypeDef(vertex, ret);
List<AtlasEnumElementDef> elements = new ArrayList<>();
- List<String> elemValues = vertex.getProperty(AtlasGraphUtilsV1.getPropertyKey(ret), List.class);
+ List<String> elemValues = vertex.getProperty(AtlasGraphUtilsV1.getTypeDefPropertyKey(ret), List.class);
for (String elemValue : elemValues) {
- String elemKey = AtlasGraphUtilsV1.getPropertyKey(ret, elemValue);
- String descKey = AtlasGraphUtilsV1.getPropertyKey(elemKey, "description");
+ String elemKey = AtlasGraphUtilsV1.getTypeDefPropertyKey(ret, elemValue);
+ String descKey = AtlasGraphUtilsV1.getTypeDefPropertyKey(elemKey, "description");
Integer ordinal = AtlasGraphUtilsV1.getProperty(vertex, elemKey, Integer.class);
String desc = AtlasGraphUtilsV1.getProperty(vertex, descKey, String.class);
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasGraphUtilsV1.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasGraphUtilsV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasGraphUtilsV1.java
index 18b3b85..1947855 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasGraphUtilsV1.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasGraphUtilsV1.java
@@ -20,16 +20,30 @@ package org.apache.atlas.repository.store.graph.v1;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
+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.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasStruct;
import org.apache.atlas.model.typedef.AtlasBaseTypeDef;
import org.apache.atlas.repository.Constants;
+import org.apache.atlas.repository.graph.GraphHelper;
import org.apache.atlas.repository.graphdb.AtlasEdge;
import org.apache.atlas.repository.graphdb.AtlasElement;
import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.atlas.type.AtlasType;
+import org.apache.atlas.typesystem.persistence.Id;
+import org.apache.atlas.typesystem.types.DataTypes;
+import org.apache.atlas.typesystem.types.IDataType;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Date;
import java.util.HashMap;
/**
@@ -52,19 +66,19 @@ public class AtlasGraphUtilsV1 {
}});
- public static String getPropertyKey(AtlasBaseTypeDef typeDef) {
- return getPropertyKey(typeDef.getName());
+ public static String getTypeDefPropertyKey(AtlasBaseTypeDef typeDef) {
+ return getTypeDefPropertyKey(typeDef.getName());
}
- public static String getPropertyKey(AtlasBaseTypeDef typeDef, String child) {
- return getPropertyKey(typeDef.getName(), child);
+ public static String getTypeDefPropertyKey(AtlasBaseTypeDef typeDef, String child) {
+ return getTypeDefPropertyKey(typeDef.getName(), child);
}
- public static String getPropertyKey(String typeName) {
+ public static String getTypeDefPropertyKey(String typeName) {
return PROPERTY_PREFIX + typeName;
}
- public static String getPropertyKey(String typeName, String child) {
+ public static String getTypeDefPropertyKey(String typeName, String child) {
return PROPERTY_PREFIX + typeName + "." + child;
}
@@ -80,6 +94,31 @@ public class AtlasGraphUtilsV1 {
return PROPERTY_PREFIX + "edge." + fromNode + "." + toNode;
}
+ public static String getAttributeEdgeLabel(AtlasStructType fromType, String attributeName) throws AtlasBaseException {
+ return GraphHelper.EDGE_LABEL_PREFIX + getQualifiedAttributePropertyKey(fromType, attributeName);
+ }
+
+ public static String getQualifiedAttributePropertyKey(AtlasStructType fromType, String attributeName) throws AtlasBaseException {
+ switch (fromType.getTypeCategory()) {
+ case STRUCT:
+ case ENTITY:
+ case CLASSIFICATION:
+ return fromType.getQualifiedAttributeName(attributeName);
+ default:
+ throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_TYPE, fromType.getTypeCategory().name());
+ }
+ }
+
+ public static boolean isReference(AtlasType type) {
+ return isReference(type.getTypeCategory());
+ }
+
+ public static boolean isReference(TypeCategory typeCategory) {
+ return typeCategory == TypeCategory.STRUCT ||
+ typeCategory == TypeCategory.ENTITY ||
+ typeCategory == TypeCategory.CLASSIFICATION;
+ }
+
public static String encodePropertyKey(String key) {
String ret = key;
@@ -104,6 +143,21 @@ public class AtlasGraphUtilsV1 {
return ret;
}
+ /**
+ * Adds an additional value to a multi-property.
+ *
+ * @param propertyName
+ * @param value
+ */
+ public static AtlasVertex addProperty(AtlasVertex vertex, String propertyName, Object value) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("==> addProperty({}, {}, {})", toString(vertex), propertyName, value);
+ }
+ propertyName = encodePropertyKey(propertyName);
+ vertex.addProperty(propertyName, value);
+ return vertex;
+ }
+
public static <T extends AtlasElement> void setProperty(T element, String propertyName, Object value) {
if (LOG.isDebugEnabled()) {
LOG.debug("==> setProperty({}, {}, {})", toString(element), propertyName, value);
@@ -127,7 +181,12 @@ public class AtlasGraphUtilsV1 {
LOG.debug("Setting property {} in {}", propertyName, toString(element));
}
- element.setProperty(propertyName, value);
+ if ( value instanceof Date) {
+ Long encodedValue = ((Date) value).getTime();
+ element.setProperty(propertyName, encodedValue);
+ } else {
+ element.setProperty(propertyName, value);
+ }
}
}
}
@@ -186,4 +245,13 @@ public class AtlasGraphUtilsV1 {
return String.format("edge[id=%s label=%s from %s -> to %s]", edge.getId(), edge.getLabel(),
toString(edge.getOutVertex()), toString(edge.getInVertex()));
}
+
+ public static AtlasEntity.Status getState(AtlasElement element) {
+ String state = getStateAsString(element);
+ return state == null ? null : AtlasEntity.Status.valueOf(state);
+ }
+
+ public static String getStateAsString(AtlasElement element) {
+ return element.getProperty(Constants.STATE_PROPERTY_KEY, String.class);
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasStructDefStoreV1.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasStructDefStoreV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasStructDefStoreV1.java
index e780dc1..425bde9 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasStructDefStoreV1.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/AtlasStructDefStoreV1.java
@@ -390,13 +390,13 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1 implements At
List<String> attrNames = new ArrayList<>(structDef.getAttributeDefs().size());
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
- String propertyKey = AtlasGraphUtilsV1.getPropertyKey(structDef, attributeDef.getName());
+ String propertyKey = AtlasGraphUtilsV1.getTypeDefPropertyKey(structDef, attributeDef.getName());
AtlasGraphUtilsV1.setProperty(vertex, propertyKey, toJsonFromAttributeDef(attributeDef, structType));
attrNames.add(attributeDef.getName());
}
- AtlasGraphUtilsV1.setProperty(vertex, AtlasGraphUtilsV1.getPropertyKey(structDef), attrNames);
+ AtlasGraphUtilsV1.setProperty(vertex, AtlasGraphUtilsV1.getTypeDefPropertyKey(structDef), attrNames);
}
public static void updateVertexPreUpdate(AtlasStructDef structDef, AtlasStructType structType,
@@ -410,7 +410,7 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1 implements At
}
}
- List<String> currAttrNames = vertex.getProperty(AtlasGraphUtilsV1.getPropertyKey(structDef), List.class);
+ List<String> currAttrNames = vertex.getProperty(AtlasGraphUtilsV1.getTypeDefPropertyKey(structDef), List.class);
// delete attributes that are not present in updated structDef
if (CollectionUtils.isNotEmpty(currAttrNames)) {
@@ -434,13 +434,13 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1 implements At
}
}
- String propertyKey = AtlasGraphUtilsV1.getPropertyKey(structDef, attributeDef.getName());
+ String propertyKey = AtlasGraphUtilsV1.getTypeDefPropertyKey(structDef, attributeDef.getName());
AtlasGraphUtilsV1.setProperty(vertex, propertyKey, toJsonFromAttributeDef(attributeDef, structType));
}
}
- AtlasGraphUtilsV1.setProperty(vertex, AtlasGraphUtilsV1.getPropertyKey(structDef), attrNames);
+ AtlasGraphUtilsV1.setProperty(vertex, AtlasGraphUtilsV1.getTypeDefPropertyKey(structDef), attrNames);
}
public static void updateVertexAddReferences(AtlasStructDef structDef, AtlasVertex vertex,
@@ -457,11 +457,11 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1 implements At
typeDefStore.vertexToTypeDef(vertex, ret);
List<AtlasAttributeDef> attributeDefs = new ArrayList<>();
- List<String> attrNames = vertex.getProperty(AtlasGraphUtilsV1.getPropertyKey(ret), List.class);
+ List<String> attrNames = vertex.getProperty(AtlasGraphUtilsV1.getTypeDefPropertyKey(ret), List.class);
if (CollectionUtils.isNotEmpty(attrNames)) {
for (String attrName : attrNames) {
- String propertyKey = AtlasGraphUtilsV1.getPropertyKey(ret, attrName);
+ String propertyKey = AtlasGraphUtilsV1.getTypeDefPropertyKey(ret, attrName);
String attribJson = vertex.getProperty(propertyKey, String.class);
attributeDefs.add(toAttributeDefFromJson(structDef, AtlasType.fromJson(attribJson, Map.class),
@@ -586,12 +586,12 @@ public class AtlasStructDefStoreV1 extends AtlasAbstractDefStoreV1 implements At
String refAttributeName = null;
List<String> attrNames = attributeType.getProperty(
- AtlasGraphUtilsV1.getPropertyKey(attrTypeName), List.class);
+ AtlasGraphUtilsV1.getTypeDefPropertyKey(attrTypeName), List.class);
if (CollectionUtils.isNotEmpty(attrNames)) {
for (String attrName : attrNames) {
String attribJson = attributeType.getProperty(
- AtlasGraphUtilsV1.getPropertyKey(attrTypeName, attrName), String.class);
+ AtlasGraphUtilsV1.getTypeDefPropertyKey(attrTypeName, attrName), String.class);
Map refAttrInfo = AtlasType.fromJson(attribJson, Map.class);
String refAttribType = (String) refAttrInfo.get("dataType");
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/DeleteHandlerV1.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/DeleteHandlerV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/DeleteHandlerV1.java
new file mode 100644
index 0000000..3b557e6
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/DeleteHandlerV1.java
@@ -0,0 +1,539 @@
+/**
+ * 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.v1;
+
+
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.RequestContextV1;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.TypeCategory;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.typedef.AtlasStructDef;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.repository.graph.AtlasEdgeLabel;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasEdgeDirection;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.type.AtlasArrayType;
+import org.apache.atlas.type.AtlasClassificationType;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasMapType;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.atlas.type.AtlasType;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import java.util.Stack;
+
+import static org.apache.atlas.repository.graph.GraphHelper.EDGE_LABEL_PREFIX;
+import static org.apache.atlas.repository.graph.GraphHelper.string;
+
+public abstract class DeleteHandlerV1 {
+
+ public static final Logger LOG = LoggerFactory.getLogger(DeleteHandlerV1.class);
+
+ private AtlasTypeRegistry typeRegistry;
+ private boolean shouldUpdateReverseAttribute;
+ private boolean softDelete;
+
+ protected static final GraphHelper graphHelper = GraphHelper.getInstance();
+
+ public DeleteHandlerV1(AtlasTypeRegistry typeRegistry, boolean shouldUpdateReverseAttribute, boolean softDelete) {
+ this.typeRegistry = typeRegistry;
+ this.shouldUpdateReverseAttribute = shouldUpdateReverseAttribute;
+ this.softDelete = softDelete;
+ }
+
+ /**
+ * Deletes the specified entity vertices.
+ * Deletes any traits, composite entities, and structs owned by each entity.
+ * Also deletes all the references from/to the entity.
+ *
+ * @param instanceVertices
+ * @throws AtlasException
+ */
+ public void deleteEntities(List<AtlasVertex> instanceVertices) throws AtlasBaseException {
+ RequestContextV1 requestContext = RequestContextV1.get();
+
+ Set<AtlasVertex> deletionCandidateVertices = new HashSet<>();
+
+ for (AtlasVertex instanceVertex : instanceVertices) {
+ String guid = GraphHelper.getGuid(instanceVertex);
+ AtlasEntity.Status state = AtlasGraphUtilsV1.getState(instanceVertex);
+ if (requestContext.getDeletedEntityIds().contains(guid) || state == AtlasEntity.Status.DELETED) {
+ LOG.debug("Skipping deletion of {} as it is already deleted", guid);
+ continue;
+ }
+
+ // Get GUIDs and vertices for all deletion candidates.
+ Set<GraphHelper.VertexInfo> compositeVertices = getCompositeVertices(instanceVertex);
+
+ // Record all deletion candidate GUIDs in RequestContext
+ // and gather deletion candidate vertices.
+ for (GraphHelper.VertexInfo vertexInfo : compositeVertices) {
+ requestContext.recordEntityDelete(vertexInfo.getGuid());
+ deletionCandidateVertices.add(vertexInfo.getVertex());
+ }
+ }
+
+ // Delete traits and vertices.
+ for (AtlasVertex deletionCandidateVertex : deletionCandidateVertices) {
+ deleteAllTraits(deletionCandidateVertex);
+ deleteTypeVertex(deletionCandidateVertex, false);
+ }
+ }
+
+ /**
+ * Get the GUIDs and vertices for all composite entities owned/contained by the specified root entity AtlasVertex.
+ * The graph is traversed from the root entity through to the leaf nodes of the containment graph.
+ *
+ * @param entityVertex the root entity vertex
+ * @return set of VertexInfo for all composite entities
+ * @throws AtlasException
+ */
+ public Set<GraphHelper.VertexInfo> getCompositeVertices(AtlasVertex entityVertex) throws AtlasBaseException {
+ Set<GraphHelper.VertexInfo> result = new HashSet<>();
+ Stack<AtlasVertex> vertices = new Stack<>();
+ vertices.push(entityVertex);
+ while (vertices.size() > 0) {
+ AtlasVertex vertex = vertices.pop();
+ String typeName = GraphHelper.getTypeName(vertex);
+ String guid = GraphHelper.getGuid(vertex);
+ AtlasEntity.Status state = AtlasGraphUtilsV1.getState(vertex);
+ if (state == AtlasEntity.Status.DELETED) {
+ //If the reference vertex is marked for deletion, skip it
+ continue;
+ }
+ result.add(new GraphHelper.VertexInfo(guid, vertex, typeName));
+ AtlasEntityType entityType = (AtlasEntityType) typeRegistry.getType(typeName);
+ for (AtlasStructType.AtlasAttribute attributeInfo : entityType.getAllAttributes().values()) {
+ if (!entityType.isMappedFromRefAttribute(attributeInfo.getAttributeDef().getName())) {
+ continue;
+ }
+ String edgeLabel = AtlasGraphUtilsV1.getAttributeEdgeLabel(entityType, attributeInfo.getAttributeDef().getName());
+ AtlasType attrType = typeRegistry.getType(attributeInfo.getAttributeDef().getTypeName());
+ switch (attrType.getTypeCategory()) {
+ case ENTITY:
+ AtlasEdge edge = graphHelper.getEdgeForLabel(vertex, edgeLabel);
+ if (edge != null && AtlasGraphUtilsV1.getState(edge) == AtlasEntity.Status.ACTIVE) {
+ AtlasVertex compositeVertex = edge.getInVertex();
+ vertices.push(compositeVertex);
+ }
+ break;
+ case ARRAY:
+ AtlasArrayType arrType = (AtlasArrayType) attrType;
+ if (arrType.getElementType().getTypeCategory() != TypeCategory.ENTITY) {
+ continue;
+ }
+ Iterator<AtlasEdge> edges = graphHelper.getOutGoingEdgesByLabel(vertex, edgeLabel);
+ if (edges != null) {
+ while (edges.hasNext()) {
+ edge = edges.next();
+ if (edge != null && AtlasGraphUtilsV1.getState(edge) == AtlasEntity.Status.ACTIVE) {
+ AtlasVertex compositeVertex = edge.getInVertex();
+ vertices.push(compositeVertex);
+ }
+ }
+ }
+ break;
+ case MAP:
+ AtlasMapType mapType = (AtlasMapType) attrType;
+ TypeCategory valueTypeCategory = mapType.getValueType().getTypeCategory();
+ if (valueTypeCategory != TypeCategory.ENTITY) {
+ continue;
+ }
+ String propertyName = AtlasGraphUtilsV1.getQualifiedAttributePropertyKey(entityType, attributeInfo.getAttributeDef().getName());
+ List<String> keys = vertex.getProperty(propertyName, List.class);
+ if (keys != null) {
+ for (String key : keys) {
+ String mapEdgeLabel = GraphHelper.getQualifiedNameForMapKey(edgeLabel, key);
+ edge = graphHelper.getEdgeForLabel(vertex, mapEdgeLabel);
+ if (edge != null && AtlasGraphUtilsV1.getState(edge) == AtlasEntity.Status.ACTIVE) {
+ AtlasVertex compositeVertex = edge.getInVertex();
+ vertices.push(compositeVertex);
+ }
+ }
+ }
+ break;
+ default:
+ }
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Force delete is used to remove struct/trait in case of entity updates
+ * @param edge
+ * @param typeCategory
+ * @param isComposite
+ * @param forceDeleteStructTrait
+ * @return returns true if the edge reference is hard deleted
+ * @throws AtlasException
+ */
+ public boolean deleteEdgeReference(AtlasEdge edge, TypeCategory typeCategory, boolean isComposite,
+ boolean forceDeleteStructTrait) throws AtlasBaseException {
+ LOG.debug("Deleting {}", string(edge));
+ boolean forceDelete =
+ (AtlasGraphUtilsV1.isReference(typeCategory))
+ ? forceDeleteStructTrait : false;
+ if (AtlasGraphUtilsV1.isReference(typeCategory) && isComposite) {
+ //If the vertex is of type struct/trait, delete the edge and then the reference vertex as the vertex is not shared by any other entities.
+ //If the vertex is of type class, and its composite attribute, this reference vertex' lifecycle is controlled
+ //through this delete, hence delete the edge and the reference vertex.
+ AtlasVertex vertexForDelete = edge.getInVertex();
+
+ //If deleting the edge and then the in vertex, reverse attribute shouldn't be updated
+ deleteEdge(edge, false, forceDelete);
+ deleteTypeVertex(vertexForDelete, typeCategory, forceDelete);
+ } else {
+ //If the vertex is of type class, and its not a composite attributes, the reference AtlasVertex' lifecycle is not controlled
+ //through this delete. Hence just remove the reference edge. Leave the reference AtlasVertex as is
+
+ //If deleting just the edge, reverse attribute should be updated for any references
+ //For example, for the department type system, if the person's manager edge is deleted, subordinates of manager should be updated
+ deleteEdge(edge, true, false);
+ }
+ return !softDelete || forceDelete;
+ }
+
+ protected void deleteEdge(AtlasEdge edge, boolean updateReverseAttribute, boolean force) throws AtlasBaseException {
+ //update reverse attribute
+ if (updateReverseAttribute) {
+ AtlasEdgeLabel atlasEdgeLabel = new AtlasEdgeLabel(edge.getLabel());
+
+ AtlasType parentType = typeRegistry.getType(atlasEdgeLabel.getTypeName());
+
+ if (parentType instanceof AtlasStructType) {
+ AtlasStructType parentStructType = (AtlasStructType) parentType;
+ if (parentStructType.isForeignKeyAttribute(atlasEdgeLabel.getAttributeName())) {
+ deleteEdgeBetweenVertices(edge.getInVertex(), edge.getOutVertex(), atlasEdgeLabel.getAttributeName());
+ }
+ }
+ }
+
+ deleteEdge(edge, force);
+
+ }
+
+
+ protected void deleteTypeVertex(AtlasVertex instanceVertex, TypeCategory typeCategory, boolean force) throws AtlasBaseException {
+ switch (typeCategory) {
+ case STRUCT:
+ case CLASSIFICATION:
+ deleteTypeVertex(instanceVertex, force);
+ break;
+
+ case ENTITY:
+ deleteEntities(Collections.singletonList(instanceVertex));
+ break;
+
+ default:
+ throw new IllegalStateException("Type category " + typeCategory + " not handled");
+ }
+ }
+
+ /**
+ * Deleting any type vertex. Goes over the complex attributes and removes the references
+ * @param instanceVertex
+ * @throws AtlasException
+ */
+ protected void deleteTypeVertex(AtlasVertex instanceVertex, boolean force) throws AtlasBaseException {
+ LOG.debug("Deleting {}", string(instanceVertex));
+ String typeName = GraphHelper.getTypeName(instanceVertex);
+
+
+ AtlasType parentType = typeRegistry.getType(typeName);
+
+ if (parentType instanceof AtlasStructType) {
+
+ AtlasStructType entityType = (AtlasStructType) parentType;
+ for (AtlasStructType.AtlasAttribute attributeInfo : getAttributes(entityType)) {
+ LOG.debug("Deleting attribute {} for {}", attributeInfo.getAttributeDef().getName(), string(instanceVertex));
+
+ AtlasType attrType = typeRegistry.getType(attributeInfo.getAttributeType().getTypeName());
+
+ String edgeLabel = AtlasGraphUtilsV1.getAttributeEdgeLabel(entityType, attributeInfo.getAttributeDef().getName());
+
+ switch (attrType.getTypeCategory()) {
+ case ENTITY:
+ //If its class attribute, delete the reference
+ deleteEdgeReference(instanceVertex, edgeLabel, TypeCategory.ENTITY, entityType.isMappedFromRefAttribute(attributeInfo.getAttributeDef().getName()));
+ break;
+
+ case STRUCT:
+ //If its struct attribute, delete the reference
+ deleteEdgeReference(instanceVertex, edgeLabel, TypeCategory.STRUCT, false);
+ break;
+
+ case ARRAY:
+ //For array attribute, if the element is struct/class, delete all the references
+ AtlasArrayType arrType = (AtlasArrayType) attrType;
+ AtlasType elemType = arrType.getElementType();
+ if (AtlasGraphUtilsV1.isReference(elemType.getTypeCategory())) {
+ Iterator<AtlasEdge> edges = graphHelper.getOutGoingEdgesByLabel(instanceVertex, edgeLabel);
+ if (edges != null) {
+ while (edges.hasNext()) {
+ AtlasEdge edge = edges.next();
+ deleteEdgeReference(edge, elemType.getTypeCategory(), entityType.isMappedFromRefAttribute(attributeInfo.getAttributeDef().getName()), false);
+ }
+ }
+ }
+ break;
+
+ case MAP:
+ //For map attribute, if the value type is struct/class, delete all the references
+ AtlasMapType mapType = (AtlasMapType) attrType;
+ AtlasType keyType = mapType.getKeyType();
+ TypeCategory valueTypeCategory = mapType.getValueType().getTypeCategory();
+ String propertyName = AtlasGraphUtilsV1.getQualifiedAttributePropertyKey(entityType, attributeInfo.getAttributeDef().getName());
+
+ if (AtlasGraphUtilsV1.isReference(valueTypeCategory)) {
+ List<Object> keys = ArrayVertexMapper.getArrayElementsProperty(keyType, instanceVertex, propertyName);
+ if (keys != null) {
+ for (Object key : keys) {
+ String mapEdgeLabel = GraphHelper.getQualifiedNameForMapKey(edgeLabel, (String) key);
+ deleteEdgeReference(instanceVertex, mapEdgeLabel, valueTypeCategory, entityType.isMappedFromRefAttribute(attributeInfo.getAttributeDef().getName()));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ deleteVertex(instanceVertex, force);
+ }
+
+ public void deleteEdgeReference(AtlasVertex outVertex, String edgeLabel, TypeCategory typeCategory,
+ boolean isComposite) throws AtlasBaseException {
+ AtlasEdge edge = graphHelper.getEdgeForLabel(outVertex, edgeLabel);
+ if (edge != null) {
+ deleteEdgeReference(edge, typeCategory, isComposite, false);
+ }
+ }
+
+ /**
+ * Delete all traits from the specified vertex.
+ * @param instanceVertex
+ * @throws AtlasException
+ */
+ private void deleteAllTraits(AtlasVertex instanceVertex) throws AtlasBaseException {
+ List<String> traitNames = GraphHelper.getTraitNames(instanceVertex);
+ LOG.debug("Deleting traits {} for {}", traitNames, string(instanceVertex));
+ String typeName = GraphHelper.getTypeName(instanceVertex);
+
+ for (String traitNameToBeDeleted : traitNames) {
+ String relationshipLabel = GraphHelper.getTraitLabel(typeName, traitNameToBeDeleted);
+ deleteEdgeReference(instanceVertex, relationshipLabel, TypeCategory.CLASSIFICATION, false);
+ }
+ }
+
+ protected AtlasStructDef.AtlasAttributeDef getAttributeForEdge(String edgeLabel) throws AtlasBaseException {
+ AtlasEdgeLabel atlasEdgeLabel = new AtlasEdgeLabel(edgeLabel);
+
+ AtlasType parentType = typeRegistry.getType(atlasEdgeLabel.getTypeName());
+ AtlasStructType parentStructType = (AtlasStructType) parentType;
+
+ return parentStructType.getAttributeDef(atlasEdgeLabel.getAttributeName());
+ }
+
+ protected abstract void _deleteVertex(AtlasVertex instanceVertex, boolean force);
+
+ protected abstract void deleteEdge(AtlasEdge edge, boolean force) throws AtlasBaseException;
+
+ /**
+ * 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 AtlasBaseException {
+ LOG.debug("Removing edge from {} to {} with attribute name {}", string(outVertex), string(inVertex),
+ attributeName);
+ String typeName = GraphHelper.getTypeName(outVertex);
+ String outId = GraphHelper.getGuid(outVertex);
+ AtlasEntity.Status state = AtlasGraphUtilsV1.getState(outVertex);
+ if ((outId != null && RequestContextV1.get().isDeletedEntity(outId)) || state == AtlasEntity.Status.DELETED) {
+ //If the reference vertex is marked for deletion, skip updating the reference
+ return;
+ }
+
+ AtlasStructType parentType = (AtlasStructType) typeRegistry.getType(typeName);
+ String propertyName = AtlasGraphUtilsV1.getQualifiedAttributePropertyKey(parentType, attributeName);
+ String edgeLabel = EDGE_LABEL_PREFIX + propertyName;
+ AtlasEdge edge = null;
+
+ AtlasStructDef.AtlasAttributeDef attrDef = parentType.getAttributeDef(attributeName);
+ AtlasType attrType = typeRegistry.getType(attrDef.getTypeName());
+
+ switch (attrType.getTypeCategory()) {
+ case ENTITY:
+ //If its class attribute, its the only edge between two vertices
+ if (attrDef.getIsOptional()) {
+ edge = graphHelper.getEdgeForLabel(outVertex, edgeLabel);
+ if (shouldUpdateReverseAttribute) {
+ GraphHelper.setProperty(outVertex, propertyName, null);
+ }
+ } else {
+ // Cannot unset a required attribute.
+ throw new AtlasBaseException("Cannot unset required attribute " + propertyName +
+ " 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) {
+ elements = new ArrayList<>(elements); //Make a copy, else list.remove reflects on titan.getProperty()
+ 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 (!attrDef.getIsOptional()
+ && elements.size() <= attrDef.getValuesMinCount()) {
+ // Deleting this edge would violate the attribute's lower bound.
+ throw new AtlasBaseException(
+ "Cannot remove array element from required attribute " +
+ propertyName + " on "
+ + GraphHelper.getVertexDetails(outVertex) + " " + GraphHelper.getEdgeDetails(elementEdge));
+ }
+
+ if (shouldUpdateReverseAttribute) {
+ //if composite attribute, remove the reference as well. else, just remove the edge
+ //for example, when table is deleted, process still references the table
+ //but when column is deleted, table will not reference the deleted column
+ LOG.debug("Removing edge {} from the array attribute {}", string(elementEdge),
+ attributeName);
+ elements.remove(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) {
+ keys = new ArrayList<>(keys); //Make a copy, else list.remove reflects on titan.getProperty()
+ 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 (attrDef.getIsOptional() || keys.size() > attrDef.getValuesMinCount()) {
+ edge = mapEdge;
+ } else {
+ // Deleting this entry would violate the attribute's lower bound.
+ throw new AtlasBaseException(
+ "Cannot remove map entry " + keyPropertyName + " from required attribute " +
+ propertyName + " on " + GraphHelper.getVertexDetails(outVertex) + " " + GraphHelper.getEdgeDetails(mapEdge));
+ }
+
+ if (shouldUpdateReverseAttribute) {
+ //remove this key
+ 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 CLASSIFICATION:
+ 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);
+ RequestContextV1 requestContext = RequestContextV1.get();
+ GraphHelper.setProperty(outVertex, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY,
+ requestContext.getRequestTime());
+ GraphHelper.setProperty(outVertex, Constants.MODIFIED_BY_KEY, requestContext.getUser());
+ requestContext.recordEntityUpdate(outId);
+ }
+ }
+
+ protected void deleteVertex(AtlasVertex instanceVertex, boolean force) throws AtlasBaseException {
+ //Update external references(incoming edges) to this vertex
+ LOG.debug("Setting the external references to {} to null(removing edges)", string(instanceVertex));
+
+ for (AtlasEdge edge : (Iterable<AtlasEdge>) instanceVertex.getEdges(AtlasEdgeDirection.IN)) {
+ AtlasEntity.Status edgeState = AtlasGraphUtilsV1.getState(edge);
+ if (edgeState == AtlasEntity.Status.ACTIVE) {
+ //Delete only the active edge references
+ AtlasStructDef.AtlasAttributeDef attribute = getAttributeForEdge(edge.getLabel());
+ //TODO use delete edge instead??
+ deleteEdgeBetweenVertices(edge.getOutVertex(), edge.getInVertex(), attribute.getName());
+ }
+ }
+ _deleteVertex(instanceVertex, force);
+ }
+
+ private Collection<AtlasStructType.AtlasAttribute> getAttributes(AtlasStructType structType) {
+ Collection<AtlasStructType.AtlasAttribute> ret = null;
+
+ if (structType.getTypeCategory() == TypeCategory.STRUCT) {
+ ret = structType.getAllAttributes().values();
+ } else if (structType.getTypeCategory() == TypeCategory.CLASSIFICATION) {
+ ret = ((AtlasClassificationType)structType).getAllAttributes().values();
+ } else if (structType.getTypeCategory() == TypeCategory.ENTITY) {
+ ret = ((AtlasEntityType)structType).getAllAttributes().values();
+ } else {
+ ret = Collections.emptyList();
+ }
+
+ return ret;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java
new file mode 100644
index 0000000..174e490
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityGraphMapper.java
@@ -0,0 +1,185 @@
+/**
+ * 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.v1;
+
+
+import com.google.inject.Inject;
+import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.RequestContextV1;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasEntityHeader;
+import org.apache.atlas.model.instance.AtlasObjectId;
+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.AtlasStructDef;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.repository.RepositoryException;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasStructType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.UUID;
+
+public class EntityGraphMapper implements InstanceGraphMapper<AtlasEdge> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(EntityGraphMapper.class);
+
+ protected final GraphHelper graphHelper = GraphHelper.getInstance();
+
+ protected EntityMutationContext context;
+
+ protected final StructVertexMapper structVertexMapper;
+
+ @Inject
+ public EntityGraphMapper(ArrayVertexMapper arrayVertexMapper, MapVertexMapper mapVertexMapper) {
+ this.structVertexMapper = new StructVertexMapper(arrayVertexMapper, mapVertexMapper);
+ arrayVertexMapper.init(structVertexMapper);
+ mapVertexMapper.init(structVertexMapper);
+ }
+
+ public AtlasVertex createVertexTemplate(final AtlasStruct instance, final AtlasStructType structType) {
+ AtlasVertex vertex = structVertexMapper.createVertexTemplate(instance, structType);
+
+ AtlasEntityType entityType = (AtlasEntityType) structType;
+ AtlasEntity entity = (AtlasEntity) instance;
+
+ // add super types
+ for (String superTypeName : entityType.getAllSuperTypes()) {
+ AtlasGraphUtilsV1.addProperty(vertex, Constants.SUPER_TYPES_PROPERTY_KEY, superTypeName);
+ }
+
+ final String guid = UUID.randomUUID().toString();
+
+ // add identity
+ AtlasGraphUtilsV1.setProperty(vertex, Constants.GUID_PROPERTY_KEY, guid);
+
+ // add version information
+ AtlasGraphUtilsV1.setProperty(vertex, Constants.VERSION_PROPERTY_KEY, Integer.valueOf(entity.getVersion().intValue()));
+
+ return vertex;
+ }
+
+
+ @Override
+ public AtlasEdge toGraph(GraphMutationContext ctx) throws AtlasBaseException {
+ AtlasEdge result = null;
+
+ String guid = getId(ctx.getValue());
+
+ AtlasVertex entityVertex = context.getDiscoveryContext().getResolvedReference(guid);
+ String edgeLabel = AtlasGraphUtilsV1.getAttributeEdgeLabel(ctx.getParentType(), ctx.getAttributeDef().getName());
+ if ( ctx.getCurrentEdge().isPresent() ) {
+ updateEdge(ctx.getAttributeDef(), ctx.getValue(), ctx.getCurrentEdge().get(), entityVertex);
+ result = ctx.getCurrentEdge().get();
+ } else {
+ try {
+ result = graphHelper.getOrCreateEdge(ctx.getReferringVertex(), entityVertex, edgeLabel);
+ } catch (RepositoryException e) {
+ throw new AtlasBaseException(AtlasErrorCode.INTERNAL_ERROR, e);
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public void cleanUp() throws AtlasBaseException {
+ }
+
+ private AtlasEdge updateEdge(AtlasStructDef.AtlasAttributeDef attributeDef, Object value, AtlasEdge currentEdge, final AtlasVertex entityVertex) throws AtlasBaseException {
+
+ LOG.debug("Updating entity reference {} for reference attribute {}", attributeDef.getName());
+ // Update edge if it exists
+
+ AtlasVertex currentVertex = currentEdge.getOutVertex();
+ String currentEntityId = AtlasGraphUtilsV1.getIdFromVertex(currentVertex);
+ String newEntityId = getId(value);
+ AtlasEdge newEdge = currentEdge;
+ if (!currentEntityId.equals(newEntityId)) {
+ // add an edge to the class vertex from the instance
+ if (entityVertex != null) {
+ try {
+ newEdge = graphHelper.getOrCreateEdge(currentEdge.getInVertex(), entityVertex, currentEdge.getLabel());
+ } catch (RepositoryException e) {
+ throw new AtlasBaseException(AtlasErrorCode.INTERNAL_ERROR, e);
+ }
+
+ }
+ }
+ return newEdge;
+ }
+
+ public EntityMutationResponse mapAttributes(EntityMutationContext ctx) throws AtlasBaseException {
+
+ this.context = ctx;
+ structVertexMapper.init(this);
+
+ EntityMutationResponse resp = new EntityMutationResponse();
+ //Map attributes
+ if (ctx.getCreatedEntities() != null) {
+ for (AtlasEntity createdEntity : ctx.getCreatedEntities()) {
+ AtlasVertex vertex = ctx.getVertex(createdEntity);
+ structVertexMapper.mapAttributestoVertex((AtlasStructType) ctx.getType(createdEntity), createdEntity, vertex);
+ resp.addEntity(EntityMutations.EntityOperation.CREATE, constructHeader(createdEntity, vertex));
+ }
+ }
+
+ if (ctx.getUpdatedEntities() != null) {
+ for (AtlasEntity updated : ctx.getUpdatedEntities()) {
+ AtlasVertex vertex = ctx.getVertex(updated);
+ structVertexMapper.mapAttributestoVertex((AtlasStructType) ctx.getType(updated), updated, vertex);
+
+ resp.addEntity(EntityMutations.EntityOperation.UPDATE, constructHeader(updated, vertex));
+ }
+ }
+
+ return resp;
+ }
+
+
+ public String getId(Object value) throws AtlasBaseException {
+ if ( value != null) {
+ if ( value instanceof AtlasObjectId) {
+ return ((AtlasObjectId) value).getGuid();
+ } else if (value instanceof AtlasEntity) {
+ return ((AtlasEntity) value).getGuid();
+ }
+ }
+ throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, (String) value);
+ }
+
+ private AtlasEntityHeader constructHeader(AtlasEntity entity, AtlasVertex vertex) {
+ //TODO - enhance to return only selective attributes
+ return new AtlasEntityHeader(entity.getTypeName(), AtlasGraphUtilsV1.getIdFromVertex(vertex), entity.getAttributes());
+ }
+
+ public EntityMutationContext getContext() {
+ return context;
+ }
+
+ public AtlasEntityType getInstanceType(Object val) throws AtlasBaseException {
+ String guid = getId(val);
+ return (AtlasEntityType) getContext().getType(guid);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityMutationContext.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityMutationContext.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityMutationContext.java
new file mode 100644
index 0000000..f942a91
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/EntityMutationContext.java
@@ -0,0 +1,124 @@
+/**
+ * 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.repository.store.graph.v1;
+
+import org.apache.atlas.model.instance.AtlasEntity;
+
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.repository.store.graph.EntityGraphDiscoveryContext;
+import org.apache.atlas.type.AtlasType;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class EntityMutationContext {
+
+ private List<AtlasEntity> entitiesCreated = new ArrayList<>();
+ private List<AtlasEntity> entitiesUpdated = new ArrayList<>();
+
+ private EntityGraphDiscoveryContext context;
+ private Map<String, AtlasType> entityVsType = new HashMap<>();
+ private Map<String, AtlasVertex> entityVsVertex = new HashMap<>();
+
+ public EntityMutationContext(final EntityGraphDiscoveryContext context) {
+ this.context = context;
+ }
+
+ public void addCreated(AtlasEntity entity, AtlasType type, AtlasVertex atlasVertex) {
+ entitiesCreated.add(entity);
+ entityVsVertex.put(entity.getGuid(), atlasVertex);
+ entityVsType.put(entity.getGuid(), type);
+ }
+
+ public void addUpdated(AtlasEntity entity, AtlasType type, AtlasVertex atlasVertex) {
+ entitiesUpdated.add(entity);
+ entityVsVertex.put(entity.getGuid(), atlasVertex);
+ entityVsType.put(entity.getGuid(), type);
+ }
+
+ public Collection<AtlasEntity> getCreatedEntities() {
+ return entitiesCreated;
+ }
+
+ public Collection<AtlasEntity> getUpdatedEntities() {
+ return entitiesUpdated;
+ }
+
+ public AtlasType getType(AtlasEntity entity) {
+ return entityVsType.get(entity.getGuid());
+ }
+
+ public AtlasType getType(String entityId) {
+ return entityVsType.get(entityId);
+ }
+
+ public AtlasVertex getVertex(AtlasEntity entity) {
+ return entityVsVertex.get(entity.getGuid());
+ }
+
+ public AtlasVertex getVertex(String entityId) {
+ return entityVsVertex.get(entityId);
+ }
+
+ public EntityGraphDiscoveryContext getDiscoveryContext() {
+ return this.context;
+ }
+
+ //TODO - equals/hashCode/toString
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final EntityMutationContext that = (EntityMutationContext) o;
+
+ if (entitiesCreated != null ? !entitiesCreated.equals(that.entitiesCreated) : that.entitiesCreated != null)
+ return false;
+ if (entitiesUpdated != null ? !entitiesUpdated.equals(that.entitiesUpdated) : that.entitiesUpdated != null)
+ return false;
+ if (context != null ? !context.equals(that.context) : that.context != null) return false;
+ if (entityVsType != null ? !entityVsType.equals(that.entityVsType) : that.entityVsType != null) return false;
+ return !(entityVsVertex != null ? !entityVsVertex.equals(that.entityVsVertex) : that.entityVsVertex != null);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = entitiesCreated != null ? entitiesCreated.hashCode() : 0;
+ result = 31 * result + (entitiesUpdated != null ? entitiesUpdated.hashCode() : 0);
+ result = 31 * result + (context != null ? context.hashCode() : 0);
+ result = 31 * result + (entityVsType != null ? entityVsType.hashCode() : 0);
+ result = 31 * result + (entityVsVertex != null ? entityVsVertex.hashCode() : 0);
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "EntityMutationContext{" +
+ "entitiesCreated=" + entitiesCreated +
+ ", entitiesUpdated=" + entitiesUpdated +
+ ", context=" + context +
+ ", entityVsType=" + entityVsType +
+ ", entityVsVertex=" + entityVsVertex +
+ '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/GraphMutationContext.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/GraphMutationContext.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/GraphMutationContext.java
new file mode 100644
index 0000000..d5ba7e1
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/GraphMutationContext.java
@@ -0,0 +1,195 @@
+/**
+ * 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.v1;
+
+
+import com.google.common.base.Optional;
+import org.apache.atlas.model.typedef.AtlasStructDef;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.atlas.type.AtlasType;
+
+import java.util.Objects;
+
+public class GraphMutationContext {
+
+
+ /**
+ * Atlas Attribute
+ */
+
+ private AtlasStructType.AtlasAttribute attribute;
+
+ /**
+ * Overriding type for which elements are being mapped
+ */
+ private AtlasType currentElementType;
+
+ /**
+ * Current attribute value/entity/Struct instance
+ */
+ private Object value;
+
+ /**
+ *
+ * The vertex which corresponds to the entity/struct for which we are mapping a complex attributes like struct, traits
+ */
+ AtlasVertex referringVertex;
+
+ /**
+ * the vertex property that we are updating
+ */
+
+ String vertexPropertyKey;
+
+ /**
+ * The current edge(in case of updates) from the parent entity/struct to the complex attribute like struct, trait
+ */
+ Optional<AtlasEdge> existingEdge;
+
+
+ private GraphMutationContext(final Builder builder) {
+ this.attribute = builder.attribute;
+ this.currentElementType = builder.elementType;
+ this.existingEdge = builder.currentEdge;
+ this.value = builder.currentValue;
+ this.referringVertex = builder.referringVertex;
+ this.vertexPropertyKey = builder.vertexPropertyKey;
+ }
+
+ public String getVertexPropertyKey() {
+ return vertexPropertyKey;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(attribute, value, referringVertex, vertexPropertyKey, existingEdge);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ } else if (obj == this) {
+ return true;
+ } else if (obj.getClass() != getClass()) {
+ return false;
+ } else {
+ GraphMutationContext rhs = (GraphMutationContext) obj;
+ return Objects.equals(attribute, rhs.getAttribute())
+ && Objects.equals(value, rhs.getValue())
+ && Objects.equals(referringVertex, rhs.getReferringVertex())
+ && Objects.equals(vertexPropertyKey, rhs.getReferringVertex())
+ && Objects.equals(existingEdge, rhs.getCurrentEdge());
+ }
+ }
+
+
+ public static final class Builder {
+
+ private final AtlasStructType.AtlasAttribute attribute;
+
+ private final AtlasType elementType;
+
+ private final Object currentValue;
+
+ private AtlasVertex referringVertex;
+
+ private Optional<AtlasEdge> currentEdge = Optional.absent();
+
+ private String vertexPropertyKey;
+
+
+ public Builder(AtlasStructType.AtlasAttribute attribute, AtlasType currentElementType, Object currentValue) {
+ this.attribute = attribute;
+ this.elementType = currentElementType;
+ this.currentValue = currentValue;
+ }
+
+ public Builder(AtlasStructType.AtlasAttribute attribute, Object currentValue) {
+ this.attribute = attribute;
+ this.elementType = null;
+ this.currentValue = currentValue;
+ }
+
+ Builder referringVertex(AtlasVertex referringVertex) {
+ this.referringVertex = referringVertex;
+ return this;
+ }
+
+ Builder edge(AtlasEdge edge) {
+ this.currentEdge = Optional.of(edge);
+ return this;
+ }
+
+ Builder edge(Optional<AtlasEdge> edge) {
+ this.currentEdge = edge;
+ return this;
+ }
+
+ Builder vertexProperty(String propertyKey) {
+ this.vertexPropertyKey = propertyKey;
+ return this;
+ }
+
+ GraphMutationContext build() {
+ return new GraphMutationContext(this);
+ }
+ }
+
+ public AtlasStructType getParentType() {
+ return attribute.getStructType();
+ }
+
+ public AtlasStructDef getStructDef() {
+ return attribute.getStructDef();
+ }
+
+ public AtlasStructDef.AtlasAttributeDef getAttributeDef() {
+ return attribute.getAttributeDef();
+ }
+
+ public AtlasType getAttrType() {
+ return currentElementType == null ? attribute.getAttributeType() : currentElementType;
+ }
+
+ public AtlasType getCurrentElementType() {
+ return currentElementType;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public AtlasVertex getReferringVertex() {
+ return referringVertex;
+ }
+
+ public Optional<AtlasEdge> getCurrentEdge() {
+ return existingEdge;
+ }
+
+ public void setElementType(final AtlasType attrType) {
+ this.currentElementType = attrType;
+ }
+
+ public AtlasStructType.AtlasAttribute getAttribute() {
+ return attribute;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/HardDeleteHandlerV1.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/HardDeleteHandlerV1.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/HardDeleteHandlerV1.java
new file mode 100644
index 0000000..fe0db39
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/HardDeleteHandlerV1.java
@@ -0,0 +1,43 @@
+/**
+ * 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.repository.store.graph.v1;
+
+import com.google.inject.Inject;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.type.AtlasTypeRegistry;
+
+public class HardDeleteHandlerV1 extends DeleteHandlerV1 {
+
+ @Inject
+ public HardDeleteHandlerV1(AtlasTypeRegistry typeRegistry) {
+ super(typeRegistry, false, true);
+ }
+
+ @Override
+ protected void _deleteVertex(AtlasVertex instanceVertex, boolean force) {
+ graphHelper.removeVertex(instanceVertex);
+ }
+
+ @Override
+ protected void deleteEdge(AtlasEdge edge, boolean force) throws AtlasBaseException {
+ graphHelper.removeEdge(edge);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/IDBasedEntityResolver.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/IDBasedEntityResolver.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/IDBasedEntityResolver.java
new file mode 100644
index 0000000..488f141
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/IDBasedEntityResolver.java
@@ -0,0 +1,118 @@
+/**
+ * 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.v1;
+
+import com.google.common.base.Optional;
+import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.repository.store.graph.EntityGraphDiscoveryContext;
+import org.apache.atlas.repository.store.graph.EntityResolver;
+import org.apache.atlas.typesystem.exception.EntityNotFoundException;
+import org.apache.atlas.typesystem.persistence.Id;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class IDBasedEntityResolver implements EntityResolver {
+
+ private Map<String, AtlasEntity> idToEntityMap = new HashMap<>();
+
+ private final GraphHelper graphHelper = GraphHelper.getInstance();
+
+ private EntityGraphDiscoveryContext context;
+
+ @Override
+ public void init(EntityGraphDiscoveryContext context) throws AtlasBaseException {
+ this.context = context;
+ for (AtlasEntity entity : context.getRootEntities()) {
+ idToEntityMap.put(entity.getGuid(), entity);
+ }
+ }
+
+ public EntityGraphDiscoveryContext resolveEntityReferences() throws AtlasBaseException {
+
+ if ( context == null) {
+ throw new AtlasBaseException(AtlasErrorCode.INTERNAL_ERROR, "Entity resolver not initialized");
+ }
+
+ List<AtlasObjectId> resolvedReferences = new ArrayList<>();
+
+ for (AtlasObjectId typeIdPair : context.getUnresolvedIdReferences()) {
+ if ( AtlasEntity.isAssigned(typeIdPair.getGuid())) {
+ //validate in graph repo that given guid, typename exists
+ Optional<AtlasVertex> vertex = resolveGuid(typeIdPair);
+
+ if ( vertex.isPresent() ) {
+ context.addRepositoryResolvedReference(typeIdPair, vertex.get());
+ resolvedReferences.add(typeIdPair);
+ }
+ } else {
+ //check if root references have this temporary id
+ if (!idToEntityMap.containsKey(typeIdPair.getGuid()) ) {
+ throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, "Could not find an entity with the specified id " + typeIdPair + " in the request");
+ }
+ }
+ }
+
+ context.removeUnResolvedIdReferences(resolvedReferences);
+
+ //Resolve root references
+ for (AtlasEntity entity : context.getRootEntities()) {
+ if ( !context.isResolved(entity.getGuid()) && AtlasEntity.isAssigned(entity.getGuid())) {
+ AtlasObjectId typeIdPair = new AtlasObjectId(entity.getTypeName(), entity.getGuid());
+ Optional<AtlasVertex> vertex = resolveGuid(typeIdPair);
+ if (vertex.isPresent()) {
+ context.addRepositoryResolvedReference(typeIdPair, vertex.get());
+ context.removeUnResolvedIdReference(typeIdPair);
+ }
+ }
+ }
+ return context;
+ }
+
+ private Optional<AtlasVertex> resolveGuid(AtlasObjectId typeIdPair) throws AtlasBaseException {
+ //validate in graph repo that given guid, typename exists
+ AtlasVertex vertex = null;
+ try {
+ vertex = graphHelper.findVertex(Constants.GUID_PROPERTY_KEY, typeIdPair.getGuid(),
+ Constants.TYPE_NAME_PROPERTY_KEY, typeIdPair.getTypeName(),
+ Constants.STATE_PROPERTY_KEY, Id.EntityState.ACTIVE.name());
+ } catch (EntityNotFoundException e) {
+ //Ignore
+ }
+ if ( vertex != null ) {
+ return Optional.of(vertex);
+ } else {
+ throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_NOT_FOUND, "Could not find an entity with the specified guid " + typeIdPair.getGuid() + " in Atlas respository");
+ }
+ }
+
+ @Override
+ public void cleanUp() throws AtlasBaseException {
+ idToEntityMap.clear();
+ this.context = null;
+ }
+
+}
[3/3] incubator-atlas git commit: ATLAS-1467: instance
create/full-Update implementation
Posted by ma...@apache.org.
ATLAS-1467: instance create/full-Update implementation
Signed-off-by: Madhan Neethiraj <ma...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/incubator-atlas/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-atlas/commit/2f1cb57a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-atlas/tree/2f1cb57a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-atlas/diff/2f1cb57a
Branch: refs/heads/master
Commit: 2f1cb57a757e15c97a2b1437e282be48c553d4e8
Parents: 511c886
Author: Suma Shivaprasad <su...@gmail.com>
Authored: Thu Jan 19 17:47:00 2017 -0800
Committer: Madhan Neethiraj <ma...@apache.org>
Committed: Thu Jan 19 17:51:04 2017 -0800
----------------------------------------------------------------------
.../java/org/apache/atlas/AtlasErrorCode.java | 7 +-
.../atlas/model/instance/AtlasEntity.java | 14 +-
.../atlas/model/instance/AtlasEntityHeader.java | 11 +-
.../atlas/model/instance/EntityMutations.java | 3 +-
.../atlas/model/typedef/AtlasStructDef.java | 5 +-
.../atlas/type/AtlasClassificationType.java | 63 +--
.../org/apache/atlas/type/AtlasEntityType.java | 114 ++--
.../org/apache/atlas/type/AtlasStructType.java | 139 ++++-
.../test/java/org/apache/atlas/TestUtilsV2.java | 74 ++-
.../atlas/type/TestAtlasTypeRegistry.java | 10 +-
release-log.txt | 4 +
.../apache/atlas/RepositoryMetadataModule.java | 26 +-
.../atlas/discovery/EntityDiscoveryService.java | 2 +-
.../atlas/discovery/EntityLineageService.java | 2 +-
.../atlas/repository/graph/GraphHelper.java | 2 +-
.../store/graph/AtlasEntityStore.java | 8 +-
.../store/graph/EntityGraphDiscovery.java | 39 ++
.../graph/EntityGraphDiscoveryContext.java | 170 ++++++
.../repository/store/graph/EntityResolver.java | 30 ++
.../store/graph/v1/ArrayVertexMapper.java | 179 ++++++
.../graph/v1/AtlasEntityGraphDiscoveryV1.java | 244 +++++++++
.../store/graph/v1/AtlasEntityStoreV1.java | 139 ++++-
.../store/graph/v1/AtlasEnumDefStoreV1.java | 12 +-
.../store/graph/v1/AtlasGraphUtilsV1.java | 82 ++-
.../store/graph/v1/AtlasStructDefStoreV1.java | 18 +-
.../store/graph/v1/DeleteHandlerV1.java | 539 +++++++++++++++++++
.../store/graph/v1/EntityGraphMapper.java | 185 +++++++
.../store/graph/v1/EntityMutationContext.java | 124 +++++
.../store/graph/v1/GraphMutationContext.java | 195 +++++++
.../store/graph/v1/HardDeleteHandlerV1.java | 43 ++
.../store/graph/v1/IDBasedEntityResolver.java | 118 ++++
.../store/graph/v1/InstanceGraphMapper.java | 39 ++
.../store/graph/v1/MapVertexMapper.java | 200 +++++++
.../store/graph/v1/SoftDeleteHandlerV1.java | 72 +++
.../store/graph/v1/StructVertexMapper.java | 203 +++++++
.../graph/v1/UniqAttrBasedEntityResolver.java | 136 +++++
.../util/AtlasRepositoryConfiguration.java | 12 +
.../atlas/lineage/EntityLineageServiceTest.java | 12 +-
.../store/graph/AtlasTypeDefGraphStoreTest.java | 3 +-
.../store/graph/v1/AtlasEntityStoreV1Test.java | 236 ++++++++
.../java/org/apache/atlas/RequestContextV1.java | 122 +++++
.../adapters/AtlasEntityFormatConverter.java | 4 +-
.../web/adapters/AtlasInstanceRestAdapters.java | 4 +-
.../adapters/AtlasStructFormatConverter.java | 32 +-
.../org/apache/atlas/web/rest/EntitiesREST.java | 2 +-
.../org/apache/atlas/web/util/LineageUtils.java | 2 +-
.../atlas/web/adapters/TestEntitiesREST.java | 4 +-
.../atlas/web/adapters/TestEntityREST.java | 4 +-
.../atlas/web/resources/BaseResourceIT.java | 6 +-
.../EntityDiscoveryJerseyResourceIT.java | 4 +-
.../web/resources/EntityV2JerseyResourceIT.java | 22 +-
51 files changed, 3450 insertions(+), 270 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
index a6438ed..f0aae0c 100644
--- a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
+++ b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
@@ -62,6 +62,7 @@ public enum AtlasErrorCode {
INSTANCE_LINEAGE_INVALID_PARAMS(404, "ATLAS4046E", "Invalid lineage query parameters passed {0}: {1}"),
INSTANCE_LINEAGE_QUERY_FAILED(404, "ATLAS4047E", "Instance lineage query failed {0}"),
DISCOVERY_QUERY_FAILED(404, "ATLAS4048E", "Discovery query failed {0}"),
+ INSTANCE_CRUD_INVALID_PARAMS(404, "ATLAS4049E", "Invalid instance creation/updation parameters passed : {0}"),
// All data conflict errors go here
@@ -72,7 +73,11 @@ public enum AtlasErrorCode {
// All internal errors go here
INTERNAL_ERROR(500, "ATLAS5001E", "Internal server error {0}"),
INDEX_CREATION_FAILED(500, "ATLAS5002E", "Index creation failed for {0}"),
- INDEX_ROLLBACK_FAILED(500, "ATLAS5003E", "Index rollback failed for {0}");
+ INDEX_ROLLBACK_FAILED(500, "ATLAS5003E", "Index rollback failed for {0}"),
+
+ INSTANCE_BY_UNIQUE_ATTRIBUTE_NOT_FOUND(400, "ATLAS40018E", "Instance {0} with unique attribute {1} does not exist"),
+
+ UNKNOWN_ATTRIBUTE(400, "ATLAS40019E", "Attribute {0} not found for type {1}");
private String errorCode;
private String errorMessage;
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java b/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java
index 2ad0f76..9494fe4 100644
--- a/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java
+++ b/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntity.java
@@ -55,15 +55,15 @@ public class AtlasEntity extends AtlasStruct implements Serializable {
/**
* Status of the entity - can be active or deleted. Deleted entities are not removed from Atlas store.
*/
- public enum Status { STATUS_ACTIVE, STATUS_DELETED }
+ public enum Status { ACTIVE, DELETED }
private String guid = null;
- private Status status = Status.STATUS_ACTIVE;
+ private Status status = Status.ACTIVE;
private String createdBy = null;
private String updatedBy = null;
private Date createTime = null;
private Date updateTime = null;
- private Long version = null;
+ private Long version = new Long(0);
@JsonIgnore
private static AtomicLong s_nextId = new AtomicLong(System.nanoTime());
@@ -89,7 +89,6 @@ public class AtlasEntity extends AtlasStruct implements Serializable {
setUpdatedBy(null);
setCreateTime(null);
setUpdateTime(null);
- setVersion(null);
}
public AtlasEntity(AtlasEntity other) {
@@ -247,7 +246,7 @@ public class AtlasEntity extends AtlasStruct implements Serializable {
@JsonIgnore
public boolean isUnassigned() {
- return guid != null && guid.length() > 0 && guid.charAt(0) == '-';
+ return isUnAssigned(guid);
}
@JsonIgnore
@@ -266,6 +265,11 @@ public class AtlasEntity extends AtlasStruct implements Serializable {
return true;
}
+ @JsonIgnore
+ public static boolean isUnAssigned(String guid) {
+ return guid != null && guid.length() > 0 && guid.charAt(0) == '-';
+ }
+
private String nextInternalId() {
return "-" + Long.toString(s_nextId.getAndIncrement());
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntityHeader.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntityHeader.java b/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntityHeader.java
index e7b70aa..5797a69 100644
--- a/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntityHeader.java
+++ b/intg/src/main/java/org/apache/atlas/model/instance/AtlasEntityHeader.java
@@ -18,6 +18,7 @@
package org.apache.atlas.model.instance;
import java.io.Serializable;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -49,7 +50,7 @@ public class AtlasEntityHeader extends AtlasStruct implements Serializable {
private static final long serialVersionUID = 1L;
private String guid = null;
- private AtlasEntity.Status status = AtlasEntity.Status.STATUS_ACTIVE;
+ private AtlasEntity.Status status = AtlasEntity.Status.ACTIVE;
private String displayText = null;
public AtlasEntityHeader() {
@@ -66,11 +67,15 @@ public class AtlasEntityHeader extends AtlasStruct implements Serializable {
public AtlasEntityHeader(String typeName, Map<String, Object> attributes) {
super(typeName, attributes);
+ }
+
- setGuid(null);
- setStatus(null);
+ public AtlasEntityHeader(String typeName, String guid, Map<String, Object> attributes) {
+ super(typeName, attributes);
+ setGuid(guid);
}
+
public AtlasEntityHeader(AtlasEntityHeader other) {
super(other);
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/intg/src/main/java/org/apache/atlas/model/instance/EntityMutations.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/model/instance/EntityMutations.java b/intg/src/main/java/org/apache/atlas/model/instance/EntityMutations.java
index 3501c90..74e3c57 100644
--- a/intg/src/main/java/org/apache/atlas/model/instance/EntityMutations.java
+++ b/intg/src/main/java/org/apache/atlas/model/instance/EntityMutations.java
@@ -43,7 +43,8 @@ public class EntityMutations implements Serializable {
private List<EntityMutation> entityMutations = new ArrayList<>();
public enum EntityOperation {
- CREATE_OR_UPDATE,
+ CREATE,
+ UPDATE,
PARTIAL_UPDATE,
DELETE,
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/intg/src/main/java/org/apache/atlas/model/typedef/AtlasStructDef.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/model/typedef/AtlasStructDef.java b/intg/src/main/java/org/apache/atlas/model/typedef/AtlasStructDef.java
index aee26ef..2c00f54 100644
--- a/intg/src/main/java/org/apache/atlas/model/typedef/AtlasStructDef.java
+++ b/intg/src/main/java/org/apache/atlas/model/typedef/AtlasStructDef.java
@@ -19,6 +19,7 @@ package org.apache.atlas.model.typedef;
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -183,7 +184,7 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
return findAttribute(attributeDefs, attrName) != null;
}
- private static AtlasAttributeDef findAttribute(List<AtlasAttributeDef> attributeDefs, String attrName) {
+ public static AtlasAttributeDef findAttribute(Collection<AtlasAttributeDef> attributeDefs, String attrName) {
AtlasAttributeDef ret = null;
if (CollectionUtils.isNotEmpty(attributeDefs)) {
@@ -451,6 +452,8 @@ public class AtlasStructDef extends AtlasBaseTypeDef implements Serializable {
}
}
+
+
/**
* class that captures details of a constraint.
*/
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/intg/src/main/java/org/apache/atlas/type/AtlasClassificationType.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasClassificationType.java b/intg/src/main/java/org/apache/atlas/type/AtlasClassificationType.java
index 8772720..7d89848 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasClassificationType.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasClassificationType.java
@@ -46,8 +46,6 @@ public class AtlasClassificationType extends AtlasStructType {
private List<AtlasClassificationType> superTypes = Collections.emptyList();
private Set<String> allSuperTypes = Collections.emptySet();
- private Map<String, AtlasAttributeDef> allAttributeDefs = Collections.emptyMap();
- private Map<String, AtlasType> allAttributeTypes = new HashMap<>();
public AtlasClassificationType(AtlasClassificationDef classificationDef) {
super(classificationDef);
@@ -72,7 +70,7 @@ public class AtlasClassificationType extends AtlasStructType {
List<AtlasClassificationType> s = new ArrayList<>();
Set<String> allS = new HashSet<>();
- Map<String, AtlasAttributeDef> allA = new HashMap<>();
+ Map<String, AtlasAttribute> allA = new HashMap<>();
getTypeHierarchyInfo(typeRegistry, allS, allA);
@@ -89,8 +87,7 @@ public class AtlasClassificationType extends AtlasStructType {
this.superTypes = Collections.unmodifiableList(s);
this.allSuperTypes = Collections.unmodifiableSet(allS);
- this.allAttributeDefs = Collections.unmodifiableMap(allA);
- this.allAttributeTypes = new HashMap<>(); // this will be rebuilt on calls to getAttributeType()
+ this.allAttributes = Collections.unmodifiableMap(allA);
}
public Set<String> getSuperTypes() {
@@ -99,51 +96,6 @@ public class AtlasClassificationType extends AtlasStructType {
public Set<String> getAllSuperTypes() { return allSuperTypes; }
- public Map<String, AtlasAttributeDef> getAllAttributeDefs() { return allAttributeDefs; }
-
- @Override
- public AtlasType getAttributeType(String attributeName) {
- AtlasType ret = allAttributeTypes.get(attributeName);
-
- if (ret == null) {
- ret = super.getAttributeType(attributeName);
-
- if (ret == null) {
- for (AtlasClassificationType superType : superTypes) {
- ret = superType.getAttributeType(attributeName);
-
- if (ret != null) {
- break;
- }
- }
- }
-
- if (ret != null) {
- allAttributeTypes.put(attributeName, ret);
- }
- }
-
- return ret;
- }
-
-
- @Override
- public AtlasAttributeDef getAttributeDef(String attributeName) {
- AtlasAttributeDef ret = super.getAttributeDef(attributeName);
-
- if (ret == null) {
- for (AtlasClassificationType superType : superTypes) {
- ret = superType.getAttributeDef(attributeName);
-
- if (ret != null) {
- break;
- }
- }
- }
-
- return ret;
- }
-
public boolean isSuperTypeOf(AtlasClassificationType classificationType) {
return classificationType != null && classificationType.getAllSuperTypes().contains(this.getTypeName());
}
@@ -243,10 +195,10 @@ public class AtlasClassificationType extends AtlasStructType {
private void getTypeHierarchyInfo(AtlasTypeRegistry typeRegistry,
Set<String> allSuperTypeNames,
- Map<String, AtlasAttributeDef> allAttributeDefs) throws AtlasBaseException {
+ Map<String, AtlasAttribute> allAttributes) throws AtlasBaseException {
List<String> visitedTypes = new ArrayList<>();
- collectTypeHierarchyInfo(typeRegistry, allSuperTypeNames, allAttributeDefs, visitedTypes);
+ collectTypeHierarchyInfo(typeRegistry, allSuperTypeNames, allAttributes, visitedTypes);
}
/*
@@ -255,7 +207,7 @@ public class AtlasClassificationType extends AtlasStructType {
*/
private void collectTypeHierarchyInfo(AtlasTypeRegistry typeRegistry,
Set<String> allSuperTypeNames,
- Map<String, AtlasAttributeDef> allAttributeDefs,
+ Map<String, AtlasAttribute> allAttributes,
List<String> visitedTypes) throws AtlasBaseException {
if (visitedTypes.contains(classificationDef.getName())) {
throw new AtlasBaseException(AtlasErrorCode.CIRCULAR_REFERENCE, classificationDef.getName(),
@@ -270,7 +222,7 @@ public class AtlasClassificationType extends AtlasStructType {
if (type instanceof AtlasClassificationType) {
AtlasClassificationType superType = (AtlasClassificationType) type;
- superType.collectTypeHierarchyInfo(typeRegistry, allSuperTypeNames, allAttributeDefs, visitedTypes);
+ superType.collectTypeHierarchyInfo(typeRegistry, allSuperTypeNames, allAttributes, visitedTypes);
}
}
visitedTypes.remove(classificationDef.getName());
@@ -280,7 +232,8 @@ public class AtlasClassificationType extends AtlasStructType {
if (CollectionUtils.isNotEmpty(classificationDef.getAttributeDefs())) {
for (AtlasAttributeDef attributeDef : classificationDef.getAttributeDefs()) {
- allAttributeDefs.put(attributeDef.getName(), attributeDef);
+ AtlasType type = typeRegistry.getType(attributeDef.getTypeName());
+ allAttributes.put(attributeDef.getName(), new AtlasAttribute(this, classificationDef, attributeDef, type));
}
}
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java b/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
index 3625f72..caadecc 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasEntityType.java
@@ -21,9 +21,11 @@ package org.apache.atlas.type;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.typedef.AtlasEntityDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef;
import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -45,8 +47,6 @@ public class AtlasEntityType extends AtlasStructType {
private List<AtlasEntityType> superTypes = Collections.emptyList();
private Set<String> allSuperTypes = Collections.emptySet();
- private Map<String, AtlasAttributeDef> allAttributeDefs = Collections.emptyMap();
- private Map<String, AtlasType> allAttributeTypes = new HashMap<>();
public AtlasEntityType(AtlasEntityDef entityDef) {
super(entityDef);
@@ -70,7 +70,7 @@ public class AtlasEntityType extends AtlasStructType {
List<AtlasEntityType> s = new ArrayList<>();
Set<String> allS = new HashSet<>();
- Map<String, AtlasAttributeDef> allA = new HashMap<>();
+ Map<String, AtlasAttribute> allA = new HashMap<>();
getTypeHierarchyInfo(typeRegistry, allS, allA);
@@ -86,8 +86,7 @@ public class AtlasEntityType extends AtlasStructType {
this.superTypes = Collections.unmodifiableList(s);
this.allSuperTypes = Collections.unmodifiableSet(allS);
- this.allAttributeDefs = Collections.unmodifiableMap(allA);
- this.allAttributeTypes = new HashMap<>(); // this will be rebuilt on calls to getAttributeType()
+ this.allAttributes = Collections.unmodifiableMap(allA);
}
public Set<String> getSuperTypes() {
@@ -98,50 +97,6 @@ public class AtlasEntityType extends AtlasStructType {
return allSuperTypes;
}
- public Map<String, AtlasAttributeDef> getAllAttributeDefs() { return allAttributeDefs; }
-
- @Override
- public AtlasType getAttributeType(String attributeName) {
- AtlasType ret = allAttributeTypes.get(attributeName);
-
- if (ret == null) {
- ret = super.getAttributeType(attributeName);
-
- if (ret == null) {
- for (AtlasEntityType superType : superTypes) {
- ret = superType.getAttributeType(attributeName);
-
- if (ret != null) {
- break;
- }
- }
- }
-
- if (ret != null) {
- allAttributeTypes.put(attributeName, ret);
- }
- }
-
- return ret;
- }
-
- @Override
- public AtlasAttributeDef getAttributeDef(String attributeName) {
- AtlasAttributeDef ret = super.getAttributeDef(attributeName);
-
- if (ret == null) {
- for (AtlasEntityType superType : superTypes) {
- ret = superType.getAttributeDef(attributeName);
-
- if (ret != null) {
- break;
- }
- }
- }
-
- return ret;
- }
-
public boolean isSuperTypeOf(AtlasEntityType entityType) {
return entityType != null && entityType.getAllSuperTypes().contains(this.getTypeName());
}
@@ -150,6 +105,10 @@ public class AtlasEntityType extends AtlasStructType {
return entityType != null && allSuperTypes.contains(entityType.getTypeName());
}
+ public boolean isSubTypeOf(String entityTypeName) {
+ return StringUtils.isNotEmpty(entityTypeName) && allSuperTypes.contains(entityTypeName);
+ }
+
@Override
public AtlasEntity createDefaultValue() {
AtlasEntity ret = new AtlasEntity(entityDef.getName());
@@ -162,13 +121,17 @@ public class AtlasEntityType extends AtlasStructType {
@Override
public boolean isValidValue(Object obj) {
if (obj != null) {
- for (AtlasEntityType superType : superTypes) {
- if (!superType.isValidValue(obj)) {
- return false;
+ if (obj instanceof AtlasObjectId) {
+ AtlasObjectId objId = (AtlasObjectId ) obj;
+ return validateAtlasObjectId(objId);
+ } else {
+ for (AtlasEntityType superType : superTypes) {
+ if (!superType.isValidValue(obj)) {
+ return false;
+ }
}
+ return super.isValidValue(obj);
}
-
- return super.isValidValue(obj);
}
return true;
@@ -186,6 +149,8 @@ public class AtlasEntityType extends AtlasStructType {
} else if (obj instanceof Map) {
normalizeAttributeValues((Map) obj);
ret = obj;
+ } else if (obj instanceof AtlasObjectId) {
+ ret = obj;
}
}
}
@@ -194,10 +159,20 @@ public class AtlasEntityType extends AtlasStructType {
}
@Override
+ public AtlasAttribute getAttribute(String attributeName) {
+ return findAttribute(allAttributes.values(), attributeName);
+ }
+
+ @Override
public boolean validateValue(Object obj, String objName, List<String> messages) {
boolean ret = true;
if (obj != null) {
+ if (obj instanceof AtlasObjectId) {
+ AtlasObjectId objId = (AtlasObjectId ) obj;
+ return validateAtlasObjectId(objId);
+ }
+
for (AtlasEntityType superType : superTypes) {
ret = superType.validateValue(obj, objName, messages) && ret;
}
@@ -241,10 +216,10 @@ public class AtlasEntityType extends AtlasStructType {
private void getTypeHierarchyInfo(AtlasTypeRegistry typeRegistry,
Set<String> allSuperTypeNames,
- Map<String, AtlasAttributeDef> allAttributeDefs) throws AtlasBaseException {
+ Map<String, AtlasAttribute> allAttributes) throws AtlasBaseException {
List<String> visitedTypes = new ArrayList<>();
- collectTypeHierarchyInfo(typeRegistry, allSuperTypeNames, allAttributeDefs, visitedTypes);
+ collectTypeHierarchyInfo(typeRegistry, allSuperTypeNames, allAttributes, visitedTypes);
}
/*
@@ -253,7 +228,7 @@ public class AtlasEntityType extends AtlasStructType {
*/
private void collectTypeHierarchyInfo(AtlasTypeRegistry typeRegistry,
Set<String> allSuperTypeNames,
- Map<String, AtlasAttributeDef> allAttributeDefs,
+ Map<String, AtlasAttribute> allAttributes,
List<String> visitedTypes) throws AtlasBaseException {
if (visitedTypes.contains(entityDef.getName())) {
throw new AtlasBaseException(AtlasErrorCode.CIRCULAR_REFERENCE, entityDef.getName(),
@@ -267,19 +242,36 @@ public class AtlasEntityType extends AtlasStructType {
if (type instanceof AtlasEntityType) {
AtlasEntityType superType = (AtlasEntityType) type;
-
- superType.collectTypeHierarchyInfo(typeRegistry, allSuperTypeNames, allAttributeDefs, visitedTypes);
+ superType.collectTypeHierarchyInfo(typeRegistry, allSuperTypeNames, allAttributes, visitedTypes);
}
}
visitedTypes.remove(entityDef.getName());
-
allSuperTypeNames.addAll(entityDef.getSuperTypes());
}
if (CollectionUtils.isNotEmpty(entityDef.getAttributeDefs())) {
for (AtlasAttributeDef attributeDef : entityDef.getAttributeDefs()) {
- allAttributeDefs.put(attributeDef.getName(), attributeDef);
+
+ AtlasType type = typeRegistry.getType(attributeDef.getTypeName());
+ allAttributes.put(attributeDef.getName(), new AtlasAttribute(this, entityDef, attributeDef, type));
+ }
+ }
+ }
+
+ private boolean validateAtlasObjectId(AtlasObjectId objId) {
+ if (StringUtils.isEmpty(objId.getTypeName()) || StringUtils.isEmpty(objId.getGuid())) {
+ return false;
+ } else {
+ String typeName = objId.getTypeName();
+ if (!typeName.equals(getTypeName())) {
+ //TODO - Enable below after enabling subType check
+// if ( !isSuperTypeOf(typeName)) {
+// return false;
+// }
+ return false;
}
}
+ return AtlasEntity.isAssigned(objId.getGuid()) || AtlasEntity.isUnAssigned((objId.getGuid()));
}
+
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java
----------------------------------------------------------------------
diff --git a/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java b/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java
index e20af76..4712508 100644
--- a/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java
+++ b/intg/src/main/java/org/apache/atlas/type/AtlasStructType.java
@@ -20,6 +20,8 @@ package org.apache.atlas.type;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.TypeCategory;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.instance.AtlasStruct;
import org.apache.atlas.model.typedef.AtlasStructDef;
import org.apache.atlas.model.typedef.AtlasStructDef.AtlasAttributeDef;
@@ -30,6 +32,7 @@ import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -49,10 +52,9 @@ public class AtlasStructType extends AtlasType {
private final AtlasStructDef structDef;
- private Map<String, AtlasType> attrTypes = Collections.emptyMap();
private Set<String> foreignKeyAttributes = new HashSet<>();
private Map<String, TypeAttributePair> mappedFromRefAttributes = new HashMap<>();
-
+ protected Map<String, AtlasAttribute> allAttributes = Collections.emptyMap();
public AtlasStructType(AtlasStructDef structDef) {
super(structDef);
@@ -70,9 +72,12 @@ public class AtlasStructType extends AtlasType {
public AtlasStructDef getStructDef() { return structDef; }
- public AtlasType getAttributeType(String attributeName) { return attrTypes.get(attributeName); }
+ public AtlasType getAttributeType(String attributeName) {
+ AtlasAttribute attribute = allAttributes.get(attributeName);
+ return attribute != null ? attribute.getAttributeType() : null;
+ }
- public AtlasAttributeDef getAttributeDef(String attributeName) { return structDef.getAttribute(attributeName); }
+ public AtlasAttributeDef getAttributeDef(String attributeName) { return allAttributes.get(attributeName) != null ? allAttributes.get(attributeName).getAttributeDef() : null; }
public boolean isForeignKeyAttribute(String attributeName) {
return foreignKeyAttributes.contains(attributeName);
@@ -101,10 +106,12 @@ public class AtlasStructType extends AtlasType {
@Override
public void resolveReferences(AtlasTypeRegistry typeRegistry) throws AtlasBaseException {
- Map<String, AtlasType> a = new HashMap<>();
+ Map<String, AtlasAttribute> a = new HashMap<>();
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
+
AtlasType attrType = typeRegistry.getType(attributeDef.getTypeName());
+ AtlasAttribute attribute = new AtlasAttribute(this, structDef, attributeDef, attrType);
resolveConstraints(attributeDef, attrType);
@@ -122,10 +129,10 @@ public class AtlasStructType extends AtlasType {
arrayType.setMaxCount(attributeDef.getValuesMaxCount());
}
- a.put(attributeDef.getName(), attrType);
+ a.put(attributeDef.getName(), attribute);
}
- this.attrTypes = Collections.unmodifiableMap(a);
+ this.allAttributes = Collections.unmodifiableMap(a);
}
@Override
@@ -137,6 +144,29 @@ public class AtlasStructType extends AtlasType {
return ret;
}
+ public Map<String, AtlasAttribute> getAllAttributes() {
+ return allAttributes;
+ }
+
+ public AtlasAttribute getAttribute(String attributeName) {
+ return findAttribute(allAttributes.values(), attributeName);
+ }
+
+ public static AtlasAttribute findAttribute(Collection<AtlasAttribute> attributes, String attrName) {
+ AtlasAttribute ret = null;
+
+ if (CollectionUtils.isNotEmpty(attributes)) {
+ for (AtlasAttribute attribute : attributes) {
+ if (org.apache.hadoop.util.StringUtils.equalsIgnoreCase(attribute.getAttributeDef().getName(), attrName)) {
+ ret = attribute;
+ break;
+ }
+ }
+ }
+
+ return ret;
+ }
+
@Override
public boolean isValidValue(Object obj) {
if (obj != null) {
@@ -157,7 +187,7 @@ public class AtlasStructType extends AtlasType {
}
}
} else {
- return false; // invalid type
+ return false;
}
}
@@ -193,9 +223,11 @@ public class AtlasStructType extends AtlasType {
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
String attrName = attributeDef.getName();
- AtlasType dataType = attrTypes.get(attributeDef.getName());
- if (dataType != null) {
+ AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
+
+ if (attribute != null) {
+ AtlasType dataType = attribute.getAttributeType();
Object value = structObj.getAttribute(attrName);
String fieldName = objName + "." + attrName;
@@ -213,9 +245,10 @@ public class AtlasStructType extends AtlasType {
for (AtlasAttributeDef attributeDef : structDef.getAttributeDefs()) {
String attrName = attributeDef.getName();
- AtlasType dataType = attrTypes.get(attributeDef.getName());
+ AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
- if (dataType != null) {
+ if (attribute != null) {
+ AtlasType dataType = attribute.getAttributeType();
Object value = map.get(attrName);
String fieldName = objName + "." + attrName;
@@ -230,7 +263,6 @@ public class AtlasStructType extends AtlasType {
}
} else {
ret = false;
-
messages.add(objName + "=" + obj + ": invalid value for type " + getTypeName());
}
}
@@ -292,9 +324,10 @@ public class AtlasStructType extends AtlasType {
Object ret = null;
if (attributeDef != null) {
- AtlasType dataType = attrTypes.get(attributeDef.getName());
+ AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
- if (dataType != null) {
+ if (attribute != null) {
+ AtlasType dataType = attribute.getAttributeType();
ret = dataType.createDefaultValue();
}
}
@@ -306,12 +339,14 @@ public class AtlasStructType extends AtlasType {
boolean ret = true;
if (value != null) {
- AtlasType attrType = attrTypes.get(attributeDef.getName());
+ AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
- if (attrType != null) {
- if (!attrType.isValidValue(value)) {
- ret = false; // invalid value
- }
+ if (attribute != null) {
+ AtlasType attrType = attribute.getAttributeType();
+
+ if (!attrType.isValidValue(value)) {
+ ret = false; // invalid value
+ }
}
} else if (!attributeDef.getIsOptional()) {
ret = false; // mandatory attribute not present
@@ -321,9 +356,11 @@ public class AtlasStructType extends AtlasType {
}
private Object getNormalizedValue(Object value, AtlasAttributeDef attributeDef) {
- AtlasType attrType = attrTypes.get(attributeDef.getName());
+ AtlasAttribute attribute = allAttributes.get(attributeDef.getName());
+
+ if (attribute != null) {
+ AtlasType attrType = attribute.getAttributeType();
- if (attrType != null) {
if (value == null) {
if (!attributeDef.getIsOptional()) {
return attrType.createDefaultValue();
@@ -419,8 +456,8 @@ public class AtlasStructType extends AtlasType {
String.valueOf(constraintDef.getParams()));
}
- AtlasStructType structType = (AtlasStructType)attribType;
- AtlasAttributeDef refAttrib = structType.getAttributeDef(refAttribName);
+ AtlasStructType structType = (AtlasStructType) attribType;
+ AtlasAttributeDef refAttrib = structType.getStructDef().getAttribute(refAttribName);
if (refAttrib == null) {
throw new AtlasBaseException(AtlasErrorCode.CONSTRAINT_NOT_EXIST,
@@ -447,4 +484,58 @@ public class AtlasStructType extends AtlasType {
this.attributeName = attributeName;
}
}
+
+ public String getQualifiedAttributeName(String attrName) throws AtlasBaseException {
+ if ( allAttributes.containsKey(attrName)) {
+ return allAttributes.get(attrName).getQualifiedName();
+ }
+
+ throw new AtlasBaseException(AtlasErrorCode.UNKNOWN_ATTRIBUTE, attrName, structDef.getName());
+ }
+
+ public static class AtlasAttribute {
+
+ private final AtlasStructType structType;
+ private final AtlasStructDef structDef;
+ private final AtlasType attributeType;
+ private final AtlasAttributeDef attributeDef;
+ private final String qualifiedName;
+
+ public AtlasAttribute(AtlasStructType structType, AtlasStructDef structDef, AtlasAttributeDef attrDef, AtlasType attributeType) {
+ this.structType = structType;
+ this.structDef = structDef;
+ this.attributeDef = attrDef;
+ this.attributeType = attributeType;
+ this.qualifiedName = getQualifiedAttributeName(structDef, attributeDef.getName());
+ }
+
+ public AtlasStructType getStructType() {
+ return structType;
+ }
+
+ public String getQualifiedName() {
+ return qualifiedName;
+ }
+
+ public AtlasStructDef getStructDef() {
+ return structDef;
+ }
+
+ public AtlasType getAttributeType() {
+ return attributeType;
+ }
+
+ public AtlasAttributeDef getAttributeDef() {
+ return attributeDef;
+ }
+
+ public String getQualifiedAttributeName() {
+ return qualifiedName;
+ }
+
+ public static String getQualifiedAttributeName(AtlasStructDef structDef, String attrName) {
+ final String typeName = structDef.getName();
+ return attrName.contains(".") ? attrName : String.format("%s.%s", typeName, attrName);
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/intg/src/test/java/org/apache/atlas/TestUtilsV2.java
----------------------------------------------------------------------
diff --git a/intg/src/test/java/org/apache/atlas/TestUtilsV2.java b/intg/src/test/java/org/apache/atlas/TestUtilsV2.java
index 53b109c..f9040f3 100755
--- a/intg/src/test/java/org/apache/atlas/TestUtilsV2.java
+++ b/intg/src/test/java/org/apache/atlas/TestUtilsV2.java
@@ -21,6 +21,7 @@ package org.apache.atlas;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.instance.AtlasStruct;
import org.apache.atlas.model.typedef.AtlasClassificationDef;
import org.apache.atlas.model.typedef.AtlasEntityDef;
@@ -80,13 +81,19 @@ public final class TestUtilsV2 {
AtlasEntityDef deptTypeDef =
AtlasTypeUtil.createClassTypeDef(DEPARTMENT_TYPE, "Department"+_description, ImmutableSet.<String>of(),
- AtlasTypeUtil.createRequiredAttrDef("name", "string"),
- new AtlasAttributeDef("employees", String.format("array<%s>", "Person"), true,
+ AtlasTypeUtil.createUniqueRequiredAttrDef("name", "string"),
+ new AtlasAttributeDef("employees", String.format("array<%s>", "Employee"), true,
AtlasAttributeDef.Cardinality.SINGLE, 0, 1, false, false,
- Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()));
+ new ArrayList<AtlasStructDef.AtlasConstraintDef>()));
+
+ deptTypeDef.getAttribute("employees").addConstraint(
+ new AtlasStructDef.AtlasConstraintDef(
+ AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_MAPPED_FROM_REF, new HashMap<String, Object>() {{
+ put(AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_REF_ATTRIBUTE, "department");
+ }}));
AtlasEntityDef personTypeDef = AtlasTypeUtil.createClassTypeDef("Person", "Person"+_description, ImmutableSet.<String>of(),
- AtlasTypeUtil.createRequiredAttrDef("name", "string"),
+ AtlasTypeUtil.createUniqueRequiredAttrDef("name", "string"),
AtlasTypeUtil.createOptionalAttrDef("address", "Address"),
AtlasTypeUtil.createOptionalAttrDef("birthday", "date"),
AtlasTypeUtil.createOptionalAttrDef("hasPets", "boolean"),
@@ -103,20 +110,25 @@ public final class TestUtilsV2 {
new AtlasAttributeDef("department", "Department", false,
AtlasAttributeDef.Cardinality.SINGLE, 1, 1,
false, false,
- Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()),
- new AtlasAttributeDef("manager", "Employee", true,
+ new ArrayList<AtlasStructDef.AtlasConstraintDef>()),
+ new AtlasAttributeDef("manager", "Manager", true,
AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
false, false,
Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()),
- new AtlasAttributeDef("mentor", "Employee", true,
+ new AtlasAttributeDef("mentor", EMPLOYEE_TYPE, true,
AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
false, false,
Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()),
AtlasTypeUtil.createOptionalAttrDef("shares", "long"),
AtlasTypeUtil.createOptionalAttrDef("salary", "double")
-
);
+ employeeTypeDef.getAttribute("department").addConstraint(
+ new AtlasStructDef.AtlasConstraintDef(
+ AtlasStructDef.AtlasConstraintDef.CONSTRAINT_TYPE_FOREIGN_KEY, new HashMap<String, Object>() {{
+ put(AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_ON_DELETE, AtlasStructDef.AtlasConstraintDef.CONSTRAINT_PARAM_VAL_CASCADE);
+ }}));
+
AtlasEntityDef managerTypeDef = AtlasTypeUtil.createClassTypeDef("Manager", "Manager"+_description, ImmutableSet.of("Employee"),
new AtlasAttributeDef("subordinates", String.format("array<%s>", "Employee"), false, AtlasAttributeDef.Cardinality.SET,
1, 10, false, false,
@@ -149,7 +161,7 @@ public final class TestUtilsV2 {
AtlasEntityDef deptTypeDef =
AtlasTypeUtil.createClassTypeDef(DEPARTMENT_TYPE, "Department"+_description,
ImmutableSet.<String>of(),
- AtlasTypeUtil.createRequiredAttrDef("name", "string"),
+ AtlasTypeUtil.createUniqueRequiredAttrDef("name", "string"),
AtlasTypeUtil.createOptionalAttrDef("dep-code", "string"),
new AtlasAttributeDef("employees", String.format("array<%s>", "Employee"), true,
AtlasAttributeDef.Cardinality.SINGLE, 0, 1, false, false,
@@ -157,7 +169,7 @@ public final class TestUtilsV2 {
AtlasEntityDef personTypeDef = AtlasTypeUtil.createClassTypeDef("Person", "Person"+_description,
ImmutableSet.<String>of(),
- AtlasTypeUtil.createRequiredAttrDef("name", "string"),
+ AtlasTypeUtil.createUniqueRequiredAttrDef("name", "string"),
AtlasTypeUtil.createOptionalAttrDef("email", "string"),
AtlasTypeUtil.createOptionalAttrDef("address", "Address"),
AtlasTypeUtil.createOptionalAttrDef("birthday", "date"),
@@ -178,11 +190,11 @@ public final class TestUtilsV2 {
AtlasAttributeDef.Cardinality.SINGLE, 1, 1,
false, false,
Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()),
- new AtlasAttributeDef("manager", "Employee", true,
+ new AtlasAttributeDef("manager", "Manager", true,
AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
false, false,
Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()),
- new AtlasAttributeDef("mentor", "Employee", true,
+ new AtlasAttributeDef("mentor", EMPLOYEE_TYPE, true,
AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
false, false,
Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()),
@@ -241,7 +253,7 @@ public final class TestUtilsV2 {
AtlasAttributeDef.Cardinality.SINGLE, 1, 1,
false, false,
Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()),
- new AtlasAttributeDef("manager", "Person", true,
+ new AtlasAttributeDef("manager", "Manager", true,
AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
false, false,
Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()),
@@ -269,24 +281,24 @@ public final class TestUtilsV2 {
public static final String DEPARTMENT_TYPE = "Department";
public static final String PERSON_TYPE = "Person";
+ public static final String EMPLOYEE_TYPE = "Employee";
public static AtlasEntity createDeptEg1() {
AtlasEntity hrDept = new AtlasEntity(DEPARTMENT_TYPE);
- AtlasEntity john = new AtlasEntity(PERSON_TYPE);
+ AtlasEntity john = new AtlasEntity(EMPLOYEE_TYPE);
-// AtlasEntity jane = new AtlasEntity("Manager", "SecurityClearance");
AtlasEntity jane = new AtlasEntity("Manager");
AtlasEntity johnAddr = new AtlasEntity("Address");
AtlasEntity janeAddr = new AtlasEntity("Address");
AtlasEntity julius = new AtlasEntity("Manager");
AtlasEntity juliusAddr = new AtlasEntity("Address");
- AtlasEntity max = new AtlasEntity("Person");
+ AtlasEntity max = new AtlasEntity(EMPLOYEE_TYPE);
AtlasEntity maxAddr = new AtlasEntity("Address");
-
+ AtlasObjectId deptId = new AtlasObjectId(hrDept.getTypeName(), hrDept.getGuid());
hrDept.setAttribute("name", "hr");
john.setAttribute("name", "John");
- john.setAttribute("department", hrDept);
+ john.setAttribute("department", deptId);
johnAddr.setAttribute("street", "Stewart Drive");
johnAddr.setAttribute("city", "Sunnyvale");
john.setAttribute("address", johnAddr);
@@ -303,26 +315,32 @@ public final class TestUtilsV2 {
john.setAttribute("approximationOfPi", new BigDecimal("3.141592653589793238462643383279502884197169399375105820974944592307816406286"));
jane.setAttribute("name", "Jane");
- jane.setAttribute("department", hrDept);
+ jane.setAttribute("department", deptId);
janeAddr.setAttribute("street", "Great America Parkway");
janeAddr.setAttribute("city", "Santa Clara");
jane.setAttribute("address", janeAddr);
janeAddr.setAttribute("street", "Great America Parkway");
julius.setAttribute("name", "Julius");
- julius.setAttribute("department", hrDept);
+ julius.setAttribute("department", deptId);
juliusAddr.setAttribute("street", "Madison Ave");
juliusAddr.setAttribute("city", "Newtonville");
julius.setAttribute("address", juliusAddr);
julius.setAttribute("subordinates", ImmutableList.of());
+ AtlasObjectId janeId = new AtlasObjectId(jane.getTypeName(), jane.getGuid());
+
+ //TODO - Change to MANAGER_TYPE for JULIUS
+ AtlasObjectId maxId = new AtlasObjectId(EMPLOYEE_TYPE, max.getGuid());
+ AtlasObjectId juliusId = new AtlasObjectId(EMPLOYEE_TYPE, julius.getGuid());
+
max.setAttribute("name", "Max");
- max.setAttribute("department", hrDept);
+ max.setAttribute("department", deptId);
maxAddr.setAttribute("street", "Ripley St");
maxAddr.setAttribute("city", "Newton");
max.setAttribute("address", maxAddr);
- max.setAttribute("manager", jane);
- max.setAttribute("mentor", julius);
+ max.setAttribute("manager", janeId);
+ max.setAttribute("mentor", juliusId);
max.setAttribute("birthday",new Date(1979, 3, 15));
max.setAttribute("hasPets", true);
max.setAttribute("age", 36);
@@ -334,15 +352,15 @@ public final class TestUtilsV2 {
max.setAttribute("numberOfStarsEstimate", new BigInteger("1000000000000000000000000000000"));
max.setAttribute("approximationOfPi", new BigDecimal("3.1415926535897932"));
- john.setAttribute("manager", jane);
- john.setAttribute("mentor", max);
+ john.setAttribute("manager", janeId);
+ john.setAttribute("mentor", maxId);
hrDept.setAttribute("employees", ImmutableList.of(john, jane, julius, max));
jane.setAttribute("subordinates", ImmutableList.of(john, max));
- Map<String, Integer> secClearanceLevelMap = new HashMap<>();
- secClearanceLevelMap.put("level", 1);
- jane.setAttribute("SecurityClearance", secClearanceLevelMap);
+// Map<String, Integer> secClearanceLevelMap = new HashMap<>();
+// secClearanceLevelMap.put("level", 1);
+// jane.setAttribute("SecurityClearance", secClearanceLevelMap);
return hrDept;
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/intg/src/test/java/org/apache/atlas/type/TestAtlasTypeRegistry.java
----------------------------------------------------------------------
diff --git a/intg/src/test/java/org/apache/atlas/type/TestAtlasTypeRegistry.java b/intg/src/test/java/org/apache/atlas/type/TestAtlasTypeRegistry.java
index 9429c07..d171dcf 100644
--- a/intg/src/test/java/org/apache/atlas/type/TestAtlasTypeRegistry.java
+++ b/intg/src/test/java/org/apache/atlas/type/TestAtlasTypeRegistry.java
@@ -355,17 +355,17 @@ public class TestAtlasTypeRegistry {
} catch (AtlasBaseException excp) {
}
- Map<String, AtlasAttributeDef> attributeDefs = null;
+ Map<String, AtlasStructType.AtlasAttribute> attributes = null;
if (type != null) {
if (type instanceof AtlasEntityType) {
- attributeDefs = ((AtlasEntityType) type).getAllAttributeDefs();
+ attributes = ((AtlasEntityType) type).getAllAttributes();
} else if (type instanceof AtlasClassificationType) {
- attributeDefs = ((AtlasClassificationType) type).getAllAttributeDefs();
+ attributes = ((AtlasClassificationType) type).getAllAttributes();
}
}
- assertNotNull(attributeDefs);
- assertEquals(attributeDefs.keySet(), attributeNames);
+ assertNotNull(attributes);
+ assertEquals(attributes.keySet(), attributeNames);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/release-log.txt
----------------------------------------------------------------------
diff --git a/release-log.txt b/release-log.txt
index 92594cf..e9587c3 100644
--- a/release-log.txt
+++ b/release-log.txt
@@ -9,7 +9,11 @@ ATLAS-1060 Add composite indexes for exact match performance improvements for al
ATLAS-1127 Modify creation and modification timestamps to Date instead of Long(sumasai)
ALL CHANGES:
+ATLAS-1467 instance create/full-Update implementation (sumasai via mneethiraj)
+ATLAS-1463 option to exclude specific entity attributes in audit records (sarath.kum4r@gmail.com via mneethiraj)
ATLAS-1386 Avoid uunnecessary type cache lookups (jnhagelb)
+ATLAS-1000 added build instructions to README.txt (mneethiraj)
+ATLAS-1471 avoid unnecessary overhead in debug log calls (mneethiraj)
ATLAS-1464 option to include only specified attributes in notification message (sarath.kum4r@gmail.com via mneethiraj)
ATLAS-1460 v2 search API updated to return name/description/owner and classification names in result (vimalsharma via mneethiraj)
ATLAS-1434 fixed unit test to use correct type names; updated error message per review comments (ashutoshm via mneethiraj)
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java b/repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java
index 54dda50..c4d5020 100755
--- a/repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java
+++ b/repository/src/main/java/org/apache/atlas/RepositoryMetadataModule.java
@@ -24,6 +24,7 @@ import com.google.inject.matcher.Matchers;
import com.google.inject.multibindings.Multibinder;
import org.aopalliance.intercept.MethodInterceptor;
+import org.apache.atlas.discovery.AtlasDiscoveryService;
import org.apache.atlas.discovery.AtlasLineageService;
import org.apache.atlas.discovery.DataSetLineageService;
import org.apache.atlas.discovery.DiscoveryService;
@@ -34,7 +35,6 @@ import org.apache.atlas.discovery.graph.GraphBackedDiscoveryService;
import org.apache.atlas.listener.EntityChangeListener;
import org.apache.atlas.listener.TypeDefChangeListener;
import org.apache.atlas.listener.TypesChangeListener;
-import org.apache.atlas.discovery.AtlasDiscoveryService;
import org.apache.atlas.repository.MetadataRepository;
import org.apache.atlas.repository.audit.EntityAuditListener;
import org.apache.atlas.repository.audit.EntityAuditRepository;
@@ -42,8 +42,17 @@ import org.apache.atlas.repository.graph.DeleteHandler;
import org.apache.atlas.repository.graph.GraphBackedMetadataRepository;
import org.apache.atlas.repository.graph.GraphBackedSearchIndexer;
import org.apache.atlas.repository.store.graph.AtlasEntityStore;
+import org.apache.atlas.repository.store.graph.EntityGraphDiscovery;
+import org.apache.atlas.repository.store.graph.EntityResolver;
+import org.apache.atlas.repository.store.graph.v1.ArrayVertexMapper;
+import org.apache.atlas.repository.store.graph.v1.AtlasEntityGraphDiscoveryV1;
import org.apache.atlas.repository.store.graph.v1.AtlasEntityStoreV1;
import org.apache.atlas.repository.store.graph.v1.AtlasTypeDefGraphStoreV1;
+import org.apache.atlas.repository.store.graph.v1.DeleteHandlerV1;
+import org.apache.atlas.repository.store.graph.v1.EntityGraphMapper;
+import org.apache.atlas.repository.store.graph.v1.IDBasedEntityResolver;
+import org.apache.atlas.repository.store.graph.v1.MapVertexMapper;
+import org.apache.atlas.repository.store.graph.v1.UniqAttrBasedEntityResolver;
import org.apache.atlas.repository.typestore.GraphBackedTypeStore;
import org.apache.atlas.repository.typestore.ITypeStore;
import org.apache.atlas.service.Service;
@@ -106,8 +115,21 @@ public class RepositoryMetadataModule extends com.google.inject.AbstractModule {
bind(DeleteHandler.class).to(AtlasRepositoryConfiguration.getDeleteHandlerImpl()).asEagerSingleton();
+ bind(DeleteHandlerV1.class).to(AtlasRepositoryConfiguration.getDeleteHandlerV1Impl()).asEagerSingleton();
+
bind(TypeCache.class).to(AtlasRepositoryConfiguration.getTypeCache()).asEagerSingleton();
+ bind(EntityGraphMapper.class);
+
+ bind(MapVertexMapper.class).asEagerSingleton();
+
+ bind(ArrayVertexMapper.class).asEagerSingleton();
+
+ Multibinder<EntityResolver> entityRefResolver =
+ Multibinder.newSetBinder(binder(), EntityResolver.class);
+ entityRefResolver.addBinding().to(IDBasedEntityResolver.class);
+ entityRefResolver.addBinding().to(UniqAttrBasedEntityResolver.class);
+
//Add EntityAuditListener as EntityChangeListener
Multibinder<EntityChangeListener> entityChangeListenerBinder =
Multibinder.newSetBinder(binder(), EntityChangeListener.class);
@@ -116,6 +138,8 @@ public class RepositoryMetadataModule extends com.google.inject.AbstractModule {
MethodInterceptor interceptor = new GraphTransactionInterceptor();
requestInjection(interceptor);
bindInterceptor(Matchers.any(), Matchers.annotatedWith(GraphTransaction.class), interceptor);
+
+ bind(EntityGraphDiscovery.class).to(AtlasEntityGraphDiscoveryV1.class);
}
protected Configuration getConfiguration() {
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
index 2be9a2d..2b4561d 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java
@@ -228,7 +228,7 @@ public class EntityDiscoveryService implements AtlasDiscoveryService {
String state = vertex.getProperty(Constants.STATE_PROPERTY_KEY, String.class);
if (state != null) {
- Status status = (state.equalsIgnoreCase("ACTIVE") ? Status.STATUS_ACTIVE : Status.STATUS_DELETED);
+ Status status = (state.equalsIgnoreCase("ACTIVE") ? Status.ACTIVE : Status.DELETED);
ret.setStatus(status);
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/discovery/EntityLineageService.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/discovery/EntityLineageService.java b/repository/src/main/java/org/apache/atlas/discovery/EntityLineageService.java
index 45e2dd2..6b7d7d3 100644
--- a/repository/src/main/java/org/apache/atlas/discovery/EntityLineageService.java
+++ b/repository/src/main/java/org/apache/atlas/discovery/EntityLineageService.java
@@ -184,7 +184,7 @@ public class EntityLineageService implements AtlasLineageService {
ret.setDisplayText(vertex.getProperty(Constants.QUALIFIED_NAME, String.class));
String state = vertex.getProperty(Constants.STATE_PROPERTY_KEY, String.class);
- Status status = (state.equalsIgnoreCase("ACTIVE") ? Status.STATUS_ACTIVE : Status.STATUS_DELETED);
+ Status status = (state.equalsIgnoreCase("ACTIVE") ? Status.ACTIVE : Status.DELETED);
ret.setStatus(status);
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java b/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java
index 5259249..889236c 100755
--- a/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java
+++ b/repository/src/main/java/org/apache/atlas/repository/graph/GraphHelper.java
@@ -967,7 +967,7 @@ public final class GraphHelper {
instanceVertex.setListProperty(actualPropertyName, value);
}
- public static List<String> getListProperty(AtlasVertex instanceVertex, String propertyName) throws AtlasException {
+ public static List<String> getListProperty(AtlasVertex instanceVertex, String propertyName) {
String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
return instanceVertex.getListProperty(actualPropertyName);
}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java
index f17b816..c42f95f 100644
--- a/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/AtlasEntityStore.java
@@ -25,6 +25,7 @@ import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasEntityWithAssociations;
import org.apache.atlas.model.instance.EntityMutations;
import org.apache.atlas.model.instance.EntityMutationResponse;
+import org.apache.atlas.type.AtlasTypeRegistry;
import java.util.List;
@@ -36,14 +37,14 @@ public interface AtlasEntityStore {
/**
* Initialization
*/
- void init() throws AtlasBaseException;
+ void init(AtlasTypeRegistry typeRegistry, EntityGraphDiscovery graphDiscovery) throws AtlasBaseException;
/**
* Create or update an entity if it already exists.
* @param entity
* @return
*/
- EntityMutationResponse createOrUpdate(AtlasEntity entity);
+ EntityMutationResponse createOrUpdate(AtlasEntity entity) throws AtlasBaseException;
/**
@@ -175,4 +176,5 @@ public interface AtlasEntityStore {
* @throws AtlasBaseException
*/
AtlasEntity.AtlasEntities searchEntities(SearchFilter searchFilter) throws AtlasBaseException;
-}
\ No newline at end of file
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityGraphDiscovery.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityGraphDiscovery.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityGraphDiscovery.java
new file mode 100644
index 0000000..38fca03
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityGraphDiscovery.java
@@ -0,0 +1,39 @@
+/**
+ * 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;
+
+
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.instance.AtlasEntity;
+
+import java.util.List;
+
+public interface EntityGraphDiscovery {
+
+
+ void init() throws AtlasBaseException;
+
+ /*
+ * Return list of resolved and unresolved references.
+ * Resolved references already exist in the ATLAS repository and have an assigned unique GUID
+ * Unresolved attribute references result in an error if they are not composite (managed by a parent entity)
+ */
+ EntityGraphDiscoveryContext discoverEntities(List<AtlasEntity> entities) throws AtlasBaseException;
+
+ void cleanUp() throws AtlasBaseException;
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityGraphDiscoveryContext.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityGraphDiscoveryContext.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityGraphDiscoveryContext.java
new file mode 100644
index 0000000..2d748da
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityGraphDiscoveryContext.java
@@ -0,0 +1,170 @@
+/**
+ * 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;
+
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.type.AtlasEntityType;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+public final class EntityGraphDiscoveryContext {
+
+ /**
+ * Keeps track of all the entities that need to be created/updated including its child entities *
+ */
+ private Set<AtlasEntity> rootEntities = new LinkedHashSet<>();
+
+ //Key is a transient id/guid
+ /**
+ * These references have been resolved using a unique identifier like guid or a qualified name etc in Atlas repository
+ */
+ private Map<String, AtlasVertex> repositoryResolvedReferences = new LinkedHashMap<>();
+
+ /**
+ * Unresolved entity references
+ */
+ private List<AtlasEntity> unresolvedEntityReferences = new ArrayList<>();
+
+ /**
+ * Unresolved entity id references
+ */
+ private Set<AtlasObjectId> unresolvedIdReferences = new HashSet<>();
+
+ public void addRepositoryResolvedReference(AtlasObjectId id, AtlasVertex vertex) {
+ repositoryResolvedReferences.put(id.getGuid(), vertex);
+ }
+
+ public void addUnResolvedEntityReference(AtlasEntity entity) {
+ this.unresolvedEntityReferences.add(entity);
+ }
+
+ public void addUnResolvedIdReference(AtlasEntityType entityType, String id) {
+ this.unresolvedIdReferences.add(new AtlasObjectId(entityType.getTypeName(), id));
+ }
+
+ public Set<AtlasObjectId> getUnresolvedIdReferences() {
+ return unresolvedIdReferences;
+ }
+
+ public boolean isResolved(String guid) {
+ return repositoryResolvedReferences.containsKey(guid);
+ }
+
+ public AtlasVertex getResolvedReference(AtlasObjectId ref) {
+ return repositoryResolvedReferences.get(ref.getGuid());
+ }
+
+ public Map<String, AtlasVertex> getRepositoryResolvedReferences() {
+ return repositoryResolvedReferences;
+ }
+
+ public AtlasVertex getResolvedReference(String id) {
+ return repositoryResolvedReferences.get(id);
+ }
+
+ public List<AtlasEntity> getUnResolvedEntityReferences() {
+ return unresolvedEntityReferences;
+ }
+
+ public void addRootEntity(AtlasEntity rootEntity) {
+ this.rootEntities.add(rootEntity);
+ }
+
+ public Collection<AtlasEntity> getRootEntities() {
+ return rootEntities;
+ }
+
+ public boolean removeUnResolvedEntityReference(final AtlasEntity entity) {
+ return unresolvedEntityReferences.remove(entity);
+ }
+
+ public boolean removeUnResolvedEntityReferences(final List<AtlasEntity> entities) {
+ return unresolvedEntityReferences.removeAll(entities);
+ }
+
+ public boolean removeUnResolvedIdReferences(final List<AtlasObjectId> entities) {
+ return unresolvedIdReferences.removeAll(entities);
+ }
+
+ public boolean removeUnResolvedIdReference(final AtlasObjectId entity) {
+ return unresolvedIdReferences.remove(entity);
+ }
+
+ public boolean hasUnresolvedReferences() {
+ return unresolvedEntityReferences.size() > 0 || unresolvedIdReferences.size() > 0;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null) {
+ return false;
+ } else if (obj == this) {
+ return true;
+ } else if (obj.getClass() != getClass()) {
+ return false;
+ } else {
+ EntityGraphDiscoveryContext ctx = (EntityGraphDiscoveryContext) obj;
+ return Objects.equals(rootEntities, ctx.getRootEntities()) &&
+ Objects.equals(repositoryResolvedReferences, ctx.getRepositoryResolvedReferences()) &&
+ Objects.equals(unresolvedEntityReferences, ctx.getUnResolvedEntityReferences()) &&
+ Objects.equals(unresolvedIdReferences, ctx.getUnresolvedIdReferences());
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(rootEntities, repositoryResolvedReferences, unresolvedEntityReferences, unresolvedIdReferences);
+ }
+
+ public StringBuilder toString(StringBuilder sb) {
+ if (sb == null) {
+ sb = new StringBuilder();
+ }
+
+ sb.append("EntityGraphDiscoveryCtx{");
+ sb.append("rootEntities='").append(rootEntities).append('\'');
+ sb.append(", repositoryResolvedReferences=").append(repositoryResolvedReferences);
+ sb.append(", unresolvedEntityReferences='").append(unresolvedEntityReferences).append('\'');
+ sb.append(", unresolvedIdReferences='").append(unresolvedIdReferences).append('\'');
+ sb.append('}');
+
+ return sb;
+ }
+
+ @Override
+ public String toString() {
+ return toString(new StringBuilder()).toString();
+ }
+
+ public void cleanUp() {
+ rootEntities.clear();
+ unresolvedEntityReferences.clear();
+ repositoryResolvedReferences.clear();
+ unresolvedIdReferences.clear();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityResolver.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityResolver.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityResolver.java
new file mode 100644
index 0000000..35ddc7d
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/EntityResolver.java
@@ -0,0 +1,30 @@
+/**
+ * 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;
+
+import org.apache.atlas.exception.AtlasBaseException;
+
+
+public interface EntityResolver {
+
+ void init(EntityGraphDiscoveryContext entities) throws AtlasBaseException;
+
+ EntityGraphDiscoveryContext resolveEntityReferences() throws AtlasBaseException;
+
+ void cleanUp() throws AtlasBaseException;
+}
http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/2f1cb57a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/ArrayVertexMapper.java
----------------------------------------------------------------------
diff --git a/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/ArrayVertexMapper.java b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/ArrayVertexMapper.java
new file mode 100644
index 0000000..528430c
--- /dev/null
+++ b/repository/src/main/java/org/apache/atlas/repository/store/graph/v1/ArrayVertexMapper.java
@@ -0,0 +1,179 @@
+/**
+ * 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.v1;
+
+import com.google.common.base.Optional;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.atlas.aspect.Monitored;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.typedef.AtlasStructDef;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.type.AtlasArrayType;
+import org.apache.atlas.type.AtlasStructType;
+import org.apache.atlas.type.AtlasType;
+import org.apache.commons.collections.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import static org.apache.atlas.repository.graph.GraphHelper.string;
+
+@Singleton
+public class ArrayVertexMapper implements InstanceGraphMapper<List> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ArrayVertexMapper.class);
+
+ protected final DeleteHandlerV1 deleteHandler;
+
+ protected StructVertexMapper structVertexMapper;
+
+ @Inject
+ public ArrayVertexMapper(DeleteHandlerV1 deleteHandler) {
+ this.deleteHandler = deleteHandler;
+ }
+
+ void init(StructVertexMapper structVertexMapper) {
+ this.structVertexMapper = structVertexMapper;
+ }
+
+ @Override
+ public List toGraph(GraphMutationContext ctx) throws AtlasBaseException {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Mapping instance to vertex {} for array attribute {}", string(ctx.getReferringVertex()), ctx.getAttrType().getTypeName());
+ }
+
+ List newElements = (List) ctx.getValue();
+ boolean newAttributeEmpty = (newElements == null || newElements.isEmpty());
+
+ AtlasArrayType arrType = (AtlasArrayType) ctx.getAttrType();
+ AtlasType elementType = arrType.getElementType();
+ List<Object> currentElements = getArrayElementsProperty(elementType, ctx.getReferringVertex(), ctx.getVertexPropertyKey());
+
+ List<Object> newElementsCreated = new ArrayList<>();
+
+ if (!newAttributeEmpty) {
+ for (int index = 0; index < newElements.size(); index++) {
+
+ LOG.debug("Adding/updating element at position {}, current element {}, new element {}", index,
+ (currentElements != null && index < currentElements.size()) ? currentElements.get(index) : null, newElements.get(index));
+
+ Optional<AtlasEdge> existingEdge = getEdgeAt(currentElements, index, arrType.getElementType());
+
+ GraphMutationContext arrCtx = new GraphMutationContext.Builder(ctx.getAttribute(),
+ arrType.getElementType(), newElements.get(index))
+ .referringVertex(ctx.getReferringVertex())
+ .edge(existingEdge)
+ .vertexProperty(ctx.getVertexPropertyKey()).build();
+
+ Object newEntry = structVertexMapper.mapCollectionElementsToVertex(arrCtx);
+ newElementsCreated.add(newEntry);
+ }
+ }
+
+ if (AtlasGraphUtilsV1.isReference(elementType)) {
+ List<AtlasEdge> additionalEdges = removeUnusedArrayEntries(ctx.getParentType(), ctx.getAttributeDef(), (List) currentElements, (List) newElementsCreated, elementType);
+ newElementsCreated.addAll(additionalEdges);
+ }
+
+ // for dereference on way out
+ setArrayElementsProperty(elementType, ctx.getReferringVertex(), ctx.getVertexPropertyKey(), newElementsCreated);
+ return newElementsCreated;
+ }
+
+ @Override
+ public void cleanUp() throws AtlasBaseException {
+
+ }
+
+ //Removes unused edges from the old collection, compared to the new collection
+ private List<AtlasEdge> removeUnusedArrayEntries(
+ AtlasStructType entityType,
+ AtlasStructDef.AtlasAttributeDef attributeDef,
+ List<AtlasEdge> currentEntries,
+ List<AtlasEdge> newEntries,
+ AtlasType entryType) throws AtlasBaseException {
+ if (currentEntries != null && !currentEntries.isEmpty()) {
+ LOG.debug("Removing unused entries from the old collection");
+ if (AtlasGraphUtilsV1.isReference(entryType)) {
+
+ Collection<AtlasEdge> edgesToRemove = CollectionUtils.subtract(currentEntries, newEntries);
+
+ LOG.debug("Removing unused entries from the old collection - {}", edgesToRemove);
+
+ if (!edgesToRemove.isEmpty()) {
+ //Remove the edges for (current edges - new edges)
+ List<AtlasEdge> additionalElements = new ArrayList<>();
+
+ for (AtlasEdge edge : edgesToRemove) {
+ boolean deleteChildReferences = StructVertexMapper.shouldManageChildReferences(entityType, attributeDef.getName());
+ boolean deleted = deleteHandler.deleteEdgeReference(edge, entryType.getTypeCategory(),
+ deleteChildReferences, true);
+ if (!deleted) {
+ additionalElements.add(edge);
+ }
+ }
+
+ return additionalElements;
+ }
+ }
+ }
+ return Collections.emptyList();
+ }
+
+ public static List<Object> getArrayElementsProperty(AtlasType elementType, AtlasVertex instanceVertex, String propertyName) {
+ String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
+ if (AtlasGraphUtilsV1.isReference(elementType)) {
+ return (List)instanceVertex.getListProperty(actualPropertyName, AtlasEdge.class);
+ }
+ else {
+ return (List)instanceVertex.getListProperty(actualPropertyName);
+ }
+ }
+
+ private Optional<AtlasEdge> getEdgeAt(List<Object> currentElements, int index, AtlasType elemType) {
+ Optional<AtlasEdge> existingEdge = Optional.absent();
+ if ( AtlasGraphUtilsV1.isReference(elemType) ) {
+ Object currentElement = (currentElements != null && index < currentElements.size()) ?
+ currentElements.get(index) : null;
+
+ if ( currentElement != null) {
+ existingEdge = Optional.of((AtlasEdge) currentElement);
+ }
+ }
+
+ return existingEdge;
+ }
+
+ private void setArrayElementsProperty(AtlasType elementType, AtlasVertex instanceVertex, String propertyName, List<Object> values) {
+ String actualPropertyName = GraphHelper.encodePropertyKey(propertyName);
+ if (AtlasGraphUtilsV1.isReference(elementType)) {
+ GraphHelper.setListPropertyFromElementIds(instanceVertex, actualPropertyName, (List) values);
+ }
+ else {
+ GraphHelper.setProperty(instanceVertex, actualPropertyName, values);
+ }
+ }
+}