RANGER-4448: updated GDS CRUD APIs to return appropriate status code on failure

Signed-off-by: Madhan Neethiraj <madhan@apache.org>
diff --git a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
index 03de8e0..38b302e 100644
--- a/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
+++ b/agents-common/src/main/java/org/apache/ranger/plugin/errors/ValidationErrorCode.java
@@ -163,7 +163,7 @@
     GDS_VALIDATION_ERR_INVALID_STATUS_CHANGE(4125, "invalid status change from [{0}] to [{1}]"),
     GDS_VALIDATION_ERR_UPDATE_IMMUTABLE_FIELD(4126, "[{0}] can't be updated"),
     GDS_VALIDATION_ERR_DATASET_IN_PROJECT_ID_NOT_FOUND(4127, "Dataset-in-project with ID [{0}] does not exist"),
-
+    GDS_VALIDATION_ERR_SHARED_RESOURCE_CONFLICT(4128, "Shared resource with resources [{0}] already exists for data share [{1}]"),
     ;
 
 
diff --git a/security-admin/src/main/java/org/apache/ranger/common/RESTErrorUtil.java b/security-admin/src/main/java/org/apache/ranger/common/RESTErrorUtil.java
index 4aaf364..ed3ed5e 100644
--- a/security-admin/src/main/java/org/apache/ranger/common/RESTErrorUtil.java
+++ b/security-admin/src/main/java/org/apache/ranger/common/RESTErrorUtil.java
@@ -22,6 +22,7 @@
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
@@ -130,7 +131,25 @@
 		return restException;
 	}
 
-	
+	public WebApplicationException create403RESTException(VXResponse gjResponse) {
+		gjResponse.setStatusCode(VXResponse.STATUS_ERROR);
+		gjResponse.setMessageList(Collections.singletonList(MessageEnums.OPER_NO_PERMISSION.getMessage()));
+
+		Response                errorResponse = Response.status(javax.servlet.http.HttpServletResponse.SC_FORBIDDEN).entity(gjResponse).build();
+		WebApplicationException restException = new WebApplicationException(errorResponse);
+
+		restException.fillInStackTrace();
+
+		if (logger.isInfoEnabled()) {
+			UserSessionBase userSession = ContextUtil.getCurrentUserSession();
+			String          loginId     = (userSession != null) ? userSession.getLoginId() : null;
+
+			logger.info("Request failed. loginId=" + loginId + ", logMessage=" + gjResponse.getMsgDesc(), restException);
+		}
+
+		return restException;
+	}
+
 	public WebApplicationException createGrantRevokeRESTException(String logMessage) {
 		RESTResponse resp = new RESTResponse();
 		resp.setMsgDesc(logMessage);
diff --git a/security-admin/src/main/java/org/apache/ranger/db/XXGdsSharedResourceDao.java b/security-admin/src/main/java/org/apache/ranger/db/XXGdsSharedResourceDao.java
index d3bd4d6..c7acd81 100644
--- a/security-admin/src/main/java/org/apache/ranger/db/XXGdsSharedResourceDao.java
+++ b/security-admin/src/main/java/org/apache/ranger/db/XXGdsSharedResourceDao.java
@@ -130,4 +130,21 @@
 
 		return ret;
 	}
+
+	public Long getIdByDataShareIdAndResourceSignature(Long dataShareId, String resourceSignature) {
+		Long ret = null;
+
+		if (dataShareId != null && resourceSignature != null) {
+			try {
+				ret = getEntityManager()
+						.createNamedQuery("XXGdsSharedResource.getIdByDataShareIdAndResourceSignature", Long.class)
+						.setParameter("dataShareId", dataShareId).setParameter("resourceSignature", resourceSignature)
+						.getSingleResult();
+			} catch (NoResultException e) {
+				LOG.debug("getIdByDataShareIdAndName({}, {}): ", dataShareId, resourceSignature, e);
+			}
+		}
+
+		return ret;
+	}
 }
diff --git a/security-admin/src/main/java/org/apache/ranger/rest/GdsREST.java b/security-admin/src/main/java/org/apache/ranger/rest/GdsREST.java
index eadcf07..b1a0053 100755
--- a/security-admin/src/main/java/org/apache/ranger/rest/GdsREST.java
+++ b/security-admin/src/main/java/org/apache/ranger/rest/GdsREST.java
@@ -222,6 +222,7 @@
 
     @DELETE
     @Path("/dataset/{id}")
