Search in sources :

Example 1 with DuplicateConceptNameException

use of org.openmrs.api.DuplicateConceptNameException in project openmrs-core by openmrs.

the class ConceptValidator method validate.

/**
 * Checks that a given concept object is valid.
 *
 * @see org.springframework.validation.Validator#validate(java.lang.Object,
 *      org.springframework.validation.Errors)
 * @should pass if the concept has at least one fully specified name added to it
 * @should fail if there is a duplicate unretired concept name in the locale
 * @should fail if there is a duplicate unretired preferred name in the same locale
 * @should fail if there is a duplicate unretired fully specified name in the same locale
 * @should fail if any names in the same locale for this concept are similar
 * @should pass if the concept with a duplicate name is retired
 * @should pass if the concept being validated is retired and has a duplicate name
 * @should fail if any name is an empty string
 * @should fail if the object parameter is null
 * @should pass if the concept is being updated with no name change
 * @should fail if any name is a null value
 * @should not allow multiple preferred names in a given locale
 * @should not allow multiple fully specified conceptNames in a given locale
 * @should not allow multiple short names in a given locale
 * @should not allow an index term to be a locale preferred name
 * @should fail if there is no name explicitly marked as fully specified
 * @should pass if the duplicate ConceptName is neither preferred nor fully Specified
 * @should pass if the concept has a synonym that is also a short name
 * @should fail if a term is mapped multiple times to the same concept
 * @should not fail if a term has two new mappings on it
 * @should fail if there is a duplicate unretired concept name in the same locale different than
 *         the system locale
 * @should pass for a new concept with a map created with deprecated concept map methods
 * @should pass for an edited concept with a map created with deprecated concept map methods
 * @should pass validation if field lengths are correct
 * @should fail validation if field lengths are not correct
 * @should pass if fully specified name is the same as short name
 * @should pass if different concepts have the same short name
 * @should fail if the concept datatype is null
 * @should fail if the concept class is null
 */
