@RequestMapping(value = SETTINGS_PATH, method = RequestMethod.POST)
  public void updateSettings(
      @ModelAttribute(SETTINGS_FORM) SettingsForm settingsForm,
      Errors errors,
      HttpServletRequest request,
      HttpSession session) {

    List<GlobalProperty> toSave = new ArrayList<GlobalProperty>();
    try {
      for (int i = 0; i < settingsForm.getSettings().size(); ++i) {
        SettingsProperty property = settingsForm.getSettings().get(i);
        if (StringUtils.isNotEmpty(property.getGlobalProperty().getDatatypeClassname())) {
          // we need to handle the submitted value with the appropriate widget
          CustomDatatype dt = CustomDatatypeUtil.getDatatypeOrDefault(property.getGlobalProperty());
          CustomDatatypeHandler handler =
              CustomDatatypeUtil.getHandler(property.getGlobalProperty());
          if (handler != null) {
            try {
              Object value =
                  WebAttributeUtil.getValue(
                      request, dt, handler, "settings[" + i + "].globalProperty.propertyValue");
              property.getGlobalProperty().setValue(value);
            } catch (Exception ex) {
              String originalValue = request.getParameter("originalValue[" + i + "]");
              property.getGlobalProperty().setPropertyValue(originalValue);
              errors.rejectValue(
                  "settings[" + i + "].globalProperty.propertyValue", "general.invalid");
            }
          }
        }
        toSave.add(property.getGlobalProperty());
      }
    } catch (Exception e) {
      log.error("Error saving global property", e);
      errors.reject("GlobalProperty.not.saved");
      session.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, e.getMessage());
    }

    if (errors.hasErrors()) {
      session.setAttribute(WebConstants.OPENMRS_ERROR_ATTR, "GlobalProperty.not.saved");

    } else {
      for (GlobalProperty gp : toSave) {
        getService().saveGlobalProperty(gp);
      }
      session.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "GlobalProperty.saved");

      // TODO: move this to a GlobalPropertyListener
      // refresh log level from global property(ies)
      OpenmrsUtil.applyLogLevels();

      OpenmrsUtil.setupLogAppenders();
    }
  }
  /**
   * @see org.springframework.validation.Validator#validate(java.lang.Object,
   *     org.springframework.validation.Errors)
   * @should require name
   * @should require minOccurs
   * @should not allow maxOccurs less than 1
   * @should not allow maxOccurs less than minOccurs
   * @should require datatypeClassname
   */
  @Override
  public void validate(Object target, Errors errors) {
    @SuppressWarnings("unchecked")
    T attributeType = (T) target;

    if (attributeType == null) {
      errors.reject("error.general");
    } else {
      ValidationUtils.rejectIfEmptyOrWhitespace(errors, "name", "error.name");
      ValidationUtils.rejectIfEmptyOrWhitespace(errors, "minOccurs", "error.null");

      Integer minOccurs = attributeType.getMinOccurs();
      Integer maxOccurs = attributeType.getMaxOccurs();

      if (minOccurs != null) {
        if (minOccurs < 0) {
          errors.rejectValue("minOccurs", "AttributeType.minOccursShouldNotBeLessThanZero");
        }
      }

      if (maxOccurs != null) {
        if (maxOccurs < 1) {
          errors.rejectValue("maxOccurs", "AttributeType.maxOccursShouldNotBeLessThanOne");
        } else if (maxOccurs < minOccurs) {
          errors.rejectValue("maxOccurs", "AttributeType.maxOccursShouldNotBeLessThanMinOccurs");
        }
      }

      if (StringUtils.isBlank(attributeType.getDatatypeClassname())) {
        errors.rejectValue("datatypeClassname", "error.null");
      } else {
        try {
          CustomDatatypeUtil.getDatatype(attributeType);
        } catch (Exception ex) {
          errors.rejectValue(
              "datatypeConfig",
              "AttributeType.datatypeConfig.invalid",
              new Object[] {ex.getMessage()},
              "Invalid");
        }
      }

      // ensure that handler is suitable for datatype
      if (StringUtils.isNotEmpty(attributeType.getPreferredHandlerClassname())) {
        try {
          CustomDatatype<?> datatype = CustomDatatypeUtil.getDatatype(attributeType);
          CustomDatatypeHandler<?, ?> handler = CustomDatatypeUtil.getHandler(attributeType);
          if (!CustomDatatypeUtil.isCompatibleHandler(handler, datatype))
            errors.rejectValue(
                "preferredHandlerClassname",
                "AttributeType.preferredHandlerClassname.wrongDatatype");
        } catch (Exception ex) {
          errors.rejectValue(
              "handlerConfig",
              "AttributeType.handlerConfig.invalid",
              new Object[] {ex.getMessage()},
              "Invalid");
        }
      }
    }
  }