/** * The contents of this file are subject to the OpenMRS Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.validator; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.Concept; import org.openmrs.annotation.Handler; import org.openmrs.api.APIException; import org.openmrs.api.DuplicateConceptNameException; import org.openmrs.api.context.Context; import org.springframework.validation.Errors; import org.springframework.validation.Validator; /** * Validates methods of the {@link Concept} object. */ @Handler(supports = { Concept.class }, order = 50) public class ConceptValidator implements Validator { /** Log for this class and subclasses */ protected final Log log = LogFactory.getLog(getClass()); /** * Determines if the command object being submitted is a valid type * * @see org.springframework.validation.Validator#supports(java.lang.Class) */ @SuppressWarnings("unchecked") public boolean supports(Class c) { return c.equals(Concept.class); } /** * Checks that a given concept object has a unique name or preferred name across the entire * unretired and preferred concept name space in a given locale(should be the default * application locale set in the openmrs context). Currently this method is called just before * the concept is persisted in the database * * @should fail if there is a duplicate unretired concept name in the locale * @should fail if the preferred name is an empty string * @should fail if the object parameter is null * @should pass if the found duplicate concept is actually retired * @should pass if the concept is being updated with no name change */ public void validate(Object obj, Errors errorss) throws APIException, DuplicateConceptNameException { if (obj == null || !(obj instanceof Concept)) { if (log.isErrorEnabled()) log.error("The parameter obj should not be null and must be of type" + Concept.class); throw new IllegalArgumentException("Concept name is null or of invalid class"); } else { Concept newConcept = (Concept) obj; String newName = null; //no name to validate, but why is this the case? if (newConcept.getName() == null) return; //if the new concept name is in a different locale other than openmrs' default one if (newConcept.getName().getLocale() != null && !newConcept.getName().getLocale().equals(Context.getLocale())) newName = newConcept.getName().getName(); else newName = newConcept.getPreferredName(Context.getLocale()).getName(); if (StringUtils.isBlank(newName)) { if (log.isErrorEnabled()) log.error("No preferred name specified for the concept to be validated"); throw new APIException("Concept name cannot be an empty String"); } if (log.isDebugEnabled()) log.debug("Looking up concept names matching " + newName); List<Concept> matchingConcepts = Context.getConceptService().getConceptsByName(newName); Set<Concept> duplicates = new HashSet<Concept>(); for (Concept c : matchingConcepts) { //If updating a concept, read past the concept being updated if (newConcept.getConceptId() != null && c.getConceptId().equals(newConcept.getConceptId())) continue; //get only duplicates that are not retired if (c.getPreferredName(Context.getLocale()).getName().equalsIgnoreCase(newName) && !c.isRetired()) { duplicates.add(c); } } if (duplicates.size() > 0) { for (Concept duplicate : duplicates) { if (log.isErrorEnabled()) log.error("The name '" + newName + "' is already being used by concept with Id: " + duplicate.getConceptId()); throw new DuplicateConceptNameException("Duplicate concept name '" + newName + "'"); } } } } }