class RangerPolicyValidator extends RangerValidator {

	boolean isValidResourceNames(final RangerPolicy policy, final List<ValidationFailureDetails> failures, final RangerServiceDef serviceDef) {
		
		if(LOG.isDebugEnabled()) {
			LOG.debug(String.format("==> RangerPolicyValidator.isValidResourceNames(%s, %s, %s)", policy, failures, serviceDef));
		}

		boolean valid = true;
		Set<String> policyResources = getPolicyResources(policy);

		RangerServiceDefHelper defHelper = new RangerServiceDefHelper(serviceDef);
		Set<List<RangerResourceDef>> hierarchies = defHelper.getResourceHierarchies(); // this can be empty but not null!
		if (hierarchies.isEmpty()) {
			LOG.warn("RangerPolicyValidator.isValidResourceNames: serviceDef does not have any resource hierarchies, possibly due to a old/migrated service def!  Skipping this check!");
		} else {
			/*
			 * A policy is for a single hierarchy however, it doesn't specify which one.  So we have to guess which hierarchy(s) it possibly be for.  First, see if the policy could be for 
			 * any of the known hierarchies?  A candidate hierarchy is one whose resource levels are a superset of those in the policy.
			 * Why?  What we want to catch at this stage is policies that straddles multiple hierarchies, e.g. db, udf and column for a hive policy.
			 * This has the side effect of catch spurious levels specified on the policy, e.g. having a level "blah" on a hive policy.  
			 */
			Set<List<RangerResourceDef>> candidateHierarchies = filterHierarchies_hierarchyHasAllPolicyResources(policyResources, hierarchies, defHelper);
			if (candidateHierarchies.isEmpty()) {
				if (LOG.isDebugEnabled()) {
					LOG.debug(String.format("No compatible resource hierarchies found: resource[%s], service-def[%s], valid-resource-hierarchies[%s]",
							policyResources.toString(), serviceDef.getName(), toStringHierarchies_all(hierarchies, defHelper)));
				}
				ValidationErrorCode error;
				if (hierarchies.size() == 1) { // we can give a simpler message for single hierarchy service-defs which is the majority of cases
					error = ValidationErrorCode.POLICY_VALIDATION_ERR_INVALID_RESOURCE_NO_COMPATIBLE_HIERARCHY_SINGLE;
				} else {
					error = ValidationErrorCode.POLICY_VALIDATION_ERR_INVALID_RESOURCE_NO_COMPATIBLE_HIERARCHY;
				}
				failures.add(new ValidationFailureDetailsBuilder()
					.field("policy resources")
					.subField("incompatible")
					.isSemanticallyIncorrect()
					.becauseOf(error.getMessage(serviceDef.getName(), toStringHierarchies_all(hierarchies, defHelper)))
					.errorCode(error.getErrorCode())
					.build());
				valid = false;
			} else {
				if (LOG.isDebugEnabled()) {
					LOG.debug("isValidResourceNames: Found [" + candidateHierarchies.size() + "] compatible hierarchies: " + toStringHierarchies_all(candidateHierarchies, defHelper));
				}
				/*
				 * Among the candidate hierarchies there should be at least one for which policy specifies all of the mandatory resources.  Note that there could be multiple
				 * hierarchies that meet that criteria, e.g. a hive policy that specified only DB.  It is not clear if it belongs to DB->UDF or DB->TBL->COL hierarchy.
				 * However, if both UDF and TBL were required then we can detect that policy does not specify mandatory levels for any of the candidate hierarchies.
				 */
				Set<List<RangerResourceDef>> validHierarchies = filterHierarchies_mandatoryResourcesSpecifiedInPolicy(policyResources, candidateHierarchies, defHelper);
				if (validHierarchies.isEmpty()) {
					ValidationErrorCode error;
					if (candidateHierarchies.size() == 1) { // we can provide better message if there is a single candidate hierarchy
						error = ValidationErrorCode.POLICY_VALIDATION_ERR_INVALID_RESOURCE_MISSING_MANDATORY_SINGLE;
					} else {
						error = ValidationErrorCode.POLICY_VALIDATION_ERR_INVALID_RESOURCE_MISSING_MANDATORY;
					}
					failures.add(new ValidationFailureDetailsBuilder()
						.field("policy resources")
						.subField("missing mandatory")
						.isSemanticallyIncorrect()
						.becauseOf(error.getMessage(serviceDef.getName(), toStringHierarchies_mandatory(candidateHierarchies, defHelper)))
						.errorCode(error.getErrorCode())
						.build());
					valid = false;
				} else {
					if (LOG.isDebugEnabled()) {
						LOG.debug("isValidResourceNames: Found hierarchies with all mandatory fields specified: " + toStringHierarchies_mandatory(validHierarchies, defHelper));
					}
				}
			}
		}

		if(LOG.isDebugEnabled()) {
			LOG.debug(String.format("<== RangerPolicyValidator.isValidResourceNames(%s, %s, %s): %s", policy, failures, serviceDef, valid));
		}
		return valid;
	}

	public  RangerPolicyValidator(ServiceStore store);

}