ATLAS-2685: Impose displayName restrictions for Glossary, term and category.

Change-Id: I4cddcfe76eabcf7ee705b60848521158bb33a8a5
diff --git a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
index dd86e48..4397dd9 100644
--- a/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
+++ b/intg/src/main/java/org/apache/atlas/AtlasErrorCode.java
@@ -146,6 +146,7 @@
     INVALID_TERM_DISSOCIATION(400, "ATLAS-400-00-080", "Given term (guid={0}) is not associated to entity(guid={1})"),
     ATTRIBUTE_TYPE_INVALID(400, "ATLAS-400-00-081", "{0}.{1}: invalid attribute type. Attribute cannot be of type classification"),
     MISSING_CATEGORY_DISPLAY_NAME(400, "ATLAS-400-00-082", "Category displayName is empty/null"),
+    INVALID_DISPLAY_NAME(400, "ATLAS-400-00-083", "displayName cannot contain following special chars ('@', '.')"),
     TERM_HAS_ENTITY_ASSOCIATION(400, "ATLAS-400-00-086", "Term (guid={}) can't be deleted as it has been assigned to {} entities."),
 
     UNAUTHORIZED_ACCESS(403, "ATLAS-403-00-001", "{0} is not authorized to perform {1}"),
diff --git a/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java b/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java
index a83f6d5..9a8676b 100644
--- a/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java
+++ b/repository/src/main/java/org/apache/atlas/glossary/GlossaryService.java
@@ -66,6 +66,8 @@
     private final GlossaryCategoryUtils glossaryCategoryUtils;
     private final AtlasTypeRegistry     atlasTypeRegistry;
 
+    private final char[] invalidNameChars = {'@', '.'};
+
     @Inject
     public GlossaryService(DataAccess dataAccess, final AtlasRelationshipStore relationshipStore, final AtlasTypeRegistry typeRegistry) {
         this.dataAccess = dataAccess;
@@ -134,6 +136,8 @@
         if (StringUtils.isEmpty(atlasGlossary.getQualifiedName())) {
             if (StringUtils.isEmpty(atlasGlossary.getDisplayName())) {
                 throw new AtlasBaseException(AtlasErrorCode.GLOSSARY_QUALIFIED_NAME_CANT_BE_DERIVED);
+            } else if (isNameInvalid(atlasGlossary.getDisplayName())){
+                throw new AtlasBaseException(AtlasErrorCode.INVALID_DISPLAY_NAME);
             } else {
                 atlasGlossary.setQualifiedName(atlasGlossary.getDisplayName());
             }
@@ -242,6 +246,10 @@
             throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "DisplayName can't be null/empty");
         }
 
+        if (isNameInvalid(atlasGlossary.getDisplayName())) {
+            throw new AtlasBaseException(AtlasErrorCode.INVALID_DISPLAY_NAME);
+        }
+
         AtlasGlossary storeObject = dataAccess.load(atlasGlossary);
 
         if (!storeObject.equals(atlasGlossary)) {
@@ -321,6 +329,9 @@
         if (StringUtils.isEmpty(glossaryTerm.getDisplayName())) {
             throw new AtlasBaseException(AtlasErrorCode.GLOSSARY_TERM_QUALIFIED_NAME_CANT_BE_DERIVED);
         }
+        if (isNameInvalid(glossaryTerm.getDisplayName())) {
+            throw new AtlasBaseException(AtlasErrorCode.INVALID_DISPLAY_NAME);
+        }
 
         // This might fail for the case when the term's qualifiedName has been updated and the duplicate request comes in with old name
         if (termExists(glossaryTerm)) {
@@ -377,6 +388,10 @@
             throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "DisplayName can't be null/empty");
         }
 
+        if (isNameInvalid(atlasGlossaryTerm.getDisplayName())) {
+            throw new AtlasBaseException(AtlasErrorCode.INVALID_DISPLAY_NAME);
+        }
+
         AtlasGlossaryTerm storeObject = dataAccess.load(atlasGlossaryTerm);
         if (!storeObject.equals(atlasGlossaryTerm)) {
             try {
@@ -495,6 +510,10 @@
         if (Objects.isNull(glossaryCategory.getDisplayName())) {
             throw new AtlasBaseException(AtlasErrorCode.MISSING_CATEGORY_DISPLAY_NAME);
         }
+        if (isNameInvalid(glossaryCategory.getDisplayName())) {
+            throw new AtlasBaseException(AtlasErrorCode.INVALID_DISPLAY_NAME);
+        }
+
 
         // This might fail for the case when the category's qualifiedName has been updated during a hierarchy change
         // and the duplicate request comes in with old name
@@ -561,6 +580,10 @@
             throw new AtlasBaseException(AtlasErrorCode.BAD_REQUEST, "DisplayName can't be null/empty");
         }
 
+        if (isNameInvalid(glossaryCategory.getDisplayName())) {
+            throw new AtlasBaseException(AtlasErrorCode.INVALID_DISPLAY_NAME);
+        }
+
         AtlasGlossaryCategory storeObject = dataAccess.load(glossaryCategory);
 
         if (!storeObject.equals(glossaryCategory)) {
@@ -952,6 +975,10 @@
         termHeaders.forEach(t -> t.setDisplayText(termMap.get(t.getTermGuid()).getDisplayName()));
     }
 
+    private boolean isNameInvalid(String name) {
+        return StringUtils.containsAny(name, invalidNameChars);
+    }
+
     static class PaginationHelper<T> {
         private int     pageStart;
         private int     pageEnd;
diff --git a/repository/src/test/java/org/apache/atlas/glossary/GlossaryServiceTest.java b/repository/src/test/java/org/apache/atlas/glossary/GlossaryServiceTest.java
index f661650..6a6b971 100644
--- a/repository/src/test/java/org/apache/atlas/glossary/GlossaryServiceTest.java
+++ b/repository/src/test/java/org/apache/atlas/glossary/GlossaryServiceTest.java
@@ -164,7 +164,7 @@
 
         fixedRateMortgage = new AtlasGlossaryTerm();
         fixedRateMortgage.setQualifiedName("fixed_mtg@testBankingGlossary");
-        fixedRateMortgage.setDisplayName("15/30 yr mortgage");
+        fixedRateMortgage.setDisplayName("Conventional mortgage");
         fixedRateMortgage.setShortDescription("Short description");
         fixedRateMortgage.setLongDescription("Long description");
         fixedRateMortgage.setAbbreviation("FMTG");