blob: d962385c2cacca911330704754b02baec057732d [file] [log] [blame]
/**
* 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.v2;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.instance.AtlasClassification;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.repository.graphdb.AtlasVertex;
import org.apache.atlas.type.AtlasEntityType;
import org.apache.atlas.type.AtlasStructType.AtlasAttribute;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.utils.AtlasEntityUtil;
import org.apache.commons.collections.MapUtils;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static org.apache.atlas.repository.graph.GraphHelper.getCustomAttributes;
public class AtlasEntityComparator {
private final AtlasTypeRegistry typeRegistry;
private final EntityGraphRetriever entityRetriever;
private final Map<String, String> guidRefMap;
private final boolean skipClassificationCompare;
private final boolean skipBusinessAttributeCompare;
public AtlasEntityComparator(AtlasTypeRegistry typeRegistry, EntityGraphRetriever entityRetriever, Map<String, String> guidRefMap,
boolean skipClassificationCompare, boolean skipBusinessAttributeCompare) {
this.typeRegistry = typeRegistry;
this.entityRetriever = entityRetriever;
this.guidRefMap = guidRefMap;
this.skipClassificationCompare = skipClassificationCompare;
this.skipBusinessAttributeCompare = skipBusinessAttributeCompare;
}
public AtlasEntityDiffResult getDiffResult(AtlasEntity updatedEntity, AtlasEntity storedEntity, boolean findOnlyFirstDiff) throws AtlasBaseException {
return getDiffResult(updatedEntity, storedEntity, null, findOnlyFirstDiff);
}
public AtlasEntityDiffResult getDiffResult(AtlasEntity updatedEntity, AtlasVertex storedVertex, boolean findOnlyFirstDiff) throws AtlasBaseException {
return getDiffResult(updatedEntity, null, storedVertex, findOnlyFirstDiff);
}
private AtlasEntityDiffResult getDiffResult(AtlasEntity updatedEntity, AtlasEntity storedEntity, AtlasVertex storedVertex, boolean findOnlyFirstDiff) throws AtlasBaseException {
AtlasEntity diffEntity = new AtlasEntity(updatedEntity.getTypeName());
AtlasEntityType entityType = typeRegistry.getEntityTypeByName(updatedEntity.getTypeName());
Map<String, AtlasAttribute> entityTypeAttributes = entityType.getAllAttributes();
Map<String, Map<String, AtlasAttribute>> entityTypeRelationshipAttributes = entityType.getRelationshipAttributes();
int sectionsWithDiff = 0;
boolean hasDiffInAttributes = false;
boolean hasDiffInRelationshipAttributes = false;
boolean hasDiffInCustomAttributes = false;
boolean hasDiffInBusinessAttributes = false;
diffEntity.setGuid(updatedEntity.getGuid());
if (MapUtils.isNotEmpty(updatedEntity.getAttributes())) { // check for attribute value change
for (Map.Entry<String, Object> entry : updatedEntity.getAttributes().entrySet()) {
String attrName = entry.getKey();
AtlasAttribute attribute = entityTypeAttributes.get(attrName);
if (attribute == null) { // no such attribute
continue;
}
Object newVal = entry.getValue();
Object currVal = (storedEntity != null) ? storedEntity.getAttribute(attrName) : entityRetriever.getEntityAttribute(storedVertex, attribute);
if (!attribute.getAttributeType().areEqualValues(currVal, newVal, guidRefMap)) {
hasDiffInAttributes = true;
diffEntity.setAttribute(attrName, newVal);
if (findOnlyFirstDiff) {
return new AtlasEntityDiffResult(diffEntity, true, false, false);
}
}
}
if (hasDiffInAttributes) {
sectionsWithDiff++;
}
}
if (MapUtils.isNotEmpty(updatedEntity.getRelationshipAttributes())) { // check for relationship-attribute value change
for (Map.Entry<String, Object> entry : updatedEntity.getRelationshipAttributes().entrySet()) {
String attrName = entry.getKey();
if (!entityTypeRelationshipAttributes.containsKey(attrName)) { // no such attribute
continue;
}
Object newVal = entry.getValue();
String relationshipType = AtlasEntityUtil.getRelationshipType(newVal);
AtlasAttribute attribute = entityType.getRelationshipAttribute(attrName, relationshipType);
Object currVal = (storedEntity != null) ? storedEntity.getRelationshipAttribute(attrName) : entityRetriever.getEntityAttribute(storedVertex, attribute);
if (!attribute.getAttributeType().areEqualValues(currVal, newVal, guidRefMap)) {
hasDiffInRelationshipAttributes = true;
diffEntity.setRelationshipAttribute(attrName, newVal);
if (findOnlyFirstDiff) {
return new AtlasEntityDiffResult(diffEntity, true, false, false);
}
}
}
if (hasDiffInRelationshipAttributes) {
sectionsWithDiff++;
}
}
if (!skipClassificationCompare) {
List<AtlasClassification> newVal = updatedEntity.getClassifications();
List<AtlasClassification> currVal = (storedEntity != null) ? storedEntity.getClassifications() : entityRetriever.getAllClassifications(storedVertex);
if (!Objects.equals(currVal, newVal)) {
diffEntity.setClassifications(newVal);
sectionsWithDiff++;
if (findOnlyFirstDiff) {
return new AtlasEntityDiffResult(diffEntity, true, false, false);
}
}
}
if (updatedEntity.getCustomAttributes() != null) {
// event coming from hook does not have custom attributes, such events must not remove existing attributes
// UI sends empty object in case of of intended removal.
Map<String, String> newCustomAttributes = updatedEntity.getCustomAttributes();
Map<String, String> currCustomAttributes = (storedEntity != null) ? storedEntity.getCustomAttributes() : getCustomAttributes(storedVertex);
if (!Objects.equals(currCustomAttributes, newCustomAttributes)) {
diffEntity.setCustomAttributes(newCustomAttributes);
hasDiffInCustomAttributes = true;
sectionsWithDiff++;
if (findOnlyFirstDiff && sectionsWithDiff > 1) {
return new AtlasEntityDiffResult(diffEntity, true, false, false);
}
}
}
if (!skipBusinessAttributeCompare) {
Map<String, Map<String, Object>> newBusinessMetadata = updatedEntity.getBusinessAttributes();
Map<String, Map<String, Object>> currBusinessMetadata = (storedEntity != null) ? storedEntity.getBusinessAttributes() : entityRetriever.getBusinessMetadata(storedVertex);;
if (!Objects.equals(currBusinessMetadata, newBusinessMetadata)) {
diffEntity.setBusinessAttributes(newBusinessMetadata);
hasDiffInBusinessAttributes = true;
sectionsWithDiff++;
if (findOnlyFirstDiff && sectionsWithDiff > 1) {
return new AtlasEntityDiffResult(diffEntity, true, false, false);
}
}
}
return new AtlasEntityDiffResult(diffEntity, sectionsWithDiff > 0, sectionsWithDiff == 1 && hasDiffInCustomAttributes, sectionsWithDiff == 1 && hasDiffInBusinessAttributes);
}
public static class AtlasEntityDiffResult {
private final AtlasEntity diffEntity;
private final boolean hasDifference;
private final boolean hasDifferenceOnlyInCustomAttributes;
private final boolean hasDifferenceOnlyInBusinessAttributes;
AtlasEntityDiffResult(AtlasEntity diffEntity, boolean hasDifference, boolean hasDifferenceOnlyInCustomAttributes, boolean hasDifferenceOnlyInBusinessAttributes) {
this.diffEntity = diffEntity;
this.hasDifference = hasDifference;
this.hasDifferenceOnlyInCustomAttributes = hasDifferenceOnlyInCustomAttributes;
this.hasDifferenceOnlyInBusinessAttributes = hasDifferenceOnlyInBusinessAttributes;
}
public AtlasEntity getDiffEntity() {
return diffEntity;
}
public boolean hasDifference() {
return hasDifference;
}
public boolean hasDifferenceOnlyInCustomAttributes() {
return hasDifferenceOnlyInCustomAttributes;
}
public boolean hasDifferenceOnlyInBusinessAttributes() {
return hasDifferenceOnlyInBusinessAttributes;
}
}
}