+    @Produces({ "application/json" })
     @PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.DELETE_DATASET + "\")")
     public void deleteDataset(@PathParam("id") Long datasetId, @Context HttpServletRequest request) {
         LOG.debug("==> deleteDataset({})", datasetId);
@@ -580,6 +581,7 @@
 
     @DELETE
     @Path("/project/{id}")
+    @Produces({ "application/json" })
     @PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.DELETE_PROJECT + "\")")
     public void deleteProject(@PathParam("id") Long projectId, @Context HttpServletRequest request) {
         LOG.debug("==> deleteProject({})", projectId);
@@ -904,6 +906,7 @@
 
     @DELETE
     @Path("/datashare/{id}")
+    @Produces({ "application/json" })
     @PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.DELETE_DATA_SHARE + "\")")
     public void deleteDataShare(@PathParam("id") Long dataShareId, @Context HttpServletRequest request) {
         LOG.debug("==> GdsREST.deleteDataShare({})", dataShareId);
@@ -1094,6 +1097,7 @@
 
     @DELETE
     @Path("/resource/{id}")
+    @Produces({ "application/json" })
     @PreAuthorize("@rangerPreAuthSecurityHandler.isAPIAccessible(\"" + RangerAPIList.REMOVE_SHARED_RESOURCE + "\")")
     public void removeSharedResource(@PathParam("id") Long resourceId) {
         LOG.debug("==> GdsREST.removeSharedResource({})", resourceId);
diff --git a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDBProvider.java b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDBProvider.java
index da41daa..30d2317 100644
--- a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDBProvider.java
+++ b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDBProvider.java
@@ -27,6 +27,7 @@
 import org.apache.ranger.plugin.model.RangerGds.RangerDataShare;
 import org.apache.ranger.plugin.model.RangerGds.RangerDataset;
 import org.apache.ranger.plugin.model.RangerGds.RangerProject;
+import org.apache.ranger.plugin.model.RangerPolicyResourceSignature;
 import org.apache.ranger.plugin.model.RangerService;
 import org.apache.ranger.plugin.util.RangerRoles;
 import org.apache.ranger.plugin.util.RangerRolesUtil;
@@ -231,6 +232,11 @@
         return ret;
     }
 
+    public Long getSharedResourceId(Long dataShareId, RangerPolicyResourceSignature signature) {
+		Long ret = daoMgr.getXXGdsSharedResource().getIdByDataShareIdAndResourceSignature(dataShareId, signature.getSignature());
+
+		return ret;
+    }
 
     private RangerRolesUtil initGetRolesUtil() {
         RangerRolesUtil ret              = this.rolesUtil;
diff --git a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDataProvider.java b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDataProvider.java
index ab74e90..2c8721e 100644
--- a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDataProvider.java
+++ b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidationDataProvider.java
@@ -18,6 +18,7 @@
 package org.apache.ranger.validation;
 
 
+import org.apache.ranger.plugin.model.RangerPolicyResourceSignature;
 import org.apache.ranger.plugin.model.RangerGds.RangerDataShare;
 import org.apache.ranger.plugin.model.RangerGds.RangerDataset;
 import org.apache.ranger.plugin.model.RangerGds.RangerProject;
@@ -67,4 +68,6 @@
     public abstract RangerDataShare getDataShare(Long id);
 
     public abstract Long getSharedResourceId(Long dataShareId, String name);
+
+    public abstract Long getSharedResourceId(Long dataShareId, RangerPolicyResourceSignature signature);
 }
diff --git a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidator.java b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidator.java
index c5a3f38..27e7cc1 100755
--- a/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidator.java
+++ b/security-admin/src/main/java/org/apache/ranger/validation/RangerGdsValidator.java
@@ -36,7 +36,9 @@
 import org.apache.ranger.plugin.model.RangerGds.RangerSharedResource;
 import org.apache.ranger.plugin.model.RangerGds.RangerTagDataMaskInfo;
 import org.apache.ranger.plugin.model.RangerPolicy.RangerPolicyItemDataMaskInfo;
+import org.apache.ranger.plugin.model.RangerPolicyResourceSignature;
 import org.apache.ranger.plugin.model.validation.ValidationFailureDetails;
+import org.apache.ranger.view.VXResponse;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -87,6 +89,16 @@
         } else {
             validateDatasetAdmin(existing, result);
             validateAcl(dataset.getAcl(), "acl", result);
+
+            boolean renamed = !StringUtils.equalsIgnoreCase(dataset.getName(), existing.getName());
+
+            if (renamed) {
+                Long existingDatasetNameId = dataProvider.getDatasetId(dataset.getName());
+
+                if (existingDatasetNameId != null) {
+                    result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_DATASET_NAME_CONFLICT, "name", dataset.getName(), existingDatasetNameId));
+                }
+            }
         }
 
         if (!result.isSuccess()) {
@@ -143,6 +155,16 @@
         } else {
             validateProjectAdmin(existing, result);
             validateAcl(project.getAcl(), "acl", result);
+
+            boolean renamed = !StringUtils.equalsIgnoreCase(project.getName(), existing.getName());
+
+            if (renamed) {
+                Long existingProjectNameId = dataProvider.getProjectId(project.getName());
+
+                if (existingProjectNameId != null) {
+                    result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_PROJECT_NAME_CONFLICT, "name", project.getName(), existingProjectNameId));
+                }
+            }
         }
 
         if (!result.isSuccess()) {
@@ -205,6 +227,16 @@
             validateAcl(dataShare.getAcl(), "acl", result);
             validateAccessTypes(dataShare.getService(), "defaultAccessTypes", dataShare.getDefaultAccessTypes(), result);
             validateMaskTypes(dataShare.getService(), "defaultTagMasks", dataShare.getDefaultTagMasks(), result);
+
+            boolean renamed = !StringUtils.equalsIgnoreCase(dataShare.getName(), existing.getName());
+
+            if (renamed) {
+                Long existingDataShareNameId = dataProvider.getDataShareId(dataShare.getName());
+
+                if (existingDataShareNameId != null) {
+                    result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_DATA_SHARE_NAME_CONFLICT, "name", dataShare.getName(), existingDataShareNameId));
+                }
+            }
         }
 
         if (!result.isSuccess()) {
@@ -246,7 +278,15 @@
             if (existing != null) {
                 result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_SHARED_RESOURCE_NAME_CONFLICT, "name", resource.getName(), dataShare.getName(), existing));
             } else {
-				validateSharedResourceCreateAndUpdate(dataShare, result);
+                validateSharedResourceCreateAndUpdate(dataShare, result);
+
+                if (result.isSuccess()) {
+                    existing = dataProvider.getSharedResourceId(resource.getDataShareId(), new RangerPolicyResourceSignature(resource));
+
+                    if (existing != null) {
+                        result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_SHARED_RESOURCE_CONFLICT, "resource", resource.getResource(), dataShare.getName()));
+                    }
+                }
             }
         }
 
