Commit 0dad9529 by apoorvnaik Committed by Madhan Neethiraj

ATLAS-2534: Glossary REST API implementation

Change-Id: I47210446be9e38c274bae0ee4a688187ba6e4fd0 Signed-off-by: 's avatarMadhan Neethiraj <madhan@apache.org>
parent 15967a93
......@@ -6,9 +6,9 @@
* 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
*
* <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.
......@@ -28,10 +28,10 @@ public final class Constants {
* Globally Unique identifier property key.
*/
public static final String INTERNAL_PROPERTY_KEY_PREFIX = "__";
public static final String INTERNAL_PROPERTY_KEY_PREFIX = "__";
public static final String RELATIONSHIP_PROPERTY_KEY_PREFIX = "_r";
public static final String GUID_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "guid";
public static final String RELATIONSHIP_GUID_PROPERTY_KEY = RELATIONSHIP_PROPERTY_KEY_PREFIX + GUID_PROPERTY_KEY;
public static final String GUID_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "guid";
public static final String RELATIONSHIP_GUID_PROPERTY_KEY = RELATIONSHIP_PROPERTY_KEY_PREFIX + GUID_PROPERTY_KEY;
/**
* Entity type name property key.
......@@ -53,35 +53,35 @@ public final class Constants {
/**
* Properties for type store graph.
*/
public static final String TYPE_CATEGORY_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type.category";
public static final String VERTEX_TYPE_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type";
public static final String TYPENAME_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type.name";
public static final String TYPE_CATEGORY_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type.category";
public static final String VERTEX_TYPE_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type";
public static final String TYPENAME_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type.name";
public static final String TYPEDESCRIPTION_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type.description";
public static final String TYPEVERSION_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type.version";
public static final String TYPEOPTIONS_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type.options";
public static final String TYPEVERSION_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type.version";
public static final String TYPEOPTIONS_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "type.options";
// relationship def constants
public static final String RELATIONSHIPTYPE_END1_KEY = "endDef1";
public static final String RELATIONSHIPTYPE_END2_KEY = "endDef2";
public static final String RELATIONSHIPTYPE_CATEGORY_KEY = "relationshipCategory";
public static final String RELATIONSHIPTYPE_TAG_PROPAGATION_KEY = "tagPropagation";
public static final String RELATIONSHIPTYPE_END1_KEY = "endDef1";
public static final String RELATIONSHIPTYPE_END2_KEY = "endDef2";
public static final String RELATIONSHIPTYPE_CATEGORY_KEY = "relationshipCategory";
public static final String RELATIONSHIPTYPE_TAG_PROPAGATION_KEY = "tagPropagation";
public static final String RELATIONSHIPTYPE_BLOCKED_PROPAGATED_CLASSIFICATIONS_KEY = "blockedPropagatedClassifications";
/**
* Trait names property key and index name.
*/
public static final String TRAIT_NAMES_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "traitNames";
public static final String TRAIT_NAMES_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "traitNames";
public static final String PROPAGATED_TRAIT_NAMES_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "propagatedTraitNames";
public static final String VERSION_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "version";
public static final String STATE_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "state";
public static final String CREATED_BY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "createdBy";
public static final String MODIFIED_BY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "modifiedBy";
public static final String STATE_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "state";
public static final String CREATED_BY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "createdBy";
public static final String MODIFIED_BY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "modifiedBy";
public static final String TIMESTAMP_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "timestamp";
public static final String MODIFICATION_TIMESTAMP_PROPERTY_KEY =
INTERNAL_PROPERTY_KEY_PREFIX + "modificationTimestamp";
INTERNAL_PROPERTY_KEY_PREFIX + "modificationTimestamp";
/**
* search backing index name.
......@@ -100,23 +100,23 @@ public final class Constants {
public static final String FULLTEXT_INDEX = "fulltext_index";
public static final String QUALIFIED_NAME = "Referenceable.qualifiedName";
public static final String TYPE_NAME_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "typeName";
public static final String INDEX_SEARCH_MAX_RESULT_SET_SIZE = "atlas.graph.index.search.max-result-set-size";
public static final String QUALIFIED_NAME = "Referenceable.qualifiedName";
public static final String TYPE_NAME_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "typeName";
public static final String INDEX_SEARCH_MAX_RESULT_SET_SIZE = "atlas.graph.index.search.max-result-set-size";
public static final String INDEX_SEARCH_TYPES_MAX_QUERY_STR_LENGTH = "atlas.graph.index.search.types.max-query-str-length";
public static final String INDEX_SEARCH_TAGS_MAX_QUERY_STR_LENGTH = "atlas.graph.index.search.tags.max-query-str-length";
public static final String INDEX_SEARCH_VERTEX_PREFIX_PROPERTY = "atlas.graph.index.search.vertex.prefix";
public static final String INDEX_SEARCH_VERTEX_PREFIX_DEFAULT = "$v$";
public static final String INDEX_SEARCH_VERTEX_PREFIX_PROPERTY = "atlas.graph.index.search.vertex.prefix";
public static final String INDEX_SEARCH_VERTEX_PREFIX_DEFAULT = "$v$";
public static final String MAX_FULLTEXT_QUERY_STR_LENGTH = "atlas.graph.fulltext-max-query-str-length";
public static final String MAX_DSL_QUERY_STR_LENGTH = "atlas.graph.dsl-max-query-str-length";
public static final String MAX_FULLTEXT_QUERY_STR_LENGTH = "atlas.graph.fulltext-max-query-str-length";
public static final String MAX_DSL_QUERY_STR_LENGTH = "atlas.graph.dsl-max-query-str-length";
public static final String ATTRIBUTE_NAME_GUID = "guid";
public static final String ATTRIBUTE_NAME_TYPENAME = "typeName";
public static final String ATTRIBUTE_NAME_GUID = "guid";
public static final String ATTRIBUTE_NAME_TYPENAME = "typeName";
public static final String ATTRIBUTE_NAME_SUPERTYPENAMES = "superTypeNames";
public static final String ATTRIBUTE_NAME_STATE = "state";
public static final String ATTRIBUTE_NAME_VERSION = "version";
public static final String TEMP_STRUCT_NAME_PREFIX = "__tempQueryResultStruct";
public static final String ATTRIBUTE_NAME_STATE = "state";
public static final String ATTRIBUTE_NAME_VERSION = "version";
public static final String TEMP_STRUCT_NAME_PREFIX = "__tempQueryResultStruct";
public static final String CLASSIFICATION_ENTITY_GUID = INTERNAL_PROPERTY_KEY_PREFIX + "entityGuid";
public static final String CLASSIFICATION_VALIDITY_PERIODS_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "validityPeriods";
......@@ -126,9 +126,10 @@ public final class Constants {
public static final String CLASSIFICATION_EDGE_IS_PROPAGATED_PROPERTY_KEY = INTERNAL_PROPERTY_KEY_PREFIX + "isPropagated";
public static final String CLASSIFICATION_EDGE_STATE_PROPERTY_KEY = STATE_PROPERTY_KEY;
public static final String CLASSIFICATION_LABEL = "classifiedAs";
public static final String TERM_ASSIGNMENT_LABEL = "r:__AtlasGlossarySemanticAssignment";
public static final String VERTEX_ID_IN_IMPORT_KEY = "__vIdInImport";
public static final String EDGE_ID_IN_IMPORT_KEY = "__eIdInImport";
public static final String EDGE_ID_IN_IMPORT_KEY = "__eIdInImport";
private Constants() {
}
......
......@@ -128,9 +128,16 @@ public enum AtlasErrorCode {
NO_CLASSIFICATIONS_FOUND_FOR_ENTITY(400, "ATLAS-400-00-06E", "No classifications associated with entity: {0}"),
INVALID_CLASSIFICATION_PARAMS(400, "ATLAS-400-00-06F", "Invalid classification parameters passed for {0} operation for entity: {1}"),
PROPAGATED_CLASSIFICATION_NOT_ASSOCIATED_WITH_ENTITY(400, "ATLAS-400-00-070", "Propagated classification {0} is not associated with entity"),
INVALID_PARTIAL_UPDATE_ATTR_VAL(400, "ATLAS-400-00-071", "Invalid attrVal for partial update of {0}, expected = {1} found {2}"),
INVALID_BLOCKED_PROPAGATED_CLASSIFICATION(400, "ATLAS-400-00-071", "Invalid propagated classification: {0} with entityGuid: {1} added to blocked propagated classifications."),
MISSING_MANDATORY_ANCHOR(400, "ATLAS-400-00-072", "Mandatory anchor attribute is missing"),
INVALID_BLOCKED_PROPAGATED_CLASSIFICATION(400, "ATLAS-400-00-073", "Invalid propagated classification: {0} with entityGuid: {1} added to blocked propagated classifications."),
MISSING_MANDATORY_QUALIFIED_NAME(400, "ATLAS-400-00-073", "Mandatory qualifiedName attribute is missing"),
INVALID_PARTIAL_UPDATE_ATTR_VAL(400, "ATLAS-400-00-074", "Invalid attrVal for partial update of {0}, expected = {1} found {2}"),
MISSING_TERM_ID_FOR_CATEGORIZATION(400, "ATLAS-400-00-075", "Term guid can't be empty/null when adding to a category"),
INVALID_NEW_ANCHOR_GUID(400, "ATLAS-400-00-076", "New Anchor guid can't be empty/null"),
TERM_DISSOCIATION_MISSING_RELATION_GUID(400, "ATLAS-400-00-077", "Missing mandatory attribute, TermAssignment relationship guid"),
GLOSSARY_QUALIFIED_NAME_CANT_BE_DERIVED(400, "ATLAS-400-00-078", "Attributes qualifiedName and displayName are missing. Failed to derive a unique name for Glossary"),
GLOSSARY_TERM_QUALIFIED_NAME_CANT_BE_DERIVED(400, "ATLAS-400-00-079", "Attributes qualifiedName, displayName & glossary name are missing. Failed to derive a unique name for Glossary term"),
GLOSSARY_CATEGORY_QUALIFIED_NAME_CANT_BE_DERIVED(400, "ATLAS-400-00-07A", "Attributes qualifiedName, displayName & glossary name are missing. Failed to derive a unique name for Glossary category"),
UNAUTHORIZED_ACCESS(403, "ATLAS-403-00-001", "{0} is not authorized to perform {1}"),
......
......@@ -23,7 +23,7 @@ import org.apache.atlas.model.annotation.AtlasJSON;
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.AtlasEntityHeader;
import org.apache.atlas.model.instance.AtlasRelatedObjectId;
import org.apache.commons.collections.CollectionUtils;
import java.util.HashMap;
......@@ -42,7 +42,7 @@ public class AtlasGlossaryTerm extends AtlasGlossaryBaseObject {
// Attributes derived from relationships
private AtlasGlossaryHeader anchor;
private Set<AtlasEntityHeader> assignedEntities;
private Set<AtlasRelatedObjectId> assignedEntities;
private Set<AtlasTermCategorizationHeader> categories;
// Related Terms
......@@ -128,21 +128,21 @@ public class AtlasGlossaryTerm extends AtlasGlossaryBaseObject {
setCategories(categories);
}
public Set<AtlasEntityHeader> getAssignedEntities() {
public Set<AtlasRelatedObjectId> getAssignedEntities() {
return assignedEntities;
}
public void setAssignedEntities(final Set<AtlasEntityHeader> assignedEntities) {
public void setAssignedEntities(final Set<AtlasRelatedObjectId> assignedEntities) {
this.assignedEntities = assignedEntities;
}
public void addAssignedEntity(final AtlasEntityHeader entityHeader) {
Set<AtlasEntityHeader> entityHeaders = this.assignedEntities;
if (entityHeaders == null) {
entityHeaders = new HashSet<>();
public void addAssignedEntity(final AtlasRelatedObjectId atlasObjectId) {
Set<AtlasRelatedObjectId> assignedEntities = this.assignedEntities;
if (assignedEntities == null) {
assignedEntities = new HashSet<>();
}
entityHeaders.add(entityHeader);
setAssignedEntities(entityHeaders);
assignedEntities.add(atlasObjectId);
setAssignedEntities(assignedEntities);
}
public Set<AtlasRelatedTermHeader> getSeeAlso() {
......
......@@ -24,6 +24,7 @@ import java.util.Objects;
@AtlasJSON
public class AtlasRelatedCategoryHeader {
private String categoryGuid;
private String parentCategoryGuid;
private String relationGuid;
private String displayText;
private String description;
......@@ -61,6 +62,7 @@ public class AtlasRelatedCategoryHeader {
if (!(o instanceof AtlasRelatedCategoryHeader)) return false;
final AtlasRelatedCategoryHeader that = (AtlasRelatedCategoryHeader) o;
return Objects.equals(categoryGuid, that.categoryGuid) &&
Objects.equals(parentCategoryGuid, that.parentCategoryGuid) &&
Objects.equals(displayText, that.displayText) &&
Objects.equals(description, that.description);
}
......@@ -68,13 +70,14 @@ public class AtlasRelatedCategoryHeader {
@Override
public int hashCode() {
return Objects.hash(categoryGuid, displayText, description);
return Objects.hash(categoryGuid, parentCategoryGuid, displayText, description);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("AtlasRelatedCategoryId{");
sb.append("categoryGuid='").append(categoryGuid).append('\'');
sb.append(", parentCategoryGuid='").append(parentCategoryGuid).append('\'');
sb.append(", relationGuid='").append(relationGuid).append('\'');
sb.append(", displayText='").append(displayText).append('\'');
sb.append(", description='").append(description).append('\'');
......@@ -90,4 +93,12 @@ public class AtlasRelatedCategoryHeader {
public void setRelationGuid(final String relationGuid) {
this.relationGuid = relationGuid;
}
public String getParentCategoryGuid() {
return parentCategoryGuid;
}
public void setParentCategoryGuid(final String parentCategoryGuid) {
this.parentCategoryGuid = parentCategoryGuid;
}
}
......@@ -475,7 +475,7 @@ public class EntityDiscoveryService implements AtlasDiscoveryService {
AtlasObjectId objId = (AtlasObjectId) attrValue;
if (ret.getReferredEntities() == null) {
ret.setReferredEntities(new HashMap<String, AtlasEntityHeader>());
ret.setReferredEntities(new HashMap<>());
}
if (!ret.getReferredEntities().containsKey(objId.getGuid())) {
......@@ -489,7 +489,7 @@ public class EntityDiscoveryService implements AtlasDiscoveryService {
AtlasObjectId objId = (AtlasObjectId) obj;
if (ret.getReferredEntities() == null) {
ret.setReferredEntities(new HashMap<String, AtlasEntityHeader>());
ret.setReferredEntities(new HashMap<>());
}
if (!ret.getReferredEntities().containsKey(objId.getGuid())) {
......
/**
* 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.exception.AtlasBaseException;
import org.apache.atlas.model.glossary.AtlasGlossaryCategory;
import org.apache.atlas.model.glossary.relations.AtlasRelatedCategoryHeader;
import org.apache.atlas.model.glossary.relations.AtlasRelatedTermHeader;
import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.instance.AtlasRelationship;
import org.apache.atlas.model.instance.AtlasStruct;
import org.apache.atlas.repository.store.graph.AtlasRelationshipStore;
import org.apache.atlas.type.AtlasRelationshipType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class GlossaryCategoryUtils extends GlossaryUtils {
private static final Logger LOG = LoggerFactory.getLogger(GlossaryCategoryUtils.class);
private static final boolean DEBUG_ENABLED = LOG.isDebugEnabled();
protected GlossaryCategoryUtils(AtlasRelationshipStore relationshipStore, AtlasTypeRegistry typeRegistry) {
super(relationshipStore, typeRegistry);
}
public void processCategoryRelations(AtlasGlossaryCategory updatedCategory, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
if (DEBUG_ENABLED) {
LOG.debug("==> GlossaryCategoryUtils.processCategoryRelations({}, {}, {})", updatedCategory, existing, op);
}
processCategoryAnchor(updatedCategory, existing, op);
processParentCategory(updatedCategory, existing, op);
processCategoryChildren(updatedCategory, existing, op);
processAssociatedTerms(updatedCategory, existing, op);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryCategoryUtils.processCategoryRelations()");
}
}
private void processCategoryAnchor(AtlasGlossaryCategory updatedCategory, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
if (Objects.isNull(updatedCategory.getAnchor()) && op != RelationshipOperation.DELETE) {
throw new AtlasBaseException(AtlasErrorCode.MISSING_MANDATORY_ANCHOR);
}
switch (op) {
case CREATE:
if (DEBUG_ENABLED) {
LOG.debug("Creating new category anchor, category = {}, glossary = {}", existing.getGuid(), updatedCategory.getAnchor().getDisplayText());
}
String anchorGlossaryGuid = updatedCategory.getAnchor().getGlossaryGuid();
createRelationship(defineCategoryAnchorRelation(anchorGlossaryGuid, existing.getGuid()));
break;
case UPDATE:
if (!Objects.equals(updatedCategory.getAnchor(), existing.getAnchor())) {
if (Objects.isNull(updatedCategory.getAnchor().getGlossaryGuid())) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_NEW_ANCHOR_GUID);
}
if (DEBUG_ENABLED) {
LOG.debug("Updating category anchor, category = {}, currAnchor = {}, newAnchor = {}", existing.getGuid(),
existing.getAnchor().getDisplayText(), updatedCategory.getAnchor().getDisplayText());
}
relationshipStore.deleteById(existing.getAnchor().getRelationGuid());
createRelationship(defineCategoryAnchorRelation(updatedCategory.getAnchor().getGlossaryGuid(), existing.getGuid()));
}
break;
case DELETE:
if (Objects.nonNull(existing.getAnchor())) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting category anchor");
}
relationshipStore.deleteById(existing.getAnchor().getRelationGuid());
}
break;
}
}
private void processParentCategory(AtlasGlossaryCategory newObj, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
AtlasRelatedCategoryHeader newParent = newObj.getParentCategory();
AtlasRelatedCategoryHeader existingParent = existing.getParentCategory();
switch (op) {
case CREATE:
if (Objects.nonNull(newParent)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new parent, category = {}, parent = {}", existing.getGuid(), newParent.getDisplayText());
}
createRelationship(defineCategoryHierarchyLink(newParent, existing.getGuid()));
}
break;
case UPDATE:
if (Objects.equals(newParent, existingParent)) {
if (DEBUG_ENABLED) {
LOG.debug("No change to parent");
}
break;
}
if (Objects.isNull(existingParent)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new parent, category = {}, parent = {}", existing.getGuid(), newParent.getDisplayText());
}
createRelationship(defineCategoryHierarchyLink(newParent, existing.getGuid()));
} else if (Objects.isNull(newParent)) {
if (DEBUG_ENABLED) {
LOG.debug("Removing category parent, category = {}, parent = {}", existing.getGuid(), existingParent.getDisplayText());
}
relationshipStore.deleteById(existingParent.getRelationGuid());
} else {
if (DEBUG_ENABLED) {
LOG.debug("Updating category parent, category = {}, currParent = {}, newParent = {}", existing.getGuid(), existingParent.getDisplayText(), newParent.getDisplayText());
}
AtlasRelationship parentRelationship = relationshipStore.getById(existingParent.getRelationGuid());
if (existingParent.getCategoryGuid().equals(newParent.getCategoryGuid())) {
updateRelationshipAttributes(parentRelationship, newParent);
relationshipStore.update(parentRelationship);
} else {
// Delete link to existing parent and link to new parent
relationshipStore.deleteById(parentRelationship.getGuid());
createRelationship(defineCategoryHierarchyLink(newParent, existing.getGuid()));
}
}
break;
case DELETE:
if (Objects.nonNull(existingParent)) {
if (DEBUG_ENABLED) {
LOG.debug("Removing category parent, category = {}, parent = {}", existing.getGuid(), existingParent.getDisplayText());
}
relationshipStore.deleteById(existingParent.getRelationGuid());
}
break;
}
}
private void processAssociatedTerms(AtlasGlossaryCategory newObj, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
Set<AtlasRelatedTermHeader> newTerms = newObj.getTerms();
Set<AtlasRelatedTermHeader> existingTerms = existing.getTerms();
switch (op) {
case CREATE:
if (DEBUG_ENABLED) {
LOG.debug("Creating term relation with category = {}, terms = {}", existing.getDisplayName(),
Objects.nonNull(newTerms) ? newTerms.size() : "none");
}
createTermCategorizationRelationships(existing, newTerms);
break;
case UPDATE:
if (CollectionUtils.isEmpty(existingTerms)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating term relation with category = {}, terms = {}", existing.getDisplayName(),
Objects.nonNull(newTerms) ? newTerms.size() : "none");
}
createTermCategorizationRelationships(existing, newTerms);
break;
}
if (CollectionUtils.isEmpty(newTerms)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting term relation with category = {}, terms = {}", existing.getDisplayName(), existingTerms.size());
}
deleteTermCategorizationRelationships(existing, existingTerms);
break;
}
Set<AtlasRelatedTermHeader> toCreate = newTerms
.stream()
.filter(c -> Objects.isNull(c.getRelationGuid()))
.collect(Collectors.toSet());
createTermCategorizationRelationships(existing, toCreate);
Set<AtlasRelatedTermHeader> toUpdate = newTerms
.stream()
.filter(c -> Objects.nonNull(c.getRelationGuid()) && existingTerms.contains(c))
.collect(Collectors.toSet());
updateTermCategorizationRelationships(existing, toUpdate);
Set<AtlasRelatedTermHeader> toDelete = existingTerms
.stream()
.filter(c -> !toCreate.contains(c) && !toUpdate.contains(c))
.collect(Collectors.toSet());
deleteTermCategorizationRelationships(existing, toDelete);
break;
case DELETE:
deleteTermCategorizationRelationships(existing, existingTerms);
break;
}
}
private void createTermCategorizationRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
Set<AtlasRelatedTermHeader> existingTerms = existing.getTerms();
for (AtlasRelatedTermHeader term : terms) {
if (Objects.isNull(term.getTermGuid())) {
throw new AtlasBaseException(AtlasErrorCode.MISSING_TERM_ID_FOR_CATEGORIZATION);
} else {
if (Objects.nonNull(existingTerms) && existingTerms.contains(term)) {
if (DEBUG_ENABLED) {
LOG.debug("Skipping existing term guid={}", term.getTermGuid());
}
continue;
}
if (DEBUG_ENABLED) {
LOG.debug("Creating relation between category = {} and term = {}", existing.getGuid(), term.getDisplayText());
}
createRelationship(defineCategorizedTerm(existing.getGuid(), term));
}
}
}
}
private void updateTermCategorizationRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
for (AtlasRelatedTermHeader term : terms) {
if (DEBUG_ENABLED) {
LOG.debug("Updating term relation with category = {}, term = {}", existing.getDisplayName(), term.getDisplayText());
}
AtlasRelationship relationship = relationshipStore.getById(term.getRelationGuid());
updateRelationshipAttributes(relationship, term);
relationshipStore.update(relationship);
}
}
}
private void deleteTermCategorizationRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
for (AtlasRelatedTermHeader term : terms) {
if (DEBUG_ENABLED) {
LOG.debug("Creating term relation with category = {}, terms = {}", existing.getDisplayName(), term.getDisplayText());
}
relationshipStore.deleteById(term.getRelationGuid());
}
}
}
private void processCategoryChildren(AtlasGlossaryCategory newObj, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
Set<AtlasRelatedCategoryHeader> newChildren = newObj.getChildrenCategories();
Set<AtlasRelatedCategoryHeader> existingChildren = existing.getChildrenCategories();
switch (op) {
case CREATE:
if (DEBUG_ENABLED) {
LOG.debug("Creating new children, category = {}, children = {}", existing.getDisplayName(),
Objects.nonNull(newChildren) ? newChildren.size() : "none");
}
createCategoryRelationships(existing, newChildren);
break;
case UPDATE:
// Create new children
if (CollectionUtils.isEmpty(existingChildren)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new children, category = {}, children = {}", existing.getDisplayName(),
Objects.nonNull(newChildren) ? newChildren.size() : "none");
}
createCategoryRelationships(existing, newChildren);
break;
}
// Delete current children
if (CollectionUtils.isEmpty(newChildren)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting children, category = {}, children = {}", existing.getDisplayName(), existingChildren.size());
}
deleteCategoryRelationships(existing, existingChildren);
break;
}
Set<AtlasRelatedCategoryHeader> toCreate = newChildren
.stream()
.filter(c -> Objects.isNull(c.getRelationGuid()))
.collect(Collectors.toSet());
createCategoryRelationships(existing, toCreate);
Set<AtlasRelatedCategoryHeader> toUpdate = newChildren
.stream()
.filter(c -> Objects.nonNull(c.getRelationGuid()) && existingChildren.contains(c))
.collect(Collectors.toSet());
updateCategoryRelationships(existing, toUpdate);
Set<AtlasRelatedCategoryHeader> toDelete = existingChildren
.stream()
.filter(c -> !toCreate.contains(c) && !toUpdate.contains(c))
.collect(Collectors.toSet());
deleteCategoryRelationships(existing, toDelete);
break;
case DELETE:
deleteCategoryRelationships(existing, existingChildren);
break;
}
}
private void createCategoryRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedCategoryHeader> newChildren) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(newChildren)) {
Set<AtlasRelatedCategoryHeader> existingChildren = existing.getChildrenCategories();
for (AtlasRelatedCategoryHeader child : newChildren) {
if (Objects.nonNull(existingChildren) && existingChildren.contains(child)) {
if (DEBUG_ENABLED) {
LOG.debug("Skipping existing child relation for category guid = {}", child.getCategoryGuid());
}
continue;
}
if (DEBUG_ENABLED) {
LOG.debug("Creating new child, category = {}, child = {}", existing.getDisplayName(), child.getDisplayText());
}
createRelationship(defineCategoryHierarchyLink(existing.getGuid(), child));
}
}
}
private void updateCategoryRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedCategoryHeader> toUpdate) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(toUpdate)) {
for (AtlasRelatedCategoryHeader categoryHeader : toUpdate) {
if (DEBUG_ENABLED) {
LOG.debug("Updating child, category = {}, child = {}", existing.getDisplayName(), categoryHeader.getDisplayText());
}
AtlasRelationship childRelationship = relationshipStore.getById(categoryHeader.getRelationGuid());
updateRelationshipAttributes(childRelationship, categoryHeader);
relationshipStore.update(childRelationship);
}
}
}
private void deleteCategoryRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedCategoryHeader> existingChildren) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(existingChildren)) {
for (AtlasRelatedCategoryHeader child : existingChildren) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting child, category = {}, child = {}", existing.getDisplayName(), child.getDisplayText());
}
relationshipStore.deleteById(child.getRelationGuid());
}
}
}
private AtlasRelationship defineCategoryAnchorRelation(String glossaryGuid, String categoryGuid) {
AtlasRelationshipType relationshipType = typeRegistry.getRelationshipTypeByName(CATEGORY_ANCHOR);
AtlasStruct defaultAttrs = relationshipType.createDefaultValue();
return new AtlasRelationship(CATEGORY_ANCHOR, new AtlasObjectId(glossaryGuid), new AtlasObjectId(categoryGuid), defaultAttrs.getAttributes());
}
private AtlasRelationship defineCategoryHierarchyLink(String parentCategoryGuid, AtlasRelatedCategoryHeader childCategory) {
AtlasRelationshipType relationshipType = typeRegistry.getRelationshipTypeByName(CATEGORY_HIERARCHY);
AtlasStruct defaultAttrs = relationshipType.createDefaultValue();
AtlasRelationship relationship = new AtlasRelationship(CATEGORY_HIERARCHY, new AtlasObjectId(parentCategoryGuid), new AtlasObjectId(childCategory.getCategoryGuid()), defaultAttrs.getAttributes());
updateRelationshipAttributes(relationship, childCategory);
return relationship;
}
private AtlasRelationship defineCategoryHierarchyLink(AtlasRelatedCategoryHeader parentCategory, String childGuid) {
AtlasRelationshipType relationshipType = typeRegistry.getRelationshipTypeByName(CATEGORY_HIERARCHY);
AtlasStruct defaultAttrs = relationshipType.createDefaultValue();
AtlasRelationship relationship = new AtlasRelationship(CATEGORY_HIERARCHY, new AtlasObjectId(parentCategory.getCategoryGuid()), new AtlasObjectId(childGuid), defaultAttrs.getAttributes());
updateRelationshipAttributes(relationship, parentCategory);
return relationship;
}
private AtlasRelationship defineCategorizedTerm(String categoryGuid, AtlasRelatedTermHeader relatedTermId) {
AtlasRelationshipType relationshipType = typeRegistry.getRelationshipTypeByName(TERM_CATEGORIZATION);
AtlasStruct defaultAttrs = relationshipType.createDefaultValue();
AtlasRelationship relationship = new AtlasRelationship(TERM_CATEGORIZATION, new AtlasObjectId(categoryGuid), new AtlasObjectId(relatedTermId.getTermGuid()), defaultAttrs.getAttributes());
updateRelationshipAttributes(relationship, relatedTermId);
return relationship;
}
private void updateRelationshipAttributes(AtlasRelationship relationship, AtlasRelatedCategoryHeader relatedCategoryHeader) {
if (Objects.nonNull(relationship)) {
relationship.setAttribute("description", relatedCategoryHeader.getDescription());
}
}
}
......@@ -26,13 +26,13 @@ import org.apache.atlas.model.glossary.AtlasGlossaryTerm;
import org.apache.atlas.model.glossary.relations.AtlasRelatedCategoryHeader;
import org.apache.atlas.model.glossary.relations.AtlasRelatedTermHeader;
import org.apache.atlas.model.glossary.relations.AtlasTermCategorizationHeader;
import org.apache.atlas.model.instance.AtlasEntityHeader;
import org.apache.atlas.model.instance.AtlasObjectId;
import org.apache.atlas.model.instance.AtlasRelationship;
import org.apache.atlas.model.instance.AtlasRelatedObjectId;
import org.apache.atlas.repository.ogm.DataAccess;
import org.apache.atlas.repository.store.graph.AtlasRelationshipStore;
import org.apache.atlas.repository.store.graph.v1.AtlasGraphUtilsV1;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
......@@ -53,24 +53,17 @@ public class GlossaryService {
private static final Logger LOG = LoggerFactory.getLogger(GlossaryService.class);
private static final boolean DEBUG_ENABLED = LOG.isDebugEnabled();
private static final String ATLAS_GLOSSARY_PREFIX = "__AtlasGlossary";
// Relation name constants
private static final String TERM_ANCHOR = ATLAS_GLOSSARY_PREFIX + "TermAnchor";
private static final String CATEGORY_ANCHOR = ATLAS_GLOSSARY_PREFIX + "CategoryAnchor";
private static final String CATEGORY_HIERARCHY = ATLAS_GLOSSARY_PREFIX + "CategoryHierarchyLink";
private static final String TERM_CATEGORIZATION = ATLAS_GLOSSARY_PREFIX + "TermCategorization";
private static final String TERM_ASSIGNMENT = ATLAS_GLOSSARY_PREFIX + "SemanticAssignment";
private final DataAccess dataAccess;
private final AtlasRelationshipStore relationshipStore;
private final GlossaryTermUtils glossaryTermUtils;
private final GlossaryCategoryUtils glossaryCategoryUtils;
@Inject
public GlossaryService(DataAccess dataAccess, final AtlasRelationshipStore relationshipStore) {
public GlossaryService(DataAccess dataAccess, final AtlasRelationshipStore relationshipStore, final AtlasTypeRegistry typeRegistry) {
this.dataAccess = dataAccess;
this.relationshipStore = relationshipStore;
glossaryTermUtils = new GlossaryTermUtils(relationshipStore, typeRegistry);
glossaryCategoryUtils = new GlossaryCategoryUtils(relationshipStore, typeRegistry);
}
/**
* List all glossaries
*
......@@ -85,7 +78,7 @@ public class GlossaryService {
LOG.debug("==> GlossaryService.getGlossaries({}, {}, {})", limit, offset, sortOrder);
}
List<String> glossaryGuids = AtlasGraphUtilsV1.findEntityGUIDsByType(ATLAS_GLOSSARY_PREFIX, sortOrder);
List<String> glossaryGuids = AtlasGraphUtilsV1.findEntityGUIDsByType(GlossaryUtils.ATLAS_GLOSSARY_PREFIX, sortOrder);
PaginationHelper paginationHelper = new PaginationHelper<>(glossaryGuids, offset, limit);
List<AtlasGlossary> ret;
......@@ -95,7 +88,11 @@ public class GlossaryService {
Iterable<AtlasGlossary> glossaries = dataAccess.load(ret);
ret.clear();
glossaries.forEach(ret::add);
// Set the displayText for all relations
for (AtlasGlossary glossary : glossaries) {
setInfoForRelations(glossary);
ret.add(glossary);
}
} else {
ret = Collections.emptyList();
}
......@@ -121,9 +118,12 @@ public class GlossaryService {
if (Objects.isNull(atlasGlossary)) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Glossary definition missing");
}
if (Objects.isNull(atlasGlossary.getQualifiedName())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Glossary qualifiedName is mandatory");
if (StringUtils.isEmpty(atlasGlossary.getQualifiedName())) {
if (StringUtils.isEmpty(atlasGlossary.getDisplayName())) {
throw new AtlasBaseException(AtlasErrorCode.GLOSSARY_QUALIFIED_NAME_CANT_BE_DERIVED);
} else {
atlasGlossary.setQualifiedName(atlasGlossary.getDisplayName());
}
}
AtlasGlossary saved = dataAccess.save(atlasGlossary);
......@@ -152,7 +152,7 @@ public class GlossaryService {
AtlasGlossary atlasGlossary = getGlossarySkeleton(glossaryGuid);
AtlasGlossary ret = dataAccess.load(atlasGlossary);
setDisplayTextForRelations(ret);
setInfoForRelations(ret);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryService.getGlossary() : {}", ret);
......@@ -219,10 +219,9 @@ public class GlossaryService {
if (!ret.equals(atlasGlossary)) {
atlasGlossary.setGuid(ret.getGuid());
atlasGlossary.setQualifiedName(ret.getQualifiedName());
ret = dataAccess.save(atlasGlossary);
setDisplayTextForRelations(ret);
setInfoForRelations(ret);
}
if (DEBUG_ENABLED) {
......@@ -239,8 +238,15 @@ public class GlossaryService {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "glossaryGuid is null/empty");
}
AtlasGlossary existing = dataAccess.load(getGlossarySkeleton(glossaryGuid));
Set<AtlasRelatedTermHeader> terms = existing.getTerms();
deleteTerms(existing, terms);
// FIXME: When deleting all other related entities, the new edge label (r:<Relation>) is failing the delete calls
Set<AtlasRelatedCategoryHeader> categories = existing.getCategories();
deleteCategories(existing, categories);
// Once all relations are deleted, then delete the Glossary
dataAccess.delete(glossaryGuid);
if (DEBUG_ENABLED) {
......@@ -263,7 +269,7 @@ public class GlossaryService {
AtlasGlossaryTerm atlasGlossary = getAtlasGlossaryTermSkeleton(termGuid);
AtlasGlossaryTerm ret = dataAccess.load(atlasGlossary);
setDisplayTextForRelations(ret);
setInfoForRelations(ret);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryService.getTerm() : {}", ret);
......@@ -278,24 +284,30 @@ public class GlossaryService {
if (Objects.isNull(glossaryTerm)) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "GlossaryTerm definition missing");
}
if (Objects.isNull(glossaryTerm.getQualifiedName())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "GlossaryTerm qualifiedName is mandatory");
if (Objects.isNull(glossaryTerm.getAnchor())) {
throw new AtlasBaseException(AtlasErrorCode.MISSING_MANDATORY_ANCHOR);
}
if (StringUtils.isEmpty(glossaryTerm.getQualifiedName())) {
String displayName = glossaryTerm.getDisplayName();
String glossaryName = glossaryTerm.getAnchor().getDisplayText();
if (StringUtils.isEmpty(displayName) || StringUtils.isEmpty(glossaryName)) {
throw new AtlasBaseException(AtlasErrorCode.GLOSSARY_TERM_QUALIFIED_NAME_CANT_BE_DERIVED);
} else {
glossaryTerm.setQualifiedName(displayName + "@" + glossaryName);
}
}
AtlasGlossaryTerm saved = dataAccess.save(glossaryTerm);
// TODO: Create all term relations
processTermAnchor(glossaryTerm, saved);
processRelatedTerms(glossaryTerm, saved);
processAssociatedCategories(glossaryTerm, saved);
AtlasGlossaryTerm existing = dataAccess.save(glossaryTerm);
glossaryTermUtils.processTermRelations(glossaryTerm, existing, GlossaryUtils.RelationshipOperation.CREATE);
saved = dataAccess.load(glossaryTerm);
setDisplayTextForRelations(saved);
// Re-load term after handling relations
existing = dataAccess.load(glossaryTerm);
setInfoForRelations(existing);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryService.create() : {}", saved);
LOG.debug("<== GlossaryService.create() : {}", existing);
}
return saved;
return existing;
}
public List<AtlasGlossaryTerm> createTerms(List<AtlasGlossaryTerm> glossaryTerm) throws AtlasBaseException {
......@@ -340,14 +352,13 @@ public class GlossaryService {
} catch (AtlasBaseException e) {
LOG.debug("Glossary term had no immediate attr updates. Exception: {}", e.getMessage());
} finally {
// TODO: Manage remaining term relations
processRelations(atlasGlossaryTerm, existing);
glossaryTermUtils.processTermRelations(atlasGlossaryTerm, existing, GlossaryUtils.RelationshipOperation.UPDATE);
}
}
updated = dataAccess.load(atlasGlossaryTerm);
setDisplayTextForRelations(updated);
setInfoForRelations(updated);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryService.updateTerm() : {}", updated);
}
......@@ -362,7 +373,15 @@ public class GlossaryService {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "termGuid is null/empty");
}
AtlasGlossaryTerm existing = dataAccess.load(getAtlasGlossaryTermSkeleton(termGuid));
// Remove term from Glossary
glossaryTermUtils.processTermRelations(existing, existing, GlossaryUtils.RelationshipOperation.DELETE);
// Remove term associations with Entities
glossaryTermUtils.processTermDissociation(existing, existing.getAssignedEntities());
// Now delete the term
dataAccess.delete(termGuid);
if (DEBUG_ENABLED) {
......@@ -370,35 +389,28 @@ public class GlossaryService {
}
}
public void assignTermToEntities(String termGuid, Collection<AtlasEntityHeader> entityHeaders) throws AtlasBaseException {
public void assignTermToEntities(String termGuid, List<AtlasRelatedObjectId> relatedObjectIds) throws AtlasBaseException {
if (DEBUG_ENABLED) {
LOG.debug("==> GlossaryService.assignTermToEntities({}, {})", termGuid, relatedObjectIds);
}
AtlasGlossaryTerm glossaryTerm = dataAccess.load(getAtlasGlossaryTermSkeleton(termGuid));
glossaryTermUtils.processTermAssignments(glossaryTerm, relatedObjectIds);
if (Objects.nonNull(glossaryTerm)) {
Set<AtlasEntityHeader> assignedEntities = glossaryTerm.getAssignedEntities();
for (AtlasEntityHeader entityHeader : entityHeaders) {
if (CollectionUtils.isNotEmpty(assignedEntities) && assignedEntities.contains(entityHeader)) continue;
if (DEBUG_ENABLED) {
LOG.debug("Assigning term guid={}, to entity guid = {}", termGuid, entityHeader.getGuid());
}
createRelationship(defineTermAssignment(termGuid, entityHeader));
}
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryService.assignTermToEntities()");
}
}
public void removeTermFromEntities(String termGuid, Collection<AtlasEntityHeader> entityHeaders) throws AtlasBaseException {
public void removeTermFromEntities(String termGuid, List<AtlasRelatedObjectId> relatedObjectIds) throws AtlasBaseException {
if (LOG.isDebugEnabled()) {
LOG.debug("==> GlossaryService.removeTermFromEntities({}, {})", termGuid, relatedObjectIds);
}
AtlasGlossaryTerm glossaryTerm = dataAccess.load(getAtlasGlossaryTermSkeleton(termGuid));
glossaryTermUtils.processTermDissociation(glossaryTerm, relatedObjectIds);
if (Objects.nonNull(glossaryTerm)) {
for (AtlasEntityHeader entityHeader : entityHeaders) {
if (DEBUG_ENABLED) {
LOG.debug("Removing term guid={}, from entity guid = {}", termGuid, entityHeader.getGuid());
}
Object relationGuid = entityHeader.getAttribute("relationGuid");
if (Objects.isNull(relationGuid)) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "EntityHeader is missing mandatory attribute relation guid");
}
relationshipStore.deleteById((String) relationGuid);
}
if (LOG.isDebugEnabled()) {
LOG.debug("<== GlossaryService.removeTermFromEntities()");
}
}
......@@ -413,11 +425,10 @@ public class GlossaryService {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "categoryGuid is null/empty");
}
AtlasGlossaryCategory atlasGlossary = getAtlasGlossaryCategorySkeleton(categoryGuid);
AtlasGlossaryCategory ret = dataAccess.load(atlasGlossary);
setDisplayTextForRelations(ret);
setInfoForRelations(ret);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryService.getCategory() : {}", ret);
......@@ -433,28 +444,26 @@ public class GlossaryService {
if (Objects.isNull(glossaryCategory)) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "GlossaryCategory definition missing");
}
if (Objects.isNull(glossaryCategory.getQualifiedName())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "GlossaryCategory qualifiedName is mandatory");
if (Objects.isNull(glossaryCategory.getAnchor())) {
throw new AtlasBaseException(AtlasErrorCode.MISSING_MANDATORY_ANCHOR);
}
if (StringUtils.isEmpty(glossaryCategory.getQualifiedName())) {
String displayName = glossaryCategory.getDisplayName();
String glossaryName = glossaryCategory.getAnchor().getDisplayText();
if (StringUtils.isEmpty(displayName) || StringUtils.isEmpty(glossaryName)) {
throw new AtlasBaseException(AtlasErrorCode.GLOSSARY_CATEGORY_QUALIFIED_NAME_CANT_BE_DERIVED);
} else {
glossaryCategory.setQualifiedName(displayName + "@" + glossaryName);
}
}
AtlasGlossaryCategory saved = dataAccess.save(glossaryCategory);
// Attempt relation creation
if (Objects.nonNull(glossaryCategory.getAnchor())) {
processCategoryAnchor(glossaryCategory, saved);
}
if (Objects.nonNull(glossaryCategory.getParentCategory())) {
processParentCategory(glossaryCategory, saved);
}
if (CollectionUtils.isNotEmpty(glossaryCategory.getChildrenCategories())) {
processCategoryChildren(glossaryCategory, saved);
}
glossaryCategoryUtils.processCategoryRelations(glossaryCategory, saved, GlossaryUtils.RelationshipOperation.CREATE);
saved = dataAccess.load(glossaryCategory);
setDisplayTextForRelations(glossaryCategory);
setInfoForRelations(glossaryCategory);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryService.createCategory() : {}", saved);
......@@ -502,7 +511,7 @@ public class GlossaryService {
} catch (AtlasBaseException e) {
LOG.debug("No immediate attribute update. Exception: {}", e.getMessage());
} finally {
processRelations(glossaryCategory, existing);
glossaryCategoryUtils.processCategoryRelations(glossaryCategory, existing, GlossaryUtils.RelationshipOperation.UPDATE);
}
}
......@@ -511,7 +520,7 @@ public class GlossaryService {
}
ret = dataAccess.load(glossaryCategory);
setDisplayTextForRelations(glossaryCategory);
setInfoForRelations(glossaryCategory);
return ret;
}
......@@ -524,12 +533,17 @@ public class GlossaryService {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Category guid is null/empty");
}
AtlasGlossaryCategory existing = dataAccess.load(getAtlasGlossaryCategorySkeleton(categoryGuid));
// Delete all relations
glossaryCategoryUtils.processCategoryRelations(existing, existing, GlossaryUtils.RelationshipOperation.DELETE);
// Now delete the category
dataAccess.delete(categoryGuid);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryService.deleteCategory()");
}
}
public List<AtlasGlossaryTerm> getGlossaryTerms(String glossaryGuid, int offset, int limit, SortOrder sortOrder) throws AtlasBaseException {
......@@ -585,8 +599,8 @@ public class GlossaryService {
if (CollectionUtils.isNotEmpty(categories)) {
if (sortOrder != null) {
categories.sort((o1, o2) -> sortOrder == SortOrder.ASCENDING ?
o1.getDisplayText().compareTo(o2.getDisplayText()) :
o2.getDisplayText().compareTo(o1.getDisplayText()));
o1.getDisplayText().compareTo(o2.getDisplayText()) :
o2.getDisplayText().compareTo(o1.getDisplayText()));
}
ret = new PaginationHelper<>(categories, offset, limit).getPaginatedList();
} else {
......@@ -615,8 +629,8 @@ public class GlossaryService {
if (CollectionUtils.isNotEmpty(glossaryCategory.getTerms())) {
if (sortOrder != null) {
terms.sort((o1, o2) -> sortOrder == SortOrder.ASCENDING ?
o1.getDisplayText().compareTo(o2.getDisplayText()) :
o2.getDisplayText().compareTo(o1.getDisplayText()));
o1.getDisplayText().compareTo(o2.getDisplayText()) :
o2.getDisplayText().compareTo(o1.getDisplayText()));
}
ret = new PaginationHelper<>(terms, offset, limit).getPaginatedList();
} else {
......@@ -682,15 +696,15 @@ public class GlossaryService {
return ret;
}
public List<AtlasEntityHeader> getAssignedEntities(final String termGuid, int offset, int limit, SortOrder sortOrder) throws AtlasBaseException {
public List<AtlasRelatedObjectId> getAssignedEntities(final String termGuid, int offset, int limit, SortOrder sortOrder) throws AtlasBaseException {
if (Objects.isNull(termGuid)) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "termGuid is null/empty");
}
AtlasGlossaryTerm glossaryTerm = dataAccess.load(getAtlasGlossaryTermSkeleton(termGuid));
Set<AtlasEntityHeader> assignedEntities = glossaryTerm.getAssignedEntities();
AtlasGlossaryTerm glossaryTerm = dataAccess.load(getAtlasGlossaryTermSkeleton(termGuid));
Set<AtlasRelatedObjectId> assignedEntities = glossaryTerm.getAssignedEntities();
List<AtlasEntityHeader> ret;
List<AtlasRelatedObjectId> ret;
if (CollectionUtils.isNotEmpty(assignedEntities)) {
ret = new ArrayList<>(assignedEntities);
if (sortOrder != null) {
......@@ -712,79 +726,69 @@ public class GlossaryService {
return glossary;
}
private void processAssignedEntities(final AtlasGlossaryTerm newObj, final AtlasGlossaryTerm existing) throws AtlasBaseException {
if (newObj.equals(existing)) return;
private void deleteCategories(final AtlasGlossary existing, final Set<AtlasRelatedCategoryHeader> categories) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(categories)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting categories within glossary guid = {}", existing.getGuid());
}
for (AtlasRelatedCategoryHeader category : categories) {
// Delete category
deleteCategory(category.getCategoryGuid());
}
}
}
if (CollectionUtils.isNotEmpty(newObj.getAssignedEntities())) {
for (AtlasEntityHeader entityHeader : newObj.getAssignedEntities()) {
createRelationship(defineTermAssignment(existing.getGuid(), entityHeader));
private void deleteTerms(final AtlasGlossary existing, final Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting terms within glossary guid = {}", existing.getGuid());
}
for (AtlasRelatedTermHeader term : terms) {
// Delete the term
deleteTerm(term.getTermGuid());
}
}
}
private void setDisplayTextForRelations(final AtlasGlossary ret) throws AtlasBaseException {
private AtlasGlossaryTerm getAtlasGlossaryTermSkeleton(final String termGuid) {
AtlasGlossaryTerm glossaryTerm = new AtlasGlossaryTerm();
glossaryTerm.setGuid(termGuid);
return glossaryTerm;
}
private AtlasGlossaryCategory getAtlasGlossaryCategorySkeleton(final String categoryGuid) {
AtlasGlossaryCategory glossaryCategory = new AtlasGlossaryCategory();
glossaryCategory.setGuid(categoryGuid);
return glossaryCategory;
}
private void setInfoForRelations(final AtlasGlossary ret) throws AtlasBaseException {
if (Objects.nonNull(ret.getTerms())) {
setDisplayNameForTerms(ret.getTerms());
setInfoForTerms(ret.getTerms());
}
if (Objects.nonNull(ret.getCategories())) {
setDisplayNameForRelatedCategories(ret.getCategories());
setInfoForRelatedCategories(ret.getCategories());
}
}
private void setDisplayTextForRelations(final AtlasGlossaryTerm ret) throws AtlasBaseException {
private void setInfoForRelations(final AtlasGlossaryTerm ret) throws AtlasBaseException {
if (Objects.nonNull(ret.getCategories())) {
setDisplayNameForTermCategories(ret.getCategories());
}
if (Objects.nonNull(ret.getRelatedTerms())) {
for (Map.Entry<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> entry : ret.getRelatedTerms().entrySet()) {
setDisplayNameForTerms(entry.getValue());
setInfoForTerms(entry.getValue());
}
}
}
private void setDisplayTextForRelations(final AtlasGlossaryCategory glossaryCategory) throws AtlasBaseException {
private void setInfoForRelations(final AtlasGlossaryCategory glossaryCategory) throws AtlasBaseException {
if (Objects.nonNull(glossaryCategory.getChildrenCategories())) {
setDisplayNameForRelatedCategories(glossaryCategory.getChildrenCategories());
setInfoForRelatedCategories(glossaryCategory.getChildrenCategories());
}
if (Objects.nonNull(glossaryCategory.getTerms())) {
setDisplayNameForTerms(glossaryCategory.getTerms());
}
}
private void processRelations(final AtlasGlossaryTerm newObj, final AtlasGlossaryTerm existing) throws AtlasBaseException {
boolean hasRelatedTerms = newObj.hasTerms();
boolean hasTermAnchor = Objects.nonNull(newObj.getAnchor());
boolean hasCategories = Objects.nonNull(newObj.getCategories());
if (hasTermAnchor) {
processTermAnchor(newObj, existing);
}
if (hasRelatedTerms) {
processRelatedTerms(newObj, existing);
}
if (hasCategories) {
processAssociatedCategories(newObj, existing);
}
}
private void processRelations(final AtlasGlossaryCategory newObj, final AtlasGlossaryCategory existing) throws AtlasBaseException {
boolean hasParent = Objects.nonNull(newObj.getParentCategory());
boolean hasChildren = Objects.nonNull(newObj.getChildrenCategories());
boolean hasAnchor = Objects.nonNull(newObj.getAnchor());
boolean hasTerms = Objects.nonNull(newObj.getTerms());
if (hasAnchor) {
processCategoryAnchor(newObj, existing);
}
if (hasParent) {
processParentCategory(newObj, existing);
}
if (hasChildren) {
processCategoryChildren(newObj, existing);
}
if (hasTerms) {
processAssociatedTerms(newObj, existing);
setInfoForTerms(glossaryCategory.getTerms());
}
}
......@@ -798,17 +802,23 @@ public class GlossaryService {
categorizationHeaders.forEach(c -> c.setDisplayText(categoryMap.get(c.getCategoryGuid()).getDisplayName()));
}
private void setDisplayNameForRelatedCategories(final Set<AtlasRelatedCategoryHeader> categoryHeaders) throws AtlasBaseException {
private void setInfoForRelatedCategories(final Set<AtlasRelatedCategoryHeader> categoryHeaders) throws AtlasBaseException {
List<AtlasGlossaryCategory> categories = categoryHeaders
.stream()
.map(id -> getAtlasGlossaryCategorySkeleton(id.getCategoryGuid()))
.collect(Collectors.toList());
.stream()
.map(id -> getAtlasGlossaryCategorySkeleton(id.getCategoryGuid()))
.collect(Collectors.toList());
Map<String, AtlasGlossaryCategory> categoryMap = new HashMap<>();
dataAccess.load(categories).forEach(c -> categoryMap.put(c.getGuid(), c));
categoryHeaders.forEach(c -> c.setDisplayText(categoryMap.get(c.getCategoryGuid()).getDisplayName()));
for (AtlasRelatedCategoryHeader c : categoryHeaders) {
AtlasGlossaryCategory category = categoryMap.get(c.getCategoryGuid());
c.setDisplayText(category.getDisplayName());
if (Objects.nonNull(category.getParentCategory())) {
c.setParentCategoryGuid(category.getParentCategory().getCategoryGuid());
}
}
}
private void setDisplayNameForTerms(final Set<AtlasRelatedTermHeader> termHeaders) throws AtlasBaseException {
private void setInfoForTerms(final Set<AtlasRelatedTermHeader> termHeaders) throws AtlasBaseException {
List<AtlasGlossaryTerm> terms = termHeaders
.stream()
.map(id -> getAtlasGlossaryTermSkeleton(id.getTermGuid()))
......@@ -819,301 +829,6 @@ public class GlossaryService {
termHeaders.forEach(t -> t.setDisplayText(termMap.get(t.getTermGuid()).getDisplayName()));
}
private void processAssociatedCategories(final AtlasGlossaryTerm newObj, final AtlasGlossaryTerm existing) throws AtlasBaseException {
if (newObj.equals(existing)) return;
Set<AtlasTermCategorizationHeader> categories = newObj.getCategories();
if (Objects.nonNull(categories)) {
Set<AtlasTermCategorizationHeader> existingCategories = existing.getCategories();
for (AtlasTermCategorizationHeader category : categories) {
if (Objects.isNull(category.getCategoryGuid())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Linked category guid can't be empty");
} else {
if (Objects.nonNull(existingCategories) && existingCategories.contains(category)) {
if (DEBUG_ENABLED) {
LOG.debug("Skipping linked category {}", category.getCategoryGuid());
}
continue;
}
if (DEBUG_ENABLED) {
LOG.debug("Creating relation between term = {} and category = {}", existing.getGuid(), category.getCategoryGuid());
}
createRelationship(defineCategorizedTerm(category, existing.getGuid()));
}
}
}
}
private void processAssociatedTerms(final AtlasGlossaryCategory glossaryCategory, final AtlasGlossaryCategory existing) throws AtlasBaseException {
if (Objects.equals(glossaryCategory.getTerms(), existing.getTerms())) return;
for (AtlasRelatedTermHeader linkedTerm : glossaryCategory.getTerms()) {
if (Objects.isNull(linkedTerm.getTermGuid())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Linked term guid can't be empty");
} else {
// Don't process existing child relation
Set<AtlasRelatedTermHeader> existingTerms = existing.getTerms();
if (Objects.nonNull(existingTerms) && existingTerms.contains(linkedTerm)) {
if (DEBUG_ENABLED) {
LOG.debug("Skipping linked term {}", linkedTerm.getTermGuid());
}
continue;
}
if (DEBUG_ENABLED) {
LOG.debug("Creating relation between category = {} and term = {}", existing.getGuid(), linkedTerm.getTermGuid());
}
// TODO: Accept the relationship attributes as well
createRelationship(defineCategorizedTerm(existing.getGuid(), linkedTerm));
}
}
}
private void processTermAnchor(final AtlasGlossaryTerm glossaryTerm, final AtlasGlossaryTerm saved) throws AtlasBaseException {
if (Objects.isNull(glossaryTerm.getAnchor())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "glossaryTerm anchor mandatory attribute");
}
if (Objects.equals(glossaryTerm.getAnchor(), saved.getAnchor())) return;
if (Objects.isNull(glossaryTerm.getAnchor().getGlossaryGuid())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Anchor guid can't be empty");
} else {
if (DEBUG_ENABLED) {
LOG.debug("Creating relation between glossary = {} and term = {}", glossaryTerm.getAnchor().getGlossaryGuid(), saved.getGuid());
}
createRelationship(defineTermAnchorRelation(glossaryTerm.getAnchor().getGlossaryGuid(), saved.getGuid()));
}
}
private void processCategoryAnchor(final AtlasGlossaryCategory newObj, final AtlasGlossaryCategory existing) throws AtlasBaseException {
if (Objects.isNull(newObj.getAnchor())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "glossaryCategory anchor mandatory attribute");
}
// Don't process anchor if no change
if (Objects.equals(newObj.getAnchor(), existing.getAnchor())) return;
if (Objects.isNull(newObj.getAnchor().getGlossaryGuid())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Category anchor guid can't be empty");
} else {
if (DEBUG_ENABLED) {
LOG.debug("Creating relation between glossary = {} and category = {}", newObj.getAnchor().getGlossaryGuid(), existing.getGuid());
}
createRelationship(defineCategoryAnchorRelation(newObj.getAnchor().getGlossaryGuid(), existing.getGuid()));
}
}
private void processRelatedTerms(final AtlasGlossaryTerm incomingObj, final AtlasGlossaryTerm savedObj) throws AtlasBaseException {
if (incomingObj.hasTerms()) {
for (Map.Entry<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> entry : incomingObj.getRelatedTerms().entrySet()) {
AtlasGlossaryTerm.Relation relation = entry.getKey();
Set<AtlasRelatedTermHeader> terms = entry.getValue();
if (DEBUG_ENABLED) {
LOG.debug("Creating relation {}", relation);
LOG.debug("Related Term count = {}", terms.size());
}
if (Objects.nonNull(terms)) {
for (AtlasRelatedTermHeader atlasGlossaryTerm : terms) {
createRelationship(defineTermRelation(relation.getRelationName(), savedObj.getGuid(), atlasGlossaryTerm));
}
}
}
}
// TODO: Process other term relations as well
}
private void processCategoryChildren(final AtlasGlossaryCategory newObj, final AtlasGlossaryCategory existing) throws AtlasBaseException {
for (AtlasRelatedCategoryHeader childCategory : newObj.getChildrenCategories()) {
if (Objects.isNull(childCategory.getCategoryGuid())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Child category guid can't be empty");
} else {
// Don't process existing child relation
Set<AtlasRelatedCategoryHeader> existingChildren = existing.getChildrenCategories();
if (Objects.nonNull(existingChildren) && existingChildren.contains(childCategory)) {
if (DEBUG_ENABLED) {
LOG.debug("Skipping category child {}", childCategory.getCategoryGuid());
}
continue;
}
if (DEBUG_ENABLED) {
LOG.debug("Creating relation between glossary = {} and term = {}", existing.getGuid(), childCategory.getCategoryGuid());
}
// TODO: Accept the relationship attributes as well
createRelationship(defineCategoryHierarchyLink(existing.getGuid(), childCategory));
}
}
}
private void processParentCategory(final AtlasGlossaryCategory newObj, final AtlasGlossaryCategory existing) throws AtlasBaseException {
// Don't process unchanged parent
if (Objects.equals(newObj.getParentCategory(), existing.getParentCategory())) return;
if (Objects.isNull(newObj.getParentCategory().getCategoryGuid())) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Parent category guid can't be empty");
} else {
if (DEBUG_ENABLED) {
LOG.debug("Creating category hierarchy b/w parent = {} and child = {}", newObj.getParentCategory().getCategoryGuid(), existing.getGuid());
}
createRelationship(defineCategoryHierarchyLink(newObj.getParentCategory(), newObj.getGuid()));
}
}
private Map<String, List<AtlasGlossaryTerm>> loadTerms(final Map<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> relatedTerms,
final int offset,
final int limit,
final SortOrder sortOrder) throws AtlasBaseException {
Map<String, List<AtlasGlossaryTerm>> ret = new HashMap<>();
for (Map.Entry<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> entry : relatedTerms.entrySet()) {
ret.put(entry.getKey().getRelationAttrName(), loadTerms(entry.getValue(), offset, limit, sortOrder));
}
return ret;
}
private List<AtlasGlossaryTerm> loadTerms(final Set<AtlasRelatedTermHeader> terms,
final int offset,
final int limit,
final SortOrder sortOrder) throws AtlasBaseException {
return loadTerms(new ArrayList<>(terms), offset, limit, sortOrder);
}
private List<AtlasGlossaryTerm> loadTerms(final List<AtlasRelatedTermHeader> terms,
final int offset,
final int limit,
final SortOrder sortOrder) throws AtlasBaseException {
Objects.requireNonNull(terms);
List<AtlasGlossaryTerm> ret;
ret = terms.stream().map(id -> getAtlasGlossaryTermSkeleton(id.getTermGuid())).collect(Collectors.toList());
Iterable<AtlasGlossaryTerm> loadedTerms = dataAccess.load(ret);
ret.clear();
loadedTerms.forEach(ret::add);
// Sort only when needed
if (sortOrder != null) {
ret.sort((o1, o2) -> sortOrder == SortOrder.ASCENDING ?
o1.getDisplayName().compareTo(o2.getDisplayName()) :
o2.getDisplayName().compareTo(o1.getDisplayName()));
}
return new PaginationHelper<>(ret, offset, limit).getPaginatedList();
}
private List<AtlasGlossaryCategory> loadCategories(final Set<AtlasRelatedCategoryHeader> categories,
final int offset,
final int limit,
final SortOrder sortOrder) throws AtlasBaseException {
return loadCategories(new ArrayList<>(categories), offset, limit, sortOrder);
}
private List<AtlasGlossaryCategory> loadCategories(final List<AtlasRelatedCategoryHeader> categories,
final int offset,
final int limit,
final SortOrder sortOrder) throws AtlasBaseException {
Objects.requireNonNull(categories);
List<AtlasGlossaryCategory> ret = categories.stream()
.map(id -> getAtlasGlossaryCategorySkeleton(id.getCategoryGuid()))
.collect(Collectors.toList());
Iterable<AtlasGlossaryCategory> loadedCategories = dataAccess.load(ret);
ret.clear();
loadedCategories.forEach(ret::add);
// Sort only when needed
if (sortOrder != null) {
ret.sort((o1, o2) -> sortOrder == SortOrder.ASCENDING ?
o1.getDisplayName().compareTo(o2.getDisplayName()) :
o2.getDisplayName().compareTo(o1.getDisplayName()));
}
return new PaginationHelper<>(ret, offset, limit).getPaginatedList();
}
private AtlasGlossaryTerm getAtlasGlossaryTermSkeleton(final String termGuid) {
AtlasGlossaryTerm glossaryTerm = new AtlasGlossaryTerm();
glossaryTerm.setGuid(termGuid);
return glossaryTerm;
}
private AtlasGlossaryCategory getAtlasGlossaryCategorySkeleton(final String categoryGuid) {
AtlasGlossaryCategory glossaryCategory = new AtlasGlossaryCategory();
glossaryCategory.setGuid(categoryGuid);
return glossaryCategory;
}
private void createRelationship(AtlasRelationship relationship) throws AtlasBaseException {
try {
relationshipStore.create(relationship);
} catch (AtlasBaseException e) {
if (!e.getAtlasErrorCode().equals(AtlasErrorCode.RELATIONSHIP_ALREADY_EXISTS)) {
throw e;
}
}
}
private AtlasRelationship defineTermAnchorRelation(String glossaryGuid, String termGuid) {
return new AtlasRelationship(TERM_ANCHOR, new AtlasObjectId(glossaryGuid), new AtlasObjectId(termGuid));
}
private AtlasRelationship defineCategoryAnchorRelation(String glossaryGuid, String categoryGuid) {
return new AtlasRelationship(CATEGORY_ANCHOR, new AtlasObjectId(glossaryGuid), new AtlasObjectId(categoryGuid));
}
private AtlasRelationship defineCategoryHierarchyLink(String parentCategoryGuid, AtlasRelatedCategoryHeader childCategory) {
AtlasRelationship relationship = new AtlasRelationship(CATEGORY_HIERARCHY, new AtlasObjectId(parentCategoryGuid), new AtlasObjectId(childCategory.getCategoryGuid()));
relationship.setAttribute("description", childCategory.getDescription());
return relationship;
}
private AtlasRelationship defineCategoryHierarchyLink(final AtlasRelatedCategoryHeader parentCategory, final String childGuid) {
AtlasRelationship relationship = new AtlasRelationship(CATEGORY_HIERARCHY, new AtlasObjectId(parentCategory.getCategoryGuid()), new AtlasObjectId(childGuid));
relationship.setAttribute("description", parentCategory.getDescription());
return relationship;
}
private AtlasRelationship defineCategorizedTerm(String categoryGuid, AtlasRelatedTermHeader relatedTermId) {
AtlasRelationship relationship = new AtlasRelationship(TERM_CATEGORIZATION, new AtlasObjectId(categoryGuid), new AtlasObjectId(relatedTermId.getTermGuid()));
relationship.setAttribute("expression", relatedTermId.getExpression());
relationship.setAttribute("description", relatedTermId.getDescription());
relationship.setAttribute("steward", relatedTermId.getSteward());
relationship.setAttribute("source", relatedTermId.getSource());
if (Objects.nonNull(relatedTermId.getStatus())) {
relationship.setAttribute("status", relatedTermId.getStatus().name());
}
return relationship;
}
private AtlasRelationship defineCategorizedTerm(AtlasTermCategorizationHeader relatedCategoryId, String termId) {
AtlasRelationship relationship = new AtlasRelationship(TERM_CATEGORIZATION, new AtlasObjectId(relatedCategoryId.getCategoryGuid()), new AtlasObjectId(termId));
relationship.setAttribute("description", relatedCategoryId.getDescription());
if (Objects.nonNull(relatedCategoryId.getStatus())) {
relationship.setAttribute("status", relatedCategoryId.getStatus().name());
}
return relationship;
}
private AtlasRelationship defineTermRelation(String relation, String end1TermGuid, AtlasRelatedTermHeader end2RelatedTerm) {
AtlasRelationship relationship = new AtlasRelationship(relation, new AtlasObjectId(end1TermGuid), new AtlasObjectId(end2RelatedTerm.getTermGuid()));
relationship.setAttribute("expression", end2RelatedTerm.getExpression());
relationship.setAttribute("description", end2RelatedTerm.getDescription());
relationship.setAttribute("steward", end2RelatedTerm.getSteward());
relationship.setAttribute("source", end2RelatedTerm.getSource());
if (Objects.nonNull(end2RelatedTerm.getStatus())) {
relationship.setAttribute("status", end2RelatedTerm.getStatus().name());
}
return relationship;
}
private AtlasRelationship defineTermAssignment(String termGuid, AtlasEntityHeader entityHeader) {
return new AtlasRelationship(TERM_ASSIGNMENT, new AtlasObjectId(termGuid), new AtlasObjectId(entityHeader.getGuid()));
}
static class PaginationHelper<T> {
private int pageStart;
private int pageEnd;
......@@ -1156,4 +871,5 @@ public class GlossaryService {
return pageStart <= maxSize;
}
}
}
/**
* 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.exception.AtlasBaseException;
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.store.graph.AtlasRelationshipStore;
import org.apache.atlas.type.AtlasRelationshipType;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public class GlossaryTermUtils extends GlossaryUtils {
private static final Logger LOG = LoggerFactory.getLogger(GlossaryTermUtils.class);
private static final boolean DEBUG_ENABLED = LOG.isDebugEnabled();
protected GlossaryTermUtils(AtlasRelationshipStore relationshipStore, AtlasTypeRegistry typeRegistry) {
super(relationshipStore, typeRegistry);
}
public void processTermRelations(AtlasGlossaryTerm updatedTerm, AtlasGlossaryTerm existing, RelationshipOperation op) throws AtlasBaseException {
if (DEBUG_ENABLED) {
LOG.debug("==> GlossaryTermUtils.processTermRelations({}, {}, {})", updatedTerm, existing, op);
}
processTermAnchor(updatedTerm, existing, op);
processRelatedTerms(updatedTerm, existing, op);
processAssociatedCategories(updatedTerm, existing, 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);
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);
}
relationshipStore.deleteById(relatedObjectId.getRelationshipGuid());
}
}
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryTermUtils.processTermDissociation()");
}
}
private void processTermAnchor(AtlasGlossaryTerm updatedTerm, AtlasGlossaryTerm existing, RelationshipOperation op) throws AtlasBaseException {
AtlasGlossaryHeader existingAnchor = existing.getAnchor();
AtlasGlossaryHeader updatedTermAnchor = updatedTerm.getAnchor();
switch (op) {
case CREATE:
if (Objects.isNull(updatedTermAnchor.getGlossaryGuid())) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_NEW_ANCHOR_GUID);
} else {
if (DEBUG_ENABLED) {
LOG.debug("Creating relation between glossary = {} and term = {}", updatedTermAnchor.getGlossaryGuid(), existing.getDisplayName());
}
createRelationship(defineTermAnchorRelation(updatedTermAnchor.getGlossaryGuid(), existing.getGuid()));
}
break;
case UPDATE:
if (!Objects.equals(updatedTermAnchor, existingAnchor)) {
if (Objects.isNull(updatedTermAnchor.getGlossaryGuid())) {
throw new AtlasBaseException(AtlasErrorCode.INVALID_NEW_ANCHOR_GUID);
}
if (DEBUG_ENABLED) {
LOG.debug("Updating relation between glossary = {} and term = {}", updatedTermAnchor.getGlossaryGuid(), existing.getDisplayName());
}
relationshipStore.deleteById(existingAnchor.getRelationGuid());
createRelationship(defineTermAnchorRelation(updatedTermAnchor.getGlossaryGuid(), existing.getGuid()));
}
break;
case DELETE:
if (Objects.nonNull(existingAnchor)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting term anchor");
}
relationshipStore.deleteById(existingAnchor.getRelationGuid());
}
break;
}
}
private void processRelatedTerms(AtlasGlossaryTerm updatedTerm, AtlasGlossaryTerm existing, RelationshipOperation op) throws AtlasBaseException {
Map<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> newRelatedTerms = updatedTerm.getRelatedTerms();
Map<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> existingRelatedTerms = existing.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, existing.getGuid());
LOG.debug("Related Term count = {}", terms.size());
}
createTermRelationships(existing, relation, terms);
}
}
break;
case UPDATE:
for (AtlasGlossaryTerm.Relation relation : AtlasGlossaryTerm.Relation.values()) {
Set<AtlasRelatedTermHeader> existingTermHeaders = existingRelatedTerms.get(relation);
Set<AtlasRelatedTermHeader> newTermHeaders = newRelatedTerms.get(relation);
// No existing term relations, create all
if (CollectionUtils.isEmpty(existingTermHeaders)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new term relations, relation = {}, terms = {}", relation,
Objects.nonNull(newTermHeaders) ? newTermHeaders.size() : "none");
}
createTermRelationships(existing, relation, newTermHeaders);
continue;
}
// Existing term relations but nothing in updated object, remove all
if (CollectionUtils.isEmpty(newTermHeaders)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting existing term relations, relation = {}, terms = {}", relation, existingTermHeaders.size());
}
deleteTermRelationships(relation, existingTermHeaders);
continue;
}
// Determine what to update, delete or create
Set<AtlasRelatedTermHeader> toCreate = newTermHeaders
.stream()
.filter(t -> Objects.isNull(t.getRelationGuid()))
.collect(Collectors.toSet());
Set<AtlasRelatedTermHeader> toUpdate = newTermHeaders
.stream()
.filter(t -> Objects.nonNull(t.getRelationGuid()) && existingTermHeaders.contains(t))
.collect(Collectors.toSet());
Set<AtlasRelatedTermHeader> toDelete = existingTermHeaders
.stream()
.filter(t -> !toCreate.contains(t) && !toUpdate.contains(t))
.collect(Collectors.toSet());
createTermRelationships(existing, 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 void processAssociatedCategories(AtlasGlossaryTerm newObj, AtlasGlossaryTerm existing, RelationshipOperation op) throws AtlasBaseException {
Set<AtlasTermCategorizationHeader> newCategories = newObj.getCategories();
Set<AtlasTermCategorizationHeader> existingCategories = existing.getCategories();
switch (op) {
case CREATE:
if (Objects.nonNull(newCategories)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new term categorization, term = {}, categories = {}", existing.getGuid(), newCategories.size());
}
createTermCategorizationRelationships(existing, newCategories);
}
break;
case UPDATE:
// If no existing categories are present then create all existing ones
if (CollectionUtils.isEmpty(existingCategories)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new term categorization, term = {}, categories = {}", existing.getGuid(),
Objects.nonNull(newCategories) ? newCategories.size() : "none");
}
createTermCategorizationRelationships(existing, newCategories);
break;
}
// If no new categories are present then delete all existing ones
if (CollectionUtils.isEmpty(newCategories)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting term categorization, term = {}, categories = {}", existing.getGuid(), existingCategories.size());
}
deleteCategorizationRelationship(existingCategories);
break;
}
Set<AtlasTermCategorizationHeader> toCreate = newCategories
.stream()
.filter(c -> Objects.isNull(c.getRelationGuid()))
.collect(Collectors.toSet());
createTermCategorizationRelationships(existing, toCreate);
Set<AtlasTermCategorizationHeader> toUpdate = newCategories
.stream()
.filter(c -> Objects.nonNull(c.getRelationGuid()) && existingCategories.contains(c))
.collect(Collectors.toSet());
updateTermCategorizationRelationships(existing, toUpdate);
Set<AtlasTermCategorizationHeader> toDelete = existingCategories
.stream()
.filter(c -> !toCreate.contains(c) && !toUpdate.contains(c))
.collect(Collectors.toSet());
deleteCategorizationRelationship(toDelete);
break;
case DELETE:
deleteCategorizationRelationship(existingCategories);
break;
}
}
private void createTermCategorizationRelationships(AtlasGlossaryTerm existing, Set<AtlasTermCategorizationHeader> categories) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(categories)) {
Set<AtlasTermCategorizationHeader> existingCategories = existing.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 = {}", existing.getGuid(), categorizationHeader.getDisplayText());
}
createRelationship(defineCategorizedTerm(categorizationHeader, existing.getGuid()));
}
}
}
private void updateTermCategorizationRelationships(AtlasGlossaryTerm existing, Set<AtlasTermCategorizationHeader> toUpdate) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(toUpdate)) {
for (AtlasTermCategorizationHeader categorizationHeader : toUpdate) {
if (DEBUG_ENABLED) {
LOG.debug("Updating relation between term = {} and category = {}", existing.getGuid(), categorizationHeader.getDisplayText());
}
AtlasRelationship relationship = relationshipStore.getById(categorizationHeader.getRelationGuid());
updateRelationshipAttributes(relationship, categorizationHeader);
relationshipStore.update(relationship);
}
}
}
private void deleteCategorizationRelationship(Set<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());
}
}
}
private void createTermRelationships(AtlasGlossaryTerm existing, AtlasGlossaryTerm.Relation relation, Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
Set<AtlasRelatedTermHeader> existingRelations = existing.getRelatedTerms().get(relation);
for (AtlasRelatedTermHeader term : terms) {
if (Objects.nonNull(existingRelations) && existingRelations.contains(term)) {
if (DEBUG_ENABLED) {
LOG.debug("Skipping existing term relation termGuid={}", term.getTermGuid());
}
continue;
}
if (DEBUG_ENABLED) {
LOG.debug("Creating new term relation = {}, terms = {}", relation, term.getDisplayText());
}
createRelationship(defineTermRelation(relation.getRelationName(), existing.getGuid(), term));
}
}
}
private void updateTermRelationships(AtlasGlossaryTerm.Relation relation, Set<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, Set<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());
}
}
}
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(String relation, String end1TermGuid, AtlasRelatedTermHeader end2RelatedTerm) {
AtlasRelationshipType relationshipType = typeRegistry.getRelationshipTypeByName(relation);
AtlasStruct defaultAttrs = relationshipType.createDefaultValue();
AtlasRelationship relationship = new AtlasRelationship(relation, 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());
}
}
}
}
/**
* 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.exception.AtlasBaseException;
import org.apache.atlas.model.glossary.relations.AtlasRelatedTermHeader;
import org.apache.atlas.model.instance.AtlasRelationship;
import org.apache.atlas.repository.store.graph.AtlasRelationshipStore;
import org.apache.atlas.type.AtlasTypeRegistry;
import java.util.Objects;
public abstract class GlossaryUtils {
public static final String TERM_ASSIGNMENT_ATTR_DESCRIPTION = "description";
public static final String TERM_ASSIGNMENT_ATTR_EXPRESSION = "expression";
public static final String TERM_ASSIGNMENT_ATTR_STATUS = "status";
public static final String TERM_ASSIGNMENT_ATTR_CONFIDENCE = "confidence";
public static final String TERM_ASSIGNMENT_ATTR_CREATED_BY = "createdBy";
public static final String TERM_ASSIGNMENT_ATTR_STEWARD = "steward";
public static final String TERM_ASSIGNMENT_ATTR_SOURCE = "source";
static final String ATLAS_GLOSSARY_PREFIX = "__AtlasGlossary";
// Relation name constants
protected static final String TERM_ANCHOR = ATLAS_GLOSSARY_PREFIX + "TermAnchor";
protected static final String CATEGORY_ANCHOR = ATLAS_GLOSSARY_PREFIX + "CategoryAnchor";
protected static final String CATEGORY_HIERARCHY = ATLAS_GLOSSARY_PREFIX + "CategoryHierarchyLink";
protected static final String TERM_CATEGORIZATION = ATLAS_GLOSSARY_PREFIX + "TermCategorization";
protected static final String TERM_ASSIGNMENT = ATLAS_GLOSSARY_PREFIX + "SemanticAssignment";
protected static final String TERM_RELATION_ATTR_EXPRESSION = "expression";
protected static final String TERM_RELATION_ATTR_DESCRIPTION = "description";
protected static final String TERM_RELATION_ATTR_STEWARD = "steward";
protected static final String TERM_RELATION_ATTR_SOURCE = "source";
protected static final String TERM_RELATION_ATTR_STATUS = "status";
protected final AtlasRelationshipStore relationshipStore;
protected final AtlasTypeRegistry typeRegistry;
protected GlossaryUtils(final AtlasRelationshipStore relationshipStore, final AtlasTypeRegistry typeRegistry) {
this.relationshipStore = relationshipStore;
this.typeRegistry = typeRegistry;
}
protected void createRelationship(AtlasRelationship relationship) throws AtlasBaseException {
try {
relationshipStore.create(relationship);
} catch (AtlasBaseException e) {
if (!e.getAtlasErrorCode().equals(AtlasErrorCode.RELATIONSHIP_ALREADY_EXISTS)) {
throw e;
}
}
}
protected void updateRelationshipAttributes(AtlasRelationship relationship, AtlasRelatedTermHeader relatedTermHeader) {
if (Objects.nonNull(relationship)) {
relationship.setAttribute(TERM_RELATION_ATTR_EXPRESSION, relatedTermHeader.getExpression());
relationship.setAttribute(TERM_RELATION_ATTR_DESCRIPTION, relatedTermHeader.getDescription());
relationship.setAttribute(TERM_RELATION_ATTR_STEWARD, relatedTermHeader.getSteward());
relationship.setAttribute(TERM_RELATION_ATTR_SOURCE, relatedTermHeader.getSource());
if (Objects.nonNull(relatedTermHeader.getStatus())) {
relationship.setAttribute(TERM_RELATION_ATTR_STATUS, relatedTermHeader.getStatus().name());
}
}
}
enum RelationshipOperation {
CREATE, UPDATE, DELETE
}
}
......@@ -113,7 +113,13 @@ public class DataAccess {
List<AtlasBaseModelObject> ret = new ArrayList<>();
for (T object : objects) {
ret.add(load(object));
try {
ret.add(load(object));
} catch (AtlasBaseException e) {
// In case of bulk load, some entities might be in deleted state causing an exception to be thrown
// by the single load API call
LOG.warn("Bulk load encountered an error.", e);
}
}
return (Iterable<T>) ret;
......
......@@ -20,7 +20,6 @@ package org.apache.atlas.repository.ogm.glossary;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.glossary.AtlasGlossaryTerm;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasEntityHeader;
import org.apache.atlas.model.instance.AtlasRelatedObjectId;
import org.apache.atlas.model.instance.AtlasRelationship;
import org.apache.atlas.type.AtlasTypeRegistry;
......@@ -92,12 +91,7 @@ public class AtlasGlossaryTermDTO extends AbstractGlossaryDTO<AtlasGlossaryTerm>
if (assignedEntity instanceof AtlasRelatedObjectId) {
AtlasRelatedObjectId id = (AtlasRelatedObjectId) assignedEntity;
if (id.getRelationshipStatus() == AtlasRelationship.Status.ACTIVE) {
AtlasEntityHeader entityHeader = new AtlasEntityHeader(id.getTypeName(), id.getGuid(), id.getUniqueAttributes());
if (entityHeader.getAttributes() == null) {
entityHeader.setAttributes(new HashMap<>());
}
entityHeader.getAttributes().put("relationGuid", id.getRelationshipGuid());
ret.addAssignedEntity(entityHeader);
ret.addAssignedEntity(id);
}
}
}
......
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
......
......@@ -21,6 +21,7 @@ import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.atlas.AtlasErrorCode;
import org.apache.atlas.exception.AtlasBaseException;
import org.apache.atlas.model.TimeBoundary;
import org.apache.atlas.model.glossary.enums.AtlasTermAssignmentStatus;
import org.apache.atlas.model.glossary.relations.AtlasTermAssignmentHeader;
import org.apache.atlas.model.instance.AtlasClassification;
import org.apache.atlas.model.instance.AtlasClassification.PropagationState;
......@@ -71,30 +72,16 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.atlas.glossary.GlossaryUtils.*;
import static org.apache.atlas.model.instance.AtlasClassification.PropagationState.ACTIVE;
import static org.apache.atlas.model.instance.AtlasClassification.PropagationState.DELETED;
import static org.apache.atlas.model.typedef.AtlasBaseTypeDef.*;
import static org.apache.atlas.model.typedef.AtlasRelationshipDef.PropagateTags.ONE_TO_TWO;
import static org.apache.atlas.repository.Constants.*;
import static org.apache.atlas.repository.graph.GraphHelper.EDGE_LABEL_PREFIX;
import static org.apache.atlas.repository.graph.GraphHelper.addToPropagatedTraitNames;
import static org.apache.atlas.repository.graph.GraphHelper.getAdjacentEdgesByLabel;
import static org.apache.atlas.repository.graph.GraphHelper.getAllClassificationEdges;
import static org.apache.atlas.repository.graph.GraphHelper.getAllTraitNames;
import static org.apache.atlas.repository.graph.GraphHelper.getAssociatedEntityVertex;
import static org.apache.atlas.repository.graph.GraphHelper.getBlockedClassificationIds;
import static org.apache.atlas.repository.graph.GraphHelper.getClassificationEdge;
import static org.apache.atlas.repository.graph.GraphHelper.getClassificationEdgeState;
import static org.apache.atlas.repository.graph.GraphHelper.getGuid;
import static org.apache.atlas.repository.graph.GraphHelper.getIncomingEdgesByLabel;
import static org.apache.atlas.repository.graph.GraphHelper.getOutGoingEdgesByLabel;
import static org.apache.atlas.repository.graph.GraphHelper.getPropagateTags;
import static org.apache.atlas.repository.graph.GraphHelper.getPropagatedClassificationEdge;
import static org.apache.atlas.repository.graph.GraphHelper.getRelationshipGuid;
import static org.apache.atlas.repository.graph.GraphHelper.getTypeName;
import static org.apache.atlas.repository.graph.GraphHelper.isPropagatedClassificationEdge;
import static org.apache.atlas.repository.graph.GraphHelper.isPropagationEnabled;
import static org.apache.atlas.repository.graph.GraphHelper.removeFromPropagatedTraitNames;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_ENTITY_GUID;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_LABEL;
import static org.apache.atlas.repository.Constants.CLASSIFICATION_VALIDITY_PERIODS_KEY;
import static org.apache.atlas.repository.Constants.TERM_ASSIGNMENT_LABEL;
import static org.apache.atlas.repository.graph.GraphHelper.*;
import static org.apache.atlas.repository.store.graph.v1.AtlasGraphUtilsV1.getIdFromVertex;
import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection;
import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelationshipEdgeDirection.BOTH;
......@@ -105,7 +92,11 @@ import static org.apache.atlas.type.AtlasStructType.AtlasAttribute.AtlasRelation
public final class EntityGraphRetriever {
private static final Logger LOG = LoggerFactory.getLogger(EntityGraphRetriever.class);
private static final String TERM_RELATION_NAME = "__AtlasGlossarySemanticAssignment";
private static final String GLOSSARY_TERM_DISPLAY_NAME_ATTR = "__AtlasGlossaryTerm.displayName";
private final String NAME = "name";
private final String DISPLAY_NAME = "displayName";
private final String DESCRIPTION = "description";
private final String OWNER = "owner";
private final String CREATE_TIME = "createTime";
......@@ -368,7 +359,9 @@ public final class EntityGraphRetriever {
ret.setStatus(GraphHelper.getStatus(entityVertex));
ret.setClassificationNames(getAllTraitNames(entityVertex));
// TODO: Add the term mapping here
List<AtlasTermAssignmentHeader> termAssignmentHeaders = mapAssignedTerms(entityVertex);
ret.setMeanings(termAssignmentHeaders);
ret.setMeaningNames(termAssignmentHeaders.stream().map(AtlasTermAssignmentHeader::getDisplayText).collect(Collectors.toList()));
AtlasEntityType entityType = typeRegistry.getEntityTypeByName(typeName);
......@@ -410,6 +403,7 @@ public final class EntityGraphRetriever {
}
}
}
}
return ret;
......@@ -503,6 +497,85 @@ public final class EntityGraphRetriever {
return ret;
}
public List<AtlasTermAssignmentHeader> mapAssignedTerms(AtlasVertex entityVertex) throws AtlasBaseException {
List<AtlasTermAssignmentHeader> ret = new ArrayList<>();
Iterable edges = entityVertex.query().direction(AtlasEdgeDirection.IN).label(TERM_ASSIGNMENT_LABEL).edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
while (iterator.hasNext()) {
AtlasEdge edge = iterator.next();
if (edge != null) {
ret.add(toTermAssignmentHeader(edge));
}
}
}
return ret;
}
private AtlasTermAssignmentHeader toTermAssignmentHeader(final AtlasEdge edge) {
AtlasTermAssignmentHeader ret = new AtlasTermAssignmentHeader();
AtlasVertex termVertex = edge.getOutVertex();
String guid = GraphHelper.getGuid(termVertex);
if (guid != null) {
ret.setTermGuid(guid);
}
String relationGuid = edge.getProperty(Constants.RELATIONSHIP_GUID_PROPERTY_KEY, String.class);
if (relationGuid != null) {
ret.setRelationGuid(relationGuid);
}
Object displayName = GraphHelper.getProperty(termVertex, GLOSSARY_TERM_DISPLAY_NAME_ATTR);
if (displayName instanceof String) {
ret.setDisplayText((String) displayName);
}
String description = edge.getProperty(TERM_ASSIGNMENT_ATTR_DESCRIPTION, String.class);
if (description != null) {
ret.setDescription(description);
}
String expression = edge.getProperty(TERM_ASSIGNMENT_ATTR_EXPRESSION, String.class);
if (expression != null) {
ret.setExpression(expression);
}
String status = edge.getProperty(TERM_ASSIGNMENT_ATTR_STATUS, String.class);
if (status != null) {
AtlasTermAssignmentStatus assignmentStatus = AtlasTermAssignmentStatus.valueOf(status);
ret.setStatus(assignmentStatus);
}
Integer confidence = edge.getProperty(TERM_ASSIGNMENT_ATTR_CONFIDENCE, Integer.class);
if (confidence != null) {
ret.setConfidence(confidence);
}
String createdBy = edge.getProperty(TERM_ASSIGNMENT_ATTR_CREATED_BY, String.class);
if (createdBy != null) {
ret.setCreatedBy(createdBy);
}
String steward = edge.getProperty(TERM_ASSIGNMENT_ATTR_STEWARD, String.class);
if (steward != null) {
ret.setSteward(steward);
}
String source = edge.getProperty(TERM_ASSIGNMENT_ATTR_SOURCE, String.class);
if (source != null) {
ret.setSource(source);
}
return ret;
}
private void mapClassifications(AtlasVertex entityVertex, AtlasEntity entity) throws AtlasBaseException {
List<AtlasEdge> edges = getAllClassificationEdges(entityVertex);
......@@ -881,6 +954,10 @@ public final class EntityGraphRetriever {
ret = getVertexAttribute(entityVertex, entityType.getAttribute(NAME));
if (ret == null) {
ret = getVertexAttribute(entityVertex, entityType.getAttribute(DISPLAY_NAME));
}
if (ret == null) {
ret = getVertexAttribute(entityVertex, entityType.getAttribute(QUALIFIED_NAME));
}
}
......
......@@ -28,8 +28,10 @@ import org.apache.atlas.model.glossary.enums.AtlasTermRelationshipStatus;
import org.apache.atlas.model.glossary.relations.AtlasGlossaryHeader;
import org.apache.atlas.model.glossary.relations.AtlasRelatedCategoryHeader;
import org.apache.atlas.model.glossary.relations.AtlasRelatedTermHeader;
import org.apache.atlas.model.glossary.relations.AtlasTermCategorizationHeader;
import org.apache.atlas.model.instance.AtlasEntity;
import org.apache.atlas.model.instance.AtlasEntityHeader;
import org.apache.atlas.model.instance.AtlasRelatedObjectId;
import org.apache.atlas.model.instance.EntityMutationResponse;
import org.apache.atlas.repository.impexp.ZipFileResourceTestUtils;
import org.apache.atlas.repository.store.graph.AtlasEntityStore;
......@@ -49,11 +51,14 @@ import javax.inject.Inject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import static org.testng.Assert.*;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.fail;
@Guice(modules = TestModules.TestOnlyModule.class)
public class GlossaryServiceTest {
......@@ -68,11 +73,21 @@ public class GlossaryServiceTest {
@Inject
private AtlasEntityStore entityStore;
private AtlasGlossary bankGlossary;
private AtlasGlossary bankGlossary, creditUnionGlossary;
private AtlasGlossaryTerm checkingAccount, savingsAccount, fixedRateMortgage, adjustableRateMortgage;
private AtlasGlossaryCategory customerCategory, accountCategory, mortgageCategory;
private AtlasEntityHeader testEntityHeader;
private AtlasRelatedObjectId relatedObjectId;
@DataProvider
public static Object[][] getGlossaryTermsProvider() {
return new Object[][]{
// offset, limit, expected
{0, -1, 4},
{0, 2, 2},
{2, 5, 2},
};
}
@BeforeClass
public void setupSampleGlossary() {
......@@ -93,19 +108,42 @@ public class GlossaryServiceTest {
bankGlossary.setUsage("N/A");
bankGlossary.setLanguage("en-US");
creditUnionGlossary = new AtlasGlossary();
creditUnionGlossary.setQualifiedName("testCreditUnionGlossary");
creditUnionGlossary.setDisplayName("Credit union glossary");
creditUnionGlossary.setShortDescription("Short description");
creditUnionGlossary.setLongDescription("Long description");
creditUnionGlossary.setUsage("N/A");
creditUnionGlossary.setLanguage("en-US");
try {
AtlasGlossary created = glossaryService.createGlossary(bankGlossary);
bankGlossary.setGuid(created.getGuid());
created = glossaryService.createGlossary(creditUnionGlossary);
creditUnionGlossary.setGuid(created.getGuid());
} catch (AtlasBaseException e) {
fail("Glossary creation should've succeeded", e);
}
}
@Test(groups = "Glossary.CREATE", dependsOnMethods = {"testCreateGlossary"})
public void testCreateGlossaryTerms() {
// Glossary anchor
AtlasGlossaryHeader glossaryId = new AtlasGlossaryHeader();
glossaryId.setGlossaryGuid(bankGlossary.getGuid());
// Create a category
accountCategory = new AtlasGlossaryCategory();
accountCategory.setQualifiedName("acc@testBankingGlossary");
accountCategory.setDisplayName("Account categorization");
accountCategory.setShortDescription("Short description");
accountCategory.setLongDescription("Long description");
accountCategory.setAnchor(glossaryId);
try {
accountCategory = glossaryService.createCategory(accountCategory);
} catch (AtlasBaseException e) {
fail("Account category creation should've succeeded");
}
// Create terms
checkingAccount = new AtlasGlossaryTerm();
checkingAccount.setQualifiedName("chk_acc@testBankingGlossary");
checkingAccount.setDisplayName("A checking account");
......@@ -146,22 +184,7 @@ public class GlossaryServiceTest {
adjustableRateMortgage.setUsage("N/A");
adjustableRateMortgage.setAnchor(glossaryId);
try {
List<AtlasGlossaryTerm> terms = glossaryService.createTerms(Arrays.asList(checkingAccount, savingsAccount, fixedRateMortgage, adjustableRateMortgage));
checkingAccount.setGuid(terms.get(0).getGuid());
savingsAccount.setGuid(terms.get(1).getGuid());
fixedRateMortgage.setGuid(terms.get(2).getGuid());
adjustableRateMortgage.setGuid(terms.get(3).getGuid());
} catch (AtlasBaseException e) {
fail("Term creation should've succeeded", e);
}
}
@Test(groups = "Glossary.CREATE", dependsOnMethods = {"testCreateGlossaryTerms"})
public void testCreateGlossaryCategory() {
AtlasGlossaryHeader glossaryId = new AtlasGlossaryHeader();
glossaryId.setGlossaryGuid(bankGlossary.getGuid());
// Create glossary categories
customerCategory = new AtlasGlossaryCategory();
customerCategory.setQualifiedName("customer@testBankingGlossary");
customerCategory.setDisplayName("Customer category");
......@@ -169,47 +192,93 @@ public class GlossaryServiceTest {
customerCategory.setLongDescription("Long description");
customerCategory.setAnchor(glossaryId);
accountCategory = new AtlasGlossaryCategory();
accountCategory.setQualifiedName("acc@testBankingGlossary");
accountCategory.setDisplayName("Account categorization");
accountCategory.setShortDescription("Short description");
accountCategory.setLongDescription("Long description");
accountCategory.setAnchor(glossaryId);
mortgageCategory = new AtlasGlossaryCategory();
mortgageCategory.setQualifiedName("mtg@testBankingGlossary");
mortgageCategory.setDisplayName("Mortgage categorization");
mortgageCategory.setShortDescription("Short description");
mortgageCategory.setLongDescription("Long description");
mortgageCategory.setAnchor(glossaryId);
}
@Test(groups = "Glossary.CREATE" , dependsOnMethods = "testCreateGlossary")
public void testTermCreationWithoutAnyRelations() {
try {
checkingAccount = glossaryService.createTerm(checkingAccount);
assertNotNull(checkingAccount);
assertNotNull(checkingAccount.getGuid());
} catch (AtlasBaseException e) {
fail("Term creation should've succeeded", e);
}
}
@Test(groups = "Glossary.CREATE" , dependsOnMethods = "testTermCreationWithoutAnyRelations")
public void testTermCreateWithRelation() {
try {
List<AtlasGlossaryCategory> categories = glossaryService.createCategories(Arrays.asList(customerCategory, accountCategory, mortgageCategory));
AtlasRelatedTermHeader relatedTermHeader = new AtlasRelatedTermHeader();
relatedTermHeader.setTermGuid(checkingAccount.getGuid());
relatedTermHeader.setDescription("test description");
relatedTermHeader.setExpression("test expression");
relatedTermHeader.setSource("UT");
relatedTermHeader.setSteward("UT");
relatedTermHeader.setStatus(AtlasTermRelationshipStatus.ACTIVE);
savingsAccount.setSeeAlso(Collections.singleton(relatedTermHeader));
savingsAccount = glossaryService.createTerm(savingsAccount);
assertNotNull(savingsAccount);
assertNotNull(savingsAccount.getGuid());
} catch (AtlasBaseException e) {
fail("Term creation with relation should've succeeded", e);
}
}
@Test(groups = "Glossary.CREATE" , dependsOnMethods = "testCreateGlossary")
public void testTermCreationWithCategory() {
try {
AtlasTermCategorizationHeader termCategorizationHeader = new AtlasTermCategorizationHeader();
termCategorizationHeader.setCategoryGuid(accountCategory.getGuid());
termCategorizationHeader.setDescription("Test description");
termCategorizationHeader.setStatus(AtlasTermRelationshipStatus.DRAFT);
fixedRateMortgage.setCategories(Collections.singleton(termCategorizationHeader));
adjustableRateMortgage.setCategories(Collections.singleton(termCategorizationHeader));
List<AtlasGlossaryTerm> terms = glossaryService.createTerms(Arrays.asList(fixedRateMortgage, adjustableRateMortgage));
fixedRateMortgage.setGuid(terms.get(0).getGuid());
adjustableRateMortgage.setGuid(terms.get(1).getGuid());
} catch (AtlasBaseException e) {
fail("Term creation should've succeeded", e);
}
}
@Test(groups = "Glossary.CREATE" , dependsOnMethods = "testCreateGlossary")
public void testCategoryCreation() {
try {
List<AtlasGlossaryCategory> categories = glossaryService.createCategories(Arrays.asList(customerCategory, mortgageCategory));
customerCategory.setGuid(categories.get(0).getGuid());
accountCategory.setGuid(categories.get(1).getGuid());
mortgageCategory.setGuid(categories.get(2).getGuid());
mortgageCategory.setGuid(categories.get(1).getGuid());
} catch (AtlasBaseException e) {
fail("Category creation should've succeeded", e);
}
}
@DataProvider
public Object[][] getAllGlossaryDataProvider() {
return new Object[][]{
// limit, offset, sortOrder, expected
{1, 0, SortOrder.ASCENDING, 1},
{5, 0, SortOrder.ASCENDING, 1},
{10, 0, SortOrder.ASCENDING, 1},
{1, 1, SortOrder.ASCENDING, 0},
{5, 1, SortOrder.ASCENDING, 0},
{10, 1, SortOrder.ASCENDING, 0},
{5, 0, SortOrder.ASCENDING, 2},
{10, 0, SortOrder.ASCENDING, 2},
{1, 1, SortOrder.ASCENDING, 1},
{5, 1, SortOrder.ASCENDING, 1},
{10, 1, SortOrder.ASCENDING, 1},
{1, 2, SortOrder.ASCENDING, 0},
{5, 2, SortOrder.ASCENDING, 0},
{10, 2, SortOrder.ASCENDING, 0},
};
}
@Test(dataProvider = "getAllGlossaryDataProvider")
@Test(dataProvider = "getAllGlossaryDataProvider", groups = "Glossary.GET", dependsOnGroups = "Glossary.CREATE")
public void testGetAllGlossaries(int limit, int offset, SortOrder sortOrder, int expected) {
try {
List<AtlasGlossary> glossaries = glossaryService.getGlossaries(limit, offset, sortOrder);
......@@ -219,17 +288,6 @@ public class GlossaryServiceTest {
}
}
@Test(groups = "Glossary.GET", dependsOnGroups = "Glossary.CREATE")
public void testGetGlossary() {
try {
AtlasGlossary glossary = glossaryService.getGlossary(bankGlossary.getGuid());
assertNotNull(glossary);
assertEquals(glossary.getGuid(), bankGlossary.getGuid());
} catch (AtlasBaseException e) {
fail("Glossary fetch should've succeeded", e);
}
}
@Test(groups = "Glossary.UPDATE", dependsOnGroups = "Glossary.CREATE")
public void testUpdateGlossary() {
try {
......@@ -241,13 +299,12 @@ public class GlossaryServiceTest {
assertNotNull(updatedGlossary);
assertEquals(updatedGlossary.getGuid(), bankGlossary.getGuid());
assertEquals(updatedGlossary, bankGlossary);
bankGlossary = updatedGlossary;
} catch (AtlasBaseException e) {
fail("Glossary fetch/update should've succeeded", e);
}
}
@Test(dependsOnGroups = {"Glossary.GET", "Glossary.UPDATE", "Glossary.GET.postUpdate"}) // Should be the last test
@Test(dependsOnGroups = {"Glossary.MIGRATE"}) // Should be the last test
public void testDeleteGlossary() {
try {
glossaryService.deleteGlossary(bankGlossary.getGuid());
......@@ -261,19 +318,6 @@ public class GlossaryServiceTest {
}
}
@Test(groups = "Glossary.GET", dependsOnGroups = "Glossary.CREATE")
public void testGetGlossaryTerm() {
for (AtlasGlossaryTerm t : Arrays.asList(checkingAccount, savingsAccount, fixedRateMortgage, adjustableRateMortgage)) {
try {
AtlasGlossaryTerm glossaryTerm = glossaryService.getTerm(t.getGuid());
assertNotNull(glossaryTerm);
assertEquals(glossaryTerm.getGuid(), t.getGuid());
} catch (AtlasBaseException e) {
fail("Glossary term fetching should've succeeded", e);
}
}
}
@Test(groups = "Glossary.UPDATE", dependsOnGroups = "Glossary.CREATE")
public void testUpdateGlossaryTerm() {
List<AtlasGlossaryTerm> glossaryTerms = new ArrayList<>();
......@@ -298,19 +342,6 @@ public class GlossaryServiceTest {
}
}
@Test(groups = "Glossary.GET", dependsOnGroups = "Glossary.CREATE")
public void testGetGlossaryCategory() {
for (AtlasGlossaryCategory c : Arrays.asList(customerCategory, accountCategory, mortgageCategory)) {
try {
AtlasGlossaryCategory glossaryCategory = glossaryService.getCategory(c.getGuid());
assertNotNull(glossaryCategory);
assertEquals(glossaryCategory.getGuid(), c.getGuid());
} catch (AtlasBaseException e) {
fail("Glossary category fetching should've succeeded", e);
}
}
}
@Test(groups = "Glossary.UPDATE", dependsOnGroups = "Glossary.CREATE")
public void testUpdateGlossaryCategory() {
List<AtlasGlossaryCategory> glossaryCategories = new ArrayList<>();
......@@ -324,17 +355,91 @@ public class GlossaryServiceTest {
for (AtlasGlossaryCategory c : glossaryCategories) {
try {
AtlasGlossaryCategory glossaryCategory = glossaryService.getCategory(c.getGuid());
glossaryCategory.setShortDescription("Updated short description");
glossaryCategory.setLongDescription("Updated long description");
c.setShortDescription("Updated short description");
c.setLongDescription("Updated long description");
AtlasGlossaryCategory updatedCategory = glossaryService.updateCategory(glossaryCategory);
AtlasGlossaryCategory updatedCategory = glossaryService.updateCategory(c);
assertNotNull(updatedCategory);
assertEquals(updatedCategory.getGuid(), c.getGuid());
} catch (AtlasBaseException e) {
fail("Glossary category fetching should've succeeded", e);
}
}
// Unlink children
try {
AtlasGlossaryCategory category = glossaryService.getCategory(customerCategory.getGuid());
category.setChildrenCategories(null);
category = glossaryService.updateCategory(category);
assertNotNull(category);
assertNull(category.getChildrenCategories());
} catch (AtlasBaseException e) {
fail("Customer category fetch should've succeeded");
}
}
@Test(groups = "Glossary.MIGRATE", dependsOnGroups = "Glossary.GET.postUpdate")
public void testTermMigration() {
assertNotNull(creditUnionGlossary);
AtlasGlossaryHeader newGlossaryHeader = new AtlasGlossaryHeader();
newGlossaryHeader.setGlossaryGuid(creditUnionGlossary.getGuid());
try {
checkingAccount = glossaryService.getTerm(checkingAccount.getGuid());
savingsAccount = glossaryService.getTerm(savingsAccount.getGuid());
checkingAccount.setAnchor(newGlossaryHeader);
savingsAccount.setAnchor(newGlossaryHeader);
} catch (AtlasBaseException e) {
fail("Term fetch for migration should've succeeded", e);
}
try {
glossaryService.updateTerm(checkingAccount);
glossaryService.updateTerm(savingsAccount);
} catch (AtlasBaseException e) {
fail("Term anchor change should've succeeded", e);
}
try {
List<AtlasGlossaryTerm> terms = glossaryService.getGlossaryTerms(creditUnionGlossary.getGuid(), 0, 5, SortOrder.ASCENDING);
assertNotNull(terms);
assertEquals(terms.size(), 2);
} catch (AtlasBaseException e) {
fail("Term fetch for glossary should've succeeded", e);
}
}
@Test(groups = "Glossary.MIGRATE", dependsOnGroups = "Glossary.GET.postUpdate")
public void testCategoryMigration() {
assertNotNull(creditUnionGlossary);
AtlasGlossaryHeader newGlossaryHeader = new AtlasGlossaryHeader();
newGlossaryHeader.setGlossaryGuid(creditUnionGlossary.getGuid());
try {
customerCategory = glossaryService.getCategory(customerCategory.getGuid());
} catch (AtlasBaseException e) {
fail("Category fetch for migration should've succeeded");
}
customerCategory.setAnchor(newGlossaryHeader);
try {
glossaryService.updateCategory(customerCategory);
} catch (AtlasBaseException e) {
fail("Category anchor change should've succeeded");
}
try {
List<AtlasRelatedCategoryHeader> categories = glossaryService.getGlossaryCategories(creditUnionGlossary.getGuid(), 0, 5, SortOrder.ASCENDING);
assertNotNull(categories);
assertEquals(categories.size(), 1);
} catch (AtlasBaseException e) {
fail("Category migration should've succeeded", e);
}
}
@Test(groups = "Glossary.UPDATE", dependsOnGroups = "Glossary.CREATE")
......@@ -345,24 +450,22 @@ public class GlossaryServiceTest {
} catch (AtlasBaseException e) {
fail("Fetch of accountCategory should've succeeded", e);
}
List<AtlasGlossaryTerm> terms = new ArrayList<>();
for (AtlasGlossaryTerm term : Arrays.asList(checkingAccount, savingsAccount)) {
try {
terms.add(glossaryService.getTerm(term.getGuid()));
AtlasGlossaryTerm termEntry = glossaryService.getTerm(term.getGuid());
AtlasRelatedTermHeader relatedTermId = new AtlasRelatedTermHeader();
relatedTermId.setTermGuid(termEntry.getGuid());
relatedTermId.setStatus(AtlasTermRelationshipStatus.ACTIVE);
relatedTermId.setSteward("UT");
relatedTermId.setSource("UT");
relatedTermId.setExpression("N/A");
relatedTermId.setDescription("Categorization under account category");
accountCategory.addTerm(relatedTermId);
} catch (AtlasBaseException e) {
fail("Term fetching should've succeeded", e);
}
}
for (AtlasGlossaryTerm termEntry : terms) {
AtlasRelatedTermHeader relatedTermId = new AtlasRelatedTermHeader();
relatedTermId.setTermGuid(termEntry.getGuid());
relatedTermId.setStatus(AtlasTermRelationshipStatus.ACTIVE);
relatedTermId.setSteward("UT");
relatedTermId.setSource("UT");
relatedTermId.setExpression("N/A");
relatedTermId.setDescription("Categorization under account category");
accountCategory.addTerm(relatedTermId);
}
try {
AtlasGlossaryCategory updated = glossaryService.updateCategory(accountCategory);
assertNotNull(updated.getTerms());
......@@ -379,26 +482,23 @@ public class GlossaryServiceTest {
fail("Fetch of accountCategory should've succeeded", e);
}
terms.clear();
for (AtlasGlossaryTerm term : Arrays.asList(fixedRateMortgage, adjustableRateMortgage)) {
try {
terms.add(glossaryService.getTerm(term.getGuid()));
AtlasGlossaryTerm termEntry = glossaryService.getTerm(term.getGuid());
AtlasRelatedTermHeader relatedTermId = new AtlasRelatedTermHeader();
relatedTermId.setTermGuid(termEntry.getGuid());
relatedTermId.setStatus(AtlasTermRelationshipStatus.ACTIVE);
relatedTermId.setSteward("UT");
relatedTermId.setSource("UT");
relatedTermId.setExpression("N/A");
relatedTermId.setDescription("Categorization under mortgage category");
mortgageCategory.addTerm(relatedTermId);
} catch (AtlasBaseException e) {
fail("Term fetching should've succeeded", e);
}
}
for (AtlasGlossaryTerm termEntry : terms) {
AtlasRelatedTermHeader relatedTermId = new AtlasRelatedTermHeader();
relatedTermId.setTermGuid(termEntry.getGuid());
relatedTermId.setStatus(AtlasTermRelationshipStatus.ACTIVE);
relatedTermId.setSteward("UT");
relatedTermId.setSource("UT");
relatedTermId.setExpression("N/A");
relatedTermId.setDescription("Categorization under mortgage category");
mortgageCategory.addTerm(relatedTermId);
}
try {
AtlasGlossaryCategory updated = glossaryService.updateCategory(mortgageCategory);
assertNotNull(updated.getTerms());
......@@ -439,77 +539,59 @@ public class GlossaryServiceTest {
assertNull(updateGlossaryCategory.getParentCategory());
assertNotNull(updateGlossaryCategory.getChildrenCategories());
assertEquals(updateGlossaryCategory.getChildrenCategories().size(), 2);
customerCategory = updateGlossaryCategory;
LOG.debug(AtlasJson.toJson(updateGlossaryCategory));
} catch (AtlasBaseException e) {
fail("Sub category addition should've succeeded", e);
}
}
@Test(groups = "Glossary.GET.postUpdate", dependsOnGroups = "Glossary.UPDATE")
public void testCategoryRelation() {
AtlasGlossaryCategory parent = customerCategory;
Map<String, List<AtlasRelatedCategoryHeader>> relatedCategories;
try {
relatedCategories = glossaryService.getRelatedCategories(parent.getGuid(), 0, -1, SortOrder.ASCENDING);
assertNotNull(relatedCategories);
assertNotNull(relatedCategories.get("children"));
assertEquals(relatedCategories.get("children").size(), 2);
} catch (AtlasBaseException e) {
fail("Category fetch should've succeeded", e);
}
for (AtlasGlossaryCategory childCategory : Arrays.asList(accountCategory, mortgageCategory)) {
for (AtlasGlossaryCategory childCategory : categories) {
try {
relatedCategories = glossaryService.getRelatedCategories(childCategory.getGuid(), 0, -1, SortOrder.ASCENDING);
assertNotNull(relatedCategories.get("parent"));
assertEquals(relatedCategories.get("parent").size(), 1);
AtlasGlossaryCategory child = glossaryService.getCategory(childCategory.getGuid());
assertNotNull(child);
assertNotNull(child.getParentCategory());
} catch (AtlasBaseException e) {
fail("Category fetch should've succeeded", e);
fail("Category fetch should've been a success", e);
}
}
}
@Test(groups = "Glossary.UPDATE", dependsOnGroups = "Glossary.CREATE")
public void testTermAssignment() {
public void testTermAssignmentAndDissociation() {
AtlasEntity assetEntity = new AtlasEntity("Asset");
assetEntity.setAttribute("qualifiedName", "testAsset");
assetEntity.setAttribute("name", "testAsset");
try {
EntityMutationResponse response = entityStore.createOrUpdate(new AtlasEntityStream(assetEntity), false);
testEntityHeader = response.getFirstEntityCreated();
assertNotNull(testEntityHeader);
AtlasEntityHeader firstEntityCreated = response.getFirstEntityCreated();
relatedObjectId = new AtlasRelatedObjectId();
relatedObjectId.setGuid(firstEntityCreated.getGuid());
relatedObjectId.setTypeName(firstEntityCreated.getTypeName());
assertNotNull(relatedObjectId);
} catch (AtlasBaseException e) {
fail("Entity creation should've succeeded", e);
}
try {
glossaryService.assignTermToEntities(fixedRateMortgage.getGuid(), Arrays.asList(testEntityHeader));
glossaryService.assignTermToEntities(fixedRateMortgage.getGuid(), Arrays.asList(relatedObjectId));
} catch (AtlasBaseException e) {
fail("Term assignment to asset should've succeeded", e);
}
try {
List<AtlasEntityHeader> assignedEntities = glossaryService.getAssignedEntities(fixedRateMortgage.getGuid(), 0, 1, SortOrder.ASCENDING);
List<AtlasRelatedObjectId> assignedEntities = glossaryService.getAssignedEntities(fixedRateMortgage.getGuid(), 0, 1, SortOrder.ASCENDING);
assertNotNull(assignedEntities);
assertEquals(assignedEntities.size(), 1);
Object relationGuid = assignedEntities.get(0).getAttribute("relationGuid");
assertNotNull(relationGuid);
testEntityHeader.setAttribute("relationGuid", relationGuid);
String relationshipGuid = assignedEntities.get(0).getRelationshipGuid();
assertNotNull(relationshipGuid);
relatedObjectId.setRelationshipGuid(relationshipGuid);
} catch (AtlasBaseException e) {
fail("Term fetch should've succeeded",e);
}
}
// FIXME: The term dissociation is not working as intended.
@Test(groups = "Glossary.UPDATE", dependsOnGroups = "Glossary.CREATE", dependsOnMethods = "testTermAssignment")
public void testTermDissociation() {
// Dissociate term from entities
try {
glossaryService.removeTermFromEntities(fixedRateMortgage.getGuid(), Arrays.asList(testEntityHeader));
glossaryService.removeTermFromEntities(fixedRateMortgage.getGuid(), Arrays.asList(relatedObjectId));
AtlasGlossaryTerm term = glossaryService.getTerm(fixedRateMortgage.getGuid());
assertNotNull(term);
assertNull(term.getAssignedEntities());
......@@ -538,9 +620,9 @@ public class GlossaryServiceTest {
checkingAccount.setSeeAlso(new HashSet<>(Arrays.asList(relatedTerm)));
try {
AtlasGlossaryTerm updatedTerm = glossaryService.updateTerm(checkingAccount);
assertNotNull(updatedTerm.getSeeAlso());
assertEquals(updatedTerm.getSeeAlso().size(), 1);
checkingAccount = glossaryService.updateTerm(checkingAccount);
assertNotNull(checkingAccount.getSeeAlso());
assertEquals(checkingAccount.getSeeAlso().size(), 1);
} catch (AtlasBaseException e) {
fail("RelatedTerm association should've succeeded", e);
}
......@@ -557,26 +639,16 @@ public class GlossaryServiceTest {
adjustableRateMortgage.setSeeAlso(new HashSet<>(Arrays.asList(relatedTerm)));
try {
AtlasGlossaryTerm updatedTerm = glossaryService.updateTerm(adjustableRateMortgage);
assertNotNull(updatedTerm.getSeeAlso());
assertEquals(updatedTerm.getSeeAlso().size(), 1);
adjustableRateMortgage = glossaryService.updateTerm(adjustableRateMortgage);
assertNotNull(adjustableRateMortgage.getSeeAlso());
assertEquals(adjustableRateMortgage.getSeeAlso().size(), 1);
} catch (AtlasBaseException e) {
fail("RelatedTerm association should've succeeded", e);
}
}
@DataProvider
public static Object[][] getGlossaryTermsProvider() {
return new Object[][]{
// offset, limit, expected
{0, -1, 4},
{0, 2, 2},
{2, 5, 2},
};
}
@Test(dataProvider = "getGlossaryTermsProvider", groups = "Glossary.GET.postUpdate", dependsOnGroups = "Glossary.UPDATE")
@Test(dataProvider = "getGlossaryTermsProvider" , groups = "Glossary.GET.postUpdate", dependsOnGroups = "Glossary.UPDATE")
public void testGetGlossaryTerms(int offset, int limit, int expected) {
String guid = bankGlossary.getGuid();
SortOrder sortOrder = SortOrder.ASCENDING;
......@@ -600,7 +672,7 @@ public class GlossaryServiceTest {
};
}
@Test(dataProvider = "getGlossaryCategoriesProvider", groups = "Glossary.GET.postUpdate", dependsOnGroups = "Glossary.UPDATE")
@Test(dataProvider = "getGlossaryCategoriesProvider" , groups = "Glossary.GET.postUpdate", dependsOnGroups = "Glossary.UPDATE")
public void testGetGlossaryCategories(int offset, int limit, int expected) {
String guid = bankGlossary.getGuid();
SortOrder sortOrder = SortOrder.ASCENDING;
......@@ -626,7 +698,7 @@ public class GlossaryServiceTest {
}
@Test(dataProvider = "getCategoryTermsProvider", groups = "Glossary.GET.postUpdate", dependsOnGroups = "Glossary.UPDATE")
@Test(dataProvider = "getCategoryTermsProvider", dependsOnGroups = "Glossary.CREATE")
public void testGetCategoryTerms(int offset, int limit, int expected) {
for (AtlasGlossaryCategory c : Arrays.asList(accountCategory, mortgageCategory)) {
try {
......
......@@ -26,7 +26,7 @@ import org.apache.atlas.model.glossary.AtlasGlossaryCategory;
import org.apache.atlas.model.glossary.AtlasGlossaryTerm;
import org.apache.atlas.model.glossary.relations.AtlasRelatedCategoryHeader;
import org.apache.atlas.model.glossary.relations.AtlasRelatedTermHeader;
import org.apache.atlas.model.instance.AtlasEntityHeader;
import org.apache.atlas.model.instance.AtlasRelatedObjectId;
import org.apache.atlas.utils.AtlasPerfTracer;
import org.apache.atlas.web.util.Servlets;
import org.apache.commons.collections.MapUtils;
......@@ -723,10 +723,10 @@ public class GlossaryREST {
*/
@GET
@Path("/terms/{termGuid}/assignedEntities")
public List<AtlasEntityHeader> getEntitiesAssignedWithTerm(@PathParam("termGuid") String termGuid,
@DefaultValue("-1") @QueryParam("limit") String limit,
@DefaultValue("0") @QueryParam("offset") String offset,
@DefaultValue("ASC") @QueryParam("sort") final String sort) throws AtlasBaseException {
public List<AtlasRelatedObjectId> getEntitiesAssignedWithTerm(@PathParam("termGuid") String termGuid,
@DefaultValue("-1") @QueryParam("limit") String limit,
@DefaultValue("0") @QueryParam("offset") String offset,
@DefaultValue("ASC") @QueryParam("sort") final String sort) throws AtlasBaseException {
Servlets.validateQueryParamLength("termGuid", termGuid);
AtlasPerfTracer perf = null;
......@@ -746,7 +746,7 @@ public class GlossaryREST {
/**
* Assign the given term to the provided list of entity headers
* @param termGuid Glossary term GUID
* @param entityHeaders Entity headers for which the term has to be associated
* @param relatedObjectIds Related Entity IDs to which the term has to be associated
* @throws AtlasBaseException
* @HTTP 204 If the term assignment was successful
* @HTTP 400 If ANY of the entity header is invalid
......@@ -754,7 +754,7 @@ public class GlossaryREST {
*/
@POST
@Path("/terms/{termGuid}/assignedEntities")
public void assignTermToEntities(@PathParam("termGuid") String termGuid, List<AtlasEntityHeader> entityHeaders) throws AtlasBaseException {
public void assignTermToEntities(@PathParam("termGuid") String termGuid, List<AtlasRelatedObjectId> relatedObjectIds) throws AtlasBaseException {
Servlets.validateQueryParamLength("termGuid", termGuid);
AtlasPerfTracer perf = null;
......@@ -763,7 +763,7 @@ public class GlossaryREST {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "GlossaryREST.assignTermToEntities(" + termGuid + ")");
}
glossaryService.assignTermToEntities(termGuid, entityHeaders);
glossaryService.assignTermToEntities(termGuid, relatedObjectIds);
} finally {
AtlasPerfTracer.log(perf);
}
......@@ -772,7 +772,7 @@ public class GlossaryREST {
/**
* Remove the term assignment for the given list of entity headers
* @param termGuid Glossary term GUID
* @param entityHeaders List of entity headers from which the term has to be dissociated
* @param relatedObjectIds List of related entity IDs from which the term has to be dissociated
* @throws AtlasBaseException
* @HTTP 204 If glossary term dissociation was successful
* @HTTP 400 If ANY of the entity header is invalid
......@@ -780,7 +780,7 @@ public class GlossaryREST {
*/
@DELETE
@Path("/terms/{termGuid}/assignedEntities")
public void removeTermAssignmentFromEntities(@PathParam("termGuid") String termGuid, List<AtlasEntityHeader> entityHeaders) throws AtlasBaseException {
public void removeTermAssignmentFromEntities(@PathParam("termGuid") String termGuid, List<AtlasRelatedObjectId> relatedObjectIds) throws AtlasBaseException {
Servlets.validateQueryParamLength("termGuid", termGuid);
AtlasPerfTracer perf = null;
......@@ -789,7 +789,7 @@ public class GlossaryREST {
perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "GlossaryREST.removeTermAssignmentFromEntities(" + termGuid + ")");
}
glossaryService.removeTermFromEntities(termGuid, entityHeaders);
glossaryService.removeTermFromEntities(termGuid, relatedObjectIds);
} finally {
AtlasPerfTracer.log(perf);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment