Commit cabc1e55 by apoorvnaik

ATLAS-2534: Glossary REST API (bugfix)

Change-Id: Ic0b40d722f2a797db19dd7ee95ef30866e073128
parent 4a938d87
......@@ -168,6 +168,9 @@ public enum AtlasErrorCode {
RELATIONSHIP_ALREADY_EXISTS(409, "ATLAS-409-00-004", "relationship {0} already exists between entities {1} and {2}"),
TYPE_HAS_RELATIONSHIPS(409, "ATLAS-409-00-005", "Given type {0} has associated relationshipDefs"),
SAVED_SEARCH_ALREADY_EXISTS(409, "ATLAS-409-00-006", "search named {0} already exists for user {1}"),
GLOSSARY_ALREADY_EXISTS(409, "ATLAS-409-00-007", "Glossary with qualifiedName {0} already exists"),
GLOSSARY_TERM_ALREADY_EXISTS(409, "ATLAS-409-00-009", "Glossary term with qualifiedName {0} already exists"),
GLOSSARY_CATEGORY_ALREADY_EXISTS(409, "ATLAS-409-00-00A", "Glossary category with qualifiedName {0} already exists"),
// All internal errors go here
INTERNAL_ERROR(500, "ATLAS-500-00-001", "Internal server error {0}"),
......
......@@ -29,9 +29,13 @@ 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.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
......@@ -96,8 +100,8 @@ public class GlossaryCategoryUtils extends GlossaryUtils {
}
}
private void processParentCategory(AtlasGlossaryCategory newObj, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
AtlasRelatedCategoryHeader newParent = newObj.getParentCategory();
private void processParentCategory(AtlasGlossaryCategory updatedCategory, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
AtlasRelatedCategoryHeader newParent = updatedCategory.getParentCategory();
AtlasRelatedCategoryHeader existingParent = existing.getParentCategory();
switch (op) {
case CREATE:
......@@ -152,9 +156,9 @@ public class GlossaryCategoryUtils extends GlossaryUtils {
}
}
private void processAssociatedTerms(AtlasGlossaryCategory newObj, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
Set<AtlasRelatedTermHeader> newTerms = newObj.getTerms();
Set<AtlasRelatedTermHeader> existingTerms = existing.getTerms();
private void processAssociatedTerms(AtlasGlossaryCategory updatedCategory, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
Map<String, AtlasRelatedTermHeader> newTerms = getTerms(updatedCategory);
Map<String, AtlasRelatedTermHeader> existingTerms = getTerms(existing);
switch (op) {
case CREATE:
......@@ -162,51 +166,66 @@ public class GlossaryCategoryUtils extends GlossaryUtils {
LOG.debug("Creating term relation with category = {}, terms = {}", existing.getDisplayName(),
Objects.nonNull(newTerms) ? newTerms.size() : "none");
}
createTermCategorizationRelationships(existing, newTerms);
createTermCategorizationRelationships(existing, newTerms.values());
break;
case UPDATE:
if (CollectionUtils.isEmpty(existingTerms)) {
if (MapUtils.isEmpty(existingTerms)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating term relation with category = {}, terms = {}", existing.getDisplayName(),
Objects.nonNull(newTerms) ? newTerms.size() : "none");
}
createTermCategorizationRelationships(existing, newTerms);
createTermCategorizationRelationships(existing, newTerms.values());
break;
}
if (CollectionUtils.isEmpty(newTerms)) {
if (MapUtils.isEmpty(newTerms)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting term relation with category = {}, terms = {}", existing.getDisplayName(), existingTerms.size());
}
deleteTermCategorizationRelationships(existing, existingTerms);
deleteTermCategorizationRelationships(existing, existingTerms.values());
break;
}
Set<AtlasRelatedTermHeader> toCreate = newTerms
.values()
.stream()
.filter(c -> Objects.isNull(c.getRelationGuid()))
.filter(t -> !existingTerms.containsKey(t.getTermGuid()))
.collect(Collectors.toSet());
createTermCategorizationRelationships(existing, toCreate);
Set<AtlasRelatedTermHeader> toUpdate = newTerms
.values()
.stream()
.filter(c -> Objects.nonNull(c.getRelationGuid()) && existingTerms.contains(c))
.filter(t -> updatedExistingTermRelation(existingTerms, t))
.collect(Collectors.toSet());
updateTermCategorizationRelationships(existing, toUpdate);
Set<AtlasRelatedTermHeader> toDelete = existingTerms
.values()
.stream()
.filter(c -> !toCreate.contains(c) && !toUpdate.contains(c))
.filter(t -> !newTerms.containsKey(t.getTermGuid()))
.collect(Collectors.toSet());
deleteTermCategorizationRelationships(existing, toDelete);
break;
case DELETE:
deleteTermCategorizationRelationships(existing, existingTerms);
deleteTermCategorizationRelationships(existing, existingTerms.values());
break;
}
}
private void createTermCategorizationRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
private boolean updatedExistingTermRelation(Map<String, AtlasRelatedTermHeader> existingTerms, AtlasRelatedTermHeader term) {
return Objects.nonNull(term.getRelationGuid()) && !existingTerms.get(term.getTermGuid()).equals(term);
}
private Map<String, AtlasRelatedTermHeader> getTerms(final AtlasGlossaryCategory category) {
return Objects.nonNull(category.getTerms()) ?
category.getTerms()
.stream()
.collect(Collectors.toMap(AtlasRelatedTermHeader::getTermGuid, t -> t)) :
Collections.EMPTY_MAP;
}
private void createTermCategorizationRelationships(AtlasGlossaryCategory existing, Collection<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
Set<AtlasRelatedTermHeader> existingTerms = existing.getTerms();
for (AtlasRelatedTermHeader term : terms) {
......@@ -228,7 +247,7 @@ public class GlossaryCategoryUtils extends GlossaryUtils {
}
}
private void updateTermCategorizationRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
private void updateTermCategorizationRelationships(AtlasGlossaryCategory existing, Collection<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
for (AtlasRelatedTermHeader term : terms) {
if (DEBUG_ENABLED) {
......@@ -241,7 +260,7 @@ public class GlossaryCategoryUtils extends GlossaryUtils {
}
}
private void deleteTermCategorizationRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
private void deleteTermCategorizationRelationships(AtlasGlossaryCategory existing, Collection<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
for (AtlasRelatedTermHeader term : terms) {
if (DEBUG_ENABLED) {
......@@ -252,61 +271,76 @@ public class GlossaryCategoryUtils extends GlossaryUtils {
}
}
private void processCategoryChildren(AtlasGlossaryCategory newObj, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
Set<AtlasRelatedCategoryHeader> newChildren = newObj.getChildrenCategories();
Set<AtlasRelatedCategoryHeader> existingChildren = existing.getChildrenCategories();
private void processCategoryChildren(AtlasGlossaryCategory updatedCategory, AtlasGlossaryCategory existing, RelationshipOperation op) throws AtlasBaseException {
Map<String, AtlasRelatedCategoryHeader> newChildren = getChildren(updatedCategory);
Map<String, AtlasRelatedCategoryHeader> existingChildren = getChildren(existing);
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);
createCategoryRelationships(existing, newChildren.values());
break;
case UPDATE:
// Create new children
if (CollectionUtils.isEmpty(existingChildren)) {
if (MapUtils.isEmpty(existingChildren)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new children, category = {}, children = {}", existing.getDisplayName(),
Objects.nonNull(newChildren) ? newChildren.size() : "none");
}
createCategoryRelationships(existing, newChildren);
createCategoryRelationships(existing, newChildren.values());
break;
}
// Delete current children
if (CollectionUtils.isEmpty(newChildren)) {
if (MapUtils.isEmpty(newChildren)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting children, category = {}, children = {}", existing.getDisplayName(), existingChildren.size());
}
deleteCategoryRelationships(existing, existingChildren);
deleteCategoryRelationships(existing, existingChildren.values());
break;
}
Set<AtlasRelatedCategoryHeader> toCreate = newChildren
.values()
.stream()
.filter(c -> Objects.isNull(c.getRelationGuid()))
.filter(c -> !existingChildren.containsKey(c.getCategoryGuid()))
.collect(Collectors.toSet());
createCategoryRelationships(existing, toCreate);
Set<AtlasRelatedCategoryHeader> toUpdate = newChildren
.values()
.stream()
.filter(c -> Objects.nonNull(c.getRelationGuid()) && existingChildren.contains(c))
.filter(c -> updatedExistingCategoryRelation(existingChildren, c))
.collect(Collectors.toSet());
updateCategoryRelationships(existing, toUpdate);
Set<AtlasRelatedCategoryHeader> toDelete = existingChildren
.values()
.stream()
.filter(c -> !toCreate.contains(c) && !toUpdate.contains(c))
.filter(c -> !newChildren.containsKey(c.getCategoryGuid()))
.collect(Collectors.toSet());
deleteCategoryRelationships(existing, toDelete);
break;
case DELETE:
deleteCategoryRelationships(existing, existingChildren);
deleteCategoryRelationships(existing, existingChildren.values());
break;
}
}
private void createCategoryRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedCategoryHeader> newChildren) throws AtlasBaseException {
private boolean updatedExistingCategoryRelation(Map<String, AtlasRelatedCategoryHeader> existingChildren, AtlasRelatedCategoryHeader header) {
return Objects.nonNull(header.getRelationGuid()) && !header.equals(existingChildren.get(header.getCategoryGuid()));
}
private Map<String, AtlasRelatedCategoryHeader> getChildren(final AtlasGlossaryCategory category) {
return Objects.nonNull(category.getChildrenCategories()) ?
category.getChildrenCategories()
.stream()
.collect(Collectors.toMap(AtlasRelatedCategoryHeader::getCategoryGuid, c -> c)) :
Collections.EMPTY_MAP;
}
private void createCategoryRelationships(AtlasGlossaryCategory existing, Collection<AtlasRelatedCategoryHeader> newChildren) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(newChildren)) {
Set<AtlasRelatedCategoryHeader> existingChildren = existing.getChildrenCategories();
for (AtlasRelatedCategoryHeader child : newChildren) {
......@@ -324,7 +358,7 @@ public class GlossaryCategoryUtils extends GlossaryUtils {
}
}
private void updateCategoryRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedCategoryHeader> toUpdate) throws AtlasBaseException {
private void updateCategoryRelationships(AtlasGlossaryCategory existing, Collection<AtlasRelatedCategoryHeader> toUpdate) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(toUpdate)) {
for (AtlasRelatedCategoryHeader categoryHeader : toUpdate) {
if (DEBUG_ENABLED) {
......@@ -337,7 +371,7 @@ public class GlossaryCategoryUtils extends GlossaryUtils {
}
}
private void deleteCategoryRelationships(AtlasGlossaryCategory existing, Set<AtlasRelatedCategoryHeader> existingChildren) throws AtlasBaseException {
private void deleteCategoryRelationships(AtlasGlossaryCategory existing, Collection<AtlasRelatedCategoryHeader> existingChildren) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(existingChildren)) {
for (AtlasRelatedCategoryHeader child : existingChildren) {
if (DEBUG_ENABLED) {
......
......@@ -27,6 +27,7 @@ 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.repository.graphdb.AtlasVertex;
import org.apache.atlas.repository.ogm.DataAccess;
import org.apache.atlas.repository.store.graph.AtlasRelationshipStore;
import org.apache.atlas.repository.store.graph.v1.AtlasGraphUtilsV1;
......@@ -53,13 +54,17 @@ public class GlossaryService {
private static final Logger LOG = LoggerFactory.getLogger(GlossaryService.class);
private static final boolean DEBUG_ENABLED = LOG.isDebugEnabled();
private final DataAccess dataAccess;
private final GlossaryTermUtils glossaryTermUtils;
private final GlossaryCategoryUtils glossaryCategoryUtils;
private static final String QUALIFIED_NAME_ATTR = "qualifiedName";
private final DataAccess dataAccess;
private final GlossaryTermUtils glossaryTermUtils;
private final GlossaryCategoryUtils glossaryCategoryUtils;
private final AtlasTypeRegistry atlasTypeRegistry;
@Inject
public GlossaryService(DataAccess dataAccess, final AtlasRelationshipStore relationshipStore, final AtlasTypeRegistry typeRegistry) {
this.dataAccess = dataAccess;
this.atlasTypeRegistry = typeRegistry;
glossaryTermUtils = new GlossaryTermUtils(relationshipStore, typeRegistry);
glossaryCategoryUtils = new GlossaryCategoryUtils(relationshipStore, typeRegistry);
}
......@@ -78,7 +83,7 @@ public class GlossaryService {
LOG.debug("==> GlossaryService.getGlossaries({}, {}, {})", limit, offset, sortOrder);
}
List<String> glossaryGuids = AtlasGraphUtilsV1.findEntityGUIDsByType(GlossaryUtils.ATLAS_GLOSSARY_PREFIX, sortOrder);
List<String> glossaryGuids = AtlasGraphUtilsV1.findEntityGUIDsByType(GlossaryUtils.ATLAS_GLOSSARY_TYPENAME, sortOrder);
PaginationHelper paginationHelper = new PaginationHelper<>(glossaryGuids, offset, limit);
List<AtlasGlossary> ret;
......@@ -118,6 +123,7 @@ public class GlossaryService {
if (Objects.isNull(atlasGlossary)) {
throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "Glossary definition missing");
}
if (StringUtils.isEmpty(atlasGlossary.getQualifiedName())) {
if (StringUtils.isEmpty(atlasGlossary.getDisplayName())) {
throw new AtlasBaseException(AtlasErrorCode.GLOSSARY_QUALIFIED_NAME_CANT_BE_DERIVED);
......@@ -125,11 +131,17 @@ public class GlossaryService {
atlasGlossary.setQualifiedName(atlasGlossary.getDisplayName());
}
}
if (glossaryExists(atlasGlossary)) {
throw new AtlasBaseException(AtlasErrorCode.GLOSSARY_ALREADY_EXISTS, atlasGlossary.getQualifiedName());
}
AtlasGlossary saved = dataAccess.save(atlasGlossary);
if (DEBUG_ENABLED) {
LOG.debug("<== GlossaryService.createGlossary() : {}", saved);
}
return saved;
}
......@@ -297,6 +309,10 @@ public class GlossaryService {
}
}
if (termExists(glossaryTerm)) {
throw new AtlasBaseException(AtlasErrorCode.GLOSSARY_TERM_ALREADY_EXISTS, glossaryTerm.getQualifiedName());
}
AtlasGlossaryTerm existing = dataAccess.save(glossaryTerm);
glossaryTermUtils.processTermRelations(glossaryTerm, existing, GlossaryUtils.RelationshipOperation.CREATE);
......@@ -457,6 +473,10 @@ public class GlossaryService {
}
}
if (categoryExists(glossaryCategory)) {
throw new AtlasBaseException(AtlasErrorCode.GLOSSARY_CATEGORY_ALREADY_EXISTS, glossaryCategory.getQualifiedName());
}
AtlasGlossaryCategory saved = dataAccess.save(glossaryCategory);
// Attempt relation creation
......@@ -726,6 +746,27 @@ public class GlossaryService {
return glossary;
}
private boolean glossaryExists(AtlasGlossary atlasGlossary) {
AtlasVertex vertex = AtlasGraphUtilsV1.findByUniqueAttributes(atlasTypeRegistry.getEntityTypeByName(GlossaryUtils.ATLAS_GLOSSARY_TYPENAME), new HashMap<String, Object>() {{
put(QUALIFIED_NAME_ATTR, atlasGlossary.getQualifiedName());
}});
return Objects.nonNull(vertex);
}
private boolean termExists(AtlasGlossaryTerm term) {
AtlasVertex vertex = AtlasGraphUtilsV1.findByUniqueAttributes(atlasTypeRegistry.getEntityTypeByName(GlossaryUtils.ATLAS_GLOSSARY_TERM_TYPENAME), new HashMap<String, Object>() {{
put(QUALIFIED_NAME_ATTR, term.getQualifiedName());
}});
return Objects.nonNull(vertex);
}
private boolean categoryExists(AtlasGlossaryCategory category) {
AtlasVertex vertex = AtlasGraphUtilsV1.findByUniqueAttributes(atlasTypeRegistry.getEntityTypeByName(GlossaryUtils.ATLAS_GLOSSARY_CATEGORY_TYPENAME), new HashMap<String, Object>() {{
put(QUALIFIED_NAME_ATTR, category.getQualifiedName());
}});
return Objects.nonNull(vertex);
}
private void deleteCategories(final AtlasGlossary existing, final Set<AtlasRelatedCategoryHeader> categories) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(categories)) {
if (DEBUG_ENABLED) {
......
......@@ -31,10 +31,12 @@ 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.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
......@@ -170,39 +172,42 @@ public class GlossaryTermUtils extends GlossaryUtils {
break;
case UPDATE:
for (AtlasGlossaryTerm.Relation relation : AtlasGlossaryTerm.Relation.values()) {
Set<AtlasRelatedTermHeader> existingTermHeaders = existingRelatedTerms.get(relation);
Set<AtlasRelatedTermHeader> newTermHeaders = newRelatedTerms.get(relation);
Map<String, AtlasRelatedTermHeader> existingTermHeaders = getRelatedTermHeaders(existingRelatedTerms, relation);
Map<String, AtlasRelatedTermHeader> newTermHeaders = getRelatedTermHeaders(newRelatedTerms, relation);
// No existing term relations, create all
if (CollectionUtils.isEmpty(existingTermHeaders)) {
if (MapUtils.isEmpty(existingTermHeaders)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new term relations, relation = {}, terms = {}", relation,
Objects.nonNull(newTermHeaders) ? newTermHeaders.size() : "none");
}
createTermRelationships(existing, relation, newTermHeaders);
createTermRelationships(existing, relation, newTermHeaders.values());
continue;
}
// Existing term relations but nothing in updated object, remove all
if (CollectionUtils.isEmpty(newTermHeaders)) {
if (MapUtils.isEmpty(newTermHeaders)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting existing term relations, relation = {}, terms = {}", relation, existingTermHeaders.size());
}
deleteTermRelationships(relation, existingTermHeaders);
deleteTermRelationships(relation, existingTermHeaders.values());
continue;
}
// Determine what to update, delete or create
Set<AtlasRelatedTermHeader> toCreate = newTermHeaders
.values()
.stream()
.filter(t -> Objects.isNull(t.getRelationGuid()))
.filter(t -> !existingTermHeaders.containsKey(t.getTermGuid()))
.collect(Collectors.toSet());
Set<AtlasRelatedTermHeader> toUpdate = newTermHeaders
.values()
.stream()
.filter(t -> Objects.nonNull(t.getRelationGuid()) && existingTermHeaders.contains(t))
.filter(t -> updatedExistingTermRelation(existingTermHeaders, t))
.collect(Collectors.toSet());
Set<AtlasRelatedTermHeader> toDelete = existingTermHeaders
.values()
.stream()
.filter(t -> !toCreate.contains(t) && !toUpdate.contains(t))
.filter(t -> !newTermHeaders.containsKey(t.getTermGuid()))
.collect(Collectors.toSet());
createTermRelationships(existing, relation, toCreate);
......@@ -221,61 +226,88 @@ public class GlossaryTermUtils extends GlossaryUtils {
}
}
private void processAssociatedCategories(AtlasGlossaryTerm newObj, AtlasGlossaryTerm existing, RelationshipOperation op) throws AtlasBaseException {
Set<AtlasTermCategorizationHeader> newCategories = newObj.getCategories();
Set<AtlasTermCategorizationHeader> existingCategories = existing.getCategories();
private Map<String, AtlasRelatedTermHeader> getRelatedTermHeaders(Map<AtlasGlossaryTerm.Relation, Set<AtlasRelatedTermHeader>> relatedTerms, AtlasGlossaryTerm.Relation relation) {
return Objects.nonNull(relatedTerms.get(relation)) ?
relatedTerms.get(relation)
.stream()
.collect(Collectors.toMap(AtlasRelatedTermHeader::getTermGuid, t -> t)) :
Collections.EMPTY_MAP;
}
private boolean updatedExistingTermRelation(Map<String, AtlasRelatedTermHeader> existingTermHeaders, AtlasRelatedTermHeader header) {
return Objects.nonNull(header.getRelationGuid()) && !header.equals(existingTermHeaders.get(header.getTermGuid()));
}
private void processAssociatedCategories(AtlasGlossaryTerm updatedTerm, AtlasGlossaryTerm existing, RelationshipOperation op) throws AtlasBaseException {
Map<String, AtlasTermCategorizationHeader> newCategories = getAssociatedCategories(updatedTerm);
Map<String, AtlasTermCategorizationHeader> existingCategories = getAssociatedCategories(existing);
switch (op) {
case CREATE:
if (Objects.nonNull(newCategories)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new term categorization, term = {}, categories = {}", existing.getGuid(), newCategories.size());
}
createTermCategorizationRelationships(existing, newCategories);
createTermCategorizationRelationships(existing, newCategories.values());
}
break;
case UPDATE:
// If no existing categories are present then create all existing ones
if (CollectionUtils.isEmpty(existingCategories)) {
if (MapUtils.isEmpty(existingCategories)) {
if (DEBUG_ENABLED) {
LOG.debug("Creating new term categorization, term = {}, categories = {}", existing.getGuid(),
Objects.nonNull(newCategories) ? newCategories.size() : "none");
}
createTermCategorizationRelationships(existing, newCategories);
createTermCategorizationRelationships(existing, newCategories.values());
break;
}
// If no new categories are present then delete all existing ones
if (CollectionUtils.isEmpty(newCategories)) {
if (MapUtils.isEmpty(newCategories)) {
if (DEBUG_ENABLED) {
LOG.debug("Deleting term categorization, term = {}, categories = {}", existing.getGuid(), existingCategories.size());
}
deleteCategorizationRelationship(existingCategories);
deleteCategorizationRelationship(existingCategories.values());
break;
}
Set<AtlasTermCategorizationHeader> toCreate = newCategories
.values()
.stream()
.filter(c -> Objects.isNull(c.getRelationGuid()))
.filter(c -> !existingCategories.containsKey(c.getCategoryGuid()))
.collect(Collectors.toSet());
createTermCategorizationRelationships(existing, toCreate);
Set<AtlasTermCategorizationHeader> toUpdate = newCategories
.values()
.stream()
.filter(c -> Objects.nonNull(c.getRelationGuid()) && existingCategories.contains(c))
.filter(c -> updatedExistingCategorizationRelation(existingCategories, c))
.collect(Collectors.toSet());
updateTermCategorizationRelationships(existing, toUpdate);
Set<AtlasTermCategorizationHeader> toDelete = existingCategories
.values()
.stream()
.filter(c -> !toCreate.contains(c) && !toUpdate.contains(c))
.filter(c -> !newCategories.containsKey(c.getCategoryGuid()))
.collect(Collectors.toSet());
deleteCategorizationRelationship(toDelete);
break;
case DELETE:
deleteCategorizationRelationship(existingCategories);
deleteCategorizationRelationship(existingCategories.values());
break;
}
}
private void createTermCategorizationRelationships(AtlasGlossaryTerm existing, Set<AtlasTermCategorizationHeader> categories) throws AtlasBaseException {
private boolean updatedExistingCategorizationRelation(Map<String, AtlasTermCategorizationHeader> existingCategories, AtlasTermCategorizationHeader header) {
return Objects.nonNull(header.getRelationGuid()) && !header.equals(existingCategories.get(header.getCategoryGuid()));
}
private Map<String, AtlasTermCategorizationHeader> getAssociatedCategories(final AtlasGlossaryTerm term) {
return Objects.nonNull(term.getCategories()) ?
term.getCategories()
.stream()
.collect(Collectors.toMap(AtlasTermCategorizationHeader::getCategoryGuid, c -> c)) :
Collections.EMPTY_MAP;
}
private void createTermCategorizationRelationships(AtlasGlossaryTerm existing, Collection<AtlasTermCategorizationHeader> categories) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(categories)) {
Set<AtlasTermCategorizationHeader> existingCategories = existing.getCategories();
for (AtlasTermCategorizationHeader categorizationHeader : categories) {
......@@ -293,7 +325,7 @@ public class GlossaryTermUtils extends GlossaryUtils {
}
}
private void updateTermCategorizationRelationships(AtlasGlossaryTerm existing, Set<AtlasTermCategorizationHeader> toUpdate) throws AtlasBaseException {
private void updateTermCategorizationRelationships(AtlasGlossaryTerm existing, Collection<AtlasTermCategorizationHeader> toUpdate) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(toUpdate)) {
for (AtlasTermCategorizationHeader categorizationHeader : toUpdate) {
if (DEBUG_ENABLED) {
......@@ -306,7 +338,7 @@ public class GlossaryTermUtils extends GlossaryUtils {
}
}
private void deleteCategorizationRelationship(Set<AtlasTermCategorizationHeader> existingCategories) throws AtlasBaseException {
private void deleteCategorizationRelationship(Collection<AtlasTermCategorizationHeader> existingCategories) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(existingCategories)) {
for (AtlasTermCategorizationHeader categorizationHeader : existingCategories) {
if (DEBUG_ENABLED) {
......@@ -317,11 +349,16 @@ public class GlossaryTermUtils extends GlossaryUtils {
}
}
private void createTermRelationships(AtlasGlossaryTerm existing, AtlasGlossaryTerm.Relation relation, Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
private void createTermRelationships(AtlasGlossaryTerm existing, AtlasGlossaryTerm.Relation relation, Collection<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
Set<AtlasRelatedTermHeader> existingRelations = existing.getRelatedTerms().get(relation);
Map<String, AtlasRelatedTermHeader> existingRelations;
if (Objects.nonNull(existing.getRelatedTerms()) && Objects.nonNull(existing.getRelatedTerms().get(relation))) {
existingRelations = existing.getRelatedTerms().get(relation).stream().collect(Collectors.toMap(AtlasRelatedTermHeader::getTermGuid, t -> t));
} else {
existingRelations = Collections.EMPTY_MAP;
}
for (AtlasRelatedTermHeader term : terms) {
if (Objects.nonNull(existingRelations) && existingRelations.contains(term)) {
if (Objects.nonNull(existingRelations) && existingRelations.containsKey(term.getTermGuid())) {
if (DEBUG_ENABLED) {
LOG.debug("Skipping existing term relation termGuid={}", term.getTermGuid());
}
......@@ -335,7 +372,7 @@ public class GlossaryTermUtils extends GlossaryUtils {
}
}
private void updateTermRelationships(AtlasGlossaryTerm.Relation relation, Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
private void updateTermRelationships(AtlasGlossaryTerm.Relation relation, Collection<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
for (AtlasRelatedTermHeader term : terms) {
if (DEBUG_ENABLED) {
......@@ -348,7 +385,7 @@ public class GlossaryTermUtils extends GlossaryUtils {
}
}
private void deleteTermRelationships(AtlasGlossaryTerm.Relation relation, Set<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
private void deleteTermRelationships(AtlasGlossaryTerm.Relation relation, Collection<AtlasRelatedTermHeader> terms) throws AtlasBaseException {
if (CollectionUtils.isNotEmpty(terms)) {
for (AtlasRelatedTermHeader termHeader : terms) {
if (DEBUG_ENABLED) {
......
......@@ -36,8 +36,12 @@ public abstract class GlossaryUtils {
public static final String TERM_ASSIGNMENT_ATTR_STEWARD = "steward";
public static final String TERM_ASSIGNMENT_ATTR_SOURCE = "source";
static final String ATLAS_GLOSSARY_PREFIX = "__AtlasGlossary";
static final String ATLAS_GLOSSARY_TYPENAME = "__AtlasGlossary";
static final String ATLAS_GLOSSARY_TERM_TYPENAME = "__AtlasGlossaryTerm";
static final String ATLAS_GLOSSARY_CATEGORY_TYPENAME = "__AtlasGlossaryCategory";
// Relation name constants
protected static final String ATLAS_GLOSSARY_PREFIX = ATLAS_GLOSSARY_TYPENAME;
protected static final String TERM_ANCHOR = ATLAS_GLOSSARY_PREFIX + "TermAnchor";
protected static final String CATEGORY_ANCHOR = ATLAS_GLOSSARY_PREFIX + "CategoryAnchor";
protected static final String CATEGORY_HIERARCHY = ATLAS_GLOSSARY_PREFIX + "CategoryHierarchyLink";
......@@ -49,7 +53,6 @@ public abstract class GlossaryUtils {
protected static final String TERM_RELATION_ATTR_SOURCE = "source";
protected static final String TERM_RELATION_ATTR_STATUS = "status";
protected final AtlasRelationshipStore relationshipStore;
protected final AtlasTypeRegistry typeRegistry;
......
......@@ -500,12 +500,8 @@ public final class EntityGraphRetriever {
Iterable edges = entityVertex.query().direction(AtlasEdgeDirection.IN).label(TERM_ASSIGNMENT_LABEL).edges();
if (edges != null) {
Iterator<AtlasEdge> iterator = edges.iterator();
while (iterator.hasNext()) {
AtlasEdge edge = iterator.next();
if (edge != null) {
for (final AtlasEdge edge : (Iterable<AtlasEdge>) edges) {
if (edge != null && GraphHelper.getStatus(edge) != AtlasEntity.Status.DELETED) {
ret.add(toTermAssignmentHeader(edge));
}
}
......
......@@ -39,6 +39,7 @@ import org.apache.atlas.repository.store.graph.v1.AtlasEntityStream;
import org.apache.atlas.store.AtlasTypeDefStore;
import org.apache.atlas.type.AtlasTypeRegistry;
import org.apache.atlas.utils.AtlasJson;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.SkipException;
......@@ -55,10 +56,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.fail;
import static org.testng.Assert.*;
@Guice(modules = TestModules.TestOnlyModule.class)
public class GlossaryServiceTest {
......@@ -96,10 +94,8 @@ public class GlossaryServiceTest {
} catch (AtlasBaseException | IOException e) {
throw new SkipException("SubjectArea model loading failed");
}
}
@Test(groups = "Glossary.CREATE")
public void testCreateGlossary() {
// Glossary
bankGlossary = new AtlasGlossary();
bankGlossary.setQualifiedName("testBankingGlossary");
bankGlossary.setDisplayName("Banking glossary");
......@@ -116,34 +112,26 @@ public class GlossaryServiceTest {
creditUnionGlossary.setUsage("N/A");
creditUnionGlossary.setLanguage("en-US");
try {
AtlasGlossary created = glossaryService.createGlossary(bankGlossary);
bankGlossary.setGuid(created.getGuid());
created = glossaryService.createGlossary(creditUnionGlossary);
creditUnionGlossary.setGuid(created.getGuid());
} catch (AtlasBaseException e) {
fail("Glossary creation should've succeeded", e);
}
// Glossary anchor
AtlasGlossaryHeader glossaryId = new AtlasGlossaryHeader();
glossaryId.setGlossaryGuid(bankGlossary.getGuid());
// Create a category
// Category
accountCategory = new AtlasGlossaryCategory();
accountCategory.setQualifiedName("acc@testBankingGlossary");
accountCategory.setDisplayName("Account categorization");
accountCategory.setShortDescription("Short description");
accountCategory.setLongDescription("Long description");
accountCategory.setAnchor(glossaryId);
try {
accountCategory = glossaryService.createCategory(accountCategory);
} catch (AtlasBaseException e) {
fail("Account category creation should've succeeded");
}
customerCategory = new AtlasGlossaryCategory();
customerCategory.setQualifiedName("customer@testBankingGlossary");
customerCategory.setDisplayName("Customer category");
customerCategory.setShortDescription("Short description");
customerCategory.setLongDescription("Long description");
// Create terms
mortgageCategory = new AtlasGlossaryCategory();
mortgageCategory.setQualifiedName("mtg@testBankingGlossary");
mortgageCategory.setDisplayName("Mortgage categorization");
mortgageCategory.setShortDescription("Short description");
mortgageCategory.setLongDescription("Long description");
// Terms
checkingAccount = new AtlasGlossaryTerm();
checkingAccount.setQualifiedName("chk_acc@testBankingGlossary");
checkingAccount.setDisplayName("A checking account");
......@@ -152,7 +140,6 @@ public class GlossaryServiceTest {
checkingAccount.setAbbreviation("CHK");
checkingAccount.setExamples(Arrays.asList("Personal", "Joint"));
checkingAccount.setUsage("N/A");
checkingAccount.setAnchor(glossaryId);
savingsAccount = new AtlasGlossaryTerm();
savingsAccount.setQualifiedName("sav_acc@testBankingGlossary");
......@@ -162,7 +149,6 @@ public class GlossaryServiceTest {
savingsAccount.setAbbreviation("SAV");
savingsAccount.setExamples(Arrays.asList("Personal", "Joint"));
savingsAccount.setUsage("N/A");
savingsAccount.setAnchor(glossaryId);
fixedRateMortgage = new AtlasGlossaryTerm();
fixedRateMortgage.setQualifiedName("fixed_mtg@testBankingGlossary");
......@@ -172,7 +158,6 @@ public class GlossaryServiceTest {
fixedRateMortgage.setAbbreviation("FMTG");
fixedRateMortgage.setExamples(Arrays.asList("15-yr", "30-yr"));
fixedRateMortgage.setUsage("N/A");
fixedRateMortgage.setAnchor(glossaryId);
adjustableRateMortgage = new AtlasGlossaryTerm();
adjustableRateMortgage.setQualifiedName("arm_mtg@testBankingGlossary");
......@@ -182,25 +167,53 @@ public class GlossaryServiceTest {
adjustableRateMortgage.setAbbreviation("ARMTG");
adjustableRateMortgage.setExamples(Arrays.asList("5/1", "7/1", "10/1"));
adjustableRateMortgage.setUsage("N/A");
}
@Test(groups = "Glossary.CREATE")
public void testCreateGlossary() {
try {
AtlasGlossary created = glossaryService.createGlossary(bankGlossary);
bankGlossary.setGuid(created.getGuid());
created = glossaryService.createGlossary(creditUnionGlossary);
creditUnionGlossary.setGuid(created.getGuid());
} catch (AtlasBaseException e) {
fail("Glossary creation should've succeeded", e);
}
// Duplicate create calls should fail with 409 Conflict
try {
glossaryService.createGlossary(bankGlossary);
fail("Glossary duplicate creation should've failed");
} catch (AtlasBaseException e) {
assertEquals(e.getAtlasErrorCode(), AtlasErrorCode.GLOSSARY_ALREADY_EXISTS);
}
try {
glossaryService.createGlossary(creditUnionGlossary);
fail("Glossary duplicate creation should've failed");
} catch (AtlasBaseException e) {
assertEquals(e.getAtlasErrorCode(), AtlasErrorCode.GLOSSARY_ALREADY_EXISTS);
}
// Glossary anchor
AtlasGlossaryHeader glossaryId = new AtlasGlossaryHeader();
glossaryId.setGlossaryGuid(bankGlossary.getGuid());
// Create terms
checkingAccount.setAnchor(glossaryId);
savingsAccount.setAnchor(glossaryId);
fixedRateMortgage.setAnchor(glossaryId);
adjustableRateMortgage.setAnchor(glossaryId);
// Create glossary categories
customerCategory = new AtlasGlossaryCategory();
customerCategory.setQualifiedName("customer@testBankingGlossary");
customerCategory.setDisplayName("Customer category");
customerCategory.setShortDescription("Short description");
customerCategory.setLongDescription("Long description");
accountCategory.setAnchor(glossaryId);
customerCategory.setAnchor(glossaryId);
mortgageCategory = new AtlasGlossaryCategory();
mortgageCategory.setQualifiedName("mtg@testBankingGlossary");
mortgageCategory.setDisplayName("Mortgage categorization");
mortgageCategory.setShortDescription("Short description");
mortgageCategory.setLongDescription("Long description");
mortgageCategory.setAnchor(glossaryId);
}
@Test(groups = "Glossary.CREATE" , dependsOnMethods = "testCreateGlossary")
@Test(groups = "Glossary.CREATE" , dependsOnMethods = "testCategoryCreation")
public void testTermCreationWithoutAnyRelations() {
try {
checkingAccount = glossaryService.createTerm(checkingAccount);
......@@ -231,11 +244,11 @@ public class GlossaryServiceTest {
}
}
@Test(groups = "Glossary.CREATE" , dependsOnMethods = "testCreateGlossary")
@Test(groups = "Glossary.CREATE" , dependsOnMethods = "testCategoryCreation")
public void testTermCreationWithCategory() {
try {
AtlasTermCategorizationHeader termCategorizationHeader = new AtlasTermCategorizationHeader();
termCategorizationHeader.setCategoryGuid(accountCategory.getGuid());
termCategorizationHeader.setCategoryGuid(mortgageCategory.getGuid());
termCategorizationHeader.setDescription("Test description");
termCategorizationHeader.setStatus(AtlasTermRelationshipStatus.DRAFT);
......@@ -253,8 +266,16 @@ public class GlossaryServiceTest {
@Test(groups = "Glossary.CREATE" , dependsOnMethods = "testCreateGlossary")
public void testCategoryCreation() {
try {
List<AtlasGlossaryCategory> categories = glossaryService.createCategories(Arrays.asList(customerCategory, mortgageCategory));
customerCategory.setGuid(categories.get(0).getGuid());
customerCategory = glossaryService.createCategory(customerCategory);
AtlasRelatedCategoryHeader parentHeader = new AtlasRelatedCategoryHeader();
parentHeader.setCategoryGuid(customerCategory.getGuid());
// Test parent relation
accountCategory.setParentCategory(parentHeader);
List<AtlasGlossaryCategory> categories = glossaryService.createCategories(Arrays.asList(accountCategory, mortgageCategory));
accountCategory.setGuid(categories.get(0).getGuid());
mortgageCategory.setGuid(categories.get(1).getGuid());
} catch (AtlasBaseException e) {
fail("Category creation should've succeeded", e);
......@@ -390,15 +411,21 @@ public class GlossaryServiceTest {
savingsAccount = glossaryService.getTerm(savingsAccount.getGuid());
checkingAccount.setAnchor(newGlossaryHeader);
checkingAccount.setSeeAlso(null);
savingsAccount.setAnchor(newGlossaryHeader);
savingsAccount.setSeeAlso(null);
} catch (AtlasBaseException e) {
fail("Term fetch for migration should've succeeded", e);
}
try {
glossaryService.updateTerm(checkingAccount);
glossaryService.updateTerm(savingsAccount);
checkingAccount = glossaryService.updateTerm(checkingAccount);
assertNotNull(checkingAccount);
assertTrue(CollectionUtils.isEmpty(checkingAccount.getSeeAlso()));
savingsAccount = glossaryService.updateTerm(savingsAccount);
assertNotNull(savingsAccount);
assertTrue(CollectionUtils.isEmpty(savingsAccount.getSeeAlso()));
} catch (AtlasBaseException e) {
fail("Term anchor change should've succeeded", e);
}
......@@ -426,9 +453,11 @@ public class GlossaryServiceTest {
}
customerCategory.setAnchor(newGlossaryHeader);
customerCategory.setChildrenCategories(null);
try {
glossaryService.updateCategory(customerCategory);
customerCategory = glossaryService.updateCategory(customerCategory);
assertTrue(CollectionUtils.isEmpty(customerCategory.getChildrenCategories()));
} catch (AtlasBaseException e) {
fail("Category anchor change should've succeeded");
}
......@@ -447,6 +476,7 @@ public class GlossaryServiceTest {
assertNotNull(accountCategory);
try {
accountCategory = glossaryService.getCategory(accountCategory.getGuid());
assertTrue(CollectionUtils.isEmpty(accountCategory.getTerms()));
} catch (AtlasBaseException e) {
fail("Fetch of accountCategory should've succeeded", e);
}
......@@ -515,24 +545,17 @@ public class GlossaryServiceTest {
assertNotNull(customerCategory);
try {
customerCategory = glossaryService.getCategory(customerCategory.getGuid());
assertNull(customerCategory.getParentCategory());
assertNotNull(customerCategory.getChildrenCategories());
assertEquals(customerCategory.getChildrenCategories().size(), 1); // Only account category
} catch (AtlasBaseException e) {
fail("Fetch of accountCategory should've succeeded", e);
}
List<AtlasGlossaryCategory> categories = new ArrayList<>();
for (AtlasGlossaryCategory category : Arrays.asList(accountCategory, mortgageCategory)) {
try {
categories.add(glossaryService.getCategory(category.getGuid()));
} catch (AtlasBaseException e) {
fail("Category fetch should've succeeded");
}
}
for (AtlasGlossaryCategory category : categories) {
AtlasRelatedCategoryHeader id = new AtlasRelatedCategoryHeader();
id.setCategoryGuid(category.getGuid());
id.setDescription("Sub-category of customer");
customerCategory.addChild(id);
}
AtlasRelatedCategoryHeader id = new AtlasRelatedCategoryHeader();
id.setCategoryGuid(mortgageCategory.getGuid());
id.setDescription("Sub-category of customer");
customerCategory.addChild(id);
try {
AtlasGlossaryCategory updateGlossaryCategory = glossaryService.updateCategory(customerCategory);
......@@ -544,7 +567,7 @@ public class GlossaryServiceTest {
fail("Sub category addition should've succeeded", e);
}
for (AtlasGlossaryCategory childCategory : categories) {
for (AtlasGlossaryCategory childCategory : Arrays.asList(accountCategory, mortgageCategory)) {
try {
AtlasGlossaryCategory child = glossaryService.getCategory(childCategory.getGuid());
assertNotNull(child);
......
......@@ -214,6 +214,7 @@ public class GlossaryREST {
* @throws AtlasBaseException
* @HTTP 200 If glossary creation was successful
* @HTTP 400 If Glossary definition has invalid or missing information
* @HTTP 409 If Glossary definition already exists (duplicate qualifiedName)
*/
@POST
public AtlasGlossary createGlossary(AtlasGlossary atlasGlossary) throws AtlasBaseException {
......@@ -236,6 +237,7 @@ public class GlossaryREST {
* @throws AtlasBaseException
* @HTTP 200 If glossary term creation was successful
* @HTTP 400 If Glossary term definition has invalid or missing information
* @HTTP 409 If Glossary term already exists (duplicate qualifiedName)
*/
@POST
@Path("/term")
......@@ -289,6 +291,7 @@ public class GlossaryREST {
* @throws AtlasBaseException
* @HTTP 200 If glossary category creation was successful
* @HTTP 400 If Glossary category definition has invalid or missing information
* @HTTP 409 If Glossary category already exists (duplicate qualifiedName)
*/
@POST
@Path("/category")
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment