ATLAS-2534: Glossary REST API implementation Change-Id: I47210446be9e38c274bae0ee4a688187ba6e4fd0 Signed-off-by: Madhan Neethiraj <[email protected]>
Project: http://git-wip-us.apache.org/repos/asf/atlas/repo Commit: http://git-wip-us.apache.org/repos/asf/atlas/commit/0dad9529 Tree: http://git-wip-us.apache.org/repos/asf/atlas/tree/0dad9529 Diff: http://git-wip-us.apache.org/repos/asf/atlas/diff/0dad9529 Branch: refs/heads/master Commit: 0dad95296daa5ee4ae38904eb211af0165503fb0 Parents: 15967a9 Author: apoorvnaik <[email protected]> Authored: Wed Mar 14 21:03:37 2018 -0700 Committer: Madhan Neethiraj <[email protected]> Committed: Sun Apr 15 01:24:45 2018 -0700 ---------------------------------------------------------------------- .../org/apache/atlas/repository/Constants.java | 67 ++- .../java/org/apache/atlas/AtlasErrorCode.java | 11 +- .../atlas/model/glossary/AtlasGlossaryTerm.java | 20 +- .../relations/AtlasRelatedCategoryHeader.java | 13 +- .../atlas/discovery/EntityDiscoveryService.java | 4 +- .../atlas/glossary/GlossaryCategoryUtils.java | 391 ++++++++++++ .../apache/atlas/glossary/GlossaryService.java | 596 +++++-------------- .../atlas/glossary/GlossaryTermUtils.java | 415 +++++++++++++ .../apache/atlas/glossary/GlossaryUtils.java | 86 +++ .../apache/atlas/repository/ogm/DataAccess.java | 8 +- .../ogm/glossary/AtlasGlossaryTermDTO.java | 8 +- .../graph/v1/AtlasRelationshipStoreV1.java | 1 + .../store/graph/v1/EntityGraphRetriever.java | 119 +++- .../atlas/glossary/GlossaryServiceTest.java | 396 +++++++----- .../org/apache/atlas/web/rest/GlossaryREST.java | 22 +- 15 files changed, 1467 insertions(+), 690 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/atlas/blob/0dad9529/common/src/main/java/org/apache/atlas/repository/Constants.java ---------------------------------------------------------------------- diff --git a/common/src/main/java/org/apache/atlas/repository/Constants.java b/common/src/main/java/org/apache/atlas/repository/Constants.java index 7ccc748..0cef5f2 100644 --- a/common/src/main/java/org/apache/atlas/repository/Constants.java +++ b/common/src/main/java/org/apache/atlas/repository/Constants.java @@ -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() { } http://git-wip-us.apache.org/repos/asf/atlas/blob/0dad9529/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java ---------------------------------------------------------------------- diff --git a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java index c6be362..539a225 100644 --- a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java +++ b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java @@ -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}"), http://git-wip-us.apache.org/repos/asf/atlas/blob/0dad9529/intg/src/main/java/org/apache/atlas/model/glossary/AtlasGlossaryTerm.java ---------------------------------------------------------------------- diff --git a/intg/src/main/java/org/apache/atlas/model/glossary/AtlasGlossaryTerm.java b/intg/src/main/java/org/apache/atlas/model/glossary/AtlasGlossaryTerm.java index f42bf35..3d714a8 100644 --- a/intg/src/main/java/org/apache/atlas/model/glossary/AtlasGlossaryTerm.java +++ b/intg/src/main/java/org/apache/atlas/model/glossary/AtlasGlossaryTerm.java @@ -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() { http://git-wip-us.apache.org/repos/asf/atlas/blob/0dad9529/intg/src/main/java/org/apache/atlas/model/glossary/relations/AtlasRelatedCategoryHeader.java ---------------------------------------------------------------------- diff --git a/intg/src/main/java/org/apache/atlas/model/glossary/relations/AtlasRelatedCategoryHeader.java b/intg/src/main/java/org/apache/atlas/model/glossary/relations/AtlasRelatedCategoryHeader.java index aa7a6b1..a62493e 100644 --- a/intg/src/main/java/org/apache/atlas/model/glossary/relations/AtlasRelatedCategoryHeader.java +++ b/intg/src/main/java/org/apache/atlas/model/glossary/relations/AtlasRelatedCategoryHeader.java @@ -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; + } } http://git-wip-us.apache.org/repos/asf/atlas/blob/0dad9529/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java index 36fb0bc..411d9b4 100644 --- a/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java +++ b/repository/src/main/java/org/apache/atlas/discovery/EntityDiscoveryService.java @@ -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())) { http://git-wip-us.apache.org/repos/asf/atlas/blob/0dad9529/repository/src/main/java/org/apache/atlas/glossary/GlossaryCategoryUtils.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/glossary/GlossaryCategoryUtils.java b/repository/src/main/java/org/apache/atlas/glossary/GlossaryCategoryUtils.java new file mode 100644 index 0000000..46d8889 --- /dev/null +++ b/repository/src/main/java/org/apache/atlas/glossary/GlossaryCategoryUtils.java @@ -0,0 +1,391 @@ +/** + * 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()); + } + } + +} http://git-wip-us.apache.org/repos/asf/atlas/blob/0dad9529/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java b/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java index 49c8f51..9fd795b 100644 --- a/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java +++ b/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java @@ -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; } } + }
