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

com.github.ydespreaux.spring.data.elasticsearch.resolver.ScrolledPageableHandlerMethodArgumentResolver Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2018 Yoann Despréaux
 *
 * 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 2 of the License, or
 * (at your option) 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; see the file COPYING . If not, write to the
 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Please send bugreports with examples or suggestions to [email protected]
 */

package com.github.ydespreaux.spring.data.elasticsearch.resolver;


import com.github.ydespreaux.spring.data.elasticsearch.ScrolledPageable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.SortArgumentResolver;
import org.springframework.data.web.SortHandlerMethodArgumentResolver;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.time.Duration;
import java.util.Optional;

/**
 * @author Yoann Despréaux
 * @since 0.0.1
 */
@Slf4j
public class ScrolledPageableHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    static final ScrolledPageable DEFAULT_PAGE_REQUEST = ScrolledPageable.of(20);
    private static final SortHandlerMethodArgumentResolver DEFAULT_SORT_RESOLVER = new SortHandlerMethodArgumentResolver();
    private static final String INVALID_DEFAULT_PAGE_SIZE = "Invalid default page size configured for method %s! Must not be less than one!";
    private static final String DEFAULT_SIZE_PARAMETER = "pageSize";
    private static final String DEFAULT_SCROLL_ID_PARAMETER = "scrollId";
    private static final String DEFAULT_SCROLL_TIME_PARAMETER = "scrollTime";
    private static final String DEFAULT_PREFIX = "";
    private static final String DEFAULT_QUALIFIER_DELIMITER = "_";
    private static final int DEFAULT_MAX_PAGE_SIZE = 2000;
    private ScrolledPageable fallbackPageable;
    private SortArgumentResolver sortResolver;
    private String sizeParameterName;
    private String scrollIdParameterName;
    private String scrollTimeParameterName;
    private String prefix;
    private String qualifierDelimiter;
    private int maxPageSize;
    private boolean oneIndexedParameters;

    public ScrolledPageableHandlerMethodArgumentResolver() {
        this((SortArgumentResolver) null);
    }

//    @Nullable
//    @Override
//    public ScrolledPageable resolveArgument(MethodParameter methodParameter, @Nullable ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, @Nullable WebDataBinderFactory webDataBinderFactory) throws Exception {
//        return ScrolledPageable.of(20);
//    }

    public ScrolledPageableHandlerMethodArgumentResolver(SortHandlerMethodArgumentResolver sortResolver) {
        this((SortArgumentResolver) sortResolver);
    }

    public ScrolledPageableHandlerMethodArgumentResolver(@Nullable SortArgumentResolver sortResolver) {
        this.fallbackPageable = DEFAULT_PAGE_REQUEST;
        this.sizeParameterName = DEFAULT_SIZE_PARAMETER;
        this.scrollIdParameterName = DEFAULT_SCROLL_ID_PARAMETER;
        this.scrollTimeParameterName = DEFAULT_SCROLL_TIME_PARAMETER;
        this.prefix = "";
        this.qualifierDelimiter = "_";
        this.maxPageSize = 2000;
        this.oneIndexedParameters = false;
        this.sortResolver = sortResolver == null ? DEFAULT_SORT_RESOLVER : sortResolver;
    }

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return ScrolledPageable.class.equals(methodParameter.getParameterType());
    }

    public void setFallbackPageable(ScrolledPageable fallbackPageable) {
        Assert.notNull(fallbackPageable, "Fallback Pageable must not be null!");
        this.fallbackPageable = fallbackPageable;
    }

    public boolean isFallbackPageable(Pageable pageable) {
        return this.fallbackPageable != null && this.fallbackPageable.equals(pageable);
    }

    protected int getMaxPageSize() {
        return this.maxPageSize;
    }

    public void setMaxPageSize(int maxPageSize) {
        this.maxPageSize = maxPageSize;
    }

    protected String getSizeParameterName() {
        return this.sizeParameterName;
    }

    public void setSizeParameterName(String sizeParameterName) {
        Assert.hasText(sizeParameterName, "Size parameter name must not be null or empty!");
        this.sizeParameterName = sizeParameterName;
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix == null ? "" : prefix;
    }

    public void setQualifierDelimiter(String qualifierDelimiter) {
        this.qualifierDelimiter = qualifierDelimiter == null ? "_" : qualifierDelimiter;
    }

    protected boolean isOneIndexedParameters() {
        return this.oneIndexedParameters;
    }

    public void setOneIndexedParameters(boolean oneIndexedParameters) {
        this.oneIndexedParameters = oneIndexedParameters;
    }

    public ScrolledPageable resolveArgument(MethodParameter methodParameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) {
//        Optional defaultOrFallback = this.getDefaultFromAnnotationOrFallback(methodParameter).toOptional();
        Optional defaultOrFallback = this.fallbackPageable.optional();
        String pageSizeString = webRequest.getParameter(this.getParameterNameToUse(this.sizeParameterName, methodParameter));
        String scrollTimeString = webRequest.getParameter(this.getParameterNameToUse(this.scrollTimeParameterName, methodParameter));
        String scrollId = webRequest.getParameter(this.getParameterNameToUse(this.scrollIdParameterName, methodParameter));
        Optional pageSize = this.parseAndApplyBoundaries(pageSizeString, this.maxPageSize, false);

        Optional scrollTime = !StringUtils.hasText(scrollTimeString) ? Optional.empty() : Optional.of(Duration.parse(scrollTimeString));

        int size = pageSize.orElseGet(() -> defaultOrFallback.map(Pageable::getPageSize).orElseThrow(IllegalStateException::new));
        size = size < 1 ? defaultOrFallback.map(Pageable::getPageSize).orElseThrow(IllegalStateException::new) : size;
        size = size > this.maxPageSize ? this.maxPageSize : size;

        Duration time = scrollTime.orElseGet(() -> defaultOrFallback.map(ScrolledPageable::getScrollTime).orElseThrow(IllegalStateException::new));
        Sort sort = this.sortResolver.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory);
        return ScrolledPageable.of(time, size, sort.isSorted() ? sort : defaultOrFallback.map(Pageable::getSort).orElseGet(Sort::unsorted), scrollId);
    }

//    private ScrolledPageable getDefaultFromAnnotationOrFallback(MethodParameter methodParameter) {
//        PageableDefault defaults = (PageableDefault)methodParameter.getParameterAnnotation(PageableDefault.class);
//        return defaults != null ? getDefaultPageRequestFrom(methodParameter, defaults) : this.fallbackPageable;
//    }

    protected String getParameterNameToUse(String source, @Nullable MethodParameter parameter) {
        StringBuilder builder = new StringBuilder(this.prefix);
        Qualifier qualifier = parameter == null ? null : parameter.getParameterAnnotation(Qualifier.class);
        if (qualifier != null) {
            builder.append(qualifier.value());
            builder.append(this.qualifierDelimiter);
        }
        return builder.append(source).toString();
    }

    private Optional parseAndApplyBoundaries(@Nullable String parameter, int upper, boolean shiftIndex) {
        if (!StringUtils.hasText(parameter)) {
            return Optional.empty();
        } else {
            try {
                int parsed = Integer.parseInt(parameter) - (this.oneIndexedParameters && shiftIndex ? 1 : 0);
                return Optional.of(parsed < 0 ? 0 : (parsed > upper ? upper : parsed));
            } catch (NumberFormatException var5) {
                return Optional.of(0);
            }
        }
    }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy