All Downloads are FREE. Search and download functionalities are using the official Maven repository.

au.org.consumerdatastandards.holder.api.ApiControllerBase Maven / Gradle / Ivy

The newest version!
package au.org.consumerdatastandards.holder.api;

import au.org.consumerdatastandards.holder.model.Error;
import au.org.consumerdatastandards.holder.model.ErrorListResponse;
import au.org.consumerdatastandards.holder.model.LinksPaginated;
import au.org.consumerdatastandards.holder.model.MetaPaginated;
import au.org.consumerdatastandards.holder.model.TxMetaPaginated;
import au.org.consumerdatastandards.holder.util.WebUtil;
import org.apache.commons.validator.routines.InetAddressValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.NativeWebRequest;

import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

public class ApiControllerBase {
    private final static String BASE64_PATTERN = "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$";

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    protected Integer getPagingValue(Integer page, int defaultValue) {
        return page != null && page > 0 ? page : defaultValue;
    }

    protected void throwCDSUnprocessableErrors(UUID interactionId, List errorList) {
        throwCDSErrors(interactionId, errorList, HttpStatus.UNPROCESSABLE_ENTITY);
    }

    protected void throwCDSErrors(UUID interactionId, List errorList, HttpStatus httpStatus) {
        ErrorListResponse errors = new ErrorListResponse();
        errors.setErrors(errorList);
        throw new CDSException(errors, interactionId, httpStatus);
    }

    protected void throwInvalidResource(String resourceId) {
        throwInvalidResource(resourceId, UUID.randomUUID());
    }

    protected void throwInvalidResource(String resourceId, UUID interactionId) {
        throwCDSErrors(interactionId, Collections.singletonList(new Error("Invalid Resource",
                "urn:au-cds:error:cds-all:Resource/Invalid", resourceId)), HttpStatus.NOT_FOUND);
    }

    protected void validatePageRange(Integer page, int totalPages, UUID interactionId) {
        if (totalPages > 0 && page != null && page > totalPages) {
            throwCDSUnprocessableErrors(interactionId, Collections.singletonList(
                    new Error("Invalid Page", "urn:au-cds:error:cds-all:Field/InvalidPage", String.valueOf(totalPages))));
        }
    }

    protected void validatePageSize(Integer pageSize, UUID interactionId) {
        if (pageSize != null && pageSize > 1000) {
            String message = String.format(
                    "Invalid page size requested: %d. Page size has to be between 1 and 1000",
                    pageSize);
            throwCDSErrors(interactionId, Collections.singletonList(
                    new Error("Invalid Page Size", "urn:au-cds:error:cds-all:Field/InvalidPageSize", message)),
                    HttpStatus.BAD_REQUEST);
        }
    }

    protected void validateUpdatedSince(OffsetDateTime updatedSince, UUID interactionId) {
        if (updatedSince != null && !updatedSince.isBefore(OffsetDateTime.now())) {
            throwInvalidDate("updated-since is not in the past", interactionId);
        }
    }

    protected void validateOldestNewestOffsetDateTime(OffsetDateTime oldestTime, OffsetDateTime newestTime, UUID interactionId) {
        if (newestTime != null && !newestTime.isBefore(OffsetDateTime.now())) {
            throwInvalidDate("newest-time is not in the past", interactionId);
        }
        if (oldestTime != null) {
            if (!oldestTime.isBefore(OffsetDateTime.now())) {
                throwInvalidDate("oldest-time is not in the past", interactionId);
            }
            if (newestTime != null && newestTime.isBefore(oldestTime)) {
                throwInvalidDate("newest-time is before oldest-time", interactionId);
            }
        }
    }

    protected void validateOldestNewestLocalDate(LocalDate oldestDate, LocalDate newestDate, UUID interactionId) {
        if (newestDate != null && !newestDate.isBefore(LocalDate.now())) {
            throwInvalidDate("newest-date is not in the past", interactionId);
        }
        if (oldestDate != null) {
            if (!oldestDate.isBefore(LocalDate.now())) {
                throwInvalidDate("oldest-date is not in the past", interactionId);
            }
            if (newestDate != null && newestDate.isBefore(oldestDate)) {
                throwInvalidDate("newest-date is before oldest-date", interactionId);
            }
        }
    }

    protected void throwInvalidDate(String message, UUID interactionId) {
        throwCDSErrors(interactionId, Collections.singletonList(
                new Error("Invalid Page Size", "urn:au-cds:error:cds-all:Field/InvalidDateTime", message)),
                HttpStatus.BAD_REQUEST);
    }

    protected boolean hasSupportedVersion(Integer xMinV, Integer xV, int maxSupportedVersion) {
        if (xMinV == null || xMinV > xV) {
            return (maxSupportedVersion >= xV);
        }
        return (maxSupportedVersion >= xMinV);
    }

