diff --git a/egov/egov-restapi/src/main/java/org/egov/restapi/model/ETransactionRequest.java b/egov/egov-restapi/src/main/java/org/egov/restapi/model/ETransactionRequest.java new file mode 100644 index 00000000000..05047d69eaf --- /dev/null +++ b/egov/egov-restapi/src/main/java/org/egov/restapi/model/ETransactionRequest.java @@ -0,0 +1,162 @@ +/* + * eGov SmartCity eGovernance suite aims to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2018 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * Further, all user interfaces, including but not limited to citizen facing interfaces, + * Urban Local Bodies interfaces, dashboards, mobile applications, of the program and any + * derived works should carry eGovernments Foundation logo on the top right corner. + * + * For the logo, please refer http://egovernments.org/html/logo/egov_logo.png. + * For any further queries on attribution, including queries on brand guidelines, + * please contact contact@egovernments.org + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + * + */ + +package org.egov.restapi.model; + +import org.egov.infra.persistence.validator.annotation.Numeric; +import org.egov.infra.persistence.validator.annotation.Required; +import org.egov.infra.validation.exception.ValidationError; +import org.egov.infra.validation.exception.ValidationException; +import org.egov.restapi.validator.annotation.NoFutureDate; +import org.egov.restapi.validator.annotation.OverlappedDateRange; +import org.egov.restapi.validator.annotation.ThisCityCode; + +import javax.validation.constraints.Pattern; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +@OverlappedDateRange(fromDate = "fromDate", toDate = "toDate", dateFormat = ETransactionRequest.DATE_FORMAT, message = "fromDate must be less than or equal to toDate") +public class ETransactionRequest { + + private static final SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy"); + + private static final String DATE_PATTERN = "([0-3][0-9])-((0[0-9])|(1[0-2]))-(\\d\\d\\d\\d)"; + protected static final String DATE_FORMAT = "dd-MM-yyyy"; + + @NoFutureDate(dateFormat = DATE_FORMAT) + @Pattern(regexp = DATE_PATTERN, message = "fromDate must be of dd-MM-yyyy pattern") + @Required + private String fromDate; + + @NoFutureDate(dateFormat = DATE_FORMAT) + @Pattern(regexp = DATE_PATTERN, message = "fromDate must be of dd-MM-yyyy pattern") + @Required + private String toDate; + + @ThisCityCode + @Numeric + @Required + private String ulbCode; + + public ETransactionRequest() { + } + + public ETransactionRequest(String fromDate, String toDate, String ulbCode) { + this.fromDate = fromDate; + this.toDate = toDate; + this.ulbCode = ulbCode; + } + + public String getFromDate() { + return fromDate; + } + + public void setFromDate(String fromDate) { + this.fromDate = fromDate; + } + + public String getToDate() { + return toDate; + } + + public void setToDate(String toDate) { + this.toDate = toDate; + } + + public String getUlbCode() { + return ulbCode; + } + + public void setUlbCode(String ulbCode) { + this.ulbCode = ulbCode; + } + + public Date getParsedFromDate() { + try { + return SIMPLE_DATE_FORMAT.parse(fromDate); + } catch (ParseException e) { + throw new ValidationException(new ValidationError("INVALID_DATE", "Invalid fromDate")); + } + } + + public Date getParsedToDate() { + try { + return SIMPLE_DATE_FORMAT.parse(toDate); + } catch (ParseException e) { + throw new ValidationException(new ValidationError("INVALID_DATE", "Invalid toDate")); + } + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + ETransactionRequest that = (ETransactionRequest) o; + + + if (fromDate != null && !fromDate.equals(that.fromDate)) + return false; + if (toDate != null && !toDate.equals(that.toDate)) + return false; + return (ulbCode == that.ulbCode && ulbCode == null) || ulbCode.equals(that.ulbCode); + + } + + @Override + public String toString() { + return "ETransactionRequest{" + + "fromDate='" + fromDate + '\'' + + ", toDate='" + toDate + '\'' + + ", ulbCode='" + ulbCode + '\'' + + '}'; + } +} diff --git a/egov/egov-restapi/src/main/java/org/egov/restapi/util/ValidationUtil.java b/egov/egov-restapi/src/main/java/org/egov/restapi/util/ValidationUtil.java index 40bf04de164..cf7af608289 100644 --- a/egov/egov-restapi/src/main/java/org/egov/restapi/util/ValidationUtil.java +++ b/egov/egov-restapi/src/main/java/org/egov/restapi/util/ValidationUtil.java @@ -72,7 +72,6 @@ import org.egov.eis.entity.Assignment; import org.egov.infra.admin.master.entity.Boundary; import org.egov.infra.admin.master.entity.BoundaryType; -import org.egov.infra.config.core.ApplicationThreadLocals; import org.egov.infra.utils.DateUtils; import org.egov.infra.validation.exception.ValidationError; import org.egov.ptis.client.service.calculator.APTaxCalculator; @@ -144,9 +143,6 @@ public class ValidationUtil { @Autowired private ApplicationContext beanProvider; - private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy"); - private static final Pattern DATE_PATTERN = Pattern.compile("([0-3][0-9])-((0[0-9])|(1[0-2]))-(\\d\\d\\d\\d)"); - private static final String EMAIL_PATTERN = "^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@" + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$"; private static final String PINCODE_PATTERN = "^[1-9][0-9]{5}$"; @@ -154,10 +150,6 @@ public class ValidationUtil { private static final String CAMEL_CASE_PATTERN = "([A-Z]+[a-z]+\\w+)+"; private static final String DIGITS_FLOAT_INT_DBL = "[-+]?[0-9]*\\.?[0-9]+"; - static { - DATE_FORMAT.setLenient(false); - } - /** * Validates Property Transfer request * @@ -648,77 +640,6 @@ private ErrorDetails validateAssignment(PropertyImpl property) { } - /* - * Appends ValidationError to @param errorList - */ - public void validateRequiredFields(final List errorList, final JsonElement object, final String... keys) { - if (!object.isJsonObject()) { - errorList.add(new ValidationError(JSON_CONVERSION_ERROR_CODE, "Expected a Object.")); - return; - } - JsonObject jsonObject = object.getAsJsonObject(); - for (final String key : keys) { - if (!jsonObject.has(key)) { - errorList.add(new ValidationError("MISSING_KEY", "Required \"" + key + "\"")); - } - JsonElement valueElement = jsonObject.get(key); - if (valueElement.isJsonNull()) { - errorList.add(new ValidationError("NO_NULL_KEY", "Key \"" + key + "\" must not be null")); - } - } - } - - /* - * Appends ValidationError to @param errorList - */ - public void validateETransactionRequest(final List errorList, String ulbCode, Date fromDate, Date toDate) { - if (StringUtils.isBlank(ulbCode)) { - errorList.add(new ValidationError("NO_EMPTY_FIELD", RestApiConstants.THIRD_PARTY_ERR_CODE_ULBCODE_NO_REQ_MSG)); - } else if (!ApplicationThreadLocals.getCityCode().equals(ulbCode)) { - errorList.add(new ValidationError(RestApiConstants.THIRD_PARTY_ERR_CODE_ULBCODE_NO_REQUIRED, "Invalid ULB Code")); - } - - if (DateUtils.compareDates(fromDate, toDate)) { - errorList.add(new ValidationError("INVALID_DATE_RANGE", "toDate must be greater or equal to fromDate")); - } - Date endOfToday = DateUtils.endOfToday().toDate(); - Date maxDate; - String maxDateParam; - if (DateUtils.compareDates(fromDate, toDate)) { - maxDate = fromDate; - maxDateParam = "fromDate"; - } else { - maxDate = toDate; - maxDateParam = "toDate"; - } - if (!maxDate.equals(endOfToday) && DateUtils.compareDates(maxDate, endOfToday)) { - errorList.add(new ValidationError("NO_FUTURE_DATE", String.format("%s(%s) must be less or equal to today (%s)", - maxDateParam, convertDateToString(maxDate), convertDateToString(endOfToday)))); - } - } - - /** - * Validate using regex and parse the date - * @param dateInString - * @return Date - * @throws ParseException - */ - public Date convertStringToDate(final String dateInString) throws ParseException { - - Matcher matcher = DATE_PATTERN.matcher(dateInString); - if (!matcher.matches()) { - throw new ParseException("Invalid date", 0); - } - return DATE_FORMAT.parse(dateInString); - } - - /** - * Convert date to string in dd-MM-yyyy format - */ - public String convertDateToString(final Date date) { - return DATE_FORMAT.format(date); - } - /** * Validates Vacant Land details * diff --git a/egov/egov-restapi/src/main/java/org/egov/restapi/validator/CityCodeValidator.java b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/CityCodeValidator.java new file mode 100644 index 00000000000..df65cb89e1e --- /dev/null +++ b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/CityCodeValidator.java @@ -0,0 +1,27 @@ +package org.egov.restapi.validator; + +import org.egov.infra.config.core.ApplicationThreadLocals; +import org.egov.infra.utils.StringUtils; +import org.egov.restapi.validator.annotation.ThisCityCode; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +public class CityCodeValidator implements ConstraintValidator { + + ThisCityCode constraintAnnotation; + + @Override + public void initialize(final ThisCityCode constraintAnnotation) { + this.constraintAnnotation = constraintAnnotation; + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if (StringUtils.isEmpty(value)) + return false; + else { + return ApplicationThreadLocals.getCityCode().equals(value.trim()); + } + } +} diff --git a/egov/egov-restapi/src/main/java/org/egov/restapi/validator/NoFutureDateValidator.java b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/NoFutureDateValidator.java new file mode 100644 index 00000000000..d9a3c60ccdb --- /dev/null +++ b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/NoFutureDateValidator.java @@ -0,0 +1,88 @@ +/* + * eGov SmartCity eGovernance suite aims to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2017 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * Further, all user interfaces, including but not limited to citizen facing interfaces, + * Urban Local Bodies interfaces, dashboards, mobile applications, of the program and any + * derived works should carry eGovernments Foundation logo on the top right corner. + * + * For the logo, please refer http://egovernments.org/html/logo/egov_logo.png. + * For any further queries on attribution, including queries on brand guidelines, + * please contact contact@egovernments.org + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + * + */ + +package org.egov.restapi.validator; + +import org.egov.infra.utils.DateUtils; +import org.egov.infra.utils.StringUtils; +import org.egov.restapi.validator.annotation.NoFutureDate; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class NoFutureDateValidator implements ConstraintValidator { + + private NoFutureDate noFutureDate; + + @Override + public void initialize(final NoFutureDate noFutureDate) { + this.noFutureDate = noFutureDate; + } + + @Override + public boolean isValid(final String value, final ConstraintValidatorContext arg1) { + if (StringUtils.isEmpty(value)) + return true; + if (noFutureDate.dateFormat() == null) { + return false; + } + try { + SimpleDateFormat sdf = new SimpleDateFormat(noFutureDate.dateFormat()); + sdf.setLenient(false); + Date date = sdf.parse(value); + Date endOfToday = DateUtils.endOfToday().toDate(); + return date.before(endOfToday); + } catch (IllegalArgumentException | ParseException e) { + return false; + } + } + +} diff --git a/egov/egov-restapi/src/main/java/org/egov/restapi/validator/OverlappedDateRangeValidator.java b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/OverlappedDateRangeValidator.java new file mode 100644 index 00000000000..12304da17c7 --- /dev/null +++ b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/OverlappedDateRangeValidator.java @@ -0,0 +1,48 @@ +package org.egov.restapi.validator; + +import org.apache.commons.lang3.reflect.FieldUtils; +import org.egov.infra.exception.ApplicationRuntimeException; +import org.egov.infra.utils.StringUtils; +import org.egov.restapi.validator.annotation.OverlappedDateRange; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +public class OverlappedDateRangeValidator implements ConstraintValidator { + + OverlappedDateRange constraintAnnotation; + + @Override + public void initialize(OverlappedDateRange constraintAnnotation) { + this.constraintAnnotation = constraintAnnotation; + } + + @Override + public boolean isValid(Object target, ConstraintValidatorContext context) { + try { + String fromDateString = (String) FieldUtils.readField(target, constraintAnnotation.fromDate(), true); + String toDateString = (String) FieldUtils.readField(target, constraintAnnotation.toDate(), true); + if(StringUtils.isEmpty(fromDateString) || StringUtils.isEmpty(toDateString)) { + return true; + } + SimpleDateFormat sdf = new SimpleDateFormat(constraintAnnotation.dateFormat()); + sdf.setLenient(false); + + Date fromDate = sdf.parse(fromDateString); + Date toDate = sdf.parse(toDateString); + + boolean isValid = (fromDate.before(toDate) || fromDate.equals(toDate)); + if (!isValid) + context.buildConstraintViolationWithTemplate(constraintAnnotation.message()). + addPropertyNode(constraintAnnotation.toDate()).addConstraintViolation(); + return isValid; + } catch (ParseException e) { + return false; + }catch (IllegalAccessException e) { + throw new ApplicationRuntimeException("Could not compare dates", e); + } + } +} diff --git a/egov/egov-restapi/src/main/java/org/egov/restapi/validator/annotation/NoFutureDate.java b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/annotation/NoFutureDate.java new file mode 100644 index 00000000000..4c1d3e4378f --- /dev/null +++ b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/annotation/NoFutureDate.java @@ -0,0 +1,76 @@ +/* + * eGov SmartCity eGovernance suite aims to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2017 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * Further, all user interfaces, including but not limited to citizen facing interfaces, + * Urban Local Bodies interfaces, dashboards, mobile applications, of the program and any + * derived works should carry eGovernments Foundation logo on the top right corner. + * + * For the logo, please refer http://egovernments.org/html/logo/egov_logo.png. + * For any further queries on attribution, including queries on brand guidelines, + * please contact contact@egovernments.org + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + * + */ + +package org.egov.restapi.validator.annotation; + +import org.egov.restapi.validator.NoFutureDateValidator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target({ METHOD, FIELD }) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = NoFutureDateValidator.class) +public @interface NoFutureDate { + + String dateFormat(); + + String message() default "Future Date Not Allowed"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} \ No newline at end of file diff --git a/egov/egov-restapi/src/main/java/org/egov/restapi/validator/annotation/OverlappedDateRange.java b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/annotation/OverlappedDateRange.java new file mode 100644 index 00000000000..ee751eb40c7 --- /dev/null +++ b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/annotation/OverlappedDateRange.java @@ -0,0 +1,30 @@ +package org.egov.restapi.validator.annotation; + +import org.egov.restapi.validator.OverlappedDateRangeValidator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target(TYPE) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = OverlappedDateRangeValidator.class) +public @interface OverlappedDateRange { + String fromDate(); + + String toDate(); + + String dateFormat(); + + String message() default "{validator.overlappedDates}"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} \ No newline at end of file diff --git a/egov/egov-restapi/src/main/java/org/egov/restapi/validator/annotation/ThisCityCode.java b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/annotation/ThisCityCode.java new file mode 100644 index 00000000000..13cacab0ada --- /dev/null +++ b/egov/egov-restapi/src/main/java/org/egov/restapi/validator/annotation/ThisCityCode.java @@ -0,0 +1,25 @@ +package org.egov.restapi.validator.annotation; + +import org.egov.restapi.validator.CityCodeValidator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target({ METHOD, FIELD }) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = CityCodeValidator.class) +public @interface ThisCityCode { + String message() default "Invalid ULB Code"; + + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/egov/egov-restapi/src/main/java/org/egov/restapi/web/rest/RestETransactionController.java b/egov/egov-restapi/src/main/java/org/egov/restapi/web/rest/RestETransactionController.java index b5bd423e75d..4f647daa239 100644 --- a/egov/egov-restapi/src/main/java/org/egov/restapi/web/rest/RestETransactionController.java +++ b/egov/egov-restapi/src/main/java/org/egov/restapi/web/rest/RestETransactionController.java @@ -48,56 +48,51 @@ package org.egov.restapi.web.rest; -import static java.lang.String.format; -import static org.egov.restapi.constants.RestApiConstants.JSON_CONVERSION_ERROR_CODE; -import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; -import static org.springframework.web.bind.annotation.RequestMethod.POST; - -import java.text.ParseException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import javax.servlet.http.HttpServletResponse; - +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import org.apache.log4j.Logger; import org.egov.infra.utils.DateUtils; import org.egov.infra.validation.exception.ValidationError; import org.egov.infra.validation.exception.ValidationException; +import org.egov.restapi.model.ETransactionRequest; import org.egov.restapi.model.ETransactionResponse; import org.egov.restapi.service.ETransactionService; import org.egov.restapi.util.JsonConvertor; -import org.egov.restapi.util.ValidationUtil; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.util.Pair; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import static org.springframework.web.bind.annotation.RequestMethod.POST; /** - * Controller to Publish(Read-only) electronic transaction statistics + * Controller to Publish(Read-only) electronic transaction statistics See: + * {@link #getETransactionStatistics(ETransactionRequest, HttpServletResponse)} */ @RestController +@SuppressWarnings("unused") public class RestETransactionController { public static final String API_STATISTICS = "/public/transaction/statistics"; - public static final String PARAM_FROM_DATE = "fromDate"; - public static final String PARAM_TO_DATE = "toDate"; - public static final String PARAM_ULB_CODE = "ulbCode"; private static final Logger LOGGER = Logger.getLogger(RestETransactionController.class); @Autowired ETransactionService eTransactionService; - @Autowired - ValidationUtil validationUtil; - /** * Formats a JSON representing the Errors * @@ -113,6 +108,13 @@ private String makeValidationErrorJson(ValidationException ve) { JsonObject jsonError = new JsonObject(); jsonError.addProperty("key", validationError.getKey()); jsonError.addProperty("message", validationError.getMessage()); + String args[] = validationError.getArgs(); + int args_i = 0; + if (args.length % 2 == 0) { + while (args_i < args.length) { + jsonError.addProperty(args[args_i++], args[args_i++]); + } + } validationErrorList.add(jsonError); } errorObject.addProperty("type", "validation_error"); @@ -122,97 +124,51 @@ private String makeValidationErrorJson(ValidationException ve) { return resultObject.toString(); } - /** - * Parses Input JSON and return a date range as {@code Pair}, also validate ulbCode against - * ApplicationThreadLocals - * @param requestJson JSON string containing PARAM_ULB_CODE, PARAM_FROM_DATE & PARAM_TO_DATE keys - * @return pair/tuple of (fromDate, toDate) - */ - private Pair parseRequestAndGetDateRange(String requestJson) { - List validationErrorList = new ArrayList<>(3); - JsonParser parser = new JsonParser(); - JsonElement jsonElement = parser.parse(requestJson); - validationUtil.validateRequiredFields(validationErrorList, jsonElement, PARAM_ULB_CODE, PARAM_FROM_DATE, PARAM_TO_DATE); - - Date fromDate = null; - Date toDate = null; - - if (validationErrorList.isEmpty()) { - try { - JsonObject requestObject = jsonElement.getAsJsonObject(); - String ulbCode = requestObject.get(PARAM_ULB_CODE).getAsString().trim(); - String fromDateString = requestObject.get(PARAM_FROM_DATE).getAsString(); - String toDateString = requestObject.get(PARAM_TO_DATE).getAsString(); - - fromDate = validationUtil.convertStringToDate(fromDateString); - toDate = validationUtil.convertStringToDate(toDateString); - - if (fromDate.equals(toDate)) { - fromDate = DateUtils.startOfDay(fromDate); - toDate = DateUtils.endOfDay(toDate); - } - // Cap toDate to now - Date now = DateUtils.now(); - if (org.apache.commons.lang3.time.DateUtils.isSameDay(toDate, now)) { - toDate = now; + @ExceptionHandler(Throwable.class) + @SuppressWarnings("unused") + public ResponseEntity handleAllException(Throwable ex) { + ResponseEntity.BodyBuilder bodyBuilder = ResponseEntity + .badRequest() + .contentType(MediaType.APPLICATION_JSON); + if (ex instanceof ValidationException) { + return bodyBuilder.body(makeValidationErrorJson((ValidationException) ex)); + } else if (ex instanceof MethodArgumentNotValidException) { + MethodArgumentNotValidException manve = (MethodArgumentNotValidException) ex; + BindingResult bindingResult = manve.getBindingResult(); + + List objectErrorList = bindingResult.getAllErrors(); + List veList = new ArrayList<>(objectErrorList.size()); + ValidationException ve = new ValidationException(veList); + + for (ObjectError oe : objectErrorList) { + if (oe instanceof FieldError) { + FieldError fe = (FieldError) oe; + veList.add(new ValidationError(fe.getField(), fe.getDefaultMessage(), "code", oe.getCode())); + } else { + veList.add(new ValidationError(oe.getObjectName(), oe.getDefaultMessage(), "code", oe.getCode())); } - - validationUtil.validateETransactionRequest(validationErrorList, ulbCode, fromDate, toDate); - - } catch (ParseException ex) { - validationErrorList.add(new ValidationError("INVALID_DATE", "Expected date in dd-MM-yyyy format")); - } catch (Exception ex) { - LOGGER.error("Unforeseen error while parsing input JSON", ex); - validationErrorList.add(new ValidationError("CODE_ERROR", "An unknown error has occured")); } + return bodyBuilder.body(makeValidationErrorJson(ve)); + } else { + LOGGER.warn("An unknown exception caught", ex); + return bodyBuilder.body( + "{\"message\": \"An Error Occurred\", \"error\": \"" + ex.getMessage().replaceAll("[\"]", "\\\\\"") + "\"}"); } - - if (!validationErrorList.isEmpty()) { - throw new ValidationException(validationErrorList); - } - - // IMPORTANT! fromDate & toDate is not null in this line. - // After line 140 (fromDate==null && toDate==null) and validationErrorList.isEmpty() are exclusive - return Pair.of(fromDate, toDate); } @RequestMapping(value = API_STATISTICS, method = POST, consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE) - public String getETransactionStatistics(@RequestBody final String requestJson, + @SuppressWarnings("unused") + public String getETransactionStatistics(@Valid @RequestBody final ETransactionRequest request, final HttpServletResponse response) { - List tnxInfoList; - try { - - Pair fromToDatePair = parseRequestAndGetDateRange(requestJson); - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(format("parsed dates; from: %s, to: %s", fromToDatePair.getFirst(), fromToDatePair.getSecond())); - } - - tnxInfoList = eTransactionService.getETransactionCount(fromToDatePair.getFirst(), fromToDatePair.getSecond()); - - } catch (JsonSyntaxException syntaxEx) { - - if (LOGGER.isInfoEnabled()) - LOGGER.info(format("JSON Syntax Error: %s; requestJson: %s Error: %s", - API_STATISTICS, - requestJson, - syntaxEx.getMessage())); - // Not throwing as we may not need to catch & log same error twice - return makeValidationErrorJson( - new ValidationException(new ValidationError(JSON_CONVERSION_ERROR_CODE, "Invalid JSON"))); - } catch (ValidationException validationEx) { - - if (LOGGER.isInfoEnabled()) - LOGGER.info(format("ValidationException: %s, requestJson: %s Error: %s", - API_STATISTICS, - requestJson, - validationEx.getErrors())); - - response.setStatus(HttpServletResponse.SC_BAD_REQUEST); - return makeValidationErrorJson(validationEx); + Date fromDate = request.getParsedFromDate(); + Date toDate = request.getParsedToDate(); + if(fromDate.equals(toDate)) { + toDate = DateUtils.endOfDay(toDate); } + return JsonConvertor + .convert(eTransactionService.getETransactionCount(fromDate, toDate)); - return JsonConvertor.convert(tnxInfoList); } + } \ No newline at end of file