blob: 8a161e4201c17edd096a5139a5554d802f0a6e9e [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.glossary;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.RequestContext;
import org.apache.atlas.bulkimport.BulkImportResponse;
import org.apache.atlas.bulkimport.BulkImportResponse.ImportInfo;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.glossary.AtlasGlossary;
import org.apache.atlas.model.glossary.AtlasGlossaryTerm;
import org.apache.atlas.model.glossary.relations.AtlasGlossaryHeader;
import org.apache.atlas.model.glossary.relations.AtlasRelatedTermHeader;
import org.apache.atlas.model.glossary.relations.AtlasTermCategorizationHeader;
import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.instance.AtlasRelatedObjectId;
import org.apache.atlas.model.instance.AtlasRelationship;
import org.apache.atlas.model.instance.AtlasStruct;
import org.apache.atlas.repository.graphdb.AtlasVertex;
import org.apache.atlas.repository.ogm.DataAccess;
import org.apache.atlas.repository.store.graph.AtlasRelationshipStore;
import org.apache.atlas.repository.store.graph.v2.AtlasGraphUtilsV2;
import org.apache.atlas.type.AtlasRelationshipType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.util.FileUtils;
import org.apache.atlas.utils.AtlasPerfMetrics;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.atlas.bulkimport.BulkImportResponse.ImportStatus.FAILED;
public class GlossaryTermUtils extends GlossaryUtils {
private static final Logger LOG = LoggerFactory.getLogger(GlossaryTermUtils.class);
private static final boolean DEBUG_ENABLED = LOG.isDebugEnabled();
private static final int INDEX_FOR_GLOSSARY_AT_RECORD = 0;
private static final int INDEX_FOR_TERM_AT_RECORD = 1;
private static final ThreadLocal<Map<String, String>> glossaryNameGuidCache = ThreadLocal.withInitial(() -> new LinkedHashMap<>());
private static final ThreadLocal<Map<String, Integer>> glossaryTermOrderCache = ThreadLocal.withInitial(() -> new HashMap<>());
private static final ThreadLocal<Map<String, String>> glossaryTermQNameGuidCache = ThreadLocal.withInitial(() -> new HashMap<>());
protected GlossaryTermUtils(AtlasRelationshipStore relationshipStore, AtlasTypeRegistry typeRegistry, DataAccess dataAccess) {
super(relationshipStore, typeRegistry, dataAccess);
}
public void processTermRelations(AtlasGlossaryTerm storeObject, AtlasGlossaryTerm updatedTerm, RelationshipOperation op) throws AtlasBaseException {
if (DEBUG_ENABLED) {
LOG.debug("==> GlossaryTermUtils.processTermRelations({}, {}, {})", storeObject, updatedTerm, op);
}
processTermAnchor(storeObject, updatedTerm, op);
processRelatedTerms(storeObject, updatedTerm, op);
processAssociatedCategories(storeObject, updatedTerm, op);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryTermUtils.processTermRelations()");
}
}
public void processTermAssignments(AtlasGlossaryTerm glossaryTerm, Collection<AtlasRelatedObjectId> relatedObjectIds) throws AtlasBaseException {
if (DEBUG_ENABLED) {
LOG.debug("==> GlossaryTermUtils.processTermAssignments({}, {})", glossaryTerm, relatedObjectIds);
}
Objects.requireNonNull(glossaryTerm);
Set<AtlasRelatedObjectId> assignedEntities = glossaryTerm.getAssignedEntities();
for (AtlasRelatedObjectId objectId : relatedObjectIds) {
if (CollectionUtils.isNotEmpty(assignedEntities) && assignedEntities.contains(objectId)) {
if (DEBUG_ENABLED) {
LOG.debug("Skipping already assigned entity {}", objectId);
continue;
}
}
if (DEBUG_ENABLED) {
LOG.debug("Assigning term guid={}, to entity guid = {}", glossaryTerm.getGuid(), objectId.getGuid());
}
createRelationship(defineTermAssignment(glossaryTerm.getGuid(), objectId));
}
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryTermUtils.processTermAssignments()");
}
}
public void processTermDissociation(AtlasGlossaryTerm glossaryTerm, Collection<AtlasRelatedObjectId> relatedObjectIds) throws AtlasBaseException {
if (DEBUG_ENABLED) {
LOG.debug("==> GlossaryTermUtils.processTermDissociation({}, {}, {})", glossaryTerm.getGuid(), relatedObjectIds, glossaryTerm);
}
Objects.requireNonNull(glossaryTerm);
Set<AtlasRelatedObjectId> assignedEntities = glossaryTerm.getAssignedEntities();
Map<String, AtlasRelatedObjectId> assignedEntityMap = new HashMap<>();
if (CollectionUtils.isNotEmpty(assignedEntities)) {
for (AtlasRelatedObjectId relatedObjectId : assignedEntities) {
assignedEntityMap.put(relatedObjectId.getGuid(), relatedObjectId);
}
}
if (CollectionUtils.isNotEmpty(relatedObjectIds)) {
for (AtlasRelatedObjectId relatedObjectId : relatedObjectIds) {
if (DEBUG_ENABLED) {
LOG.debug("Removing term guid={}, from entity guid = {}", glossaryTerm.getGuid(), relatedObjectId.getGuid());
}
if (Objects.isNull(relatedObjectId.getRelationshipGuid())) {
throw new AtlasBaseException(AtlasErrorCode.TERM_DISSOCIATION_MISSING_RELATION_GUID);
}
AtlasRelatedObjectId existingTermRelation = assignedEntityMap.get(relatedObjectId.getGuid());
if (CollectionUtils.isNotEmpty(assignedEntities) && isRelationshipGuidSame(existingTermRelation, relatedObjectId)) {
relationshipStore.deleteById(relatedObjectId.getRelationshipGuid(), true);
} else {
throw new AtlasBaseException(AtlasErrorCode.INVALID_TERM_DISSOCIATION, relatedObjectId.getRelationshipGuid(), glossaryTerm.getGuid(), relatedObjectId.getGuid());
}
}
}
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryTermUtils.processTermDissociation()");
}
}
public void clearImportCache() {
glossaryNameGuidCache.get().clear();
glossaryTermOrderCache.get().clear();
glossaryTermQNameGuidCache.get().clear();
}
private boolean isRelationshipGuidSame(AtlasRelatedObjectId storeObject, AtlasRelatedObjectId relatedObjectId) {
return StringUtils.equals(relatedObjectId.getRelationshipGuid(), storeObject.getRelationshipGuid());
}
private void processTermAnchor(AtlasGlossaryTerm currentTerm, AtlasGlossaryTerm updatedTerm, RelationshipOperation op) throws AtlasBaseException {
if (Objects.isNull(updatedTerm.getAnchor()) && op != RelationshipOperation.DELETE) {
throw new AtlasBaseException(AtlasErrorCode.MISSING_MANDATORY_ANCHOR);
}
AtlasGlossaryHeader currentTermGlossary = currentTerm.getAnchor(); // glossary_g1
AtlasGlossaryHeader updatedTermGlossary = updatedTerm.getAnchor(); // glossary_g2
String updatedTermGlossaryGuid = updatedTermGlossary.getGlossaryGuid();
String currentTermGlossaryGuid = currentTermGlossary.getGlossaryGuid();
switch (op) {
case CREATE:
if (Objects.isNull(updatedTermGlossaryGuid)) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_NEW_ANCHOR_GUID);
} else {
if (DEBUG_ENABLED) {
LOG.debug("Creating new term anchor, category = {}, glossary = {}", currentTerm.getGuid(), updatedTerm.getAnchor().getGlossaryGuid());
}
if (!StringUtils.equals(updatedTermGlossaryGuid, currentTermGlossaryGuid)) {
createRelationship(defineTermAnchorRelation(updatedTermGlossaryGuid, currentTerm.getGuid()));
}
}
break;
case UPDATE:
if (!Objects.equals(updatedTermGlossary, currentTermGlossary)) {
if (Objects.isNull(updatedTermGlossaryGuid)) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_NEW_ANCHOR_GUID);
}
if (DEBUG_ENABLED) {
LOG.debug("Updating term anchor, currAnchor = {}, newAnchor = {} and term = {}",
currentTermGlossaryGuid,
updatedTermGlossaryGuid,
currentTerm.getName());
}
relationshipStore.deleteById(currentTermGlossary.getRelationGuid(), true);
// Derive the qualifiedName when anchor changes
String anchorGlossaryGuid = updatedTermGlossaryGuid;
AtlasGlossary glossary = dataAccess.load(getGlossarySkeleton(anchorGlossaryGuid));
currentTerm.setQualifiedName(currentTerm.getName() + "@" + glossary.getQualifiedName());
if (LOG.isDebugEnabled()) {
LOG.debug("Derived qualifiedName = {}", currentTerm.getQualifiedName());
}
createRelationship(defineTermAnchorRelation(updatedTermGlossaryGuid, currentTerm.getGuid()));
}
break;
case DELETE:
if (Objects.nonNull(currentTermGlossary)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting term anchor");
}
relationshipStore.deleteById(currentTermGlossary.getRelationGuid(), true);
}
break;
}
}
private void processRelatedTerms(AtlasGlossaryTerm storeObject, AtlasGlossaryTerm updatedTerm, RelationshipOperation op) throws AtlasBaseException {
Map<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> newRelatedTerms = updatedTerm.getRelatedTerms();
Map<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> existingRelatedTerms = storeObject.getRelatedTerms();
switch (op) {
case CREATE:
for (Map.Entry<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> entry : newRelatedTerms.entrySet()) {
AtlasGlossaryTerm.Relation relation = entry.getKey();
Set<AtlasRelatedTermHeader> terms = entry.getValue();
if (Objects.nonNull(terms)) {
if (DEBUG_ENABLED) {
LOG.debug("{} relation {} for term = {}", op, relation, storeObject.getGuid());
LOG.debug("Related Term count = {}", terms.size());
}
createTermRelationships(storeObject, relation, terms);
}
}
break;
case UPDATE:
for (AtlasGlossaryTerm.Relation relation : AtlasGlossaryTerm.Relation.values()) {
Map<String, AtlasRelatedTermHeader> existingTermHeaders = getRelatedTermHeaders(existingRelatedTerms, relation);
Map<String, AtlasRelatedTermHeader> newTermHeaders = getRelatedTermHeaders(newRelatedTerms, relation);
// No existing term relations, create all
if (MapUtils.isEmpty(existingTermHeaders)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new term relations, relation = {}, terms = {}", relation,
Objects.nonNull(newTermHeaders) ? newTermHeaders.size() : "none");
}
createTermRelationships(storeObject, relation, newTermHeaders.values());
continue;
}
// Existing term relations but nothing in updated object, remove all
if (MapUtils.isEmpty(newTermHeaders)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting existing term relations, relation = {}, terms = {}", relation, existingTermHeaders.size());
}
deleteTermRelationships(relation, existingTermHeaders.values());
continue;
}
// Determine what to update, delete or create
Set<AtlasRelatedTermHeader> toCreate = newTermHeaders
.values()
.stream()
.filter(t -> !existingTermHeaders.containsKey(t.getTermGuid()))
.collect(Collectors.toSet());
Set<AtlasRelatedTermHeader> toUpdate = newTermHeaders
.values()
.stream()
.filter(t -> updatedExistingTermRelation(existingTermHeaders, t))
.collect(Collectors.toSet());
Set<AtlasRelatedTermHeader> toDelete = existingTermHeaders
.values()
.stream()
.filter(t -> !newTermHeaders.containsKey(t.getTermGuid()))
.collect(Collectors.toSet());
createTermRelationships(storeObject, relation, toCreate);
updateTermRelationships(relation, toUpdate);
deleteTermRelationships(relation, toDelete);
}
break;
case DELETE:
for (AtlasGlossaryTerm.Relation relation : AtlasGlossaryTerm.Relation.values()) {
// No existing term relations, create all
Set<AtlasRelatedTermHeader> existingTermHeaders = existingRelatedTerms.get(relation);
deleteTermRelationships(relation, existingTermHeaders);
}
break;
}
}
private Map<String, AtlasRelatedTermHeader> getRelatedTermHeaders(Map<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> relatedTerms, AtlasGlossaryTerm.Relation relation) {
if (Objects.nonNull(relatedTerms.get(relation))) {
Map<String, AtlasRelatedTermHeader> map = new HashMap<>();
for (AtlasRelatedTermHeader t : relatedTerms.get(relation)) {
AtlasRelatedTermHeader header = map.get(t.getTermGuid());
if (header == null || (StringUtils.isEmpty(header.getRelationGuid()) && StringUtils.isNotEmpty(t.getRelationGuid()))) {
map.put(t.getTermGuid(), t);
}
}
return map;
} else {
return Collections.emptyMap();
}
}
private boolean updatedExistingTermRelation(Map<String, AtlasRelatedTermHeader> existingTermHeaders, AtlasRelatedTermHeader header) {
return Objects.nonNull(header.getRelationGuid()) && !header.equals(existingTermHeaders.get(header.getTermGuid()));
}
private void processAssociatedCategories(AtlasGlossaryTerm storeObject, AtlasGlossaryTerm updatedTerm, RelationshipOperation op) throws AtlasBaseException {
Map<String, AtlasTermCategorizationHeader> newCategories = getAssociatedCategories(updatedTerm);
Map<String, AtlasTermCategorizationHeader> existingCategories = getAssociatedCategories(storeObject);
switch (op) {
case CREATE:
if (Objects.nonNull(newCategories)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new term categorization, term = {}, categories = {}", storeObject.getGuid(), newCategories.size());
}
createTermCategorizationRelationships(storeObject, newCategories.values());
}
break;
case UPDATE:
// If no existing categories are present then create all existing ones
if (MapUtils.isEmpty(existingCategories)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new term categorization, term = {}, categories = {}", storeObject.getGuid(),
Objects.nonNull(newCategories) ? newCategories.size() : "none");
}
createTermCategorizationRelationships(storeObject, newCategories.values());
break;
}
// If no new categories are present then delete all existing ones
if (MapUtils.isEmpty(newCategories)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting term categorization, term = {}, categories = {}", storeObject.getGuid(), existingCategories.size());
}
deleteCategorizationRelationship(existingCategories.values());
break;
}
Set<AtlasTermCategorizationHeader> toCreate = newCategories
.values()
.stream()
.filter(c -> !existingCategories.containsKey(c.getCategoryGuid()))
.collect(Collectors.toSet());
createTermCategorizationRelationships(storeObject, toCreate);
Set<AtlasTermCategorizationHeader> toUpdate = newCategories
.values()
.stream()
.filter(c -> updatedExistingCategorizationRelation(existingCategories, c))
.collect(Collectors.toSet());
updateTermCategorizationRelationships(storeObject, toUpdate);
Set<AtlasTermCategorizationHeader> toDelete = existingCategories
.values()
.stream()
.filter(c -> !newCategories.containsKey(c.getCategoryGuid()))
.collect(Collectors.toSet());
deleteCategorizationRelationship(toDelete);
break;
case DELETE:
deleteCategorizationRelationship(existingCategories.values());
break;
}
}
private boolean updatedExistingCategorizationRelation(Map<String, AtlasTermCategorizationHeader> existingCategories, AtlasTermCategorizationHeader header) {
return Objects.nonNull(header.getRelationGuid()) && !header.equals(existingCategories.get(header.getCategoryGuid()));
}
private Map<String, AtlasTermCategorizationHeader> getAssociatedCategories(AtlasGlossaryTerm term) {
if (Objects.nonNull(term.getCategories())) {
Map<String, AtlasTermCategorizationHeader> map = new HashMap<>();
for (AtlasTermCategorizationHeader c : term.getCategories()) {
AtlasTermCategorizationHeader header = map.get(c.getCategoryGuid());
if (header == null || (StringUtils.isEmpty(header.getRelationGuid()) && StringUtils.isNotEmpty(c.getRelationGuid()))) {
map.put(c.getCategoryGuid(), c);
}
}
return map;
} else {
return Collections.emptyMap();
}
}
private void createTermCategorizationRelationships(AtlasGlossaryTerm storeObject, Collection<AtlasTermCategorizationHeader> categories) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(categories)) {
Set<AtlasTermCategorizationHeader> existingCategories = storeObject.getCategories();
for (AtlasTermCategorizationHeader categorizationHeader : categories) {
if (Objects.nonNull(existingCategories) && existingCategories.contains(categorizationHeader)) {
if (DEBUG_ENABLED) {
LOG.debug("Skipping existing category guid={}", categorizationHeader.getCategoryGuid());
}
continue;
}
if (DEBUG_ENABLED) {
LOG.debug("Creating relation between term = {} and category = {}", storeObject.getGuid(), categorizationHeader.getDisplayText());
}
createRelationship(defineCategorizedTerm(categorizationHeader, storeObject.getGuid()));
}
}
}
private void updateTermCategorizationRelationships(AtlasGlossaryTerm storeObject, Collection<AtlasTermCategorizationHeader> toUpdate) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(toUpdate)) {
for (AtlasTermCategorizationHeader categorizationHeader : toUpdate) {
if (DEBUG_ENABLED) {
LOG.debug("Updating relation between term = {} and category = {}", storeObject.getGuid(), categorizationHeader.getDisplayText());
}
AtlasRelationship relationship = relationshipStore.getById(categorizationHeader.getRelationGuid());
updateRelationshipAttributes(relationship, categorizationHeader);
relationshipStore.update(relationship);
}
}
}
private void deleteCategorizationRelationship(Collection<AtlasTermCategorizationHeader> existingCategories) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(existingCategories)) {
for (AtlasTermCategorizationHeader categorizationHeader : existingCategories) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting relation guid = {}, text = {}", categorizationHeader.getRelationGuid(), categorizationHeader.getDisplayText());
}
relationshipStore.deleteById(categorizationHeader.getRelationGuid(), true);
}
}
}
private void createTermRelationships(AtlasGlossaryTerm storeObject, AtlasGlossaryTerm.Relation relation, Collection<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
Map<String, AtlasRelatedTermHeader> existingRelations;
if (Objects.nonNull(storeObject.getRelatedTerms()) && Objects.nonNull(storeObject.getRelatedTerms().get(relation))) {
Map<String, AtlasRelatedTermHeader> map = new HashMap<>();
for (AtlasRelatedTermHeader t : storeObject.getRelatedTerms().get(relation)) {
AtlasRelatedTermHeader header = map.get(t.getTermGuid());
if (header == null || (StringUtils.isEmpty(header.getRelationGuid()) && StringUtils.isNotEmpty(t.getRelationGuid()))) {
map.put(t.getTermGuid(), t);
}
}
existingRelations = map;
} else {
existingRelations = Collections.emptyMap();
}
for (AtlasRelatedTermHeader term : terms) {
if (existingRelations.containsKey(term.getTermGuid())) {
if (DEBUG_ENABLED) {
LOG.debug("Skipping existing term relation termGuid={}", term.getTermGuid());
}
continue;
}
if (storeObject.getGuid().equals(term.getTermGuid())) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_TERM_RELATION_TO_SELF);
}
if (DEBUG_ENABLED) {
LOG.debug("Creating new term relation = {}, terms = {}", relation, term.getDisplayText());
}
createRelationship(defineTermRelation(relation, storeObject.getGuid(), term));
}
}
}
private void updateTermRelationships(AtlasGlossaryTerm.Relation relation, Collection<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
for (AtlasRelatedTermHeader term : terms) {
if (DEBUG_ENABLED) {
LOG.debug("Updating term relation = {}, terms = {}", relation, term.getDisplayText());
}
AtlasRelationship relationship = relationshipStore.getById(term.getRelationGuid());
updateRelationshipAttributes(relationship, term);
relationshipStore.update(relationship);
}
}
}
private void deleteTermRelationships(AtlasGlossaryTerm.Relation relation, Collection<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
for (AtlasRelatedTermHeader termHeader : terms) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting term relation = {}, terms = {}", relation, termHeader.getDisplayText());
}
relationshipStore.deleteById(termHeader.getRelationGuid(), true);
}
}
}
private AtlasRelationship defineTermAnchorRelation(String glossaryGuid, String termGuid) {
AtlasRelationshipType relationshipType = typeRegistry.getRelationshipTypeByName(TERM_ANCHOR);
AtlasStruct defaultAttrs = relationshipType.createDefaultValue();
return new AtlasRelationship(TERM_ANCHOR, new AtlasObjectId(glossaryGuid), new AtlasObjectId(termGuid), defaultAttrs.getAttributes());
}
private AtlasRelationship defineTermRelation(AtlasGlossaryTerm.Relation relation, String end1TermGuid, AtlasRelatedTermHeader end2RelatedTerm) {
AtlasRelationshipType relationshipType = typeRegistry.getRelationshipTypeByName(relation.getName());
AtlasStruct defaultAttrs = relationshipType.createDefaultValue();
AtlasRelationship relationship;
// End1 and End2 ObjectIds depend on the attribute
if (relation.isEnd2Attr()) {
relationship = new AtlasRelationship(relation.getName(), new AtlasObjectId(end2RelatedTerm.getTermGuid()), new AtlasObjectId(end1TermGuid), defaultAttrs.getAttributes());
} else {
relationship = new AtlasRelationship(relation.getName(), new AtlasObjectId(end1TermGuid), new AtlasObjectId(end2RelatedTerm.getTermGuid()), defaultAttrs.getAttributes());
}
updateRelationshipAttributes(relationship, end2RelatedTerm);
return relationship;
}
private AtlasRelationship defineCategorizedTerm(AtlasTermCategorizationHeader relatedCategoryId, String termId) {
AtlasRelationshipType relationshipType = typeRegistry.getRelationshipTypeByName(TERM_CATEGORIZATION);
AtlasStruct defaultAttrs = relationshipType.createDefaultValue();
AtlasRelationship relationship = new AtlasRelationship(TERM_CATEGORIZATION, new AtlasObjectId(relatedCategoryId.getCategoryGuid()), new AtlasObjectId(termId), defaultAttrs.getAttributes());
updateRelationshipAttributes(relationship, relatedCategoryId);
return relationship;
}
private AtlasRelationship defineTermAssignment(String termGuid, AtlasRelatedObjectId relatedObjectId) {
AtlasRelationshipType relationshipType = typeRegistry.getRelationshipTypeByName(TERM_ASSIGNMENT);
AtlasStruct defaultAttrs = relationshipType.createDefaultValue();
AtlasObjectId end1 = new AtlasObjectId(termGuid);
AtlasRelationship relationship = new AtlasRelationship(TERM_ASSIGNMENT, end1, relatedObjectId, defaultAttrs.getAttributes());
updateRelationshipAttributes(relationship, relatedObjectId);
return relationship;
}
private void updateRelationshipAttributes(AtlasRelationship relationship, AtlasTermCategorizationHeader categorizationHeader) {
if (Objects.nonNull(relationship)) {
relationship.setAttribute(TERM_RELATION_ATTR_DESCRIPTION, categorizationHeader.getDescription());
if (Objects.nonNull(categorizationHeader.getStatus())) {
relationship.setAttribute(TERM_RELATION_ATTR_STATUS, categorizationHeader.getStatus().name());
}
}
}
private void updateRelationshipAttributes(AtlasRelationship relationship, AtlasRelatedObjectId relatedObjectId) {
AtlasStruct relationshipAttributes = relatedObjectId.getRelationshipAttributes();
if (Objects.nonNull(relationshipAttributes)) {
for (Map.Entry<String, Object> attrEntry : relationshipAttributes.getAttributes().entrySet()) {
relationship.setAttribute(attrEntry.getKey(), attrEntry.getValue());
}
}
}
protected List<AtlasGlossaryTerm> getGlossaryTermDataWithoutRelations(List<String[]> fileData, BulkImportResponse bulkImportResponse) throws AtlasBaseException {
List<AtlasGlossaryTerm> glossaryTerms = new ArrayList<>();
int rowCount = 1;
for (String[] record : fileData) {
List<String> failedTermMsgs = new ArrayList<>();
AtlasGlossaryTerm glossaryTerm = new AtlasGlossaryTerm();
String glossaryName = StringUtils.EMPTY;
if (ArrayUtils.isEmpty(record) || StringUtils.isBlank(record[INDEX_FOR_GLOSSARY_AT_RECORD])) {
LOG.error("The GlossaryName is blank for the record : ", Arrays.toString(record));
failedTermMsgs.add("The GlossaryName is blank for the record : " + Arrays.toString(record));
} else {
glossaryName = record[INDEX_FOR_GLOSSARY_AT_RECORD];
String glossaryGuid = glossaryNameGuidCache.get().get(glossaryName);
if (StringUtils.isEmpty(glossaryGuid)) {
glossaryGuid = getGlossaryGUIDFromGraphDB(glossaryName);
if (StringUtils.isEmpty(glossaryGuid)) {
glossaryGuid = createGlossary(glossaryName, failedTermMsgs);
}
glossaryNameGuidCache.get().put(glossaryName, glossaryGuid);
}
if (StringUtils.isNotEmpty(glossaryGuid)) {
glossaryTerm = populateGlossaryTermObject(failedTermMsgs, record, glossaryGuid, false);
glossaryTerm.setQualifiedName(getGlossaryTermQualifiedName(glossaryTerm.getName(), glossaryName));
glossaryTermOrderCache.get().put(glossaryTerm.getQualifiedName(), rowCount);
glossaryTerms.add(glossaryTerm);
}
}
if (failedTermMsgs.size() > 0) {
String failedTermMsg = StringUtils.join(failedTermMsgs, System.lineSeparator());
String glossaryTermName = glossaryTerm.getName();
bulkImportResponse.addToFailedImportInfoList(new ImportInfo(glossaryName, glossaryTermName, FAILED, failedTermMsg, rowCount));
}
rowCount++;
}
return glossaryTerms;
}
protected List<AtlasGlossaryTerm> getGlossaryTermDataWithRelations(List<String[]> fileData, BulkImportResponse bulkImportResponse) throws AtlasBaseException {
List<AtlasGlossaryTerm> glossaryTerms = new ArrayList<>();
int rowCount = 1;
for (String[] record : fileData) {
List<String> failedTermMsgs = new ArrayList<>();
if (ArrayUtils.isNotEmpty(record) && StringUtils.isNotBlank(record[INDEX_FOR_GLOSSARY_AT_RECORD])) {
AtlasGlossaryTerm glossaryTerm = new AtlasGlossaryTerm();
String glossaryName = record[INDEX_FOR_GLOSSARY_AT_RECORD];
String glossaryGuid = glossaryNameGuidCache.get().get(glossaryName);
if (StringUtils.isNotEmpty(glossaryGuid)) {
glossaryTerm = populateGlossaryTermObject(failedTermMsgs, record, glossaryGuid, true);
glossaryTerm.setQualifiedName(getGlossaryTermQualifiedName(glossaryTerm.getName(), glossaryName));
glossaryTerms.add(glossaryTerm);
}
if (failedTermMsgs.size() > 0) {
String failedTermMsg = StringUtils.join(failedTermMsgs, System.lineSeparator());
String glossaryTermName = glossaryTerm.getName();
bulkImportResponse.addToFailedImportInfoList(new ImportInfo(glossaryName, glossaryTermName, FAILED, failedTermMsg, rowCount));
}
}
rowCount++;
}
return glossaryTerms;
}
public static String getGlossaryTermHeaders() {
List<String> ret = new ArrayList<>();
ret.add("GlossaryName");
ret.add("TermName");
ret.add("ShortDescription");
ret.add("LongDescription");
ret.add("Examples");
ret.add("Abbreviation");
ret.add("Usage");
ret.add("AdditionalAttributes");
ret.add("TranslationTerms");
ret.add("ValidValuesFor");
ret.add("Synonyms");
ret.add("ReplacedBy");
ret.add("ValidValues");
ret.add("ReplacementTerms");
ret.add("SeeAlso");
ret.add("TranslatedTerms");
ret.add("IsA");
ret.add("Antonyms");
ret.add("Classifies");
ret.add("PreferredToTerms");
ret.add("PreferredTerms");
return String.join(", ", ret);
}
public void updateGlossaryTermRelations(AtlasGlossaryTerm updatedGlossaryTerm) {
if (glossaryTermQNameGuidCache.get().containsKey(updatedGlossaryTerm.getQualifiedName())) {
try {
AtlasGlossaryTerm glossaryTermFromDB = getGlossaryTem(glossaryTermQNameGuidCache.get().get(updatedGlossaryTerm.getQualifiedName()));
copyRelations(updatedGlossaryTerm, glossaryTermFromDB);
} catch (AtlasBaseException e) {
if (DEBUG_ENABLED) {
LOG.debug("Error occurred while loading glossary Term", e);
}
}
}
}
protected Map getMapValue(String csvRecord, List<String> failedTermMsgs, boolean populateRelations) {
Map ret = null;
if (StringUtils.isNotBlank(csvRecord)) {
ret = new HashMap<>();
String csvRecordArray[] = csvRecord.split(FileUtils.ESCAPE_CHARACTER + FileUtils.PIPE_CHARACTER);
String recordArray[];
for (String record : csvRecordArray) {
recordArray = record.split(FileUtils.COLON_CHARACTER);
if ((recordArray.length % 2) == 0) {
ret.put(recordArray[0], recordArray[1]);
} else if (!populateRelations) {
failedTermMsgs.add("The Data in the uploaded file is incorrectly specified : " + csvRecord
+ System.lineSeparator() + "AdditionalAttributes needs to be a key:value pair");
}
}
}
return ret;
}
protected List getListValue(String csvRecord) {
List ret = null;
if (StringUtils.isNotBlank(csvRecord)) {
ret = Arrays.asList(csvRecord.split(FileUtils.ESCAPE_CHARACTER + FileUtils.PIPE_CHARACTER));
}
return ret;
}
protected Set getAtlasRelatedTermHeaderSet(String csvRecord, String termName, String glossaryName, List<String> failedTermMsgs) {
Set ret = null;
if (StringUtils.isNotBlank(csvRecord)) {
ret = new HashSet();
String csvRecordArray[] = csvRecord.split(FileUtils.ESCAPE_CHARACTER + FileUtils.PIPE_CHARACTER);
AtlasRelatedTermHeader relatedTermHeader;
for (String data : csvRecordArray) {
AtlasVertex vertex = null;
String dataArray[] = data.split(FileUtils.ESCAPE_CHARACTER + FileUtils.COLON_CHARACTER);
if (dataArray.length == 2) {
String relatedTermQualifiedName = dataArray[1] + invalidNameChars[0] + dataArray[0];
String currTermQualifiedName = termName + invalidNameChars[0] + glossaryName;
if (relatedTermQualifiedName.equalsIgnoreCase(currTermQualifiedName)) {
failedTermMsgs.add("Invalid relationship specified for Term. Term cannot have a relationship with self");
} else {
vertex = AtlasGraphUtilsV2.findByTypeAndUniquePropertyName(GlossaryUtils.ATLAS_GLOSSARY_TERM_TYPENAME,
GlossaryUtils.ATLAS_GLOSSARY_TERM_TYPENAME + invalidNameChars[1] + QUALIFIED_NAME_ATTR, relatedTermQualifiedName);
if (vertex != null) {
String glossaryTermGuid = AtlasGraphUtilsV2.getIdFromVertex(vertex);
relatedTermHeader = new AtlasRelatedTermHeader();
relatedTermHeader.setTermGuid(glossaryTermGuid);
cacheRelatedTermQNameGuid(currTermQualifiedName, relatedTermQualifiedName, glossaryTermGuid);
ret.add(relatedTermHeader);
} else {
failedTermMsgs.add("The provided Reference " + dataArray[1] + "@" + dataArray[0] +
" does not exist at Atlas referred at record with TermName : " + termName + " and GlossaryName : " + glossaryName);
}
}
} else {
failedTermMsgs.add("Incorrect relation data specified for the term : " + termName + "@" + glossaryName);
}
}
}
return ret;
}
protected AtlasGlossaryTerm populateGlossaryTermObject(List<String> failedTermMsgList, String[] record, String glossaryGuid, boolean populateRelations) {
int length = record.length;
int i = INDEX_FOR_TERM_AT_RECORD;
AtlasGlossaryTerm ret = new AtlasGlossaryTerm();
if (length > i) {
ret.setName(record[i]);
}
if (StringUtils.isBlank(ret.getName())) {
if (!populateRelations) {
failedTermMsgList.add("The TermName is blank for provided record: " + Arrays.toString(record));
}
} else {
ret.setAnchor(new AtlasGlossaryHeader(glossaryGuid));
ret.setShortDescription((length > ++i) ? record[i] : null);
ret.setLongDescription((length > ++i) ? record[i] : null);
ret.setExamples((length > ++i) ? (List<String>) getListValue(record[i]) : null);
ret.setAbbreviation((length > ++i) ? record[i] : null);
ret.setUsage((length > ++i) ? record[i] : null);
ret.setAdditionalAttributes(((length > ++i) ? (Map<String, Object>) getMapValue(record[i], failedTermMsgList, populateRelations) : null));
if (populateRelations) {
ret.setTranslationTerms((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setValidValuesFor((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setSynonyms((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setReplacedBy((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setValidValues((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setReplacementTerms((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setSeeAlso((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setTranslatedTerms((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setIsA((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setAntonyms((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setClassifies((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setPreferredToTerms((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
ret.setPreferredTerms((length > ++i) ? (Set<AtlasRelatedTermHeader>) getAtlasRelatedTermHeaderSet(record[i], ret.getName(), record[INDEX_FOR_GLOSSARY_AT_RECORD], failedTermMsgList) : null);
}
}
return ret;
}
private String getGlossaryTermQualifiedName(String glossaryTermName, String glossaryName) throws AtlasBaseException {
return glossaryTermName + "@" + glossaryName;
}
private String getGlossaryGUIDFromGraphDB(String glossaryName) {
AtlasVertex vertex = AtlasGraphUtilsV2.findByTypeAndUniquePropertyName(GlossaryUtils.ATLAS_GLOSSARY_TYPENAME, GlossaryUtils.ATLAS_GLOSSARY_TYPENAME + "." + QUALIFIED_NAME_ATTR, glossaryName);
return (vertex != null) ? AtlasGraphUtilsV2.getIdFromVertex(vertex) : null;
}
private String createGlossary(String glossaryName, List<String> failedTermMsgs) throws AtlasBaseException {
String ret = null;
if (GlossaryService.isNameInvalid(glossaryName)) {
LOG.error("The provided Glossary Name is invalid : " + glossaryName);
failedTermMsgs.add("The provided Glossary Name {" + glossaryName + "} is invalid : " + AtlasErrorCode.INVALID_DISPLAY_NAME.getFormattedErrorMessage());
} else {
AtlasGlossary glossary = new AtlasGlossary();
glossary.setQualifiedName(glossaryName);
glossary.setName(glossaryName);
glossary = dataAccess.save(glossary);
ret = glossary.getGuid();
}
return ret;
}
private void cacheRelatedTermQNameGuid(String currTermQualifiedName, String relatedTermQualifiedName, String termGuid) {
if (!glossaryTermQNameGuidCache.get().containsKey(relatedTermQualifiedName) &&
glossaryTermOrderCache.get().containsKey(currTermQualifiedName) &&
glossaryTermOrderCache.get().containsKey(relatedTermQualifiedName) &&
glossaryTermOrderCache.get().get(currTermQualifiedName) < glossaryTermOrderCache.get().get(relatedTermQualifiedName)) {
glossaryTermQNameGuidCache.get().put(relatedTermQualifiedName, termGuid);
}
}
private AtlasGlossaryTerm getGlossaryTem(String termGuid) throws AtlasBaseException {
AtlasGlossaryTerm ret = null;
if (DEBUG_ENABLED) {
LOG.debug("==> GlossaryTemUtils.getGlossaryTem({})", termGuid);
}
if (!Objects.isNull(termGuid)) {
AtlasGlossaryTerm atlasGlossary = getAtlasGlossaryTermSkeleton(termGuid);
ret = dataAccess.load(atlasGlossary);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryTemUtils.getGlossaryTem() : {}", ret);
}
}
return ret;
}
private void copyRelations(AtlasGlossaryTerm toGlossaryTerm, AtlasGlossaryTerm fromGlossaryTerm) {
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getSeeAlso())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getSeeAlso())) {
toGlossaryTerm.getSeeAlso().addAll(fromGlossaryTerm.getSeeAlso());
} else {
toGlossaryTerm.setSeeAlso(fromGlossaryTerm.getSeeAlso());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getSynonyms())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getSynonyms())) {
toGlossaryTerm.getSynonyms().addAll(fromGlossaryTerm.getSynonyms());
} else {
toGlossaryTerm.setSynonyms(fromGlossaryTerm.getSynonyms());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getAntonyms())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getAntonyms())) {
toGlossaryTerm.getAntonyms().addAll(fromGlossaryTerm.getAntonyms());
} else {
toGlossaryTerm.setAntonyms(fromGlossaryTerm.getAntonyms());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getPreferredTerms())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getPreferredTerms())) {
toGlossaryTerm.getPreferredTerms().addAll(fromGlossaryTerm.getPreferredTerms());
} else {
toGlossaryTerm.setPreferredTerms(fromGlossaryTerm.getPreferredTerms());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getPreferredToTerms())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getPreferredToTerms())) {
toGlossaryTerm.getPreferredToTerms().addAll(fromGlossaryTerm.getPreferredToTerms());
} else {
toGlossaryTerm.setPreferredToTerms(fromGlossaryTerm.getPreferredToTerms());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getReplacementTerms())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getReplacementTerms())) {
toGlossaryTerm.getReplacementTerms().addAll(fromGlossaryTerm.getReplacementTerms());
} else {
toGlossaryTerm.setReplacementTerms(fromGlossaryTerm.getReplacementTerms());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getReplacedBy())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getReplacedBy())) {
toGlossaryTerm.getReplacedBy().addAll(fromGlossaryTerm.getReplacedBy());
} else {
toGlossaryTerm.setReplacedBy(fromGlossaryTerm.getReplacedBy());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getTranslationTerms())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getTranslationTerms())) {
toGlossaryTerm.getTranslationTerms().addAll(fromGlossaryTerm.getTranslationTerms());
} else {
toGlossaryTerm.setTranslationTerms(fromGlossaryTerm.getTranslationTerms());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getTranslatedTerms())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getTranslatedTerms())) {
toGlossaryTerm.getTranslatedTerms().addAll(fromGlossaryTerm.getTranslatedTerms());
} else {
toGlossaryTerm.setTranslatedTerms(fromGlossaryTerm.getTranslatedTerms());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getIsA())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getIsA())) {
toGlossaryTerm.getIsA().addAll(fromGlossaryTerm.getIsA());
} else {
toGlossaryTerm.setIsA(fromGlossaryTerm.getIsA());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getClassifies())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getClassifies())) {
toGlossaryTerm.getClassifies().addAll(fromGlossaryTerm.getClassifies());
} else {
toGlossaryTerm.setClassifies(fromGlossaryTerm.getClassifies());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getValidValues())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getValidValues())) {
toGlossaryTerm.getValidValues().addAll(fromGlossaryTerm.getValidValues());
} else {
toGlossaryTerm.setValidValues(fromGlossaryTerm.getValidValues());
}
}
if (CollectionUtils.isNotEmpty(fromGlossaryTerm.getValidValuesFor())) {
if (CollectionUtils.isNotEmpty(toGlossaryTerm.getValidValuesFor())) {
toGlossaryTerm.getValidValuesFor().addAll(fromGlossaryTerm.getValidValuesFor());
} else {
toGlossaryTerm.setValidValuesFor(fromGlossaryTerm.getValidValuesFor());
}
}
}
}