http://git-wip-us.apache.org/repos/asf/atlas/blob/75415862/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 new file mode 100644 index 0000000..91abf5e --- /dev/null +++ b/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java @@ -0,0 +1,1159 @@ +/** + * 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.SortOrder; +import org.apache.atlas.exception.AtlasBaseException; +import org.apache.atlas.model.glossary.AtlasGlossary; +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.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.repository.ogm.DataAccess; +import org.apache.atlas.repository.store.graph.AtlasRelationshipStore; +import org.apache.atlas.repository.store.graph.v1.AtlasGraphUtilsV1; +import org.apache.commons.collections.CollectionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +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; + + @Inject + public GlossaryService(DataAccess dataAccess, final AtlasRelationshipStore relationshipStore) { + this.dataAccess = dataAccess; + this.relationshipStore = relationshipStore; + } + + + /** + * List all glossaries + * + * @param limit page size - no paging by default + * @param offset offset for pagination + * @param sortOrder ASC (default) or DESC + * @return List of all glossaries + * @throws AtlasBaseException + */ + public List<AtlasGlossary> getGlossaries(int limit, int offset, SortOrder sortOrder) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.getGlossaries({}, {}, {})", limit, offset, sortOrder); + } + + List<String> glossaryGuids = AtlasGraphUtilsV1.findEntityGUIDsByType(ATLAS_GLOSSARY_PREFIX, sortOrder); + PaginationHelper paginationHelper = new PaginationHelper<>(glossaryGuids, offset, limit); + + List<AtlasGlossary> ret; + List<String> guidsToLoad = paginationHelper.getPaginatedList(); + if (CollectionUtils.isNotEmpty(guidsToLoad)) { + ret = guidsToLoad.stream().map(GlossaryService::getGlossarySkeleton).collect(Collectors.toList()); + Iterable<AtlasGlossary> glossaries = dataAccess.load(ret); + ret.clear(); + + glossaries.forEach(ret::add); + } else { + ret = Collections.emptyList(); + } + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.getGlossaries() : {}", ret); + } + return ret; + } + + /** + * Create a glossary + * + * @param atlasGlossary Glossary specification to be created + * @return Glossary definition + * @throws AtlasBaseException + */ + public AtlasGlossary createGlossary(AtlasGlossary atlasGlossary) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.createGlossary({})", atlasGlossary); + } + + 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"); + + } + AtlasGlossary saved = dataAccess.save(atlasGlossary); + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.createGlossary() : {}", saved); + } + return saved; + } + + /** + * Get specific glossary + * + * @param glossaryGuid unique identifier + * @return Glossary corresponding to specified glossaryGuid + * @throws AtlasBaseException + */ + public AtlasGlossary getGlossary(String glossaryGuid) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.getGlossary({})", glossaryGuid); + } + + if (Objects.isNull(glossaryGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "glossaryGuid is null/empty"); + } + + AtlasGlossary atlasGlossary = getGlossarySkeleton(glossaryGuid); + AtlasGlossary ret = dataAccess.load(atlasGlossary); + + setDisplayTextForRelations(ret); + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.getGlossary() : {}", ret); + } + return ret; + } + + /** + * Get specific glossary + * + * @param glossaryGuid unique identifier + * @return Glossary corresponding to specified glossaryGuid + * @throws AtlasBaseException + */ + public AtlasGlossary.AtlasGlossaryExtInfo getDetailedGlossary(String glossaryGuid) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.getGlossary({})", glossaryGuid); + } + + if (Objects.isNull(glossaryGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "glossaryGuid is null/empty"); + } + + AtlasGlossary atlasGlossary = getGlossarySkeleton(glossaryGuid); + AtlasGlossary glossary = dataAccess.load(atlasGlossary); + + AtlasGlossary.AtlasGlossaryExtInfo ret = new AtlasGlossary.AtlasGlossaryExtInfo(glossary); + + // Load all linked terms + if (CollectionUtils.isNotEmpty(ret.getTerms())) { + List<AtlasGlossaryTerm> termsToLoad = ret.getTerms() + .stream() + .map(id -> getAtlasGlossaryTermSkeleton(id.getTermGuid())) + .collect(Collectors.toList()); + Iterable<AtlasGlossaryTerm> glossaryTerms = dataAccess.load(termsToLoad); + glossaryTerms.forEach(ret::addTermInfo); + } + + // Load all linked categories + if (CollectionUtils.isNotEmpty(ret.getCategories())) { + List<AtlasGlossaryCategory> categoriesToLoad = ret.getCategories() + .stream() + .map(id -> getAtlasGlossaryCategorySkeleton(id.getCategoryGuid())) + .collect(Collectors.toList()); + Iterable<AtlasGlossaryCategory> glossaryCategories = dataAccess.load(categoriesToLoad); + glossaryCategories.forEach(ret::addCategoryInfo); + } + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.getGlossary() : {}", ret); + } + return ret; + } + + public AtlasGlossary updateGlossary(AtlasGlossary atlasGlossary) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.updateGlossary({})", atlasGlossary); + } + if (Objects.isNull(atlasGlossary)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Glossary is null/empty"); + } + + AtlasGlossary ret = dataAccess.load(atlasGlossary); + + if (!ret.equals(atlasGlossary)) { + atlasGlossary.setGuid(ret.getGuid()); + atlasGlossary.setQualifiedName(ret.getQualifiedName()); + + ret = dataAccess.save(atlasGlossary); + setDisplayTextForRelations(ret); + } + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.updateGlossary() : {}", ret); + } + return ret; + } + + public void deleteGlossary(String glossaryGuid) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.deleteGlossary({})", glossaryGuid); + } + if (Objects.isNull(glossaryGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "glossaryGuid is null/empty"); + } + + + // FIXME: When deleting all other related entities, the new edge label (r:<Relation>) is failing the delete calls + dataAccess.delete(glossaryGuid); + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.deleteGlossary()"); + } + } + + /* + * GlossaryTerms related operations + * */ + public AtlasGlossaryTerm getTerm(String termGuid) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.getTerm({})", termGuid); + } + if (Objects.isNull(termGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "termGuid is null/empty"); + } + + + AtlasGlossaryTerm atlasGlossary = getAtlasGlossaryTermSkeleton(termGuid); + AtlasGlossaryTerm ret = dataAccess.load(atlasGlossary); + + setDisplayTextForRelations(ret); + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.getTerm() : {}", ret); + } + return ret; + } + + public AtlasGlossaryTerm createTerm(AtlasGlossaryTerm glossaryTerm) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.create({})", glossaryTerm); + } + 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"); + } + + AtlasGlossaryTerm saved = dataAccess.save(glossaryTerm); + + // TODO: Create all term relations + processTermAnchor(glossaryTerm, saved); + processRelatedTerms(glossaryTerm, saved); + processAssociatedCategories(glossaryTerm, saved); + + saved = dataAccess.load(glossaryTerm); + setDisplayTextForRelations(saved); + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.create() : {}", saved); + } + return saved; + } + + public List<AtlasGlossaryTerm> createTerms(List<AtlasGlossaryTerm> glossaryTerm) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.create({})", glossaryTerm); + } + + if (Objects.isNull(glossaryTerm)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "glossaryTerm(s) is null/empty"); + } + + + List<AtlasGlossaryTerm> ret = new ArrayList<>(); + for (AtlasGlossaryTerm atlasGlossaryTerm : glossaryTerm) { + ret.add(createTerm(atlasGlossaryTerm)); + } + + if (LOG.isDebugEnabled()) { + LOG.debug("<== GlossaryService.createTerms() : {}", ret); + } + + return ret; + } + + public AtlasGlossaryTerm updateTerm(AtlasGlossaryTerm atlasGlossaryTerm) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.updateTerm({})", atlasGlossaryTerm); + } + if (Objects.isNull(atlasGlossaryTerm)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "atlasGlossaryTerm is null/empty"); + } + + + AtlasGlossaryTerm existing = dataAccess.load(atlasGlossaryTerm); + AtlasGlossaryTerm updated = atlasGlossaryTerm; + if (!existing.equals(updated)) { + try { + updated.setGuid(existing.getGuid()); + updated.setQualifiedName(existing.getQualifiedName()); + + atlasGlossaryTerm = dataAccess.save(updated); + } catch (AtlasBaseException e) { + LOG.debug("Glossary term had no immediate attr updates. Exception: {}", e.getMessage()); + } finally { + // TODO: Manage remaining term relations + processRelations(atlasGlossaryTerm, existing); + } + + } + + updated = dataAccess.load(atlasGlossaryTerm); + setDisplayTextForRelations(updated); + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.updateTerm() : {}", updated); + } + return updated; + } + + public void deleteTerm(String termGuid) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.deleteTerm({})", termGuid); + } + if (Objects.isNull(termGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "termGuid is null/empty"); + } + + + dataAccess.delete(termGuid); + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.deleteTerm()"); + } + } + + public void assignTermToEntities(String termGuid, Collection<AtlasEntityHeader> entityHeaders) throws AtlasBaseException { + AtlasGlossaryTerm glossaryTerm = dataAccess.load(getAtlasGlossaryTermSkeleton(termGuid)); + + 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)); + } + } + } + + public void removeTermFromEntities(String termGuid, Collection<AtlasEntityHeader> entityHeaders) throws AtlasBaseException { + AtlasGlossaryTerm glossaryTerm = dataAccess.load(getAtlasGlossaryTermSkeleton(termGuid)); + + 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); + } + } + } + + /* + * GlossaryCategory related operations + * */ + public AtlasGlossaryCategory getCategory(String categoryGuid) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.getCategory({})", categoryGuid); + } + if (Objects.isNull(categoryGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "categoryGuid is null/empty"); + } + + + AtlasGlossaryCategory atlasGlossary = getAtlasGlossaryCategorySkeleton(categoryGuid); + AtlasGlossaryCategory ret = dataAccess.load(atlasGlossary); + + setDisplayTextForRelations(ret); + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.getCategory() : {}", ret); + } + return ret; + } + + public AtlasGlossaryCategory createCategory(AtlasGlossaryCategory glossaryCategory) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.createCategory({})", glossaryCategory); + } + + 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"); + } + + 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); + } + + saved = dataAccess.load(glossaryCategory); + + setDisplayTextForRelations(glossaryCategory); + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.createCategory() : {}", saved); + } + + return saved; + } + + public List<AtlasGlossaryCategory> createCategories(List<AtlasGlossaryCategory> glossaryCategory) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.createCategories({})", glossaryCategory); + } + if (Objects.isNull(glossaryCategory)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "glossaryCategory is null/empty"); + } + + + List<AtlasGlossaryCategory> ret = new ArrayList<>(); + for (AtlasGlossaryCategory category : glossaryCategory) { + ret.add(createCategory(category)); + } + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.createCategories() : {}", ret); + } + return ret; + } + + public AtlasGlossaryCategory updateCategory(AtlasGlossaryCategory glossaryCategory) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.updateCategory({})", glossaryCategory); + } + if (Objects.isNull(glossaryCategory)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "GlossaryCategory is null/empty"); + } + + AtlasGlossaryCategory existing = dataAccess.load(glossaryCategory); + AtlasGlossaryCategory ret = glossaryCategory; + + if (!existing.equals(glossaryCategory)) { + try { + glossaryCategory.setGuid(existing.getGuid()); + glossaryCategory.setQualifiedName(existing.getQualifiedName()); + + ret = dataAccess.save(glossaryCategory); + } catch (AtlasBaseException e) { + LOG.debug("No immediate attribute update. Exception: {}", e.getMessage()); + } finally { + processRelations(glossaryCategory, existing); + } + } + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.updateCategory() : {}", ret); + } + ret = dataAccess.load(glossaryCategory); + + setDisplayTextForRelations(glossaryCategory); + + return ret; + } + + public void deleteCategory(String categoryGuid) throws AtlasBaseException { + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.deleteCategory({})", categoryGuid); + } + if (Objects.isNull(categoryGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Category guid is null/empty"); + } + + dataAccess.delete(categoryGuid); + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.deleteCategory()"); + } + + } + + public List<AtlasGlossaryTerm> getGlossaryTerms(String glossaryGuid, int offset, int limit, SortOrder sortOrder) throws AtlasBaseException { + if (Objects.isNull(glossaryGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "glossaryGuid is null/empty"); + } + + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.getGlossaryTerms({}, {}, {}, {})", glossaryGuid, offset, limit, sortOrder); + } + + AtlasGlossary glossary = getGlossary(glossaryGuid); + + List<AtlasGlossaryTerm> ret; + if (CollectionUtils.isNotEmpty(glossary.getTerms())) { + List<AtlasGlossaryTerm> toLoad = glossary.getTerms().stream() + .map(t -> getAtlasGlossaryTermSkeleton(t.getTermGuid())) + .collect(Collectors.toList()); + Iterable<AtlasGlossaryTerm> terms = dataAccess.load(toLoad); + toLoad.clear(); + terms.forEach(toLoad::add); + if (sortOrder != null) { + toLoad.sort((o1, o2) -> sortOrder == SortOrder.ASCENDING ? + o1.getDisplayName().compareTo(o2.getDisplayName()) : + o2.getDisplayName().compareTo(o1.getDisplayName())); + } + ret = new PaginationHelper<>(toLoad, offset, limit).getPaginatedList(); + } else { + ret = Collections.emptyList(); + } + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.getGlossaryTerms() : {}", ret); + } + + return ret; + } + + public List<AtlasRelatedCategoryHeader> getGlossaryCategories(String glossaryGuid, int offset, int limit, SortOrder sortOrder) throws AtlasBaseException { + if (Objects.isNull(glossaryGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "glossaryGuid is null/empty"); + } + + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.getGlossaryCategories({}, {}, {}, {})", glossaryGuid, offset, limit, sortOrder); + } + + AtlasGlossary glossary = getGlossary(glossaryGuid); + + List<AtlasRelatedCategoryHeader> ret; + + List<AtlasRelatedCategoryHeader> categories = new ArrayList<>(glossary.getCategories()); + if (CollectionUtils.isNotEmpty(categories)) { + if (sortOrder != null) { + categories.sort((o1, o2) -> sortOrder == SortOrder.ASCENDING ? + o1.getDisplayText().compareTo(o2.getDisplayText()) : + o2.getDisplayText().compareTo(o1.getDisplayText())); + } + ret = new PaginationHelper<>(categories, offset, limit).getPaginatedList(); + } else { + ret = Collections.emptyList(); + } + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.getGlossaryCategories() : {}", ret); + } + + return ret; + } + + public List<AtlasRelatedTermHeader> getCategoryTerms(String categoryGuid, int offset, int limit, SortOrder sortOrder) throws AtlasBaseException { + if (Objects.isNull(categoryGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "categoryGuid is null/empty"); + } + + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.getCategoryTerms({}, {}, {}, {})", categoryGuid, offset, limit, sortOrder); + } + AtlasGlossaryCategory glossaryCategory = getCategory(categoryGuid); + + List<AtlasRelatedTermHeader> ret; + List<AtlasRelatedTermHeader> terms = new ArrayList<>(glossaryCategory.getTerms()); + 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())); + } + ret = new PaginationHelper<>(terms, offset, limit).getPaginatedList(); + } else { + ret = Collections.emptyList(); + } + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.getCategoryTerms() : {}", ret); + } + return ret; + } + + public Map<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> getRelatedTerms(String termGuid, int offset, int limit, SortOrder sortOrder) throws AtlasBaseException { + if (Objects.isNull(termGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "termGuid is null/empty"); + } + + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.getRelatedTerms({}, {}, {}, {})", termGuid, offset, limit, sortOrder); + } + + AtlasGlossaryTerm glossaryTerm = getTerm(termGuid); + Map<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> ret; + if (glossaryTerm.hasTerms()) { + ret = glossaryTerm.getRelatedTerms(); + } else { + ret = Collections.emptyMap(); + } + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.getRelatedTerms() : {}", ret); + } + + return ret; + } + + public Map<String, List<AtlasRelatedCategoryHeader>> getRelatedCategories(String categoryGuid, int offset, int limit, SortOrder sortOrder) throws AtlasBaseException { + if (Objects.isNull(categoryGuid)) { + throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "categoryGuid is null/empty"); + } + + if (DEBUG_ENABLED) { + LOG.debug("==> GlossaryService.getRelatedCategories({}, {}, {}, {})", categoryGuid, offset, limit, sortOrder); + } + + AtlasGlossaryCategory glossaryCategory = getCategory(categoryGuid); + + Map<String, List<AtlasRelatedCategoryHeader>> ret = new HashMap<>(); + if (glossaryCategory.getParentCategory() != null) { + ret.put("parent", new ArrayList<AtlasRelatedCategoryHeader>() {{ + add(glossaryCategory.getParentCategory()); + }}); + } + if (CollectionUtils.isNotEmpty(glossaryCategory.getChildrenCategories())) { + ret.put("children", new ArrayList<>(glossaryCategory.getChildrenCategories())); + } + + + if (DEBUG_ENABLED) { + LOG.debug("<== GlossaryService.getRelatedCategories() : {}", ret); + } + + return ret; + } + + public List<AtlasEntityHeader> 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(); + + List<AtlasEntityHeader> ret; + if (CollectionUtils.isNotEmpty(assignedEntities)) { + ret = new ArrayList<>(assignedEntities); + if (sortOrder != null) { + ret.sort((o1, o2) -> sortOrder == SortOrder.ASCENDING ? + o1.getDisplayText().compareTo(o2.getDisplayText()) : + o2.getDisplayText().compareTo(o1.getDisplayText())); + } + ret = new PaginationHelper<>(assignedEntities, offset, limit).getPaginatedList(); + } else { + ret = Collections.emptyList(); + } + + return ret; + } + + private static AtlasGlossary getGlossarySkeleton(String glossaryGuid) { + AtlasGlossary glossary = new AtlasGlossary(); + glossary.setGuid(glossaryGuid); + return glossary; + } + + private void processAssignedEntities(final AtlasGlossaryTerm newObj, final AtlasGlossaryTerm existing) throws AtlasBaseException { + if (newObj.equals(existing)) return; + + if (CollectionUtils.isNotEmpty(newObj.getAssignedEntities())) { + for (AtlasEntityHeader entityHeader : newObj.getAssignedEntities()) { + createRelationship(defineTermAssignment(existing.getGuid(), entityHeader)); + } + } + } + + private void setDisplayTextForRelations(final AtlasGlossary ret) throws AtlasBaseException { + if (Objects.nonNull(ret.getTerms())) { + setDisplayNameForTerms(ret.getTerms()); + } + + if (Objects.nonNull(ret.getCategories())) { + setDisplayNameForRelatedCategories(ret.getCategories()); + } + } + + private void setDisplayTextForRelations(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()); + } + } + } + + private void setDisplayTextForRelations(final AtlasGlossaryCategory glossaryCategory) throws AtlasBaseException { + if (Objects.nonNull(glossaryCategory.getChildrenCategories())) { + setDisplayNameForRelatedCategories(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); + } + } + + private void setDisplayNameForTermCategories(final Set<AtlasTermCategorizationHeader> categorizationHeaders) throws AtlasBaseException { + List<AtlasGlossaryCategory> categories = categorizationHeaders + .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)); + categorizationHeaders.forEach(c -> c.setDisplayText(categoryMap.get(c.getCategoryGuid()).getDisplayName())); + } + + private void setDisplayNameForRelatedCategories(final Set<AtlasRelatedCategoryHeader> categoryHeaders) throws AtlasBaseException { + List<AtlasGlossaryCategory> categories = categoryHeaders + .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())); + } + + private void setDisplayNameForTerms(final Set<AtlasRelatedTermHeader> termHeaders) throws AtlasBaseException { + List<AtlasGlossaryTerm> terms = termHeaders + .stream() + .map(id -> getAtlasGlossaryTermSkeleton(id.getTermGuid())) + .collect(Collectors.toList()); + Map<String, AtlasGlossaryTerm> termMap = new HashMap<>(); + dataAccess.load(terms).iterator().forEachRemaining(t -> termMap.put(t.getGuid(), t)); + + 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(), glossaryTerm.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; + private int maxSize; + private List<T> items; + + PaginationHelper(Collection<T> items, int offset, int limit) { + Objects.requireNonNull(items, "items can't be empty/null"); + this.items = new ArrayList<>(items); + this.maxSize = items.size(); + + // If limit is negative then limit is effectively the maxSize, else the smaller one out of limit and maxSize + int adjustedLimit = limit < 0 ? maxSize : Integer.min(maxSize, limit); + // Page starting can only be between zero and adjustedLimit + pageStart = Integer.max(0, offset); + // Page end can't exceed the maxSize + pageEnd = Integer.min(adjustedLimit + pageStart, maxSize); + } + + List<T> getPaginatedList() { + List<T> ret; + if (isValidOffset()) { + if (isPagingNeeded()) { + ret = items.subList(pageStart, pageEnd); + } else { + ret = items; + } + } else { + ret = Collections.emptyList(); + } + + return ret; + } + + private boolean isPagingNeeded() { + return !(pageStart == 0 && pageEnd == maxSize) && pageStart <= pageEnd; + } + + private boolean isValidOffset() { + return pageStart <= maxSize; + } + } +}
http://git-wip-us.apache.org/repos/asf/atlas/blob/75415862/repository/src/main/java/org/apache/atlas/repository/ogm/AbstractDataTransferObject.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/ogm/AbstractDataTransferObject.java b/repository/src/main/java/org/apache/atlas/repository/ogm/AbstractDataTransferObject.java index f1a8bc9..2afdfe1 100644 --- a/repository/src/main/java/org/apache/atlas/repository/ogm/AbstractDataTransferObject.java +++ b/repository/src/main/java/org/apache/atlas/repository/ogm/AbstractDataTransferObject.java @@ -27,14 +27,24 @@ import org.apache.commons.lang3.StringUtils; public abstract class AbstractDataTransferObject<T extends AtlasBaseModelObject> implements DataTransferObject<T> { + + private static final String DEFAULT_PREFIX = "Atlas"; + private final AtlasTypeRegistry typeRegistry; private final Class<T> objectType; private final String entityTypeName; + private final String alternateEntityTypeName; - protected AbstractDataTransferObject(AtlasTypeRegistry typeRegistry, Class<T> tClass) { + protected AbstractDataTransferObject(AtlasTypeRegistry typeRegistry, Class<T> tClass, boolean isInternal) { this.typeRegistry = typeRegistry; this.objectType = tClass; - this.entityTypeName = Constants.INTERNAL_PROPERTY_KEY_PREFIX + objectType.getSimpleName(); + if (isInternal) { + this.entityTypeName = Constants.INTERNAL_PROPERTY_KEY_PREFIX + objectType.getSimpleName(); + this.alternateEntityTypeName = null; + } else { + this.entityTypeName = objectType.getSimpleName(); + this.alternateEntityTypeName = entityTypeName.startsWith(DEFAULT_PREFIX) ? entityTypeName.substring(DEFAULT_PREFIX.length()) : null; + } } @Override @@ -44,7 +54,11 @@ public abstract class AbstractDataTransferObject<T extends AtlasBaseModelObject> @Override public AtlasEntityType getEntityType() { - return typeRegistry.getEntityTypeByName(entityTypeName); + AtlasEntityType ret = typeRegistry.getEntityTypeByName(entityTypeName); + if (ret == null) { + ret = typeRegistry.getEntityTypeByName(alternateEntityTypeName); + } + return ret; } http://git-wip-us.apache.org/repos/asf/atlas/blob/75415862/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasSavedSearchDTO.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasSavedSearchDTO.java b/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasSavedSearchDTO.java deleted file mode 100644 index a1a8f59..0000000 --- a/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasSavedSearchDTO.java +++ /dev/null @@ -1,105 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * <p> - * http://www.apache.org/licenses/LICENSE-2.0 - * <p> - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.atlas.repository.ogm; - -import org.apache.atlas.exception.AtlasBaseException; -import org.apache.atlas.model.discovery.SearchParameters; -import org.apache.atlas.model.instance.AtlasEntity; -import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo; -import org.apache.atlas.model.profile.AtlasUserSavedSearch; -import org.apache.atlas.type.AtlasType; -import org.apache.atlas.type.AtlasTypeRegistry; -import org.apache.commons.lang3.StringUtils; - -import java.util.HashMap; -import java.util.Map; - - -public class AtlasSavedSearchDTO extends AbstractDataTransferObject<AtlasUserSavedSearch> { - private static final String PROPERTY_NAME = "name"; - private static final String PROPERTY_OWNER_NAME = "ownerName"; - private static final String PROPERTY_SEARCH_PARAMETERS = "searchParameters"; - private static final String PROPERTY_UNIQUE_NAME = "uniqueName"; - private static final String PROPERTY_SEARCH_TYPE = "searchType"; - private static final String PROPERTY_UI_PARAMETERS = "uiParameters"; - - public AtlasSavedSearchDTO(AtlasTypeRegistry typeRegistry) { - super(typeRegistry, AtlasUserSavedSearch.class); - } - - @Override - public AtlasUserSavedSearch from(AtlasEntity entity) { - AtlasUserSavedSearch savedSearch = new AtlasUserSavedSearch(); - - savedSearch.setGuid(entity.getGuid()); - savedSearch.setName((String) entity.getAttribute(PROPERTY_NAME)); - savedSearch.setOwnerName((String) entity.getAttribute(PROPERTY_OWNER_NAME)); - savedSearch.setSearchType(AtlasUserSavedSearch.SavedSearchType.to((String) entity.getAttribute(PROPERTY_SEARCH_TYPE))); - - String jsonSearchParams = (String) entity.getAttribute(PROPERTY_SEARCH_PARAMETERS); - - if (StringUtils.isNotEmpty(jsonSearchParams)) { - savedSearch.setSearchParameters(AtlasType.fromJson(jsonSearchParams, SearchParameters.class)); - } - - savedSearch.setUiParameters((String) entity.getAttribute(PROPERTY_UI_PARAMETERS)); - - return savedSearch; - } - - @Override - public AtlasUserSavedSearch from(AtlasEntityWithExtInfo entityWithExtInfo) { - return from(entityWithExtInfo.getEntity()); - } - - @Override - public AtlasEntity toEntity(AtlasUserSavedSearch obj) throws AtlasBaseException { - AtlasEntity entity = getDefaultAtlasEntity(obj); - - entity.setAttribute(PROPERTY_NAME, obj.getName()); - entity.setAttribute(PROPERTY_OWNER_NAME, obj.getOwnerName()); - entity.setAttribute(PROPERTY_SEARCH_TYPE, obj.getSearchType()); - entity.setAttribute(PROPERTY_UNIQUE_NAME, getUniqueValue(obj)); - - if (obj.getSearchParameters() != null) { - entity.setAttribute(PROPERTY_SEARCH_PARAMETERS, AtlasType.toJson(obj.getSearchParameters())); - } - - entity.setAttribute(PROPERTY_UI_PARAMETERS, obj.getUiParameters()); - - return entity; - } - - @Override - public AtlasEntityWithExtInfo toEntityWithExtInfo(AtlasUserSavedSearch obj) throws AtlasBaseException { - return new AtlasEntityWithExtInfo(toEntity(obj)); - } - - @Override - public Map<String, Object> getUniqueAttributes(AtlasUserSavedSearch obj) { - Map<String, Object> ret = new HashMap<>(); - - ret.put(PROPERTY_UNIQUE_NAME, getUniqueValue(obj)); - - return ret; - } - - private String getUniqueValue(AtlasUserSavedSearch obj) { - return String.format("%s:%s", obj.getOwnerName(), obj.getName()) ; - } -} http://git-wip-us.apache.org/repos/asf/atlas/blob/75415862/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasUserProfileDTO.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasUserProfileDTO.java b/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasUserProfileDTO.java deleted file mode 100644 index bcf2b9d..0000000 --- a/repository/src/main/java/org/apache/atlas/repository/ogm/AtlasUserProfileDTO.java +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * <p> - * http://www.apache.org/licenses/LICENSE-2.0 - * <p> - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.atlas.repository.ogm; - -import org.apache.atlas.exception.AtlasBaseException; -import org.apache.atlas.model.instance.AtlasEntity; -import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo; -import org.apache.atlas.model.instance.AtlasObjectId; -import org.apache.atlas.model.profile.AtlasUserProfile; -import org.apache.atlas.model.profile.AtlasUserSavedSearch; -import org.apache.atlas.type.AtlasTypeRegistry; - -import java.util.*; - -public class AtlasUserProfileDTO extends AbstractDataTransferObject<AtlasUserProfile> { - private final String PROPERTY_USER_NAME = "name"; - private final String PROPERTY_FULL_NAME = "fullName"; - private final String PROPERTY_SAVED_SEARCHES = "savedSearches"; - - private final AtlasSavedSearchDTO savedSearchDTO; - - public AtlasUserProfileDTO(AtlasTypeRegistry typeRegistry, AtlasSavedSearchDTO savedSearchDTO) { - super(typeRegistry, AtlasUserProfile.class); - - this.savedSearchDTO = savedSearchDTO; - } - - public AtlasUserProfile from(AtlasEntity entity) { - AtlasUserProfile profile = new AtlasUserProfile(); - - profile.setGuid(entity.getGuid()); - profile.setName((String) entity.getAttribute(PROPERTY_USER_NAME)); - profile.setFullName((String) entity.getAttribute(PROPERTY_FULL_NAME)); - - return profile; - } - - public AtlasUserProfile from(AtlasEntityWithExtInfo entityWithExtInfo) { - AtlasUserProfile userProfile = from(entityWithExtInfo.getEntity()); - - Object savedSearches = entityWithExtInfo.getEntity().getAttribute(PROPERTY_SAVED_SEARCHES); - - if (savedSearches instanceof Collection) { - for (Object o : (Collection) savedSearches) { - if (o instanceof AtlasObjectId) { - AtlasObjectId ssObjId = (AtlasObjectId) o; - AtlasEntity ssEntity = entityWithExtInfo.getReferredEntity(ssObjId.getGuid()); - - if (ssEntity != null && ssEntity.getStatus() == AtlasEntity.Status.ACTIVE) { - AtlasUserSavedSearch savedSearch = savedSearchDTO.from(ssEntity); - userProfile.getSavedSearches().add(savedSearch); - } - } - } - } - - return userProfile; - } - - @Override - public AtlasEntity toEntity(AtlasUserProfile obj) throws AtlasBaseException { - AtlasEntity entity = getDefaultAtlasEntity(obj); - - entity.setAttribute(PROPERTY_USER_NAME, obj.getName()); - entity.setAttribute(PROPERTY_FULL_NAME, obj.getFullName()); - - return entity; - } - - @Override - public AtlasEntityWithExtInfo toEntityWithExtInfo(AtlasUserProfile obj) throws AtlasBaseException { - AtlasEntity entity = toEntity(obj); - AtlasEntityWithExtInfo entityWithExtInfo = new AtlasEntityWithExtInfo(entity); - - List<AtlasObjectId> objectIds = new ArrayList<>(); - - for (AtlasUserSavedSearch ss : obj.getSavedSearches()) { - AtlasEntity ssEntity = savedSearchDTO.toEntity(ss); - - entityWithExtInfo.addReferredEntity(ssEntity); - - objectIds.add(new AtlasObjectId(ssEntity.getGuid(), savedSearchDTO.getEntityType().getTypeName(), savedSearchDTO.getUniqueAttributes(ss))); - } - - if (objectIds.size() > 0) { - entity.setAttribute(PROPERTY_SAVED_SEARCHES, objectIds); - } - - return entityWithExtInfo; - } - - @Override - public Map<String, Object> getUniqueAttributes(AtlasUserProfile obj) { - Map<String, Object> ret = new HashMap<>(); - - ret.put(PROPERTY_USER_NAME, obj.getName()); - - return ret; - } -} http://git-wip-us.apache.org/repos/asf/atlas/blob/75415862/repository/src/main/java/org/apache/atlas/repository/ogm/DTORegistry.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/ogm/DTORegistry.java b/repository/src/main/java/org/apache/atlas/repository/ogm/DTORegistry.java index 818960d..43f4a60 100644 --- a/repository/src/main/java/org/apache/atlas/repository/ogm/DTORegistry.java +++ b/repository/src/main/java/org/apache/atlas/repository/ogm/DTORegistry.java @@ -17,29 +17,30 @@ */ package org.apache.atlas.repository.ogm; -import org.apache.atlas.type.AtlasTypeRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.inject.Inject; -import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; +import java.util.Set; @Component public class DTORegistry { - private final Map<Type, DataTransferObject> typeDTOMap = new HashMap<>(); + private static final Logger LOG = LoggerFactory.getLogger(DTORegistry.class); + private final Map<Class, DataTransferObject> typeDTOMap = new HashMap<>(); @Inject - public DTORegistry(AtlasTypeRegistry typeRegistry) { - AtlasSavedSearchDTO savedSearchDTO = new AtlasSavedSearchDTO(typeRegistry); - AtlasUserProfileDTO userProfileDTO = new AtlasUserProfileDTO(typeRegistry, savedSearchDTO); - - registerDTO(savedSearchDTO); - registerDTO(userProfileDTO); + public DTORegistry(Set<DataTransferObject> availableDTOs) { + for (DataTransferObject availableDTO : availableDTOs) { + LOG.info("Registering DTO: {}", availableDTO.getClass().getSimpleName()); + registerDTO(availableDTO); + } } - public <T extends DataTransferObject> DataTransferObject get(Type t) { + public <T extends DataTransferObject> DataTransferObject get(Class t) { return typeDTOMap.get(t); } http://git-wip-us.apache.org/repos/asf/atlas/blob/75415862/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java b/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java index c99d2f8..e00c3e9 100644 --- a/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java +++ b/repository/src/main/java/org/apache/atlas/repository/ogm/DataAccess.java @@ -20,18 +20,29 @@ package org.apache.atlas.repository.ogm; import org.apache.atlas.AtlasErrorCode; import org.apache.atlas.exception.AtlasBaseException; import org.apache.atlas.model.AtlasBaseModelObject; +import org.apache.atlas.model.instance.AtlasEntity; import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo; import org.apache.atlas.model.instance.EntityMutationResponse; import org.apache.atlas.repository.store.graph.AtlasEntityStore; import org.apache.atlas.repository.store.graph.v1.AtlasEntityStream; +import org.apache.atlas.utils.AtlasPerfTracer; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; @Component public class DataAccess { + private static final Logger LOG = LoggerFactory.getLogger(DataAccess.class); + private static final Logger PERF_LOG = AtlasPerfTracer.getPerfLogger("repository.DataAccess"); + private final AtlasEntityStore entityStore; private final DTORegistry dtoRegistry; @@ -42,49 +53,186 @@ public class DataAccess { } public <T extends AtlasBaseModelObject> T save(T obj) throws AtlasBaseException { - DataTransferObject<T> dto = (DataTransferObject<T>)dtoRegistry.get(obj.getClass()); + Objects.requireNonNull(obj, "Can't save a null object"); + + AtlasPerfTracer perf = null; + + try { + if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { + perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DataAccess.save()"); + } + + DataTransferObject<T> dto = (DataTransferObject<T>) dtoRegistry.get(obj.getClass()); + + AtlasEntityWithExtInfo entityWithExtInfo = dto.toEntityWithExtInfo(obj); + EntityMutationResponse entityMutationResponse = entityStore.createOrUpdate(new AtlasEntityStream(entityWithExtInfo), false); + + if (noEntityMutation(entityMutationResponse)) { + throw new AtlasBaseException(AtlasErrorCode.DATA_ACCESS_SAVE_FAILED, obj.toString()); + } - AtlasEntityWithExtInfo entityWithExtInfo = dto.toEntityWithExtInfo(obj); - EntityMutationResponse entityMutationResponse = entityStore.createOrUpdate(new AtlasEntityStream(entityWithExtInfo), false); + // Since mutation context has guid information, attempt to set the same. + if (entityMutationResponse.getFirstEntityCreated() != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("Object created"); + } + obj.setGuid(entityMutationResponse.getFirstEntityCreated().getGuid()); + } else if (entityMutationResponse.getFirstEntityUpdated() != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("Object updated"); + } + obj.setGuid(entityMutationResponse.getFirstEntityUpdated().getGuid()); + } - if (hasError(entityMutationResponse)) { - throw new AtlasBaseException(AtlasErrorCode.DATA_ACCESS_SAVE_FAILED, obj.toString()); + return this.load(obj); + + } finally { + AtlasPerfTracer.log(perf); } - return this.load(obj); + } + + public <T extends AtlasBaseModelObject> Iterable<T> save(Iterable<T> obj) throws AtlasBaseException { + Objects.requireNonNull(obj, "Can't save a null object"); + + AtlasPerfTracer perf = null; + + try { + if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { + perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DataAccess.multiSave()"); + } + + List<T> ret = new ArrayList<>(); + for (T o : obj) { + ret.add(save(o)); + } + return ret; + + } finally { + AtlasPerfTracer.log(perf); + } + } + + public <T extends AtlasBaseModelObject> Iterable<T> load(final Iterable<T> objects) throws AtlasBaseException { + Objects.requireNonNull(objects, "Objects to load"); + + AtlasPerfTracer perf = null; + + try { + if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { + perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DataAccess.multiLoad()"); + } + + List<AtlasBaseModelObject> ret = new ArrayList<>(); + + for (T object : objects) { + ret.add(load(object)); + } + + return (Iterable<T>) ret; + + } finally { + AtlasPerfTracer.log(perf); + } } public <T extends AtlasBaseModelObject> T load(T obj) throws AtlasBaseException { - DataTransferObject<T> dto = (DataTransferObject<T>)dtoRegistry.get(obj.getClass()); + return load(obj, false); + } + + public <T extends AtlasBaseModelObject> T load(T obj, boolean loadDeleted) throws AtlasBaseException { + Objects.requireNonNull(obj, "Can't load a null object"); + + AtlasPerfTracer perf = null; + + try { + if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { + perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DataAccess.load()"); + } + + DataTransferObject<T> dto = (DataTransferObject<T>) dtoRegistry.get(obj.getClass()); + + AtlasEntityWithExtInfo entityWithExtInfo; - AtlasEntityWithExtInfo entityWithExtInfo; + if (StringUtils.isNotEmpty(obj.getGuid())) { + if (LOG.isDebugEnabled()) { + LOG.debug("Load using GUID"); + } + entityWithExtInfo = entityStore.getById(obj.getGuid()); + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("Load using unique attributes"); + } + entityWithExtInfo = entityStore.getByUniqueAttributes(dto.getEntityType(), dto.getUniqueAttributes(obj)); + } - if (StringUtils.isNotEmpty(obj.getGuid())) { - entityWithExtInfo = entityStore.getById(obj.getGuid()); - } else { - entityWithExtInfo = entityStore.getByUniqueAttributes(dto.getEntityType(), dto.getUniqueAttributes(obj)); + if (!loadDeleted && entityWithExtInfo.getEntity().getStatus() == AtlasEntity.Status.DELETED) { + throw new AtlasBaseException(AtlasErrorCode.INSTANCE_GUID_DELETED, obj.getGuid()); + } + + return dto.from(entityWithExtInfo); + + } finally { + AtlasPerfTracer.log(perf); } - return dto.from(entityWithExtInfo); } + public void delete(String guid) throws AtlasBaseException { + Objects.requireNonNull(guid, "guid"); + AtlasPerfTracer perf = null; + + try { + if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { + perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DataAccess.delete()"); + } + + entityStore.deleteById(guid); + + } finally { + AtlasPerfTracer.log(perf); + } + } + + public void delete(List<String> guids) throws AtlasBaseException { + Objects.requireNonNull(guids, "guids"); + + AtlasPerfTracer perf = null; + + try { + if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { + perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DataAccess.multiDelete()"); + } + + entityStore.deleteByIds(guids); - public void deleteUsingGuid(String guid) throws AtlasBaseException { - entityStore.deleteById(guid); + } finally { + AtlasPerfTracer.log(perf); + } } public <T extends AtlasBaseModelObject> void delete(T obj) throws AtlasBaseException { - T object = load(obj); + Objects.requireNonNull(obj, "Can't delete a null object"); + + AtlasPerfTracer perf = null; + + try { + if (AtlasPerfTracer.isPerfTraceEnabled(PERF_LOG)) { + perf = AtlasPerfTracer.getPerfTracer(PERF_LOG, "DataAccess.delete()"); + } + + T object = load(obj); + + if (object != null) { + delete(object.getGuid()); + } - if (object != null) { - deleteUsingGuid(object.getGuid()); + } finally { + AtlasPerfTracer.log(perf); } } - private boolean hasError(EntityMutationResponse er) { - return (er == null || - !((er.getCreatedEntities() != null && er.getCreatedEntities().size() > 0) - || (er.getUpdatedEntities() != null && er.getUpdatedEntities().size() > 0) - ) - ); + // Helper functions + private boolean noEntityMutation(EntityMutationResponse er) { + return er == null || (CollectionUtils.isEmpty(er.getCreatedEntities()) && CollectionUtils.isEmpty(er.getUpdatedEntities())); } } http://git-wip-us.apache.org/repos/asf/atlas/blob/75415862/repository/src/main/java/org/apache/atlas/repository/ogm/glossary/AbstractGlossaryDTO.java ---------------------------------------------------------------------- diff --git a/repository/src/main/java/org/apache/atlas/repository/ogm/glossary/AbstractGlossaryDTO.java b/repository/src/main/java/org/apache/atlas/repository/ogm/glossary/AbstractGlossaryDTO.java new file mode 100644 index 0000000..722a463 --- /dev/null +++ b/repository/src/main/java/org/apache/atlas/repository/ogm/glossary/AbstractGlossaryDTO.java @@ -0,0 +1,163 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.atlas.repository.ogm.glossary; + +import org.apache.atlas.model.AtlasBaseModelObject; +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.AtlasRelatedObjectId; +import org.apache.atlas.model.instance.AtlasRelationship; +import org.apache.atlas.model.instance.AtlasStruct; +import org.apache.atlas.repository.ogm.AbstractDataTransferObject; +import org.apache.atlas.type.AtlasTypeRegistry; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +public abstract class AbstractGlossaryDTO<T extends AtlasBaseModelObject> extends AbstractDataTransferObject<T> { + protected AbstractGlossaryDTO(final AtlasTypeRegistry typeRegistry, final Class<T> tClass, final boolean isInternal) { + super(typeRegistry, tClass, isInternal); + } + + protected AtlasRelatedTermHeader constructRelatedTermId(AtlasRelatedObjectId relatedObjectId) { + AtlasRelatedTermHeader ret = new AtlasRelatedTermHeader(); + + ret.setTermGuid(relatedObjectId.getGuid()); + ret.setRelationGuid(relatedObjectId.getRelationshipGuid()); + + AtlasStruct relationshipAttributes = relatedObjectId.getRelationshipAttributes(); + if (relationshipAttributes != null) { + ret.setDescription((String) relationshipAttributes.getAttribute("description")); + ret.setExpression((String) relationshipAttributes.getAttribute("expression")); + ret.setSource((String) relationshipAttributes.getAttribute("source")); + ret.setSteward((String) relationshipAttributes.getAttribute("steward")); + Object status = relationshipAttributes.getAttribute("status"); + if (status instanceof String) { + ret.setStatus(AtlasTermRelationshipStatus.valueOf((String) status)); + } else if (status instanceof AtlasTermRelationshipStatus) { + ret.setStatus((AtlasTermRelationshipStatus) status); + } + } + + return ret; + } + + protected AtlasRelatedObjectId termIdToRelatedObjectId(AtlasRelatedTermHeader relatedTermId) { + AtlasRelatedObjectId ret = new AtlasRelatedObjectId(); + + ret.setGuid(relatedTermId.getTermGuid()); + ret.setRelationshipGuid(relatedTermId.getRelationGuid()); + + AtlasStruct relationshipAttributes = new AtlasStruct(); + relationshipAttributes.setAttribute("description", relatedTermId.getDescription()); + relationshipAttributes.setAttribute("expression", relatedTermId.getExpression()); + relationshipAttributes.setAttribute("source", relatedTermId.getSource()); + relationshipAttributes.setAttribute("steward", relatedTermId.getSteward()); + relationshipAttributes.setAttribute("status", relatedTermId.getStatus().name()); + + ret.setRelationshipAttributes(relationshipAttributes); + + return ret; + } + + protected AtlasRelatedCategoryHeader constructRelatedCategoryId(AtlasRelatedObjectId relatedObjectId) { + AtlasRelatedCategoryHeader ret = new AtlasRelatedCategoryHeader(); + + ret.setCategoryGuid(relatedObjectId.getGuid()); + ret.setRelationGuid(relatedObjectId.getRelationshipGuid()); + + AtlasStruct relationshipAttributes = relatedObjectId.getRelationshipAttributes(); + if (relationshipAttributes != null) { + ret.setDescription((String) relationshipAttributes.getAttribute("description")); + } + + return ret; + } + + protected AtlasRelatedObjectId relatedCategoryIdToRelatedObjectId(AtlasRelatedCategoryHeader relatedCategoryId) { + AtlasRelatedObjectId ret = new AtlasRelatedObjectId(); + + ret.setGuid(relatedCategoryId.getCategoryGuid()); + ret.setRelationshipGuid(relatedCategoryId.getRelationGuid()); + + AtlasStruct relationshipAttributes = new AtlasStruct(); + relationshipAttributes.setAttribute("description", relatedCategoryId.getDescription()); + ret.setRelationshipAttributes(relationshipAttributes); + + return ret; + } + + protected AtlasGlossaryHeader constructGlossaryId(AtlasRelatedObjectId relatedObjectId) { + AtlasGlossaryHeader ret = new AtlasGlossaryHeader(); + + ret.setGlossaryGuid(relatedObjectId.getGuid()); + ret.setRelationGuid(relatedObjectId.getRelationshipGuid()); + + return ret; + } + + protected AtlasRelatedObjectId glossaryIdToRelatedObjectId(AtlasGlossaryHeader glossaryId) { + AtlasRelatedObjectId ret = new AtlasRelatedObjectId(); + + ret.setGuid(glossaryId.getGlossaryGuid()); + ret.setRelationshipGuid(glossaryId.getRelationGuid()); + + return ret; + } + + protected AtlasTermCategorizationHeader constructTermCategorizationId(final AtlasRelatedObjectId category) { + AtlasTermCategorizationHeader ret = new AtlasTermCategorizationHeader(); + + ret.setCategoryGuid(category.getGuid()); + ret.setRelationGuid(category.getRelationshipGuid()); + + AtlasStruct relationshipAttributes = category.getRelationshipAttributes(); + if (relationshipAttributes != null) { + ret.setDescription((String) relationshipAttributes.getAttribute("description")); + Object status = relationshipAttributes.getAttribute("status"); + if (status instanceof AtlasTermRelationshipStatus) { + ret.setStatus((AtlasTermRelationshipStatus) status); + } else if (status instanceof String) { + ret.setStatus(AtlasTermRelationshipStatus.valueOf((String) status)); + } + } + + return ret; + } + + protected Set<AtlasRelatedTermHeader> toRelatedTermIdsSet(Object relatedObjectIds) { + Set<AtlasRelatedTermHeader> ret = null; + + if (relatedObjectIds instanceof Collection) { + ret = new HashSet<>(); + for (Object t : (Collection) relatedObjectIds) { + if (t instanceof AtlasRelatedObjectId) { + if (((AtlasRelatedObjectId) t).getRelationshipStatus() == AtlasRelationship.Status.ACTIVE) { + ret.add(constructRelatedTermId((AtlasRelatedObjectId) t)); + } + } + } + } + + return ret; + } +}