@@ -270,7 +310,27 @@
             if (dataShare == null) {
                 result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_DATA_SHARE_ID_NOT_FOUND, "dataShareId", resource.getDataShareId()));
             } else {
-				validateSharedResourceCreateAndUpdate(dataShare, result);
+                validateSharedResourceCreateAndUpdate(dataShare, result);
+
+                if (result.isSuccess()) {
+                    boolean renamed = !StringUtils.equalsIgnoreCase(resource.getName(), existing.getName());
+
+                    if (renamed) {
+                        Long existingSharedResourceNameId = dataProvider.getSharedResourceId(resource.getDataShareId(), resource.getName());
+
+                        if (existingSharedResourceNameId != null) {
+                            result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_SHARED_RESOURCE_NAME_CONFLICT, "name", resource.getName(), dataShare.getName(), existing));
+                        }
+                    }
+
+                    if (result.isSuccess()) {
+                        Long existingSharedResourceNameId = dataProvider.getSharedResourceId(resource.getDataShareId(),new RangerPolicyResourceSignature(resource));
+
+                        if (existingSharedResourceNameId != null && !existingSharedResourceNameId.equals(existing.getId())) {
+                            result.addValidationFailure(new ValidationFailureDetails(ValidationErrorCode.GDS_VALIDATION_ERR_SHARED_RESOURCE_CONFLICT, "resource", resource.getResource(), dataShare.getName()));
+                        }
+                    }
+                }
             }
         }
 
@@ -1031,5 +1091,13 @@
         public void throwRESTException() {
             throw restErrorUtil.createRESTException(validationFailures.toString(), MessageEnums.INVALID_INPUT_DATA);
         }
+
+        public void throwREST403Exception() {
+            VXResponse gjResponse = new VXResponse();
+
+            gjResponse.setMsgDesc(validationFailures.toString());
+
+            throw restErrorUtil.create403RESTException(gjResponse);
+        }
     }
 }
diff --git a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
index 0502512..ae6788b 100755
--- a/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
+++ b/security-admin/src/main/resources/META-INF/jpa_named_queries.xml
@@ -2260,6 +2260,13 @@
 		</query>
 	</named-query>
 
+	<named-query name="XXGdsSharedResource.getIdByDataShareIdAndResourceSignature">
+			<query>select obj.id from XXGdsSharedResource obj
+			        where obj.dataShareId = :dataShareId
+			          and obj.resourceSignature = :resourceSignature
+			</query>
+	</named-query>
+
 	<named-query name="XXGdsDataShareInDataset.findByGuid">
 		<query>select obj from XXGdsDataShareInDataset obj where obj.guid = :guid</query>
 	</named-query>