class RangerServiceDefValidator extends RangerValidator {

	boolean isValidAccessTypes(final List<RangerAccessTypeDef> accessTypeDefs, final List<ValidationFailureDetails> failures) {
		if(LOG.isDebugEnabled()) {
			LOG.debug(String.format("==> RangerServiceDefValidator.isValidAccessTypes(%s, %s)", accessTypeDefs, failures));
		}
		
		boolean valid = true;
		if (CollectionUtils.isEmpty(accessTypeDefs)) {
			ValidationErrorCode error = ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_MISSING_FIELD;
			failures.add(new ValidationFailureDetailsBuilder()
				.field("access types")
				.isMissing()
				.errorCode(error.getErrorCode())
				.becauseOf(error.getMessage("access types"))
				.build());
			valid = false;
		} else {
			List<RangerAccessTypeDef> defsWithImpliedGrants = new ArrayList<RangerAccessTypeDef>();
			Set<String> accessNames = new HashSet<String>();
			Set<Long> ids = new HashSet<Long>();
			for (RangerAccessTypeDef def : accessTypeDefs) {
				String name = def.getName();
				valid = isUnique(name, accessNames, "access type name", "access types", failures) && valid;
				valid = isUnique(def.getItemId(), ids, "access type itemId", "access types", failures) && valid;
				if (CollectionUtils.isNotEmpty(def.getImpliedGrants())) {
					defsWithImpliedGrants.add(def);
				}
			}
			// validate implied grants
			for (RangerAccessTypeDef def : defsWithImpliedGrants) {
				Collection<String> impliedGrants = getImpliedGrants(def);
				Set<String> unknownAccessTypes = Sets.difference(Sets.newHashSet(impliedGrants), accessNames);
				if (!unknownAccessTypes.isEmpty()) {
					ValidationErrorCode error = ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_IMPLIED_GRANT_UNKNOWN_ACCESS_TYPE;
					failures.add(new ValidationFailureDetailsBuilder()
						.field("implied grants")
						.subField(unknownAccessTypes.iterator().next())  // we return just on item here.  Message has all unknow items
						.isSemanticallyIncorrect()
						.errorCode(error.getErrorCode())
						.becauseOf(error.getMessage(impliedGrants, unknownAccessTypes))
						.build());
					valid = false;
				}
				// implied grant should not imply itself! 
				String name = def.getName(); // note: this name could be null/blank/empty!
				if (impliedGrants.contains(name)) {
					ValidationErrorCode error = ValidationErrorCode.SERVICE_DEF_VALIDATION_ERR_IMPLIED_GRANT_IMPLIES_ITSELF;
					failures.add(new ValidationFailureDetailsBuilder()
						.field("implied grants")
						.subField(name)
						.isSemanticallyIncorrect()
						.errorCode(error.getErrorCode())
						.becauseOf(error.getMessage(impliedGrants, name))
						.build());
					valid = false;
				}
			}
		}
		
		if(LOG.isDebugEnabled()) {
			LOG.debug(String.format("<== RangerServiceDefValidator.isValidAccessTypes(%s, %s): %s", accessTypeDefs, failures, valid));
		}
		return valid;
	}

	public  RangerServiceDefValidator(ServiceStore store);

}