@Override
public void validate(Object obj, Errors errors) throws APIException, DuplicateConceptNameException {
    if (obj == null || !(obj instanceof Concept)) {
        throw new IllegalArgumentException("The parameter obj should not be null and must be of type" + Concept.class);
    }
    Concept conceptToValidate = (Concept) obj;
    // no name to validate, but why is this the case?
    if (conceptToValidate.getNames().isEmpty()) {
        errors.reject("Concept.name.atLeastOneRequired");
        return;
    }
    ValidationUtils.rejectIfEmpty(errors, "datatype", "Concept.datatype.empty");
    ValidationUtils.rejectIfEmpty(errors, "conceptClass", "Concept.conceptClass.empty");
    boolean hasFullySpecifiedName = false;
    for (Locale conceptNameLocale : conceptToValidate.getAllConceptNameLocales()) {
        boolean fullySpecifiedNameForLocaleFound = false;
        boolean preferredNameForLocaleFound = false;
        boolean shortNameForLocaleFound = false;
        Set<String> validNamesFoundInLocale = new HashSet<>();
        Collection<ConceptName> namesInLocale = conceptToValidate.getNames(conceptNameLocale);
        for (ConceptName nameInLocale : namesInLocale) {
            if (StringUtils.isBlank(nameInLocale.getName())) {
                log.debug("Name in locale '" + conceptNameLocale.toString() + "' cannot be an empty string or white space");
                errors.reject("Concept.name.empty");
            }
            if (nameInLocale.getLocalePreferred() != null) {
                if (nameInLocale.getLocalePreferred() && !preferredNameForLocaleFound) {
                    if (nameInLocale.isIndexTerm()) {
                        log.warn("Preferred name in locale '" + conceptNameLocale.toString() + "' shouldn't be an index term");
                        errors.reject("Concept.error.preferredName.is.indexTerm");
                    } else if (nameInLocale.isShort()) {
                        log.warn("Preferred name in locale '" + conceptNameLocale.toString() + "' shouldn't be a short name");
                        errors.reject("Concept.error.preferredName.is.shortName");
                    } else if (nameInLocale.getVoided()) {
                        log.warn("Preferred name in locale '" + conceptNameLocale.toString() + "' shouldn't be a voided name");
                        errors.reject("Concept.error.preferredName.is.voided");
                    }
                    preferredNameForLocaleFound = true;
                } else // should have one preferred name per locale
                if (nameInLocale.getLocalePreferred() && preferredNameForLocaleFound) {
                    log.warn("Found multiple preferred names in locale '" + conceptNameLocale.toString() + "'");
                    errors.reject("Concept.error.multipleLocalePreferredNames");
                }
            }
            if (nameInLocale.isFullySpecifiedName()) {
                if (!hasFullySpecifiedName) {
                    hasFullySpecifiedName = true;
                }
                if (!fullySpecifiedNameForLocaleFound) {
                    fullySpecifiedNameForLocaleFound = true;
                } else {
                    log.warn("Found multiple fully specified names in locale '" + conceptNameLocale.toString() + "'");
                    errors.reject("Concept.error.multipleFullySpecifiedNames");
                }
                if (nameInLocale.getVoided()) {
                    log.warn("Fully Specified name in locale '" + conceptNameLocale.toString() + "' shouldn't be a voided name");
                    errors.reject("Concept.error.fullySpecifiedName.is.voided");
                }
            }
            if (nameInLocale.isShort()) {
                if (!shortNameForLocaleFound) {
                    shortNameForLocaleFound = true;
                } else // should have one short name per locale
                {
                    log.warn("Found multiple short names in locale '" + conceptNameLocale.toString() + "'");
                    errors.reject("Concept.error.multipleShortNames");
                }
            }
            // find duplicate names for a non-retired concept
            if (Context.getConceptService().isConceptNameDuplicate(nameInLocale)) {
                throw new DuplicateConceptNameException("'" + nameInLocale.getName() + "' is a duplicate name in locale '" + conceptNameLocale.toString() + "'");
            }
            // 
            if (errors.hasErrors()) {
                log.debug("Concept name '" + nameInLocale.getName() + "' for locale '" + conceptNameLocale + "' is invalid");
                // for different conceptNames
                return;
            }
            // except for short names
            if (!nameInLocale.isShort() && !validNamesFoundInLocale.add(nameInLocale.getName().toLowerCase())) {
                throw new DuplicateConceptNameException("'" + nameInLocale.getName() + "' is a duplicate name in locale '" + conceptNameLocale.toString() + "' for the same concept");
            }
            if (log.isDebugEnabled()) {
                log.debug("Valid name found: " + nameInLocale.getName());
            }
        }
    }
    // Ensure that each concept has at least a fully specified name
    if (!hasFullySpecifiedName) {
        log.debug("Concept has no fully specified name");
        errors.reject("Concept.error.no.FullySpecifiedName");
    }
    if (CollectionUtils.isNotEmpty(conceptToValidate.getConceptMappings())) {
        // validate all the concept maps
        int index = 0;
        Set<Integer> mappedTermIds = null;
        for (ConceptMap map : conceptToValidate.getConceptMappings()) {
            if (map.getConceptReferenceTerm().getConceptReferenceTermId() == null) {
                // if this term is getting created on the fly e.g. from old legacy code, validate it
                try {
                    errors.pushNestedPath("conceptMappings[" + index + "].conceptReferenceTerm");
                    ValidationUtils.invokeValidator(new ConceptReferenceTermValidator(), map.getConceptReferenceTerm(), errors);
                } finally {
                    errors.popNestedPath();
                }
            }
            // don't proceed to the next maps since the current one already has errors
            if (errors.hasErrors()) {
                return;
            }
            if (mappedTermIds == null) {
                mappedTermIds = new HashSet<>();
            }
            // if we already have a mapping to this term, reject it this map
            if (map.getConceptReferenceTerm().getId() != null && !mappedTermIds.add(map.getConceptReferenceTerm().getId())) {
                errors.rejectValue("conceptMappings[" + index + "]", "ConceptReferenceTerm.term.alreadyMapped", "Cannot map a reference term multiple times to the same concept");
            }
            index++;
        }
    }
    if (CollectionUtils.isNotEmpty(conceptToValidate.getAnswers())) {
        for (ConceptAnswer conceptAnswer : conceptToValidate.getAnswers()) {
            if (conceptAnswer.getAnswerConcept().equals(conceptToValidate)) {
                errors.reject("Concept.contains.itself.as.answer");
            }
        }
    }
    ValidateUtil.validateFieldLengths(errors, obj.getClass(), "version", "retireReason");
    super.validateAttributes(conceptToValidate, errors, Context.getConceptService().getAllConceptAttributeTypes());
}
Also used : Concept(org.openmrs.Concept) Locale(java.util.Locale) ConceptAnswer(org.openmrs.ConceptAnswer) DuplicateConceptNameException(org.openmrs.api.DuplicateConceptNameException) ConceptName(org.openmrs.ConceptName) ConceptMap(org.openmrs.ConceptMap) HashSet(java.util.HashSet)

Aggregations

HashSet (java.util.HashSet)1 Locale (java.util.Locale)1 Concept (org.openmrs.Concept)1 ConceptAnswer (org.openmrs.ConceptAnswer)1 ConceptMap (org.openmrs.ConceptMap)1 ConceptName (org.openmrs.ConceptName)1 DuplicateConceptNameException (org.openmrs.api.DuplicateConceptNameException)1