    protected int getSupportedVersion(Integer xMinV, Integer xV, int maxSupportedVersion) {
        if (xMinV == null) return xV;
        return Math.min(xV, maxSupportedVersion);
    }

    protected HttpHeaders generateResponseHeaders(UUID fapiInteractionId, int supportedVersion) {
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.set("content-type", "application/json");
        responseHeaders.set("x-v", "" + supportedVersion);
        responseHeaders.set("x-fapi-interaction-id", (fapiInteractionId == null ? UUID.randomUUID() : fapiInteractionId).toString());
        return responseHeaders;
    }

    protected int validateSupportedVersion(Integer xMinV, Integer xV, UUID interactionId, int maxSupportedVersion) {
        if (xV == null) {
            Error error = new Error("Missing Required Header", "urn:au-cds:error:cds-all:Header/Missing", "x-v");
            throwCDSErrors(interactionId, Collections.singletonList(error), HttpStatus.BAD_REQUEST);
        }
        if (!hasSupportedVersion(xMinV, xV, maxSupportedVersion)) {
            String message = String.format(
                "Unsupported version requested, minimum version specified is %d, maximum version specified is %d, current version is %d",
                xMinV, xV, maxSupportedVersion);
            Error error = new Error("Unsupported Version", "urn:au-cds:error:cds-all:Header/UnsupportedVersion", message);
            throwCDSErrors(interactionId, Collections.singletonList(error), HttpStatus.NOT_ACCEPTABLE);
        }
        return getSupportedVersion(xMinV, xV, maxSupportedVersion);
    }

    protected int validateHeaders(String xCdsClientHeaders,
                                   String xFapiCustomerIpAddress,
                                   UUID interactionId,
                                   Integer xMinV, Integer xV, int maxSupportedVersion) {
        int supportedVersion = validateSupportedVersion(xMinV, xV, interactionId, maxSupportedVersion);
        if (StringUtils.hasText(xFapiCustomerIpAddress)) {
            ArrayList errorList = new ArrayList<>();
            InetAddressValidator inetAddressValidator = InetAddressValidator.getInstance();
            if (!inetAddressValidator.isValid(xFapiCustomerIpAddress)) {
                errorList.add(new Error("Invalid Header", "urn:au-cds:error:cds-all:Header/Invalid", "x-fapi-customer-ip-address: request header value is not a valid IP address"));
            }
            if (StringUtils.isEmpty(xCdsClientHeaders)) {
                errorList.add(new Error("Missing Required Header", "urn:au-cds:error:cds-all:Header/Missing", "x-cds-client-headers: request header is not present"));
            } else if (!xCdsClientHeaders.matches(BASE64_PATTERN)) {
                errorList.add(new Error("Invalid Header", "urn:au-cds:error:cds-all:Header/Invalid", "x-cds-client-headers: request header value is not Base64 encoded"));
            }
            if (!errorList.isEmpty()) {
                throwCDSErrors(interactionId, errorList, HttpStatus.BAD_REQUEST);
            }
        }
        return supportedVersion;
    }

    protected LinksPaginated getLinkData(NativeWebRequest request, @SuppressWarnings("rawtypes") Page page, Integer actualPage, Integer actualPageSize) {
        LinksPaginated linkData = new LinksPaginated();
        linkData.setSelf(WebUtil.getOriginalUrl(request));

        if (page.getTotalPages() == 0) {
            linkData.setFirst(null);
            linkData.setLast(null);
        } else {
            linkData.setFirst(WebUtil.getPaginatedLink(request, 1, actualPageSize));
            linkData.setLast(WebUtil.getPaginatedLink(request, page.getTotalPages(), actualPageSize));
        }

        if (page.hasPrevious()) {
            linkData.setPrev(WebUtil.getPaginatedLink(request, actualPage - 1, actualPageSize));
        }

        if (page.hasNext()) {
            linkData.setNext(WebUtil.getPaginatedLink(request, actualPage + 1, actualPageSize));
        }
        return linkData;
    }

    protected MetaPaginated getMetaData(@SuppressWarnings("rawtypes") Page page) {
        MetaPaginated metaData = new MetaPaginated();
        metaData.setTotalPages(page.getTotalPages());
        metaData.setTotalRecords((int)page.getTotalElements());
        return metaData;
    }

    protected TxMetaPaginated getTxMetaData(@SuppressWarnings("rawtypes") Page page, boolean isQueryParamUnsupported) {
        TxMetaPaginated metaData = new TxMetaPaginated();
        metaData.setTotalPages(page.getTotalPages());
        metaData.setTotalRecords((int)page.getTotalElements());
        metaData.setIsQueryParamUnsupported(isQueryParamUnsupported);
        return metaData;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy