tds/src/main/java/thredds/server/ncss/validation/NcssGridRequestValidator.java
@Override
  public boolean isValid(NcssGridParamsBean params, ConstraintValidatorContext constraintValidatorContext) {

    constraintValidatorContext.disableDefaultConstraintViolation();
    boolean isValid = true;

    // lat/lon point
    if (params.getLatitude() != null || params.getLongitude() != null) {
      if (!params.hasLatLonPoint()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.lat_or_lon_missing}").addConstraintViolation();
      }
    }

    // lat/lon bb
    if (params.getNorth() != null || params.getSouth() != null || params.getEast() != null || params.getWest() != null) {
      if (!params.hasLatLonBB()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.wrong_bbox}").addConstraintViolation();
      }

      if (params.getNorth() < params.getSouth()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.north_south}").addConstraintViolation();
      }
      if (params.getEast() < params.getWest()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.east_west}").addConstraintViolation();
      }
    }

    // proj bb
    if (params.getMaxx() != null || params.getMinx() != null || params.getMaxy() != null || params.getMiny() != null) {
      if (!params.hasProjectionBB()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.wrong_pbox}").addConstraintViolation();
      }

      if (params.getMaxx() < params.getMinx()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.rangex}").addConstraintViolation();
      }
      if (params.getMaxy() < params.getMiny()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.rangey}").addConstraintViolation();
      }
    }

    // runtime: latest, all, or time
    if (params.getRuntime() != null) {
      if ("latest".equalsIgnoreCase(params.getRuntime())) {
        params.setLatestRuntime(true);

      } else if ("all".equalsIgnoreCase(params.getRuntime())) {
        params.setAllRuntime(true);

      } else {
        CalendarDate cd = TimeParamsValidator.validateISOString(params.getRuntime(), "{thredds.server.ncSubset.validation.param.runtime}", constraintValidatorContext);
        if (cd != null)
          params.setRuntimeDate(cd);
      }
    }

    // timeOffset: first or double
    if (params.getTimeOffset() != null) {
      if ("first".equalsIgnoreCase(params.getTimeOffset())) {
        params.setFirstTimeOffset(true);

      } else {
        try {
          double val = Double.parseDouble(params.getTimeOffset());
          params.setTimeOffsetVal(val);
        } catch (NumberFormatException e) {
          constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.param.time_offset}").addConstraintViolation();
        }
      }
    }

    return isValid;
  }
@Override
  public boolean isValid(NcssGridParamsBean params, ConstraintValidatorContext constraintValidatorContext) {

    constraintValidatorContext.disableDefaultConstraintViolation();
    boolean isValid = true;

    // lat/lon point
    if (params.getLatitude() != null || params.getLongitude() != null) {
      if (!params.hasLatLonPoint()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.lat_or_lon_missing}").addConstraintViolation();
      }
    }

    // lat/lon bb
    if (params.getNorth() != null || params.getSouth() != null || params.getEast() != null || params.getWest() != null) {
      if (!params.hasLatLonBB()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.wrong_bbox}").addConstraintViolation();
      }

      if (params.getNorth() < params.getSouth()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.north_south}").addConstraintViolation();
      }
      if (params.getEast() < params.getWest()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.east_west}").addConstraintViolation();
      }
    }

    // proj bb
    if (params.getMaxx() != null || params.getMinx() != null || params.getMaxy() != null || params.getMiny() != null) {
      if (!params.hasProjectionBB()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.wrong_pbox}").addConstraintViolation();
      }

      if (params.getMaxx() < params.getMinx()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.rangex}").addConstraintViolation();
      }
      if (params.getMaxy() < params.getMiny()) {
        isValid = false;
        constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.rangey}").addConstraintViolation();
      }
    }

    // runtime: latest, all, or time
    if (params.getRuntime() != null) {
      if ("latest".equalsIgnoreCase(params.getRuntime())) {
        params.setLatestRuntime(true);

      } else if ("all".equalsIgnoreCase(params.getRuntime())) {
        params.setAllRuntime(true);

      } else {
        CalendarDate cd = TimeParamsValidator.validateISOString(params.getRuntime(), "{thredds.server.ncSubset.validation.param.runtime}", constraintValidatorContext);
        if (cd != null)
          params.setRuntimeDate(cd);
      }
    }

    // timeOffset: first or double
    if (params.getTimeOffset() != null) {
      if ("first".equalsIgnoreCase(params.getTimeOffset())) {
        params.setFirstTimeOffset(true);

      } else {
        try {
          double val = Double.parseDouble(params.getTimeOffset());
          params.setTimeOffsetVal(val);
        } catch (NumberFormatException e) {
          constraintValidatorContext.buildConstraintViolationWithTemplate("{thredds.server.ncSubset.validation.param.time_offset}").addConstraintViolation();
        }
      }
    }

    return isValid;
  }
/*
since none of these are required, can only do consistency checks
@see "http://www.unidata.ucar.edu/software/thredds/current/tds/reference/NetcdfSubsetServiceReference.html"